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

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

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

88.67
/pdns/recursordist/syncres.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
#include <string>
24
#include <atomic>
25
#include "utility.hh"
26
#include "dns.hh"
27
#include "qtype.hh"
28
#include <vector>
29
#include <set>
30
#include <unordered_set>
31
#include <map>
32
#include <cmath>
33
#include <iostream>
34
#include <utility>
35
#include "misc.hh"
36
#include "lwres.hh"
37
#include <boost/optional.hpp>
38
#include <boost/utility.hpp>
39
#include "circular_buffer.hh"
40
#include "sstuff.hh"
41
#include "recursor_cache.hh"
42
#include "mtasker.hh"
43
#include "iputils.hh"
44
#include "validate-recursor.hh"
45
#include "ednssubnet.hh"
46
#include "filterpo.hh"
47
#include "negcache.hh"
48
#include "proxy-protocol.hh"
49
#include "sholder.hh"
50
#include "histogram.hh"
51
#include "stat_t.hh"
52
#include "tcpiohandler.hh"
53
#include "rec-eventtrace.hh"
54
#include "logr.hh"
55
#include "rec-tcounters.hh"
56
#include "ednsextendederror.hh"
57

58
#ifdef HAVE_CONFIG_H
59
#include "config.h"
60
#endif
61

62
#include <boost/uuid/uuid.hpp>
63
#ifdef HAVE_FSTRM
64
#include "fstrm_logger.hh"
65
#endif /* HAVE_FSTRM */
66

67
extern GlobalStateHolder<SuffixMatchNode> g_xdnssec;
68
extern GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames;
69
extern GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks;
70
extern GlobalStateHolder<SuffixMatchNode> g_DoTToAuthNames;
71

72
enum class AdditionalMode : uint8_t; // defined in rec-lua-conf.hh
73

74
class RecursorLua4;
75

76
using NsSet = std::unordered_map<DNSName, pair<vector<ComboAddress>, bool>>;
77

78
extern std::unique_ptr<NegCache> g_negCache;
79

80
class SyncRes : public boost::noncopyable
81
{
82
public:
83
  enum LogMode
84
  {
85
    LogNone,
86
    Log,
87
    Store
88
  };
89
  using asyncresolve_t = std::function<LWResult::Result(const ComboAddress&, const DNSName&, int, bool, bool, int, struct timeval*, boost::optional<Netmask>&, const ResolveContext&, LWResult*, bool*)>;
90

91
  enum class HardenNXD
92
  {
93
    No,
94
    DNSSEC,
95
    Yes
96
  };
97

98
  struct Context
99
  {
100
    boost::optional<EDNSExtendedError> extendedError;
101
    vState state{vState::Indeterminate};
102
  };
103

104
  vState getDSRecords(const DNSName& zone, dsset_t& dsSet, bool onlyTA, unsigned int depth, const string& prefix, bool bogusOnNXD = true, bool* foundCut = nullptr);
105

106
  class AuthDomain
107
  {
108
  public:
109
    using records_t = multi_index_container<
110
      DNSRecord,
111
      indexed_by<
112
        ordered_non_unique<
113
          composite_key<DNSRecord,
114
                        member<DNSRecord, DNSName, &DNSRecord::d_name>,
115
                        member<DNSRecord, uint16_t, &DNSRecord::d_type>>,
116
          composite_key_compare<std::less<>, std::less<>>>>>;
117

118
    records_t d_records;
119
    vector<ComboAddress> d_servers;
120
    DNSName d_name;
121
    bool d_rdForward{false};
122

123
    bool operator==(const AuthDomain& rhs) const;
124

125
    [[nodiscard]] std::string print(const std::string& indent = "",
126
                                    const std::string& indentLevel = "  ") const;
127

128
    int getRecords(const DNSName& qname, QType qtype, std::vector<DNSRecord>& records) const;
129
    [[nodiscard]] bool isAuth() const
130
    {
1,647✔
131
      return d_servers.empty();
1,647✔
132
    }
1,647✔
133
    [[nodiscard]] bool isForward() const
134
    {
×
135
      return !isAuth();
×
136
    }
×
137
    [[nodiscard]] bool shouldRecurse() const
138
    {
667✔
139
      return d_rdForward;
667✔
140
    }
667✔
141
    [[nodiscard]] const DNSName& getName() const
142
    {
84✔
143
      return d_name;
84✔
144
    }
84✔
145

146
  private:
147
    void addSOA(std::vector<DNSRecord>& records) const;
148
  };
149

150
  using domainmap_t = std::unordered_map<DNSName, AuthDomain>;
151

152
  struct ThreadLocalStorage
153
  {
154
    std::shared_ptr<domainmap_t> domainmap;
155
  };
156

157
  static void setDefaultLogMode(LogMode logmode)
158
  {
138✔
159
    s_lm = logmode;
138✔
160
  }
138✔
161

162
  OptLog LogObject(const string& prefix);
163

164
  static uint64_t doEDNSDump(int fileDesc);
165
  static uint64_t doDumpNSSpeeds(int fileDesc);
166
  static uint64_t doDumpThrottleMap(int fileDesc);
167
  static uint64_t doDumpFailedServers(int fileDesc);
168
  static uint64_t doDumpNonResolvingNS(int fileDesc);
169
  static uint64_t doDumpSavedParentNSSets(int fileDesc);
170
  static uint64_t doDumpDoTProbeMap(int fileDesc);
171

172
  static int getRootNS(struct timeval now, asyncresolve_t asyncCallback, unsigned int depth, Logr::log_t);
173
  static void addDontQuery(const std::string& mask)
174
  {
294✔
175
    if (!s_dontQuery) {
294✔
176
      s_dontQuery = std::make_unique<NetmaskGroup>();
14✔
177
    }
14✔
178
    s_dontQuery->addMask(mask);
294✔
179
  }
294✔
180
  static void addDontQuery(const Netmask& mask)
181
  {
2✔
182
    if (!s_dontQuery) {
2!
183
      s_dontQuery = std::make_unique<NetmaskGroup>();
2✔
184
    }
2✔
185
    s_dontQuery->addMask(mask);
2✔
186
  }
2✔
187
  static void clearDontQuery()
188
  {
598✔
189
    s_dontQuery = nullptr;
598✔
190
  }
598✔
191
  static void parseEDNSSubnetAllowlist(const std::string& alist);
192
  static void parseEDNSSubnetAddFor(const std::string& subnetlist);
193
  static void addEDNSLocalSubnet(const std::string& subnet)
194
  {
1,202✔
195
    s_ednslocalsubnets.addMask(subnet);
1,202✔
196
  }
1,202✔
197
  static void addEDNSRemoteSubnet(const std::string& subnet)
198
  {
10✔
199
    s_ednsremotesubnets.addMask(subnet);
10✔
200
  }
10✔
201
  static void addEDNSDomain(const DNSName& domain)
202
  {
16✔
203
    s_ednsdomains.add(domain);
16✔
204
  }
16✔
205
  static void clearEDNSLocalSubnets()
206
  {
604✔
207
    s_ednslocalsubnets.clear();
604✔
208
  }
604✔
209
  static void clearEDNSRemoteSubnets()
210
  {
598✔
211
    s_ednsremotesubnets.clear();
598✔
212
  }
598✔
213
  static void clearEDNSDomains()
214
  {
598✔
215
    s_ednsdomains = SuffixMatchNode();
598✔
216
  }
598✔
217

218
  static void pruneNSSpeeds(time_t limit);
219
  static uint64_t getNSSpeedsSize();
220
  static void submitNSSpeed(const DNSName& server, const ComboAddress& address, int usec, const struct timeval& now);
221
  static void clearNSSpeeds();
222
  static float getNSSpeed(const DNSName& server, const ComboAddress& address);
223

224
  struct EDNSStatus
225
  {
226
    EDNSStatus(const ComboAddress& arg) :
227
      address(arg) {}
169✔
228
    ComboAddress address;
229
    time_t ttd{0};
230
    enum EDNSMode : uint8_t
231
    {
232
      EDNSOK = 0,
233
      EDNSIGNORANT = 1,
234
      NOEDNS = 2
235
    } mode{EDNSOK};
236

237
    [[nodiscard]] std::string toString() const
238
    {
×
239
      const std::array<std::string, 3> modes = {"OK", "Ignorant", "No"};
×
240
      auto umode = static_cast<unsigned int>(mode);
×
241
      if (umode >= modes.size()) {
×
242
        return "?";
×
243
      }
×
244
      return modes.at(umode);
×
245
    }
×
246
  };
247

248
  static EDNSStatus::EDNSMode getEDNSStatus(const ComboAddress& server);
249
  static uint64_t getEDNSStatusesSize();
250
  static void clearEDNSStatuses();
251
  static void pruneEDNSStatuses(time_t cutoff);
252

253
  static uint64_t getThrottledServersSize();
254
  static void pruneThrottledServers(time_t now);
255
  static void clearThrottle();
256
  static bool isThrottled(time_t now, const ComboAddress& server, const DNSName& target, QType qtype);
257
  static bool isThrottled(time_t now, const ComboAddress& server);
258

259
  enum class ThrottleReason : uint8_t
260
  {
261
    None,
262
    ServerDown,
263
    PermanentError,
264
    Timeout,
265
    ParseError,
266
    RCodeServFail,
267
    RCodeRefused,
268
    RCodeOther,
269
    TCPTruncate,
270
    Lame,
271
  };
272
  static void doThrottle(time_t now, const ComboAddress& server, time_t duration, unsigned int tries, ThrottleReason reason);
273
  static void doThrottle(time_t now, const ComboAddress& server, const DNSName& name, QType qtype, time_t duration, unsigned int tries, ThrottleReason reason);
274
  static void unThrottle(const ComboAddress& server, const DNSName& qname, QType qtype);
275

276
  static uint64_t getFailedServersSize();
277
  static void clearFailedServers();
278
  static void pruneFailedServers(time_t cutoff);
279
  static unsigned long getServerFailsCount(const ComboAddress& server);
280

281
  static void clearNonResolvingNS();
282
  static uint64_t getNonResolvingNSSize();
283
  static void pruneNonResolving(time_t cutoff);
284

285
  static void clearSaveParentsNSSets();
286
  static size_t getSaveParentsNSSetsSize();
287
  static void pruneSaveParentsNSSets(time_t now);
288

289
  static void pruneDoTProbeMap(time_t cutoff);
290

291
  static void setDomainMap(std::shared_ptr<domainmap_t> newMap)
292
  {
1,476✔
293
    t_sstorage.domainmap = std::move(newMap);
1,476✔
294
  }
1,476✔
295
  static std::shared_ptr<domainmap_t> getDomainMap()
296
  {
21✔
297
    return t_sstorage.domainmap;
21✔
298
  }
21✔
299

300
  static void setECSScopeZeroAddress(const Netmask& scopeZeroMask)
301
  {
751✔
302
    s_ecsScopeZero.source = scopeZeroMask;
751✔
303
  }
751✔
304

305
  static void clearECSStats()
306
  {
904✔
307
    s_ecsqueries.store(0);
904✔
308
    s_ecsresponses.store(0);
904✔
309

310
    for (size_t idx = 0; idx < 32; idx++) {
29,832✔
311
      SyncRes::s_ecsResponsesBySubnetSize4[idx].store(0);
28,928✔
312
    }
28,928✔
313

314
    for (size_t idx = 0; idx < 128; idx++) {
116,616✔
315
      SyncRes::s_ecsResponsesBySubnetSize6[idx].store(0);
115,712✔
316
    }
115,712✔
317
  }
904✔
318

319
  explicit SyncRes(const struct timeval& now);
320

321
  int beginResolve(const DNSName& qname, QType qtype, QClass qclass, vector<DNSRecord>& ret, unsigned int depth = 0);
322
  bool tryDoT(const DNSName& qname, QType qtype, const DNSName& nsName, ComboAddress address, time_t);
323

324
  void setId(int threadid)
325
  {
2,374✔
326
    if (doLog()) {
2,374✔
327
      d_prefix = "[" + std::to_string(threadid) + "] ";
846✔
328
    }
846✔
329
  }
2,374✔
330

331
  void setId(const string& prefix)
332
  {
13✔
333
    if (doLog()) {
13!
334
      d_prefix = "[" + prefix + "] ";
×
335
    }
×
336
  }
13✔
337

338
  void setLogMode(LogMode logmode)
339
  {
544✔
340
    d_lm = logmode;
544✔
341
  }
544✔
342

343
  bool doLog() const
344
  {
117,903✔
345
    return d_lm != LogNone;
117,903✔
346
  }
117,903✔
347

348
  bool setCacheOnly(bool state = true)
349
  {
66,946✔
350
    bool old = d_cacheonly;
66,946✔
351
    d_cacheonly = state;
66,946✔
352
    return old;
66,946✔
353
  }
66,946✔
354

355
  bool setRefreshAlmostExpired(bool doit)
356
  {
251✔
357
    auto old = d_refresh;
251✔
358
    d_refresh = doit;
251✔
359
    return old;
251✔
360
  }
251✔
361

362
  bool setQNameMinimization(bool state = true)
363
  {
9,688✔
364
    auto old = d_qNameMinimization;
9,688✔
365
    d_qNameMinimization = state;
9,688✔
366
    return old;
9,688✔
367
  }
9,688✔
368

369
  bool setQMFallbackMode(bool state = true)
370
  {
40✔
371
    auto old = d_qNameMinimizationFallbackMode;
40✔
372
    d_qNameMinimizationFallbackMode = state;
40✔
373
    return old;
40✔
374
  }
40✔
375

376
  bool getQMFallbackMode() const
377
  {
30,917✔
378
    return d_qNameMinimizationFallbackMode;
30,917✔
379
  }
30,917✔
380

381
  void setDoEDNS0(bool state = true)
382
  {
771✔
383
    d_doEDNS0 = state;
771✔
384
  }
771✔
385

386
  void setDoDNSSEC(bool state = true)
387
  {
2,896✔
388
    d_doDNSSEC = state;
2,896✔
389
  }
2,896✔
390

391
  void setDNSSECValidationRequested(bool requested = true)
392
  {
2,979✔
393
    d_DNSSECValidationRequested = requested;
2,979✔
394
  }
2,979✔
395

396
  bool isDNSSECValidationRequested() const
397
  {
2,020✔
398
    return d_DNSSECValidationRequested;
2,020✔
399
  }
2,020✔
400

401
  bool shouldValidate() const
402
  {
41,072✔
403
    return d_DNSSECValidationRequested && !d_wasOutOfBand;
41,072✔
404
  }
41,072✔
405

406
  void setWantsRPZ(bool state = true)
407
  {
2,289✔
408
    d_wantsRPZ = state;
2,289✔
409
  }
2,289✔
410

411
  bool getWantsRPZ() const
412
  {
×
413
    return d_wantsRPZ;
×
414
  }
×
415

416
  string getTrace() const
417
  {
19✔
418
    return d_trace.str();
19✔
419
  }
19✔
420

421
  bool getQNameMinimization() const
422
  {
15,595✔
423
    return d_qNameMinimization;
15,595✔
424
  }
15,595✔
425

426
  void setLuaEngine(shared_ptr<RecursorLua4> pdl)
427
  {
430✔
428
    d_pdl = std::move(pdl);
430✔
429
  }
430✔
430

431
  bool wasVariable() const
432
  {
5,407✔
433
    return d_wasVariable;
5,407✔
434
  }
5,407✔
435

436
  bool wasOutOfBand() const
437
  {
2,285✔
438
    return d_wasOutOfBand;
2,285✔
439
  }
2,285✔
440

441
  struct timeval getNow() const
442
  {
2,488✔
443
    return d_now;
2,488✔
444
  }
2,488✔
445

446
  // For debugging purposes
447
  void setNow(const struct timeval& tval)
448
  {
36✔
449
    d_now = tval;
36✔
450
  }
36✔
451

452
  void setQuerySource(const ComboAddress& requestor, const boost::optional<const EDNSSubnetOpts&>& incomingECS);
453
  void setQuerySource(const Netmask& netmask);
454

455
  void setInitialRequestId(const boost::optional<const boost::uuids::uuid&>& initialRequestId)
456
  {
2,375✔
457
    d_initialRequestId = initialRequestId;
2,375✔
458
  }
2,375✔
459

460
  void setOutgoingProtobufServers(std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& servers)
461
  {
2,375✔
462
    d_outgoingProtobufServers = servers;
2,375✔
463
  }
2,375✔
464

465
#ifdef HAVE_FSTRM
466
  void setFrameStreamServers(std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& servers)
467
  {
2,374✔
468
    d_frameStreamServers = servers;
2,374✔
469
  }
2,374✔
470
#endif /* HAVE_FSTRM */
471

472
  void setAsyncCallback(asyncresolve_t func)
473
  {
783✔
474
    d_asyncResolve = std::move(func);
783✔
475
  }
783✔
476

477
  vState getValidationState() const
478
  {
6,638✔
479
    return d_queryValidationState;
6,638✔
480
  }
6,638✔
481

482
  [[nodiscard]] bool getDNSSECLimitHit() const
483
  {
302✔
484
    return d_validationContext.d_limitHit;
302✔
485
  }
302✔
486

487
  void setQueryReceivedOverTCP(bool tcp)
488
  {
2,373✔
489
    d_queryReceivedOverTCP = tcp;
2,373✔
490
  }
2,373✔
491

492
  static bool isUnsupported(QType qtype)
493
  {
6,809✔
494
    auto qcode = qtype.getCode();
6,809✔
495
    // rfc6895 section 3.1, note ANY is 255 and falls outside the range
496
    if (qcode >= QType::rfc6895MetaLowerBound && qcode <= QType::rfc6895MetaUpperBound) {
6,809✔
497
      return true;
18✔
498
    }
18✔
499
    switch (qcode) {
6,791✔
500
      // Internal types
501
    case QType::ENT: // aka TYPE0
×
502
    case QType::ADDR:
×
503
      // RFC
504
    case QType::rfc6895Reserved:
2✔
505
      // Other
506
    case QType::RRSIG:
6✔
507
    case QType::NSEC3: // We use the same logic as for an auth: NSEC is queryable, NSEC3 not
10✔
508
    case QType::OPT:
12✔
509
      return true;
12✔
510
    }
6,791✔
511
    return false;
6,779✔
512
  }
6,791✔
513

514
  static bool answerIsNOData(uint16_t requestedType, int rcode, const std::vector<DNSRecord>& records);
515

516
  static thread_local ThreadLocalStorage t_sstorage;
517

518
  static pdns::stat_t s_ecsqueries;
519
  static pdns::stat_t s_ecsresponses;
520
  static std::map<uint8_t, pdns::stat_t> s_ecsResponsesBySubnetSize4;
521
  static std::map<uint8_t, pdns::stat_t> s_ecsResponsesBySubnetSize6;
522

523
  static string s_serverID;
524
  static unsigned int s_minimumTTL;
525
  static unsigned int s_minimumECSTTL;
526
  static unsigned int s_maxqperq;
527
  static unsigned int s_maxnsperresolve;
528
  static unsigned int s_maxnsaddressqperq;
529
  static unsigned int s_maxtotusec;
530
  static unsigned int s_maxdepth;
531
  static unsigned int s_maxnegttl;
532
  static unsigned int s_maxbogusttl;
533
  static unsigned int s_maxcachettl;
534
  static unsigned int s_packetcachettl;
535
  static unsigned int s_packetcacheservfailttl;
536
  static unsigned int s_packetcachenegativettl;
537
  static unsigned int s_serverdownmaxfails;
538
  static unsigned int s_serverdownthrottletime;
539
  static unsigned int s_nonresolvingnsmaxfails;
540
  static unsigned int s_nonresolvingnsthrottletime;
541
  static unsigned int s_unthrottle_n;
542
  static unsigned int s_ecscachelimitttl;
543
  static unsigned int s_maxvalidationsperq;
544
  static unsigned int s_maxnsec3iterationsperq;
545
  static uint8_t s_ecsipv4limit;
546
  static uint8_t s_ecsipv6limit;
547
  static uint8_t s_ecsipv4cachelimit;
548
  static uint8_t s_ecsipv6cachelimit;
549
  static bool s_ecsipv4nevercache;
550
  static bool s_ecsipv6nevercache;
551

552
  static bool s_doIPv4;
553
  static bool s_doIPv6;
554
  static bool s_noEDNSPing;
555
  static bool s_noEDNS;
556
  static bool s_rootNXTrust;
557
  static bool s_qnameminimization;
558
  static HardenNXD s_hardenNXD;
559
  static unsigned int s_refresh_ttlperc;
560
  static unsigned int s_locked_ttlperc;
561
  static int s_tcp_fast_open;
562
  static bool s_tcp_fast_open_connect;
563
  static bool s_dot_to_port_853;
564
  static unsigned int s_max_busy_dot_probes;
565
  static unsigned int s_max_CNAMES_followed;
566
  static unsigned int s_max_minimize_count;
567
  static unsigned int s_minimize_one_label;
568

569
  static const int event_trace_to_pb = 1;
570
  static const int event_trace_to_log = 2;
571
  static int s_event_trace_enabled;
572
  static bool s_save_parent_ns_set;
573
  static bool s_addExtendedResolutionDNSErrors;
574

575
  std::unordered_map<std::string, bool> d_discardedPolicies;
576
  DNSFilterEngine::Policy d_appliedPolicy;
577
  std::unordered_set<std::string> d_policyTags;
578
  boost::optional<string> d_routingTag;
579
  ComboAddress d_fromAuthIP;
580
  RecEventTrace d_eventTrace;
581
  std::shared_ptr<Logr::Logger> d_slog = g_slog->withName("syncres");
582
  boost::optional<EDNSExtendedError> d_extendedError;
583

584
  unsigned int d_authzonequeries;
585
  unsigned int d_outqueries;
586
  unsigned int d_tcpoutqueries;
587
  unsigned int d_dotoutqueries;
588
  unsigned int d_throttledqueries;
589
  unsigned int d_timeouts;
590
  unsigned int d_unreachables;
591
  unsigned int d_totUsec;
592
  unsigned int d_maxdepth{0};
593
  // Initialized ony once, as opposed to d_now which gets updated after outgoing requests
594
  struct timeval d_fixednow;
595

596
private:
597
  ComboAddress d_requestor;
598
  ComboAddress d_cacheRemote;
599

600
  static NetmaskGroup s_ednslocalsubnets;
601
  static NetmaskGroup s_ednsremotesubnets;
602
  static SuffixMatchNode s_ednsdomains;
603
  static EDNSSubnetOpts s_ecsScopeZero;
604
  static LogMode s_lm;
605
  static std::unique_ptr<NetmaskGroup> s_dontQuery;
606

607
  struct GetBestNSAnswer
608
  {
609
    DNSName qname;
610
    set<pair<DNSName, DNSName>> bestns;
611
    uint8_t qtype;
612
    bool operator<(const GetBestNSAnswer& bestAnswer) const
613
    {
14,411✔
614
      return std::tie(qtype, qname, bestns) < std::tie(bestAnswer.qtype, bestAnswer.qname, bestAnswer.bestns);
14,411✔
615
    }
14,411✔
616
  };
617

618
  using zonesStates_t = std::map<DNSName, vState>;
619
  enum StopAtDelegation
620
  {
621
    DontStop,
622
    Stop,
623
    Stopped
624
  };
625

626
  void resolveAdditionals(const DNSName& qname, QType qtype, AdditionalMode mode, std::vector<DNSRecord>& additionals, unsigned int depth, bool& additionalsNotInCache);
627
  void addAdditionals(QType qtype, const vector<DNSRecord>& start, vector<DNSRecord>& additionals, std::set<std::pair<DNSName, QType>>& uniqueCalls, std::set<std::tuple<DNSName, QType, QType>>& uniqueResults, unsigned int depth, unsigned int additionaldepth, bool& additionalsNotInCache);
628
  bool addAdditionals(QType qtype, vector<DNSRecord>& ret, unsigned int depth);
629

630
  void updateQueryCounts(const string& prefix, const DNSName& qname, const ComboAddress& address, bool doTCP, bool doDoT);
631
  static bool doDoTtoAuth(const DNSName& nameServer);
632
  int doResolveAt(NsSet& nameservers, DNSName auth, bool flawedNSSet, const DNSName& qname, QType qtype, vector<DNSRecord>& ret,
633
                  unsigned int depth, const string& prefix, set<GetBestNSAnswer>& beenthere, Context& context, StopAtDelegation* stopAtDelegation,
634
                  std::map<DNSName, std::vector<ComboAddress>>* fallback);
635
  void ednsStats(boost::optional<Netmask>& ednsmask, const DNSName& qname, const string& prefix);
636
  void incTimeoutStats(const ComboAddress& remoteIP);
637
  bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, QType qtype, LWResult& lwr, boost::optional<Netmask>& ednsmask, const DNSName& auth, bool sendRDQuery, bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, boost::optional<EDNSExtendedError>& extendedError, bool dontThrottle = false);
638
  bool processAnswer(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask>& ednsmask, bool sendRDQuery, NsSet& nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP);
639

640
  int doResolve(const DNSName& qname, QType qtype, vector<DNSRecord>& ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, Context& context);
641
  int doResolveNoQNameMinimization(const DNSName& qname, QType qtype, vector<DNSRecord>& ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, Context& context, bool* fromCache = nullptr, StopAtDelegation* stopAtDelegation = nullptr);
642
  bool doOOBResolve(const AuthDomain& domain, const DNSName& qname, QType qtype, vector<DNSRecord>& ret, int& res);
643
  bool doOOBResolve(const DNSName& qname, QType qtype, vector<DNSRecord>& ret, unsigned int depth, const string& prefix, int& res);
644
  static bool isRecursiveForwardOrAuth(const DNSName& qname);
645
  static bool isForwardOrAuth(const DNSName& qname);
646
  static domainmap_t::const_iterator getBestAuthZone(DNSName* qname);
647
  bool doCNAMECacheCheck(const DNSName& qname, QType qtype, vector<DNSRecord>& ret, unsigned int depth, const string& prefix, int& res, Context& context, bool wasAuthZone, bool wasForwardRecurse, bool checkForDups);
648
  bool doCacheCheck(const DNSName& qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, QType qtype, vector<DNSRecord>& ret, unsigned int depth, const string& prefix, int& res, Context& context);
649
  void getBestNSFromCache(const DNSName& qname, QType qtype, vector<DNSRecord>& bestns, bool* flawedNSSet, unsigned int depth, const string& prefix, set<GetBestNSAnswer>& beenthere, const boost::optional<DNSName>& cutOffDomain = boost::none);
650
  DNSName getBestNSNamesFromCache(const DNSName& qname, QType qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, const string& prefix, set<GetBestNSAnswer>& beenthere);
651

652
  vector<std::pair<DNSName, float>> shuffleInSpeedOrder(const DNSName& qname, NsSet& nameservers, const string& prefix);
653
  vector<ComboAddress> shuffleForwardSpeed(const DNSName& qname, const vector<ComboAddress>& rnameservers, const string& prefix, bool wasRd);
654
  static bool moreSpecificThan(const DNSName& lhs, const DNSName& rhs);
655
  void selectNSOnSpeed(const DNSName& qname, const string& prefix, vector<ComboAddress>& ret);
656
  vector<ComboAddress> getAddrs(const DNSName& qname, unsigned int depth, const string& prefix, set<GetBestNSAnswer>& beenthere, bool cacheOnly, unsigned int& addressQueriesForNS);
657

658
  bool nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers);
659
  bool nameserverIPBlockedByRPZ(const DNSFilterEngine& dfe, const ComboAddress&);
660
  void checkMaxQperQ(const DNSName& qname) const;
661
  bool throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, QType qtype, bool pierceDontQuery);
662

663
  vector<ComboAddress> retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector<std::pair<DNSName, float>>::const_iterator& tns, unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<std::pair<DNSName, float>>& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly, unsigned int& nretrieveAddressesForNS);
664

665
  void sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, bool wasForwarded, bool rdQuery);
666
  void sanitizeRecordsPass2(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, std::unordered_set<DNSName>& allowedAnswerNames, std::unordered_set<DNSName>& allowedAdditionals, bool isNXDomain, bool isNXQType, std::vector<bool>& skipvec, unsigned int& skipCount);
667
  /* This function will check whether the answer should have the AA bit set, and will set if it should be set and isn't.
668
     This is unfortunately needed to deal with very crappy so-called DNS servers */
669
  void fixupAnswer(const std::string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, bool wasForwarded, bool rdQuery);
670
  void rememberParentSetIfNeeded(const DNSName& domain, const vector<DNSRecord>& newRecords, unsigned int depth, const string& prefix);
671
  RCode::rcodes_ updateCacheFromRecords(unsigned int depth, const string& prefix, LWResult& lwr, const DNSName& qname, QType qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask>&, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery, const ComboAddress& remoteIP);
672
  bool processRecords(const std::string& prefix, const DNSName& qname, QType qtype, const DNSName& auth, LWResult& lwr, bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, bool needWildcardProof, bool gatherwildcardProof, unsigned int wildcardLabelsCount, int& rcode, bool& negIndicHasSignatures, unsigned int depth);
673

674
  bool doSpecialNamesResolve(const DNSName& qname, QType qtype, QClass qclass, vector<DNSRecord>& ret);
675

676
  LWResult::Result asyncresolveWrapper(const ComboAddress& address, bool ednsMANDATORY, const DNSName& domain, const DNSName& auth, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult* res, bool* chained, const DNSName& nsName) const;
677

678
  boost::optional<Netmask> getEDNSSubnetMask(const DNSName& name, const ComboAddress& rem);
679

680
  static bool validationEnabled();
681
  uint32_t computeLowestTTD(const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<const RRSIGRecordContent>>& signatures, uint32_t signaturesTTL, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs) const;
682
  void updateValidationState(const DNSName& qname, vState& state, vState stateUpdate, const string& prefix);
683
  vState validateRecordsWithSigs(unsigned int depth, const string& prefix, const DNSName& qname, QType qtype, const DNSName& name, QType type, const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<const RRSIGRecordContent>>& signatures);
684
  vState validateDNSKeys(const DNSName& zone, const std::vector<DNSRecord>& dnskeys, const std::vector<std::shared_ptr<const RRSIGRecordContent>>& signatures, unsigned int depth, const string& prefix);
685
  vState getDNSKeys(const DNSName& signer, skeyset_t& keys, bool& servFailOccurred, unsigned int depth, const string& prefix);
686
  dState getDenialValidationState(const NegCache::NegCacheEntry& negEntry, dState expectedState, bool referralToUnsigned, const string& prefix);
687
  void updateDenialValidationState(const DNSName& qname, vState& neValidationState, const DNSName& neName, vState& state, dState denialState, dState expectedState, bool isDS, unsigned int depth, const string& prefix);
688
  void computeNegCacheValidationStatus(const NegCache::NegCacheEntry& negEntry, const DNSName& qname, QType qtype, int res, vState& state, unsigned int depth, const string& prefix);
689
  vState getTA(const DNSName& zone, dsset_t& dsSet, const string& prefix);
690
  vState getValidationStatus(const DNSName& name, bool wouldBeValid, bool typeIsDS, unsigned int depth, const string& prefix);
691
  void updateValidationStatusInCache(const DNSName& qname, QType qtype, bool aaFlag, vState newState) const;
692
  void initZoneCutsFromTA(const DNSName& from, const string& prefix);
693
  size_t countSupportedDS(const dsset_t& dsSet, const string& prefix);
694

695
  void handleNewTarget(const std::string& prefix, const DNSName& qname, const DNSName& newtarget, QType qtype, std::vector<DNSRecord>& ret, int& rcode, unsigned int depth, const std::vector<DNSRecord>& recordsFromAnswer, vState& state);
696

697
  void handlePolicyHit(const std::string& prefix, const DNSName& qname, QType qtype, vector<DNSRecord>& ret, bool& done, int& rcode, unsigned int depth);
698
  unsigned int getAdjustedRecursionBound() const;
699

700
  void checkWildcardProof(const DNSName& qname, const QType& qtype, DNSRecord& rec, const LWResult& lwr, vState& state, unsigned int depth, const std::string& prefix, unsigned int wildcardLabelsCount);
701

702
  void setUpdatingRootNS()
703
  {
229✔
704
    d_updatingRootNS = true;
229✔
705
  }
229✔
706

707
  std::string getPrefix(unsigned int depth) const
708
  {
41,812✔
709
    if (!doLog()) {
41,815✔
710
      return "";
35,563✔
711
    }
35,563✔
712
    auto prefix = d_prefix;
2,147,489,895✔
713
    prefix.append(depth, ' ');
2,147,489,895✔
714
    return prefix;
2,147,489,895✔
715
  }
41,812✔
716

717
  zonesStates_t d_cutStates;
718
  ostringstream d_trace;
719
  shared_ptr<RecursorLua4> d_pdl;
720
  boost::optional<Netmask> d_outgoingECSNetwork;
721
  std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>> d_outgoingProtobufServers;
722
  std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>> d_frameStreamServers;
723
  boost::optional<const boost::uuids::uuid&> d_initialRequestId;
724
  pdns::validation::ValidationContext d_validationContext;
725
  asyncresolve_t d_asyncResolve{nullptr};
726
  // d_now is initialized in the constructor and updates after outgoing requests in lwres.cc:asyncresolve
727
  struct timeval d_now;
728
  /* if the client is asking for a DS that does not exist, we need to provide the SOA along with the NSEC(3) proof
729
     and we might not have it if we picked up the proof from a delegation */
730
  DNSName d_externalDSQuery;
731
  string d_prefix;
732
  vState d_queryValidationState{vState::Indeterminate};
733

734
  /* When d_cacheonly is set to true, we will only check the cache.
735
   * This is set when the RD bit is unset in the incoming query
736
   */
737
  bool d_cacheonly;
738
  bool d_doDNSSEC;
739
  bool d_DNSSECValidationRequested{false};
740
  bool d_doEDNS0{true};
741
  bool d_requireAuthData{true};
742
  bool d_updatingRootNS{false};
743
  bool d_wantsRPZ{true};
744
  bool d_wasOutOfBand{false};
745
  bool d_wasVariable{false};
746
  bool d_qNameMinimization{false};
747
  bool d_qNameMinimizationFallbackMode{false};
748
  bool d_queryReceivedOverTCP{false};
749
  bool d_followCNAME{true};
750
  bool d_refresh{false};
751
  bool d_serveStale{false};
752

753
  LogMode d_lm;
754
};
755

756
/* external functions, opaque to us */
757
LWResult::Result asendtcp(const PacketBuffer& data, shared_ptr<TCPIOHandler>&);
758
LWResult::Result arecvtcp(PacketBuffer& data, size_t len, shared_ptr<TCPIOHandler>&, bool incompleteOkay);
759
void mthreadSleep(unsigned int jitterMsec);
760

761
enum TCPAction : uint8_t
762
{
763
  DoingRead,
764
  DoingWrite
765
};
766

767
struct PacketID
768
{
769
  PacketID()
770
  {
25,806✔
771
    remote.reset();
25,806✔
772
  }
25,806✔
773

774
  ComboAddress remote; // this is the remote
775
  DNSName domain; // this is the question
776

777
  PacketBuffer inMSG; // they'll go here
778
  PacketBuffer outMSG; // the outgoing message that needs to be sent
779

780
  using chain_t = set<std::pair<int, uint16_t>>;
781
  mutable chain_t authReqChain;
782
  shared_ptr<TCPIOHandler> tcphandler{nullptr};
783
  timeval creationTime{};
784
  string::size_type inPos{0}; // how far are we along in the inMSG
785
  size_t inWanted{0}; // if this is set, we'll read until inWanted bytes are read
786
  string::size_type outPos{0}; // how far we are along in the outMSG
787
  mutable uint32_t nearMisses{0}; // number of near misses - host correct, id wrong
788
  int fd{-1};
789
  int tcpsock{0}; // or wait for an event on a TCP fd
790
  mutable bool closed{false}; // Processing already started, don't accept new chained ids
791
  bool inIncompleteOkay{false};
792
  uint16_t id{0}; // wait for a specific id/remote pair
793
  uint16_t type{0}; // and this is its type
794
  TCPAction highState{TCPAction::DoingRead};
795
  IOState lowState{IOState::NeedRead};
796

797
  bool operator<(const PacketID& /* b */) const
798
  {
×
799
    // We don't want explicit PacketID compare here, but always via predicate classes below
×
800
    assert(0); // NOLINT: lib
×
801
  }
×
802
};
803

804
inline ostream& operator<<(ostream& ostr, const PacketID& pid)
805
{
×
806
  return ostr << "PacketID(id=" << pid.id << ",remote=" << pid.remote.toString() << ",type=" << pid.type << ",tcpsock=" << pid.tcpsock << ",fd=" << pid.fd << ',' << pid.domain << ')';
×
807
}
×
808

809
inline ostream& operator<<(ostream& ostr, const shared_ptr<PacketID>& pid)
810
{
×
811
  return ostr << *pid;
×
812
}
×
813

814
/*
815
 * The two compare predicates below must be consistent!
816
 * PacketIDBirthdayCompare can omit minor fields, but not change the or skip fields
817
 * order! See boost docs on CompatibleCompare.
818
 */
819
struct PacketIDCompare
820
{
821
  bool operator()(const std::shared_ptr<PacketID>& lhs, const std::shared_ptr<PacketID>& rhs) const
822
  {
195,096✔
823
    if (std::tie(lhs->remote, lhs->tcpsock, lhs->type) < std::tie(rhs->remote, rhs->tcpsock, rhs->type)) {
195,096✔
824
      return true;
60,153✔
825
    }
60,153✔
826
    if (std::tie(lhs->remote, lhs->tcpsock, lhs->type) > std::tie(rhs->remote, rhs->tcpsock, rhs->type)) {
134,943✔
827
      return false;
34,584✔
828
    }
34,584✔
829

830
    return std::tie(lhs->domain, lhs->fd, lhs->id) < std::tie(rhs->domain, rhs->fd, rhs->id);
100,359✔
831
  }
134,943✔
832
};
833

834
struct PacketIDBirthdayCompare
835
{
836
  bool operator()(const std::shared_ptr<PacketID>& lhs, const std::shared_ptr<PacketID>& rhs) const
837
  {
45,785✔
838
    if (std::tie(lhs->remote, lhs->tcpsock, lhs->type) < std::tie(rhs->remote, rhs->tcpsock, rhs->type)) {
45,785✔
839
      return true;
21,209✔
840
    }
21,209✔
841
    if (std::tie(lhs->remote, lhs->tcpsock, lhs->type) > std::tie(rhs->remote, rhs->tcpsock, rhs->type)) {
24,576✔
842
      return false;
7,074✔
843
    }
7,074✔
844
    return lhs->domain < rhs->domain;
17,502✔
845
  }
24,576✔
846
};
847
extern std::unique_ptr<MemRecursorCache> g_recCache;
848

849
extern rec::GlobalCounters g_Counters;
850
extern thread_local rec::TCounters t_Counters;
851

852
//! represents a running TCP/IP client session
853
class TCPConnection
854
{
855
public:
856
  TCPConnection(int fileDesc, const ComboAddress& addr);
857
  ~TCPConnection();
858
  TCPConnection(const TCPConnection&) = delete;
859
  TCPConnection& operator=(const TCPConnection&) = delete;
860
  TCPConnection(TCPConnection&&) = delete;
861
  TCPConnection& operator=(TCPConnection&&) = delete;
862

863
  [[nodiscard]] int getFD() const
864
  {
2,058✔
865
    return d_fd;
2,058✔
866
  }
2,058✔
867
  void setDropOnIdle()
868
  {
3✔
869
    d_dropOnIdle = true;
3✔
870
  }
3✔
871
  [[nodiscard]] bool isDropOnIdle() const
872
  {
242✔
873
    return d_dropOnIdle;
242✔
874
  }
242✔
875

876
  // The max number of concurrent TCP requests we're willing to process
877
  static uint16_t s_maxInFlight;
878
  static unsigned int getCurrentConnections() { return s_currentConnections; }
495✔
879

880
  std::vector<ProxyProtocolValue> proxyProtocolValues;
881
  std::string data;
882
  ComboAddress d_remote;
883
  ComboAddress d_source;
884
  ComboAddress d_destination;
885
  ComboAddress d_mappedSource;
886
  size_t queriesCount{0};
887
  size_t proxyProtocolGot{0};
888
  ssize_t proxyProtocolNeed{0};
889
  enum stateenum
890
  {
891
    PROXYPROTOCOLHEADER,
892
    BYTE0,
893
    BYTE1,
894
    GETQUESTION,
895
    DONE
896
  } state{BYTE0};
897
  uint16_t qlen{0};
898
  uint16_t bytesread{0};
899
  uint16_t d_requestsInFlight{0}; // number of mthreads spawned for this connection
900

901
private:
902
  int d_fd;
903
  static std::atomic<uint32_t> s_currentConnections; //!< total number of current TCP connections
904
  bool d_dropOnIdle{false};
905
};
906

907
class ImmediateServFailException
908
{
909
public:
910
  ImmediateServFailException(string reason_) :
911
    reason(std::move(reason_)){};
48✔
912

913
  string reason; //! Print this to tell the user what went wrong
914
};
915

916
class PolicyHitException
917
{
918
};
919

920
class ImmediateQueryDropException
921
{
922
};
923

924
class SendTruncatedAnswerException
925
{
926
};
927

928
using addrringbuf_t = boost::circular_buffer<ComboAddress>;
929
extern thread_local std::unique_ptr<addrringbuf_t> t_servfailremotes, t_largeanswerremotes, t_remotes, t_bogusremotes, t_timeouts;
930

931
extern thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t>>> t_queryring, t_servfailqueryring, t_bogusqueryring;
932
extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
933
extern thread_local std::shared_ptr<NetmaskGroup> t_allowNotifyFrom;
934
extern unsigned int g_networkTimeoutMsec;
935
extern uint16_t g_outgoingEDNSBufsize;
936
extern std::atomic<uint32_t> g_maxCacheEntries, g_maxPacketCacheEntries;
937
extern bool g_lowercaseOutgoing;
938

939
using pipefunc_t = std::function<void*()>;
940
void broadcastFunction(const pipefunc_t& func);
941
void distributeAsyncFunction(const std::string& packet, const pipefunc_t& func);
942

943
int directResolve(const DNSName& qname, QType qtype, QClass qclass, vector<DNSRecord>& ret, const shared_ptr<RecursorLua4>& pdl, Logr::log_t);
944
int directResolve(const DNSName& qname, QType qtype, QClass qclass, vector<DNSRecord>& ret, const shared_ptr<RecursorLua4>& pdl, bool qnamemin, Logr::log_t);
945
int followCNAMERecords(std::vector<DNSRecord>& ret, QType qtype, int rcode);
946
int getFakeAAAARecords(const DNSName& qname, ComboAddress prefix, vector<DNSRecord>& ret);
947
int getFakePTRRecords(const DNSName& qname, vector<DNSRecord>& ret);
948

949
template <class T>
950
T broadcastAccFunction(const std::function<T*()>& func);
951

952
using notifyset_t = std::unordered_set<DNSName>;
953
std::tuple<std::shared_ptr<SyncRes::domainmap_t>, std::shared_ptr<notifyset_t>> parseZoneConfiguration(bool yaml);
954
void* pleaseSupplantAllowNotifyFor(std::shared_ptr<notifyset_t> allowNotifyFor);
955

956
uint64_t* pleaseGetNsSpeedsSize();
957
uint64_t* pleaseGetFailedServersSize();
958
uint64_t* pleaseGetConcurrentQueries();
959
uint64_t* pleaseGetThrottleSize();
960
void doCarbonDump(void*);
961
bool primeHints(time_t now = time(nullptr));
962

963
using timebuf_t = std::array<char, 64>;
964
const char* isoDateTimeMillis(const struct timeval& tval, timebuf_t& buf);
965

966
struct WipeCacheResult
967
{
968
  int record_count = 0;
969
  int negative_record_count = 0;
970
  int packet_count = 0;
971
};
972

973
struct WipeCacheResult wipeCaches(const DNSName& canon, bool subtree, uint16_t qtype);
974

975
extern __thread struct timeval g_now;
976

977
struct ThreadTimes
978
{
979
  uint64_t msec{0};
980
  vector<uint64_t> times;
981
  ThreadTimes& operator+=(const ThreadTimes& rhs)
982
  {
321✔
983
    times.push_back(rhs.msec);
321✔
984
    return *this;
321✔
985
  }
321✔
986
};
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