summaryrefslogtreecommitdiffstats
path: root/dnsdist-lua.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:14:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 21:14:51 +0000
commitbc282425088455198a7a99511c75914477d4ed32 (patch)
tree1b1fb887a634136a093deea7e4dd95d054201e7a /dnsdist-lua.cc
parentReleasing progress-linux version 1.8.3-3~progress7.99u1. (diff)
downloaddnsdist-bc282425088455198a7a99511c75914477d4ed32.tar.xz
dnsdist-bc282425088455198a7a99511c75914477d4ed32.zip
Merging upstream version 1.9.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dnsdist-lua.cc')
-rw-r--r--dnsdist-lua.cc1081
1 files changed, 795 insertions, 286 deletions
diff --git a/dnsdist-lua.cc b/dnsdist-lua.cc
index fa1b8b6..73a8567 100644
--- a/dnsdist-lua.cc
+++ b/dnsdist-lua.cc
@@ -21,6 +21,7 @@
*/
#include <cstdint>
+#include <cstdio>
#include <dirent.h>
#include <fstream>
#include <cinttypes>
@@ -39,11 +40,14 @@
#include "dnsdist-carbon.hh"
#include "dnsdist-concurrent-connections.hh"
#include "dnsdist-console.hh"
+#include "dnsdist-crypto.hh"
#include "dnsdist-dynblocks.hh"
#include "dnsdist-discovery.hh"
#include "dnsdist-ecs.hh"
#include "dnsdist-healthchecks.hh"
#include "dnsdist-lua.hh"
+#include "dnsdist-lua-hooks.hh"
+#include "xsk.hh"
#ifdef LUAJIT_VERSION
#include "dnsdist-lua-ffi.hh"
#endif /* LUAJIT_VERSION */
@@ -57,8 +61,10 @@
#include "dnsdist-web.hh"
#include "base64.hh"
+#include "coverage.hh"
+#include "doh.hh"
+#include "doq-common.hh"
#include "dolog.hh"
-#include "sodcrypto.hh"
#include "threadname.hh"
#ifdef HAVE_LIBSSL
@@ -107,14 +113,15 @@ void resetLuaSideEffect()
g_noLuaSideEffect = boost::logic::indeterminate;
}
-using localbind_t = LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int>, LuaArray<std::string>, LuaAssociativeTable<std::string>>>;
+using localbind_t = LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int>, LuaArray<std::string>, LuaAssociativeTable<std::string>, std::shared_ptr<XskSocket>>>;
-static void parseLocalBindVars(boost::optional<localbind_t>& vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus, int& tcpListenQueueSize, uint64_t& maxInFlightQueriesPerConnection, uint64_t& tcpMaxConcurrentConnections)
+static void parseLocalBindVars(boost::optional<localbind_t>& vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus, int& tcpListenQueueSize, uint64_t& maxInFlightQueriesPerConnection, uint64_t& tcpMaxConcurrentConnections, bool& enableProxyProtocol)
{
if (vars) {
LuaArray<int> setCpus;
getOptionalValue<bool>(vars, "reusePort", reusePort);
+ getOptionalValue<bool>(vars, "enableProxyProtocol", enableProxyProtocol);
getOptionalValue<int>(vars, "tcpFastOpenQueueSize", tcpFastOpenQueueSize);
getOptionalValue<int>(vars, "tcpListenQueueSize", tcpListenQueueSize);
getOptionalValue<int>(vars, "maxConcurrentTCPConnections", tcpMaxConcurrentConnections);
@@ -127,9 +134,19 @@ static void parseLocalBindVars(boost::optional<localbind_t>& vars, bool& reusePo
}
}
}
+#ifdef HAVE_XSK
+static void parseXskVars(boost::optional<localbind_t>& vars, std::shared_ptr<XskSocket>& socket)
+{
+ if (!vars) {
+ return;
+ }
-#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
-static bool loadTLSCertificateAndKeys(const std::string& context, std::vector<TLSCertKeyPair>& pairs, boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, LuaTypeOrArrayOf<std::string> keyFiles)
+ getOptionalValue<std::shared_ptr<XskSocket>>(vars, "xskSocket", socket);
+}
+#endif /* HAVE_XSK */
+
+#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS) || defined(HAVE_DNS_OVER_QUIC)
+static bool loadTLSCertificateAndKeys(const std::string& context, std::vector<TLSCertKeyPair>& pairs, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const LuaTypeOrArrayOf<std::string>& keyFiles)
{
if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) {
auto certFile = boost::get<std::string>(certFiles);
@@ -225,6 +242,7 @@ static void parseTLSConfig(TLSConfig& config, const std::string& context, boost:
getOptionalValue<bool>(vars, "enableRenegotiation", config.d_enableRenegotiation);
getOptionalValue<bool>(vars, "tlsAsyncMode", config.d_asyncMode);
getOptionalValue<bool>(vars, "ktls", config.d_ktls);
+ getOptionalValue<bool>(vars, "readAhead", config.d_readAhead);
}
#endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
@@ -256,7 +274,7 @@ static void LuaThread(const std::string& code)
// maybe offer more than `void`
auto func = lua->readVariable<boost::optional<std::function<void(std::string cmd, LuaAssociativeTable<std::string> data)>>>("threadmessage");
if (func) {
- func.get()(cmd, data);
+ func.get()(std::move(cmd), std::move(data));
}
else {
errlog("Lua thread called submitToMainThread but no threadmessage receiver is defined");
@@ -280,13 +298,6 @@ static void LuaThread(const std::string& code)
}
}
-#ifdef COVERAGE
-extern "C"
-{
- void __gcov_dump(void);
-}
-#endif
-
static bool checkConfigurationTime(const std::string& name)
{
if (!g_configurationDone) {
@@ -297,9 +308,101 @@ static bool checkConfigurationTime(const std::string& name)
return false;
}
+using newserver_t = LuaAssociativeTable<boost::variant<bool, std::string, LuaArray<std::string>, LuaArray<std::shared_ptr<XskSocket>>, DownstreamState::checkfunc_t>>;
+
+static void handleNewServerHealthCheckParameters(boost::optional<newserver_t>& vars, DownstreamState::Config& config)
+{
+ std::string valueStr;
+
+ if (getOptionalValue<std::string>(vars, "checkInterval", valueStr) > 0) {
+ config.checkInterval = static_cast<unsigned int>(std::stoul(valueStr));
+ }
+
+ if (getOptionalValue<std::string>(vars, "healthCheckMode", valueStr) > 0) {
+ const auto& mode = valueStr;
+ if (pdns_iequals(mode, "auto")) {
+ config.availability = DownstreamState::Availability::Auto;
+ }
+ else if (pdns_iequals(mode, "lazy")) {
+ config.availability = DownstreamState::Availability::Lazy;
+ }
+ else if (pdns_iequals(mode, "up")) {
+ config.availability = DownstreamState::Availability::Up;
+ }
+ else if (pdns_iequals(mode, "down")) {
+ config.availability = DownstreamState::Availability::Down;
+ }
+ else {
+ warnlog("Ignoring unknown value '%s' for 'healthCheckMode' on 'newServer'", mode);
+ }
+ }
+
+ if (getOptionalValue<std::string>(vars, "checkName", valueStr) > 0) {
+ config.checkName = DNSName(valueStr);
+ }
+
+ getOptionalValue<std::string>(vars, "checkType", config.checkType);
+ getOptionalIntegerValue("newServer", vars, "checkClass", config.checkClass);
+ getOptionalValue<DownstreamState::checkfunc_t>(vars, "checkFunction", config.checkFunction);
+ getOptionalIntegerValue("newServer", vars, "checkTimeout", config.checkTimeout);
+ getOptionalValue<bool>(vars, "checkTCP", config.d_tcpCheck);
+ getOptionalValue<bool>(vars, "setCD", config.setCD);
+ getOptionalValue<bool>(vars, "mustResolve", config.mustResolve);
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckSampleSize", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckSampleSize", value);
+ config.d_lazyHealthCheckSampleSize = value;
+ }
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckMinSampleCount", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckMinSampleCount", value);
+ config.d_lazyHealthCheckMinSampleCount = value;
+ }
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckThreshold", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckThreshold", value, std::numeric_limits<uint8_t>::max());
+ config.d_lazyHealthCheckThreshold = value;
+ }
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckFailedInterval", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckFailedInterval", value);
+ config.d_lazyHealthCheckFailedInterval = value;
+ }
+
+ getOptionalValue<bool>(vars, "lazyHealthCheckUseExponentialBackOff", config.d_lazyHealthCheckUseExponentialBackOff);
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckMaxBackOff", valueStr) > 0) {
+ const auto& value = std::stoi(valueStr);
+ checkParameterBound("lazyHealthCheckMaxBackOff", value);
+ config.d_lazyHealthCheckMaxBackOff = value;
+ }
+
+ if (getOptionalValue<std::string>(vars, "lazyHealthCheckMode", valueStr) > 0) {
+ const auto& mode = valueStr;
+ if (pdns_iequals(mode, "TimeoutOnly")) {
+ config.d_lazyHealthCheckMode = DownstreamState::LazyHealthCheckMode::TimeoutOnly;
+ }
+ else if (pdns_iequals(mode, "TimeoutOrServFail")) {
+ config.d_lazyHealthCheckMode = DownstreamState::LazyHealthCheckMode::TimeoutOrServFail;
+ }
+ else {
+ warnlog("Ignoring unknown value '%s' for 'lazyHealthCheckMode' on 'newServer'", mode);
+ }
+ }
+
+ getOptionalValue<bool>(vars, "lazyHealthCheckWhenUpgraded", config.d_upgradeToLazyHealthChecks);
+
+ getOptionalIntegerValue("newServer", vars, "maxCheckFailures", config.maxCheckFailures);
+ getOptionalIntegerValue("newServer", vars, "rise", config.minRiseSuccesses);
+}
+
+// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
{
- typedef LuaAssociativeTable<boost::variant<bool, std::string, LuaArray<std::string>, DownstreamState::checkfunc_t>> newserver_t;
luaCtx.writeFunction("inClientStartup", [client]() {
return client && !g_configurationDone;
});
@@ -395,9 +498,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
getOptionalIntegerValue("newServer", vars, "tcpSendTimeout", config.tcpSendTimeout);
getOptionalIntegerValue("newServer", vars, "tcpRecvTimeout", config.tcpRecvTimeout);
- if (getOptionalValue<std::string>(vars, "checkInterval", valueStr) > 0) {
- config.checkInterval = static_cast<unsigned int>(std::stoul(valueStr));
- }
+ handleNewServerHealthCheckParameters(vars, config);
bool fastOpen{false};
if (getOptionalValue<bool>(vars, "tcpFastOpen", fastOpen) > 0) {
@@ -419,92 +520,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
config.id = boost::uuids::string_generator()(valueStr);
}
- if (getOptionalValue<std::string>(vars, "healthCheckMode", valueStr) > 0) {
- const auto& mode = valueStr;
- if (pdns_iequals(mode, "auto")) {
- config.availability = DownstreamState::Availability::Auto;
- }
- else if (pdns_iequals(mode, "lazy")) {
- config.availability = DownstreamState::Availability::Lazy;
- }
- else if (pdns_iequals(mode, "up")) {
- config.availability = DownstreamState::Availability::Up;
- }
- else if (pdns_iequals(mode, "down")) {
- config.availability = DownstreamState::Availability::Down;
- }
- else {
- warnlog("Ignoring unknown value '%s' for 'healthCheckMode' on 'newServer'", mode);
- }
- }
-
- if (getOptionalValue<std::string>(vars, "checkName", valueStr) > 0) {
- config.checkName = DNSName(valueStr);
- }
-
- getOptionalValue<std::string>(vars, "checkType", config.checkType);
- getOptionalIntegerValue("newServer", vars, "checkClass", config.checkClass);
- getOptionalValue<DownstreamState::checkfunc_t>(vars, "checkFunction", config.checkFunction);
- getOptionalIntegerValue("newServer", vars, "checkTimeout", config.checkTimeout);
- getOptionalValue<bool>(vars, "checkTCP", config.d_tcpCheck);
- getOptionalValue<bool>(vars, "setCD", config.setCD);
- getOptionalValue<bool>(vars, "mustResolve", config.mustResolve);
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckSampleSize", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckSampleSize", value);
- config.d_lazyHealthCheckSampleSize = value;
- }
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckMinSampleCount", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckMinSampleCount", value);
- config.d_lazyHealthCheckMinSampleCount = value;
- }
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckThreshold", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckThreshold", value, std::numeric_limits<uint8_t>::max());
- config.d_lazyHealthCheckThreshold = value;
- }
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckFailedInterval", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckFailedInterval", value);
- config.d_lazyHealthCheckFailedInterval = value;
- }
-
- getOptionalValue<bool>(vars, "lazyHealthCheckUseExponentialBackOff", config.d_lazyHealthCheckUseExponentialBackOff);
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckMaxBackOff", valueStr) > 0) {
- const auto& value = std::stoi(valueStr);
- checkParameterBound("lazyHealthCheckMaxBackOff", value);
- config.d_lazyHealthCheckMaxBackOff = value;
- }
-
- if (getOptionalValue<std::string>(vars, "lazyHealthCheckMode", valueStr) > 0) {
- const auto& mode = valueStr;
- if (pdns_iequals(mode, "TimeoutOnly")) {
- config.d_lazyHealthCheckMode = DownstreamState::LazyHealthCheckMode::TimeoutOnly;
- }
- else if (pdns_iequals(mode, "TimeoutOrServFail")) {
- config.d_lazyHealthCheckMode = DownstreamState::LazyHealthCheckMode::TimeoutOrServFail;
- }
- else {
- warnlog("Ignoring unknown value '%s' for 'lazyHealthCheckMode' on 'newServer'", mode);
- }
- }
-
- getOptionalValue<bool>(vars, "lazyHealthCheckWhenUpgraded", config.d_upgradeToLazyHealthChecks);
-
getOptionalValue<bool>(vars, "useClientSubnet", config.useECS);
getOptionalValue<bool>(vars, "useProxyProtocol", config.useProxyProtocol);
+ getOptionalValue<bool>(vars, "proxyProtocolAdvertiseTLS", config.d_proxyProtocolAdvertiseTLS);
getOptionalValue<bool>(vars, "disableZeroScope", config.disableZeroScope);
getOptionalValue<bool>(vars, "ipBindAddrNoPort", config.ipBindAddrNoPort);
getOptionalIntegerValue("newServer", vars, "addXPF", config.xpfRRCode);
- getOptionalIntegerValue("newServer", vars, "maxCheckFailures", config.maxCheckFailures);
- getOptionalIntegerValue("newServer", vars, "rise", config.minRiseSuccesses);
getOptionalValue<bool>(vars, "reconnectOnUp", config.reconnectOnUp);
@@ -547,8 +569,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
tlsCtx = getTLSContext(config.d_tlsParams);
if (getOptionalValue<std::string>(vars, "dohPath", valueStr) > 0) {
-#ifndef HAVE_NGHTTP2
- throw std::runtime_error("Outgoing DNS over HTTPS support requested (via 'dohPath' on newServer()) but nghttp2 support is not available");
+#if !defined(HAVE_DNS_OVER_HTTPS) || !defined(HAVE_NGHTTP2)
+ throw std::runtime_error("Outgoing DNS over HTTPS support requested (via 'dohPath' on newServer()) but it is not available");
#endif
serverPort = 443;
@@ -618,10 +640,39 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
// create but don't connect the socket in client or check-config modes
auto ret = std::make_shared<DownstreamState>(std::move(config), std::move(tlsCtx), !(client || configCheck));
- if (!(client || configCheck)) {
+#ifdef HAVE_XSK
+ LuaArray<std::shared_ptr<XskSocket>> luaXskSockets;
+ if (getOptionalValue<LuaArray<std::shared_ptr<XskSocket>>>(vars, "xskSockets", luaXskSockets) > 0 && !luaXskSockets.empty()) {
+ if (g_configurationDone) {
+ throw std::runtime_error("Adding a server with xsk at runtime is not supported");
+ }
+ std::vector<std::shared_ptr<XskSocket>> xskSockets;
+ for (auto& socket : luaXskSockets) {
+ xskSockets.push_back(socket.second);
+ }
+ ret->registerXsk(xskSockets);
+ std::string mac;
+ if (getOptionalValue<std::string>(vars, "MACAddr", mac) > 0) {
+ auto* addr = &ret->d_config.destMACAddr[0];
+ sscanf(mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", addr, addr + 1, addr + 2, addr + 3, addr + 4, addr + 5);
+ }
+ else {
+ mac = getMACAddress(ret->d_config.remote);
+ if (mac.size() != ret->d_config.destMACAddr.size()) {
+ throw runtime_error("Field 'MACAddr' is not set on 'newServer' directive for '" + ret->d_config.remote.toStringWithPort() + "' and cannot be retrieved from the system either!");
+ }
+ memcpy(ret->d_config.destMACAddr.data(), mac.data(), ret->d_config.destMACAddr.size());
+ }
+ infolog("Added downstream server %s via XSK in %s mode", ret->d_config.remote.toStringWithPort(), xskSockets.at(0)->getXDPMode());
+ }
+ else if (!(client || configCheck)) {
infolog("Added downstream server %s", ret->d_config.remote.toStringWithPort());
}
-
+#else /* HAVE_XSK */
+ if (!(client || configCheck)) {
+ infolog("Added downstream server %s", ret->d_config.remote.toStringWithPort());
+ }
+#endif /* HAVE_XSK */
if (autoUpgrade && ret->getProtocol() != dnsdist::Protocol::DoT && ret->getProtocol() != dnsdist::Protocol::DoH) {
dnsdist::ServiceDiscovery::addUpgradeableServer(ret, upgradeInterval, upgradePool, upgradeDoHKey, keepAfterUpgrade);
}
@@ -725,10 +776,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
uint64_t tcpMaxConcurrentConnections = 0;
std::string interface;
std::set<int> cpus;
+ bool enableProxyProtocol = true;
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections);
-
- checkAllParametersConsumed("setLocal", vars);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
try {
ComboAddress loc(addr, 53);
@@ -743,8 +793,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
// only works pre-startup, so no sync necessary
- g_frontends.push_back(std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus));
- auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ auto udpCS = std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
@@ -755,7 +805,21 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
tcpCS->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
+#ifdef HAVE_XSK
+ std::shared_ptr<XskSocket> socket;
+ parseXskVars(vars, socket);
+ if (socket) {
+ udpCS->xskInfo = XskWorker::create();
+ udpCS->xskInfo->sharedEmptyFrameOffset = socket->sharedEmptyFrameOffset;
+ socket->addWorker(udpCS->xskInfo);
+ socket->addWorkerRoute(udpCS->xskInfo, loc);
+ vinfolog("Enabling XSK in %s mode for incoming UDP packets to %s", socket->getXDPMode(), loc.toStringWithPort());
+ }
+#endif /* HAVE_XSK */
+ g_frontends.push_back(std::move(udpCS));
g_frontends.push_back(std::move(tcpCS));
+
+ checkAllParametersConsumed("setLocal", vars);
}
catch (const std::exception& e) {
g_outputBuffer = "Error: " + string(e.what()) + "\n";
@@ -777,15 +841,15 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
uint64_t tcpMaxConcurrentConnections = 0;
std::string interface;
std::set<int> cpus;
+ bool enableProxyProtocol = true;
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections);
- checkAllParametersConsumed("addLocal", vars);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
try {
ComboAddress loc(addr, 53);
// only works pre-startup, so no sync necessary
- g_frontends.push_back(std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus));
- auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ auto udpCS = std::make_unique<ClientState>(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ auto tcpCS = std::make_unique<ClientState>(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
if (tcpListenQueueSize > 0) {
tcpCS->tcpListenQueueSize = tcpListenQueueSize;
}
@@ -795,7 +859,21 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
if (tcpMaxConcurrentConnections > 0) {
tcpCS->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
+#ifdef HAVE_XSK
+ std::shared_ptr<XskSocket> socket;
+ parseXskVars(vars, socket);
+ if (socket) {
+ udpCS->xskInfo = XskWorker::create();
+ udpCS->xskInfo->sharedEmptyFrameOffset = socket->sharedEmptyFrameOffset;
+ socket->addWorker(udpCS->xskInfo);
+ socket->addWorkerRoute(udpCS->xskInfo, loc);
+ vinfolog("Enabling XSK in %s mode for incoming UDP packets to %s", socket->getXDPMode(), loc.toStringWithPort());
+ }
+#endif /* HAVE_XSK */
+ g_frontends.push_back(std::move(udpCS));
g_frontends.push_back(std::move(tcpCS));
+
+ checkAllParametersConsumed("addLocal", vars);
}
catch (std::exception& e) {
g_outputBuffer = "Error: " + string(e.what()) + "\n";
@@ -843,12 +921,11 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("showACL", []() {
setLuaNoSideEffect();
- vector<string> vec;
-
- g_ACL.getLocal()->toStringVector(&vec);
+ auto aclEntries = g_ACL.getLocal()->toStringVector();
- for (const auto& s : vec)
- g_outputBuffer += s + "\n";
+ for (const auto& entry : aclEntries) {
+ g_outputBuffer += entry + "\n";
+ }
});
luaCtx.writeFunction("shutdown", []() {
@@ -864,9 +941,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
g_tlslocals.clear();
g_rings.clear();
#endif /* 0 */
-#ifdef COVERAGE
- __gcov_dump();
-#endif
+ pdns::coverage::dumpCoverageData();
_exit(0);
});
@@ -942,7 +1017,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
LuaArray<std::shared_ptr<DownstreamState>> ret;
int count = 1;
for (const auto& s : g_dstates.getCopy()) {
- ret.push_back(make_pair(count++, s));
+ ret.emplace_back(count++, s);
}
return ret;
});
@@ -1107,23 +1182,22 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
g_consoleEnabled = true;
-#ifdef HAVE_LIBSODIUM
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
if (g_configurationDone && g_consoleKey.empty()) {
warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
}
#endif
try {
- int sock = SSocket(local.sin4.sin_family, SOCK_STREAM, 0);
- SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
- SBind(sock, local);
- SListen(sock, 5);
- auto launch = [sock, local]() {
- thread t(controlThread, sock, local);
- t.detach();
+ auto sock = std::make_shared<Socket>(local.sin4.sin_family, SOCK_STREAM, 0);
+ sock->bind(local, true);
+ sock->listen(5);
+ auto launch = [sock = std::move(sock), local]() {
+ std::thread consoleControlThread(controlThread, sock, local);
+ consoleControlThread.detach();
};
if (g_launchWork) {
- g_launchWork->push_back(launch);
+ g_launchWork->emplace_back(std::move(launch));
}
else {
launch();
@@ -1137,8 +1211,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("addConsoleACL", [](const std::string& netmask) {
setLuaSideEffect();
-#ifndef HAVE_LIBSODIUM
- warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
+#if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
+ warnlog("Allowing remote access to the console while neither libsodium not libcrypto support has been enabled is not secure, and will result in cleartext communications");
#endif
g_consoleACL.modify([netmask](NetmaskGroup& nmg) { nmg.addMask(netmask); });
@@ -1147,8 +1221,8 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("setConsoleACL", [](LuaTypeOrArrayOf<std::string> inp) {
setLuaSideEffect();
-#ifndef HAVE_LIBSODIUM
- warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
+#if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
+ warnlog("Allowing remote access to the console while neither libsodium nor libcrypto support has not been enabled is not secure, and will result in cleartext communications");
#endif
NetmaskGroup nmg;
@@ -1165,15 +1239,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("showConsoleACL", []() {
setLuaNoSideEffect();
-#ifndef HAVE_LIBSODIUM
- warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
+#if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
+ warnlog("Allowing remote access to the console while neither libsodium nor libcrypto support has not been enabled is not secure, and will result in cleartext communications");
#endif
- vector<string> vec;
- g_consoleACL.getLocal()->toStringVector(&vec);
+ auto aclEntries = g_consoleACL.getLocal()->toStringVector();
- for (const auto& s : vec) {
- g_outputBuffer += s + "\n";
+ for (const auto& entry : aclEntries) {
+ g_outputBuffer += entry + "\n";
}
});
@@ -1212,20 +1285,20 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("setQueryCount", [](bool enabled) { g_qcount.enabled = enabled; });
luaCtx.writeFunction("setQueryCountFilter", [](QueryCountFilter func) {
- g_qcount.filter = func;
+ g_qcount.filter = std::move(func);
});
luaCtx.writeFunction("makeKey", []() {
setLuaNoSideEffect();
- g_outputBuffer = "setKey(" + newKey() + ")\n";
+ g_outputBuffer = "setKey(" + dnsdist::crypto::authenticated::newKey() + ")\n";
});
luaCtx.writeFunction("setKey", [](const std::string& key) {
if (!g_configurationDone && !g_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
return; // but later setKeys() trump the -k value again
}
-#ifndef HAVE_LIBSODIUM
- warnlog("Calling setKey() while libsodium support has not been enabled is not secure, and will result in cleartext communications");
+#if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
+ warnlog("Calling setKey() while neither libsodium nor libcrypto support has been enabled is not secure, and will result in cleartext communications");
#endif
setLuaSideEffect();
@@ -1235,7 +1308,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
errlog("%s", g_outputBuffer);
}
else
- g_consoleKey = newkey;
+ g_consoleKey = std::move(newkey);
});
luaCtx.writeFunction("clearConsoleHistory", []() {
@@ -1244,7 +1317,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.writeFunction("testCrypto", [](boost::optional<string> optTestMsg) {
setLuaNoSideEffect();
-#ifdef HAVE_LIBSODIUM
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
try {
string testmsg;
@@ -1255,22 +1328,25 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
testmsg = "testStringForCryptoTests";
}
- SodiumNonce sn, sn2;
- sn.init();
- sn2 = sn;
- string encrypted = sodEncryptSym(testmsg, g_consoleKey, sn);
- string decrypted = sodDecryptSym(encrypted, g_consoleKey, sn2);
+ dnsdist::crypto::authenticated::Nonce nonce1;
+ dnsdist::crypto::authenticated::Nonce nonce2;
+ nonce1.init();
+ nonce2 = nonce1;
+ string encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
+ string decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
- sn.increment();
- sn2.increment();
+ nonce1.increment();
+ nonce2.increment();
- encrypted = sodEncryptSym(testmsg, g_consoleKey, sn);
- decrypted = sodDecryptSym(encrypted, g_consoleKey, sn2);
+ encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
+ decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
- if (testmsg == decrypted)
+ if (testmsg == decrypted) {
g_outputBuffer = "Everything is ok!\n";
- else
+ }
+ else {
g_outputBuffer = "Crypto failed.. (the decoded value does not match the cleartext one)\n";
+ }
}
catch (const std::exception& e) {
g_outputBuffer = "Crypto failed: " + std::string(e.what()) + "\n";
@@ -1337,6 +1413,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setTCPDownstreamMaxIdleConnectionsPerBackend(max);
});
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
luaCtx.writeFunction("setMaxIdleDoHConnectionsPerDownstream", [](uint64_t max) {
setDoHDownstreamMaxIdleConnectionsPerBackend(max);
});
@@ -1347,6 +1424,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
g_outgoingDoHWorkerThreads = workers;
});
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
luaCtx.writeFunction("setOutgoingTLSSessionsCacheMaxTicketsPerBackend", [](uint64_t max) {
if (!checkConfigurationTime("setOutgoingTLSSessionsCacheMaxTicketsPerBackend")) {
@@ -1421,6 +1499,58 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
});
});
+ luaCtx.writeFunction("getDynamicBlocks", []() {
+ setLuaNoSideEffect();
+ struct timespec now
+ {
+ };
+ gettime(&now);
+
+ LuaAssociativeTable<DynBlock> entries;
+ auto fullCopy = g_dynblockNMG.getCopy();
+ for (const auto& blockPair : fullCopy) {
+ const auto& requestor = blockPair.first;
+ if (!(now < blockPair.second.until)) {
+ continue;
+ }
+ auto entry = blockPair.second;
+ if (g_defaultBPFFilter && entry.bpf) {
+ entry.blocks += g_defaultBPFFilter->getHits(requestor.getNetwork());
+ }
+ if (entry.action == DNSAction::Action::None) {
+ entry.action = g_dynBlockAction;
+ }
+ entries.emplace(requestor.toString(), std::move(entry));
+ }
+ return entries;
+ });
+
+ luaCtx.writeFunction("getDynamicBlocksSMT", []() {
+ setLuaNoSideEffect();
+ struct timespec now
+ {
+ };
+ gettime(&now);
+
+ LuaAssociativeTable<DynBlock> entries;
+ auto fullCopy = g_dynblockSMT.getCopy();
+ fullCopy.visit([&now, &entries](const SuffixMatchTree<DynBlock>& node) {
+ if (!(now < node.d_value.until)) {
+ return;
+ }
+ auto entry = node.d_value;
+ string key("empty");
+ if (!entry.domain.empty()) {
+ key = entry.domain.toString();
+ }
+ if (entry.action == DNSAction::Action::None) {
+ entry.action = g_dynBlockAction;
+ }
+ entries.emplace(std::move(key), std::move(entry));
+ });
+ return entries;
+ });
+
luaCtx.writeFunction("clearDynBlocks", []() {
setLuaSideEffect();
nmts_t nmg;
@@ -1466,61 +1596,87 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
if (!got || expired) {
warnlog("Inserting dynamic block for %s for %d seconds: %s", capair.first.toString(), actualSeconds, msg);
}
- slow.insert(requestor).second = db;
+ slow.insert(requestor).second = std::move(db);
}
g_dynblockNMG.setState(slow);
});
+ luaCtx.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
+ if (!checkConfigurationTime("setDynBlocksAction")) {
+ return;
+ }
+ if (action == DNSAction::Action::Drop || action == DNSAction::Action::NoOp || action == DNSAction::Action::Nxdomain || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate || action == DNSAction::Action::NoRecurse) {
+ g_dynBlockAction = action;
+ }
+ else {
+ errlog("Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!");
+ g_outputBuffer = "Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!\n";
+ }
+ });
+#endif /* DISABLE_DEPRECATED_DYNBLOCK */
+
luaCtx.writeFunction("addDynBlockSMT",
[](const LuaArray<std::string>& names, const std::string& msg, boost::optional<int> seconds, boost::optional<DNSAction::Action> action) {
if (names.empty()) {
return;
}
setLuaSideEffect();
- auto slow = g_dynblockSMT.getCopy();
- struct timespec until, now;
+ struct timespec now
+ {
+ };
gettime(&now);
- until = now;
- int actualSeconds = seconds ? *seconds : 10;
- until.tv_sec += actualSeconds;
+ unsigned int actualSeconds = seconds ? *seconds : 10;
+ bool needUpdate = false;
+ auto slow = g_dynblockSMT.getCopy();
for (const auto& capair : names) {
- unsigned int count = 0;
DNSName domain(capair.second);
domain.makeUsLowerCase();
- auto got = slow.lookup(domain);
- bool expired = false;
- if (got) {
- if (until < got->until) // had a longer policy
- continue;
- if (now < got->until) // only inherit count on fresh query we are extending
- count = got->blocks;
- else
- expired = true;
+
+ if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, msg, actualSeconds, action ? *action : DNSAction::Action::None, false)) {
+ needUpdate = true;
}
+ }
- DynBlock db{msg, until, domain, (action ? *action : DNSAction::Action::None)};
- db.blocks = count;
- if (!got || expired)
- warnlog("Inserting dynamic block for %s for %d seconds: %s", domain, actualSeconds, msg);
- slow.add(domain, std::move(db));
+ if (needUpdate) {
+ g_dynblockSMT.setState(slow);
}
- g_dynblockSMT.setState(slow);
});
- luaCtx.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
- if (!checkConfigurationTime("setDynBlocksAction")) {
- return;
- }
- if (action == DNSAction::Action::Drop || action == DNSAction::Action::NoOp || action == DNSAction::Action::Nxdomain || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate || action == DNSAction::Action::NoRecurse) {
- g_dynBlockAction = action;
- }
- else {
- errlog("Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!");
- g_outputBuffer = "Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!\n";
- }
- });
-#endif /* DISABLE_DEPRECATED_DYNBLOCK */
+ luaCtx.writeFunction("addDynamicBlock",
+ [](const boost::variant<ComboAddress, std::string>& clientIP, const std::string& msg, const boost::optional<DNSAction::Action> action, const boost::optional<int> seconds, boost::optional<uint8_t> clientIPMask, boost::optional<uint8_t> clientIPPortMask) {
+ setLuaSideEffect();
+
+ ComboAddress clientIPCA;
+ if (clientIP.type() == typeid(ComboAddress)) {
+ clientIPCA = boost::get<ComboAddress>(clientIP);
+ }
+ else {
+ const auto& clientIPStr = boost::get<std::string>(clientIP);
+ try {
+ clientIPCA = ComboAddress(clientIPStr);
+ }
+ catch (const std::exception& exp) {
+ errlog("addDynamicBlock: Unable to parse '%s': %s", clientIPStr, exp.what());
+ return;
+ }
+ catch (const PDNSException& exp) {
+ errlog("addDynamicBlock: Unable to parse '%s': %s", clientIPStr, exp.reason);
+ return;
+ }
+ }
+ AddressAndPortRange target(clientIPCA, clientIPMask ? *clientIPMask : (clientIPCA.isIPv4() ? 32 : 128), clientIPPortMask ? *clientIPPortMask : 0);
+ unsigned int actualSeconds = seconds ? *seconds : 10;
+
+ struct timespec now
+ {
+ };
+ gettime(&now);
+ auto slow = g_dynblockNMG.getCopy();
+ if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, msg, actualSeconds, action ? *action : DNSAction::Action::None, false, false)) {
+ g_dynblockNMG.setState(slow);
+ }
+ });
luaCtx.writeFunction("setDynBlocksPurgeInterval", [](uint64_t interval) {
DynBlockMaintenance::s_expiredDynBlocksPurgeInterval = interval;
@@ -1540,14 +1696,15 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
std::string interface;
std::set<int> cpus;
std::vector<DNSCryptContext::CertKeyPaths> certKeys;
+ bool enableProxyProtocol = true;
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
checkAllParametersConsumed("addDNSCryptBind", vars);
if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) {
auto certFile = boost::get<std::string>(certFiles);
auto keyFile = boost::get<std::string>(keyFiles);
- certKeys.push_back({certFile, keyFile});
+ certKeys.push_back({std::move(certFile), std::move(keyFile)});
}
else if (certFiles.type() == typeid(LuaArray<std::string>) && keyFiles.type() == typeid(LuaArray<std::string>)) {
auto certFilesVect = boost::get<LuaArray<std::string>>(certFiles);
@@ -1573,29 +1730,29 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto ctx = std::make_shared<DNSCryptContext>(providerName, certKeys);
/* UDP */
- auto cs = std::make_unique<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus);
- cs->dnscryptCtx = ctx;
+ auto clientState = std::make_unique<ClientState>(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->dnscryptCtx = ctx;
g_dnsCryptLocals.push_back(ctx);
- g_frontends.push_back(std::move(cs));
+ g_frontends.push_back(std::move(clientState));
/* TCP */
- cs = std::make_unique<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus);
- cs->dnscryptCtx = ctx;
+ clientState = std::make_unique<ClientState>(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->dnscryptCtx = std::move(ctx);
if (tcpListenQueueSize > 0) {
- cs->tcpListenQueueSize = tcpListenQueueSize;
+ clientState->tcpListenQueueSize = tcpListenQueueSize;
}
if (maxInFlightQueriesPerConn > 0) {
- cs->d_maxInFlightQueriesPerConn = maxInFlightQueriesPerConn;
+ clientState->d_maxInFlightQueriesPerConn = maxInFlightQueriesPerConn;
}
if (tcpMaxConcurrentConnections > 0) {
- cs->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
+ clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
- g_frontends.push_back(std::move(cs));
+ g_frontends.push_back(std::move(clientState));
}
- catch (std::exception& e) {
- errlog(e.what());
- g_outputBuffer = "Error: " + string(e.what()) + "\n";
+ catch (const std::exception& e) {
+ errlog("Error during addDNSCryptBind() processing: %s", e.what());
+ g_outputBuffer = "Error during addDNSCryptBind() processing: " + string(e.what()) + "\n";
}
});
@@ -1683,7 +1840,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
const auto localPools = g_pools.getCopy();
for (const auto& entry : localPools) {
const string& name = entry.first;
- ret.push_back(make_pair(count++, name));
+ ret.emplace_back(count++, name);
}
return ret;
});
@@ -1707,12 +1864,33 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
try {
auto stream = std::ofstream(dest.c_str());
- g_verboseStream = std::move(stream);
+ dnsdist::logging::LoggingConfiguration::setVerboseStream(std::move(stream));
}
catch (const std::exception& e) {
errlog("Error while opening the verbose logging destination file %s: %s", dest, e.what());
}
});
+ luaCtx.writeFunction("setStructuredLogging", [](bool enable, boost::optional<LuaAssociativeTable<std::string>> options) {
+ std::string levelPrefix;
+ std::string timeFormat;
+ if (options) {
+ getOptionalValue<std::string>(options, "levelPrefix", levelPrefix);
+ if (getOptionalValue<std::string>(options, "timeFormat", timeFormat) == 1) {
+ if (timeFormat == "numeric") {
+ dnsdist::logging::LoggingConfiguration::setStructuredTimeFormat(dnsdist::logging::LoggingConfiguration::TimeFormat::Numeric);
+ }
+ else if (timeFormat == "ISO8601") {
+ dnsdist::logging::LoggingConfiguration::setStructuredTimeFormat(dnsdist::logging::LoggingConfiguration::TimeFormat::ISO8601);
+ }
+ else {
+ warnlog("Unknown value '%s' to setStructuredLogging's 'timeFormat' parameter", timeFormat);
+ }
+ }
+ checkAllParametersConsumed("setStructuredLogging", options);
+ }
+
+ dnsdist::logging::LoggingConfiguration::setStructuredLogging(enable, levelPrefix);
+ });
luaCtx.writeFunction("setStaleCacheEntriesTTL", [](uint64_t ttl) {
checkParameterBound("setStaleCacheEntriesTTL", ttl, std::numeric_limits<uint32_t>::max());
@@ -1783,12 +1961,12 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
if (!checkConfigurationTime("setDefaultBPFFilter")) {
return;
}
- g_defaultBPFFilter = bpf;
+ g_defaultBPFFilter = std::move(bpf);
});
luaCtx.writeFunction("registerDynBPFFilter", [](std::shared_ptr<DynBPFFilter> dbpf) {
if (dbpf) {
- g_dynBPFFilters.push_back(dbpf);
+ g_dynBPFFilters.push_back(std::move(dbpf));
}
});
@@ -1830,10 +2008,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setLuaNoSideEffect();
std::unordered_map<string, uint64_t> res;
{
- auto entries = g_stats.entries.read_lock();
+ auto entries = dnsdist::metrics::g_stats.entries.read_lock();
res.reserve(entries->size());
for (const auto& entry : *entries) {
- if (const auto& val = boost::get<pdns::stat_t*>(&entry.d_value)) {
+ if (const auto& val = std::get_if<pdns::stat_t*>(&entry.d_value)) {
res[entry.d_name] = (*val)->load();
}
}
@@ -1864,33 +2042,30 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
return;
}
- DIR* dirp;
- struct dirent* ent;
std::vector<std::string> files;
- if (!(dirp = opendir(dirname.c_str()))) {
- errlog("Error opening the included directory %s!", dirname.c_str());
- g_outputBuffer = "Error opening the included directory " + dirname + "!";
- return;
- }
-
- while ((ent = readdir(dirp)) != NULL) {
- if (ent->d_name[0] == '.') {
- continue;
+ auto directoryError = pdns::visit_directory(dirname, [&dirname, &files]([[maybe_unused]] ino_t inodeNumber, const std::string_view& name) {
+ if (boost::starts_with(name, ".")) {
+ return true;
}
-
- if (boost::ends_with(ent->d_name, ".conf")) {
+ if (boost::ends_with(name, ".conf")) {
std::ostringstream namebuf;
- namebuf << dirname << "/" << ent->d_name;
-
- if (stat(namebuf.str().c_str(), &st) || !S_ISREG(st.st_mode)) {
- continue;
+ namebuf << dirname << "/" << name;
+ struct stat fileStat
+ {
+ };
+ if (stat(namebuf.str().c_str(), &fileStat) == 0 && S_ISREG(fileStat.st_mode)) {
+ files.push_back(namebuf.str());
}
-
- files.push_back(namebuf.str());
}
+ return true;
+ });
+
+ if (directoryError) {
+ errlog("Error opening included directory: %s!", *directoryError);
+ g_outputBuffer = "Error opening included directory: " + *directoryError + "!";
+ return;
}
- closedir(dirp);
std::sort(files.begin(), files.end());
g_included = true;
@@ -2051,9 +2226,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
#endif /* HAVE_NET_SNMP */
#ifndef DISABLE_POLICIES_BINDINGS
- luaCtx.writeFunction("setServerPolicy", [](const ServerPolicy& policy) {
+ luaCtx.writeFunction("setServerPolicy", [](const std::shared_ptr<ServerPolicy>& policy) {
setLuaSideEffect();
- g_policy.setState(policy);
+ g_policy.setState(*policy);
});
luaCtx.writeFunction("setServerPolicyLua", [](const string& name, ServerPolicy::policyfunc_t policy) {
@@ -2078,24 +2253,24 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
g_outputBuffer = g_policy.getLocal()->getName() + "\n";
});
- luaCtx.writeFunction("setPoolServerPolicy", [](ServerPolicy policy, const string& pool) {
+ luaCtx.writeFunction("setPoolServerPolicy", [](const std::shared_ptr<ServerPolicy>& policy, const string& pool) {
setLuaSideEffect();
auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(policy));
+ setPoolPolicy(localPools, pool, policy);
g_pools.setState(localPools);
});
luaCtx.writeFunction("setPoolServerPolicyLua", [](const string& name, ServerPolicy::policyfunc_t policy, const string& pool) {
setLuaSideEffect();
auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policy, true}));
+ setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy), true}));
g_pools.setState(localPools);
});
luaCtx.writeFunction("setPoolServerPolicyLuaFFI", [](const string& name, ServerPolicy::ffipolicyfunc_t policy, const string& pool) {
setLuaSideEffect();
auto localPools = g_pools.getCopy();
- setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, policy}));
+ setPoolPolicy(localPools, pool, std::make_shared<ServerPolicy>(ServerPolicy{name, std::move(policy)}));
g_pools.setState(localPools);
});
@@ -2125,11 +2300,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setTCPDownstreamCleanupInterval(interval);
});
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
luaCtx.writeFunction("setDoHDownstreamCleanupInterval", [](uint64_t interval) {
setLuaSideEffect();
checkParameterBound("setDoHDownstreamCleanupInterval", interval);
setDoHDownstreamCleanupInterval(interval);
});
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
luaCtx.writeFunction("setTCPDownstreamMaxIdleTime", [](uint64_t max) {
setLuaSideEffect();
@@ -2137,11 +2314,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setTCPDownstreamMaxIdleTime(max);
});
+#if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
luaCtx.writeFunction("setDoHDownstreamMaxIdleTime", [](uint64_t max) {
setLuaSideEffect();
checkParameterBound("setDoHDownstreamMaxIdleTime", max);
setDoHDownstreamMaxIdleTime(max);
});
+#endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
luaCtx.writeFunction("setConsoleConnectionsLogging", [](bool enabled) {
g_logConsoleConnections = enabled;
@@ -2221,7 +2400,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
#ifndef DISABLE_SECPOLL
luaCtx.writeFunction("showSecurityStatus", []() {
setLuaNoSideEffect();
- g_outputBuffer = std::to_string(g_stats.securityStatus) + "\n";
+ g_outputBuffer = std::to_string(dnsdist::metrics::g_stats.securityStatus) + "\n";
});
luaCtx.writeFunction("setSecurityPollSuffix", [](const std::string& suffix) {
@@ -2320,7 +2499,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
password = boost::get<const string>((*opts)["password"]);
}
}
- result = std::make_shared<TLSCertKeyPair>(TLSCertKeyPair{cert, key, password});
+ result = std::make_shared<TLSCertKeyPair>(cert, std::move(key), std::move(password));
#endif
return result;
});
@@ -2336,31 +2515,61 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
setLuaSideEffect();
auto frontend = std::make_shared<DOHFrontend>();
+ if (getOptionalValue<std::string>(vars, "library", frontend->d_library) == 0) {
+#ifdef HAVE_NGHTTP2
+ frontend->d_library = "nghttp2";
+#else /* HAVE_NGHTTP2 */
+ frontend->d_library = "h2o";
+#endif /* HAVE_NGHTTP2 */
+ }
+ if (frontend->d_library == "h2o") {
+#ifdef HAVE_LIBH2OEVLOOP
+ frontend = std::make_shared<H2ODOHFrontend>();
+ // we _really_ need to set it again, as we just replaced the generic frontend by a new one
+ frontend->d_library = "h2o";
+#else /* HAVE_LIBH2OEVLOOP */
+ errlog("DOH bind %s is configured to use libh2o but the library is not available", addr);
+ return;
+#endif /* HAVE_LIBH2OEVLOOP */
+ }
+ else if (frontend->d_library == "nghttp2") {
+#ifndef HAVE_NGHTTP2
+ errlog("DOH bind %s is configured to use nghttp2 but the library is not available", addr);
+ return;
+#endif /* HAVE_NGHTTP2 */
+ }
+ else {
+ errlog("DOH bind %s is configured to use an unknown library ('%s')", addr, frontend->d_library);
+ return;
+ }
+
+ bool useTLS = true;
if (certFiles && !certFiles->empty()) {
- if (!loadTLSCertificateAndKeys("addDOHLocal", frontend->d_tlsConfig.d_certKeyPairs, *certFiles, *keyFiles)) {
+ if (!loadTLSCertificateAndKeys("addDOHLocal", frontend->d_tlsContext.d_tlsConfig.d_certKeyPairs, *certFiles, *keyFiles)) {
return;
}
- frontend->d_local = ComboAddress(addr, 443);
+ frontend->d_tlsContext.d_addr = ComboAddress(addr, 443);
}
else {
- frontend->d_local = ComboAddress(addr, 80);
- infolog("No certificate provided for DoH endpoint %s, running in DNS over HTTP mode instead of DNS over HTTPS", frontend->d_local.toStringWithPort());
+ frontend->d_tlsContext.d_addr = ComboAddress(addr, 80);
+ infolog("No certificate provided for DoH endpoint %s, running in DNS over HTTP mode instead of DNS over HTTPS", frontend->d_tlsContext.d_addr.toStringWithPort());
+ useTLS = false;
}
if (urls) {
if (urls->type() == typeid(std::string)) {
- frontend->d_urls.push_back(boost::get<std::string>(*urls));
+ frontend->d_urls.insert(boost::get<std::string>(*urls));
}
else if (urls->type() == typeid(LuaArray<std::string>)) {
auto urlsVect = boost::get<LuaArray<std::string>>(*urls);
for (const auto& p : urlsVect) {
- frontend->d_urls.push_back(p.second);
+ frontend->d_urls.insert(p.second);
}
}
}
else {
- frontend->d_urls = {"/dns-query"};
+ frontend->d_urls.insert("/dns-query");
}
bool reusePort = false;
@@ -2371,16 +2580,20 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
std::string interface;
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> additionalAddresses;
+ bool enableProxyProtocol = true;
if (vars) {
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
getOptionalValue<int>(vars, "idleTimeout", frontend->d_idleTimeout);
getOptionalValue<std::string>(vars, "serverTokens", frontend->d_serverTokens);
+ getOptionalValue<std::string>(vars, "provider", frontend->d_tlsContext.d_provider);
+ boost::algorithm::to_lower(frontend->d_tlsContext.d_provider);
+ getOptionalValue<bool>(vars, "proxyProtocolOutsideTLS", frontend->d_tlsContext.d_proxyProtocolOutsideTLS);
LuaAssociativeTable<std::string> customResponseHeaders;
if (getOptionalValue<decltype(customResponseHeaders)>(vars, "customResponseHeaders", customResponseHeaders) > 0) {
for (auto const& headerMap : customResponseHeaders) {
- std::pair<std::string, std::string> headerResponse = std::make_pair(boost::to_lower_copy(headerMap.first), headerMap.second);
+ auto headerResponse = std::pair(boost::to_lower_copy(headerMap.first), headerMap.second);
frontend->d_customResponseHeaders.insert(headerResponse);
}
}
@@ -2388,6 +2601,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
getOptionalValue<bool>(vars, "sendCacheControlHeaders", frontend->d_sendCacheControlHeaders);
getOptionalValue<bool>(vars, "keepIncomingHeaders", frontend->d_keepIncomingHeaders);
getOptionalValue<bool>(vars, "trustForwardedForHeader", frontend->d_trustForwardedForHeader);
+ getOptionalValue<bool>(vars, "earlyACLDrop", frontend->d_earlyACLDrop);
getOptionalValue<int>(vars, "internalPipeBufferSize", frontend->d_internalPipeBufferSize);
getOptionalValue<bool>(vars, "exactPathMatching", frontend->d_exactPathMatching);
@@ -2405,7 +2619,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
}
- parseTLSConfig(frontend->d_tlsConfig, "addDOHLocal", vars);
+ parseTLSConfig(frontend->d_tlsContext.d_tlsConfig, "addDOHLocal", vars);
bool ignoreTLSConfigurationErrors = false;
if (getOptionalValue<bool>(vars, "ignoreTLSConfigurationErrors", ignoreTLSConfigurationErrors) > 0 && ignoreTLSConfigurationErrors) {
@@ -2413,7 +2627,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
// and properly ignore the frontend before actually launching it
try {
std::map<int, std::string> ocspResponses = {};
- auto ctx = libssl_init_server_context(frontend->d_tlsConfig, ocspResponses);
+ auto ctx = libssl_init_server_context(frontend->d_tlsContext.d_tlsConfig, ocspResponses);
}
catch (const std::runtime_error& e) {
errlog("Ignoring DoH frontend: '%s'", e.what());
@@ -2423,23 +2637,246 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
checkAllParametersConsumed("addDOHLocal", vars);
}
+
+ if (useTLS && frontend->d_library == "nghttp2") {
+ if (!frontend->d_tlsContext.d_provider.empty()) {
+ vinfolog("Loading TLS provider '%s'", frontend->d_tlsContext.d_provider);
+ }
+ else {
+#ifdef HAVE_LIBSSL
+ const std::string provider("openssl");
+#else
+ const std::string provider("gnutls");
+#endif
+ vinfolog("Loading default TLS provider '%s'", provider);
+ }
+ }
+
g_dohlocals.push_back(frontend);
- auto cs = std::make_unique<ClientState>(frontend->d_local, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
- cs->dohFrontend = frontend;
- cs->d_additionalAddresses = std::move(additionalAddresses);
+ auto clientState = std::make_unique<ClientState>(frontend->d_tlsContext.d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->dohFrontend = std::move(frontend);
+ clientState->d_additionalAddresses = std::move(additionalAddresses);
if (tcpListenQueueSize > 0) {
- cs->tcpListenQueueSize = tcpListenQueueSize;
+ clientState->tcpListenQueueSize = tcpListenQueueSize;
}
if (tcpMaxConcurrentConnections > 0) {
- cs->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
+ clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConnections;
}
- g_frontends.push_back(std::move(cs));
-#else
+ g_frontends.push_back(std::move(clientState));
+#else /* HAVE_DNS_OVER_HTTPS */
throw std::runtime_error("addDOHLocal() called but DNS over HTTPS support is not present!");
+#endif /* HAVE_DNS_OVER_HTTPS */
+ });
+
+ // NOLINTNEXTLINE(performance-unnecessary-value-param): somehow clang-tidy gets confused about the fact vars could be const while it cannot
+ luaCtx.writeFunction("addDOH3Local", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles, boost::optional<localbind_t> vars) {
+ if (client) {
+ return;
+ }
+#ifdef HAVE_DNS_OVER_HTTP3
+ if (!checkConfigurationTime("addDOH3Local")) {
+ return;
+ }
+ setLuaSideEffect();
+
+ auto frontend = std::make_shared<DOH3Frontend>();
+ if (!loadTLSCertificateAndKeys("addDOH3Local", frontend->d_quicheParams.d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
+ return;
+ }
+ frontend->d_local = ComboAddress(addr, 443);
+
+ bool reusePort = false;
+ int tcpFastOpenQueueSize = 0;
+ int tcpListenQueueSize = 0;
+ uint64_t maxInFlightQueriesPerConn = 0;
+ uint64_t tcpMaxConcurrentConnections = 0;
+ std::string interface;
+ std::set<int> cpus;
+ std::vector<std::pair<ComboAddress, int>> additionalAddresses;
+ bool enableProxyProtocol = true;
+
+ if (vars) {
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
+ if (maxInFlightQueriesPerConn > 0) {
+ frontend->d_quicheParams.d_maxInFlight = maxInFlightQueriesPerConn;
+ }
+ getOptionalValue<int>(vars, "internalPipeBufferSize", frontend->d_internalPipeBufferSize);
+ getOptionalValue<int>(vars, "idleTimeout", frontend->d_quicheParams.d_idleTimeout);
+ getOptionalValue<std::string>(vars, "keyLogFile", frontend->d_quicheParams.d_keyLogFile);
+ {
+ std::string valueStr;
+ if (getOptionalValue<std::string>(vars, "congestionControlAlgo", valueStr) > 0) {
+ if (dnsdist::doq::s_available_cc_algorithms.count(valueStr) > 0) {
+ frontend->d_quicheParams.d_ccAlgo = valueStr;
+ }
+ else {
+ warnlog("Ignoring unknown value '%s' for 'congestionControlAlgo' on 'addDOH3Local'", valueStr);
+ }
+ }
+ }
+ parseTLSConfig(frontend->d_quicheParams.d_tlsConfig, "addDOH3Local", vars);
+
+ bool ignoreTLSConfigurationErrors = false;
+ if (getOptionalValue<bool>(vars, "ignoreTLSConfigurationErrors", ignoreTLSConfigurationErrors) > 0 && ignoreTLSConfigurationErrors) {
+ // we are asked to try to load the certificates so we can return a potential error
+ // and properly ignore the frontend before actually launching it
+ try {
+ std::map<int, std::string> ocspResponses = {};
+ auto ctx = libssl_init_server_context(frontend->d_quicheParams.d_tlsConfig, ocspResponses);
+ }
+ catch (const std::runtime_error& e) {
+ errlog("Ignoring DoH3 frontend: '%s'", e.what());
+ return;
+ }
+ }
+
+ checkAllParametersConsumed("addDOH3Local", vars);
+ }
+ g_doh3locals.push_back(frontend);
+ auto clientState = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->doh3Frontend = frontend;
+ clientState->d_additionalAddresses = std::move(additionalAddresses);
+
+ g_frontends.push_back(std::move(clientState));
+#else
+ throw std::runtime_error("addDOH3Local() called but DNS over HTTP/3 support is not present!");
#endif
});
+ // NOLINTNEXTLINE(performance-unnecessary-value-param): somehow clang-tidy gets confused about the fact vars could be const while it cannot
+ luaCtx.writeFunction("addDOQLocal", [client](const std::string& addr, const boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>>& certFiles, const boost::variant<std::string, LuaArray<std::string>>& keyFiles, boost::optional<localbind_t> vars) {
+ if (client) {
+ return;
+ }
+#ifdef HAVE_DNS_OVER_QUIC
+ if (!checkConfigurationTime("addDOQLocal")) {
+ return;
+ }
+ setLuaSideEffect();
+
+ auto frontend = std::make_shared<DOQFrontend>();
+ if (!loadTLSCertificateAndKeys("addDOQLocal", frontend->d_quicheParams.d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
+ return;
+ }
+ frontend->d_local = ComboAddress(addr, 853);
+
+ bool reusePort = false;
+ int tcpFastOpenQueueSize = 0;
+ int tcpListenQueueSize = 0;
+ uint64_t maxInFlightQueriesPerConn = 0;
+ uint64_t tcpMaxConcurrentConnections = 0;
+ std::string interface;
+ std::set<int> cpus;
+ std::vector<std::pair<ComboAddress, int>> additionalAddresses;
+ bool enableProxyProtocol = true;
+
+ if (vars) {
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConnections, enableProxyProtocol);
+ if (maxInFlightQueriesPerConn > 0) {
+ frontend->d_quicheParams.d_maxInFlight = maxInFlightQueriesPerConn;
+ }
+ getOptionalValue<int>(vars, "internalPipeBufferSize", frontend->d_internalPipeBufferSize);
+ getOptionalValue<int>(vars, "idleTimeout", frontend->d_quicheParams.d_idleTimeout);
+ getOptionalValue<std::string>(vars, "keyLogFile", frontend->d_quicheParams.d_keyLogFile);
+ {
+ std::string valueStr;
+ if (getOptionalValue<std::string>(vars, "congestionControlAlgo", valueStr) > 0) {
+ if (dnsdist::doq::s_available_cc_algorithms.count(valueStr) > 0) {
+ frontend->d_quicheParams.d_ccAlgo = std::move(valueStr);
+ }
+ else {
+ warnlog("Ignoring unknown value '%s' for 'congestionControlAlgo' on 'addDOQLocal'", valueStr);
+ }
+ }
+ }
+ parseTLSConfig(frontend->d_quicheParams.d_tlsConfig, "addDOQLocal", vars);
+
+ bool ignoreTLSConfigurationErrors = false;
+ if (getOptionalValue<bool>(vars, "ignoreTLSConfigurationErrors", ignoreTLSConfigurationErrors) > 0 && ignoreTLSConfigurationErrors) {
+ // we are asked to try to load the certificates so we can return a potential error
+ // and properly ignore the frontend before actually launching it
+ try {
+ std::map<int, std::string> ocspResponses = {};
+ auto ctx = libssl_init_server_context(frontend->d_quicheParams.d_tlsConfig, ocspResponses);
+ }
+ catch (const std::runtime_error& e) {
+ errlog("Ignoring DoQ frontend: '%s'", e.what());
+ return;
+ }
+ }
+
+ checkAllParametersConsumed("addDOQLocal", vars);
+ }
+ g_doqlocals.push_back(frontend);
+ auto clientState = std::make_unique<ClientState>(frontend->d_local, false, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->doqFrontend = std::move(frontend);
+ clientState->d_additionalAddresses = std::move(additionalAddresses);
+
+ g_frontends.push_back(std::move(clientState));
+#else
+ throw std::runtime_error("addDOQLocal() called but DNS over QUIC support is not present!");
+#endif
+ });
+
+ luaCtx.writeFunction("showDOQFrontends", []() {
+#ifdef HAVE_DNS_OVER_QUIC
+ setLuaNoSideEffect();
+ try {
+ ostringstream ret;
+ boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d");
+ ret << (fmt % "#" % "Address" % "Bad Version" % "Invalid Token" % "Errors" % "Valid") << endl;
+ size_t counter = 0;
+ for (const auto& ctx : g_doqlocals) {
+ ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_doqUnsupportedVersionErrors % ctx->d_doqInvalidTokensReceived % ctx->d_errorResponses % ctx->d_validResponses) << endl;
+ counter++;
+ }
+ g_outputBuffer = ret.str();
+ }
+ catch (const std::exception& e) {
+ g_outputBuffer = e.what();
+ throw;
+ }
+#else
+ g_outputBuffer = "DNS over QUIC support is not present!\n";
+#endif
+ });
+
+#ifdef HAVE_DNS_OVER_QUIC
+ luaCtx.writeFunction("getDOQFrontend", [client](uint64_t index) {
+ std::shared_ptr<DOQFrontend> result = nullptr;
+ if (client) {
+ return result;
+ }
+ setLuaNoSideEffect();
+ try {
+ if (index < g_doqlocals.size()) {
+ result = g_doqlocals.at(index);
+ }
+ else {
+ errlog("Error: trying to get DOQ frontend with index %d but we only have %d frontend(s)\n", index, g_doqlocals.size());
+ g_outputBuffer = "Error: trying to get DOQ frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doqlocals.size()) + " frontend(s)\n";
+ }
+ }
+ catch (const std::exception& e) {
+ g_outputBuffer = "Error while trying to get DOQ frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
+ errlog("Error while trying to get DOQ frontend with index %d: %s\n", index, string(e.what()));
+ }
+ return result;
+ });
+
+ luaCtx.writeFunction("getDOQFrontendCount", []() {
+ setLuaNoSideEffect();
+ return g_doqlocals.size();
+ });
+
+ luaCtx.registerFunction<void (std::shared_ptr<DOQFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOQFrontend>& frontend) {
+ if (frontend != nullptr) {
+ frontend->reloadCertificates();
+ }
+ });
+#endif
+
luaCtx.writeFunction("showDOHFrontends", []() {
#ifdef HAVE_DNS_OVER_HTTPS
setLuaNoSideEffect();
@@ -2449,7 +2886,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
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_http2Stats.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;
+ ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1Stats.d_nbQueries % ctx->d_http2Stats.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();
@@ -2463,6 +2900,64 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
#endif
});
+ luaCtx.writeFunction("showDOH3Frontends", []() {
+#ifdef HAVE_DNS_OVER_HTTP3
+ setLuaNoSideEffect();
+ try {
+ ostringstream ret;
+ boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d");
+ ret << (fmt % "#" % "Address" % "Bad Version" % "Invalid Token" % "Errors" % "Valid") << endl;
+ size_t counter = 0;
+ for (const auto& ctx : g_doh3locals) {
+ ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_doh3UnsupportedVersionErrors % ctx->d_doh3InvalidTokensReceived % ctx->d_errorResponses % ctx->d_validResponses) << endl;
+ counter++;
+ }
+ g_outputBuffer = ret.str();
+ }
+ catch (const std::exception& e) {
+ g_outputBuffer = e.what();
+ throw;
+ }
+#else
+ g_outputBuffer = "DNS over HTTP3 support is not present!\n";
+#endif
+ });
+
+#ifdef HAVE_DNS_OVER_HTTP3
+ luaCtx.writeFunction("getDOH3Frontend", [client](uint64_t index) {
+ std::shared_ptr<DOH3Frontend> result = nullptr;
+ if (client) {
+ return result;
+ }
+ setLuaNoSideEffect();
+ try {
+ if (index < g_doh3locals.size()) {
+ result = g_doh3locals.at(index);
+ }
+ else {
+ errlog("Error: trying to get DOH3 frontend with index %d but we only have %d frontend(s)\n", index, g_doh3locals.size());
+ g_outputBuffer = "Error: trying to get DOH3 frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doh3locals.size()) + " frontend(s)\n";
+ }
+ }
+ catch (const std::exception& e) {
+ g_outputBuffer = "Error while trying to get DOH3 frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
+ errlog("Error while trying to get DOH3 frontend with index %d: %s\n", index, string(e.what()));
+ }
+ return result;
+ });
+
+ luaCtx.writeFunction("getDOH3FrontendCount", []() {
+ setLuaNoSideEffect();
+ return g_doh3locals.size();
+ });
+
+ luaCtx.registerFunction<void (std::shared_ptr<DOH3Frontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOH3Frontend>& frontend) {
+ if (frontend != nullptr) {
+ frontend->reloadCertificates();
+ }
+ });
+#endif
+
luaCtx.writeFunction("showDOHResponseCodes", []() {
#ifdef HAVE_DNS_OVER_HTTPS
setLuaNoSideEffect();
@@ -2473,7 +2968,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others") << endl;
size_t counter = 0;
for (const auto& ctx : g_dohlocals) {
- ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_http1Stats.d_nb200Responses % ctx->d_http1Stats.d_nb400Responses % ctx->d_http1Stats.d_nb403Responses % ctx->d_http1Stats.d_nb500Responses % ctx->d_http1Stats.d_nb502Responses % ctx->d_http1Stats.d_nbOtherResponses) << endl;
+ ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_http1Stats.d_nb200Responses % ctx->d_http1Stats.d_nb400Responses % ctx->d_http1Stats.d_nb403Responses % ctx->d_http1Stats.d_nb500Responses % ctx->d_http1Stats.d_nb502Responses % ctx->d_http1Stats.d_nbOtherResponses) << endl;
counter++;
}
g_outputBuffer += ret.str();
@@ -2483,7 +2978,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
ret << (fmt % "#" % "Address" % "200" % "400" % "403" % "500" % "502" % "Others") << endl;
counter = 0;
for (const auto& ctx : g_dohlocals) {
- ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_http2Stats.d_nb200Responses % ctx->d_http2Stats.d_nb400Responses % ctx->d_http2Stats.d_nb403Responses % ctx->d_http2Stats.d_nb500Responses % ctx->d_http2Stats.d_nb502Responses % ctx->d_http2Stats.d_nbOtherResponses) << endl;
+ ret << (fmt % counter % ctx->d_tlsContext.d_addr.toStringWithPort() % ctx->d_http2Stats.d_nb200Responses % ctx->d_http2Stats.d_nb400Responses % ctx->d_http2Stats.d_nb403Responses % ctx->d_http2Stats.d_nb500Responses % ctx->d_http2Stats.d_nb502Responses % ctx->d_http2Stats.d_nbOtherResponses) << endl;
counter++;
}
g_outputBuffer += ret.str();
@@ -2509,13 +3004,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
result = g_dohlocals.at(index);
}
else {
- errlog("Error: trying to get DOH frontend with index %zu but we only have %zu frontend(s)\n", index, g_dohlocals.size());
+ errlog("Error: trying to get DOH frontend with index %d but we only have %d frontend(s)\n", index, g_dohlocals.size());
g_outputBuffer = "Error: trying to get DOH frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_dohlocals.size()) + " frontend(s)\n";
}
}
catch (const std::exception& e) {
g_outputBuffer = "Error while trying to get DOH frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
- errlog("Error while trying to get DOH frontend with index %zu: %s\n", index, string(e.what()));
+ errlog("Error while trying to get DOH frontend with index %d: %s\n", index, string(e.what()));
}
#else
g_outputBuffer="DNS over HTTPS support is not present!\n";
@@ -2528,7 +3023,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
return g_dohlocals.size();
});
- luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<DOHFrontend> frontend) {
+ luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<DOHFrontend>& frontend) {
if (frontend != nullptr) {
frontend->reloadCertificates();
}
@@ -2537,7 +3032,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
luaCtx.registerFunction<void (std::shared_ptr<DOHFrontend>::*)(boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, boost::variant<std::string, LuaArray<std::string>> keyFiles)>("loadNewCertificatesAndKeys", [](std::shared_ptr<DOHFrontend> frontend, boost::variant<std::string, std::shared_ptr<TLSCertKeyPair>, LuaArray<std::string>, LuaArray<std::shared_ptr<TLSCertKeyPair>>> certFiles, boost::variant<std::string, LuaArray<std::string>> keyFiles) {
#ifdef HAVE_DNS_OVER_HTTPS
if (frontend != nullptr) {
- if (loadTLSCertificateAndKeys("DOHFrontend::loadNewCertificatesAndKeys", frontend->d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
+ if (loadTLSCertificateAndKeys("DOHFrontend::loadNewCertificatesAndKeys", frontend->d_tlsContext.d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
frontend->reloadCertificates();
}
}
@@ -2579,7 +3074,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
setLuaSideEffect();
- shared_ptr<TLSFrontend> frontend = std::make_shared<TLSFrontend>();
+ auto frontend = std::make_shared<TLSFrontend>(TLSFrontend::ALPN::DoT);
if (!loadTLSCertificateAndKeys("addTLSLocal", frontend->d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
return;
}
@@ -2592,12 +3087,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
std::string interface;
std::set<int> cpus;
std::vector<std::pair<ComboAddress, int>> additionalAddresses;
+ bool enableProxyProtocol = true;
if (vars) {
- parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConns);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus, tcpListenQueueSize, maxInFlightQueriesPerConn, tcpMaxConcurrentConns, enableProxyProtocol);
getOptionalValue<std::string>(vars, "provider", frontend->d_provider);
boost::algorithm::to_lower(frontend->d_provider);
+ getOptionalValue<bool>(vars, "proxyProtocolOutsideTLS", frontend->d_proxyProtocolOutsideTLS);
LuaArray<std::string> addresses;
if (getOptionalValue<decltype(addresses)>(vars, "additionalAddresses", addresses) > 0) {
@@ -2639,27 +3136,28 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
else {
#ifdef HAVE_LIBSSL
- vinfolog("Loading default TLS provider 'openssl'");
+ const std::string provider("openssl");
#else
- vinfolog("Loading default TLS provider 'gnutls'");
+ const std::string provider("gnutls");
#endif
+ vinfolog("Loading default TLS provider '%s'", provider);
}
// only works pre-startup, so no sync necessary
- auto cs = std::make_unique<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus);
- cs->tlsFrontend = frontend;
- cs->d_additionalAddresses = std::move(additionalAddresses);
+ auto clientState = std::make_unique<ClientState>(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus, enableProxyProtocol);
+ clientState->tlsFrontend = frontend;
+ clientState->d_additionalAddresses = std::move(additionalAddresses);
if (tcpListenQueueSize > 0) {
- cs->tcpListenQueueSize = tcpListenQueueSize;
+ clientState->tcpListenQueueSize = tcpListenQueueSize;
}
if (maxInFlightQueriesPerConn > 0) {
- cs->d_maxInFlightQueriesPerConn = maxInFlightQueriesPerConn;
+ clientState->d_maxInFlightQueriesPerConn = maxInFlightQueriesPerConn;
}
if (tcpMaxConcurrentConns > 0) {
- cs->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConns;
+ clientState->d_tcpConcurrentConnectionsLimit = tcpMaxConcurrentConns;
}
- g_tlslocals.push_back(cs->tlsFrontend);
- g_frontends.push_back(std::move(cs));
+ g_tlslocals.push_back(clientState->tlsFrontend);
+ g_frontends.push_back(std::move(clientState));
}
catch (const std::exception& e) {
g_outputBuffer = "Error: " + string(e.what()) + "\n";
@@ -2702,13 +3200,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
result = g_tlslocals.at(index)->getContext();
}
else {
- errlog("Error: trying to get TLS context with index %zu but we only have %zu context(s)\n", index, g_tlslocals.size());
+ errlog("Error: trying to get TLS context with index %d but we only have %d context(s)\n", index, g_tlslocals.size());
g_outputBuffer = "Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " context(s)\n";
}
}
catch (const std::exception& e) {
g_outputBuffer = "Error while trying to get TLS context with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
- errlog("Error while trying to get TLS context with index %zu: %s\n", index, string(e.what()));
+ errlog("Error while trying to get TLS context with index %d: %s\n", index, string(e.what()));
}
#else
g_outputBuffer="DNS over TLS support is not present!\n";
@@ -2725,13 +3223,13 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
result = g_tlslocals.at(index);
}
else {
- errlog("Error: trying to get TLS frontend with index %zu but we only have %zu frontends\n", index, g_tlslocals.size());
+ errlog("Error: trying to get TLS frontend with index %d but we only have %d frontends\n", index, g_tlslocals.size());
g_outputBuffer = "Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " frontend(s)\n";
}
}
catch (const std::exception& e) {
g_outputBuffer = "Error while trying to get TLS frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
- errlog("Error while trying to get TLS frontend with index %zu: %s\n", index, string(e.what()));
+ errlog("Error while trying to get TLS frontend with index %d: %s\n", index, string(e.what()));
}
#else
g_outputBuffer="DNS over TLS support is not present!\n";
@@ -2783,7 +3281,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
}
});
- luaCtx.registerFunction<void (std::shared_ptr<TLSFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<TLSFrontend>& frontend) {
+ luaCtx.registerFunction<void (std::shared_ptr<TLSFrontend>::*)()>("reloadCertificates", [](const std::shared_ptr<TLSFrontend>& frontend) {
if (frontend == nullptr) {
return;
}
@@ -2819,6 +3317,16 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
frontend->dohFrontend->reloadCertificates();
}
#endif /* HAVE_DNS_OVER_HTTPS */
+#ifdef HAVE_DNS_OVER_QUIC
+ if (frontend->doqFrontend) {
+ frontend->doqFrontend->reloadCertificates();
+ }
+#endif /* HAVE_DNS_OVER_QUIC */
+#ifdef HAVE_DNS_OVER_HTTP3
+ if (frontend->doh3Frontend) {
+ frontend->doh3Frontend->reloadCertificates();
+ }
+#endif /* HAVE_DNS_OVER_HTTP3 */
}
catch (const std::exception& e) {
errlog("Error reloading certificates for frontend %s: %s", frontend->local.toStringWithPort(), e.what());
@@ -2918,7 +3426,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::declareCustomMetric(name, type, description, customName ? std::optional<std::string>(*customName) : std::nullopt);
if (result) {
g_outputBuffer += *result + "\n";
- errlog("%s", *result);
+ errlog("Error in declareMetric: %s", *result);
return false;
}
return true;
@@ -2927,7 +3435,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::incrementCustomCounter(name, step ? *step : 1);
if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
g_outputBuffer = *errorStr + "'\n";
- errlog("%s", *errorStr);
+ errlog("Error in incMetric: %s", *errorStr);
return static_cast<uint64_t>(0);
}
return std::get<uint64_t>(result);
@@ -2936,7 +3444,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::decrementCustomCounter(name, step ? *step : 1);
if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
g_outputBuffer = *errorStr + "'\n";
- errlog("%s", *errorStr);
+ errlog("Error in decMetric: %s", *errorStr);
return static_cast<uint64_t>(0);
}
return std::get<uint64_t>(result);
@@ -2945,7 +3453,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::setCustomGauge(name, value);
if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
g_outputBuffer = *errorStr + "'\n";
- errlog("%s", *errorStr);
+ errlog("Error in setMetric: %s", *errorStr);
return 0.;
}
return std::get<double>(result);
@@ -2954,7 +3462,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
auto result = dnsdist::metrics::getCustomMetric(name);
if (const auto* errorStr = std::get_if<dnsdist::metrics::Error>(&result)) {
g_outputBuffer = *errorStr + "'\n";
- errlog("%s", *errorStr);
+ errlog("Error in getMetric: %s", *errorStr);
return 0.;
}
return std::get<double>(result);
@@ -2969,7 +3477,7 @@ vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool
setupLuaActions(luaCtx);
setupLuaConfig(luaCtx, client, configCheck);
- setupLuaBindings(luaCtx, client);
+ setupLuaBindings(luaCtx, client, configCheck);
setupLuaBindingsDNSCrypt(luaCtx, client);
setupLuaBindingsDNSParser(luaCtx);
setupLuaBindingsDNSQuestion(luaCtx);
@@ -2978,6 +3486,7 @@ vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool
setupLuaBindingsPacketCache(luaCtx, client);
setupLuaBindingsProtoBuf(luaCtx, client, configCheck);
setupLuaBindingsRings(luaCtx, client);
+ dnsdist::lua::hooks::setupLuaHooks(luaCtx);
setupLuaInspection(luaCtx);
setupLuaRules(luaCtx);
setupLuaVars(luaCtx);