Skip to content

Commit c4ceb9f

Browse files
committed
feat(dnsdist): Allow RemoteLog(Response)Action to use global Server ID
1 parent b3c1343 commit c4ceb9f

7 files changed

Lines changed: 212 additions & 17 deletions

pdns/dnsdistdist/dnsdist-actions-definitions.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,11 @@ The function will be invoked in a per-thread Lua state, without access to the gl
278278
- name: "server_id"
279279
type: "String"
280280
default: ""
281-
description: "Set the Server Identity field"
281+
description: "Set the value for the Server Identity field"
282+
- name: "use_server_id"
283+
type: "bool"
284+
default: "false"
285+
description: "Use the value of general.server_id for the Server Identity field. Overrides the value set with server_id"
282286
- name: "ip_encrypt_key"
283287
type: "String"
284288
default: ""

pdns/dnsdistdist/dnsdist-actions-factory.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "dnsdist-actions-factory.hh"
2929

3030
#include "config.h"
31+
#include "dnsdist-configuration.hh"
3132
#include "dnsdist.hh"
3233
#include "dnsdist-async.hh"
3334
#include "dnsdist-dnsparser.hh"
@@ -1607,7 +1608,7 @@ class RemoteLogAction : public DNSAction, public boost::noncopyable
16071608
public:
16081609
// this action does not stop the processing
16091610
RemoteLogAction(RemoteLogActionConfiguration& config) :
1610-
d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterQueryFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_ipEncryptMethod(config.ipEncryptMethod)
1611+
d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterQueryFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_ipEncryptMethod(config.ipEncryptMethod), d_useServerID(config.useServerID)
16111612
{
16121613
if (!d_ipEncryptKey.empty() && d_ipEncryptMethod == "ipcrypt-pfx") {
16131614
d_ipcrypt2 = pdns::ipcrypt2::IPCrypt2(pdns::ipcrypt2::IPCryptMethod::pfx, d_ipEncryptKey);
@@ -1625,7 +1626,9 @@ class RemoteLogAction : public DNSAction, public boost::noncopyable
16251626
}
16261627

16271628
DNSDistProtoBufMessage message(*dnsquestion);
1628-
if (!d_serverID.empty()) {
1629+
if (d_useServerID) {
1630+
message.setServerIdentity(dnsdist::configuration::getCurrentRuntimeConfiguration().d_server_id);
1631+
} else if (!d_serverID.empty()) {
16291632
message.setServerIdentity(d_serverID);
16301633
}
16311634

@@ -1675,6 +1678,7 @@ class RemoteLogAction : public DNSAction, public boost::noncopyable
16751678
std::string d_ipEncryptKey;
16761679
std::string d_ipEncryptMethod;
16771680
std::optional<pdns::ipcrypt2::IPCrypt2> d_ipcrypt2{std::nullopt};
1681+
bool d_useServerID;
16781682
};
16791683
#endif /* DISABLE_PROTOBUF */
16801684

@@ -1873,7 +1877,7 @@ class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopya
18731877
public:
18741878
// this action does not stop the processing
18751879
RemoteLogResponseAction(RemoteLogActionConfiguration& config) :
1876-
d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterResponseFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_ipEncryptMethod(config.ipEncryptMethod), d_exportExtendedErrorsToMeta(std::move(config.exportExtendedErrorsToMeta)), d_includeCNAME(config.includeCNAME), d_delay(config.delay)
1880+
d_tagsToExport(std::move(config.tagsToExport)), d_metas(std::move(config.metas)), d_logger(config.logger), d_alterFunc(std::move(config.alterResponseFunc)), d_serverID(config.serverID), d_ipEncryptKey(config.ipEncryptKey), d_ipEncryptMethod(config.ipEncryptMethod), d_exportExtendedErrorsToMeta(std::move(config.exportExtendedErrorsToMeta)), d_includeCNAME(config.includeCNAME), d_useServerID(config.useServerID), d_delay(config.delay)
18771881
{
18781882
if (!d_ipEncryptKey.empty() && d_ipEncryptMethod == "ipcrypt-pfx") {
18791883
d_ipcrypt2 = pdns::ipcrypt2::IPCrypt2(pdns::ipcrypt2::IPCryptMethod::pfx, d_ipEncryptKey);
@@ -1890,7 +1894,9 @@ class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopya
18901894
}
18911895

18921896
DNSDistProtoBufMessage message(*response, d_includeCNAME);
1893-
if (!d_serverID.empty()) {
1897+
if (d_useServerID) {
1898+
message.setServerIdentity(dnsdist::configuration::getCurrentRuntimeConfiguration().d_server_id);
1899+
} else if (!d_serverID.empty()) {
18941900
message.setServerIdentity(d_serverID);
18951901
}
18961902

@@ -1953,6 +1959,7 @@ class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopya
19531959
std::optional<pdns::ipcrypt2::IPCrypt2> d_ipcrypt2{std::nullopt};
19541960
std::optional<std::string> d_exportExtendedErrorsToMeta{std::nullopt};
19551961
bool d_includeCNAME;
1962+
bool d_useServerID{false};
19561963
bool d_delay{false};
19571964
};
19581965

pdns/dnsdistdist/dnsdist-actions-factory.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ struct RemoteLogActionConfiguration
117117
std::optional<std::string> exportExtendedErrorsToMeta{std::nullopt};
118118
bool includeCNAME{false};
119119
bool delay{false};
120+
bool useServerID{false};
120121
};
121122
std::shared_ptr<DNSAction> getRemoteLogAction(RemoteLogActionConfiguration& config);
122123
std::shared_ptr<DNSResponseAction> getRemoteLogResponseAction(RemoteLogActionConfiguration& config);

pdns/dnsdistdist/dnsdist-configuration-yaml.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,7 @@ std::shared_ptr<DNSActionWrapper> getRemoteLogAction(const RemoteLogActionConfig
17761776
if (dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(alterFunc, config.alter_function_name, config.alter_function_code, config.alter_function_file, "remote log action")) {
17771777
actionConfig.alterQueryFunc = std::move(alterFunc);
17781778
}
1779+
actionConfig.useServerID = config.use_server_id;
17791780
auto action = dnsdist::actions::getRemoteLogAction(actionConfig);
17801781
return newDNSActionWrapper(std::move(action), config.name);
17811782
#endif
@@ -1813,6 +1814,7 @@ std::shared_ptr<DNSResponseActionWrapper> getRemoteLogResponseAction(const Remot
18131814
actionConfig.alterResponseFunc = std::move(alterFunc);
18141815
}
18151816
actionConfig.delay = config.delay;
1817+
actionConfig.useServerID = config.use_server_id;
18161818
auto action = dnsdist::actions::getRemoteLogResponseAction(actionConfig);
18171819
return newDNSResponseActionWrapper(std::move(action), config.name);
18181820
#endif

pdns/dnsdistdist/dnsdist-lua-actions.cc

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "dnsdist-protobuf.hh"
2929
#include "dnsdist-rule-chains.hh"
3030
#include "dnstap.hh"
31+
#include "dolog.hh"
3132
#include "remote_logger.hh"
3233
#include <memory>
3334
#include <optional>
@@ -267,7 +268,7 @@ void setupLuaActions(LuaContext& luaCtx)
267268
// Used for both RemoteLogAction and RemoteLogResponseAction
268269
static const std::array<std::string, 2> s_validIpEncryptMethods = {"legacy", "ipcrypt-pfx"};
269270

270-
luaCtx.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, std::optional<dnsdist::actions::ProtobufAlterFunction> alterFunc, std::optional<LuaAssociativeTable<std::string>> vars, std::optional<LuaAssociativeTable<std::string>> metas) {
271+
luaCtx.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, std::optional<dnsdist::actions::ProtobufAlterFunction> alterFunc, std::optional<LuaAssociativeTable<boost::variant<std::string,bool>>> vars, std::optional<LuaAssociativeTable<std::string>> metas) {
271272
if (logger) {
272273
// avoids potentially-evaluated-expression warning with clang.
273274
RemoteLoggerInterface& remoteLoggerRef = *logger;
@@ -283,10 +284,25 @@ void setupLuaActions(LuaContext& luaCtx)
283284
if (alterFunc) {
284285
config.alterQueryFunc = std::move(*alterFunc);
285286
}
286-
getOptionalValue<std::string>(vars, "serverID", config.serverID);
287-
getOptionalValue<std::string>(vars, "ipEncryptKey", config.ipEncryptKey);
288-
getOptionalValue<std::string>(vars, "ipEncryptMethod", config.ipEncryptMethod);
289-
getOptionalValue<std::string>(vars, "exportTags", tags);
287+
if (getOptionalValue<std::string>(vars, "serverID", config.serverID) < 0) {
288+
throw std::runtime_error("serverID in RemoteLogAction is not a string");
289+
}
290+
if (getOptionalValue<std::string>(vars, "ipEncryptKey", config.ipEncryptKey) < 0) {
291+
throw std::runtime_error("ipEncryptKey in RemoteLogAction is not a string");
292+
}
293+
if (getOptionalValue<std::string>(vars, "ipEncryptMethod", config.ipEncryptMethod) < 0) {
294+
throw std::runtime_error("ipEncryptMethod in RemoteLogAction is not a string");
295+
}
296+
if (getOptionalValue<std::string>(vars, "exportTags", tags) < 0) {
297+
throw std::runtime_error("exportTags in RemoteLogAction is not a string");
298+
}
299+
if (getOptionalValue<bool>(vars, "useServerID", config.useServerID) < 0) {
300+
throw std::runtime_error("useServerID in RemoteLogAction is not a string");
301+
}
302+
303+
if (config.useServerID && !config.serverID.empty()) {
304+
warnlog("useServerID and serverID set in RemoteLogAction configuration. value for serverID will not be used");
305+
}
290306

291307
if (metas) {
292308
for (const auto& [key, value] : *metas) {
@@ -314,7 +330,7 @@ void setupLuaActions(LuaContext& luaCtx)
314330
return dnsdist::actions::getRemoteLogAction(config);
315331
});
316332

317-
luaCtx.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, std::optional<dnsdist::actions::ProtobufAlterResponseFunction> alterFunc, std::optional<bool> includeCNAME, std::optional<LuaAssociativeTable<std::string>> vars, std::optional<LuaAssociativeTable<std::string>> metas, std::optional<bool> delay) {
333+
luaCtx.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, std::optional<dnsdist::actions::ProtobufAlterResponseFunction> alterFunc, std::optional<bool> includeCNAME, std::optional<LuaAssociativeTable<boost::variant<std::string,bool>>> vars, std::optional<LuaAssociativeTable<std::string>> metas, std::optional<bool> delay) {
318334
if (logger) {
319335
// avoids potentially-evaluated-expression warning with clang.
320336
RemoteLoggerInterface& remoteLoggerRef = *logger;
@@ -331,11 +347,28 @@ void setupLuaActions(LuaContext& luaCtx)
331347
config.alterResponseFunc = std::move(*alterFunc);
332348
}
333349
config.includeCNAME = includeCNAME ? *includeCNAME : false;
334-
getOptionalValue<std::string>(vars, "serverID", config.serverID);
335-
getOptionalValue<std::string>(vars, "ipEncryptKey", config.ipEncryptKey);
336-
getOptionalValue<std::string>(vars, "ipEncryptMethod", config.ipEncryptMethod);
337-
getOptionalValue<std::string>(vars, "exportTags", tags);
338-
getOptionalValue<std::string>(vars, "exportExtendedErrorsToMeta", config.exportExtendedErrorsToMeta);
350+
if (getOptionalValue<std::string>(vars, "serverID", config.serverID) < 0) {
351+
throw std::runtime_error("serverID in RemoteLogResponseAction is not a string");
352+
}
353+
if (getOptionalValue<std::string>(vars, "ipEncryptKey", config.ipEncryptKey) < 0) {
354+
throw std::runtime_error("ipEncryptKey in RemoteLogResponseAction is not a string");
355+
}
356+
if (getOptionalValue<std::string>(vars, "ipEncryptMethod", config.ipEncryptMethod) < 0) {
357+
throw std::runtime_error("ipEncryptMethod in RemoteLogResponseAction is not a string");
358+
}
359+
if (getOptionalValue<std::string>(vars, "exportTags", tags) < 0) {
360+
throw std::runtime_error("exportTags in RemoteLogResponseAction is not a string");
361+
}
362+
if (getOptionalValue<std::string>(vars, "exportExtendedErrorsToMeta", config.exportExtendedErrorsToMeta) < 0) {
363+
throw std::runtime_error("exportExtendedErrorsToMeta in RemoteLogResponseAction is not a string");
364+
}
365+
if (getOptionalValue<bool>(vars, "useServerID", config.useServerID) < 0) {
366+
throw std::runtime_error("useServerID in RemoteLogResponseAction is not a string");
367+
}
368+
369+
if (config.useServerID && !config.serverID.empty()) {
370+
warnlog("useServerID and serverID set in RemoteLogResponseAction configuration. value for serverID will not be used");
371+
}
339372

340373
if (metas) {
341374
for (const auto& [key, value] : *metas) {

pdns/dnsdistdist/dnsdist-response-actions-definitions.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@ The function will be invoked in a per-thread Lua state, without access to the gl
151151
- name: "server_id"
152152
type: "String"
153153
default: ""
154-
description: "Set the Server Identity field"
154+
description: "Set the value of the Server Identity field"
155+
- name: "use_server_id"
156+
type: "bool"
157+
default: "false"
158+
description: "Use the general.server_id value to set the Server Identity field"
155159
- name: "ip_encrypt_key"
156160
type: "String"
157161
default: ""

regression-tests.dnsdist/test_Protobuf.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,3 +1473,147 @@ def testProtobuf(self):
14731473

14741474
self.assertTrue(gotUDP)
14751475
self.assertTrue(gotTCP)
1476+
1477+
class TestProtobufGlobalServerIDYaml(TestYamlProtobuf):
1478+
_yaml_config_template = """---
1479+
binds:
1480+
- listen_address: "127.0.0.1:%d"
1481+
reuseport: true
1482+
protocol: Do53
1483+
threads: 2
1484+
1485+
backends:
1486+
- address: "127.0.0.1:%d"
1487+
protocol: Do53
1488+
1489+
remote_logging:
1490+
protobuf_loggers:
1491+
- name: "my-logger"
1492+
address: "127.0.0.1:%d"
1493+
timeout: 1
1494+
1495+
general:
1496+
server_id: "%s"
1497+
1498+
query_rules:
1499+
- name: "my-rule"
1500+
selector:
1501+
type: "All"
1502+
action:
1503+
type: "RemoteLog"
1504+
logger_name: "my-logger"
1505+
use_server_id: true
1506+
export_tags:
1507+
- "tag-1"
1508+
- "tag-2"
1509+
"""
1510+
1511+
class TestProtobufGlobalServerIDLua(DNSDistProtobufTest):
1512+
_config_params = ['_protobufServerID', '_testServerPort', '_protobufServerPort']
1513+
_config_template = """
1514+
setServerID("%s")
1515+
luasmn = newSuffixMatchNode()
1516+
luasmn:add(newDNSName('lua.protobuf.tests.powerdns.com.'))
1517+
1518+
function alterProtobufResponse(dq, protobuf)
1519+
if luasmn:check(dq.qname) then
1520+
requestor = newCA(tostring(dq.remoteaddr)) -- called by testLuaProtobuf()
1521+
if requestor:isIPv4() then
1522+
requestor:truncate(24)
1523+
else
1524+
requestor:truncate(56)
1525+
end
1526+
protobuf:setRequestor(requestor)
1527+
1528+
local tableTags = {}
1529+
table.insert(tableTags, "TestLabel1,TestData1")
1530+
table.insert(tableTags, "TestLabel2,TestData2")
1531+
1532+
protobuf:setTagArray(tableTags)
1533+
1534+
protobuf:setTag('TestLabel3,TestData3')
1535+
1536+
protobuf:setTag("Response,456")
1537+
1538+
else
1539+
1540+
local tableTags = {} -- called by testProtobuf()
1541+
table.insert(tableTags, "TestLabel1,TestData1")
1542+
table.insert(tableTags, "TestLabel2,TestData2")
1543+
protobuf:setTagArray(tableTags)
1544+
1545+
protobuf:setTag('TestLabel3,TestData3')
1546+
1547+
protobuf:setTag("Response,456")
1548+
1549+
end
1550+
end
1551+
1552+
function alterProtobufQuery(dq, protobuf)
1553+
1554+
if luasmn:check(dq.qname) then
1555+
requestor = newCA(tostring(dq.remoteaddr)) -- called by testLuaProtobuf()
1556+
if requestor:isIPv4() then
1557+
requestor:truncate(24)
1558+
else
1559+
requestor:truncate(56)
1560+
end
1561+
protobuf:setRequestor(requestor)
1562+
1563+
local tableTags = {}
1564+
tableTags = dq:getTagArray() -- get table from DNSQuery
1565+
1566+
local tablePB = {}
1567+
for k, v in pairs( tableTags) do
1568+
table.insert(tablePB, k .. "," .. v)
1569+
end
1570+
1571+
protobuf:setTagArray(tablePB) -- store table in protobuf
1572+
protobuf:setTag("Query,123") -- add another tag entry in protobuf
1573+
1574+
protobuf:setResponseCode(DNSRCode.NXDOMAIN) -- set protobuf response code to be NXDOMAIN
1575+
1576+
local strReqName = tostring(dq.qname) -- get request dns name
1577+
1578+
protobuf:setProtobufResponseType() -- set protobuf to look like a response and not a query, with 0 default time
1579+
1580+
blobData = '\127' .. '\000' .. '\000' .. '\002' -- 127.0.0.2, note: lua 5.1 can only embed decimal not hex
1581+
1582+
protobuf:addResponseRR(strReqName, 1, 1, 123, blobData) -- add a RR to the protobuf
1583+
1584+
protobuf:setBytes(65) -- set the size of the query to confirm in checkProtobufBase
1585+
1586+
else
1587+
1588+
local tableTags = {} -- called by testProtobuf()
1589+
table.insert(tableTags, "TestLabel1,TestData1")
1590+
table.insert(tableTags, "TestLabel2,TestData2")
1591+
1592+
protobuf:setTagArray(tableTags)
1593+
protobuf:setTag('TestLabel3,TestData3')
1594+
protobuf:setTag("Query,123")
1595+
1596+
end
1597+
end
1598+
1599+
function alterLuaFirst(dq) -- called when dnsdist receives new request
1600+
local tt = {}
1601+
tt["TestLabel1"] = "TestData1"
1602+
tt["TestLabel2"] = "TestData2"
1603+
1604+
dq:setTagArray(tt)
1605+
1606+
dq:setTag("TestLabel3","TestData3")
1607+
return DNSAction.None, "" -- continue to the next rule
1608+
end
1609+
1610+
newServer{address="127.0.0.1:%d", useClientSubnet=true}
1611+
rl = newRemoteLogger('127.0.0.1:%d')
1612+
1613+
addAction(AllRule(), LuaAction(alterLuaFirst)) -- Add tags to DNSQuery first
1614+
1615+
addAction(AllRule(), RemoteLogAction(rl, alterProtobufQuery, {useServerID=true})) -- Send protobuf message before lookup
1616+
1617+
addResponseAction(AllRule(), RemoteLogResponseAction(rl, alterProtobufResponse, true, {useServerID=true})) -- Send protobuf message after lookup
1618+
1619+
"""

0 commit comments

Comments
 (0)