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

PowerDNS / pdns / 12595591960

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

Pull #15008

github

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

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

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

89.68
/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 */) {
11✔
784
    if (isRootServer(address)) {
11✔
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")) {
7✔
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;
3✔
821
  });
7✔
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);
2✔
969
        addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
2✔
970
        addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
2✔
971
        return LWResult::Result::Success;
2✔
972
      }
2✔
973
      if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
×
974
        setLWResult(res, 0, true, false, true);
×
975
        addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
×
976
        addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
×
977
        return LWResult::Result::Success;
×
978
      }
×
979

980
      setLWResult(res, RCode::NXDomain, false, false, true);
×
981
      return LWResult::Result::Success;
×
982
    }
×
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 */) {
50✔
1010
    if (isRootServer(address)) {
50✔
1011
      setLWResult(res, 0, false, false, true);
11✔
1012

1013
      if (domain.isPartOf(DNSName("com."))) {
11✔
1014
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1015
      }
2✔
1016
      else if (domain.isPartOf(DNSName("org."))) {
9!
1017
        addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
9✔
1018
      }
9✔
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);
11✔
1025
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
11✔
1026
      return LWResult::Result::Success;
11✔
1027
    }
11✔
1028
    if (domain == target) {
39✔
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);
37✔
1035
    addRecordToLW(res, domain, QType::NS, std::to_string(count) + ".ns1.powerdns.org", DNSResourceRecord::AUTHORITY, 172800);
37✔
1036
    addRecordToLW(res, domain, QType::NS, std::to_string(count) + ".ns2.powerdns.org", DNSResourceRecord::AUTHORITY, 172800);
37✔
1037
    count++;
37✔
1038
    return LWResult::Result::Success;
37✔
1039
  });
39✔
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✔
1085
        setLWResult(res, 0, true, false, true);
1✔
1086
        if (type == QType::A) {
1!
1087
          addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
1✔
1088
        }
1✔
1089
        else {
×
1090
          addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
×
1091
        }
×
1092
        return LWResult::Result::Success;
1✔
1093
      }
1✔
1094
      if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
1!
1095
        setLWResult(res, 0, true, false, true);
1✔
1096
        if (type == QType::A) {
1!
1097
          addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
1✔
1098
        }
1✔
1099
        else {
×
1100
          addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
×
1101
        }
×
1102
        return LWResult::Result::Success;
1✔
1103
      }
1✔
1104

1105
      setLWResult(res, RCode::NXDomain, false, false, true);
×
1106
      return LWResult::Result::Success;
×
1107
    }
1✔
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_long_step0_shortcut)
1741
{
2✔
1742
  // This tets the case fixed /optimizaed in #14973
1743
  std::unique_ptr<SyncRes> resolver;
2✔
1744
  initSR(resolver);
2✔
1745
  resolver->setQNameMinimization();
2✔
1746
  primeHints();
2✔
1747
  resolver->setLogMode(SyncRes::Store);
2✔
1748

1749
  size_t count = 0;
2✔
1750
  const DNSName target1("cname1.powerdns.com.");
2✔
1751
  const DNSName target2("cname2.powerdns.com.");
2✔
1752
  const DNSName target3("cname3.powerdns.com.");
2✔
1753
  const DNSName target4("cname4.powerdns.com.");
2✔
1754

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

1758
    if (domain == DNSName("com.")) {
14✔
1759
      setLWResult(res, 0, false, false, true);
2✔
1760
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1761
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1762
      return LWResult::Result::Success;
2✔
1763
    }
2✔
1764
    if (domain == DNSName("powerdns.com.")) {
12✔
1765
      setLWResult(res, 0, false, false, true);
2✔
1766
      addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
1767
      addRecordToLW(res, "ns.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1768
      return LWResult::Result::Success;
2✔
1769
    }
2✔
1770
    if (address == ComboAddress("192.0.2.2:53")) {
10!
1771

1772
      if (domain == target1) {
10✔
1773
        setLWResult(res, 0, true, false, false);
2✔
1774
        addRecordToLW(res, domain, QType::CNAME, target2.toString());
2✔
1775
        return LWResult::Result::Success;
2✔
1776
      }
2✔
1777
      if (domain == target2) {
8✔
1778
        setLWResult(res, 0, true, false, false);
2✔
1779
        addRecordToLW(res, domain, QType::CNAME, target3.toString());
2✔
1780
        return LWResult::Result::Success;
2✔
1781
      }
2✔
1782
      if (domain == target3) {
6✔
1783
        setLWResult(res, 0, true, false, false);
2✔
1784
        addRecordToLW(res, domain, QType::CNAME, target4.toString());
2✔
1785
        return LWResult::Result::Success;
2✔
1786
      }
2✔
1787
      if (domain == target4) {
4!
1788
        setLWResult(res, 0, true, false, false);
4✔
1789
        if (qtype == QType::A) {
4!
1790
          addRecordToLW(res, domain, QType::A, "1.2.3.4");
×
1791
        }
×
1792
        else if (qtype == QType::AAAA) {
4!
1793
          addRecordToLW(res, domain, QType::AAAA, "::1234");
4✔
1794
        }
4✔
1795
        return LWResult::Result::Success;
4✔
1796
      }
4✔
1797

1798
      return LWResult::Result::Success;
×
1799
    }
4✔
1800

1801
    return LWResult::Result::Timeout;
×
1802
  });
10✔
1803

1804
  // We analyze the trace to see how many cases of a failed Step0 occurs. This is a bit dirty, but
1805
  // we have no other way of telling how the resolving took place, as the number of cache lookups is
1806
  // not recorded by the record cache. Also, we like to know if something in Syncres changed that
1807
  // influences the number of failing Step0 lookups.
1808
  auto counter = [](const string& str) {
6✔
1809
    const std::string key = "Step0 Not cached";
6✔
1810
    size_t occurences = 0;
6✔
1811
    auto pos = str.find(key);
6✔
1812
    while (pos != std::string::npos) {
60✔
1813
      occurences++;
54✔
1814
      pos = str.find(key, pos + 1);
54✔
1815
    }
54✔
1816
    return occurences;
6✔
1817
  };
6✔
1818
  vector<DNSRecord> ret;
2✔
1819
  int res = resolver->beginResolve(target1, QType(QType::AAAA), QClass::IN, ret);
2✔
1820
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1821
  BOOST_CHECK_EQUAL(ret.size(), 4U);
2✔
1822
  BOOST_CHECK_EQUAL(count, 6U);
2✔
1823
  BOOST_CHECK_EQUAL(resolver->d_maxdepth, 3U);
2✔
1824
  auto trace = resolver->getTrace();
2✔
1825
  trace = resolver->getTrace();
2✔
1826
  BOOST_CHECK_EQUAL(counter(trace), 4U);
2✔
1827

1828
  // And again to check cache, all Step0 cases should succeed
1829
  ret.clear();
2✔
1830
  res = resolver->beginResolve(target1, QType(QType::AAAA), QClass::IN, ret);
2✔
1831
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1832
  BOOST_CHECK_EQUAL(ret.size(), 4U);
2✔
1833
  BOOST_CHECK_EQUAL(count, 6U);
2✔
1834
  BOOST_CHECK_EQUAL(resolver->d_maxdepth, 3U);
2✔
1835
  trace = resolver->getTrace();
2✔
1836
  BOOST_CHECK_EQUAL(counter(trace), 4U);
2✔
1837

1838
  // And again to check a name that does not fully resolve, we expect Step0 failures to increase
1839
  g_recCache->doWipeCache(target4, false, QType::AAAA);
2✔
1840
  ret.clear();
2✔
1841
  res = resolver->beginResolve(target1, QType(QType::AAAA), QClass::IN, ret);
2✔
1842
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1843
  BOOST_CHECK_EQUAL(ret.size(), 4U);
2✔
1844
  BOOST_CHECK_EQUAL(count, 7U);
2✔
1845
  BOOST_CHECK_EQUAL(resolver->d_maxdepth, 3U);
2✔
1846
  trace = resolver->getTrace();
2✔
1847
  // XXX This number feels pretty high (15 extra, same as before #14973, there seems to be room for more improvement).
1848
  BOOST_CHECK_EQUAL(counter(trace), 19U);
2✔
1849
}
2✔
1850

1851
BOOST_AUTO_TEST_CASE(test_cname_length)
1852
{
2✔
1853
  std::unique_ptr<SyncRes> sr;
2✔
1854
  initSR(sr);
2✔
1855

1856
  primeHints();
2✔
1857

1858
  size_t length = 0;
2✔
1859
  const DNSName target("cname.powerdns.com.");
2✔
1860

1861
  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✔
1862
    if (isRootServer(address)) {
44✔
1863

1864
      setLWResult(res, 0, false, false, true);
22✔
1865
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
22✔
1866
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
22✔
1867
      return LWResult::Result::Success;
22✔
1868
    }
22✔
1869
    if (address == ComboAddress("192.0.2.1:53")) {
22!
1870

1871
      setLWResult(res, 0, true, false, false);
22✔
1872
      addRecordToLW(res, domain, QType::CNAME, std::to_string(length) + "-cname.powerdns.com");
22✔
1873
      length++;
22✔
1874
      return LWResult::Result::Success;
22✔
1875
    }
22✔
1876

1877
    return LWResult::Result::Timeout;
×
1878
  });
22✔
1879

1880
  vector<DNSRecord> ret;
2✔
1881
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1882
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
1883
  BOOST_CHECK_EQUAL(ret.size(), length);
2✔
1884
  BOOST_CHECK_EQUAL(length, SyncRes::s_max_CNAMES_followed + 1);
2✔
1885

1886
  // The CNAME bounds check originating from the record cache causes an ImmediateServFail
1887
  // exception. This is different from the non-cached case, tested above.
1888
  ret.clear();
2✔
1889
  BOOST_CHECK_EXCEPTION(sr->beginResolve(target, QType(QType::A), QClass::IN, ret),
2✔
1890
                        ImmediateServFailException,
2✔
1891
                        [&](const ImmediateServFailException& isfe) {
2✔
1892
                          return isfe.reason == "max number of CNAMEs exceeded";
2✔
1893
                        });
2✔
1894
  BOOST_CHECK_EQUAL(ret.size(), SyncRes::s_max_CNAMES_followed + 1);
2✔
1895

1896
  // Again, now with QName Minimization on, originally this would fail as the result was collected
1897
  // in a temp vector and the throw would skip the copy of the temp vector into the end result
1898
  sr->setQNameMinimization();
2✔
1899
  ret.clear();
2✔
1900
  BOOST_CHECK_EXCEPTION(sr->beginResolve(target, QType(QType::A), QClass::IN, ret),
2✔
1901
                        ImmediateServFailException,
2✔
1902
                        [&](const ImmediateServFailException& isfe) {
2✔
1903
                          return isfe.reason == "max number of CNAMEs exceeded";
2✔
1904
                        });
2✔
1905
  BOOST_CHECK_EQUAL(ret.size(), SyncRes::s_max_CNAMES_followed + 1);
2✔
1906
}
2✔
1907

1908
BOOST_AUTO_TEST_CASE(test_cname_target_servfail)
1909
{
2✔
1910
  std::unique_ptr<SyncRes> resolver;
2✔
1911
  initSR(resolver);
2✔
1912

1913
  primeHints();
2✔
1914

1915
  const DNSName target("cname.powerdns.com.");
2✔
1916
  const DNSName cnameTarget("cname-target.powerdns.com");
2✔
1917

1918
  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✔
1919
    if (isRootServer(ipAddress)) {
8✔
1920
      setLWResult(res, 0, false, false, true);
4✔
1921
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
4✔
1922
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
1923
      return LWResult::Result::Success;
4✔
1924
    }
4✔
1925
    if (ipAddress == ComboAddress("192.0.2.1:53")) {
4!
1926

1927
      if (domain == target) {
4✔
1928
        setLWResult(res, 0, true, false, false);
2✔
1929
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2✔
1930
        return LWResult::Result::Success;
2✔
1931
      }
2✔
1932
      if (domain == cnameTarget) {
2!
1933
        return LWResult::Result::PermanentError;
2✔
1934
      }
2✔
1935

1936
      return LWResult::Result::Success;
×
1937
    }
2✔
1938

1939
    return LWResult::Result::Timeout;
×
1940
  });
4✔
1941

1942
  vector<DNSRecord> ret;
2✔
1943
  int res = resolver->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1944
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
1945
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1946
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1947
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1948
}
2✔
1949

1950
BOOST_AUTO_TEST_CASE(test_cname_target_servfail_servestale)
1951
{
2✔
1952
  std::unique_ptr<SyncRes> resolver;
2✔
1953
  initSR(resolver);
2✔
1954
  MemRecursorCache::s_maxServedStaleExtensions = 1440;
2✔
1955

1956
  primeHints();
2✔
1957

1958
  const DNSName target("cname.powerdns.com.");
2✔
1959
  const DNSName cnameTarget("cname-target.powerdns.com");
2✔
1960

1961
  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✔
1962
    if (isRootServer(ipAddress)) {
8✔
1963
      setLWResult(res, 0, false, false, true);
4✔
1964
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
4✔
1965
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4✔
1966
      return LWResult::Result::Success;
4✔
1967
    }
4✔
1968
    if (ipAddress == ComboAddress("192.0.2.1:53")) {
4!
1969

1970
      if (domain == target) {
4✔
1971
        setLWResult(res, 0, true, false, false);
2✔
1972
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2✔
1973
        return LWResult::Result::Success;
2✔
1974
      }
2✔
1975
      if (domain == cnameTarget) {
2!
1976
        return LWResult::Result::PermanentError;
2✔
1977
      }
2✔
1978

1979
      return LWResult::Result::Success;
×
1980
    }
2✔
1981

1982
    return LWResult::Result::Timeout;
×
1983
  });
4✔
1984

1985
  vector<DNSRecord> ret;
2✔
1986
  int res = resolver->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1987
  // different compared no non-servestale case (returns ServFail), handled by pdns_recursor
1988
  BOOST_CHECK_EQUAL(res, -1);
2✔
1989
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1990
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1991
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
1992
}
2✔
1993

1994
BOOST_AUTO_TEST_CASE(test_time_limit)
1995
{
2✔
1996
  std::unique_ptr<SyncRes> sr;
2✔
1997
  initSR(sr);
2✔
1998

1999
  primeHints();
2✔
2000

2001
  size_t queries = 0;
2✔
2002
  const DNSName target("cname.powerdns.com.");
2✔
2003

2004
  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✔
2005
    queries++;
2✔
2006

2007
    if (isRootServer(address)) {
2!
2008
      setLWResult(res, 0, false, false, true);
2✔
2009
      /* Pretend that this query took 2000 ms */
2010
      res->d_usec = 2000;
2✔
2011

2012
      addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2013
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2014
      return LWResult::Result::Success;
2✔
2015
    }
2✔
2016
    if (address == ComboAddress("192.0.2.1:53")) {
×
2017

2018
      setLWResult(res, 0, true, false, false);
×
2019
      addRecordToLW(res, domain, QType::A, "192.0.2.2");
×
2020
      return LWResult::Result::Success;
×
2021
    }
×
2022

2023
    return LWResult::Result::Timeout;
×
2024
  });
×
2025

2026
  /* Set the maximum time to 1 ms */
2027
  SyncRes::s_maxtotusec = 1000;
2✔
2028

2029
  try {
2✔
2030
    vector<DNSRecord> ret;
2✔
2031
    sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2032
    BOOST_CHECK(false);
2✔
2033
  }
2✔
2034
  catch (const ImmediateServFailException& e) {
2✔
2035
  }
2✔
2036
  BOOST_CHECK_EQUAL(queries, 1U);
2✔
2037
}
2✔
2038

2039
BOOST_AUTO_TEST_CASE(test_dname_processing)
2040
{
2✔
2041
  std::unique_ptr<SyncRes> sr;
2✔
2042
  initSR(sr);
2✔
2043

2044
  primeHints();
2✔
2045

2046
  const DNSName dnameOwner("powerdns.com");
2✔
2047
  const DNSName dnameTarget("powerdns.net");
2✔
2048

2049
  const DNSName target("dname.powerdns.com.");
2✔
2050
  const DNSName cnameTarget("dname.powerdns.net");
2✔
2051

2052
  const DNSName uncachedTarget("dname-uncached.powerdns.com.");
2✔
2053
  const DNSName uncachedCNAMETarget("dname-uncached.powerdns.net.");
2✔
2054

2055
  const DNSName synthCNAME("cname-uncached.powerdns.com.");
2✔
2056
  const DNSName synthCNAMETarget("cname-uncached.powerdns.net.");
2✔
2057

2058
  size_t queries = 0;
2✔
2059

2060
  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✔
2061
    queries++;
10✔
2062

2063
    if (isRootServer(address)) {
10✔
2064
      if (domain.isPartOf(dnameOwner)) {
4✔
2065
        setLWResult(res, 0, false, false, true);
2✔
2066
        addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2067
        addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2068
        return LWResult::Result::Success;
2✔
2069
      }
2✔
2070
      if (domain.isPartOf(dnameTarget)) {
2!
2071
        setLWResult(res, 0, false, false, true);
2✔
2072
        addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2073
        addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2074
        return LWResult::Result::Success;
2✔
2075
      }
2✔
2076
    }
2✔
2077
    else if (address == ComboAddress("192.0.2.1:53")) {
6✔
2078
      if (domain == target) {
2!
2079
        setLWResult(res, 0, true, false, false);
2✔
2080
        addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
2081
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2✔
2082
        return LWResult::Result::Success;
2✔
2083
      }
2✔
2084
    }
2✔
2085
    else if (address == ComboAddress("192.0.2.2:53")) {
4!
2086
      if (domain == cnameTarget) {
4✔
2087
        setLWResult(res, 0, true, false, false);
2✔
2088
        addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
2089
      }
2✔
2090
      if (domain == uncachedCNAMETarget) {
4✔
2091
        setLWResult(res, 0, true, false, false);
2✔
2092
        addRecordToLW(res, domain, QType::A, "192.0.2.3");
2✔
2093
      }
2✔
2094
      return LWResult::Result::Success;
4✔
2095
    }
4✔
2096
    return LWResult::Result::Timeout;
×
2097
  });
10✔
2098

2099
  vector<DNSRecord> ret;
2✔
2100
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2101

2102
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2103
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
2104

2105
  BOOST_CHECK_EQUAL(queries, 4u);
2✔
2106

2107
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2108
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2109
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2110

2111
  BOOST_CHECK(ret[1].d_type == QType::CNAME);
2✔
2112
  BOOST_CHECK_EQUAL(ret[1].d_name, target);
2✔
2113

2114
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2115
  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2✔
2116

2117
  // Now check the cache
2118
  ret.clear();
2✔
2119
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2120

2121
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2122
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
2123

2124
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2125

2126
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2127
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2128
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2129

2130
  BOOST_CHECK(ret[1].d_type == QType::CNAME);
2✔
2131
  BOOST_CHECK_EQUAL(ret[1].d_name, target);
2✔
2132

2133
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2134
  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2✔
2135

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

2140
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2141
  BOOST_CHECK_EQUAL(queries, 5U);
2✔
2142

2143
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2144
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2145
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2146

2147
  BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
2✔
2148
  BOOST_CHECK_EQUAL(ret[1].d_name, uncachedTarget);
2✔
2149
  BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), uncachedCNAMETarget);
2✔
2150

2151
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2152
  BOOST_CHECK_EQUAL(ret[2].d_name, uncachedCNAMETarget);
2✔
2153

2154
  // Check if we correctly return the DNAME from cache when asked
2155
  ret.clear();
2✔
2156
  res = sr->beginResolve(dnameOwner, QType(QType::DNAME), QClass::IN, ret);
2✔
2157
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2158
  BOOST_CHECK_EQUAL(queries, 5U);
2✔
2159

2160
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2161
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2162
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2163

2164
  // Check if we correctly return the synthesized CNAME from cache when asked
2165
  ret.clear();
2✔
2166
  res = sr->beginResolve(synthCNAME, QType(QType::CNAME), QClass::IN, ret);
2✔
2167
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2168
  BOOST_CHECK_EQUAL(queries, 5U);
2✔
2169

2170
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2171
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2172
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2173

2174
  BOOST_REQUIRE(ret[1].d_type == QType::CNAME);
2✔
2175
  BOOST_CHECK(ret[1].d_name == synthCNAME);
2✔
2176
  BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[1])->getTarget(), synthCNAMETarget);
2✔
2177
}
2✔
2178

2179
BOOST_AUTO_TEST_CASE(test_dname_dnssec_secure)
2180
{
2✔
2181
  std::unique_ptr<SyncRes> sr;
2✔
2182
  initSR(sr, true);
2✔
2183
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
2184

2185
  primeHints();
2✔
2186

2187
  const DNSName dnameOwner("powerdns");
2✔
2188
  const DNSName dnameTarget("example");
2✔
2189

2190
  const DNSName target("dname.powerdns");
2✔
2191
  const DNSName cnameTarget("dname.example");
2✔
2192

2193
  testkeysset_t keys;
2✔
2194

2195
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
2196
  luaconfsCopy.dsAnchors.clear();
2✔
2197
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
2198
  generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
2199
  generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
2200
  g_luaconfs.setState(luaconfsCopy);
2✔
2201

2202
  size_t queries = 0;
2✔
2203

2204
  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✔
2205
    queries++;
14✔
2206
    /* 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
2207
     * As such, we need to do some more work to make the answers correct.
2208
     */
2209

2210
    if (isRootServer(address)) {
14✔
2211
      if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
6!
2212
        setLWResult(res, 0, true, false, true);
2✔
2213
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2214
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2215
        return LWResult::Result::Success;
2✔
2216
      }
2✔
2217
      if (domain.countLabels() == 1 && type == QType::DS) { // powerdns|DS or example|DS
4!
2218
        setLWResult(res, 0, true, false, true);
×
2219
        addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
×
2220
        addRRSIG(keys, res->d_records, DNSName("."), 300);
×
2221
        return LWResult::Result::Success;
×
2222
      }
×
2223
      // For the rest, delegate!
2224
      if (domain.isPartOf(dnameOwner)) {
4✔
2225
        setLWResult(res, 0, false, false, true);
2✔
2226
        addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2227
        addDS(dnameOwner, 300, res->d_records, keys);
2✔
2228
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2229
        addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2230
        return LWResult::Result::Success;
2✔
2231
      }
2✔
2232
      if (domain.isPartOf(dnameTarget)) {
2!
2233
        setLWResult(res, 0, false, false, true);
2✔
2234
        addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2235
        addDS(dnameTarget, 300, res->d_records, keys);
2✔
2236
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2237
        addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2238
        return LWResult::Result::Success;
2✔
2239
      }
2✔
2240
    }
2✔
2241
    else if (address == ComboAddress("192.0.2.1:53")) {
8✔
2242
      if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
4!
2243
        setLWResult(res, 0, true, false, true);
2✔
2244
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2245
        addRRSIG(keys, res->d_records, domain, 300);
2✔
2246
        return LWResult::Result::Success;
2✔
2247
      }
2✔
2248
      if (domain == target && type == QType::DS) { // dname.powerdns|DS
2!
2249
        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
×
2250
      }
×
2251
      if (domain == target) {
2!
2252
        setLWResult(res, 0, true, false, false);
2✔
2253
        addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
2254
        addRRSIG(keys, res->d_records, dnameOwner, 300);
2✔
2255
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2✔
2256
        return LWResult::Result::Success;
2✔
2257
      }
2✔
2258
    }
2✔
2259
    else if (address == ComboAddress("192.0.2.2:53")) {
4!
2260
      if (domain.countLabels() == 1 && type == QType::DNSKEY) { // example|DNSKEY
4!
2261
        setLWResult(res, 0, true, false, true);
2✔
2262
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2263
        addRRSIG(keys, res->d_records, domain, 300);
2✔
2264
        return LWResult::Result::Success;
2✔
2265
      }
2✔
2266
      if (domain == cnameTarget && type == QType::DS) { // dname.example|DS
2!
2267
        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
×
2268
      }
×
2269
      if (domain == cnameTarget) {
2!
2270
        setLWResult(res, 0, true, false, false);
2✔
2271
        addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
2272
        addRRSIG(keys, res->d_records, dnameTarget, 300);
2✔
2273
      }
2✔
2274
      return LWResult::Result::Success;
2✔
2275
    }
2✔
2276
    return LWResult::Result::Timeout;
×
2277
  });
14✔
2278

2279
  vector<DNSRecord> ret;
2✔
2280
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2281

2282
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2283
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
2284
  BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2✔
2285

2286
  BOOST_CHECK_EQUAL(queries, 7U);
2✔
2287

2288
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2289
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2290
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2291

2292
  BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
2✔
2293
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2294

2295
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2296
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2297

2298
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2299
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2300

2301
  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2✔
2302
  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2✔
2303

2304
  // And the cache
2305
  ret.clear();
2✔
2306
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2307

2308
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2309
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
2310
  BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2✔
2311

2312
  BOOST_CHECK_EQUAL(queries, 7U);
2✔
2313

2314
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2315
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2316
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2317

2318
  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2✔
2319
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2320

2321
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2322
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2323

2324
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2325
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2326

2327
  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2✔
2328
  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2✔
2329
}
2✔
2330

2331
BOOST_AUTO_TEST_CASE(test_dname_plus_ns_dnssec_secure)
2332
{
2✔
2333
  std::unique_ptr<SyncRes> sr;
2✔
2334
  initSR(sr, true);
2✔
2335
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
2336

2337
  primeHints();
2✔
2338

2339
  const DNSName dnameOwner("powerdns");
2✔
2340
  const DNSName dnameTarget("example");
2✔
2341

2342
  const DNSName target("dname.powerdns");
2✔
2343
  const DNSName cnameTarget("dname.example");
2✔
2344

2345
  testkeysset_t keys;
2✔
2346

2347
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
2348
  luaconfsCopy.dsAnchors.clear();
2✔
2349
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
2350
  generateKeyMaterial(dnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
2351
  g_luaconfs.setState(luaconfsCopy);
2✔
2352

2353
  size_t queries = 0;
2✔
2354

2355
  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✔
2356
    queries++;
8✔
2357

2358
    if (type == QType::DS || type == QType::DNSKEY) {
8!
2359
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
4✔
2360
    }
4✔
2361

2362
    if (domain.isPartOf(dnameOwner)) {
4✔
2363
      setLWResult(res, 0, true, false, true);
2✔
2364
      addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
2365
      addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2366
      addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2✔
2367

2368
      addRecordToLW(res, dnameTarget, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2369
      addDS(dnameTarget, 300, res->d_records, keys);
2✔
2370
      addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2371
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2372
      return LWResult::Result::Success;
2✔
2373
    }
2✔
2374
    if (domain == cnameTarget) {
2!
2375
      setLWResult(res, 0, true, false, true);
2✔
2376
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
2377
      addRRSIG(keys, res->d_records, dnameTarget, 300);
2✔
2378
      return LWResult::Result::Success;
2✔
2379
    }
2✔
2380
    return LWResult::Result::Timeout;
×
2381
  });
2✔
2382

2383
  vector<DNSRecord> ret;
2✔
2384
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2385

2386
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2387
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
2388
  BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2✔
2389

2390
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2391

2392
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2393
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2394
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2395

2396
  BOOST_REQUIRE(ret[1].d_type == QType::RRSIG);
2✔
2397
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2398

2399
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2400
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2401

2402
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2403
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2404

2405
  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2✔
2406
  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2✔
2407

2408
  // And the cache
2409
  ret.clear();
2✔
2410
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2411

2412
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2413
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
2414
  BOOST_REQUIRE_EQUAL(ret.size(), 5U); /* DNAME + RRSIG(DNAME) + CNAME + A + RRSIG(A) */
2✔
2415

2416
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2417

2418
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2419
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2420
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2421

2422
  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2✔
2423
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2424

2425
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2426
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2427

2428
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2429
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2430

2431
  BOOST_CHECK(ret[4].d_type == QType::RRSIG);
2✔
2432
  BOOST_CHECK_EQUAL(ret[4].d_name, cnameTarget);
2✔
2433
}
2✔
2434

2435
BOOST_AUTO_TEST_CASE(test_dname_dnssec_insecure)
2436
{
2✔
2437
  /*
2438
   * The DNAME itself is signed, but the final A record is not
2439
   */
2440
  std::unique_ptr<SyncRes> sr;
2✔
2441
  initSR(sr, true);
2✔
2442
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
2443

2444
  primeHints();
2✔
2445

2446
  const DNSName dnameOwner("powerdns");
2✔
2447
  const DNSName dnameTarget("example");
2✔
2448

2449
  const DNSName target("dname.powerdns");
2✔
2450
  const DNSName cnameTarget("dname.example");
2✔
2451

2452
  testkeysset_t keys;
2✔
2453

2454
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
2455
  luaconfsCopy.dsAnchors.clear();
2✔
2456
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
2457
  generateKeyMaterial(dnameOwner, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
2458
  g_luaconfs.setState(luaconfsCopy);
2✔
2459

2460
  size_t queries = 0;
2✔
2461

2462
  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✔
2463
    queries++;
14✔
2464

2465
    if (isRootServer(address)) {
14✔
2466
      if (domain.countLabels() == 0 && type == QType::DNSKEY) { // .|DNSKEY
8!
2467
        setLWResult(res, 0, true, false, true);
2✔
2468
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2469
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2470
        return LWResult::Result::Success;
2✔
2471
      }
2✔
2472
      if (domain == dnameOwner && type == QType::DS) { // powerdns|DS
6!
2473
        setLWResult(res, 0, true, false, true);
×
2474
        addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
×
2475
        addRRSIG(keys, res->d_records, DNSName("."), 300);
×
2476
        return LWResult::Result::Success;
×
2477
      }
×
2478
      if (domain == dnameTarget && type == QType::DS) { // example|DS
6!
2479
        return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
2✔
2480
      }
2✔
2481
      // For the rest, delegate!
2482
      if (domain.isPartOf(dnameOwner)) {
4✔
2483
        setLWResult(res, 0, false, false, true);
2✔
2484
        addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2485
        addDS(dnameOwner, 300, res->d_records, keys);
2✔
2486
        addRRSIG(keys, res->d_records, DNSName("."), 300);
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
        addDS(dnameTarget, 300, res->d_records, keys);
2✔
2494
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
2495
        addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2496
        return LWResult::Result::Success;
2✔
2497
      }
2✔
2498
    }
2✔
2499
    else if (address == ComboAddress("192.0.2.1:53")) {
6✔
2500
      if (domain.countLabels() == 1 && type == QType::DNSKEY) { // powerdns|DNSKEY
4!
2501
        setLWResult(res, 0, true, false, true);
2✔
2502
        addDNSKEY(keys, domain, 300, res->d_records);
2✔
2503
        addRRSIG(keys, res->d_records, domain, 300);
2✔
2504
        return LWResult::Result::Success;
2✔
2505
      }
2✔
2506
      if (domain == target && type == QType::DS) { // dname.powerdns|DS
2!
2507
        return genericDSAndDNSKEYHandler(res, domain, dnameOwner, type, keys, false);
×
2508
      }
×
2509
      if (domain == target) {
2!
2510
        setLWResult(res, 0, true, false, false);
2✔
2511
        addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
2512
        addRRSIG(keys, res->d_records, dnameOwner, 300);
2✔
2513
        addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString()); // CNAME from a DNAME is not signed
2✔
2514
        return LWResult::Result::Success;
2✔
2515
      }
2✔
2516
    }
2✔
2517
    else if (address == ComboAddress("192.0.2.2:53")) {
2!
2518
      if (domain == target && type == QType::DS) { // dname.example|DS
2!
2519
        return genericDSAndDNSKEYHandler(res, domain, dnameTarget, type, keys, false);
×
2520
      }
×
2521
      if (domain == cnameTarget) {
2!
2522
        setLWResult(res, 0, true, false, false);
2✔
2523
        addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
2524
      }
2✔
2525
      return LWResult::Result::Success;
2✔
2526
    }
2✔
2527
    return LWResult::Result::Timeout;
×
2528
  });
14✔
2529

2530
  vector<DNSRecord> ret;
2✔
2531
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2532

2533
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2534
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
2535
  BOOST_REQUIRE_EQUAL(ret.size(), 4U); /* DNAME + RRSIG(DNAME) + CNAME + A */
2✔
2536

2537
  BOOST_CHECK_EQUAL(queries, 7U);
2✔
2538

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

2543
  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2✔
2544
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2545

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

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

2552
  // And the cache
2553
  ret.clear();
2✔
2554
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2555

2556
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2557
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
2558
  BOOST_REQUIRE_EQUAL(ret.size(), 4U); /* DNAME + RRSIG(DNAME) + CNAME + A */
2✔
2559

2560
  BOOST_CHECK_EQUAL(queries, 7U);
2✔
2561

2562
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2563
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2564
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2565

2566
  BOOST_CHECK(ret[1].d_type == QType::RRSIG);
2✔
2567
  BOOST_CHECK_EQUAL(ret[1].d_name, dnameOwner);
2✔
2568

2569
  BOOST_CHECK(ret[2].d_type == QType::CNAME);
2✔
2570
  BOOST_CHECK_EQUAL(ret[2].d_name, target);
2✔
2571

2572
  BOOST_CHECK(ret[3].d_type == QType::A);
2✔
2573
  BOOST_CHECK_EQUAL(ret[3].d_name, cnameTarget);
2✔
2574
}
2✔
2575

2576
BOOST_AUTO_TEST_CASE(test_dname_processing_no_CNAME)
2577
{
2✔
2578
  std::unique_ptr<SyncRes> sr;
2✔
2579
  initSR(sr);
2✔
2580

2581
  primeHints();
2✔
2582

2583
  const DNSName dnameOwner("powerdns.com");
2✔
2584
  const DNSName dnameTarget("powerdns.net");
2✔
2585

2586
  const DNSName target("dname.powerdns.com.");
2✔
2587
  const DNSName cnameTarget("dname.powerdns.net");
2✔
2588

2589
  size_t queries = 0;
2✔
2590

2591
  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✔
2592
    queries++;
8✔
2593

2594
    if (isRootServer(address)) {
8✔
2595
      if (domain.isPartOf(dnameOwner)) {
4✔
2596
        setLWResult(res, 0, false, false, true);
2✔
2597
        addRecordToLW(res, dnameOwner, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2598
        addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2599
        return LWResult::Result::Success;
2✔
2600
      }
2✔
2601
      if (domain.isPartOf(dnameTarget)) {
2!
2602
        setLWResult(res, 0, false, false, true);
2✔
2603
        addRecordToLW(res, dnameTarget, QType::NS, "b.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2604
        addRecordToLW(res, "b.gtld-servers.net.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2605
        return LWResult::Result::Success;
2✔
2606
      }
2✔
2607
    }
2✔
2608
    else if (address == ComboAddress("192.0.2.1:53")) {
4✔
2609
      if (domain == target) {
2!
2610
        setLWResult(res, 0, true, false, false);
2✔
2611
        addRecordToLW(res, dnameOwner, QType::DNAME, dnameTarget.toString());
2✔
2612
        // No CNAME, recursor should synth
2613
        return LWResult::Result::Success;
2✔
2614
      }
2✔
2615
    }
2✔
2616
    else if (address == ComboAddress("192.0.2.2:53")) {
2!
2617
      if (domain == cnameTarget) {
2!
2618
        setLWResult(res, 0, true, false, false);
2✔
2619
        addRecordToLW(res, domain, QType::A, "192.0.2.2");
2✔
2620
      }
2✔
2621
      return LWResult::Result::Success;
2✔
2622
    }
2✔
2623
    return LWResult::Result::Timeout;
×
2624
  });
8✔
2625

2626
  vector<DNSRecord> ret;
2✔
2627
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2628

2629
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2630
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
2631

2632
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2633

2634
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2635
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2636
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2637

2638
  BOOST_CHECK(ret[1].d_type == QType::CNAME);
2✔
2639
  BOOST_CHECK_EQUAL(ret[1].d_name, target);
2✔
2640

2641
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2642
  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2✔
2643

2644
  // Now check the cache
2645
  ret.clear();
2✔
2646
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2647

2648
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2649
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
2650

2651
  BOOST_CHECK_EQUAL(queries, 4U);
2✔
2652

2653
  BOOST_REQUIRE(ret[0].d_type == QType::DNAME);
2✔
2654
  BOOST_CHECK(ret[0].d_name == dnameOwner);
2✔
2655
  BOOST_CHECK_EQUAL(getRR<DNAMERecordContent>(ret[0])->getTarget(), dnameTarget);
2✔
2656

2657
  BOOST_CHECK(ret[1].d_type == QType::CNAME);
2✔
2658
  BOOST_CHECK_EQUAL(ret[1].d_name, target);
2✔
2659

2660
  BOOST_CHECK(ret[2].d_type == QType::A);
2✔
2661
  BOOST_CHECK_EQUAL(ret[2].d_name, cnameTarget);
2✔
2662
}
2✔
2663

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

2667
- check out of band support
2668

2669
- check preoutquery
2670

2671
*/
2672

2673
BOOST_AUTO_TEST_CASE(test_glued_referral_child_ns_set_wrong)
2674
{
2✔
2675
  std::unique_ptr<SyncRes> sr;
2✔
2676
  initSR(sr);
2✔
2677

2678
  primeHints();
2✔
2679

2680
  const DNSName target("powerdns.com.");
2✔
2681

2682
  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✔
2683
    /* this will cause issue with qname minimization if we ever implement it */
2684
    if (domain != target) {
26!
2685
      return LWResult::Result::Timeout;
×
2686
    }
×
2687

2688
    if (isRootServer(address)) {
26✔
2689
      setLWResult(res, 0, false, false, true);
2✔
2690
      addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2691
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2692
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
2693
      return LWResult::Result::Success;
2✔
2694
    }
2✔
2695
    if (address == ComboAddress("192.0.2.1:53") || address == ComboAddress("[2001:DB8::1]:53")) {
24!
2696
      setLWResult(res, 0, false, false, true);
2✔
2697
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2698
      addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2✔
2699
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2700
      addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2701
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2702
      addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2703
      return LWResult::Result::Success;
2✔
2704
    }
2✔
2705
    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!
2706

2707
      if (type == QType::A) {
6✔
2708
        setLWResult(res, 0, true, false, true);
4✔
2709
        addRecordToLW(res, target, QType::A, "192.0.2.4");
4✔
2710
        return LWResult::Result::Success;
4✔
2711
      }
4✔
2712
      if (type == QType::NS) {
2!
2713
        setLWResult(res, 0, true, false, true);
2✔
2714
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-nsX1.powerdns.com.", DNSResourceRecord::ANSWER, 172800);
2✔
2715
        addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-nsX2.powerdns.com.", DNSResourceRecord::ANSWER, 172800);
2✔
2716
        addRecordToLW(res, "pdns-public-nsX1.powerdns.com.", QType::A, "192.0.2.11", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2717
        addRecordToLW(res, "pdns-public-nsX1.powerdns.com.", QType::AAAA, "2001:DB8::11", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2718
        addRecordToLW(res, "pdns-public-nsX2.powerdns.com.", QType::A, "192.0.2.12", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2719
        addRecordToLW(res, "pdns-public-nsX2.powerdns.com.", QType::AAAA, "2001:DB8::12", DNSResourceRecord::ADDITIONAL, 172800);
2✔
2720
        return LWResult::Result::Success;
2✔
2721
      }
2✔
2722
      return LWResult::Result::Timeout;
×
2723
    }
2✔
2724
    return LWResult::Result::Timeout;
16✔
2725
  });
22✔
2726

2727
  vector<DNSRecord> ret;
2✔
2728
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2729
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2730
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
2731
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
2732
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
2733

2734
  // Now resolve NS to get auth NS set in cache and save the parent NS set
2735
  ret.clear();
2✔
2736
  res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
2✔
2737
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2738
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
2739
  BOOST_CHECK(ret[0].d_type == QType::NS);
2✔
2740
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
2741
  BOOST_CHECK_EQUAL(SyncRes::getSaveParentsNSSetsSize(), 1U);
2✔
2742

2743
  g_recCache->doWipeCache(target, false, QType::A);
2✔
2744
  SyncRes::s_save_parent_ns_set = false;
2✔
2745

2746
  // Try to resolve now via the broken child NS set... should not work
2747
  ret.clear();
2✔
2748
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2749
  BOOST_CHECK_EQUAL(res, RCode::ServFail);
2✔
2750
  BOOST_REQUIRE_EQUAL(ret.size(), 0U);
2✔
2751

2752
  SyncRes::s_save_parent_ns_set = true;
2✔
2753

2754
  // Try to resolve now via the broken child... should work now via fallback to parent NS set
2755
  ret.clear();
2✔
2756
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
2757
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
2758
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
2759
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
2760
  BOOST_CHECK_EQUAL(ret[0].d_name, target);
2✔
2761
}
2✔
2762

2763
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