{ "KeyValueStoreLookupRule", true, "kvs, lookupKey", "matches queries if the key is found in the specified Key Value store" },
{ "KeyValueStoreRangeLookupRule", true, "kvs, lookupKey", "matches queries if the key is found in the specified Key Value store" },
{ "leastOutstanding", false, "", "Send traffic to downstream server with least outstanding queries, with the lowest 'order', and within that the lowest recent latency"},
+#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
{ "loadTLSEngine", true, "engineName [, defaultString]", "Load the OpenSSL engine named 'engineName', setting the engine default string to 'defaultString' if supplied"},
+#endif
+#if defined(HAVE_LIBSSL) && OPENSSL_VERSION_MAJOR >= 3 && defined(HAVE_TLS_PROVIDERS)
+ { "loadTLSProvider", true, "providerName", "Load the OpenSSL provider named 'providerName'"},
+#endif
{ "LogAction", true, "[filename], [binary], [append], [buffered]", "Log a line for each query, to the specified file if any, to the console (require verbose) otherwise. When logging to a file, the `binary` optional parameter specifies whether we log in binary form (default) or in textual form, the `append` optional parameter specifies whether we open the file for appending or truncate each time (default), and the `buffered` optional parameter specifies whether writes to the file are buffered (default) or not." },
{ "LogResponseAction", true, "[filename], [append], [buffered]", "Log a line for each response, to the specified file if any, to the console (require verbose) otherwise. The `append` optional parameter specifies whether we open the file for appending or truncate each time (default), and the `buffered` optional parameter specifies whether writes to the file are buffered (default) or not." },
{ "LuaAction", true, "function", "Invoke a Lua function that accepts a DNSQuestion" },
{ "TCPRule", true, "[tcp]", "Matches question received over TCP if tcp is true, over UDP otherwise" },
{ "TeeAction", true, "remote [, addECS [, local]]", "send copy of query to remote, optionally adding ECS info, optionally set local address" },
{ "testCrypto", true, "", "test of the crypto all works" },
- { "TimedIPSetRule", true, "", "Create a rule which matches a set of IP addresses which expire"},
+ { "TimedIPSetRule", true, "", "Create a rule which matches a set of IP addresses which expire"},
{ "topBandwidth", true, "top", "show top-`top` clients that consume the most bandwidth over length of ringbuffer" },
{ "topCacheHitResponseRules", true, "[top][, vars]", "show `top` cache-hit response rules" },
{ "topCacheInsertedResponseRules", true, "[top][, vars]", "show `top` cache-inserted response rules" },
DownstreamState::s_randomizeIDs = randomized;
});
-#if defined(HAVE_LIBSSL)
+#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
luaCtx.writeFunction("loadTLSEngine", [client](const std::string& engineName, boost::optional<std::string> defaultString) {
if (client) {
return;
errlog("Error while trying to load TLS engine '%s': %s", engineName, error);
}
});
-#endif /* HAVE_LIBSSL */
+#endif /* HAVE_LIBSSL && !HAVE_TLS_PROVIDERS */
+
+#if defined(HAVE_LIBSSL) && OPENSSL_VERSION_MAJOR >= 3 && defined(HAVE_TLS_PROVIDERS)
+ luaCtx.writeFunction("loadTLSProvider", [client](const std::string& providerName) {
+ if (client) {
+ return;
+ }
+
+ auto [success, error] = libssl_load_provider(providerName);
+ if (!success) {
+ g_outputBuffer = "Error while trying to load TLS provider '" + providerName + "': " + error + "\n";
+ errlog("Error while trying to load TLS provider '%s': %s", providerName, error);
+ }
+ });
+#endif /* HAVE_LIBSSL && OPENSSL_VERSION_MAJOR >= 3 && HAVE_TLS_PROVIDERS */
luaCtx.writeFunction("newThread", [client, configCheck](const std::string& code) {
if (client || configCheck) {
PDNS_CHECK_LIBCRYPTO
+DNSDIST_ENABLE_TLS_PROVIDERS
+
PDNS_ENABLE_DNS_OVER_TLS
DNSDIST_ENABLE_DNS_OVER_HTTPS
* ``maxConcurrentTCPConnections=0``: int - Maximum number of concurrent incoming TCP connections. The default is 0 which means unlimited.
* ``releaseBuffers=true``: bool - Whether OpenSSL should release its I/O buffers when a connection goes idle, saving roughly 35 kB of memory per connection.
* ``enableRenegotiation=false``: bool - Whether secure TLS renegotiation should be enabled (OpenSSL only, the GnuTLS provider does not support it). Disabled by default since it increases the attack surface and is seldom used for DNS.
- * ``tlsAsyncMode=false``: bool - Whether to enable experimental asynchronous TLS I/O operations if OpenSSL is used as the TLS provider and an asynchronous capable SSL engine is loaded. See also :func:`loadTLSEngine` to load the engine.
+ * ``tlsAsyncMode=false``: bool - Whether to enable experimental asynchronous TLS I/O operations if 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).
* ``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
:param string engineName: The name of the engine to load.
:param string defaultString: The default string to pass to the engine. The exact value depends on the engine but represents the algorithms to register with the engine, as a list of comma-separated keywords. For example "RSA,EC,DSA,DH,PKEY,PKEY_CRYPTO,PKEY_ASN1".
+.. function:: loadTLSProvider(providerName)
+
+ .. versionadded:: 1.8.0
+
+ Load the OpenSSL provider named ``providerName``. Providers can be used to accelerate cryptographic operations, like for example Intel QAT.
+ At the moment up to a maximum of 32 loaded providers are supported, and that support is experimental.
+ Note that :func:`loadTLSProvider` is only available when building against OpenSSL version >= 3.0 and with the `--enable-tls-provider` configure flag on. In other cases, :func:`loadTLSEngine` should be used instead.
+ Some providers might actually degrade performance unless the TLS asynchronous mode of OpenSSL is enabled. To enable it see the ``tlsAsyncMode`` parameter on :func:`addTLSLocal`.
+
+ :param string providerName: The name of the provider to load.
+
.. function:: newTLSCertificate(pathToCert[, options])
.. versionadded:: 1.8.0
--- /dev/null
+AC_DEFUN([DNSDIST_ENABLE_TLS_PROVIDERS], [
+ AC_MSG_CHECKING([whether to enable OpenSSL >= 3.0 TLS providers (experimental)])
+ AC_ARG_ENABLE([tls-providers],
+ AS_HELP_STRING([--enable-tls-providers], [enable TLS providers (experimental and requires OpenSSL >= 3.0) @<:@default=no@:>@]),
+ [enable_tls_providers=$enableval],
+ [enable_tls_providers=no]
+ )
+ AC_MSG_RESULT([$enable_tls_providers])
+ AM_CONDITIONAL([HAVE_TLS_PROVIDERS], [test "x$enable_tls_providers" != "xno"])
+
+ PKG_CHECK_MODULES([LIBSSL], [libssl >= 3.0], [
+ [HAVE_LIBSSL_3_PLUS=1]
+ AC_DEFINE([HAVE_LIBSSL_3_PLUS], [1], [Define to 1 if you have OpenSSL >= 3.0])
+ ], [ : ])
+
+ AM_COND_IF([HAVE_TLS_PROVIDERS], [
+ AC_DEFINE([HAVE_TLS_PROVIDERS], [1], [Define to 1 if you enable OpenSSL >= 3.0 TLS providers])
+ AS_IF([test "x$HAVE_LIBSSL_3_PLUS" != "x1"], [
+ AC_MSG_ERROR([TLS providers support requires OpenSSL >= 3.0])
+ ])
+ ])
+])
#if OPENSSL_VERSION_MAJOR >= 3
#include <openssl/param_build.h>
+#include <openssl/core.h>
#include <openssl/core_names.h>
#include <openssl/evp.h>
#endif
#endif /* (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2090100fL) */
static std::atomic<uint64_t> s_users;
+
+#if OPENSSL_VERSION_MAJOR >= 3 && defined(HAVE_TLS_PROVIDERS)
+static LockGuarded<std::unordered_map<std::string, std::unique_ptr<OSSL_PROVIDER, decltype(&OSSL_PROVIDER_unload)>>> s_providers;
+#else
#ifndef OPENSSL_NO_ENGINE
static LockGuarded<std::unordered_map<std::string, std::unique_ptr<ENGINE, int(*)(ENGINE*)>>> s_engines;
#endif
+#endif
+
static int s_ticketsKeyIndex{-1};
static int s_countersIndex{-1};
static int s_keyLogIndex{-1};
void unregisterOpenSSLUser()
{
if (s_users.fetch_sub(1) == 1) {
+#if OPENSSL_VERSION_MAJOR < 3 || !defined(HAVE_TLS_PROVIDERS)
#ifndef OPENSSL_NO_ENGINE
for (auto& [name, engine] : *s_engines.lock()) {
ENGINE_finish(engine.get());
}
s_engines.lock()->clear();
#endif
+#endif
#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || (defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER < 0x2090100fL))
ERR_free_strings();
}
}
+#if defined(HAVE_LIBSSL) && OPENSSL_VERSION_MAJOR >= 3 && defined(HAVE_TLS_PROVIDERS)
+std::pair<bool, std::string> libssl_load_provider(const std::string& providerName)
+{
+ if (s_users.load() == 0) {
+ /* We need to make sure that OpenSSL has been properly initialized before loading an engine.
+ This messes up our accounting a bit, so some memory might not be properly released when
+ the program exits when engines are in use. */
+ registerOpenSSLUser();
+ }
+
+ auto providers = s_providers.lock();
+ if (providers->count(providerName) > 0) {
+ return { false, "TLS provider already loaded" };
+ }
+
+ auto provider = std::unique_ptr<OSSL_PROVIDER, decltype(&OSSL_PROVIDER_unload)>(OSSL_PROVIDER_load(nullptr, providerName.c_str()), OSSL_PROVIDER_unload);
+ if (provider == nullptr) {
+ return { false, "unable to load TLS provider '" + providerName + "'" };
+ }
+
+ providers->insert({providerName, std::move(provider)});
+ return { true, "" };
+}
+#endif /* HAVE_LIBSSL && OPENSSL_VERSION_MAJOR >= 3 && HAVE_TLS_PROVIDERS */
+
+#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
std::pair<bool, std::string> libssl_load_engine(const std::string& engineName, const std::optional<std::string>& defaultString)
{
#ifdef OPENSSL_NO_ENGINE
return { true, "" };
#endif
}
+#endif /* HAVE_LIBSSL && !HAVE_TLS_PROVIDERS */
void* libssl_get_ticket_key_callback_data(SSL* s)
{
std::string libssl_get_error_string();
+#if defined(HAVE_LIBSSL) && OPENSSL_VERSION_MAJOR >= 3 && defined(HAVE_TLS_PROVIDERS)
+std::pair<bool, std::string> libssl_load_provider(const std::string& engineName);
+#endif /* HAVE_LIBSSL && OPENSSL_VERSION_MAJOR >= 3 && HAVE_TLS_PROVIDERS */
+
+#if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
std::pair<bool, std::string> libssl_load_engine(const std::string& engineName, const std::optional<std::string>& defaultString);
+#endif /* HAVE_LIBSSL && !HAVE_TLS_PROVIDERS */
#endif /* HAVE_LIBSSL */