#include "dnsdist-ecs.hh"
#include "dnsdist-healthchecks.hh"
#include "dnsdist-lua.hh"
-#include "dnsdist-lua-ffi.hh"
#include "dnsdist-rings.hh"
#include "dnsdist-secpoll.hh"
#include "dnsdist-xpf.hh"
GlobalStateHolder<pools_t> g_pools;
size_t g_udpVectorSize{1};
-bool g_snmpEnabled{false};
-bool g_snmpTrapsEnabled{false};
-DNSDistSNMPAgent* g_snmpAgent{nullptr};
-
/* UDP: the grand design. Per socket we listen on for incoming queries there is one thread.
Then we have a bunch of connected sockets for talking to downstream servers.
We send directly to those sockets.
policy = *(serverPool->policy);
}
auto servers = serverPool->getServers();
- if (policy.isLua) {
- if (!policy.isFFI) {
- std::lock_guard<std::mutex> lock(g_luamutex);
- selectedBackend = policy.policy(servers, &dq);
- }
- else {
- dnsdist_ffi_dnsquestion_t dnsq(&dq);
- dnsdist_ffi_servers_list_t serversList(servers);
- unsigned int selected = 0;
- {
- std::lock_guard<std::mutex> lock(g_luamutex);
- selected = policy.ffipolicy(&serversList, &dnsq);
- }
- selectedBackend = servers.at(selected).second;
- }
- }
- else {
- selectedBackend = policy.policy(servers, &dq);
- }
+ selectedBackend = getSelectedBackendFromPolicy(policy, servers, dq);
uint16_t cachedResponseSize = dq.size;
uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL;
#include "dolog.hh"
uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
+
std::mutex g_luamutex;
+#include "ext/luawrapper/include/LuaContext.hpp"
+LuaContext g_lua;
+
+bool g_snmpEnabled{false};
+bool g_snmpTrapsEnabled{false};
+DNSDistSNMPAgent* g_snmpAgent{nullptr};
+
+/* add stub implementations, we don't want to include the corresponding object files
+ and their dependencies */
-static std::shared_ptr<DownstreamState> getSelectedBackendFromPolicy(const ServerPolicy& policy, const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq)
+#ifdef HAVE_DNS_OVER_HTTPS
+std::unordered_map<std::string, std::string> DOHUnit::getHTTPHeaders() const
{
- std::shared_ptr<DownstreamState> selectedBackend{nullptr};
+ return {};
+}
- if (policy.isLua) {
- if (!policy.isFFI) {
- std::lock_guard<std::mutex> lock(g_luamutex);
- selectedBackend = policy.policy(servers, &dq);
- }
- else {
- dnsdist_ffi_dnsquestion_t dnsq(&dq);
- dnsdist_ffi_servers_list_t serversList(servers);
- unsigned int selected = 0;
- {
- std::lock_guard<std::mutex> lock(g_luamutex);
- selected = policy.ffipolicy(&serversList, &dnsq);
- }
- selectedBackend = servers.at(selected).second;
- }
- }
- else {
- selectedBackend = policy.policy(servers, &dq);
- }
+std::string DOHUnit::getHTTPPath() const
+{
+ return "";
+}
+
+std::string DOHUnit::getHTTPHost() const
+{
+ return "";
+}
+
+std::string DOHUnit::getHTTPScheme() const
+{
+ return "";
+}
+
+std::string DOHUnit::getHTTPQueryString() const
+{
+ return "";
+}
+
+void DOHUnit::setHTTPResponse(uint16_t statusCode, const std::string& body_, const std::string& contentType_)
+{
+}
+#endif /* HAVE_DNS_OVER_HTTPS */
- return selectedBackend;
+std::string DNSQuestion::getTrailingData() const
+{
+ return "";
+}
+
+bool DNSQuestion::setTrailingData(const std::string& tail)
+{
+ return false;
+}
+
+bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dq, const std::string& reason)
+{
+ return false;
}
static DNSQuestion getDQ(const DNSName* providedName = nullptr)
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx + 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
}
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx + 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
}
BOOST_CHECK_LT(got, expected * 2);
}
+
BOOST_AUTO_TEST_CASE(test_chashed) {
bool existingVerboseValue = g_verbose;
g_verbose = false;
ServerPolicy::NumberedServerVector servers;
std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
for (size_t idx = 1; idx <= 10; idx++) {
- servers.push_back({ idx + 1, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
serversMap[servers.at(idx - 1).second] = 0;
servers.at(idx - 1).second->setUp();
/* we need to have a weight of at least 1000 to get an optimal repartition with the consistent hashing algo */
g_verbose = existingVerboseValue;
}
+BOOST_AUTO_TEST_CASE(test_lua) {
+ std::vector<DNSName> names;
+ names.reserve(1000);
+ for (size_t idx = 0; idx < 1000; idx++) {
+ names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ }
+
+ static const std::string policySetupStr = R"foo(
+ local counter = 0
+ function luaroundrobin(servers, dq)
+ counter = counter + 1
+ return servers[1 + (counter % #servers)]
+ end
+
+ setServerPolicyLua("luaroundrobin", luaroundrobin)
+ )foo";
+ g_lua.writeFunction("setServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy) {
+ g_policy.setState(ServerPolicy{name, policy, true});
+ });
+ g_lua.executeCode(policySetupStr);
+
+ ServerPolicy pol = g_policy.getCopy();
+ ServerPolicy::NumberedServerVector servers;
+ std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
+ for (size_t idx = 1; idx <= 10; idx++) {
+ servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ serversMap[servers.at(idx - 1).second] = 0;
+ servers.at(idx - 1).second->setUp();
+ }
+ BOOST_REQUIRE_EQUAL(servers.size(), 10);
+
+ for (const auto& name : names) {
+ auto dq = getDQ(&name);
+ auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+ BOOST_REQUIRE(serversMap.count(server) == 1);
+ ++serversMap[server];
+ }
+ uint64_t total = 0;
+ for (const auto& entry : serversMap) {
+ BOOST_CHECK_GT(entry.second, 0);
+ BOOST_CHECK_GT(entry.second, (names.size() / servers.size() / 2));
+ BOOST_CHECK_LT(entry.second, (names.size() / servers.size() * 2));
+ total += entry.second;
+ }
+ BOOST_CHECK_EQUAL(total, names.size());
+}
+
+#ifdef LUAJIT_VERSION
+BOOST_AUTO_TEST_CASE(test_lua_ffi) {
+ std::vector<DNSName> names;
+ names.reserve(1000);
+ for (size_t idx = 0; idx < 1000; idx++) {
+ names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com."));
+ }
+
+ static const std::string policySetupStr = R"foo(
+ local ffi = require("ffi")
+ local C = ffi.C
+ local counter = 0
+ function ffilb(servers_list, dq)
+ local serversCount = tonumber(C.dnsdist_ffi_servers_list_get_count(servers_list))
+ counter = counter + 1
+ return counter % serversCount
+ end
+
+ setServerPolicyLuaFFI("FFI", ffilb)
+ )foo";
+ g_lua.executeCode(getLuaFFIWrappers());
+ g_lua.writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) {
+ auto pol = ServerPolicy(name, policy);
+ g_policy.setState(std::move(pol));
+ });
+ g_lua.executeCode(policySetupStr);
+
+ ServerPolicy pol = g_policy.getCopy();
+ ServerPolicy::NumberedServerVector servers;
+ std::map<std::shared_ptr<DownstreamState>, uint64_t> serversMap;
+ for (size_t idx = 1; idx <= 10; idx++) {
+ servers.push_back({ idx, std::make_shared<DownstreamState>(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) });
+ serversMap[servers.at(idx - 1).second] = 0;
+ servers.at(idx - 1).second->setUp();
+ }
+ BOOST_REQUIRE_EQUAL(servers.size(), 10);
+
+ for (const auto& name : names) {
+ auto dq = getDQ(&name);
+ auto server = getSelectedBackendFromPolicy(pol, servers, dq);
+ BOOST_REQUIRE(serversMap.count(server) == 1);
+ ++serversMap[server];
+ }
+ uint64_t total = 0;
+ for (const auto& entry : serversMap) {
+ BOOST_CHECK_GT(entry.second, 0);
+ BOOST_CHECK_GT(entry.second, (names.size() / servers.size() / 2));
+ BOOST_CHECK_LT(entry.second, (names.size() / servers.size() * 2));
+ total += entry.second;
+ }
+ BOOST_CHECK_EQUAL(total, names.size());
+}
+#endif /* LUAJIT_VERSION */
+
BOOST_AUTO_TEST_SUITE_END()