Skip to content

Commit

Permalink
Merge pull request #13505 from rgacogne/ddist-getaddressinfo
Browse files Browse the repository at this point in the history
dnsdist: Add `getAddressInfo()` for asynchronous DNS resolution
  • Loading branch information
rgacogne committed Dec 1, 2023
2 parents f0086f0 + 7527f42 commit 099d31d
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 4 deletions.
23 changes: 22 additions & 1 deletion pdns/dnsdist-lua-bindings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@
#include "bpf-filter.hh"
#include "config.h"
#include "dnsdist.hh"
#include "dnsdist-async.hh"
#include "dnsdist-lua.hh"
#include "dnsdist-resolver.hh"
#include "dnsdist-svc.hh"

#include "dolog.hh"

// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
void setupLuaBindings(LuaContext& luaCtx, bool client)
void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
{
luaCtx.writeFunction("vinfolog", [](const string& arg) {
vinfolog("%s", arg);
Expand Down Expand Up @@ -785,4 +787,23 @@ void setupLuaBindings(LuaContext& luaCtx, bool client)
}
return now;
});

luaCtx.writeFunction("getAddressInfo", [client, configCheck](std::string hostname, std::function<void(const std::string& hostname, const LuaArray<ComboAddress>& ips)> callback) {
if (client || configCheck) {
return;
}
std::thread newThread(dnsdist::resolver::asynchronousResolver, std::move(hostname), [callback=std::move(callback)](const std::string& resolvedHostname, std::vector<ComboAddress>& ips) {
LuaArray<ComboAddress> result;
result.reserve(ips.size());
for (const auto& entry : ips) {
result.emplace_back(result.size() + 1, entry);
}
{
auto lua = g_lua.lock();
callback(resolvedHostname, result);
dnsdist::handleQueuedAsynchronousEvents();
}
});
newThread.detach();
});
}
2 changes: 1 addition & 1 deletion pdns/dnsdist-lua.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3214,7 +3214,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);
Expand Down
2 changes: 1 addition & 1 deletion pdns/dnsdist-lua.hh
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ void checkParameterBound(const std::string& parameter, uint64_t value, size_t ma

vector<std::function<void(void)>> setupLua(LuaContext& luaCtx, bool client, bool configCheck, const std::string& config);
void setupLuaActions(LuaContext& luaCtx);
void setupLuaBindings(LuaContext& luaCtx, bool client);
void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck);
void setupLuaBindingsDNSCrypt(LuaContext& luaCtx, bool client);
void setupLuaBindingsDNSParser(LuaContext& luaCtx);
void setupLuaBindingsDNSQuestion(LuaContext& luaCtx);
Expand Down
2 changes: 2 additions & 0 deletions pdns/dnsdistdist/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ dnsdist_SOURCES = \
dnsdist-protocols.cc dnsdist-protocols.hh \
dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
dnsdist-random.cc dnsdist-random.hh \
dnsdist-resolver.cc dnsdist-resolver.hh \
dnsdist-rings.cc dnsdist-rings.hh \
dnsdist-rules.cc dnsdist-rules.hh \
dnsdist-secpoll.cc dnsdist-secpoll.hh \
Expand Down Expand Up @@ -292,6 +293,7 @@ testrunner_SOURCES = \
dnsdist-protocols.cc dnsdist-protocols.hh \
dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
dnsdist-random.cc dnsdist-random.hh \
dnsdist-resolver.cc dnsdist-resolver.hh \
dnsdist-rings.cc dnsdist-rings.hh \
dnsdist-rules.cc dnsdist-rules.hh \
dnsdist-session-cache.cc dnsdist-session-cache.hh \
Expand Down
2 changes: 1 addition & 1 deletion pdns/dnsdistdist/dnsdist-lua-ffi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ const char* getLuaFFIWrappers()

void setupLuaLoadBalancingContext(LuaContext& luaCtx)
{
setupLuaBindings(luaCtx, true);
setupLuaBindings(luaCtx, true, false);
setupLuaBindingsDNSQuestion(luaCtx);
setupLuaBindingsKVS(luaCtx, true);
setupLuaVars(luaCtx);
Expand Down
52 changes: 52 additions & 0 deletions pdns/dnsdistdist/dnsdist-resolver.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* This file is part of PowerDNS or dnsdist.
* Copyright -- PowerDNS.COM B.V. and its contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* In addition, for the avoidance of any doubt, permission is granted to
* link this program with OpenSSL and to (re)distribute the binaries
* produced as the result of such linking.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <vector>

#include "dnsdist-resolver.hh"
#include "iputils.hh"

namespace dnsdist::resolver
{
void asynchronousResolver(const std::string& hostname, const std::function<void(const std::string& hostname, std::vector<ComboAddress>& ips)>& callback)
{
addrinfo hints{};
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_socktype = SOCK_DGRAM;
addrinfo* infosRaw{nullptr};
std::vector<ComboAddress> addresses;
auto ret = getaddrinfo(hostname.c_str(), nullptr, &hints, &infosRaw);
if (ret != 0) {
callback(hostname, addresses);
return;
}
auto infos = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>(infosRaw, &freeaddrinfo);
for (const auto* addr = infos.get(); addr != nullptr; addr = addr->ai_next) {
try {
addresses.emplace_back(addr->ai_addr, addr->ai_addrlen);
}
catch (...) {
}
}
callback(hostname, addresses);
}
}
28 changes: 28 additions & 0 deletions pdns/dnsdistdist/dnsdist-resolver.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* This file is part of PowerDNS or dnsdist.
* Copyright -- PowerDNS.COM B.V. and its contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* In addition, for the avoidance of any doubt, permission is granted to
* link this program with OpenSSL and to (re)distribute the binaries
* produced as the result of such linking.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "iputils.hh"

namespace dnsdist::resolver
{
void asynchronousResolver(const std::string& hostname, const std::function<void(const std::string& hostname, std::vector<ComboAddress>& ips)>& callback);
}
19 changes: 19 additions & 0 deletions pdns/dnsdistdist/docs/reference/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1915,6 +1915,25 @@ These values can be set at configuration time via:
Other functions
---------------

.. function:: getAddressInfo(hostname, callback)

.. versionadded:: 1.9.0

Asynchronously resolve, via the system resolver (using ``getaddrinfo()``), the supplied ``hostname`` to IPv4 and IPv6 addresses (if configured on the host) before invoking the supplied ``callback`` function with the ``hostname`` and a list of IPv4 and IPv6 addresses as :class:`ComboAddress`.
For example, to get the addresses of Quad9's resolver and dynamically add them as backends:

.. code-block:: lua
function resolveCB(hostname, ips)
for _, ip in ipairs(ips) do
newServer(ip:toString())
end
end
getAddressInfo('dns.quad9.net.', resolveCB)
:param str hostname: The hostname to resolve.
:param function callback: The function to invoke when the name has been resolved.

.. function:: getCurrentTime -> timespec

.. versionadded:: 1.8.0
Expand Down
48 changes: 48 additions & 0 deletions regression-tests.dnsdist/test_BackendDiscovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,3 +409,51 @@ def testBackendUpgrade(self):
# let's wait a bit longer
time.sleep(5)
self.assertTrue(self.checkBackendsUpgraded())

class TestBackendDiscoveryByHostname(DNSDistTest):
_consoleKey = DNSDistTest.generateConsoleKey()
_consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
_config_params = ['_consoleKeyB64', '_consolePort']
_config_template = """
setKey("%s")
controlSocket("127.0.0.1:%d")
function resolveCB(hostname, ips)
print('Got response for '..hostname)
for _, ip in ipairs(ips) do
print(ip)
newServer(ip:toString())
end
end
getAddressInfo('dns.quad9.net.', resolveCB)
"""
def checkBackends(self):
output = self.sendConsoleCommand('showServers()')
print(output)
backends = {}
for line in output.splitlines(False):
if line.startswith('#') or line.startswith('All'):
continue
tokens = line.split()
self.assertTrue(len(tokens) == 13 or len(tokens) == 14)
backends[tokens[1]] = tokens[2]

if len(backends) != 4:
return False

for expected in ['9.9.9.9:53', '149.112.112.112:53', '[2620:fe::9]:53', '[2620:fe::fe]:53']:
self.assertIn(expected, backends)
for backend in backends:
self.assertTrue(backends[backend])
return True

def testBackendFromHostname(self):
"""
Backend Discovery: From hostname
"""
# enough time for resolution to happen
time.sleep(4)
if not self.checkBackends():
time.sleep(4)
self.assertTrue(self.checkBackends())

0 comments on commit 099d31d

Please sign in to comment.