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

PowerDNS / pdns / 12323094430

13 Dec 2024 09:11PM UTC coverage: 64.759% (-0.02%) from 64.78%
12323094430

Pull #14970

github

web-flow
Merge 3e4597ff7 into 3dfd8e317
Pull Request #14970: boost > std optional

37533 of 88820 branches covered (42.26%)

Branch coverage included in aggregate %.

17 of 19 new or added lines in 4 files covered. (89.47%)

79 existing lines in 16 files now uncovered.

125890 of 163537 relevant lines covered (76.98%)

4110788.26 hits per line

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

89.42
/pdns/recursordist/test-syncres_cc1.cc
1
#ifndef BOOST_TEST_DYN_LINK
2
#define BOOST_TEST_DYN_LINK
3
#endif
4

5
#include <boost/test/unit_test.hpp>
6

7
#include "test-syncres_cc.hh"
8
#include "taskqueue.hh"
9
#include "rec-taskqueue.hh"
10

11
BOOST_AUTO_TEST_SUITE(syncres_cc1)
12

13
BOOST_AUTO_TEST_CASE(test_root_primed)
14
{
2✔
15
  std::unique_ptr<SyncRes> sr;
2✔
16
  initSR(sr);
2✔
17

18
  primeHints();
2✔
19

20
  const DNSName target("a.root-servers.net.");
2✔
21
  try {
2✔
22
    /* we are primed, but only with non-auth data so we cannot resolve A a.root-servers.net. without any query */
23
    vector<DNSRecord> ret;
2✔
24
    int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
25
    BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
26
    BOOST_REQUIRE_EQUAL(ret.size(), 0U);
2✔
27

28
    ret.clear();
2✔
29
    res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
2✔
30
    BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
31
    BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
2✔
32
    BOOST_REQUIRE_EQUAL(ret.size(), 0U);
2✔
33
    BOOST_CHECK(false);
2✔
34
  }
2✔
35
  catch (const ImmediateServFailException) {
2✔
36
    // Expected
37
  }
2✔
38
}
2✔
39

40
BOOST_AUTO_TEST_CASE(test_root_primed_ns)
41
{
2✔
42
  std::unique_ptr<SyncRes> sr;
2✔
43
  initSR(sr);
2✔
44

45
  primeHints();
2✔
46
  const DNSName target(".");
2✔
47

48
  /* we are primed, but we should not be able to NS . without any query
49
   because the . NS entry is not stored as authoritative */
50

51
  size_t queriesCount = 0;
2✔
52

53
  sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
2✔
54
    queriesCount++;
2✔
55

56
    if (domain == target && type == QType::NS) {
2!
57

58
      setLWResult(res, 0, true, false, true);
2✔
59
      char addr[] = "a.root-servers.net.";
2✔
60
      for (char idx = 'a'; idx <= 'm'; idx++) {
28✔
61
        addr[0] = idx;
26✔
62
        addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
26✔
63
      }
26✔
64

65
      addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
2✔
66
      addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
2✔
67

68
      return LWResult::Result::Success;
2✔
69
    }
2✔
70

71
    return LWResult::Result::Timeout;
×
72
  });
2✔
73

74
  vector<DNSRecord> ret;
2✔
75
  int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
2✔
76
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
77
  BOOST_REQUIRE_EQUAL(ret.size(), 13U);
2✔
78
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
79
}
2✔
80

81
BOOST_AUTO_TEST_CASE(test_root_not_primed)
82
{
2✔
83
  std::unique_ptr<SyncRes> sr;
2✔
84
  initSR(sr);
2✔
85

86
  size_t queriesCount = 0;
2✔
87

88
  sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
89
    queriesCount++;
4✔
90

91
    if (domain == g_rootdnsname && type == QType::NS) {
4!
92
      setLWResult(res, 0, true, false, true);
4✔
93
      addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
4✔
94
      addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4✔
95
      addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4✔
96

97
      return LWResult::Result::Success;
4✔
98
    }
4✔
99

100
    return LWResult::Result::Timeout;
×
101
  });
4✔
102

103
  /* we are not primed yet, so SyncRes will have to call primeHints()
104
     then call getRootNS(), for which at least one of the root servers needs to answer */
105
  vector<DNSRecord> ret;
2✔
106
  int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
2✔
107
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
108
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
109
  BOOST_CHECK_EQUAL(queriesCount, 2U);
2✔
110
}
2✔
111

112
BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response)
113
{
2✔
114
  std::unique_ptr<SyncRes> sr;
2✔
115
  initSR(sr);
2✔
116
  // We expect an error, do not log it
117
  g_log.toConsole(Logger::Critical);
2✔
118
  std::set<ComboAddress> downServers;
2✔
119

120
  /* we are not primed yet, so SyncRes will have to call primeHints()
121
     then call getRootNS(), for which at least one of the root servers needs to answer.
122
     None will, so it should ServFail.
123
  */
124
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) {
104✔
125
    downServers.insert(address);
104✔
126
    return LWResult::Result::Timeout;
104✔
127
  });
104✔
128

129
  vector<DNSRecord> ret;
2✔
130
  int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
2✔
131
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
132
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
133
  BOOST_CHECK(downServers.size() > 0);
2✔
134
  /* we explicitly refuse to mark the root servers down */
135
  for (const auto& server : downServers) {
52✔
136
    BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0U);
52✔
137
  }
52✔
138
}
2✔
139

140
BOOST_AUTO_TEST_CASE(test_root_ns_poison_resistance)
141
{
2✔
142
  std::unique_ptr<SyncRes> sr;
2✔
143
  initSR(sr);
2✔
144

145
  primeHints();
2✔
146
  const DNSName target("www.example.com.");
2✔
147

148
  sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
149
    if (domain == g_rootdnsname && type == QType::NS) {
4!
150

151
      setLWResult(res, 0, true, false, true);
2✔
152
      char addr[] = "a.root-servers.net.";
2✔
153
      for (char idx = 'a'; idx <= 'm'; idx++) {
28✔
154
        addr[0] = idx;
26✔
155
        addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
26✔
156
      }
26✔
157

158
      addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
2✔
159
      addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
2✔
160

161
      return LWResult::Result::Success;
2✔
162
    }
2✔
163

164
    if (domain == target && type == QType::A) {
2!
165

166
      setLWResult(res, 0, true, false, true);
2✔
167
      addRecordToLW(res, target, QType::A, "1.2.3.4", DNSResourceRecord::ANSWER, 3600);
2✔
168

169
      addRecordToLW(res, ".", QType::NS, "poison.name.", DNSResourceRecord::AUTHORITY, 3600);
2✔
170
      addRecordToLW(res, "poison.name", QType::A, "4.5.6.7", DNSResourceRecord::ADDITIONAL, 3600);
2✔
171

172
      return LWResult::Result::Success;
2✔
173
    }
2✔
174

175
    return LWResult::Result::Timeout;
×
176
  });
2✔
177

178
  vector<DNSRecord> ret;
2✔
179
  // Check we have 13 root servers
180
  int res = sr->beginResolve(g_rootdnsname, QType(QType::NS), QClass::IN, ret);
2✔
181
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
182
  BOOST_REQUIRE_EQUAL(ret.size(), 13U);
2✔
183

184
  // Try to poison
185
  ret.clear();
2✔
186
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
187
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
188
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
189

190
  // Still should have 13
191
  ret.clear();
2✔
192
  res = sr->beginResolve(g_rootdnsname, QType(QType::NS), QClass::IN, ret);
2✔
193
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
194
  BOOST_REQUIRE_EQUAL(ret.size(), 13U);
2✔
195
}
2✔
196

197
BOOST_AUTO_TEST_CASE(test_root_primed_ns_update)
198
{
2✔
199
  std::unique_ptr<SyncRes> sr;
2✔
200
  initSR(sr);
2✔
201

202
  primeHints();
2✔
203
  const DNSName target(".");
2✔
204
  const DNSName aroot("a.root-servers.net.");
2✔
205
  const string newA = "1.2.3.4";
2✔
206
  const string newAAAA = "1::2";
2✔
207

208
  /* we are primed, but we should not be able to NS . without any query
209
   because the . NS entry is not stored as authoritative */
210

211
  size_t queriesCount = 0;
2✔
212

213
  auto asynccb = [&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
2✔
214
    queriesCount++;
2✔
215

216
    if (domain == target && type == QType::NS) {
2!
217

218
      setLWResult(res, 0, true, false, true);
2✔
219
      char addr[] = "a.root-servers.net.";
2✔
220
      for (char idx = 'a'; idx <= 'm'; idx++) {
28✔
221
        addr[0] = idx;
26✔
222
        addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
26✔
223
      }
26✔
224

225
      addRecordToLW(res, aroot.toString(), QType::A, newA, DNSResourceRecord::ADDITIONAL, 3600);
2✔
226
      addRecordToLW(res, aroot.toString(), QType::AAAA, newAAAA, DNSResourceRecord::ADDITIONAL, 3600);
2✔
227

228
      return LWResult::Result::Success;
2✔
229
    }
2✔
230
    return LWResult::Result::Timeout;
×
231
  };
2✔
232

233
  sr->setAsyncCallback(asynccb);
2✔
234

235
  struct timeval now;
2✔
236
  Utility::gettimeofday(&now, nullptr);
2✔
237

238
  vector<DNSRecord> ret;
2✔
239
  int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
2✔
240
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
241
  BOOST_REQUIRE_EQUAL(ret.size(), 13U);
2✔
242
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
243

244
  ret.clear();
2✔
245
  time_t cached = g_recCache->get(now.tv_sec, aroot, QType::A, MemRecursorCache::None, &ret, ComboAddress());
2✔
246
  BOOST_CHECK(cached > 0);
2✔
247
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
248
  BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress(newA));
2✔
249

250
  ret.clear();
2✔
251
  cached = g_recCache->get(now.tv_sec, aroot, QType::AAAA, MemRecursorCache::None, &ret, ComboAddress());
2✔
252
  BOOST_CHECK(cached > 0);
2✔
253
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
254
  BOOST_CHECK(getRR<AAAARecordContent>(ret[0])->getCA() == ComboAddress(newAAAA));
2✔
255
}
2✔
256

257
static void test_edns_formerr_fallback_f(bool sample)
258
{
2✔
259
  std::unique_ptr<SyncRes> sr;
2✔
260
  initSR(sr);
2✔
261
  if (sample) {
2!
262
    sr->setQNameMinimization();
×
263
  }
×
264
  ComboAddress noEDNSServer;
2✔
265
  size_t queriesWithEDNS = 0;
2✔
266
  size_t queriesWithoutEDNS = 0;
2✔
267

268
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool /* sendRDQuery */, int EDNS0Level, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
269
    if (EDNS0Level != 0) {
4✔
270
      queriesWithEDNS++;
2✔
271
      noEDNSServer = address;
2✔
272

273
      setLWResult(res, RCode::FormErr);
2✔
274
      return LWResult::Result::Success;
2✔
275
    }
2✔
276

277
    queriesWithoutEDNS++;
2✔
278

279
    if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
2!
280
      setLWResult(res, 0, true, false, false);
2✔
281
      addRecordToLW(res, domain, QType::A, "192.0.2.1");
2✔
282
      return LWResult::Result::Success;
2✔
283
    }
2✔
284

285
    return sample ? basicRecordsForQnameMinimization(res, domain, type) : LWResult::Result::Timeout;
×
286
  });
2✔
287

288
  primeHints();
2✔
289

290
  /* fake that the root NS doesn't handle EDNS, check that we fallback */
291
  vector<DNSRecord> ret;
2✔
292
  int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
2✔
293
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
294
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
295
  BOOST_CHECK_EQUAL(queriesWithEDNS, sample ? 3U : 1U);
2✔
296
  BOOST_CHECK_EQUAL(queriesWithoutEDNS, sample ? 4U : 1U);
2✔
297
  BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), sample ? 3U : 1U);
2✔
298
  BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
2✔
299
}
2✔
300

301
BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback)
302
{
2✔
303
  test_edns_formerr_fallback_f(false);
2✔
304
}
2✔
305

306
BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback_qmin)
307
{
2✔
308
  // DISABLED UNTIL QNAME MINIMIZATION IS THERE
309
  return;
2✔
310
  test_edns_formerr_fallback_f(true);
×
311
}
×
312

313
BOOST_AUTO_TEST_CASE(test_edns_formerr_but_edns_enabled)
314
{
2✔
315
  std::unique_ptr<SyncRes> sr;
2✔
316
  initSR(sr);
2✔
317

318
  /* in this test, the auth answers with FormErr to an EDNS-enabled
319
     query, but the response does contain EDNS so we should not mark
320
     it as EDNS ignorant or intolerant.
321
  */
322
  size_t queriesWithEDNS = 0;
2✔
323
  size_t queriesWithoutEDNS = 0;
2✔
324
  std::set<ComboAddress> usedServers;
2✔
325

326
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int type, bool /* doTCP */, bool /* sendRDQuery */, int EDNS0Level, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
52✔
327
    if (EDNS0Level > 0) {
52!
328
      queriesWithEDNS++;
52✔
329
    }
52✔
330
    else {
×
331
      queriesWithoutEDNS++;
×
332
    }
×
333
    usedServers.insert(address);
52✔
334

335
    if (type == QType::DNAME) {
52!
336
      setLWResult(res, RCode::FormErr);
52✔
337
      if (EDNS0Level > 0) {
52!
338
        res->d_haveEDNS = true;
52✔
339
      }
52✔
340
      return LWResult::Result::Success;
52✔
341
    }
52✔
342

343
    return LWResult::Result::Timeout;
×
344
  });
52✔
345

346
  primeHints();
2✔
347

348
  vector<DNSRecord> ret;
2✔
349
  int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::DNAME), QClass::IN, ret);
2✔
350
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
351
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
352
  BOOST_CHECK_EQUAL(queriesWithEDNS, 26U);
2✔
353
  BOOST_CHECK_EQUAL(queriesWithoutEDNS, 0U);
2✔
354
  BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0U);
2✔
355
  BOOST_CHECK_EQUAL(usedServers.size(), 26U);
2✔
356
  for (const auto& server : usedServers) {
52✔
357
    BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
52✔
358
  }
52✔
359
}
2✔
360

361
BOOST_AUTO_TEST_CASE(test_meta_types)
362
{
2✔
363
  std::unique_ptr<SyncRes> sr;
2✔
364
  initSR(sr);
2✔
365

366
  static const std::set<uint16_t> invalidTypes = {128, QType::AXFR, QType::IXFR, QType::RRSIG, QType::NSEC3, QType::OPT, QType::TSIG, QType::TKEY, QType::MAILA, QType::MAILB, 65535};
2✔
367

368
  for (const auto qtype : invalidTypes) {
22✔
369
    size_t queriesCount = 0;
22✔
370

371
    sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* /* res */, bool* /* chained */) {
22✔
372
      queriesCount++;
×
373
      return LWResult::Result::Timeout;
×
374
    });
×
375

376
    primeHints();
22✔
377

378
    vector<DNSRecord> ret;
22✔
379
    int res = sr->beginResolve(DNSName("powerdns.com."), QType(qtype), QClass::IN, ret);
22✔
380
    BOOST_CHECK_EQUAL(res, -1);
22✔
381
    BOOST_CHECK_EQUAL(ret.size(), 0U);
22✔
382
    BOOST_CHECK_EQUAL(queriesCount, 0U);
22✔
383
  }
22✔
384
}
2✔
385

386
BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp)
387
{
2✔
388
  std::unique_ptr<SyncRes> sr;
2✔
389
  initSR(sr);
2✔
390

391
  sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool doTCP, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
392
    if (!doTCP) {
4✔
393
      setLWResult(res, 0, false, true, false);
2✔
394
      return LWResult::Result::Success;
2✔
395
    }
2✔
396
    if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
2!
397
      setLWResult(res, 0, true, false, false);
2✔
398
      addRecordToLW(res, domain, QType::A, "192.0.2.1");
2✔
399
      return LWResult::Result::Success;
2✔
400
    }
2✔
401

402
    return LWResult::Result::Timeout;
×
403
  });
2✔
404

405
  primeHints();
2✔
406

407
  /* fake that the NS truncates every request over UDP, we should fallback to TCP */
408
  vector<DNSRecord> ret;
2✔
409
  int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
2✔
410
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
411
}
2✔
412

413
BOOST_AUTO_TEST_CASE(test_tc_over_tcp)
414
{
2✔
415
  std::unique_ptr<SyncRes> sr;
2✔
416
  initSR(sr);
2✔
417

418
  size_t tcpQueriesCount = 0;
2✔
419

420
  sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int /* type */, bool doTCP, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
8✔
421
    if (!doTCP) {
8✔
422
      setLWResult(res, 0, true, true, false);
4✔
423
      return LWResult::Result::Success;
4✔
424
    }
4✔
425

426
    /* first TCP query is answered with a TC response */
427
    tcpQueriesCount++;
4✔
428
    if (tcpQueriesCount == 1) {
4✔
429
      setLWResult(res, 0, true, true, false);
2✔
430
    }
2✔
431
    else {
2✔
432
      setLWResult(res, 0, true, false, false);
2✔
433
    }
2✔
434

435
    addRecordToLW(res, domain, QType::A, "192.0.2.1");
4✔
436
    return LWResult::Result::Success;
4✔
437
  });
8✔
438

439
  primeHints();
2✔
440

441
  vector<DNSRecord> ret;
2✔
442
  int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
2✔
443
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
444
  BOOST_CHECK_EQUAL(tcpQueriesCount, 2U);
2✔
445
}
2✔
446

447
BOOST_AUTO_TEST_CASE(test_all_nss_down)
448
{
2✔
449
  std::unique_ptr<SyncRes> sr;
2✔
450
  initSR(sr);
2✔
451
  std::set<ComboAddress> downServers;
2✔
452

453
  primeHints();
2✔
454

455
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
12✔
456
    if (isRootServer(address)) {
12✔
457
      setLWResult(res, 0, false, false, true);
2✔
458
      addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
459
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
460
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
461
      return LWResult::Result::Success;
2✔
462
    }
2✔
463
    if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
10!
464
      setLWResult(res, 0, false, false, true);
2✔
465
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
466
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
467
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
468
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
469
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
470
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
471
      return LWResult::Result::Success;
2✔
472
    }
2✔
473
    downServers.insert(address);
8✔
474
    res->d_usec = g_networkTimeoutMsec * 1000;
8✔
475
    return LWResult::Result::Timeout;
8✔
476
  });
10✔
477

478
  DNSName target("powerdns.com.");
2✔
479

480
  vector<DNSRecord> ret;
2✔
481
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
482
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
483
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
484
  BOOST_CHECK_EQUAL(downServers.size(), 4U);
2✔
485

486
  time_t now = sr->getNow().tv_sec;
2✔
487
  for (const auto& server : downServers) {
8✔
488
    BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1U);
8✔
489
    BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
8✔
490
  }
8✔
491
}
2✔
492

493
BOOST_AUTO_TEST_CASE(test_all_nss_network_error)
494
{
2✔
495
  std::unique_ptr<SyncRes> sr;
2✔
496
  initSR(sr);
2✔
497
  std::set<ComboAddress> downServers;
2✔
498

499
  primeHints();
2✔
500

501
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
12✔
502
    if (isRootServer(address)) {
12✔
503
      setLWResult(res, 0, false, false, true);
2✔
504
      addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
505
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
506
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
507
      return LWResult::Result::Success;
2✔
508
    }
2✔
509
    if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
10✔
510
      setLWResult(res, 0, false, false, true);
2✔
511
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
512
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
513
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
514
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
515
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
516
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
517
      return LWResult::Result::Success;
2✔
518
    }
2✔
519
    downServers.insert(address);
8✔
520
    res->d_usec = g_networkTimeoutMsec * 1000;
8✔
521
    return LWResult::Result::Timeout;
8✔
522
  });
10✔
523

524
  /* exact same test than the previous one, except instead of a time out we fake a network error */
525
  DNSName target("powerdns.com.");
2✔
526

527
  vector<DNSRecord> ret;
2✔
528
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
529
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
530
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
531
  BOOST_CHECK_EQUAL(downServers.size(), 4U);
2✔
532

533
  time_t now = sr->getNow().tv_sec;
2✔
534
  for (const auto& server : downServers) {
8✔
535
    BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1U);
8✔
536
    BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
8✔
537
  }
8✔
538
}
2✔
539

540
BOOST_AUTO_TEST_CASE(test_all_nss_send_tc_then_garbage_over_tcp)
541
{
2✔
542
  std::unique_ptr<SyncRes> sr;
2✔
543
  initSR(sr);
2✔
544

545
  primeHints();
2✔
546

547
  std::set<ComboAddress> downServers;
2✔
548

549
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool doTCP, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
10✔
550
    if (isRootServer(address)) {
10✔
551
      setLWResult(res, 0, false, false, true);
2✔
552
      addRecordToLW(res, "lock-up.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
553
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
554
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
555
      return LWResult::Result::Success;
2✔
556
    }
2✔
557

558
    if (!doTCP) {
8✔
559
      setLWResult(res, 0, false, true, false);
4✔
560
      return LWResult::Result::Success;
4✔
561
    }
4✔
562
    downServers.insert(address);
4✔
563

564
    setLWResult(res, RCode::FormErr, false, false, false);
4✔
565
    res->d_validpacket = false;
4✔
566
    return LWResult::Result::Success;
4✔
567
  });
8✔
568

569
  DNSName target("www.lock-up.");
2✔
570

571
  vector<DNSRecord> ret;
2✔
572
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
573
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
574
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
575
  BOOST_CHECK_EQUAL(downServers.size(), 2U);
2✔
576

577
  for (const auto& server : downServers) {
4✔
578
    BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
4✔
579
    BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName("a.gtld-servers.net."), server), 1000000U);
4✔
580
  }
4✔
581
}
2✔
582

583
BOOST_AUTO_TEST_CASE(test_all_nss_send_garbage_over_udp)
584
{
2✔
585
  std::unique_ptr<SyncRes> sr;
2✔
586
  initSR(sr);
2✔
587

588
  primeHints();
2✔
589

590
  std::set<ComboAddress> downServers;
2✔
591
  size_t queriesCount = 0;
2✔
592

593
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
6✔
594
    if (isRootServer(address)) {
6✔
595
      setLWResult(res, 0, false, false, true);
2✔
596
      addRecordToLW(res, "lock-up.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
597
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
598
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
599
      return LWResult::Result::Success;
2✔
600
    }
2✔
601

602
    ++queriesCount;
4✔
603
    downServers.insert(address);
4✔
604

605
    setLWResult(res, RCode::FormErr, false, false, false);
4✔
606
    res->d_validpacket = false;
4✔
607
    return LWResult::Result::Success;
4✔
608
  });
6✔
609

610
  DNSName target("www.lock-up.");
2✔
611

612
  vector<DNSRecord> ret;
2✔
613
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
614
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
615
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
616
  BOOST_CHECK_EQUAL(downServers.size(), 2U);
2✔
617
  /* two queries with EDNS, that's it */
618
  BOOST_CHECK_EQUAL(queriesCount, 2U);
2✔
619

620
  for (const auto& server : downServers) {
4✔
621
    BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
4✔
622
    BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName("a.gtld-servers.net."), server), 1000000U);
4✔
623
    BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSIGNORANT);
4✔
624
  }
4✔
625
}
2✔
626

627
BOOST_AUTO_TEST_CASE(test_regular_ns_send_refused)
628
{
2✔
629
  std::unique_ptr<SyncRes> sr;
2✔
630
  initSR(sr);
2✔
631

632
  primeHints();
2✔
633

634
  std::set<ComboAddress> downServers;
2✔
635
  size_t queriesCount = 0;
2✔
636

637
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
6✔
638
    if (isRootServer(address)) {
6✔
639
      setLWResult(res, 0, false, false, true);
2✔
640
      addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
641
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
642
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
643
      return LWResult::Result::Success;
2✔
644
    }
2✔
645

646
    ++queriesCount;
4✔
647
    downServers.insert(address);
4✔
648

649
    setLWResult(res, RCode::Refused, false, false, true);
4✔
650

651
    return LWResult::Result::Success;
4✔
652
  });
6✔
653

654
  DNSName target("www.refused.");
2✔
655

656
  vector<DNSRecord> ret;
2✔
657
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
658
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
659
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
660
  BOOST_CHECK_EQUAL(downServers.size(), 2U);
2✔
661
  BOOST_CHECK_EQUAL(queriesCount, 2U);
2✔
662

663
  for (const auto& server : downServers) {
4✔
664
    /* same as any other server */
665
    BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
4✔
666
    BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName("a.gtld-servers.net."), server), 0U);
4✔
667
    BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
4✔
668
  }
4✔
669
}
2✔
670

671
BOOST_AUTO_TEST_CASE(test_forward_ns_send_refused)
672
{
2✔
673
  std::unique_ptr<SyncRes> sr;
2✔
674
  initSR(sr);
2✔
675

676
  primeHints();
2✔
677

678
  std::set<ComboAddress> downServers;
2✔
679
  size_t queriesCount = 0;
2✔
680

681
  const DNSName target("www.refused.");
2✔
682

683
  SyncRes::AuthDomain ad;
2✔
684
  const std::vector<ComboAddress> forwardedNSs{ComboAddress("192.0.2.42:53"), ComboAddress("192.0.2.43:53")};
2✔
685
  ad.d_rdForward = false;
2✔
686
  ad.d_servers = forwardedNSs;
2✔
687
  (*SyncRes::t_sstorage.domainmap)[target] = ad;
2✔
688

689
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
690
    if (isRootServer(address)) {
4!
691
      setLWResult(res, 0, false, false, true);
×
692
      addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
×
693
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
694
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
×
695
      return LWResult::Result::Success;
×
696
    }
×
697

698
    ++queriesCount;
4✔
699
    downServers.insert(address);
4✔
700

701
    setLWResult(res, RCode::Refused, false, false, true);
4✔
702

703
    return LWResult::Result::Success;
4✔
704
  });
4✔
705

706
  vector<DNSRecord> ret;
2✔
707
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
708
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
709
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
710
  BOOST_CHECK_EQUAL(downServers.size(), 2U);
2✔
711
  BOOST_CHECK_EQUAL(queriesCount, 2U);
2✔
712

713
  for (const auto& server : forwardedNSs) {
4✔
714
    BOOST_CHECK_EQUAL(downServers.count(server), 1U);
4✔
715
    /* same as any other server */
716
    BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
4✔
717
    BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName("a.gtld-servers.net."), server), 0U);
4✔
718
    BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
4✔
719
  }
4✔
720
}
2✔
721

722
BOOST_AUTO_TEST_CASE(test_forward_ns_send_servfail)
723
{
2✔
724
  std::unique_ptr<SyncRes> sr;
2✔
725
  initSR(sr);
2✔
726

727
  primeHints();
2✔
728

729
  std::set<ComboAddress> downServers;
2✔
730
  size_t queriesCount = 0;
2✔
731

732
  const DNSName target("www.refused.");
2✔
733

734
  SyncRes::AuthDomain ad;
2✔
735
  const std::vector<ComboAddress> forwardedNSs{ComboAddress("192.0.2.42:53"), ComboAddress("192.0.2.43:53")};
2✔
736
  ad.d_rdForward = false;
2✔
737
  ad.d_servers = forwardedNSs;
2✔
738
  (*SyncRes::t_sstorage.domainmap)[DNSName("refused.")] = ad;
2✔
739

740
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
741
    if (isRootServer(address)) {
4!
742
      setLWResult(res, 0, false, false, true);
×
743
      addRecordToLW(res, "refused.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
×
744
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
745
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
×
746
      return LWResult::Result::Success;
×
747
    }
×
748

749
    ++queriesCount;
4✔
750
    downServers.insert(address);
4✔
751

752
    setLWResult(res, RCode::ServFail, false, false, true);
4✔
753

754
    return LWResult::Result::Success;
4✔
755
  });
4✔
756

757
  vector<DNSRecord> ret;
2✔
758
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
759
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
760
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
761
  BOOST_CHECK_EQUAL(downServers.size(), 2U);
2✔
762
  BOOST_CHECK_EQUAL(queriesCount, 2U);
2✔
763

764
  for (const auto& server : forwardedNSs) {
4✔
765
    BOOST_CHECK_EQUAL(downServers.count(server), 1U);
4✔
766
    /* on servfail from a server we forward to we only increase the NS speed so
767
       that a different server might be tried instead, but we don't throttle */
768
    BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
4✔
769
    BOOST_CHECK_EQUAL(SyncRes::getNSSpeed(DNSName(server.toStringWithPort()), server), 1000000U);
4✔
770
    BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
4✔
771
  }
4✔
772
}
2✔
773

774
BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue)
775
{
2✔
776
  std::unique_ptr<SyncRes> sr;
2✔
777
  initSR(sr);
2✔
778

779
  primeHints();
2✔
780

781
  DNSName target("www.powerdns.com.");
2✔
782

783
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
15✔
784
    if (isRootServer(address)) {
15✔
785
      setLWResult(res, 0, false, false, true);
4✔
786
      if (domain == target) {
4✔
787
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
788
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
789
        addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
790
        addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
791
      }
2✔
792
      else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
2!
793
        addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
794
        addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
795
        addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
796
        addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
797
      }
2✔
798
      return LWResult::Result::Success;
4✔
799
    }
4✔
800
    if (address == ComboAddress("192.0.2.3:53")) {
11✔
801
      setLWResult(res, 0, true, false, true);
4✔
802
      if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
4✔
803
        if (type == QType::A) {
2!
804
          addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
2✔
805
        }
2✔
806
        else if (type == QType::AAAA) {
×
807
          addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
×
808
        }
×
809
      }
2✔
810
      else if (domain == target) {
2!
811
        if (type == QType::A) {
2!
812
          addRecordToLW(res, domain, QType::A, "192.0.2.1");
2✔
813
        }
2✔
814
        else if (type == QType::AAAA) {
×
815
          addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
×
816
        }
×
817
      }
2✔
818
      return LWResult::Result::Success;
4✔
819
    }
4✔
820
    return LWResult::Result::Timeout;
7✔
821
  });
11✔
822

823
  vector<DNSRecord> ret;
2✔
824
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
825
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
826
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
827
}
2✔
828

829
BOOST_AUTO_TEST_CASE(test_os_limit_errors)
830
{
2✔
831
  std::unique_ptr<SyncRes> sr;
2✔
832
  initSR(sr);
2✔
833
  std::set<ComboAddress> downServers;
2✔
834

835
  primeHints();
2✔
836

837
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
12✔
838
    if (isRootServer(address)) {
12✔
839
      setLWResult(res, 0, false, false, true);
2✔
840
      addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
841
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
842
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
843
      return LWResult::Result::Success;
2✔
844
    }
2✔
845
    if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
10!
846
      setLWResult(res, 0, false, false, true);
2✔
847
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
848
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
849
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
850
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
851
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
852
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
853
      return LWResult::Result::Success;
2✔
854
    }
2✔
855
    {
8✔
856
      if (downServers.size() < 3) {
8✔
857
        /* only the last one will answer */
858
        downServers.insert(address);
6✔
859
        res->d_usec = g_networkTimeoutMsec * 1000;
6✔
860
        return LWResult::Result::OSLimitError;
6✔
861
      }
6✔
862
      setLWResult(res, 0, true, false, true);
2✔
863
      addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
2✔
864
      return LWResult::Result::Success;
2✔
865
    }
8✔
866
  });
8✔
867

868
  DNSName target("powerdns.com.");
2✔
869

870
  vector<DNSRecord> ret;
2✔
871
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
872
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
873
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
874
  BOOST_CHECK_EQUAL(downServers.size(), 3U);
2✔
875

876
  /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
877
  time_t now = sr->getNow().tv_sec;
2✔
878
  for (const auto& server : downServers) {
6✔
879
    BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0U);
6✔
880
    BOOST_CHECK(!SyncRes::isThrottled(now, server, target, QType::A));
6✔
881
  }
6✔
882
}
2✔
883

884
BOOST_AUTO_TEST_CASE(test_glued_referral)
885
{
2✔
886
  std::unique_ptr<SyncRes> sr;
2✔
887
  initSR(sr);
2✔
888

889
  primeHints();
2✔
890

891
  const DNSName target("powerdns.com.");
2✔
892

893
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
6✔
894
    /* this will cause issue with qname minimization if we ever implement it */
895
    if (domain != target) {
6!
896
      return LWResult::Result::Timeout;
×
897
    }
×
898

899
    if (isRootServer(address)) {
6✔
900
      setLWResult(res, 0, false, false, true);
2✔
901
      addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
902
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
903
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
904
      return LWResult::Result::Success;
2✔
905
    }
2✔
906
    if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
4✔
907
      setLWResult(res, 0, false, false, true);
2✔
908
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
909
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
910
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
911
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
912
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
913
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
914
      return LWResult::Result::Success;
2✔
915
    }
2✔
916
    if (address == ComboAddress("192.0.2.2:53") || address == ComboAddress("192.0.2.3:53") || address == ComboAddress("[2001:DB8::2]:53") || address == ComboAddress("[2001:DB8::3]:53")) {
2!
917
      setLWResult(res, 0, true, false, true);
2✔
918
      addRecordToLW(res, target, QType::A, "192.0.2.4");
2✔
919
      return LWResult::Result::Success;
2✔
920
    }
2✔
921
    return LWResult::Result::Timeout;
×
922
  });
2✔
923

924
  vector<DNSRecord> ret;
2✔
925
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
926
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
927
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
928
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
929
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
930
}
2✔
931

932
BOOST_AUTO_TEST_CASE(test_glueless_referral)
933
{
2✔
934
  std::unique_ptr<SyncRes> sr;
2✔
935
  initSR(sr);
2✔
936

937
  primeHints();
2✔
938

939
  const DNSName target("powerdns.com.");
2✔
940

941
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
10✔
942
    if (isRootServer(address)) {
10✔
943
      setLWResult(res, 0, false, false, true);
4✔
944

945
      if (domain.isPartOf(DNSName("com."))) {
4✔
946
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
947
      }
2✔
948
      else if (domain.isPartOf(DNSName("org."))) {
2!
949
        addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
950
      }
2✔
951
      else {
×
952
        setLWResult(res, RCode::NXDomain, false, false, true);
×
953
        return LWResult::Result::Success;
×
954
      }
×
955

956
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
957
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
958
      return LWResult::Result::Success;
4✔
959
    }
4✔
960
    if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
6✔
961
      if (domain == target) {
4✔
962
        setLWResult(res, 0, false, false, true);
2✔
963
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
2✔
964
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
2✔
965
        return LWResult::Result::Success;
2✔
966
      }
2✔
967
      if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
2!
968
        setLWResult(res, 0, true, false, true);
×
969
        addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
×
970
        addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
×
971
        return LWResult::Result::Success;
×
972
      }
×
973
      if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
2!
974
        setLWResult(res, 0, true, false, true);
2✔
975
        addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
2✔
976
        addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
2✔
977
        return LWResult::Result::Success;
2✔
978
      }
2✔
979

980
      setLWResult(res, RCode::NXDomain, false, false, true);
×
981
      return LWResult::Result::Success;
×
982
    }
2✔
983
    if (address == ComboAddress("192.0.2.2:53") || address == ComboAddress("192.0.2.3:53") || address == ComboAddress("[2001:DB8::2]:53") || address == ComboAddress("[2001:DB8::3]:53")) {
2!
984
      setLWResult(res, 0, true, false, true);
2✔
985
      addRecordToLW(res, target, QType::A, "192.0.2.4");
2✔
986
      return LWResult::Result::Success;
2✔
987
    }
2✔
988
    return LWResult::Result::Timeout;
×
989
  });
2✔
990

991
  vector<DNSRecord> ret;
2✔
992
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
993
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
994
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
995
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
996
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
997
}
2✔
998

999
BOOST_AUTO_TEST_CASE(test_endless_glueless_referral)
1000
{
2✔
1001
  std::unique_ptr<SyncRes> sr;
2✔
1002
  initSR(sr);
2✔
1003

1004
  primeHints();
2✔
1005

1006
  const DNSName target("powerdns.com.");
2✔
1007

1008
  size_t count = 0;
2✔
1009
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
58✔
1010
    if (isRootServer(address)) {
58✔
1011
      setLWResult(res, 0, false, false, true);
10✔
1012

1013
      if (domain.isPartOf(DNSName("com."))) {
10✔
1014
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1015
      }
2✔
1016
      else if (domain.isPartOf(DNSName("org."))) {
8!
1017
        addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
8✔
1018
      }
8✔
1019
      else {
×
1020
        setLWResult(res, RCode::NXDomain, false, false, true);
×
1021
        return LWResult::Result::Success;
×
1022
      }
×
1023

1024
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
10✔
1025
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
10✔
1026
      return LWResult::Result::Success;
10✔
1027
    }
10✔
1028
    if (domain == target) {
48✔
1029
      setLWResult(res, 0, false, false, true);
2✔
1030
      addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1031
      addRecordToLW(res, "powerdns.com.", QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1032
      return LWResult::Result::Success;
2✔
1033
    }
2✔
1034
    setLWResult(res, 0, false, false, true);
46✔
1035
    addRecordToLW(res, domain, QType::NS, std::to_string(count) + ".ns1.powerdns.org", DNSResourceRecord::AUTHORITY, 172800);
46✔
1036
    addRecordToLW(res, domain, QType::NS, std::to_string(count) + ".ns2.powerdns.org", DNSResourceRecord::AUTHORITY, 172800);
46✔
1037
    count++;
46✔
1038
    return LWResult::Result::Success;
46✔
1039
  });
48✔
1040

1041
  vector<DNSRecord> ret;
2✔
1042
  BOOST_CHECK_EXCEPTION(sr->beginResolve(target, QType(QType::A), QClass::IN, ret),
2✔
1043
                        ImmediateServFailException,
2✔
1044
                        [&](const ImmediateServFailException& isfe) {
2✔
1045
                          return isfe.reason.substr(0, 9) == "More than";
2✔
1046
                        });
2✔
1047
}
2✔
1048

1049
BOOST_AUTO_TEST_CASE(test_glueless_referral_aaaa_task)
1050
{
2✔
1051
  std::unique_ptr<SyncRes> sr;
2✔
1052
  initSR(sr);
2✔
1053

1054
  primeHints();
2✔
1055

1056
  const DNSName target("powerdns.com.");
2✔
1057

1058
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
10✔
1059
    if (isRootServer(address)) {
10✔
1060
      setLWResult(res, 0, false, false, true);
4✔
1061

1062
      if (domain.isPartOf(DNSName("com."))) {
4✔
1063
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1064
      }
2✔
1065
      else if (domain.isPartOf(DNSName("org."))) {
2!
1066
        addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1067
      }
2✔
1068
      else {
×
1069
        setLWResult(res, RCode::NXDomain, false, false, true);
×
1070
        return LWResult::Result::Success;
×
1071
      }
×
1072

1073
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
1074
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
1075
      return LWResult::Result::Success;
4✔
1076
    }
4✔
1077
    if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
6✔
1078
      if (domain == target) {
4✔
1079
        setLWResult(res, 0, false, false, true);
2✔
1080
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1081
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1082
        return LWResult::Result::Success;
2✔
1083
      }
2✔
1084
      if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
2!
UNCOV
1085
        setLWResult(res, 0, true, false, true);
×
UNCOV
1086
        if (type == QType::A) {
×
UNCOV
1087
          addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
×
UNCOV
1088
        }
×
1089
        else {
×
1090
          addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
×
1091
        }
×
UNCOV
1092
        return LWResult::Result::Success;
×
UNCOV
1093
      }
×
1094
      if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
2!
1095
        setLWResult(res, 0, true, false, true);
2✔
1096
        if (type == QType::A) {
2!
1097
          addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
2✔
1098
        }
2✔
1099
        else {
×
1100
          addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
×
1101
        }
×
1102
        return LWResult::Result::Success;
2✔
1103
      }
2✔
1104

1105
      setLWResult(res, RCode::NXDomain, false, false, true);
×
1106
      return LWResult::Result::Success;
×
1107
    }
2✔
1108
    if (address == ComboAddress("192.0.2.2:53") || address == ComboAddress("192.0.2.3:53") || address == ComboAddress("[2001:DB8::2]:53") || address == ComboAddress("[2001:DB8::3]:53")) {
2!
1109
      setLWResult(res, 0, true, false, true);
2✔
1110
      addRecordToLW(res, target, QType::A, "192.0.2.4");
2✔
1111
      return LWResult::Result::Success;
2✔
1112
    }
2✔
1113
    return LWResult::Result::Timeout;
×
1114
  });
2✔
1115

1116
  vector<DNSRecord> ret;
2✔
1117
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1118
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1119
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1120
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1121
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1122

1123
  // One task should be submitted
1124
  BOOST_REQUIRE_EQUAL(getTaskSize(), 1U);
2✔
1125
  auto task = taskQueuePop();
2✔
1126
  BOOST_CHECK(task.d_qname == DNSName("pdns-public-ns1.powerdns.org") || task.d_qname == DNSName("pdns-public-ns2.powerdns.org"));
2✔
1127
  BOOST_CHECK_EQUAL(task.d_qtype, QType::AAAA);
2✔
1128
}
2✔
1129

1130
BOOST_AUTO_TEST_CASE(test_edns_subnet_by_domain)
1131
{
2✔
1132
  std::unique_ptr<SyncRes> sr;
2✔
1133
  initSR(sr);
2✔
1134

1135
  primeHints();
2✔
1136

1137
  const DNSName target("powerdns.com.");
2✔
1138
  SyncRes::addEDNSDomain(target);
2✔
1139

1140
  EDNSSubnetOpts incomingECS;
2✔
1141
  incomingECS.source = Netmask("192.0.2.128/32");
2✔
1142
  sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
2✔
1143

1144
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
1145
    BOOST_REQUIRE(srcmask);
4✔
1146
    BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
4✔
1147

1148
    if (isRootServer(address)) {
4✔
1149
      setLWResult(res, 0, false, false, true);
2✔
1150
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1151
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1152

1153
      /* this one did not use the ECS info */
1154
      srcmask = boost::none;
2✔
1155

1156
      return LWResult::Result::Success;
2✔
1157
    }
2✔
1158
    if (address == ComboAddress("192.0.2.1:53")) {
2!
1159

1160
      setLWResult(res, 0, true, false, false);
2✔
1161
      addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
1162

1163
      /* this one did, but only up to a precision of /16, not the full /24 */
1164
      srcmask = Netmask("192.0.0.0/16");
2✔
1165

1166
      return LWResult::Result::Success;
2✔
1167
    }
2✔
1168

1169
    return LWResult::Result::Timeout;
×
1170
  });
2✔
1171

1172
  SyncRes::s_ecsqueries = 0;
2✔
1173
  SyncRes::s_ecsresponses = 0;
2✔
1174
  vector<DNSRecord> ret;
2✔
1175
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1176
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1177
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1178
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1179
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1180
  BOOST_CHECK_EQUAL(SyncRes::s_ecsqueries, 2U);
2✔
1181
  BOOST_CHECK_EQUAL(SyncRes::s_ecsresponses, 1U);
2✔
1182
  for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize4) {
64✔
1183
    BOOST_CHECK_EQUAL(entry.second, entry.first == 15 ? 1U : 0U);
64✔
1184
  }
64✔
1185
  for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize6) {
256✔
1186
    BOOST_CHECK_EQUAL(entry.second, 0U);
256✔
1187
  }
256✔
1188
}
2✔
1189

1190
BOOST_AUTO_TEST_CASE(test_edns_subnet_by_addr)
1191
{
2✔
1192
  std::unique_ptr<SyncRes> sr;
2✔
1193
  initSR(sr);
2✔
1194

1195
  primeHints();
2✔
1196

1197
  const DNSName target("powerdns.com.");
2✔
1198
  SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
2✔
1199

1200
  EDNSSubnetOpts incomingECS;
2✔
1201
  incomingECS.source = Netmask("2001:DB8::FF/128");
2✔
1202
  sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
2✔
1203

1204
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
1205
    if (isRootServer(address)) {
4✔
1206
      BOOST_REQUIRE(!srcmask);
2✔
1207

1208
      setLWResult(res, 0, false, false, true);
2✔
1209
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1210
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1211
      return LWResult::Result::Success;
2✔
1212
    }
2✔
1213
    if (address == ComboAddress("192.0.2.1:53")) {
2!
1214

1215
      BOOST_REQUIRE(srcmask);
2✔
1216
      BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
2✔
1217

1218
      setLWResult(res, 0, true, false, false);
2✔
1219
      addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
1220
      return LWResult::Result::Success;
2✔
1221
    }
2✔
1222

1223
    return LWResult::Result::Timeout;
×
1224
  });
2✔
1225

1226
  SyncRes::s_ecsqueries = 0;
2✔
1227
  SyncRes::s_ecsresponses = 0;
2✔
1228
  vector<DNSRecord> ret;
2✔
1229
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1230
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1231
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1232
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1233
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1234
  BOOST_CHECK_EQUAL(SyncRes::s_ecsqueries, 1U);
2✔
1235
  BOOST_CHECK_EQUAL(SyncRes::s_ecsresponses, 1U);
2✔
1236
  for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize4) {
64✔
1237
    BOOST_CHECK_EQUAL(entry.second, 0u);
64✔
1238
  }
64✔
1239
  for (const auto& entry : SyncRes::s_ecsResponsesBySubnetSize6) {
256✔
1240
    BOOST_CHECK_EQUAL(entry.second, entry.first == 55 ? 1U : 0U);
256✔
1241
  }
256✔
1242
}
2✔
1243

1244
BOOST_AUTO_TEST_CASE(test_ecs_use_requestor)
1245
{
2✔
1246
  std::unique_ptr<SyncRes> sr;
2✔
1247
  initSR(sr);
2✔
1248

1249
  primeHints();
2✔
1250

1251
  const DNSName target("powerdns.com.");
2✔
1252
  SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
2✔
1253
  // No incoming ECS data
1254
  sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
2✔
1255

1256
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
1257
    if (isRootServer(address)) {
4✔
1258
      BOOST_REQUIRE(!srcmask);
2✔
1259

1260
      setLWResult(res, 0, false, false, true);
2✔
1261
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1262
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1263
      return LWResult::Result::Success;
2✔
1264
    }
2✔
1265
    if (address == ComboAddress("192.0.2.1:53")) {
2!
1266

1267
      BOOST_REQUIRE(srcmask);
2✔
1268
      BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
2✔
1269

1270
      setLWResult(res, 0, true, false, false);
2✔
1271
      addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
1272
      return LWResult::Result::Success;
2✔
1273
    }
2✔
1274

1275
    return LWResult::Result::Timeout;
×
1276
  });
2✔
1277

1278
  vector<DNSRecord> ret;
2✔
1279
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1280
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1281
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1282
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1283
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1284
}
2✔
1285

1286
BOOST_AUTO_TEST_CASE(test_ecs_use_scope_zero)
1287
{
2✔
1288
  std::unique_ptr<SyncRes> sr;
2✔
1289
  initSR(sr);
2✔
1290

1291
  primeHints();
2✔
1292

1293
  const DNSName target("powerdns.com.");
2✔
1294
  SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
2✔
1295
  SyncRes::clearEDNSLocalSubnets();
2✔
1296
  SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
2✔
1297
  // No incoming ECS data, Requestor IP not in ecs-add-for
1298
  sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
2✔
1299

1300
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
1301
    if (isRootServer(address)) {
4✔
1302
      BOOST_REQUIRE(!srcmask);
2✔
1303

1304
      setLWResult(res, 0, false, false, true);
2✔
1305
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1306
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1307
      return LWResult::Result::Success;
2✔
1308
    }
2✔
1309
    if (address == ComboAddress("192.0.2.1:53")) {
2!
1310

1311
      BOOST_REQUIRE(srcmask);
2✔
1312
      BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
2✔
1313

1314
      setLWResult(res, 0, true, false, false);
2✔
1315
      addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
1316
      return LWResult::Result::Success;
2✔
1317
    }
2✔
1318

1319
    return LWResult::Result::Timeout;
×
1320
  });
2✔
1321

1322
  vector<DNSRecord> ret;
2✔
1323
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1324
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1325
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1326
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1327
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1328
}
2✔
1329

1330
BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask)
1331
{
2✔
1332
  std::unique_ptr<SyncRes> sr;
2✔
1333
  initSR(sr);
2✔
1334

1335
  primeHints();
2✔
1336

1337
  const DNSName target("powerdns.com.");
2✔
1338
  SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
2✔
1339
  SyncRes::clearEDNSLocalSubnets();
2✔
1340
  SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
2✔
1341
  EDNSSubnetOpts incomingECS;
2✔
1342
  incomingECS.source = Netmask("192.0.0.0/16");
2✔
1343
  sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
2✔
1344

1345
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
1346
    if (isRootServer(address)) {
4✔
1347
      BOOST_REQUIRE(!srcmask);
2✔
1348

1349
      setLWResult(res, 0, false, false, true);
2✔
1350
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1351
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1352
      return LWResult::Result::Success;
2✔
1353
    }
2✔
1354
    if (address == ComboAddress("192.0.2.1:53")) {
2!
1355

1356
      BOOST_REQUIRE(srcmask);
2✔
1357
      BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.0.0/16");
2✔
1358

1359
      setLWResult(res, 0, true, false, false);
2✔
1360
      addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
1361
      return LWResult::Result::Success;
2✔
1362
    }
2✔
1363

1364
    return LWResult::Result::Timeout;
×
1365
  });
2✔
1366

1367
  vector<DNSRecord> ret;
2✔
1368
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1369
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1370
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1371
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1372
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1373
}
2✔
1374

1375
BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask_zero)
1376
{
2✔
1377
  std::unique_ptr<SyncRes> sr;
2✔
1378
  initSR(sr);
2✔
1379

1380
  primeHints();
2✔
1381

1382
  const DNSName target("powerdns.com.");
2✔
1383
  SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
2✔
1384
  SyncRes::clearEDNSLocalSubnets();
2✔
1385
  SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
2✔
1386
  EDNSSubnetOpts incomingECS;
2✔
1387
  incomingECS.source = Netmask("0.0.0.0/0");
2✔
1388
  sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
2✔
1389

1390
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& srcmask, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
1391
    if (isRootServer(address)) {
4✔
1392
      BOOST_REQUIRE(!srcmask);
2✔
1393

1394
      setLWResult(res, 0, false, false, true);
2✔
1395
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1396
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1397
      return LWResult::Result::Success;
2✔
1398
    }
2✔
1399
    if (address == ComboAddress("192.0.2.1:53")) {
2!
1400

1401
      BOOST_REQUIRE(srcmask);
2✔
1402
      BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
2✔
1403

1404
      setLWResult(res, 0, true, false, false);
2✔
1405
      addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
1406
      return LWResult::Result::Success;
2✔
1407
    }
2✔
1408

1409
    return LWResult::Result::Timeout;
×
1410
  });
2✔
1411

1412
  vector<DNSRecord> ret;
2✔
1413
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1414
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1415
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1416
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1417
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1418
}
2✔
1419

1420
BOOST_AUTO_TEST_CASE(test_following_cname)
1421
{
2✔
1422
  std::unique_ptr<SyncRes> sr;
2✔
1423
  initSR(sr);
2✔
1424

1425
  primeHints();
2✔
1426

1427
  const DNSName target("cname.powerdns.com.");
2✔
1428
  const DNSName cnameTarget("cname-target.powerdns.com");
2✔
1429

1430
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
8✔
1431
    if (isRootServer(address)) {
8✔
1432
      setLWResult(res, 0, false, false, true);
4✔
1433
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
4✔
1434
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
1435
      return LWResult::Result::Success;
4✔
1436
    }
4✔
1437
    if (address == ComboAddress("192.0.2.1:53")) {
4!
1438

1439
      if (domain == target) {
4✔
1440
        setLWResult(res, 0, true, false, false);
2✔
1441
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2✔
1442
        return LWResult::Result::Success;
2✔
1443
      }
2✔
1444
      if (domain == cnameTarget) {
2!
1445
        setLWResult(res, 0, true, false, false);
2✔
1446
        addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
1447
      }
2✔
1448

1449
      return LWResult::Result::Success;
2✔
1450
    }
4✔
1451

1452
    return LWResult::Result::Timeout;
×
1453
  });
4✔
1454

1455
  vector<DNSRecord> ret;
2✔
1456
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1457
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1458
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1459
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1460
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1461
  BOOST_CHECK(ret[1].d_type == QType::A);
2✔
1462
  BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
2✔
1463
}
2✔
1464

1465
BOOST_AUTO_TEST_CASE(test_cname_nxdomain)
1466
{
2✔
1467
  std::unique_ptr<SyncRes> sr;
2✔
1468
  initSR(sr);
2✔
1469

1470
  primeHints();
2✔
1471

1472
  const DNSName target("cname.powerdns.com.");
2✔
1473
  const DNSName cnameTarget("cname-target.powerdns.com");
2✔
1474

1475
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
6✔
1476
    if (isRootServer(address)) {
6✔
1477
      setLWResult(res, 0, false, false, true);
2✔
1478
      addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1479
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1480
      return LWResult::Result::Success;
2✔
1481
    }
2✔
1482
    if (address == ComboAddress("192.0.2.1:53")) {
4!
1483

1484
      if (domain == target) {
4✔
1485
        setLWResult(res, RCode::NXDomain, true, false, false);
2✔
1486
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2✔
1487
        addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2✔
1488
      }
2✔
1489
      else if (domain == cnameTarget) {
2!
1490
        setLWResult(res, RCode::NXDomain, true, false, false);
2✔
1491
        addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2✔
1492
        return LWResult::Result::Success;
2✔
1493
      }
2✔
1494

1495
      return LWResult::Result::Success;
2✔
1496
    }
4✔
1497

1498
    return LWResult::Result::Timeout;
×
1499
  });
4✔
1500

1501
  vector<DNSRecord> ret;
2✔
1502
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1503
  BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2✔
1504
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1505
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1506
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1507
  BOOST_CHECK(ret[1].d_type == QType::SOA);
2✔
1508

1509
  /* a second time, to check the cache */
1510
  ret.clear();
2✔
1511
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1512
  BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2✔
1513
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1514
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1515
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1516
  BOOST_CHECK(ret[1].d_type == QType::SOA);
2✔
1517
}
2✔
1518

1519
BOOST_AUTO_TEST_CASE(test_included_poisonous_cname)
1520
{
2✔
1521
  std::unique_ptr<SyncRes> sr;
2✔
1522
  initSR(sr);
2✔
1523

1524
  primeHints();
2✔
1525

1526
  /* In this test we directly get the NS server for cname.powerdns.com.,
1527
     and we don't know whether it's also authoritative for
1528
     cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1529
     the additional A record for cname-target.powerdns.com. */
1530
  const DNSName target("cname.powerdns.com.");
2✔
1531
  const DNSName cnameTarget("cname-target.powerdns.com");
2✔
1532

1533
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
8✔
1534
    if (isRootServer(address)) {
8✔
1535

1536
      setLWResult(res, 0, false, false, true);
4✔
1537

1538
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
4✔
1539
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
1540
      return LWResult::Result::Success;
4✔
1541
    }
4✔
1542
    if (address == ComboAddress("192.0.2.1:53")) {
4!
1543

1544
      if (domain == target) {
4✔
1545
        setLWResult(res, 0, true, false, false);
2✔
1546
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2✔
1547
        addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
2✔
1548
        return LWResult::Result::Success;
2✔
1549
      }
2✔
1550
      if (domain == cnameTarget) {
2!
1551
        setLWResult(res, 0, true, false, false);
2✔
1552
        addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
2✔
1553
        return LWResult::Result::Success;
2✔
1554
      }
2✔
1555

1556
      return LWResult::Result::Success;
×
1557
    }
2✔
1558

1559
    return LWResult::Result::Timeout;
×
1560
  });
4✔
1561

1562
  vector<DNSRecord> ret;
2✔
1563
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1564
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1565
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1566
  BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
2✔
1567
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1568
  BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
2✔
1569
  BOOST_REQUIRE(ret[1].d_type == QType::A);
2✔
1570
  BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
2✔
1571
  BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
2✔
1572
}
2✔
1573

1574
BOOST_AUTO_TEST_CASE(test_cname_loop)
1575
{
2✔
1576
  std::unique_ptr<SyncRes> sr;
2✔
1577
  initSR(sr);
2✔
1578

1579
  primeHints();
2✔
1580

1581
  size_t count = 0;
2✔
1582
  const DNSName target("cname.powerdns.com.");
2✔
1583

1584
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
4✔
1585
    count++;
4✔
1586

1587
    if (isRootServer(address)) {
4✔
1588

1589
      setLWResult(res, 0, false, false, true);
2✔
1590
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1591
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1592
      return LWResult::Result::Success;
2✔
1593
    }
2✔
1594
    if (address == ComboAddress("192.0.2.1:53")) {
2!
1595

1596
      if (domain == target) {
2!
1597
        setLWResult(res, 0, true, false, false);
2✔
1598
        addRecordToLW(res, domain, QType::CNAME, domain.toString());
2✔
1599
        return LWResult::Result::Success;
2✔
1600
      }
2✔
1601

1602
      return LWResult::Result::Success;
×
1603
    }
2✔
1604

1605
    return LWResult::Result::Timeout;
×
1606
  });
2✔
1607

1608
  vector<DNSRecord> ret;
2✔
1609
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1610
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
1611
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
1612
  BOOST_CHECK_EQUAL(count, 2U);
2✔
1613

1614
  // Again to check cache
1615
  try {
2✔
1616
    sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1617
    BOOST_CHECK(false);
2✔
1618
  }
2✔
1619
  catch (const ImmediateServFailException& ex) {
2✔
1620
    BOOST_CHECK(true);
2✔
1621
  }
2✔
1622
}
2✔
1623

1624
BOOST_AUTO_TEST_CASE(test_cname_loop_forwarder)
1625
{
2✔
1626
  std::unique_ptr<SyncRes> resolver;
2✔
1627
  initSR(resolver);
2✔
1628

1629
  primeHints();
2✔
1630

1631
  size_t count = 0;
2✔
1632
  const DNSName target("cname.powerdns.com.");
2✔
1633
  const DNSName cname1("cname1.cname.powerdns.com.");
2✔
1634
  const DNSName cname2("cname2.cname.powerdns.com.");
2✔
1635

1636
  SyncRes::AuthDomain ad;
2✔
1637
  const std::vector<ComboAddress> forwardedNSs{ComboAddress("192.0.2.42:53")};
2✔
1638
  ad.d_rdForward = true;
2✔
1639
  ad.d_servers = forwardedNSs;
2✔
1640
  (*SyncRes::t_sstorage.domainmap)[target] = ad;
2✔
1641

1642
  resolver->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
2✔
1643
    count++;
2✔
1644

1645
    if (isRootServer(address)) {
2!
1646

1647
      setLWResult(res, 0, false, false, true);
×
1648
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
×
1649
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1650
      return LWResult::Result::Success;
×
1651
    }
×
1652
    if (address == ComboAddress("192.0.2.42:53")) {
2!
1653

1654
      if (domain == target) {
2!
1655
        setLWResult(res, 0, true, false, false);
2✔
1656
        addRecordToLW(res, domain, QType::CNAME, cname1.toString());
2✔
1657
        addRecordToLW(res, cname1, QType::CNAME, cname2.toString());
2✔
1658
        addRecordToLW(res, cname2, QType::CNAME, domain.toString());
2✔
1659
        return LWResult::Result::Success;
2✔
1660
      }
2✔
1661

1662
      return LWResult::Result::Success;
×
1663
    }
2✔
1664

1665
    return LWResult::Result::Timeout;
×
1666
  });
2✔
1667

1668
  vector<DNSRecord> ret;
2✔
1669
  BOOST_REQUIRE_THROW(resolver->beginResolve(target, QType(QType::A), QClass::IN, ret), ImmediateServFailException);
2✔
1670
}
2✔
1671

1672
BOOST_AUTO_TEST_CASE(test_cname_long_loop)
1673
{
2✔
1674
  std::unique_ptr<SyncRes> sr;
2✔
1675
  initSR(sr);
2✔
1676

1677
  primeHints();
2✔
1678

1679
  size_t count = 0;
2✔
1680
  const DNSName target1("cname1.powerdns.com.");
2✔
1681
  const DNSName target2("cname2.powerdns.com.");
2✔
1682
  const DNSName target3("cname3.powerdns.com.");
2✔
1683
  const DNSName target4("cname4.powerdns.com.");
2✔
1684

1685
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
16✔
1686
    count++;
16✔
1687

1688
    if (isRootServer(address)) {
16✔
1689

1690
      setLWResult(res, 0, false, false, true);
8✔
1691
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
8✔
1692
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8✔
1693
      return LWResult::Result::Success;
8✔
1694
    }
8✔
1695
    if (address == ComboAddress("192.0.2.1:53")) {
8!
1696

1697
      if (domain == target1) {
8✔
1698
        setLWResult(res, 0, true, false, false);
2✔
1699
        addRecordToLW(res, domain, QType::CNAME, target2.toString());
2✔
1700
        return LWResult::Result::Success;
2✔
1701
      }
2✔
1702
      if (domain == target2) {
6✔
1703
        setLWResult(res, 0, true, false, false);
2✔
1704
        addRecordToLW(res, domain, QType::CNAME, target3.toString());
2✔
1705
        return LWResult::Result::Success;
2✔
1706
      }
2✔
1707
      if (domain == target3) {
4✔
1708
        setLWResult(res, 0, true, false, false);
2✔
1709
        addRecordToLW(res, domain, QType::CNAME, target4.toString());
2✔
1710
        return LWResult::Result::Success;
2✔
1711
      }
2✔
1712
      if (domain == target4) {
2!
1713
        setLWResult(res, 0, true, false, false);
2✔
1714
        addRecordToLW(res, domain, QType::CNAME, target1.toString());
2✔
1715
        return LWResult::Result::Success;
2✔
1716
      }
2✔
1717

1718
      return LWResult::Result::Success;
×
1719
    }
2✔
1720

1721
    return LWResult::Result::Timeout;
×
1722
  });
8✔
1723

1724
  vector<DNSRecord> ret;
2✔
1725
  int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
2✔
1726
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
1727
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
1728
  BOOST_CHECK_EQUAL(count, 8U);
2✔
1729

1730
  // And again to check cache
1731
  try {
2✔
1732
    sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
2✔
1733
    BOOST_CHECK(false);
2✔
1734
  }
2✔
1735
  catch (const ImmediateServFailException& ex) {
2✔
1736
    BOOST_CHECK(true);
2✔
1737
  }
2✔
1738
}
2✔
1739

1740
BOOST_AUTO_TEST_CASE(test_cname_length)
1741
{
2✔
1742
  std::unique_ptr<SyncRes> sr;
2✔
1743
  initSR(sr);
2✔
1744

1745
  primeHints();
2✔
1746

1747
  size_t length = 0;
2✔
1748
  const DNSName target("cname.powerdns.com.");
2✔
1749

1750
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
44✔
1751
    if (isRootServer(address)) {
44✔
1752

1753
      setLWResult(res, 0, false, false, true);
22✔
1754
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
22✔
1755
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
22✔
1756
      return LWResult::Result::Success;
22✔
1757
    }
22✔
1758
    if (address == ComboAddress("192.0.2.1:53")) {
22!
1759

1760
      setLWResult(res, 0, true, false, false);
22✔
1761
      addRecordToLW(res, domain, QType::CNAME, std::to_string(length) + "-cname.powerdns.com");
22✔
1762
      length++;
22✔
1763
      return LWResult::Result::Success;
22✔
1764
    }
22✔
1765

1766
    return LWResult::Result::Timeout;
×
1767
  });
22✔
1768

1769
  vector<DNSRecord> ret;
2✔
1770
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1771
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
1772
  BOOST_CHECK_EQUAL(ret.size(), length);
2✔
1773
  BOOST_CHECK_EQUAL(length, SyncRes::s_max_CNAMES_followed + 1);
2✔
1774

1775
  // The CNAME bounds check originating from the record cache causes an ImmediateServFail
1776
  // exception. This is different from the non-cached case, tested above.
1777
  ret.clear();
2✔
1778
  BOOST_CHECK_EXCEPTION(sr->beginResolve(target, QType(QType::A), QClass::IN, ret),
2✔
1779
                        ImmediateServFailException,
2✔
1780
                        [&](const ImmediateServFailException& isfe) {
2✔
1781
                          return isfe.reason == "max number of CNAMEs exceeded";
2✔
1782
                        });
2✔
1783
  BOOST_CHECK_EQUAL(ret.size(), SyncRes::s_max_CNAMES_followed + 1);
2✔
1784

1785
  // Again, now with QName Minimization on, originally this would fail as the result was collected
1786
  // in a temp vector and the throw would skip the copy of the temp vector into the end result
1787
  sr->setQNameMinimization();
2✔
1788
  ret.clear();
2✔
1789
  BOOST_CHECK_EXCEPTION(sr->beginResolve(target, QType(QType::A), QClass::IN, ret),
2✔
1790
                        ImmediateServFailException,
2✔
1791
                        [&](const ImmediateServFailException& isfe) {
2✔
1792
                          return isfe.reason == "max number of CNAMEs exceeded";
2✔
1793
                        });
2✔
1794
  BOOST_CHECK_EQUAL(ret.size(), SyncRes::s_max_CNAMES_followed + 1);
2✔
1795
}
2✔
1796

1797
BOOST_AUTO_TEST_CASE(test_cname_target_servfail)
1798
{
2✔
1799
  std::unique_ptr<SyncRes> resolver;
2✔
1800
  initSR(resolver);
2✔
1801

1802
  primeHints();
2✔
1803

1804
  const DNSName target("cname.powerdns.com.");
2✔
1805
  const DNSName cnameTarget("cname-target.powerdns.com");
2✔
1806

1807
  resolver->setAsyncCallback([&](const ComboAddress& ipAddress, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
8✔
1808
    if (isRootServer(ipAddress)) {
8✔
1809
      setLWResult(res, 0, false, false, true);
4✔
1810
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
4✔
1811
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
1812
      return LWResult::Result::Success;
4✔
1813
    }
4✔
1814
    if (ipAddress == ComboAddress("192.0.2.1:53")) {
4!
1815

1816
      if (domain == target) {
4✔
1817
        setLWResult(res, 0, true, false, false);
2✔
1818
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2✔
1819
        return LWResult::Result::Success;
2✔
1820
      }
2✔
1821
      if (domain == cnameTarget) {
2!
1822
        return LWResult::Result::PermanentError;
2✔
1823
      }
2✔
1824

1825
      return LWResult::Result::Success;
×
1826
    }
2✔
1827

1828
    return LWResult::Result::Timeout;
×
1829
  });
4✔
1830

1831
  vector<DNSRecord> ret;
2✔
1832
  int res = resolver->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1833
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
1834
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1835
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1836
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1837
}
2✔
1838

1839
BOOST_AUTO_TEST_CASE(test_cname_target_servfail_servestale)
1840
{
2✔
1841
  std::unique_ptr<SyncRes> resolver;
2✔
1842
  initSR(resolver);
2✔
1843
  MemRecursorCache::s_maxServedStaleExtensions = 1440;
2✔
1844

1845
  primeHints();
2✔
1846

1847
  const DNSName target("cname.powerdns.com.");
2✔
1848
  const DNSName cnameTarget("cname-target.powerdns.com");
2✔
1849

1850
  resolver->setAsyncCallback([&](const ComboAddress& ipAddress, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
8✔
1851
    if (isRootServer(ipAddress)) {
8✔
1852
      setLWResult(res, 0, false, false, true);
4✔
1853
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
4✔
1854
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
1855
      return LWResult::Result::Success;
4✔
1856
    }
4✔
1857
    if (ipAddress == ComboAddress("192.0.2.1:53")) {
4!
1858

1859
      if (domain == target) {
4✔
1860
        setLWResult(res, 0, true, false, false);
2✔
1861
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2✔
1862
        return LWResult::Result::Success;
2✔
1863
      }
2✔
1864
      if (domain == cnameTarget) {
2!
1865
        return LWResult::Result::PermanentError;
2✔
1866
      }
2✔
1867

1868
      return LWResult::Result::Success;
×
1869
    }
2✔
1870

1871
    return LWResult::Result::Timeout;
×
1872
  });
4✔
1873

1874
  vector<DNSRecord> ret;
2✔
1875
  int res = resolver->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1876
  // different compared no non-servestale case (returns ServFail), handled by pdns_recursor
1877
  BOOST_CHECK_EQUAL(res, -1);
2✔
1878
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1879
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1880
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1881
}
2✔
1882

1883
BOOST_AUTO_TEST_CASE(test_time_limit)
1884
{
2✔
1885
  std::unique_ptr<SyncRes> sr;
2✔
1886
  initSR(sr);
2✔
1887

1888
  primeHints();
2✔
1889

1890
  size_t queries = 0;
2✔
1891
  const DNSName target("cname.powerdns.com.");
2✔
1892

1893
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
2✔
1894
    queries++;
2✔
1895

1896
    if (isRootServer(address)) {
2!
1897
      setLWResult(res, 0, false, false, true);
2✔
1898
      /* Pretend that this query took 2000 ms */
1899
      res->d_usec = 2000;
2✔
1900

1901
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1902
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1903
      return LWResult::Result::Success;
2✔
1904
    }
2✔
1905
    if (address == ComboAddress("192.0.2.1:53")) {
×
1906

1907
      setLWResult(res, 0, true, false, false);
×
1908
      addRecordToLW(res, domain, QType::A, "192.0.2.2");
×
1909
      return LWResult::Result::Success;
×
1910
    }
×
1911

1912
    return LWResult::Result::Timeout;
×
1913
  });
×
1914

1915
  /* Set the maximum time to 1 ms */
1916
  SyncRes::s_maxtotusec = 1000;
2✔
1917

1918
  try {
2✔
1919
    vector<DNSRecord> ret;
2✔
1920
    sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1921
    BOOST_CHECK(false);
2✔
1922
  }
2✔
1923
  catch (const ImmediateServFailException& e) {
2✔
1924
  }
2✔
1925
  BOOST_CHECK_EQUAL(queries, 1U);
2✔
1926
}
2✔
1927

1928
BOOST_AUTO_TEST_CASE(test_dname_processing)
1929
{
2✔
1930
  std::unique_ptr<SyncRes> sr;
2✔
1931
  initSR(sr);
2✔
1932

1933
  primeHints();
2✔
1934

1935
  const DNSName dnameOwner("powerdns.com");
2✔
1936
  const DNSName dnameTarget("powerdns.net");
2✔
1937

1938
  const DNSName target("dname.powerdns.com.");
2✔
1939
  const DNSName cnameTarget("dname.powerdns.net");
2✔
1940

1941
  const DNSName uncachedTarget("dname-uncached.powerdns.com.");
2✔
1942
  const DNSName uncachedCNAMETarget("dname-uncached.powerdns.net.");
2✔
1943

1944
  const DNSName synthCNAME("cname-uncached.powerdns.com.");
2✔
1945
  const DNSName synthCNAMETarget("cname-uncached.powerdns.net.");
2✔
1946

1947
  size_t queries = 0;
2✔
1948

1949
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
10✔
1950
    queries++;
10✔
1951

1952
    if (isRootServer(address)) {
10✔
1953
      if (domain.isPartOf(dnameOwner)) {
4✔
1954
        setLWResult(res, 0, false, false, true);
2✔
1955
        addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1956
        addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1957
        return LWResult::Result::Success;
2✔
1958
      }
2✔
1959
      if (domain.isPartOf(dnameTarget)) {
2!
1960
        setLWResult(res, 0, false, false, true);
2✔
1961
        addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1962
        addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1963
        return LWResult::Result::Success;
2✔
1964
      }
2✔
1965
    }
2✔
1966
    else if (address == ComboAddress("192.0.2.1:53")) {
6✔
1967
      if (domain == target) {
2!
1968
        setLWResult(res, 0, true, false, false);
2✔
1969
        addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
1970
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2✔
1971
        return LWResult::Result::Success;
2✔
1972
      }
2✔
1973
    }
2✔
1974
    else if (address == ComboAddress("192.0.2.2:53")) {
4!
1975
      if (domain == cnameTarget) {
4✔
1976
        setLWResult(res, 0, true, false, false);
2✔
1977
        addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
1978
      }
2✔
1979
      if (domain == uncachedCNAMETarget) {
4✔
1980
        setLWResult(res, 0, true, false, false);
2✔
1981
        addRecordToLW(res, domain, QType::A, "192.0.2.3");
2✔
1982
      }
2✔
1983
      return LWResult::Result::Success;
4✔
1984
    }
4✔
1985
    return LWResult::Result::Timeout;
×
1986
  });
10✔
1987

1988
  vector<DNSRecord> ret;
2✔
1989
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1990

1991
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1992
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
1993

1994
  BOOST_CHECK_EQUAL(queries, 4u);
2✔
1995

1996
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
1997
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
1998
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
1999

2000
  BOOST_CHECK(ret[1].d_type == QType::CNAME);
2✔
2001
  BOOST_CHECK_EQUAL(ret[1].d_name, target);
2✔
2002

2003
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2004
  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2✔
2005

2006
  // Now check the cache
2007
  ret.clear();
2✔
2008
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2009

2010
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2011
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
2012

2013
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2014

2015
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2016
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2017
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2018

2019
  BOOST_CHECK(ret[1].d_type == QType::CNAME);
2✔
2020
  BOOST_CHECK_EQUAL(ret[1].d_name, target);
2✔
2021

2022
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2023
  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2✔
2024

2025
  // Check if we correctly return a synthesized CNAME, should send out just 1 more query
2026
  ret.clear();
2✔
2027
  res = sr->beginResolve(uncachedTarget, QType(QType::A), QClass::IN, ret);
2✔
2028

2029
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2030
  BOOST_CHECK_EQUAL(queries, 5U);
2✔
2031

2032
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2033
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2034
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2035

2036
  BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
2✔
2037
  BOOST_CHECK_EQUAL(ret[1].d_name, uncachedTarget);
2✔
2038
  BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), uncachedCNAMETarget);
2✔
2039

2040
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2041
  BOOST_CHECK_EQUAL(ret[2].d_name, uncachedCNAMETarget);
2✔
2042

2043
  // Check if we correctly return the DNAME from cache when asked
2044
  ret.clear();
2✔
2045
  res = sr->beginResolve(dnameOwner, QType(QType::DNAME), QClass::IN, ret);
2✔
2046
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2047
  BOOST_CHECK_EQUAL(queries, 5U);
2✔
2048

2049
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2050
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2051
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2052

2053
  // Check if we correctly return the synthesized CNAME from cache when asked
2054
  ret.clear();
2✔
2055
  res = sr->beginResolve(synthCNAME, QType(QType::CNAME), QClass::IN, ret);
2✔
2056
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2057
  BOOST_CHECK_EQUAL(queries, 5U);
2✔
2058

2059
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2060
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2061
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2062

2063
  BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
2✔
2064
  BOOST_CHECK(ret[1].d_name == synthCNAME);
2✔
2065
  BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), synthCNAMETarget);
2✔
2066
}
2✔
2067

2068
BOOST_AUTO_TEST_CASE(test_dname_dnssec_secure)
2069
{
2✔
2070
  std::unique_ptr<SyncRes> sr;
2✔
2071
  initSR(sr, true);
2✔
2072
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
2073

2074
  primeHints();
2✔
2075

2076
  const DNSName dnameOwner("powerdns");
2✔
2077
  const DNSName dnameTarget("example");
2✔
2078

2079
  const DNSName target("dname.powerdns");
2✔
2080
  const DNSName cnameTarget("dname.example");
2✔
2081

2082
  testkeysset_t keys;
2✔
2083

2084
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
2085
  luaconfsCopy.dsAnchors.clear();
2✔
2086
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
2087
  generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
2088
  generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
2089
  g_luaconfs.setState(luaconfsCopy);
2✔
2090

2091
  size_t queries = 0;
2✔
2092

2093
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
14✔
2094
    queries++;
14✔
2095
    /* We don't use the genericDSAndDNSKEYHandler here, as it would deny names existing at the wrong level of the tree, due to the way computeZoneCuts works
2096
     * As such, we need to do some more work to make the answers correct.
2097
     */
2098

2099
    if (isRootServer(address)) {
14✔
2100
      if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
6!
2101
        setLWResult(res, 0, true, false, true);
2✔
2102
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2103
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2104
        return LWResult::Result::Success;
2✔
2105
      }
2✔
2106
      if (domain.countLabels() == 1 && type == QType::DS) { // powerdns|DS or example|DS
4!
2107
        setLWResult(res, 0, true, false, true);
×
2108
        addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
×
2109
        addRRSIG(keys, res->d_records, DNSName("."), 300);
×
2110
        return LWResult::Result::Success;
×
2111
      }
×
2112
      // For the rest, delegate!
2113
      if (domain.isPartOf(dnameOwner)) {
4✔
2114
        setLWResult(res, 0, false, false, true);
2✔
2115
        addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2116
        addDS(dnameOwner, 300, res->d_records, keys);
2✔
2117
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2118
        addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2119
        return LWResult::Result::Success;
2✔
2120
      }
2✔
2121
      if (domain.isPartOf(dnameTarget)) {
2!
2122
        setLWResult(res, 0, false, false, true);
2✔
2123
        addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2124
        addDS(dnameTarget, 300, res->d_records, keys);
2✔
2125
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2126
        addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2127
        return LWResult::Result::Success;
2✔
2128
      }
2✔
2129
    }
2✔
2130
    else if (address == ComboAddress("192.0.2.1:53")) {
8✔
2131
      if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
4!
2132
        setLWResult(res, 0, true, false, true);
2✔
2133
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2134
        addRRSIG(keys, res->d_records, domain, 300);
2✔
2135
        return LWResult::Result::Success;
2✔
2136
      }
2✔
2137
      if (domain == target && type == QType::DS) { // dname.powerdns|DS
2!
2138
        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
×
2139
      }
×
2140
      if (domain == target) {
2!
2141
        setLWResult(res, 0, true, false, false);
2✔
2142
        addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
2143
        addRRSIG(keys, res->d_records, dnameOwner, 300);
2✔
2144
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2✔
2145
        return LWResult::Result::Success;
2✔
2146
      }
2✔
2147
    }
2✔
2148
    else if (address == ComboAddress("192.0.2.2:53")) {
4!
2149
      if (domain.countLabels() == 1 && type == QType::DNSKEY) { // example|DNSKEY
4!
2150
        setLWResult(res, 0, true, false, true);
2✔
2151
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2152
        addRRSIG(keys, res->d_records, domain, 300);
2✔
2153
        return LWResult::Result::Success;
2✔
2154
      }
2✔
2155
      if (domain == cnameTarget && type == QType::DS) { // dname.example|DS
2!
2156
        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
×
2157
      }
×
2158
      if (domain == cnameTarget) {
2!
2159
        setLWResult(res, 0, true, false, false);
2✔
2160
        addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
2161
        addRRSIG(keys, res->d_records, dnameTarget, 300);
2✔
2162
      }
2✔
2163
      return LWResult::Result::Success;
2✔
2164
    }
2✔
2165
    return LWResult::Result::Timeout;
×
2166
  });
14✔
2167

2168
  vector<DNSRecord> ret;
2✔
2169
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2170

2171
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2172
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
2173
  BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2✔
2174

2175
  BOOST_CHECK_EQUAL(queries, 7U);
2✔
2176

2177
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2178
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2179
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2180

2181
  BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
2✔
2182
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2183

2184
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2185
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2186

2187
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2188
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2189

2190
  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2✔
2191
  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2✔
2192

2193
  // And the cache
2194
  ret.clear();
2✔
2195
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2196

2197
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2198
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
2199
  BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2✔
2200

2201
  BOOST_CHECK_EQUAL(queries, 7U);
2✔
2202

2203
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2204
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2205
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2206

2207
  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2✔
2208
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2209

2210
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2211
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2212

2213
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2214
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2215

2216
  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2✔
2217
  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2✔
2218
}
2✔
2219

2220
BOOST_AUTO_TEST_CASE(test_dname_plus_ns_dnssec_secure)
2221
{
2✔
2222
  std::unique_ptr<SyncRes> sr;
2✔
2223
  initSR(sr, true);
2✔
2224
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
2225

2226
  primeHints();
2✔
2227

2228
  const DNSName dnameOwner("powerdns");
2✔
2229
  const DNSName dnameTarget("example");
2✔
2230

2231
  const DNSName target("dname.powerdns");
2✔
2232
  const DNSName cnameTarget("dname.example");
2✔
2233

2234
  testkeysset_t keys;
2✔
2235

2236
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
2237
  luaconfsCopy.dsAnchors.clear();
2✔
2238
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
2239
  generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
2240
  g_luaconfs.setState(luaconfsCopy);
2✔
2241

2242
  size_t queries = 0;
2✔
2243

2244
  sr->setAsyncCallback([&](const ComboAddress& /* ip */, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
8✔
2245
    queries++;
8✔
2246

2247
    if (type == QType::DS || type == QType::DNSKEY) {
8!
2248
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
4✔
2249
    }
4✔
2250

2251
    if (domain.isPartOf(dnameOwner)) {
4✔
2252
      setLWResult(res, 0, true, false, true);
2✔
2253
      addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
2254
      addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2255
      addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2✔
2256

2257
      addRecordToLW(res, dnameTarget, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2258
      addDS(dnameTarget, 300, res->d_records, keys);
2✔
2259
      addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2260
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2261
      return LWResult::Result::Success;
2✔
2262
    }
2✔
2263
    if (domain == cnameTarget) {
2!
2264
      setLWResult(res, 0, true, false, true);
2✔
2265
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
2266
      addRRSIG(keys, res->d_records, dnameTarget, 300);
2✔
2267
      return LWResult::Result::Success;
2✔
2268
    }
2✔
2269
    return LWResult::Result::Timeout;
×
2270
  });
2✔
2271

2272
  vector<DNSRecord> ret;
2✔
2273
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2274

2275
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2276
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
2277
  BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2✔
2278

2279
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2280

2281
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2282
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2283
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2284

2285
  BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
2✔
2286
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2287

2288
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2289
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2290

2291
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2292
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2293

2294
  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2✔
2295
  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2✔
2296

2297
  // And the cache
2298
  ret.clear();
2✔
2299
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2300

2301
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2302
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
2303
  BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2✔
2304

2305
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2306

2307
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2308
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2309
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2310

2311
  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2✔
2312
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2313

2314
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2315
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2316

2317
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2318
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2319

2320
  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2✔
2321
  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2✔
2322
}
2✔
2323

2324
BOOST_AUTO_TEST_CASE(test_dname_dnssec_insecure)
2325
{
2✔
2326
  /*
2327
   * The DNAME itself is signed, but the final A record is not
2328
   */
2329
  std::unique_ptr<SyncRes> sr;
2✔
2330
  initSR(sr, true);
2✔
2331
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
2332

2333
  primeHints();
2✔
2334

2335
  const DNSName dnameOwner("powerdns");
2✔
2336
  const DNSName dnameTarget("example");
2✔
2337

2338
  const DNSName target("dname.powerdns");
2✔
2339
  const DNSName cnameTarget("dname.example");
2✔
2340

2341
  testkeysset_t keys;
2✔
2342

2343
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
2344
  luaconfsCopy.dsAnchors.clear();
2✔
2345
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
2346
  generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
2347
  g_luaconfs.setState(luaconfsCopy);
2✔
2348

2349
  size_t queries = 0;
2✔
2350

2351
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
14✔
2352
    queries++;
14✔
2353

2354
    if (isRootServer(address)) {
14✔
2355
      if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
8!
2356
        setLWResult(res, 0, true, false, true);
2✔
2357
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2358
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2359
        return LWResult::Result::Success;
2✔
2360
      }
2✔
2361
      if (domain == dnameOwner && type == QType::DS) { // powerdns|DS
6!
2362
        setLWResult(res, 0, true, false, true);
×
2363
        addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
×
2364
        addRRSIG(keys, res->d_records, DNSName("."), 300);
×
2365
        return LWResult::Result::Success;
×
2366
      }
×
2367
      if (domain == dnameTarget && type == QType::DS) { // example|DS
6!
2368
        return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
2✔
2369
      }
2✔
2370
      // For the rest, delegate!
2371
      if (domain.isPartOf(dnameOwner)) {
4✔
2372
        setLWResult(res, 0, false, false, true);
2✔
2373
        addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2374
        addDS(dnameOwner, 300, res->d_records, keys);
2✔
2375
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2376
        addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2377
        return LWResult::Result::Success;
2✔
2378
      }
2✔
2379
      if (domain.isPartOf(dnameTarget)) {
2!
2380
        setLWResult(res, 0, false, false, true);
2✔
2381
        addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2382
        addDS(dnameTarget, 300, res->d_records, keys);
2✔
2383
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2384
        addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2385
        return LWResult::Result::Success;
2✔
2386
      }
2✔
2387
    }
2✔
2388
    else if (address == ComboAddress("192.0.2.1:53")) {
6✔
2389
      if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
4!
2390
        setLWResult(res, 0, true, false, true);
2✔
2391
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2392
        addRRSIG(keys, res->d_records, domain, 300);
2✔
2393
        return LWResult::Result::Success;
2✔
2394
      }
2✔
2395
      if (domain == target && type == QType::DS) { // dname.powerdns|DS
2!
2396
        return genericDSAndDNSKEYHandler(res, domain, dnameOwner, type, keys, false);
×
2397
      }
×
2398
      if (domain == target) {
2!
2399
        setLWResult(res, 0, true, false, false);
2✔
2400
        addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
2401
        addRRSIG(keys, res->d_records, dnameOwner, 300);
2✔
2402
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2✔
2403
        return LWResult::Result::Success;
2✔
2404
      }
2✔
2405
    }
2✔
2406
    else if (address == ComboAddress("192.0.2.2:53")) {
2!
2407
      if (domain == target && type == QType::DS) { // dname.example|DS
2!
2408
        return genericDSAndDNSKEYHandler(res, domain, dnameTarget, type, keys, false);
×
2409
      }
×
2410
      if (domain == cnameTarget) {
2!
2411
        setLWResult(res, 0, true, false, false);
2✔
2412
        addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
2413
      }
2✔
2414
      return LWResult::Result::Success;
2✔
2415
    }
2✔
2416
    return LWResult::Result::Timeout;
×
2417
  });
14✔
2418

2419
  vector<DNSRecord> ret;
2✔
2420
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2421

2422
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2423
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
2424
  BOOST_REQUIRE_EQUAL(ret.size(), 4U); /* DNAME + RRSIG(DNAME) + CNAME + A */
2✔
2425

2426
  BOOST_CHECK_EQUAL(queries, 7U);
2✔
2427

2428
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2429
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2430
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2431

2432
  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2✔
2433
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2434

2435
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2436
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2437

2438
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2439
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2440

2441
  // And the cache
2442
  ret.clear();
2✔
2443
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2444

2445
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2446
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
2447
  BOOST_REQUIRE_EQUAL(ret.size(), 4U); /* DNAME + RRSIG(DNAME) + CNAME + A */
2✔
2448

2449
  BOOST_CHECK_EQUAL(queries, 7U);
2✔
2450

2451
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2452
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2453
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2454

2455
  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2✔
2456
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2457

2458
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2459
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2460

2461
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2462
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2463
}
2✔
2464

2465
BOOST_AUTO_TEST_CASE(test_dname_processing_no_CNAME)
2466
{
2✔
2467
  std::unique_ptr<SyncRes> sr;
2✔
2468
  initSR(sr);
2✔
2469

2470
  primeHints();
2✔
2471

2472
  const DNSName dnameOwner("powerdns.com");
2✔
2473
  const DNSName dnameTarget("powerdns.net");
2✔
2474

2475
  const DNSName target("dname.powerdns.com.");
2✔
2476
  const DNSName cnameTarget("dname.powerdns.net");
2✔
2477

2478
  size_t queries = 0;
2✔
2479

2480
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
8✔
2481
    queries++;
8✔
2482

2483
    if (isRootServer(address)) {
8✔
2484
      if (domain.isPartOf(dnameOwner)) {
4✔
2485
        setLWResult(res, 0, false, false, true);
2✔
2486
        addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2487
        addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2488
        return LWResult::Result::Success;
2✔
2489
      }
2✔
2490
      if (domain.isPartOf(dnameTarget)) {
2!
2491
        setLWResult(res, 0, false, false, true);
2✔
2492
        addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2493
        addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2494
        return LWResult::Result::Success;
2✔
2495
      }
2✔
2496
    }
2✔
2497
    else if (address == ComboAddress("192.0.2.1:53")) {
4✔
2498
      if (domain == target) {
2!
2499
        setLWResult(res, 0, true, false, false);
2✔
2500
        addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
2501
        // No CNAME, recursor should synth
2502
        return LWResult::Result::Success;
2✔
2503
      }
2✔
2504
    }
2✔
2505
    else if (address == ComboAddress("192.0.2.2:53")) {
2!
2506
      if (domain == cnameTarget) {
2!
2507
        setLWResult(res, 0, true, false, false);
2✔
2508
        addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
2509
      }
2✔
2510
      return LWResult::Result::Success;
2✔
2511
    }
2✔
2512
    return LWResult::Result::Timeout;
×
2513
  });
8✔
2514

2515
  vector<DNSRecord> ret;
2✔
2516
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2517

2518
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2519
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
2520

2521
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2522

2523
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2524
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2525
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2526

2527
  BOOST_CHECK(ret[1].d_type == QType::CNAME);
2✔
2528
  BOOST_CHECK_EQUAL(ret[1].d_name, target);
2✔
2529

2530
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2531
  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2✔
2532

2533
  // Now check the cache
2534
  ret.clear();
2✔
2535
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2536

2537
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2538
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
2539

2540
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2541

2542
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2543
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2544
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2545

2546
  BOOST_CHECK(ret[1].d_type == QType::CNAME);
2✔
2547
  BOOST_CHECK_EQUAL(ret[1].d_name, target);
2✔
2548

2549
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2550
  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2✔
2551
}
2✔
2552

2553
/*
2554
// cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2555

2556
- check out of band support
2557

2558
- check preoutquery
2559

2560
*/
2561

2562
BOOST_AUTO_TEST_CASE(test_glued_referral_child_ns_set_wrong)
2563
{
2✔
2564
  std::unique_ptr<SyncRes> sr;
2✔
2565
  initSR(sr);
2✔
2566

2567
  primeHints();
2✔
2568

2569
  const DNSName target("powerdns.com.");
2✔
2570

2571
  sr->setAsyncCallback([&](const ComboAddress& address, const DNSName& domain, int type, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */, struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */, LWResult* res, bool* /* chained */) {
26✔
2572
    /* this will cause issue with qname minimization if we ever implement it */
2573
    if (domain != target) {
26!
2574
      return LWResult::Result::Timeout;
×
2575
    }
×
2576

2577
    if (isRootServer(address)) {
26✔
2578
      setLWResult(res, 0, false, false, true);
2✔
2579
      addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2580
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2581
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2582
      return LWResult::Result::Success;
2✔
2583
    }
2✔
2584
    if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
24✔
2585
      setLWResult(res, 0, false, false, true);
2✔
2586
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2587
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2588
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2589
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2590
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2591
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2592
      return LWResult::Result::Success;
2✔
2593
    }
2✔
2594
    if (address == ComboAddress("192.0.2.2:53") || address == ComboAddress("192.0.2.3:53") || address == ComboAddress("[2001:DB8::2]:53") || address == ComboAddress("[2001:DB8::3]:53")) {
22!
2595

2596
      if (type == QType::A) {
6✔
2597
        setLWResult(res, 0, true, false, true);
4✔
2598
        addRecordToLW(res, target, QType::A, "192.0.2.4");
4✔
2599
        return LWResult::Result::Success;
4✔
2600
      }
4✔
2601
      if (type == QType::NS) {
2!
2602
        setLWResult(res, 0, true, false, true);
2✔
2603
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-nsX1.powerdns.com.", DNSResourceRecord::ANSWER, 172800);
2✔
2604
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-nsX2.powerdns.com.", DNSResourceRecord::ANSWER, 172800);
2✔
2605
        addRecordToLW(res, "pdns-public-nsX1.powerdns.com.", QType::A, "192.0.2.11", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2606
        addRecordToLW(res, "pdns-public-nsX1.powerdns.com.", QType::AAAA, "2001:DB8::11", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2607
        addRecordToLW(res, "pdns-public-nsX2.powerdns.com.", QType::A, "192.0.2.12", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2608
        addRecordToLW(res, "pdns-public-nsX2.powerdns.com.", QType::AAAA, "2001:DB8::12", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2609
        return LWResult::Result::Success;
2✔
2610
      }
2✔
2611
      return LWResult::Result::Timeout;
×
2612
    }
2✔
2613
    return LWResult::Result::Timeout;
16✔
2614
  });
22✔
2615

2616
  vector<DNSRecord> ret;
2✔
2617
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2618
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2619
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
2620
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
2621
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
2622

2623
  // Now resolve NS to get auth NS set in cache and save the parent NS set
2624
  ret.clear();
2✔
2625
  res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
2✔
2626
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2627
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
2628
  BOOST_CHECK(ret[0].d_type == QType::NS);
2✔
2629
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
2630
  BOOST_CHECK_EQUAL(SyncRes::getSaveParentsNSSetsSize(), 1U);
2✔
2631

2632
  g_recCache->doWipeCache(target, false, QType::A);
2✔
2633
  SyncRes::s_save_parent_ns_set = false;
2✔
2634

2635
  // Try to resolve now via the broken child NS set... should not work
2636
  ret.clear();
2✔
2637
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2638
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
2639
  BOOST_REQUIRE_EQUAL(ret.size(), 0U);
2✔
2640

2641
  SyncRes::s_save_parent_ns_set = true;
2✔
2642

2643
  // Try to resolve now via the broken child... should work now via fallback to parent NS set
2644
  ret.clear();
2✔
2645
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2646
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2647
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
2648
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
2649
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
2650
}
2✔
2651

2652
BOOST_AUTO_TEST_SUITE_END()
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