• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 19741624072

27 Nov 2025 03:45PM UTC coverage: 73.086% (+0.02%) from 73.065%
19741624072

Pull #16570

github

web-flow
Merge 08a2cdb1d into f94a3f63f
Pull Request #16570: rec: rewrite all unwrap calls in web.rs

38523 of 63408 branches covered (60.75%)

Branch coverage included in aggregate %.

128044 of 164496 relevant lines covered (77.84%)

6531485.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.71
/pdns/dnsdistdist/dnsdist-idstate.hh
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#pragma once
23

24
#include <cstdint>
25
#include <ctime>
26
#include <memory>
27
#include <optional>
28
#include <string_view>
29
#include <unordered_map>
30
#include <utility>
31
#include <vector>
32

33
#include "config.h"
34
#include "dnscrypt.hh"
35
#include "dnsdist-configuration.hh"
36
#include "dnsname.hh"
37
#include "dnsdist-protocols.hh"
38
#include "ednsextendederror.hh"
39
#include "gettime.hh"
40
#include "iputils.hh"
41
#include "noinitvector.hh"
42
#include "dnsdist-opentelemetry.hh"
43
#include "uuid-utils.hh"
44

45
#ifndef DISABLE_PROTOBUF
46
#include "dnsdist-protobuf.hh"
47
#include "remote_logger.hh"
48
#endif
49

50
struct ClientState;
51
struct DOHUnitInterface;
52
struct DOQUnit;
53
struct DOH3Unit;
54
class DNSCryptQuery;
55
class DNSDistPacketCache;
56

57
using QTag = std::unordered_map<string, string>;
58
using HeadersMap = std::unordered_map<std::string, std::string>;
59

60
struct StopWatch
61
{
62
  StopWatch(bool realTime = false) :
63
    d_needRealTime(realTime)
27,368,162✔
64
  {
27,368,162✔
65
  }
27,368,162✔
66

67
  void start()
68
  {
465,974✔
69
    d_start = getCurrentTime();
465,974✔
70
  }
465,974✔
71

72
  void set(const struct timespec& from)
73
  {
×
74
    d_start = from;
×
75
  }
×
76

77
  double udiff() const
78
  {
72,587✔
79
    struct timespec now = getCurrentTime();
72,587✔
80
    return 1000000.0 * (now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec) / 1000.0;
72,587✔
81
  }
72,587✔
82

83
  double udiffAndSet()
84
  {
198,715✔
85
    struct timespec now = getCurrentTime();
198,715✔
86
    auto ret = 1000000.0 * (now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec) / 1000.0;
198,715✔
87
    d_start = now;
198,715✔
88
    return ret;
198,715✔
89
  }
198,715✔
90

91
  struct timespec getStartTime() const
92
  {
4✔
93
    return d_start;
4✔
94
  }
4✔
95

96
  struct timespec d_start{
97
    0, 0};
98

99
private:
100
  struct timespec getCurrentTime() const
101
  {
737,276✔
102
    struct timespec now;
737,276✔
103
    if (gettime(&now, d_needRealTime) < 0) {
737,276!
104
      unixDie("Getting timestamp");
×
105
    }
×
106
    return now;
737,276✔
107
  }
737,276✔
108

109
  bool d_needRealTime;
110
};
111

112
class CrossProtocolContext;
113

114
struct InternalQueryState
115
{
116
  struct ProtoBufData
117
  {
118
    std::optional<boost::uuids::uuid> uniqueId{std::nullopt}; // 17
119
    std::string d_deviceName;
120
    std::string d_deviceID;
121
    std::string d_requestorID;
122
  };
123

124
  /**
125
   * @brief Returns the Tracer, but only if OpenTelemetry tracing is globally enabled
126
   *
127
   * @return
128
   */
129
  std::shared_ptr<pdns::trace::dnsdist::Tracer> getTracer()
130
  {
115,749✔
131
#ifdef DISABLE_PROTOBUF
20,180✔
132
    return nullptr;
20,180✔
133
#else
134
    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_openTelemetryTracing) {
95,569✔
135
      if (d_OTTracer != nullptr) {
348✔
136
        return d_OTTracer;
330✔
137
      }
330✔
138
      // OpenTelemetry tracing is enabled, but we don't have a tracer yet
139
      d_OTTracer = pdns::trace::dnsdist::Tracer::getTracer();
18✔
140
      return d_OTTracer;
18✔
141
    }
348✔
142
    return nullptr;
95,221✔
143
#endif
95,569✔
144
  }
115,749✔
145

146
  /**
147
   * @brief Returns a Tracer::Closer, but only if OpenTelemetry tracing is needed
148
   *
149
   * @return
150
   */
151
  std::optional<pdns::trace::dnsdist::Tracer::Closer> getCloser([[maybe_unused]] const std::string_view& name, [[maybe_unused]] const SpanID& parentSpanID);
152
  std::optional<pdns::trace::dnsdist::Tracer::Closer> getCloser([[maybe_unused]] const std::string_view& name, [[maybe_unused]] const std::string_view& parentSpanName);
153
  std::optional<pdns::trace::dnsdist::Tracer::Closer> getCloser([[maybe_unused]] const std::string_view& name);
154
  std::optional<pdns::trace::dnsdist::Tracer::Closer> getRulesCloser([[maybe_unused]] const std::string_view& ruleName, [[maybe_unused]] const std::string_view& parentSpanName);
155

156
  InternalQueryState()
157
  {
27,168,622✔
158
    origDest.sin4.sin_family = 0;
27,168,622✔
159
  }
27,168,622✔
160

161
  InternalQueryState(InternalQueryState&& rhs) = default;
336,051✔
162
  InternalQueryState& operator=(InternalQueryState&& rhs) = default;
132,396✔
163

164
  InternalQueryState(const InternalQueryState& orig) = delete;
165
  InternalQueryState& operator=(const InternalQueryState& orig) = delete;
166

167
  bool isXSK() const noexcept
168
  {
7,575✔
169
#ifdef HAVE_XSK
7,575✔
170
    return !xskPacketHeader.empty();
7,575✔
171
#else
172
    return false;
173
#endif /* HAVE_XSK */
174
  }
7,575✔
175

176
  void sendDelayedProtobufMessages() const;
177

178
  InternalQueryState partialCloneForXFR() const;
179

180
  boost::optional<Netmask> subnet{boost::none}; // 40
181
  std::string poolName; // 32
182
#if !defined(DISABLE_PROTOBUF)
183
  std::string d_rawProtobufContent; // protobuf-encoded content to add to protobuf messages // 32
184
#endif /* DISABLE_PROTOBUF */
185
  ComboAddress origRemote; // 28
186
  ComboAddress origDest; // 28
187
  ComboAddress hopRemote;
188
  ComboAddress hopLocal;
189
  DNSName qname; // 24
190
#ifdef HAVE_XSK
191
  PacketBuffer xskPacketHeader; // 24
192
#endif /* HAVE_XSK */
193
  StopWatch queryRealTime{true}; // 24
194
private:
195
  std::shared_ptr<pdns::trace::dnsdist::Tracer> d_OTTracer{nullptr};
196

197
public:
198
  std::shared_ptr<DNSDistPacketCache> packetCache{nullptr}; // 16
199
  std::unique_ptr<DNSCryptQuery> dnsCryptQuery{nullptr}; // 8
200
  std::unique_ptr<QTag> qTag{nullptr}; // 8
201
  std::unique_ptr<PacketBuffer> d_packet{nullptr}; // Initial packet, so we can restart the query from the response path if needed // 8
202
  std::unique_ptr<ProtoBufData> d_protoBufData{nullptr};
203
#ifndef DISABLE_PROTOBUF
204
  std::vector<std::pair<std::string, std::shared_ptr<RemoteLoggerInterface>>> delayedResponseMsgs;
205
#endif
206
  std::unique_ptr<EDNSExtendedError> d_extendedError{nullptr};
207
  boost::optional<uint32_t> tempFailureTTL{boost::none}; // 8
208
  ClientState* cs{nullptr}; // 8
209
  std::unique_ptr<DOHUnitInterface> du; // 8
210
  size_t d_proxyProtocolPayloadSize{0}; // 8
211
  std::unique_ptr<DOQUnit> doqu{nullptr}; // 8
212
  std::unique_ptr<DOH3Unit> doh3u{nullptr}; // 8
213
  int32_t d_streamID{-1}; // 4
214
  uint32_t cacheKey{0}; // 4
215
  uint32_t cacheKeyNoECS{0}; // 4
216
  // DoH-only: if we received a TC=1 answer, we had to retry over TCP and thus we need the TCP cache key */
217
  uint32_t cacheKeyTCP{0}; // 4
218
  uint32_t ttlCap{0}; // cap the TTL _after_ inserting into the packet cache // 4
219
  int backendFD{-1}; // 4
220
  int delayMsec{0};
221
  uint16_t qtype{0}; // 2
222
  uint16_t qclass{0}; // 2
223
  // origID is in network-byte order
224
  uint16_t origID{0}; // 2
225
  uint16_t origFlags{0}; // 2
226
  uint16_t cacheFlags{0}; // DNS flags as sent to the backend // 2
227
  uint16_t udpPayloadSize{0}; // Max UDP payload size from the query // 2
228
  std::optional<bool> dnssecOK;
229
  dnsdist::Protocol protocol; // 1
230
  uint8_t restartCount{0}; // 1
231
  bool ednsAdded{false};
232
  bool ecsAdded{false};
233
  bool skipCache{false};
234
  bool useZeroScope{false};
235
  bool forwardedOverUDP{false};
236
  bool selfGenerated{false};
237
  bool cacheHit{false};
238
  bool staleCacheHit{false};
239
  bool tracingEnabled{false}; // Whether or not Open Telemetry tracing is enabled for this query
240
  bool rulesAppliedToQuery{false}; // Whether applyRulesToQuery has been called for the query, used to determine if we need to trace
241
  struct rulesAppliedToQuerySetter
242
  {
243
    rulesAppliedToQuerySetter(bool& pastProcessRules) :
244
      d_rulesAppliedToQuery(pastProcessRules)
6,116✔
245
    {
6,116✔
246
      d_rulesAppliedToQuery = false;
6,116✔
247
    }
6,116✔
248
    ~rulesAppliedToQuerySetter()
249
    {
6,116✔
250
      d_rulesAppliedToQuery = true;
6,116✔
251
    }
6,116✔
252

253
  private:
254
    bool& d_rulesAppliedToQuery;
255
  };
256
};
257

258
struct IDState
259
{
260
  IDState()
261
  {
27,065,975✔
262
  }
27,065,975✔
263

264
  IDState(const IDState& orig) = delete;
265
  IDState(IDState&& rhs) noexcept :
266
    internal(std::move(rhs.internal))
20✔
267
  {
20✔
268
    inUse.store(rhs.inUse.load());
20✔
269
    age.store(rhs.age.load());
20✔
270
  }
20✔
271

272
  IDState& operator=(IDState&& rhs) noexcept
273
  {
×
274
    inUse.store(rhs.inUse.load());
×
275
    age.store(rhs.age.load());
×
276
    internal = std::move(rhs.internal);
×
277
    return *this;
×
278
  }
×
279

280
  bool isInUse() const
281
  {
2,299,030✔
282
    return inUse;
2,299,030✔
283
  }
2,299,030✔
284

285
  /* For performance reasons we don't want to use a lock here, but that means
286
     we need to be very careful when modifying this value. Modifications happen
287
     from:
288
     - one of the UDP or DoH 'client' threads receiving a query, selecting a backend
289
       then picking one of the states associated to this backend (via the idOffset).
290
       Most of the time this state should not be in use and usageIndicator is -1, but we
291
       might not yet have received a response for the query previously associated to this
292
       state, meaning that we will 'reuse' this state and erase the existing state.
293
       If we ever receive a response for this state, it will be discarded. This is
294
       mostly fine for UDP except that we still need to be careful in order to miss
295
       the 'outstanding' counters, which should only be increased when we are picking
296
       an empty state, and not when reusing ;
297
       For DoH, though, we have dynamically allocated a DOHUnit object that needs to
298
       be freed, as well as internal objects internals to libh2o.
299
     - one of the UDP receiver threads receiving a response from a backend, picking
300
       the corresponding state and sending the response to the client ;
301
     - the 'healthcheck' thread scanning the states to actively discover timeouts,
302
       mostly to keep some counters like the 'outstanding' one sane.
303

304
     We have two flags:
305
     - inUse tells us if there currently is an in-flight query whose state is stored
306
       in this state
307
     - locked tells us whether someone currently owns the state, so no-one else can touch
308
       it
309
  */
310
  InternalQueryState internal;
311
  std::atomic<uint16_t> age{0};
312

313
  class StateGuard
314
  {
315
  public:
316
    StateGuard(IDState& ids) :
317
      d_ids(ids)
5,305✔
318
    {
5,305✔
319
    }
5,305✔
320
    ~StateGuard()
321
    {
5,305✔
322
      d_ids.release();
5,305✔
323
    }
5,305✔
324
    StateGuard(const StateGuard&) = delete;
325
    StateGuard(StateGuard&&) = delete;
326
    StateGuard& operator=(const StateGuard&) = delete;
327
    StateGuard& operator=(StateGuard&&) = delete;
328

329
  private:
330
    IDState& d_ids;
331
  };
332

333
  [[nodiscard]] std::optional<StateGuard> acquire()
334
  {
5,305✔
335
    bool expected = false;
5,305✔
336
    if (locked.compare_exchange_strong(expected, true)) {
5,305!
337
      return std::optional<StateGuard>(*this);
5,305✔
338
    }
5,305✔
339
    return std::nullopt;
×
340
  }
5,305✔
341

342
  void release()
343
  {
5,305✔
344
    locked.store(false);
5,305✔
345
  }
5,305✔
346

347
  std::atomic<bool> inUse{false}; // 1
348

349
private:
350
  std::atomic<bool> locked{false}; // 1
351
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc