bool d_addECS{false};
};
-TeeAction::TeeAction(const ComboAddress& rca, const boost::optional<ComboAddress>& lca, bool addECS)
+TeeAction::TeeAction(const ComboAddress& rca, const boost::optional<ComboAddress>& lca, bool addECS)
: d_remote(rca), d_addECS(addECS)
{
d_fd=SSocket(d_remote.sin4.sin_family, SOCK_DGRAM, 0);
}
}
+static void addTagsToProtobuf(DNSDistProtoBufMessage& message, const DNSQuestion& dq, const std::unordered_set<std::string>& allowed)
+{
+ if (!dq.ids.qTag) {
+ return;
+ }
+
+ for (const auto& [key, value] : *dq.ids.qTag) {
+ if (!allowed.empty() && allowed.count(key) == 0) {
+ continue;
+ }
+
+ if (value.empty()) {
+ message.addTag(key);
+ }
+ else {
+ message.addTag(key + ":" + value);
+ }
+ }
+}
+
class RemoteLogAction : public DNSAction, public boost::noncopyable
{
public:
// this action does not stop the processing
- RemoteLogAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, std::vector<std::pair<std::string, ProtoBufMetaKey>>& metas): d_metas(std::move(metas)), d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey)
+ RemoteLogAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, std::vector<std::pair<std::string, ProtoBufMetaKey>>&& metas, std::optional<std::unordered_set<std::string>>&& tagsToExport): d_tagsToExport(std::move(tagsToExport)), d_metas(std::move(metas)), d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey)
{
}
}
#endif /* HAVE_IPCIPHER */
+ if (d_tagsToExport) {
+ addTagsToProtobuf(message, *dq, *d_tagsToExport);
+ }
+
addMetaDataToProtobuf(message, *dq, d_metas);
if (d_alterFunc) {
return "remote log to " + (d_logger ? d_logger->toString() : "");
}
private:
+ std::optional<std::unordered_set<std::string>> d_tagsToExport;
std::vector<std::pair<std::string, ProtoBufMetaKey>> d_metas;
std::shared_ptr<RemoteLoggerInterface> d_logger;
boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > d_alterFunc;
{
public:
// this action does not stop the processing
- RemoteLogResponseAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, bool includeCNAME, std::vector<std::pair<std::string, ProtoBufMetaKey>>& metas): d_metas(std::move(metas)), d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey), d_includeCNAME(includeCNAME)
+ RemoteLogResponseAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, bool includeCNAME, std::vector<std::pair<std::string, ProtoBufMetaKey>>&& metas, std::optional<std::unordered_set<std::string>>&& tagsToExport): d_tagsToExport(std::move(tagsToExport)), d_metas(std::move(metas)), d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey), d_includeCNAME(includeCNAME)
{
}
DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
}
#endif /* HAVE_IPCIPHER */
+ if (d_tagsToExport) {
+ addTagsToProtobuf(message, *dr, *d_tagsToExport);
+ }
+
addMetaDataToProtobuf(message, *dr, d_metas);
if (d_alterFunc) {
return "remote log response to " + (d_logger ? d_logger->toString() : "");
}
private:
+ std::optional<std::unordered_set<std::string>> d_tagsToExport;
std::vector<std::pair<std::string, ProtoBufMetaKey>> d_metas;
std::shared_ptr<RemoteLoggerInterface> d_logger;
boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > d_alterFunc;
std::string serverID;
std::string ipEncryptKey;
+ std::string tags;
getOptionalValue<std::string>(vars, "serverID", serverID);
getOptionalValue<std::string>(vars, "ipEncryptKey", ipEncryptKey);
+ getOptionalValue<std::string>(vars, "exportTags", tags);
std::vector<std::pair<std::string, ProtoBufMetaKey>> metaOptions;
if (metas) {
}
}
+ std::optional<std::unordered_set<std::string>> tagsToExport{std::nullopt};
+ if (!tags.empty()) {
+ tagsToExport = std::unordered_set<std::string>();
+ if (tags != "*") {
+ std::vector<std::string> tokens;
+ stringtok(tokens, tags, ",");
+ for (auto& token : tokens) {
+ tagsToExport->insert(std::move(token));
+ }
+ }
+ }
+
checkAllParametersConsumed("RemoteLogAction", vars);
- return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID, ipEncryptKey, metaOptions));
+ return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID, ipEncryptKey, std::move(metaOptions), std::move(tagsToExport)));
});
luaCtx.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME, boost::optional<LuaAssociativeTable<std::string>> vars, boost::optional<LuaAssociativeTable<std::string>> metas) {
std::string serverID;
std::string ipEncryptKey;
+ std::string tags;
getOptionalValue<std::string>(vars, "serverID", serverID);
getOptionalValue<std::string>(vars, "ipEncryptKey", ipEncryptKey);
+ getOptionalValue<std::string>(vars, "exportTags", tags);
std::vector<std::pair<std::string, ProtoBufMetaKey>> metaOptions;
if (metas) {
}
}
+ std::optional<std::unordered_set<std::string>> tagsToExport{std::nullopt};
+ if (!tags.empty()) {
+ tagsToExport = std::unordered_set<std::string>();
+ if (tags != "*") {
+ std::vector<std::string> tokens;
+ stringtok(tokens, tags, ",");
+ for (auto& token : tokens) {
+ tagsToExport->insert(std::move(token));
+ }
+ }
+ }
+
checkAllParametersConsumed("RemoteLogResponseAction", vars);
- return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, ipEncryptKey, includeCNAME ? *includeCNAME : false, metaOptions));
+ return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, ipEncryptKey, includeCNAME ? *includeCNAME : false, std::move(metaOptions), std::move(tagsToExport)));
});
luaCtx.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
.. versionchanged:: 1.8.0
``metas`` optional parameter added.
+ ``exportTags`` optional key added to the options table.
Send the content of this query to a remote logger via Protocol Buffer.
``alterFunction`` is a callback, receiving a :class:`DNSQuestion` and a :class:`DNSDistProtoBufMessage`, that can be used to modify the Protocol Buffer content, for example for anonymization purposes.
* ``serverID=""``: str - Set the Server Identity field.
* ``ipEncryptKey=""``: str - A key, that can be generated via the :func:`makeIPCipherKey` function, to encrypt the IP address of the requestor for anonymization purposes. The encryption is done using ipcrypt for IPv4 and a 128-bit AES ECB operation for IPv6.
+ * ``exportTags=""``: str - The comma-separated list of keys of internal tags to export into the ``tags`` Protocol Buffer field, as "key:value" strings. Note that a tag with an empty value will be exported as "<key>", not "<key>:". An empty string means that no internal tag will be exported. The special value ``*`` means that all tags will be exported.
.. function:: RemoteLogResponseAction(remoteLogger[, alterFunction[, includeCNAME [, options [, metas]]]])
.. versionchanged:: 1.8.0
``metas`` optional parameter added.
+ ``exportTags`` optional key added to the options table.
Send the content of this response to a remote logger via Protocol Buffer.
``alterFunction`` is the same callback that receiving a :class:`DNSQuestion` and a :class:`DNSDistProtoBufMessage`, that can be used to modify the Protocol Buffer content, for example for anonymization purposes.
* ``serverID=""``: str - Set the Server Identity field.
* ``ipEncryptKey=""``: str - A key, that can be generated via the :func:`makeIPCipherKey` function, to encrypt the IP address of the requestor for anonymization purposes. The encryption is done using ipcrypt for IPv4 and a 128-bit AES ECB operation for IPv6.
+ * ``exportTags=""``: str - The comma-separated list of keys of internal tags to export into the ``tags`` Protocol Buffer field, as "key:value" strings. Note that a tag with an empty value will be exported as "<key>", not "<key>:". An empty string means that no internal tag will be exported. The special value ``*`` means that all tags will be exported.
.. function:: SetAdditionalProxyProtocolValueAction(type, value)
addAction(AllRule(), SetTagAction('my-tag-key', 'my-tag-value'))
addAction(AllRule(), SetTagAction('my-empty-key', ''))
- addAction(AllRule(), RemoteLogAction(rl, nil, {serverID='dnsdist-server-1'}, {b64='b64-content', ['my-tag-export-name']='tag:my-tag-key'}))
+ addAction(AllRule(), RemoteLogAction(rl, nil, {serverID='dnsdist-server-1', exportTags='*'}, {b64='b64-content', ['my-tag-export-name']='tag:my-tag-key'}))
addResponseAction(AllRule(), SetTagResponseAction('my-tag-key2', 'my-tag-value2'))
- addResponseAction(AllRule(), RemoteLogResponseAction(rl, nil, false, {serverID='dnsdist-server-1'}, {['my-tag-export-name']='tags'}))
+ addResponseAction(AllRule(), RemoteLogResponseAction(rl, nil, false, {serverID='dnsdist-server-1', exportTags='my-empty-key,my-tag-key2'}, {['my-tag-export-name']='tags'}))
"""
def testProtobufMeta(self):
msg = self.getFirstProtobufMessage()
self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
+ # regular tags
+ self.assertEqual(len(msg.response.tags), 2)
+ self.assertIn('my-tag-key:my-tag-value', msg.response.tags)
+ self.assertIn('my-empty-key', msg.response.tags)
+ # meta tags
self.assertEqual(len(msg.meta), 2)
tags = {}
for entry in msg.meta:
# check the protobuf message corresponding to the UDP response
msg = self.getFirstProtobufMessage()
self.checkProtobufResponse(msg, dnsmessage_pb2.PBDNSMessage.UDP, response)
+ # regular tags
+ self.assertEqual(len(msg.response.tags), 2)
+ self.assertIn('my-tag-key2:my-tag-value2', msg.response.tags)
+ self.assertIn('my-empty-key', msg.response.tags)
+ # meta tags
self.assertEqual(len(msg.meta), 1)
self.assertEqual(msg.meta[0].key, 'my-tag-export-name')
self.assertEqual(len(msg.meta[0].value.stringVal), 3)