]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
feat(dnsdist): Add delay option to RemoteLogResponseAction
authorPieter Lexis <pieter.lexis@powerdns.com>
Mon, 13 Oct 2025 19:27:38 +0000 (21:27 +0200)
committerPieter Lexis <pieter.lexis@powerdns.com>
Tue, 14 Oct 2025 19:00:01 +0000 (21:00 +0200)
pdns/dnsdistdist/dnsdist-actions-factory.cc
pdns/dnsdistdist/dnsdist-actions-factory.hh
pdns/dnsdistdist/dnsdist-configuration-yaml.cc
pdns/dnsdistdist/dnsdist-idstate.hh
pdns/dnsdistdist/dnsdist-response-actions-definitions.yml
pdns/dnsdistdist/dnsdist.cc
pdns/dnsdistdist/docs/reference/ottrace.rst

index fdfe8ef092a4293a7fd7de7a2d176ab5e7c0a4fc..610bd4687932c69b3abb0612d598adae4f4e641c 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
+#include <memory>
 #include <optional>
 #include <unordered_map>
+#include <utility>
 
 #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<DNSDistProtoBufMessage>(std::make_unique<DNSDistProtoBufMessage>(message)), std::shared_ptr<RemoteLoggerInterface>(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<pdns::ipcrypt2::IPCrypt2> d_ipcrypt2{std::nullopt};
   std::optional<std::string> d_exportExtendedErrorsToMeta{std::nullopt};
   bool d_includeCNAME;
+  bool d_delay{false};
 };
 
 #endif /* DISABLE_PROTOBUF */
index 589467046859f251b43c2b2e5e63b630475648df..f02f0be2328b0236f6cbd4eeb0d254e027eb6568 100644 (file)
@@ -116,6 +116,7 @@ struct RemoteLogActionConfiguration
   std::string ipEncryptMethod{"legacy"};
   std::optional<std::string> exportExtendedErrorsToMeta{std::nullopt};
   bool includeCNAME{false};
+  bool delay{false};
 };
 std::shared_ptr<DNSAction> getRemoteLogAction(RemoteLogActionConfiguration& config);
 std::shared_ptr<DNSResponseAction> getRemoteLogResponseAction(RemoteLogActionConfiguration& config);
index 35495415330ea46bb09c3fc88bef12c0fcddf96f..f1467c5291b49bfbe183b1c746465755fee9f735 100644 (file)
@@ -1724,6 +1724,7 @@ std::shared_ptr<DNSResponseActionWrapper> 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
index 0afb8a89bebd1c8ebe05d73f73240fa247c386a1..9287f4fddd96ac158fc860d4132d2abb64bfae9d 100644 (file)
 #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> qTag{nullptr}; // 8
   std::unique_ptr<PacketBuffer> d_packet{nullptr}; // Initial packet, so we can restart the query from the response path if needed // 8
   std::unique_ptr<ProtoBufData> d_protoBufData{nullptr};
+#ifndef DISABLE_PROTOBUF
+  std::vector<std::pair<std::unique_ptr<DNSDistProtoBufMessage>, std::shared_ptr<RemoteLoggerInterface>>> delayedResponseMsgs;
+#endif
   std::unique_ptr<EDNSExtendedError> d_extendedError{nullptr};
   boost::optional<uint32_t> tempFailureTTL{boost::none}; // 8
   ClientState* cs{nullptr}; // 8
index 6b2aa60e1817b0d814cc9b5df44a7f767541fb39..f9959dfe0844c471079ae361f2514c1e7fa8f894 100644 (file)
@@ -179,6 +179,10 @@ The function will be invoked in a per-thread Lua state, without access to the gl
       type: "Vec<ProtoBufMetaConfiguration>"
       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:
index 4cfc5ebec35f010de45e107246d0c3c307797352..1640d4c1ed3156c3d12de39039bef0cf8d4313bd 100644 (file)
@@ -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)
index 472874519329cb73053ad098f41b923eb16ba760..0402d8da4b06e020a27c2cea971f5afa1ceb9d61 100644 (file)
@@ -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
 ==================================================