• 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

91.83
/pdns/recursordist/test-syncres_cc3.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

9
BOOST_AUTO_TEST_SUITE(syncres_cc3)
10

11
BOOST_AUTO_TEST_CASE(test_cache_auth)
12
{
2✔
13
  std::unique_ptr<SyncRes> sr;
2✔
14
  initSR(sr);
2✔
15

16
  primeHints();
2✔
17

18
  /* the auth server is sending the same answer in answer and additional,
19
     check that we only return one result, and we only cache one too. */
20
  const DNSName target("cache-auth.powerdns.com.");
2✔
21

22
  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✔
23
    setLWResult(res, 0, true, false, true);
2✔
24
    addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2✔
25
    addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 10);
2✔
26

27
    return LWResult::Result::Success;
2✔
28
  });
2✔
29

30
  const time_t now = sr->getNow().tv_sec;
2✔
31

32
  vector<DNSRecord> ret;
2✔
33
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
34
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
35
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
36
  BOOST_REQUIRE_EQUAL(QType(ret.at(0).d_type).toString(), QType(QType::A).toString());
2✔
37
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2✔
38

39
  /* check that we correctly cached only the answer entry, not the additional one */
40
  const ComboAddress who;
2✔
41
  vector<DNSRecord> cached;
2✔
42
  BOOST_REQUIRE_GT(g_recCache->get(now, target, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
2✔
43
  BOOST_REQUIRE_EQUAL(cached.size(), 1U);
2✔
44
  BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
2✔
45
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2✔
46
}
2✔
47

48
BOOST_AUTO_TEST_CASE(test_unauth_any)
49
{
2✔
50
  std::unique_ptr<SyncRes> sr;
2✔
51
  initSR(sr);
2✔
52

53
  primeHints();
2✔
54

55
  const DNSName target("powerdns.com.");
2✔
56

57
  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✔
58
    if (isRootServer(address)) {
6✔
59
      setLWResult(res, 0, false, false, true);
2✔
60
      addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
61
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
62
      return LWResult::Result::Success;
2✔
63
    }
2✔
64
    if (address == ComboAddress("192.0.2.1:53")) {
4!
65
      if (type == QType::A) {
4✔
66
        setLWResult(res, 0, false, false, true);
2✔
67
        addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
68
        addRecordToLW(res, domain, QType::A, "192.0.2.43");
2✔
69
        return LWResult::Result::Success;
2✔
70
      }
2✔
71
      if (type == QType::AAAA) {
2!
72
        setLWResult(res, 0, false, false, true);
2✔
73
        addRecordToLW(res, domain, QType::AAAA, "::1");
2✔
74
        return LWResult::Result::Success;
2✔
75
      }
2✔
76
    }
2✔
77

78
    return LWResult::Result::Timeout;
×
79
  });
4✔
80

81
  vector<DNSRecord> ret;
2✔
82
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
83
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
84
  BOOST_CHECK_EQUAL(ret.size(), 2U);
2✔
85

86
  ret.clear();
2✔
87
  res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
2✔
88
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
89
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
90

91
  ret.clear();
2✔
92
  MemRecursorCache::s_maxRRSetSize = 2;
2✔
93
  BOOST_CHECK_THROW(sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret), ImmediateServFailException);
2✔
94

95
  MemRecursorCache::s_limitQTypeAny = false;
2✔
96
  ret.clear();
2✔
97
  res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2✔
98
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
99
  BOOST_CHECK_EQUAL(ret.size(), 3U);
2✔
100
}
2✔
101

102
static void test_no_data_f(bool qmin)
103
{
4✔
104
  std::unique_ptr<SyncRes> sr;
4✔
105
  initSR(sr);
4✔
106
  if (qmin)
4✔
107
    sr->setQNameMinimization();
2✔
108

109
  primeHints();
4✔
110

111
  const DNSName target("powerdns.com.");
4✔
112

113
  sr->setAsyncCallback(
4✔
114
    [&](const ComboAddress& /* ip */, const DNSName& /* domain */, int /* type */, bool /* doTCP */, bool /* sendRDQuery */, int /* EDNS0Level */,
4✔
115
        struct timeval* /* now */, boost::optional<Netmask>& /* srcmask */, const ResolveContext& /* context */,
4✔
116
        LWResult* res, bool* /* chained */) {
6✔
117
      setLWResult(res, 0, true, false, true);
6✔
118
      return LWResult::Result::Success;
6✔
119
    });
6✔
120

121
  vector<DNSRecord> ret;
4✔
122
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4✔
123
  BOOST_CHECK_EQUAL(res, RCode::NoError);
4✔
124
  BOOST_CHECK_EQUAL(ret.size(), 0U);
4✔
125
}
4✔
126

127
BOOST_AUTO_TEST_CASE(test_no_data)
128
{
2✔
129
  test_no_data_f(false);
2✔
130
}
2✔
131

132
BOOST_AUTO_TEST_CASE(test_no_data_qmin)
133
{
2✔
134
  test_no_data_f(true);
2✔
135
}
2✔
136

137
BOOST_AUTO_TEST_CASE(test_extra_answers)
138
{
2✔
139
  // Test extra records in the answer section
140
  std::unique_ptr<SyncRes> sr;
2✔
141
  initSR(sr);
2✔
142

143
  primeHints();
2✔
144

145
  const DNSName target("www.powerdns.com.");
2✔
146
  const DNSName target2("www2.powerdns.com."); // in bailiwick, but not asked for
2✔
147
  const DNSName target3("www.random.net."); // out of bailiwick and not asked for
2✔
148

149
  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✔
150
    if (isRootServer(address)) {
4✔
151
      setLWResult(res, 0, false, false, true);
2✔
152
      addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
153
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
154
      return LWResult::Result::Success;
2✔
155
    }
2✔
156

157
    setLWResult(res, 0, true, false, true);
2✔
158
    addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2✔
159
    addRecordToLW(res, target2, QType::A, "192.0.2.3", DNSResourceRecord::ANSWER, 10);
2✔
160
    addRecordToLW(res, target3, QType::A, "192.0.2.4", DNSResourceRecord::ANSWER, 10);
2✔
161

162
    return LWResult::Result::Success;
2✔
163
  });
4✔
164

165
  const time_t now = sr->getNow().tv_sec;
2✔
166

167
  // we should only see a single record for the question we asked
168
  vector<DNSRecord> ret;
2✔
169
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
170
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
171
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
172
  BOOST_REQUIRE_EQUAL(QType(ret.at(0).d_type).toString(), QType(QType::A).toString());
2✔
173
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2✔
174

175
  // Also check the cache
176
  const ComboAddress who;
2✔
177
  vector<DNSRecord> cached;
2✔
178
  BOOST_REQUIRE_GT(g_recCache->get(now, target, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
2✔
179
  BOOST_REQUIRE_EQUAL(cached.size(), 1U);
2✔
180
  BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
2✔
181
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2✔
182

183
  // The cache should not have an authoritative record for the extra in-bailiwick record
184
  BOOST_REQUIRE_LE(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
2✔
185

186
  // And the out-of-bailiwick record should not be there
187
  BOOST_REQUIRE_LE(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
2✔
188
}
2✔
189

190
BOOST_AUTO_TEST_CASE(test_dnssec_extra_answers)
191
{
2✔
192
  // Test extra records in the answer section
193
  std::unique_ptr<SyncRes> sr;
2✔
194
  initSR(sr, true);
2✔
195

196
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
197

198
  primeHints();
2✔
199
  const DNSName target("www.powerdns.com.");
2✔
200
  const DNSName target2("www2.powerdns.com."); // in bailiwick, but not asked for
2✔
201
  const DNSName target3("www.random.net."); // out of bailiwick and not asked for
2✔
202
  testkeysset_t keys;
2✔
203

204
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
205
  luaconfsCopy.dsAnchors.clear();
2✔
206
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
207
  generateKeyMaterial(DNSName("powerdns.com"), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
208
  g_luaconfs.setState(luaconfsCopy);
2✔
209

210
  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✔
211
    if (type == QType::DS || type == QType::DNSKEY) {
6!
212
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
2✔
213
    }
2✔
214
    if (isRootServer(address)) {
4✔
215
      setLWResult(res, 0, false, false, true);
2✔
216
      addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
217
      addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
218
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
219
      return LWResult::Result::Success;
2✔
220
    }
2✔
221

222
    setLWResult(res, 0, true, false, true);
2✔
223
    addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2✔
224
    addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
2✔
225
    addRecordToLW(res, target2, QType::A, "192.0.2.3", DNSResourceRecord::ANSWER, 10);
2✔
226
    addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
2✔
227
    addRecordToLW(res, target3, QType::A, "192.0.2.4", DNSResourceRecord::ANSWER, 10);
2✔
228

229
    return LWResult::Result::Success;
2✔
230
  });
4✔
231

232
  const time_t now = sr->getNow().tv_sec;
2✔
233

234
  // we should only see a single record for the question we asked
235
  vector<DNSRecord> ret;
2✔
236
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
237
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
238
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
239
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
240
  BOOST_REQUIRE_EQUAL(QType(ret.at(0).d_type).toString(), QType(QType::A).toString());
2✔
241
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2✔
242

243
  // Also check the cache
244
  const ComboAddress who;
2✔
245
  vector<DNSRecord> cached;
2✔
246
  BOOST_REQUIRE_GT(g_recCache->get(now, target, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
2✔
247
  BOOST_REQUIRE_EQUAL(cached.size(), 1U);
2✔
248
  BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).toString(), QType(QType::A).toString());
2✔
249
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2✔
250

251
  // The cache should not have an authoritative record for the extra in-bailiwick record
252
  BOOST_REQUIRE_LE(g_recCache->get(now, target2, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
2✔
253

254
  // And the out-of-bailiwick record should not be there
255
  BOOST_REQUIRE_LE(g_recCache->get(now, target3, QType(QType::A), MemRecursorCache::RequireAuth, &cached, who), 0);
2✔
256
}
2✔
257

258
BOOST_AUTO_TEST_CASE(test_skip_opt_any)
259
{
2✔
260
  std::unique_ptr<SyncRes> sr;
2✔
261
  initSR(sr);
2✔
262

263
  primeHints();
2✔
264

265
  const DNSName target("powerdns.com.");
2✔
266

267
  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✔
268
    setLWResult(res, 0, true, false, true);
2✔
269
    addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
270
    addRecordToLW(res, domain, QType::ANY, "\\# 0");
2✔
271
    addRecordToLW(res, domain, QType::OPT, "");
2✔
272
    return LWResult::Result::Success;
2✔
273
  });
2✔
274

275
  vector<DNSRecord> ret;
2✔
276
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
277
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
278
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
279
}
2✔
280

281
BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec)
282
{
2✔
283
  std::unique_ptr<SyncRes> sr;
2✔
284
  initSR(sr);
2✔
285

286
  primeHints();
2✔
287

288
  const DNSName target("powerdns.com.");
2✔
289

290
  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✔
291
    setLWResult(res, 0, true, false, true);
2✔
292
    addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
293
    /* the NSEC and RRSIG contents are complete garbage, please ignore them */
294
    addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2✔
295
    addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2✔
296
    addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2✔
297
    return LWResult::Result::Success;
2✔
298
  });
2✔
299

300
  vector<DNSRecord> ret;
2✔
301
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
302
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
303
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
304
}
2✔
305

306
BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec)
307
{
2✔
308
  std::unique_ptr<SyncRes> sr;
2✔
309
  initSR(sr, true);
2✔
310

311
  primeHints();
2✔
312

313
  const DNSName target("powerdns.com.");
2✔
314

315
  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✔
316
    setLWResult(res, 0, true, false, true);
2✔
317
    addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
318
    /* the NSEC and RRSIG contents are complete garbage, please ignore them */
319
    addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2✔
320
    addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2✔
321
    addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2✔
322
    return LWResult::Result::Success;
2✔
323
  });
2✔
324

325
  vector<DNSRecord> ret;
2✔
326
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
327
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
328
  BOOST_CHECK_EQUAL(ret.size(), 4U);
2✔
329
}
2✔
330

331
BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec)
332
{
2✔
333
  std::unique_ptr<SyncRes> sr;
2✔
334
  initSR(sr);
2✔
335

336
  primeHints();
2✔
337

338
  const DNSName target("powerdns.com.");
2✔
339

340
  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✔
341
    setLWResult(res, RCode::NXDomain, true, false, true);
2✔
342
    addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
343
    /* the NSEC and RRSIG contents are complete garbage, please ignore them */
344
    addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2✔
345
    addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2✔
346
    addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2✔
347
    return LWResult::Result::Success;
2✔
348
  });
2✔
349

350
  vector<DNSRecord> ret;
2✔
351
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
352
  BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2✔
353
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
354
}
2✔
355

356
BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec)
357
{
2✔
358
  std::unique_ptr<SyncRes> sr;
2✔
359
  initSR(sr, true);
2✔
360

361
  primeHints();
2✔
362

363
  const DNSName target("powerdns.com.");
2✔
364

365
  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✔
366
    setLWResult(res, RCode::NXDomain, true, false, true);
2✔
367
    addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
368
    /* the NSEC and RRSIG contents are complete garbage, please ignore them */
369
    addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2✔
370
    addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2✔
371
    addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2✔
372
    return LWResult::Result::Success;
2✔
373
  });
2✔
374

375
  vector<DNSRecord> ret;
2✔
376
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
377
  BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2✔
378
  BOOST_CHECK_EQUAL(ret.size(), 4U);
2✔
379
}
2✔
380

381
BOOST_AUTO_TEST_CASE(test_qclass_none)
382
{
2✔
383
  std::unique_ptr<SyncRes> sr;
2✔
384
  initSR(sr);
2✔
385

386
  primeHints();
2✔
387

388
  /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
389
  size_t queriesCount = 0;
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 */) {
2✔
392
    queriesCount++;
×
393
    return LWResult::Result::Timeout;
×
394
  });
×
395

396
  const DNSName target("powerdns.com.");
2✔
397
  vector<DNSRecord> ret;
2✔
398
  int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2✔
399
  BOOST_CHECK_EQUAL(res, -1);
2✔
400
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
401
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
402
}
2✔
403

404
BOOST_AUTO_TEST_CASE(test_answer_no_aa)
405
{
2✔
406
  std::unique_ptr<SyncRes> sr;
2✔
407
  initSR(sr, true);
2✔
408

409
  primeHints();
2✔
410

411
  const DNSName target("powerdns.com.");
2✔
412

413
  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✔
414
    setLWResult(res, 0, false, false, true);
2✔
415
    addRecordToLW(res, domain, QType::A, "192.0.2.1");
2✔
416
    return LWResult::Result::Success;
2✔
417
  });
2✔
418

419
  const time_t now = sr->getNow().tv_sec;
2✔
420

421
  vector<DNSRecord> ret;
2✔
422
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
423
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
424
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
425

426
  /* check that the record in the answer section has not been cached */
427
  const ComboAddress who;
2✔
428
  vector<DNSRecord> cached;
2✔
429
  vector<std::shared_ptr<const RRSIGRecordContent>> signatures;
2✔
430
  BOOST_REQUIRE_GT(g_recCache->get(now, target, QType(QType::A), MemRecursorCache::None, &cached, who, boost::none, &signatures), 0);
2✔
431
}
2✔
432

433
BOOST_AUTO_TEST_CASE(test_special_types)
434
{
2✔
435
  std::unique_ptr<SyncRes> sr;
2✔
436
  initSR(sr);
2✔
437

438
  primeHints();
2✔
439

440
  /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
441
  size_t queriesCount = 0;
2✔
442

443
  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✔
444
    cerr << "asyncresolve called to ask " << address.toStringWithPort() << " about " << domain.toString() << " / " << QType(type).toString() << " over " << (doTCP ? "TCP" : "UDP") << " (rd: " << sendRDQuery << ", EDNS0 level: " << EDNS0Level << ")" << endl;
×
445
    queriesCount++;
×
446
    return LWResult::Result::Timeout;
×
447
  });
×
448

449
  const DNSName target("powerdns.com.");
2✔
450
  vector<DNSRecord> ret;
2✔
451
  int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2✔
452
  BOOST_CHECK_EQUAL(res, -1);
2✔
453
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
454
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
455

456
  res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2✔
457
  BOOST_CHECK_EQUAL(res, -1);
2✔
458
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
459
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
460

461
  res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2✔
462
  BOOST_CHECK_EQUAL(res, -1);
2✔
463
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
464
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
465

466
  res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
2✔
467
  BOOST_CHECK_EQUAL(res, -1);
2✔
468
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
469
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
470
}
2✔
471

472
BOOST_AUTO_TEST_CASE(test_special_names)
473
{
2✔
474
  std::unique_ptr<SyncRes> sr;
2✔
475
  initSR(sr);
2✔
476

477
  primeHints();
2✔
478

479
  /* special names should be handled internally */
480

481
  size_t queriesCount = 0;
2✔
482

483
  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✔
484
    queriesCount++;
×
485
    return LWResult::Result::Timeout;
×
486
  });
×
487

488
  vector<DNSRecord> ret;
2✔
489
  int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
2✔
490
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
491
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
492
  BOOST_CHECK(ret[0].d_type == QType::PTR);
2✔
493
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
494

495
  ret.clear();
2✔
496
  res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
2✔
497
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
498
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
499
  BOOST_CHECK(ret[0].d_type == QType::PTR);
2✔
500
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
501

502
  ret.clear();
2✔
503
  res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::PTR), QClass::IN, ret);
2✔
504
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
505
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
506
  BOOST_CHECK(ret[0].d_type == QType::PTR);
2✔
507
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
508

509
  ret.clear();
2✔
510
  res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::ANY), QClass::IN, ret);
2✔
511
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
512
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
513
  BOOST_CHECK(ret[0].d_type == QType::PTR);
2✔
514
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
515

516
  ret.clear();
2✔
517
  res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
2✔
518
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
519
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
520
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
521
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2✔
522
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
523

524
  ret.clear();
2✔
525
  res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
2✔
526
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
527
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
528
  BOOST_CHECK(ret[0].d_type == QType::AAAA);
2✔
529
  BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2✔
530
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
531

532
  ret.clear();
2✔
533
  res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
2✔
534
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
535
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
536
  for (const auto& rec : ret) {
4✔
537
    BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
4✔
538
    if (rec.d_type == QType::A) {
4✔
539
      BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2✔
540
    }
2✔
541
    else {
2✔
542
      BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2✔
543
    }
2✔
544
  }
4✔
545
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
546

547
  ret.clear();
2✔
548
  res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
2✔
549
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
550
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
551
  BOOST_CHECK(ret[0].d_type == QType::TXT);
2✔
552
  BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2✔
553
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
554

555
  ret.clear();
2✔
556
  res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
2✔
557
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
558
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
559
  BOOST_CHECK(ret[0].d_type == QType::TXT);
2✔
560
  BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2✔
561
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
562

563
  ret.clear();
2✔
564
  res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
2✔
565
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
566
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
567
  BOOST_CHECK(ret[0].d_type == QType::TXT);
2✔
568
  BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2✔
569
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
570

571
  ret.clear();
2✔
572
  res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
2✔
573
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
574
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
575
  BOOST_CHECK(ret[0].d_type == QType::TXT);
2✔
576
  BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2✔
577
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
578

579
  ret.clear();
2✔
580
  res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
2✔
581
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
582
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
583
  BOOST_CHECK(ret[0].d_type == QType::TXT);
2✔
584
  BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2✔
585
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
586

587
  ret.clear();
2✔
588
  res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
2✔
589
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
590
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
591
  BOOST_CHECK(ret[0].d_type == QType::TXT);
2✔
592
  BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2✔
593
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
594
}
2✔
595

596
BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz)
597
{
2✔
598
  std::unique_ptr<SyncRes> sr;
2✔
599
  initSR(sr);
2✔
600

601
  primeHints();
2✔
602

603
  const DNSName target("rpz.powerdns.com.");
2✔
604
  const ComboAddress ns("192.0.2.1:53");
2✔
605

606
  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✔
607
    if (isRootServer(address)) {
2!
608
      setLWResult(res, false, true, false, true);
2✔
609
      addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
610
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2✔
611
      return LWResult::Result::Success;
2✔
612
    }
2✔
613
    if (address == ns) {
×
614

615
      setLWResult(res, 0, true, false, true);
×
616
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
×
617
      return LWResult::Result::Success;
×
618
    }
×
619

620
    return LWResult::Result::Timeout;
×
621
  });
×
622

623
  DNSFilterEngine::Policy pol;
2✔
624
  pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2✔
625
  std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2✔
626
  zone->setName("Unit test policy 0");
2✔
627
  zone->addNSIPTrigger(Netmask(ns, 32), std::move(pol));
2✔
628
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
629
  luaconfsCopy.dfe.clearZones();
2✔
630
  luaconfsCopy.dfe.addZone(zone);
2✔
631
  g_luaconfs.setState(luaconfsCopy);
2✔
632

633
  vector<DNSRecord> ret;
2✔
634
  BOOST_CHECK_THROW(sr->beginResolve(target, QType(QType::A), QClass::IN, ret), PolicyHitException);
2✔
635
}
2✔
636

637
BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz)
638
{
2✔
639
  std::unique_ptr<SyncRes> sr;
2✔
640
  initSR(sr);
2✔
641

642
  primeHints();
2✔
643

644
  const DNSName target("rpz.powerdns.com.");
2✔
645
  const ComboAddress ns("[2001:DB8::42]:53");
2✔
646

647
  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✔
648
    if (isRootServer(address)) {
2!
649
      setLWResult(res, 0, false, false, true);
2✔
650
      addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2✔
651
      addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2✔
652
      return LWResult::Result::Success;
2✔
653
    }
2✔
654
    if (address == ns) {
×
655

656
      setLWResult(res, 0, true, false, true);
×
657
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
×
658
      return LWResult::Result::Success;
×
659
    }
×
660

661
    return LWResult::Result::Timeout;
×
662
  });
×
663

664
  DNSFilterEngine::Policy pol;
2✔
665
  pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2✔
666
  std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2✔
667
  zone->setName("Unit test policy 0");
2✔
668
  zone->addNSIPTrigger(Netmask(ns, 128), std::move(pol));
2✔
669
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
670
  luaconfsCopy.dfe.clearZones();
2✔
671
  luaconfsCopy.dfe.addZone(zone);
2✔
672
  g_luaconfs.setState(luaconfsCopy);
2✔
673

674
  vector<DNSRecord> ret;
2✔
675
  BOOST_CHECK_THROW(sr->beginResolve(target, QType(QType::A), QClass::IN, ret), PolicyHitException);
2✔
676
}
2✔
677

678
BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz)
679
{
2✔
680
  std::unique_ptr<SyncRes> sr;
2✔
681
  initSR(sr);
2✔
682

683
  primeHints();
2✔
684

685
  const DNSName target("rpz.powerdns.com.");
2✔
686
  const ComboAddress ns("192.0.2.1:53");
2✔
687
  const DNSName nsName("ns1.powerdns.com.");
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 */) {
2✔
690
    if (isRootServer(address)) {
2!
691
      setLWResult(res, 0, false, false, true);
2✔
692
      addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2✔
693
      addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2✔
694
      return LWResult::Result::Success;
2✔
695
    }
2✔
696
    if (address == ns) {
×
697

698
      setLWResult(res, 0, true, false, true);
×
699
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
×
700
      return LWResult::Result::Success;
×
701
    }
×
702

703
    return LWResult::Result::Timeout;
×
704
  });
×
705

706
  DNSFilterEngine::Policy pol;
2✔
707
  pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2✔
708
  std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2✔
709
  zone->setName("Unit test policy 0");
2✔
710
  zone->addNSTrigger(nsName, std::move(pol));
2✔
711
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
712
  luaconfsCopy.dfe.clearZones();
2✔
713
  luaconfsCopy.dfe.addZone(zone);
2✔
714
  g_luaconfs.setState(luaconfsCopy);
2✔
715

716
  vector<DNSRecord> ret;
2✔
717
  BOOST_CHECK_THROW(sr->beginResolve(target, QType(QType::A), QClass::IN, ret), PolicyHitException);
2✔
718
}
2✔
719

720
BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled)
721
{
2✔
722
  std::unique_ptr<SyncRes> sr;
2✔
723
  initSR(sr);
2✔
724

725
  primeHints();
2✔
726

727
  const DNSName target("rpz.powerdns.com.");
2✔
728
  const ComboAddress ns("192.0.2.1:53");
2✔
729
  const DNSName nsName("ns1.powerdns.com.");
2✔
730

731
  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✔
732
    if (isRootServer(address)) {
4✔
733
      setLWResult(res, 0, false, false, true);
2✔
734
      addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2✔
735
      addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2✔
736
      return LWResult::Result::Success;
2✔
737
    }
2✔
738
    if (address == ns) {
2!
739

740
      setLWResult(res, 0, true, false, true);
2✔
741
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
742
      return LWResult::Result::Success;
2✔
743
    }
2✔
744

745
    return LWResult::Result::Timeout;
×
746
  });
2✔
747

748
  DNSFilterEngine::Policy pol;
2✔
749
  pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2✔
750
  std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2✔
751
  zone->setName("Unit test policy 0");
2✔
752
  zone->addNSIPTrigger(Netmask(ns, 128), DNSFilterEngine::Policy(pol));
2✔
753
  zone->addNSTrigger(nsName, std::move(pol));
2✔
754
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
755
  luaconfsCopy.dfe.clearZones();
2✔
756
  luaconfsCopy.dfe.addZone(zone);
2✔
757
  g_luaconfs.setState(luaconfsCopy);
2✔
758

759
  /* RPZ is disabled for this query, we should not be blocked */
760
  sr->setWantsRPZ(false);
2✔
761

762
  vector<DNSRecord> ret;
2✔
763
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
764
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
765
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
766
}
2✔
767

768
BOOST_AUTO_TEST_CASE(test_forward_zone_nord)
769
{
2✔
770
  std::unique_ptr<SyncRes> sr;
2✔
771
  initSR(sr);
2✔
772

773
  primeHints();
2✔
774

775
  const DNSName target("powerdns.com.");
2✔
776
  const ComboAddress ns("192.0.2.1:53");
2✔
777
  const ComboAddress forwardedNS("192.0.2.42:53");
2✔
778

779
  SyncRes::AuthDomain ad;
2✔
780
  ad.d_rdForward = false;
2✔
781
  ad.d_servers.push_back(forwardedNS);
2✔
782
  (*SyncRes::t_sstorage.domainmap)[target] = ad;
2✔
783

784
  size_t queriesCount = 0;
2✔
785

786
  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✔
787
    ++queriesCount;
2✔
788
    if (address == forwardedNS) {
2!
789
      BOOST_CHECK_EQUAL(sendRDQuery, false);
2✔
790

791
      setLWResult(res, 0, true, false, true);
2✔
792
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
793
      return LWResult::Result::Success;
2✔
794
    }
2✔
795

796
    return LWResult::Result::Timeout;
×
797
  });
2✔
798

799
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
800
  /* simulate a no-RD query */
801
  sr->setCacheOnly();
2✔
802

803
  vector<DNSRecord> ret;
2✔
804
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
805
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
806
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
807
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
808

809
  /* simulate a RD query */
810
  sr->setCacheOnly(false);
2✔
811

812
  ret.clear();
2✔
813
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
814
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
815
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
816
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
817

818
  /* simulate a no-RD query */
819
  sr->setCacheOnly();
2✔
820

821
  ret.clear();
2✔
822
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
823
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
824
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
825
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
826
}
2✔
827

828
BOOST_AUTO_TEST_CASE(test_forward_zone_rd)
829
{
2✔
830
  std::unique_ptr<SyncRes> sr;
2✔
831
  initSR(sr);
2✔
832

833
  primeHints();
2✔
834

835
  const DNSName target("powerdns.com.");
2✔
836
  const ComboAddress ns("192.0.2.1:53");
2✔
837
  const ComboAddress forwardedNS("192.0.2.42:53");
2✔
838

839
  size_t queriesCount = 0;
2✔
840
  SyncRes::AuthDomain ad;
2✔
841
  ad.d_rdForward = true;
2✔
842
  ad.d_servers.push_back(forwardedNS);
2✔
843
  (*SyncRes::t_sstorage.domainmap)[target] = ad;
2✔
844

845
  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✔
846
    queriesCount++;
2✔
847

848
    if (address == forwardedNS) {
2!
849
      BOOST_CHECK_EQUAL(sendRDQuery, true);
2✔
850

851
      /* set AA=0, we are a recursor */
852
      setLWResult(res, 0, false, false, true);
2✔
853
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
854
      return LWResult::Result::Success;
2✔
855
    }
2✔
856

857
    return LWResult::Result::Timeout;
×
858
  });
2✔
859

860
  vector<DNSRecord> ret;
2✔
861
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
862
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
863
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
864
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
865

866
  /* now make sure we can resolve from the cache (see #6340
867
     where the entries were added to the cache but not retrieved,
868
     because the recursor doesn't set the AA bit and we require
869
     it. We fixed it by not requiring the AA bit for forward-recurse
870
     answers. */
871
  ret.clear();
2✔
872
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
873
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
874
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
875
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
876
}
2✔
877

878
BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord)
879
{
2✔
880
  std::unique_ptr<SyncRes> sr;
2✔
881
  initSR(sr);
2✔
882

883
  primeHints();
2✔
884

885
  const DNSName target("powerdns.com.");
2✔
886
  const ComboAddress ns("192.0.2.1:53");
2✔
887
  const ComboAddress forwardedNS("192.0.2.42:53");
2✔
888

889
  SyncRes::AuthDomain ad;
2✔
890
  ad.d_rdForward = true;
2✔
891
  ad.d_servers.push_back(forwardedNS);
2✔
892
  (*SyncRes::t_sstorage.domainmap)[target] = ad;
2✔
893

894
  size_t queriesCount = 0;
2✔
895

896
  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✔
897
    ++queriesCount;
2✔
898
    if (address == forwardedNS) {
2!
899
      BOOST_CHECK_EQUAL(sendRDQuery, true);
2✔
900

901
      setLWResult(res, 0, true, false, true);
2✔
902
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
903
      return LWResult::Result::Success;
2✔
904
    }
2✔
905

906
    return LWResult::Result::Timeout;
×
907
  });
2✔
908

909
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
910
  /* simulate a no-RD query */
911
  sr->setCacheOnly();
2✔
912

913
  vector<DNSRecord> ret;
2✔
914
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
915
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
916
  BOOST_CHECK_EQUAL(ret.size(), 0U);
2✔
917
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
918

919
  /* simulate a RD query */
920
  sr->setCacheOnly(false);
2✔
921

922
  ret.clear();
2✔
923
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
924
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
925
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
926
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
927

928
  /* simulate a no-RD query */
929
  sr->setCacheOnly();
2✔
930

931
  ret.clear();
2✔
932
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
933
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
934
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
935
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
936
}
2✔
937

938
BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd)
939
{
2✔
940
  std::unique_ptr<SyncRes> sr;
2✔
941
  initSR(sr);
2✔
942

943
  primeHints();
2✔
944

945
  const DNSName target("powerdns.com.");
2✔
946
  const ComboAddress ns("192.0.2.1:53");
2✔
947
  const ComboAddress forwardedNS("192.0.2.42:53");
2✔
948

949
  SyncRes::AuthDomain ad;
2✔
950
  ad.d_rdForward = true;
2✔
951
  ad.d_servers.push_back(forwardedNS);
2✔
952
  (*SyncRes::t_sstorage.domainmap)[target] = ad;
2✔
953

954
  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✔
955
    if (address == forwardedNS) {
2!
956
      BOOST_CHECK_EQUAL(sendRDQuery, true);
2✔
957

958
      setLWResult(res, 0, true, false, true);
2✔
959
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
960
      return LWResult::Result::Success;
2✔
961
    }
2✔
962

963
    return LWResult::Result::Timeout;
×
964
  });
2✔
965

966
  vector<DNSRecord> ret;
2✔
967
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
968
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
969
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
970
}
2✔
971

972
BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd_dnssec)
973
{
2✔
974
  std::unique_ptr<SyncRes> sr;
2✔
975
  initSR(sr, true);
2✔
976

977
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
978

979
  primeHints();
2✔
980
  /* signed */
981
  const DNSName target("test.");
2✔
982
  /* unsigned */
983
  const DNSName cnameTarget("cname.");
2✔
984
  testkeysset_t keys;
2✔
985

986
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
987
  luaconfsCopy.dsAnchors.clear();
2✔
988
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
989
  generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
990
  g_luaconfs.setState(luaconfsCopy);
2✔
991

992
  const ComboAddress forwardedNS("192.0.2.42:53");
2✔
993
  size_t queriesCount = 0;
2✔
994

995
  SyncRes::AuthDomain ad;
2✔
996
  ad.d_rdForward = true;
2✔
997
  ad.d_servers.push_back(forwardedNS);
2✔
998
  (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = ad;
2✔
999

1000
  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✔
1001
    queriesCount++;
10✔
1002

1003
    BOOST_CHECK_EQUAL(sendRDQuery, true);
10✔
1004

1005
    if (address != forwardedNS) {
10!
1006
      return LWResult::Result::Timeout;
×
1007
    }
×
1008

1009
    if (type == QType::DS || type == QType::DNSKEY) {
10✔
1010
      return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
8✔
1011
    }
8✔
1012

1013
    if (domain == target && type == QType::A) {
2!
1014

1015
      setLWResult(res, 0, false, false, true);
2✔
1016
      addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
2✔
1017
      addRRSIG(keys, res->d_records, domain, 300);
2✔
1018
      addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
2✔
1019

1020
      return LWResult::Result::Success;
2✔
1021
    }
2✔
1022
    return LWResult::Result::Timeout;
×
1023
  });
2✔
1024

1025
  vector<DNSRecord> ret;
2✔
1026
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1027
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1028
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1029
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
1030
  BOOST_CHECK_EQUAL(queriesCount, 5U);
2✔
1031

1032
  /* again, to test the cache */
1033
  ret.clear();
2✔
1034
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1035
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1036
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1037
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
1038
  BOOST_CHECK_EQUAL(queriesCount, 5U);
2✔
1039
}
2✔
1040

1041
BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord_dnssec)
1042
{
2✔
1043
  std::unique_ptr<SyncRes> sr;
2✔
1044
  initSR(sr, true);
2✔
1045

1046
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1047

1048
  primeHints();
2✔
1049
  /* signed */
1050
  const DNSName parent("test.");
2✔
1051
  const DNSName target1("a.test.");
2✔
1052
  const DNSName target2("b.test.");
2✔
1053

1054
  testkeysset_t keys;
2✔
1055

1056
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1057
  luaconfsCopy.dsAnchors.clear();
2✔
1058
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1059
  generateKeyMaterial(DNSName("test."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1060
  g_luaconfs.setState(luaconfsCopy);
2✔
1061

1062
  const ComboAddress forwardedNS("192.0.2.42:53");
2✔
1063
  size_t queriesCount = 0;
2✔
1064
  size_t DSforParentCount = 0;
2✔
1065

1066
  SyncRes::AuthDomain ad;
2✔
1067
  ad.d_rdForward = false;
2✔
1068
  ad.d_servers.push_back(forwardedNS);
2✔
1069
  (*SyncRes::t_sstorage.domainmap)[DNSName("test.")] = ad;
2✔
1070

1071
  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✔
1072
    queriesCount++;
10✔
1073

1074
    BOOST_CHECK_EQUAL(sendRDQuery, false);
10✔
1075

1076
    if (type == QType::DS && domain == parent) {
10!
1077
      DSforParentCount++;
2✔
1078
    }
2✔
1079
    if (type == QType::DS || type == QType::DNSKEY) {
10✔
1080
      if (domain != parent && domain.isPartOf(parent)) {
6!
1081
        return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false /* no cut / delegation */);
×
1082
      }
×
1083
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6✔
1084
    }
6✔
1085

1086
    if (isRootServer(address)) {
4!
1087
      setLWResult(res, 0, false, false, true);
×
1088
      addRecordToLW(res, parent, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 42);
×
1089
      addRRSIG(keys, res->d_records, g_rootdnsname, 300);
×
1090
      addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1091
    }
×
1092

1093
    if (address != forwardedNS) {
4!
1094
      return LWResult::Result::Timeout;
×
1095
    }
×
1096

1097
    if (domain == target1 && type == QType::A) {
4!
1098

1099
      setLWResult(res, 0, true, false, true);
2✔
1100
      addRecordToLW(res, target1, QType::A, "192.0.2.1");
2✔
1101
      addRRSIG(keys, res->d_records, parent, 300);
2✔
1102

1103
      return LWResult::Result::Success;
2✔
1104
    }
2✔
1105
    if (domain == target2 && type == QType::A) {
2!
1106

1107
      setLWResult(res, 0, true, false, true);
2✔
1108
      addRecordToLW(res, target2, QType::A, "192.0.2.2");
2✔
1109
      addRRSIG(keys, res->d_records, parent, 300);
2✔
1110

1111
      return LWResult::Result::Success;
2✔
1112
    }
2✔
1113

1114
    return LWResult::Result::Timeout;
×
1115
  });
2✔
1116

1117
  vector<DNSRecord> ret;
2✔
1118
  int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
2✔
1119
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1120
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
1121
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1122
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1123
  BOOST_CHECK_EQUAL(DSforParentCount, 1U);
2✔
1124

1125
  /* again, to test the cache */
1126
  ret.clear();
2✔
1127
  res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
2✔
1128
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1129
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
1130
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1131
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1132
  BOOST_CHECK_EQUAL(DSforParentCount, 1U);
2✔
1133

1134
  /* new target should not cause a DS query for test. */
1135
  ret.clear();
2✔
1136
  res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
2✔
1137
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1138
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
1139
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1140
  BOOST_CHECK_EQUAL(queriesCount, 5U);
2✔
1141
  BOOST_CHECK_EQUAL(DSforParentCount, 1U);
2✔
1142
}
2✔
1143

1144
BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd_dnssec_bogus)
1145
{
2✔
1146
  std::unique_ptr<SyncRes> sr;
2✔
1147
  initSR(sr, true);
2✔
1148

1149
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1150

1151
  primeHints();
2✔
1152
  /* signed */
1153
  const DNSName target("test.");
2✔
1154
  /* signed */
1155
  const DNSName cnameTarget("cname.");
2✔
1156
  testkeysset_t keys;
2✔
1157

1158
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1159
  luaconfsCopy.dsAnchors.clear();
2✔
1160
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1161
  generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1162
  generateKeyMaterial(cnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1163
  g_luaconfs.setState(luaconfsCopy);
2✔
1164

1165
  const ComboAddress forwardedNS("192.0.2.42:53");
2✔
1166
  size_t queriesCount = 0;
2✔
1167

1168
  SyncRes::AuthDomain ad;
2✔
1169
  ad.d_rdForward = true;
2✔
1170
  ad.d_servers.push_back(forwardedNS);
2✔
1171
  (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = ad;
2✔
1172

1173
  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✔
1174
    queriesCount++;
10✔
1175

1176
    BOOST_CHECK_EQUAL(sendRDQuery, true);
10✔
1177

1178
    if (address != forwardedNS) {
10!
1179
      return LWResult::Result::Timeout;
×
1180
    }
×
1181

1182
    if (type == QType::DS || type == QType::DNSKEY) {
10✔
1183
      return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
8✔
1184
    }
8✔
1185

1186
    if (domain == target && type == QType::A) {
2!
1187

1188
      setLWResult(res, 0, false, false, true);
2✔
1189
      addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
2✔
1190
      addRRSIG(keys, res->d_records, domain, 300);
2✔
1191
      addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
2✔
1192
      /* no RRSIG in a signed zone, Bogus ! */
1193

1194
      return LWResult::Result::Success;
2✔
1195
    }
2✔
1196
    return LWResult::Result::Timeout;
×
1197
  });
2✔
1198

1199
  vector<DNSRecord> ret;
2✔
1200
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1201
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1202
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
2✔
1203
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
1204
  BOOST_CHECK_EQUAL(queriesCount, 5U);
2✔
1205

1206
  /* again, to test the cache */
1207
  ret.clear();
2✔
1208
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1209
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1210
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
2✔
1211
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
1212
  BOOST_CHECK_EQUAL(queriesCount, 5U);
2✔
1213
}
2✔
1214

1215
BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd_dnssec_nodata_bogus)
1216
{
2✔
1217
  std::unique_ptr<SyncRes> sr;
2✔
1218
  initSR(sr, true);
2✔
1219

1220
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1221

1222
  primeHints();
2✔
1223
  const DNSName target("powerdns.com.");
2✔
1224
  testkeysset_t keys;
2✔
1225

1226
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1227
  luaconfsCopy.dsAnchors.clear();
2✔
1228
  generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1229
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1230
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1231
  g_luaconfs.setState(luaconfsCopy);
2✔
1232

1233
  const ComboAddress forwardedNS("192.0.2.42:53");
2✔
1234
  SyncRes::AuthDomain ad;
2✔
1235
  ad.d_rdForward = true;
2✔
1236
  ad.d_servers.push_back(forwardedNS);
2✔
1237
  (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = ad;
2✔
1238

1239
  size_t queriesCount = 0;
2✔
1240

1241
  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✔
1242
    queriesCount++;
8✔
1243

1244
    BOOST_CHECK_EQUAL(sendRDQuery, true);
8✔
1245

1246
    if (address != forwardedNS) {
8!
1247
      return LWResult::Result::Timeout;
×
1248
    }
×
1249

1250
    if (type == QType::DS || type == QType::DNSKEY) {
8✔
1251
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4✔
1252
    }
4✔
1253

1254
    setLWResult(res, 0, false, false, true);
4✔
1255
    return LWResult::Result::Success;
4✔
1256
  });
8✔
1257

1258
  vector<DNSRecord> ret;
2✔
1259
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1260
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1261
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusMissingNegativeIndication);
2✔
1262
  BOOST_REQUIRE_EQUAL(ret.size(), 0U);
2✔
1263
  /* com|NS, powerdns.com|NS, powerdns.com|A */
1264
  BOOST_CHECK_EQUAL(queriesCount, 3U);
2✔
1265

1266
  /* again, to test the cache */
1267
  ret.clear();
2✔
1268
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1269
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1270
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusMissingNegativeIndication);
2✔
1271
  BOOST_REQUIRE_EQUAL(ret.size(), 0U);
2✔
1272
  /* we don't store empty results */
1273
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1274
}
2✔
1275

1276
BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd_dnssec_cname_wildcard_expanded)
1277
{
2✔
1278
  std::unique_ptr<SyncRes> testSR;
2✔
1279
  initSR(testSR, true);
2✔
1280

1281
  setDNSSECValidation(testSR, DNSSECMode::ValidateAll);
2✔
1282

1283
  primeHints();
2✔
1284
  /* unsigned */
1285
  const DNSName target("test.");
2✔
1286
  /* signed */
1287
  const DNSName cnameTarget("cname.");
2✔
1288
  testkeysset_t keys;
2✔
1289

1290
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1291
  luaconfsCopy.dsAnchors.clear();
2✔
1292
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1293
  generateKeyMaterial(cnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1294
  g_luaconfs.setState(luaconfsCopy);
2✔
1295

1296
  const ComboAddress forwardedNS("192.0.2.42:53");
2✔
1297
  size_t queriesCount = 0;
2✔
1298

1299
  SyncRes::AuthDomain authDomain;
2✔
1300
  authDomain.d_rdForward = true;
2✔
1301
  authDomain.d_servers.push_back(forwardedNS);
2✔
1302
  (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = authDomain;
2✔
1303

1304
  testSR->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✔
1305
    queriesCount++;
10✔
1306

1307
    BOOST_CHECK_EQUAL(sendRDQuery, true);
10✔
1308

1309
    if (address != forwardedNS) {
10!
1310
      return LWResult::Result::Timeout;
×
1311
    }
×
1312

1313
    if (type == QType::DS || type == QType::DNSKEY) {
10✔
1314
      return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
8✔
1315
    }
8✔
1316

1317
    if (domain == target && type == QType::A) {
2!
1318

1319
      setLWResult(res, 0, false, false, true);
2✔
1320
      addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
2✔
1321
      addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
2✔
1322
      /* the RRSIG proves that the cnameTarget was expanded from a wildcard */
1323
      addRRSIG(keys, res->d_records, cnameTarget, 300, false, boost::none, DNSName("*"));
2✔
1324
      /* we need to add the proof that this name does not exist, so the wildcard may apply */
1325
      addNSECRecordToLW(DNSName("cnamd."), DNSName("cnamf."), {QType::A, QType::NSEC, QType::RRSIG}, 60, res->d_records);
2✔
1326
      addRRSIG(keys, res->d_records, cnameTarget, 300);
2✔
1327

1328
      return LWResult::Result::Success;
2✔
1329
    }
2✔
1330
    return LWResult::Result::Timeout;
×
1331
  });
2✔
1332

1333
  vector<DNSRecord> ret;
2✔
1334
  int res = testSR->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1335
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1336
  BOOST_CHECK_EQUAL(testSR->getValidationState(), vState::Insecure);
2✔
1337
  BOOST_REQUIRE_EQUAL(ret.size(), 5U);
2✔
1338
  BOOST_CHECK_EQUAL(queriesCount, 5U);
2✔
1339

1340
  /* again, to test the cache */
1341
  ret.clear();
2✔
1342
  res = testSR->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1343
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1344
  BOOST_CHECK_EQUAL(testSR->getValidationState(), vState::Insecure);
2✔
1345
  BOOST_REQUIRE_EQUAL(ret.size(), 5U);
2✔
1346
  BOOST_CHECK_EQUAL(queriesCount, 5U);
2✔
1347
}
2✔
1348

1349
BOOST_AUTO_TEST_CASE(test_auth_zone_oob)
1350
{
2✔
1351
  std::unique_ptr<SyncRes> sr;
2✔
1352
  initSR(sr, true);
2✔
1353

1354
  primeHints();
2✔
1355

1356
  size_t queriesCount = 0;
2✔
1357
  const DNSName target("test.xx.");
2✔
1358
  const ComboAddress targetAddr("127.0.0.1");
2✔
1359
  const DNSName authZone("test.xx");
2✔
1360

1361
  SyncRes::AuthDomain ad;
2✔
1362
  DNSRecord dr;
2✔
1363

1364
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1365
  dr.d_name = target;
2✔
1366
  dr.d_type = QType::A;
2✔
1367
  dr.d_ttl = 1800;
2✔
1368
  dr.setContent(std::make_shared<ARecordContent>(targetAddr));
2✔
1369
  ad.d_records.insert(dr);
2✔
1370

1371
  (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2✔
1372

1373
  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✔
1374
    queriesCount++;
×
1375
    return LWResult::Result::Timeout;
×
1376
  });
×
1377

1378
  vector<DNSRecord> ret;
2✔
1379
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1380
  BOOST_CHECK_EQUAL(res, 0);
2✔
1381
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1382
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1383
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
1384
  BOOST_CHECK(sr->wasOutOfBand());
2✔
1385
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
2✔
1386

1387
  /* a second time, to check that the OOB flag is set when the query cache is used */
1388
  ret.clear();
2✔
1389
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1390
  BOOST_CHECK_EQUAL(res, 0);
2✔
1391
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1392
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1393
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
1394
  BOOST_CHECK(sr->wasOutOfBand());
2✔
1395
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
2✔
1396

1397
  /* a third time, to check that the validation is disabled when the OOB flag is set */
1398
  ret.clear();
2✔
1399
  sr->setDNSSECValidationRequested(true);
2✔
1400
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1401
  BOOST_CHECK_EQUAL(res, 0);
2✔
1402
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1403
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1404
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
1405
  BOOST_CHECK(sr->wasOutOfBand());
2✔
1406
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
2✔
1407
}
2✔
1408

1409
BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname)
1410
{
2✔
1411
  std::unique_ptr<SyncRes> sr;
2✔
1412
  initSR(sr, true);
2✔
1413

1414
  primeHints();
2✔
1415

1416
  size_t queriesCount = 0;
2✔
1417
  const DNSName target("cname.test.xx.");
2✔
1418
  const DNSName targetCname("cname-target.test.xx.");
2✔
1419
  const ComboAddress targetCnameAddr("127.0.0.1");
2✔
1420
  const DNSName authZone("test.xx");
2✔
1421

1422
  SyncRes::AuthDomain ad;
2✔
1423
  DNSRecord dr;
2✔
1424

1425
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1426
  dr.d_name = target;
2✔
1427
  dr.d_type = QType::CNAME;
2✔
1428
  dr.d_ttl = 1800;
2✔
1429
  dr.setContent(std::make_shared<CNAMERecordContent>(targetCname));
2✔
1430
  ad.d_records.insert(dr);
2✔
1431

1432
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1433
  dr.d_name = targetCname;
2✔
1434
  dr.d_type = QType::A;
2✔
1435
  dr.d_ttl = 1800;
2✔
1436
  dr.setContent(std::make_shared<ARecordContent>(targetCnameAddr));
2✔
1437
  ad.d_records.insert(dr);
2✔
1438

1439
  (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2✔
1440

1441
  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✔
1442
    queriesCount++;
×
1443
    return LWResult::Result::Timeout;
×
1444
  });
×
1445

1446
  vector<DNSRecord> ret;
2✔
1447
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1448
  BOOST_CHECK_EQUAL(res, 0);
2✔
1449
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1450
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1451
  BOOST_CHECK(ret[1].d_type == QType::A);
2✔
1452
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
1453
  BOOST_CHECK(sr->wasOutOfBand());
2✔
1454
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
2✔
1455

1456
  /* a second time, to check that the OOB flag is set when the query cache is used */
1457
  ret.clear();
2✔
1458
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1459
  BOOST_CHECK_EQUAL(res, 0);
2✔
1460
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1461
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1462
  BOOST_CHECK(ret[1].d_type == QType::A);
2✔
1463
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
1464
  BOOST_CHECK(sr->wasOutOfBand());
2✔
1465
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
2✔
1466

1467
  /* a third time, to check that the validation is disabled when the OOB flag is set */
1468
  ret.clear();
2✔
1469
  sr->setDNSSECValidationRequested(true);
2✔
1470
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1471
  BOOST_CHECK_EQUAL(res, 0);
2✔
1472
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1473
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1474
  BOOST_CHECK(ret[1].d_type == QType::A);
2✔
1475
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
1476
  BOOST_CHECK(sr->wasOutOfBand());
2✔
1477
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Indeterminate);
2✔
1478
}
2✔
1479

1480
BOOST_AUTO_TEST_CASE(test_auth_zone)
1481
{
2✔
1482
  std::unique_ptr<SyncRes> sr;
2✔
1483
  initSR(sr);
2✔
1484

1485
  primeHints();
2✔
1486

1487
  size_t queriesCount = 0;
2✔
1488
  const DNSName target("powerdns.com.");
2✔
1489
  const ComboAddress addr("192.0.2.5");
2✔
1490

1491
  SyncRes::AuthDomain ad;
2✔
1492
  ad.d_name = target;
2✔
1493
  DNSRecord dr;
2✔
1494
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1495
  dr.d_name = target;
2✔
1496
  dr.d_type = QType::SOA;
2✔
1497
  dr.d_ttl = 3600;
2✔
1498
  dr.setContent(std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"));
2✔
1499
  ad.d_records.insert(dr);
2✔
1500

1501
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1502
  dr.d_name = target;
2✔
1503
  dr.d_type = QType::A;
2✔
1504
  dr.d_ttl = 3600;
2✔
1505
  dr.setContent(std::make_shared<ARecordContent>(addr));
2✔
1506
  ad.d_records.insert(dr);
2✔
1507

1508
  auto map = std::make_shared<SyncRes::domainmap_t>();
2✔
1509
  (*map)[target] = ad;
2✔
1510
  SyncRes::setDomainMap(map);
2✔
1511

1512
  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✔
1513
    queriesCount++;
×
1514
    setLWResult(res, 0, true, false, true);
×
1515
    addRecordToLW(res, domain, QType::A, "192.0.2.42");
×
1516
    return LWResult::Result::Success;
×
1517
  });
×
1518

1519
  vector<DNSRecord> ret;
2✔
1520
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1521
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1522
  BOOST_CHECK_EQUAL(ret.size(), 1U);
2✔
1523
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1524
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
2✔
1525
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
1526
}
2✔
1527

1528
BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob)
1529
{
2✔
1530
  std::unique_ptr<SyncRes> sr;
2✔
1531
  initSR(sr);
2✔
1532

1533
  primeHints();
2✔
1534

1535
  size_t queriesCount = 0;
2✔
1536
  const DNSName target("powerdns.com.");
2✔
1537
  const DNSName authZone("internal.powerdns.com.");
2✔
1538
  const ComboAddress addr("192.0.2.5");
2✔
1539

1540
  SyncRes::AuthDomain ad;
2✔
1541
  ad.d_name = authZone;
2✔
1542
  DNSRecord dr;
2✔
1543
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1544
  dr.d_name = authZone;
2✔
1545
  dr.d_type = QType::SOA;
2✔
1546
  dr.d_ttl = 3600;
2✔
1547
  dr.setContent(std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"));
2✔
1548
  ad.d_records.insert(dr);
2✔
1549

1550
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1551
  dr.d_name = authZone;
2✔
1552
  dr.d_type = QType::A;
2✔
1553
  dr.d_ttl = 3600;
2✔
1554
  dr.setContent(std::make_shared<ARecordContent>(addr));
2✔
1555
  ad.d_records.insert(dr);
2✔
1556

1557
  auto map = std::make_shared<SyncRes::domainmap_t>();
2✔
1558
  (*map)[authZone] = ad;
2✔
1559
  SyncRes::setDomainMap(map);
2✔
1560

1561
  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✔
1562
    queriesCount++;
2✔
1563

1564
    if (domain == target) {
2!
1565
      setLWResult(res, 0, true, false, true);
2✔
1566
      addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
2✔
1567
      return LWResult::Result::Success;
2✔
1568
    }
2✔
1569

1570
    return LWResult::Result::Timeout;
×
1571
  });
2✔
1572

1573
  vector<DNSRecord> ret;
2✔
1574
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1575
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1576
  BOOST_CHECK_EQUAL(ret.size(), 2U);
2✔
1577
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1578
  BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
2✔
1579
  BOOST_CHECK(ret[1].d_type == QType::A);
2✔
1580
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
2✔
1581
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
1582
}
2✔
1583

1584
BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb)
1585
{
2✔
1586
  std::unique_ptr<SyncRes> sr;
2✔
1587
  initSR(sr);
2✔
1588

1589
  primeHints();
2✔
1590

1591
  size_t queriesCount = 0;
2✔
1592
  const DNSName target("powerdns.com.");
2✔
1593
  const DNSName externalCNAME("www.open-xchange.com.");
2✔
1594
  const ComboAddress addr("192.0.2.5");
2✔
1595

1596
  SyncRes::AuthDomain ad;
2✔
1597
  ad.d_name = target;
2✔
1598
  DNSRecord dr;
2✔
1599
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1600
  dr.d_name = target;
2✔
1601
  dr.d_type = QType::SOA;
2✔
1602
  dr.d_ttl = 3600;
2✔
1603
  dr.setContent(std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"));
2✔
1604
  ad.d_records.insert(dr);
2✔
1605

1606
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1607
  dr.d_name = target;
2✔
1608
  dr.d_type = QType::CNAME;
2✔
1609
  dr.d_ttl = 3600;
2✔
1610
  dr.setContent(std::make_shared<CNAMERecordContent>(externalCNAME));
2✔
1611
  ad.d_records.insert(dr);
2✔
1612

1613
  auto map = std::make_shared<SyncRes::domainmap_t>();
2✔
1614
  (*map)[target] = ad;
2✔
1615
  SyncRes::setDomainMap(map);
2✔
1616

1617
  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✔
1618
    queriesCount++;
2✔
1619

1620
    if (domain == externalCNAME) {
2!
1621
      setLWResult(res, 0, true, false, true);
2✔
1622
      addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
2✔
1623
      return LWResult::Result::Success;
2✔
1624
    }
2✔
1625

1626
    return LWResult::Result::Timeout;
×
1627
  });
2✔
1628

1629
  vector<DNSRecord> ret;
2✔
1630
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1631
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1632
  BOOST_CHECK_EQUAL(ret.size(), 2U);
2✔
1633
  BOOST_CHECK(ret[0].d_type == QType::CNAME);
2✔
1634
  BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
2✔
1635
  BOOST_CHECK(ret[1].d_type == QType::A);
2✔
1636
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
2✔
1637
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
1638
}
2✔
1639

1640
BOOST_AUTO_TEST_CASE(test_auth_zone_ds)
1641
{
2✔
1642
  // #10189
1643
  std::unique_ptr<SyncRes> sr;
2✔
1644
  initSR(sr);
2✔
1645

1646
  primeHints();
2✔
1647

1648
  size_t queriesCount = 0;
2✔
1649
  const DNSName target("powerdns.corp");
2✔
1650
  const ComboAddress addr("192.0.2.5");
2✔
1651

1652
  SyncRes::AuthDomain ad;
2✔
1653
  ad.d_name = target;
2✔
1654
  DNSRecord dr;
2✔
1655
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1656
  dr.d_name = target;
2✔
1657
  dr.d_type = QType::SOA;
2✔
1658
  dr.d_ttl = 3600;
2✔
1659
  dr.setContent(std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.corp. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600"));
2✔
1660
  ad.d_records.insert(dr);
2✔
1661

1662
  dr.d_place = DNSResourceRecord::ANSWER;
2✔
1663
  dr.d_name = target;
2✔
1664
  dr.d_type = QType::A;
2✔
1665
  dr.d_ttl = 3600;
2✔
1666
  dr.setContent(std::make_shared<ARecordContent>(addr));
2✔
1667
  ad.d_records.insert(dr);
2✔
1668

1669
  auto map = std::make_shared<SyncRes::domainmap_t>();
2✔
1670
  (*map)[target] = ad;
2✔
1671
  SyncRes::setDomainMap(map);
2✔
1672

1673
  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✔
1674
    queriesCount++;
2✔
1675
    if (type != QType::DS) {
2!
1676
      setLWResult(res, 0, true, false, true);
×
1677
      addRecordToLW(res, domain, QType::A, "192.0.2.42");
×
1678
      return LWResult::Result::Success;
×
1679
    }
×
1680
    else {
2✔
1681
      setLWResult(res, RCode::NXDomain, true, false, true);
2✔
1682
      addRecordToLW(res, domain, QType::SOA, "a.root-servers.net. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
1683
      return LWResult::Result::Success;
2✔
1684
    }
2✔
1685
  });
2✔
1686

1687
  vector<DNSRecord> ret;
2✔
1688
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1689
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1690
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1691
  BOOST_REQUIRE(ret[0].d_type == QType::A);
2✔
1692
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
2✔
1693
  BOOST_CHECK_EQUAL(queriesCount, 0U);
2✔
1694

1695
  ret.clear();
2✔
1696
  res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
1697
  BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2✔
1698
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1699
  BOOST_CHECK(ret[0].d_type == QType::SOA);
2✔
1700
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
1701

1702
  ret.clear();
2✔
1703
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1704
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1705
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1706
  BOOST_REQUIRE(ret[0].d_type == QType::A);
2✔
1707
  BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
2✔
1708
  BOOST_CHECK_EQUAL(queriesCount, 1U);
2✔
1709
}
2✔
1710

1711
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