{ "getQueryCounters", true, "[max=10]", "show current buffer of query counters, limited by 'max' if provided" },
{ "getResponseRing", true, "", "return the current content of the response ring" },
{ "getRespRing", true, "", "return the qname/rcode content of the response ring" },
- { "getServer", true, "n", "returns server with index n" },
+ { "getServer", true, "id", "returns server with index 'n' or whose uuid matches if 'id' is an UUID string" },
{ "getServers", true, "", "returns a table with all defined servers" },
{ "getStatisticsCounters", true, "", "returns a map of statistic counters" },
{ "getTLSContext", true, "n", "returns the TLS context with index n" },
{ "KeyValueStoreLookupRule", 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"},
{ "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" },
{ "LuaResponseAction", true, "function", "Invoke a Lua function that accepts a DNSResponse" },
{ "MacAddrAction", true, "option", "Add the source MAC address to the query as EDNS0 option option. This action is currently only supported on Linux. Subsequent rules are processed after this action" },
{ "rmResponseRule", true, "id", "remove response rule in position 'id', or whose uuid matches if 'id' is an UUID string" },
{ "rmRule", true, "id", "remove rule in position 'id', or whose uuid matches if 'id' is an UUID string" },
{ "rmSelfAnsweredResponseRule", true, "id", "remove self-answered response rule in position 'id', or whose uuid matches if 'id' is an UUID string" },
- { "rmServer", true, "n", "remove server with index n" },
+ { "rmServer", true, "id", "remove server with index 'id' or whose uuid matches if 'id' is an UUID string" },
{ "roundrobin", false, "", "Simple round robin over available servers" },
{ "sendCustomTrap", true, "str", "send a custom `SNMP` trap from Lua, containing the `str` string"},
{ "setACL", true, "{netmask, netmask}", "replace the ACL set with these netmasks. Use `setACL({})` to reset the list, meaning no one can use us" },
{ "setAPIWritable", true, "bool, dir", "allow modifications via the API. if `dir` is set, it must be a valid directory where the configuration files will be written by the API" },
{ "setCacheCleaningDelay", true, "num", "Set the interval in seconds between two runs of the cache cleaning algorithm, removing expired entries" },
{ "setCacheCleaningPercentage", true, "num", "Set the percentage of the cache that the cache cleaning algorithm will try to free by removing expired entries. By default (100), all expired entries are remove" },
+ { "setConsistentHashingBalancingFactor", true, "factor", "Set the balancing factor for bounded-load consistent hashing" },
{ "setConsoleACL", true, "{netmask, netmask}", "replace the console ACL set with these netmasks" },
{ "setConsoleConnectionsLogging", true, "enabled", "whether to log the opening and closing of console connections" },
{ "setConsoleOutputMaxMsgSize", true, "messageSize", "set console message maximum size in bytes, default is 10 MB" },
#include "dnsdist.hh"
#include "dnsdist-console.hh"
#include "dnsdist-ecs.hh"
+#include "dnsdist-healthchecks.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-secpoll.hh"
#endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
-void setupLuaConfig(bool client)
+void setupLuaConfig(bool client, bool configCheck)
{
typedef std::unordered_map<std::string, boost::variant<bool, std::string, vector<pair<int, std::string> >, DownstreamState::checkfunc_t > > newserver_t;
g_lua.writeFunction("inClientStartup", [client]() {
return client && !g_configurationDone;
});
+ g_lua.writeFunction("inConfigCheck", [client, configCheck]() {
+ return !configCheck;
+ });
+
g_lua.writeFunction("newServer",
- [client](boost::variant<string,newserver_t> pvars, boost::optional<int> qps) {
+ [client, configCheck](boost::variant<string,newserver_t> pvars, boost::optional<int> qps) {
setLuaSideEffect();
std::shared_ptr<DownstreamState> ret = std::make_shared<DownstreamState>(ComboAddress());
}
}
- if(client) {
- // do not construct DownstreamState now, it would try binding sockets.
- return ret;
- }
- ret=std::make_shared<DownstreamState>(serverAddr, sourceAddr, sourceItf, sourceItfName, numberOfSockets);
+ // create but don't connect the socket in client or check-config modes
+ ret=std::make_shared<DownstreamState>(serverAddr, sourceAddr, sourceItf, sourceItfName, numberOfSockets, !(client || configCheck));
if(vars.count("qps")) {
int qpsVal=std::stoi(boost::get<string>(vars["qps"]));
} );
g_lua.writeFunction("rmServer",
- [](boost::variant<std::shared_ptr<DownstreamState>, int> var)
+ [](boost::variant<std::shared_ptr<DownstreamState>, int, std::string> var)
{
setLuaSideEffect();
- shared_ptr<DownstreamState> server;
- auto* rem = boost::get<shared_ptr<DownstreamState>>(&var);
+ shared_ptr<DownstreamState> server = nullptr;
auto states = g_dstates.getCopy();
- if(rem) {
+ if (auto* rem = boost::get<shared_ptr<DownstreamState>>(&var)) {
server = *rem;
}
+ else if (auto str = boost::get<std::string>(&var)) {
+ const auto uuid = getUniqueID(*str);
+ for (auto& state : states) {
+ if (state->id == uuid) {
+ server = state;
+ }
+ }
+ }
else {
int idx = boost::get<int>(var);
server = states.at(idx);
}
+ if (!server) {
+ throw std::runtime_error("unable to locate the requested server");
+ }
auto localPools = g_pools.getCopy();
for (const string& poolName : server->pools) {
removeServerFromPool(localPools, poolName, server);
return getDownstreamCandidates(g_pools.getCopy(), pool);
});
- g_lua.writeFunction("getServer", [client](int i) {
- if (client)
+ g_lua.writeFunction("getServer", [client](boost::variant<unsigned int, std::string> i) {
+ if (client) {
return std::make_shared<DownstreamState>(ComboAddress());
- return g_dstates.getCopy().at(i);
+ }
+ auto states = g_dstates.getCopy();
+ if (auto str = boost::get<std::string>(&i)) {
+ const auto uuid = getUniqueID(*str);
+ for (auto& state : states) {
+ if (state->id == uuid) {
+ return state;
+ }
+ }
+ }
+ else if (auto pos = boost::get<unsigned int>(&i)) {
+ return states.at(*pos);
+ }
+
+ g_outputBuffer = "Error: no rule matched\n";
+ return std::shared_ptr<DownstreamState>(nullptr);
});
g_lua.writeFunction("carbonServer", [](const std::string& address, boost::optional<string> ourName,
g_carbon.setState(ours);
});
- g_lua.writeFunction("webserver", [client](const std::string& address, const std::string& password, const boost::optional<std::string> apiKey, const boost::optional<std::map<std::string, std::string> > customHeaders) {
+ g_lua.writeFunction("webserver", [client,configCheck](const std::string& address, const std::string& password, const boost::optional<std::string> apiKey, const boost::optional<std::map<std::string, std::string> > customHeaders) {
setLuaSideEffect();
ComboAddress local;
try {
throw std::runtime_error(std::string("Error parsing the bind address for the webserver: ") + e.reason);
}
- if (client) {
+ if (client || configCheck) {
return;
}
}
});
- g_lua.writeFunction("controlSocket", [client](const std::string& str) {
+ g_lua.writeFunction("controlSocket", [client,configCheck](const std::string& str) {
setLuaSideEffect();
ComboAddress local(str, 5199);
- if(client) {
+ if(client || configCheck) {
g_serverControl = local;
return;
}
#endif
});
- g_lua.writeFunction("generateDNSCryptProviderKeys", [](const std::string& publicKeyFile, const std::string privateKeyFile) {
+ g_lua.writeFunction("generateDNSCryptProviderKeys", [client](const std::string& publicKeyFile, const std::string privateKeyFile) {
setLuaNoSideEffect();
#ifdef HAVE_DNSCRYPT
+ if (client) {
+ return;
+ }
unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
unsigned char privateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
sodium_mlock(privateKey, sizeof(privateKey));
});
#ifdef HAVE_DNSCRYPT
- g_lua.writeFunction("generateDNSCryptCertificate", [](const std::string& providerPrivateKeyFile, const std::string& certificateFile, const std::string privateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
+ g_lua.writeFunction("generateDNSCryptCertificate", [client](const std::string& providerPrivateKeyFile, const std::string& certificateFile, const std::string privateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
setLuaNoSideEffect();
+ if (client) {
+ return;
+ }
DNSCryptPrivateKey privateKey;
DNSCryptCert cert;
g_roundrobinFailOnNoServer = fail;
});
+ g_lua.writeFunction("setConsistentHashingBalancingFactor", [](double factor) {
+ setLuaSideEffect();
+ if (factor >= 0) {
+ g_consistentHashBalancingFactor = factor;
+ }
+ else {
+ errlog("Invalid value passed to setConsistentHashingBalancingFactor()!");
+ g_outputBuffer="Invalid value passed to setConsistentHashingBalancingFactor()!\n";
+ return;
+ }
+ });
+
g_lua.writeFunction("setRingBuffersSize", [](size_t capacity, boost::optional<size_t> numberOfShards) {
setLuaSideEffect();
if (g_configurationDone) {
g_useTCPSinglePipe = flag;
});
- g_lua.writeFunction("snmpAgent", [client](bool enableTraps, boost::optional<std::string> masterSocket) {
- if(client)
+ g_lua.writeFunction("snmpAgent", [client,configCheck](bool enableTraps, boost::optional<std::string> masterSocket) {
+ if(client || configCheck)
return;
#ifdef HAVE_NET_SNMP
if (g_configurationDone) {
if (vars->count("provider")) {
frontend->d_provider = boost::get<const string>((*vars)["provider"]);
+ boost::algorithm::to_lower(frontend->d_provider);
}
parseTLSConfig(frontend->d_tlsConfig, "addTLSLocal", vars);
vinfolog("Loading TLS provider '%s'", frontend->d_provider);
}
else {
+#ifdef HAVE_LIBSSL
vinfolog("Loading default TLS provider 'openssl'");
+#else
+ vinfolog("Loading default TLS provider 'gnutls'");
+#endif
}
// only works pre-startup, so no sync necessary
auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
#if defined(HAVE_LIBSSL) && defined(HAVE_OCSP_BASIC_SIGN)
- g_lua.writeFunction("generateOCSPResponse", [](const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin) {
- return libssl_generate_ocsp_response(certFile, caCert, caKey, outFile, ndays, nmin);
+ g_lua.writeFunction("generateOCSPResponse", [client](const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin) {
+ if (client) {
+ return;
+ }
+
+ libssl_generate_ocsp_response(certFile, caCert, caKey, outFile, ndays, nmin);
});
#endif /* HAVE_LIBSSL && HAVE_OCSP_BASIC_SIGN*/
}
-vector<std::function<void(void)>> setupLua(bool client, const std::string& config)
+vector<std::function<void(void)>> setupLua(bool client, bool configCheck, const std::string& config)
{
g_launchWork= new vector<std::function<void(void)>>();
setupLuaActions();
- setupLuaConfig(client);
+ setupLuaConfig(client, configCheck);
setupLuaBindings(client);
setupLuaBindingsDNSCrypt();
setupLuaBindingsDNSQuestion();
setupLuaBindingsKVS(client);
setupLuaBindingsPacketCache();
- setupLuaBindingsProtoBuf(client);
+ setupLuaBindingsProtoBuf(client, configCheck);
setupLuaInspection();
setupLuaRules();
setupLuaVars();
Returns true while the console client is parsing the configuration.
+.. function:: inConfigCheck()
+
+ .. versionadded:: 1.5.0
+
+ Returns true while the configuration is being checked, ie when run with ``--check-config``.
+
.. function:: makeKey()
Generate and print an encryption key.
.. function:: getServer(index) -> Server
+ .. versionchanged:: 1.5.0
+ ``index`` might be an UUID.
+
Get a :class:`Server`
- :param int index: The number of the server (as seen in :func:`showServers`).
+ :param int or str index: The number of the server (as seen in :func:`showServers`) or its UUID as a string.
:returns: The :class:`Server` object or nil
.. function:: getServers()
Returns a table with all defined servers.
.. function:: rmServer(index)
+ rmServer(uuid)
rmServer(server)
+ .. versionchanged:: 1.5.0
+ ``uuid`` selection added.
+
Remove a backend server.
- :param int index: The number of the server (as seen in :func:`showServers`).
+ :param int or str index: The number of the server (as seen in :func:`showServers`), its UUID as a string, or a server object.
:param Server server: A :class:`Server` object as returned by e.g. :func:`getServer`.
Server Functions
:param int action: The action to take when the dynamic block matches, see :ref:`here <DNSAction>`. (default to the one set with :func:`setDynBlocksAction`)
:param int warningRate: If set to a non-zero value, the rate above which a warning message will be issued and a no-op block inserted
+ .. method:: DynBlockRulesGroup:setRCodeRatio(rcode, ratio, seconds, reason, blockingTime, minimumNumberOfResponses [, action [, warningRate]])
+
+ .. versionadded:: 1.5.0
+
+ Adds a rate-limiting rule for the ratio of responses of code ``rcode`` over the total number of responses for a given client.
+
+ :param int rcode: The response code
+ :param int ratio: Ratio of responses per second of the given rcode over the total number of responses for this client to exceed
+ :param int seconds: Number of seconds the ratio has been exceeded
+ :param string reason: The message to show next to the blocks
+ :param int blockingTime: The number of seconds this block to expire
+ :param int minimumNumberOfResponses: How many total responses is required for this rule to apply
+ :param int action: The action to take when the dynamic block matches, see :ref:`here <DNSAction>`. (default to the one set with :func:`setDynBlocksAction`)
+ :param int warningRatio: If set to a non-zero value, the ratio above which a warning message will be issued and a no-op block inserted
+
.. method:: DynBlockRulesGroup:setQTypeRate(qtype, rate, seconds, reason, blockingTime [, action [, warningRate]])
.. versionchanged:: 1.3.3