From 6e3a9fe40c6a0803c4c6cc11b73fcb8bc7e8a7ca Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Mon, 15 Apr 2019 19:21:25 +0200 Subject: [PATCH] dnsdist: Make DoH ciphers configurable --- pdns/dnsdist-lua.cc | 11 ++++ pdns/dnsdistdist/doh.cc | 58 +++++++++++++--------- pdns/dnsdistdist/doh.hh | 10 ++++ pdns/dnsdistdist/m4/dnsdist_with_libssl.m4 | 8 +++ 4 files changed, 64 insertions(+), 23 deletions(-) diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index bb68d91cb5..1eec9e5937 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -1677,6 +1677,12 @@ void setupLuaConfig(bool client) if (vars->count("idleTimeout")) { frontend->d_idleTimeout = boost::get((*vars)["idleTimeout"]); } + if (vars->count("ciphers")) { + frontend->d_ciphers = boost::get((*vars)["ciphers"]); + } + if (vars->count("ciphersTLS13")) { + frontend->d_ciphers13 = boost::get((*vars)["ciphersTLS13"]); + } } g_dohlocals.push_back(frontend); auto cs = std::unique_ptr(new ClientState(frontend->d_local, true, false, 0, "", {})); @@ -1871,6 +1877,11 @@ void setupLuaConfig(bool client) frontend->tlsFrontend->setupTLS(); } #endif /* HAVE_DNS_OVER_TLS */ +#ifdef HAVE_DNS_OVER_HTTPS + if (frontend->dohFrontend) { + frontend->dohFrontend->reloadCertificate(); + } +#endif /* HAVE_DNS_OVER_HTTPS */ } catch(const std::exception& e) { errlog("Error reloading certificates for frontend %s: %s", frontend->local.toStringWithPort(), e.what()); diff --git a/pdns/dnsdistdist/doh.cc b/pdns/dnsdistdist/doh.cc index c3a7409891..5456685ac2 100644 --- a/pdns/dnsdistdist/doh.cc +++ b/pdns/dnsdistdist/doh.cc @@ -45,7 +45,7 @@ using namespace std; // through the bowels of h2o struct DOHServerConfig { - DOHServerConfig(ClientState* cs_): cs(cs_), df(cs_->dohFrontend) + DOHServerConfig(uint32_t idleTimeout) { memset(&h2o_accept_ctx, 0, sizeof(h2o_accept_ctx)); @@ -60,7 +60,7 @@ struct DOHServerConfig } h2o_config_init(&h2o_config); - h2o_config.http2.idle_timeout = df->d_idleTimeout * 1000; + h2o_config.http2.idle_timeout = idleTimeout * 1000; } h2o_globalconf_t h2o_config; @@ -86,7 +86,7 @@ static int processDOHQuery(DOHUnit* du) // we got closed meanwhile. XXX small race condition here return -1; } - DOHServerConfig* dsc = (DOHServerConfig*)du->req->conn->ctx->storage.entries[0].data; + DOHServerConfig* dsc = reinterpret_cast(du->req->conn->ctx->storage.entries[0].data); ClientState& cs = *dsc->cs; if (du->query.size() < sizeof(dnsheader)) { @@ -261,7 +261,7 @@ try h2o_socket_t* sock = req->conn->callbacks->get_socket(req->conn); ComboAddress remote; h2o_socket_getpeername(sock, reinterpret_cast(&remote)); - DOHServerConfig* dsc = (DOHServerConfig*)req->conn->ctx->storage.entries[0].data; + DOHServerConfig* dsc = reinterpret_cast(req->conn->ctx->storage.entries[0].data); if(auto tlsversion = h2o_socket_get_ssl_protocol_version(sock)) { if(!strcmp(tlsversion, "TLSv1.0")) @@ -441,7 +441,7 @@ void dnsdistclient(int qsock, int rsock) static void on_dnsdist(h2o_socket_t *listener, const char *err) { DOHUnit *du = nullptr; - DOHServerConfig* dsc = (DOHServerConfig*)listener->data; + DOHServerConfig* dsc = reinterpret_cast(listener->data); ssize_t got = recv(dsc->dohresponsepair[1], &du, sizeof(du), 0); if (got < 0) { @@ -481,7 +481,7 @@ static void on_dnsdist(h2o_socket_t *listener, const char *err) static void on_accept(h2o_socket_t *listener, const char *err) { - DOHServerConfig* dsc = (DOHServerConfig*)listener->data; + DOHServerConfig* dsc = reinterpret_cast(listener->data); h2o_socket_t *sock = nullptr; if (err != nullptr) { @@ -501,16 +501,16 @@ static void on_accept(h2o_socket_t *listener, const char *err) h2o_accept(&dsc->h2o_accept_ctx, sock); } -static int create_listener(const ComboAddress& addr, DOHServerConfig* dsc, int fd) +static int create_listener(const ComboAddress& addr, std::shared_ptr& dsc, int fd) { auto sock = h2o_evloop_socket_create(dsc->h2o_ctx.loop, fd, H2O_SOCKET_FLAG_DONT_READ); - sock->data = (void*) dsc; + sock->data = dsc.get(); h2o_socket_read_start(sock, on_accept); return 0; } -static int setup_ssl(DOHServerConfig* dsc, const char *cert_file, const char *key_file, const char *ciphers) +static int setup_ssl(std::shared_ptr& dsc, const std::string& cert_file, const std::string& key_file, const std::string& ciphers, const std::string& ciphers13) { SSL_load_error_strings(); SSL_library_init(); @@ -525,20 +525,27 @@ static int setup_ssl(DOHServerConfig* dsc, const char *cert_file, const char *ke #endif /* load certificate and private key */ - if (SSL_CTX_use_certificate_chain_file(dsc->h2o_accept_ctx.ssl_ctx, cert_file) != 1) { - fprintf(stderr, "an error occurred while trying to load server certificate file:%s\n", cert_file); + if (SSL_CTX_use_certificate_chain_file(dsc->h2o_accept_ctx.ssl_ctx, cert_file.c_str()) != 1) { + errlog("An error occurred while trying to load the DOH server certificate file: %s", cert_file); return -1; } - if (SSL_CTX_use_PrivateKey_file(dsc->h2o_accept_ctx.ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { - fprintf(stderr, "an error occurred while trying to load private key file:%s\n", key_file); + if (SSL_CTX_use_PrivateKey_file(dsc->h2o_accept_ctx.ssl_ctx, key_file.c_str(), SSL_FILETYPE_PEM) != 1) { + errlog("An error occurred while trying to load the DOH server private key file: %s", key_file); return -1; } - if (SSL_CTX_set_cipher_list(dsc->h2o_accept_ctx.ssl_ctx, ciphers) != 1) { - fprintf(stderr, "ciphers could not be set: %s\n", ciphers); + if (SSL_CTX_set_cipher_list(dsc->h2o_accept_ctx.ssl_ctx, ciphers.c_str()) != 1) { + errlog("DOH ciphers could not be set: %s\n", ciphers); return -1; } +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES + if (!ciphers13.empty() && SSL_CTX_set_ciphersuites(dsc->h2o_accept_ctx.ssl_ctx, ciphers13.c_str()) != 1) { + errlog("DOH TLS 1.3 ciphers could not be set: %s", ciphers13); + return -1; + } +#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */ + h2o_ssl_register_alpn_protocols(dsc->h2o_accept_ctx.ssl_ctx, h2o_http2_alpn_protocols); return 0; @@ -546,6 +553,14 @@ static int setup_ssl(DOHServerConfig* dsc, const char *cert_file, const char *ke void DOHFrontend::setup() { + d_dsc = std::make_shared(d_idleTimeout); + + // we should probably make that hash, algorithm etc line configurable too + if (setup_ssl(d_dsc, d_certFile, d_keyFile, + d_ciphers.empty() ? "DEFAULT:!MD5:!DSS:!DES:!RC4:!RC2:!SEED:!IDEA:!NULL:!ADH:!EXP:!SRP:!PSK" : d_ciphers, + d_ciphers13) != 0) { + throw std::runtime_error("Failed to setup SSL/TLS for DoH listener"); + } } // this is the entrypoint from dnsdist.cc @@ -553,7 +568,9 @@ void dohThread(ClientState* cs) try { std::shared_ptr& df = cs->dohFrontend; - auto dsc = new DOHServerConfig(cs); + auto& dsc = df->d_dsc; + dsc->cs = cs; + dsc->df = cs->dohFrontend; std::thread dnsdistThread(dnsdistclient, dsc->dohquerypair[1], dsc->dohresponsepair[0]); dnsdistThread.detach(); // gets us better error reporting @@ -570,20 +587,15 @@ try // in this complicated way we insert the DOHServerConfig pointer in there h2o_vector_reserve(nullptr, &dsc->h2o_ctx.storage, 1); - dsc->h2o_ctx.storage.entries[0].data = (void*)dsc; + dsc->h2o_ctx.storage.entries[0].data = dsc.get(); ++dsc->h2o_ctx.storage.size; auto sock = h2o_evloop_socket_create(dsc->h2o_ctx.loop, dsc->dohresponsepair[1], H2O_SOCKET_FLAG_DONT_READ); - sock->data = dsc; + sock->data = dsc.get(); // this listens to responses from dnsdist to turn into http responses h2o_socket_read_start(sock, on_dnsdist); - // we should probably make that hash, algorithm etc line configurable too - if(setup_ssl(dsc, df->d_certFile.c_str(), df->d_keyFile.c_str(), - "DEFAULT:!MD5:!DSS:!DES:!RC4:!RC2:!SEED:!IDEA:!NULL:!ADH:!EXP:!SRP:!PSK") != 0) - throw std::runtime_error("Failed to setup SSL/TLS for DoH listener"); - // as one does dsc->h2o_accept_ctx.ctx = &dsc->h2o_ctx; dsc->h2o_accept_ctx.hosts = dsc->h2o_config.hosts; diff --git a/pdns/dnsdistdist/doh.hh b/pdns/dnsdistdist/doh.hh index 58d1ae56b0..cf0c04fa7a 100644 --- a/pdns/dnsdistdist/doh.hh +++ b/pdns/dnsdistdist/doh.hh @@ -1,10 +1,15 @@ #pragma once #include "iputils.hh" +struct DOHServerConfig; + struct DOHFrontend { + std::shared_ptr d_dsc{nullptr}; std::string d_certFile; std::string d_keyFile; + std::string d_ciphers; + std::string d_ciphers13; ComboAddress d_local; uint32_t d_idleTimeout{30}; // HTTP idle timeout in seconds @@ -25,6 +30,11 @@ struct DOHFrontend std::atomic d_errorresponses; // dnsdist set 'error' on response std::atomic d_validresponses; // valid responses sent out + void reloadCertificate() + { + // XXX: not implemented yet + } + #ifndef HAVE_DNS_OVER_HTTPS void setup() { diff --git a/pdns/dnsdistdist/m4/dnsdist_with_libssl.m4 b/pdns/dnsdistdist/m4/dnsdist_with_libssl.m4 index 79489448d6..624a3d688f 100644 --- a/pdns/dnsdistdist/m4/dnsdist_with_libssl.m4 +++ b/pdns/dnsdistdist/m4/dnsdist_with_libssl.m4 @@ -13,6 +13,14 @@ AC_DEFUN([DNSDIST_WITH_LIBSSL], [ PKG_CHECK_MODULES([LIBSSL], [libssl], [ [HAVE_LIBSSL=1] AC_DEFINE([HAVE_LIBSSL], [1], [Define to 1 if you have OpenSSL libssl]) + save_CFLAGS=$CFLAGS + save_LIBS=$LIBS + CFLAGS="$LIBSSL_CFLAGS $CFLAGS" + LIBS="$LIBSSL_LIBS $LIBS" + AC_CHECK_FUNCS([SSL_CTX_set_ciphersuites]) + CFLAGS=$save_CFLAGS + LIBS=$save_LIBS + ], [ : ]) ]) ]) -- 2.39.2