From: Pieter Lexis Date: Mon, 13 Oct 2025 19:27:38 +0000 (+0200) Subject: feat(dnsdist): Add delay option to RemoteLogResponseAction X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=456341c0fcdd4be6631b6e87a644718a6856cbf6;p=thirdparty%2Fpdns.git feat(dnsdist): Add delay option to RemoteLogResponseAction --- diff --git a/pdns/dnsdistdist/dnsdist-actions-factory.cc b/pdns/dnsdistdist/dnsdist-actions-factory.cc index fdfe8ef092..610bd46879 100644 --- a/pdns/dnsdistdist/dnsdist-actions-factory.cc +++ b/pdns/dnsdistdist/dnsdist-actions-factory.cc @@ -19,8 +19,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include #include +#include #include "dnsdist-actions-factory.hh" @@ -1812,7 +1814,7 @@ class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopya public: // this action does not stop the processing RemoteLogResponseAction(RemoteLogActionConfiguration& config) : - 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_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) { if (!d_ipEncryptKey.empty() && d_ipEncryptMethod == "ipcrypt-pfx") { d_ipcrypt2 = pdns::ipcrypt2::IPCrypt2(pdns::ipcrypt2::IPCryptMethod::pfx, d_ipEncryptKey); @@ -1859,13 +1861,18 @@ public: (*d_alterFunc)(response, &message); } - static thread_local std::string data; - data.clear(); - message.serialize(data); - if (!response->ids.d_rawProtobufContent.empty()) { - data.insert(data.end(), response->ids.d_rawProtobufContent.begin(), response->ids.d_rawProtobufContent.end()); + if (d_delay) { + response->ids.delayedResponseMsgs.emplace_back(std::unique_ptr(std::make_unique(message)), std::shared_ptr(d_logger)); + } + else { + static thread_local std::string data; + data.clear(); + message.serialize(data); + if (!response->ids.d_rawProtobufContent.empty()) { + data.insert(data.end(), response->ids.d_rawProtobufContent.begin(), response->ids.d_rawProtobufContent.end()); + } + d_logger->queueData(data); } - d_logger->queueData(data); return Action::None; } @@ -1885,6 +1892,7 @@ private: std::optional d_ipcrypt2{std::nullopt}; std::optional d_exportExtendedErrorsToMeta{std::nullopt}; bool d_includeCNAME; + bool d_delay{false}; }; #endif /* DISABLE_PROTOBUF */ diff --git a/pdns/dnsdistdist/dnsdist-actions-factory.hh b/pdns/dnsdistdist/dnsdist-actions-factory.hh index 5894670468..f02f0be232 100644 --- a/pdns/dnsdistdist/dnsdist-actions-factory.hh +++ b/pdns/dnsdistdist/dnsdist-actions-factory.hh @@ -116,6 +116,7 @@ struct RemoteLogActionConfiguration std::string ipEncryptMethod{"legacy"}; std::optional exportExtendedErrorsToMeta{std::nullopt}; bool includeCNAME{false}; + bool delay{false}; }; std::shared_ptr getRemoteLogAction(RemoteLogActionConfiguration& config); std::shared_ptr getRemoteLogResponseAction(RemoteLogActionConfiguration& config); diff --git a/pdns/dnsdistdist/dnsdist-configuration-yaml.cc b/pdns/dnsdistdist/dnsdist-configuration-yaml.cc index 3549541533..f1467c5291 100644 --- a/pdns/dnsdistdist/dnsdist-configuration-yaml.cc +++ b/pdns/dnsdistdist/dnsdist-configuration-yaml.cc @@ -1724,6 +1724,7 @@ std::shared_ptr getRemoteLogResponseAction(const Remot if (dnsdist::configuration::yaml::getLuaFunctionFromConfiguration(alterFunc, config.alter_function_name, config.alter_function_code, config.alter_function_file, "remote log response action")) { actionConfig.alterResponseFunc = std::move(alterFunc); } + actionConfig.delay = config.delay; auto action = dnsdist::actions::getRemoteLogResponseAction(actionConfig); return newDNSResponseActionWrapper(std::move(action), config.name); #endif diff --git a/pdns/dnsdistdist/dnsdist-idstate.hh b/pdns/dnsdistdist/dnsdist-idstate.hh index 0afb8a89be..9287f4fddd 100644 --- a/pdns/dnsdistdist/dnsdist-idstate.hh +++ b/pdns/dnsdistdist/dnsdist-idstate.hh @@ -41,6 +41,11 @@ #include "dnsdist-opentelemetry.hh" #include "uuid-utils.hh" +#ifndef DISABLE_PROTOBUF +#include "dnsdist-protobuf.hh" +#include "remote_logger.hh" +#endif + struct ClientState; struct DOHUnitInterface; struct DOQUnit; @@ -180,6 +185,9 @@ struct InternalQueryState std::unique_ptr qTag{nullptr}; // 8 std::unique_ptr d_packet{nullptr}; // Initial packet, so we can restart the query from the response path if needed // 8 std::unique_ptr d_protoBufData{nullptr}; +#ifndef DISABLE_PROTOBUF + std::vector, std::shared_ptr>> delayedResponseMsgs; +#endif std::unique_ptr d_extendedError{nullptr}; boost::optional tempFailureTTL{boost::none}; // 8 ClientState* cs{nullptr}; // 8 diff --git a/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml b/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml index 6b2aa60e18..f9959dfe08 100644 --- a/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml +++ b/pdns/dnsdistdist/dnsdist-response-actions-definitions.yml @@ -179,6 +179,10 @@ The function will be invoked in a per-thread Lua state, without access to the gl type: "Vec" default: true description: "A list of ``name``=``key`` pairs, for meta-data to be added to Protocol Buffer message" + - name: "delay" + type: "bool" + default: "false" + description: "Delay sending the protobuf message until after the response has been sent to the client. Useful when using OpenTelemetry Tracing" - name: "SetEDNSOption" description: "Add arbitrary EDNS option and data to the response. Any existing EDNS content with the same option code will be replaced. Subsequent rules are processed after this action" parameters: diff --git a/pdns/dnsdistdist/dnsdist.cc b/pdns/dnsdistdist/dnsdist.cc index 4cfc5ebec3..1640d4c1ed 100644 --- a/pdns/dnsdistdist/dnsdist.cc +++ b/pdns/dnsdistdist/dnsdist.cc @@ -651,6 +651,20 @@ bool sendUDPResponse(int origFD, const PacketBuffer& response, [[maybe_unused]] void handleResponseSent(const InternalQueryState& ids, double udiff, const ComboAddress& client, const ComboAddress& backend, unsigned int size, const dnsheader& cleartextDH, dnsdist::Protocol outgoingProtocol, bool fromBackend) { handleResponseSent(ids.qname, ids.qtype, udiff, client, backend, size, cleartextDH, outgoingProtocol, ids.protocol, fromBackend); + +#ifndef DISABLE_PROTOBUF + if (ids.tracingEnabled && !ids.delayedResponseMsgs.empty()) { + static thread_local std::string data; + for (auto const& msg_logger : ids.delayedResponseMsgs) { + data.clear(); + msg_logger.first->serialize(data); + if (!ids.d_rawProtobufContent.empty()) { + data.insert(data.end(), ids.d_rawProtobufContent.begin(), ids.d_rawProtobufContent.end()); + } + msg_logger.second->queueData(data); + } + } +#endif } void handleResponseSent(const DNSName& qname, const QType& qtype, double udiff, const ComboAddress& client, const ComboAddress& backend, unsigned int size, const dnsheader& cleartextDH, dnsdist::Protocol outgoingProtocol, dnsdist::Protocol incomingProtocol, bool fromBackend) diff --git a/pdns/dnsdistdist/docs/reference/ottrace.rst b/pdns/dnsdistdist/docs/reference/ottrace.rst index 4728745193..0402d8da4b 100644 --- a/pdns/dnsdistdist/docs/reference/ottrace.rst +++ b/pdns/dnsdistdist/docs/reference/ottrace.rst @@ -48,6 +48,11 @@ Example configuration action: type: RemoteLog logger_name: pblog + # Delay ensures that the PB message is sent + # after the response is sent to client, instead + # of immediately. This ensures all Trace Spans + # have proper end timestamps. + delay: true Passing Trace ID and Span ID to downstream servers ==================================================