]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Encode TraceID and SpanID into a single EDNS option record, as suggested by Habbie
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 19 Jun 2025 08:28:53 +0000 (10:28 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 19 Jun 2025 08:28:53 +0000 (10:28 +0200)
Signed-off-by: Otto Moerbeek <otto.moerbeek@open-xchange.com>
pdns/ednsoptions.hh
pdns/protozero-trace.cc
pdns/sdig.cc

index 9ec8a5b81f95958098f9fa52cba53c0391f80657..fee6eb4afdd1cf65eb698e7129abb38600b17d97 100644 (file)
@@ -25,7 +25,7 @@
 struct EDNSOptionCode
 {
   // Temporary code assigned for OpenTelemetry TraceID and SpanID
-  enum EDNSOptionCodeEnum : uint16_t {NSID=3, DAU=5, DHU=6, N3U=7, ECS=8, EXPIRE=9, COOKIE=10, TCPKEEPALIVE=11, PADDING=12, CHAIN=13, KEYTAG=14, EXTENDEDERROR=15, OTTRACEID=65500, OTSPANID=65501};
+  enum EDNSOptionCodeEnum : uint16_t {NSID=3, DAU=5, DHU=6, N3U=7, ECS=8, EXPIRE=9, COOKIE=10, TCPKEEPALIVE=11, PADDING=12, CHAIN=13, KEYTAG=14, EXTENDEDERROR=15, OTTRACEIDS=65500};
 };
 
 /* extract the position (relative to the optRR pointer!) and size of a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
index c501c4ce1c4b21f3f42c4a7adbe616d2dca15243..059e2a679647f25f4f4e00b36a47f85599d062f9 100644 (file)
@@ -512,25 +512,23 @@ void extractOTraceIDs(const EDNSOptionViewMap& map, pdns::trace::Span& span)
   // parent_span_id gets set from edns options (if available and well-formed, otherwise it remains cleared (no parent))
   // span_id gets inited randomly
   bool traceidset = false;
-  if (const auto& option = map.find(EDNSOptionCode::OTTRACEID); option != map.end()) {
+  const auto traceIDSize = span.trace_id.size();
+
+  if (const auto& option = map.find(EDNSOptionCode::OTTRACEIDS); option != map.end()) {
     if (option->second.values.size() > 0) {
-      if (option->second.values.at(0).size == span.trace_id.size()) {
+      if (option->second.values.at(0).size >= traceIDSize) {
         traceidset = true;
-        pdns::trace::fill(span.trace_id, option->second.values.at(0).content, span.trace_id.size());
+        pdns::trace::fill(span.trace_id, option->second.values.at(0).content, traceIDSize);
+      }
+      if (option->second.values.at(0).size == traceIDSize + span.parent_span_id.size()) {
+        pdns::trace::fill(span.parent_span_id, &option->second.values.at(0).content[traceIDSize], span.parent_span_id.size()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) it's the API
       }
     }
   }
   if (!traceidset) {
     random(span.trace_id);
   }
-  if (const auto& option = map.find(EDNSOptionCode::OTSPANID); option != map.end()) {
-    if (option->second.values.size() > 0) {
-      if (option->second.values.at(0).size == span.parent_span_id.size()) {
-        pdns::trace::fill(span.parent_span_id, option->second.values.at(0).content, span.parent_span_id.size());
-      }
-    }
-    // Empty parent span id indicated the client did not set one
-  }
+  // Empty parent span id indicated the client did not set one, thats fine
   random(span.span_id);
 }
 
index 41f67128d9bfc3c7e84abfaaa74297f957982afe..6de3a4a95121f39d076401b49214882bc3fade36 100644 (file)
@@ -95,8 +95,12 @@ static void fillPacket(vector<uint8_t>& packet, const string& q, const string& t
       opts.emplace_back(EDNSOptionCode::COOKIE, cookieOpt.makeOptString());
     }
     if (otids) {
-      opts.emplace_back(EDNSOptionCode::OTTRACEID, std::string_view(reinterpret_cast<const char*>(otids->first.data()), otids->first.size())); // NOLINT
-      opts.emplace_back(EDNSOptionCode::OTSPANID, std::string_view(reinterpret_cast<const char*>(otids->second.data()), otids->second.size())); // NOLINT
+      const auto traceid = otids->first;
+      const auto spanid = otids->second;
+      std::array<uint8_t, traceid.size() + spanid.size()> data{};
+      std::copy(traceid.begin(), traceid.end(), data.begin());
+      std::copy(spanid.begin(), spanid.end(), data.begin() + traceid.size());
+      opts.emplace_back(EDNSOptionCode::OTTRACEIDS, std::string_view(reinterpret_cast<const char*>(data.data()), data.size())); // NOLINT
     }
     pw.addOpt(bufsize, 0, dnssec ? EDNSOpts::DNSSECOK : 0, opts);
     pw.commit();