Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rec: reload proxy settings on rec_control reload-acls #15167

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions pdns/recursordist/pdns_recursor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t>>> t_
thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
thread_local std::shared_ptr<NetmaskGroup> t_allowNotifyFrom;
thread_local std::shared_ptr<notifyset_t> t_allowNotifyFor;
thread_local std::shared_ptr<NetmaskGroup> t_proxyProtocolACL;
thread_local std::shared_ptr<std::set<ComboAddress>> t_proxyProtocolExceptions;

__thread struct timeval g_now; // timestamp, updated (too) frequently

using listenSocketsAddresses_t = map<int, ComboAddress>; // is shared across all threads right now
Expand Down Expand Up @@ -2150,7 +2153,16 @@ void requestWipeCaches(const DNSName& canon)

bool expectProxyProtocol(const ComboAddress& from, const ComboAddress& listenAddress)
{
return g_proxyProtocolACL.match(from) && g_proxyProtocolExceptions.count(listenAddress) == 0;
if (!t_proxyProtocolACL) {
return false;
}
if (t_proxyProtocolACL->match(from)) {
if (!t_proxyProtocolExceptions) {
return true;
}
return t_proxyProtocolExceptions->count(listenAddress) == 0;
}
return false;
}

// fromaddr: the address the query is coming from
Expand Down Expand Up @@ -2437,7 +2449,8 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr

static void handleNewUDPQuestion(int fileDesc, FDMultiplexer::funcparam_t& /* var */) // NOLINT(readability-function-cognitive-complexity): https://github.com/PowerDNS/pdns/issues/12791
{
static const size_t maxIncomingQuerySize = g_proxyProtocolACL.empty() ? 512 : (512 + g_proxyProtocolMaximumSize);
const bool proxyActive = t_proxyProtocolACL && !t_proxyProtocolACL->empty();
static const size_t maxIncomingQuerySize = !proxyActive ? 512 : (512 + g_proxyProtocolMaximumSize);
static thread_local std::string data;
ComboAddress fromaddr; // the address the query is coming from
ComboAddress source; // the address we assume the query is coming from, might be set by proxy protocol
Expand Down
83 changes: 59 additions & 24 deletions pdns/recursordist/rec-main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ std::unique_ptr<nod::UniqueResponseDB> g_udrDBp;
std::atomic<bool> statsWanted;
uint32_t g_disthashseed;
bool g_useIncomingECS;
NetmaskGroup g_proxyProtocolACL;
std::set<ComboAddress> g_proxyProtocolExceptions;
static shared_ptr<NetmaskGroup> g_initialProxyProtocolACL;
static shared_ptr<std::set<ComboAddress>> g_initialProxyProtocolExceptions;
boost::optional<ComboAddress> g_dns64Prefix{boost::none};
DNSName g_dns64PrefixReverse;
unsigned int g_maxChainLength;
Expand Down Expand Up @@ -1388,11 +1388,25 @@ void* pleaseSupplantAllowNotifyFor(std::shared_ptr<notifyset_t> allowNotifyFor)
return nullptr;
}

void* pleaseSupplantProxyProtocolSettings(std::shared_ptr<NetmaskGroup> acl, std::shared_ptr<std::set<ComboAddress>> except)
{
t_proxyProtocolACL = std::move(acl);
t_proxyProtocolExceptions = std::move(except);
return nullptr;
}

void parseACLs()
{
auto log = g_slog->withName("config");

static bool l_initialized;
const std::array<string, 6> aclNames = {
"allow-from-file",
"allow-from",
"allow-notify-from-file",
"allow-notify-from",
"proxy-protocol-from",
"proxy-protocol-exceptions"};

if (l_initialized) { // only reload configuration file on second call

Expand Down Expand Up @@ -1434,6 +1448,8 @@ void parseACLs()
throw runtime_error("Unable to re-parse configuration file '" + configName + "'");
}
::arg().preParseFile(configName, "allow-notify-from");
::arg().preParseFile(configName, "proxy-protocol-from");
::arg().preParseFile(configName, "proxy-protocol-exceptions");

::arg().preParseFile(configName, "include-dir");
::arg().preParse(g_argc, g_argv, "include-dir");
Expand All @@ -1443,28 +1459,18 @@ void parseACLs()
::arg().gatherIncludes(::arg()["include-dir"], ".conf", extraConfigs);

for (const std::string& fileName : extraConfigs) {
if (!::arg().preParseFile(fileName, "allow-from-file", ::arg()["allow-from-file"])) {
throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
}
if (!::arg().preParseFile(fileName, "allow-from", ::arg()["allow-from"])) {
throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
}

if (!::arg().preParseFile(fileName, "allow-notify-from-file", ::arg()["allow-notify-from-file"])) {
throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
}
if (!::arg().preParseFile(fileName, "allow-notify-from", ::arg()["allow-notify-from"])) {
throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
for (const auto& aclName : aclNames) {
if (!::arg().preParseFile(fileName, aclName, ::arg()[aclName])) {
throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
}
}
}
}
}
// Process command line args potentially overriding settings read from file
::arg().preParse(g_argc, g_argv, "allow-from-file");
::arg().preParse(g_argc, g_argv, "allow-from");

::arg().preParse(g_argc, g_argv, "allow-notify-from-file");
::arg().preParse(g_argc, g_argv, "allow-notify-from");
for (const auto& aclName : aclNames) {
::arg().preParse(g_argc, g_argv, aclName);
}

auto allowFrom = parseACL("allow-from-file", "allow-from", log);

Expand All @@ -1486,6 +1492,28 @@ void parseACLs()
// coverity[copy_constructor_call] maybe this can be avoided, but be careful as pointers get passed to other threads
broadcastFunction([=] { return pleaseSupplantAllowNotifyFrom(allowNotifyFrom); });

std::shared_ptr<NetmaskGroup> proxyProtocolACL;
std::shared_ptr<std::set<ComboAddress>> proxyProtocolExceptions;
if (!::arg()["proxy-protocol-from"].empty()) {
proxyProtocolACL = std::make_shared<NetmaskGroup>();
proxyProtocolACL->toMasks(::arg()["proxy-protocol-from"]);

std::vector<std::string> vec;
stringtok(vec, ::arg()["proxy-protocol-exceptions"], ", ");
if (!vec.empty()) {
proxyProtocolExceptions = std::make_shared<std::set<ComboAddress>>();
for (const auto& sockAddrStr : vec) {
ComboAddress sockAddr(sockAddrStr, 53);
proxyProtocolExceptions->emplace(sockAddr);
}
}
}
g_initialProxyProtocolACL = proxyProtocolACL;
g_initialProxyProtocolExceptions = proxyProtocolExceptions;

// coverity[copy_constructor_call] maybe this can be avoided, but be careful as pointers get passed to other threads
broadcastFunction([=] { return pleaseSupplantProxyProtocolSettings(proxyProtocolACL, proxyProtocolExceptions); });

l_initialized = true;
}

Expand Down Expand Up @@ -2216,13 +2244,18 @@ static int serviceMain(Logr::log_t log)
return ret;
}

g_proxyProtocolACL.toMasks(::arg()["proxy-protocol-from"]);
{
if (!::arg()["proxy-protocol-from"].empty()) {
g_initialProxyProtocolACL = std::make_shared<NetmaskGroup>();
g_initialProxyProtocolACL->toMasks(::arg()["proxy-protocol-from"]);

std::vector<std::string> vec;
stringtok(vec, ::arg()["proxy-protocol-exceptions"], ", ");
for (const auto& sockAddrStr : vec) {
ComboAddress sockAddr(sockAddrStr, 53);
g_proxyProtocolExceptions.emplace(sockAddr);
if (!vec.empty()) {
g_initialProxyProtocolExceptions = std::make_shared<std::set<ComboAddress>>();
for (const auto& sockAddrStr : vec) {
ComboAddress sockAddr(sockAddrStr, 53);
g_initialProxyProtocolExceptions->emplace(sockAddr);
}
}
}
g_proxyProtocolMaximumSize = ::arg().asNum("proxy-protocol-maximum-size");
Expand Down Expand Up @@ -2834,6 +2867,8 @@ static void recursorThread()
t_allowFrom = *g_initialAllowFrom.lock();
t_allowNotifyFrom = *g_initialAllowNotifyFrom.lock();
t_allowNotifyFor = *g_initialAllowNotifyFor.lock();
t_proxyProtocolACL = g_initialProxyProtocolACL;
t_proxyProtocolExceptions = g_initialProxyProtocolExceptions;
t_udpclientsocks = std::make_unique<UDPClientSocks>();
t_tcpClientCounts = std::make_unique<tcpClientCounts_t>();
if (g_proxyMapping) {
Expand Down
4 changes: 2 additions & 2 deletions pdns/recursordist/rec-main.hh
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,12 @@ extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
extern thread_local std::shared_ptr<NetmaskGroup> t_allowNotifyFrom;
extern thread_local std::shared_ptr<notifyset_t> t_allowNotifyFor;
extern thread_local std::unique_ptr<UDPClientSocks> t_udpclientsocks;
extern thread_local std::shared_ptr<NetmaskGroup> t_proxyProtocolACL;
extern thread_local std::shared_ptr<std::set<ComboAddress>> t_proxyProtocolExceptions;
extern bool g_useIncomingECS;
extern boost::optional<ComboAddress> g_dns64Prefix;
extern DNSName g_dns64PrefixReverse;
extern uint64_t g_latencyStatSize;
extern NetmaskGroup g_proxyProtocolACL;
extern std::set<ComboAddress> g_proxyProtocolExceptions;
extern std::atomic<bool> g_statsWanted;
extern uint32_t g_disthashseed;
extern int g_argc;
Expand Down
2 changes: 2 additions & 0 deletions pdns/recursordist/rec-rust-lib/cxxsupport.cc
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,8 @@ void pdns::settings::rec::setArgsForACLRelatedSettings(Recursorsettings& setting
::arg().set("allow-from-file") = to_arg(settings.incoming.allow_from_file);
::arg().set("allow-notify-from") = to_arg(settings.incoming.allow_notify_from);
::arg().set("allow-notify-from-file") = to_arg(settings.incoming.allow_notify_from_file);
::arg().set("proxy-protocol-from") = to_arg(settings.incoming.proxy_protocol_from);
::arg().set("proxy-protocol-exceptions") = to_arg(settings.incoming.proxy_protocol_exceptions);
}

void pdns::settings::rec::to_yaml(uint64_t& field, const std::string& val)
Expand Down
6 changes: 5 additions & 1 deletion pdns/recursordist/rec-rust-lib/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -2196,7 +2196,9 @@
The dnsdist docs have `more information about the PROXY protocol <https://dnsdist.org/advanced/passing-source-address.html#proxy-protocol>`_.
''',
'versionadded' : '4.4.0',
'versionchanged' : ('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence')
'versionchanged' : [('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence'),
('5.3.0', '``rec_control reload-acls`` reloads this setting')],
'runtime': ['reload-acls (since 5.3.0)'],
},
{
'name' : 'proxy_protocol_exceptions',
Expand All @@ -2210,6 +2212,8 @@
This is typically used to provide an easy to use address and port to send debug queries to.
''',
'versionadded' : '5.1.0',
'versionchanged' : ('5.3.0', '``rec_control reload-acls`` reloads this setting'),
'runtime': ['reload-acls (since 5.3.0)'],
},
{
'name' : 'proxy_protocol_maximum_size',
Expand Down