• 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

80.24
/pdns/recursordist/test-syncres_cc6.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_cc6)
10

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

16
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
17

18
  primeHints();
2✔
19
  const DNSName target("www.powerdns.com.");
2✔
20
  testkeysset_t keys;
2✔
21

22
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
23
  luaconfsCopy.dsAnchors.clear();
2✔
24
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
25
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
26
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
27

28
  g_luaconfs.setState(luaconfsCopy);
2✔
29

30
  size_t queriesCount = 0;
2✔
31
  size_t dsQueriesCount = 0;
2✔
32

33
  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✔
34
    queriesCount++;
16✔
35

36
    if (type == QType::DS) {
16✔
37
      DNSName auth(domain);
4✔
38
      auth.chopOff();
4✔
39
      dsQueriesCount++;
4✔
40

41
      if (domain == target) {
4!
42
        if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false) == LWResult::Result::Timeout) {
×
43
          return LWResult::Result::Timeout;
×
44
        }
×
45
        return LWResult::Result::Success;
×
46
      }
×
47

48
      setLWResult(res, 0, true, false, true);
4✔
49
      addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
4✔
50
      addRRSIG(keys, res->d_records, auth, 300);
4✔
51
      return LWResult::Result::Success;
4✔
52
    }
4✔
53
    if (type == QType::DNSKEY) {
12✔
54
      setLWResult(res, 0, true, false, true);
6✔
55
      addDNSKEY(keys, domain, 300, res->d_records);
6✔
56
      addRRSIG(keys, res->d_records, domain, 300);
6✔
57
      return LWResult::Result::Success;
6✔
58
    }
6✔
59
    {
6✔
60
      if (isRootServer(address)) {
6✔
61
        setLWResult(res, 0, false, false, true);
2✔
62
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
63
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
64
        /* No DS on referral, and no denial of the DS either */
65
        return LWResult::Result::Success;
2✔
66
      }
2✔
67
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
68
        if (domain == DNSName("com.")) {
2!
69
          setLWResult(res, 0, true, false, true);
×
70
          addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
×
71
          addRRSIG(keys, res->d_records, domain, 300);
×
72
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
73
          addRRSIG(keys, res->d_records, domain, 300);
×
74
        }
×
75
        else {
2✔
76
          setLWResult(res, 0, false, false, true);
2✔
77
          addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
78
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
79
          /* No DS on referral, and no denial of the DS either */
80
        }
2✔
81
        return LWResult::Result::Success;
2✔
82
      }
2✔
83
      if (address == ComboAddress("192.0.2.2:53")) {
2!
84
        setLWResult(res, 0, true, false, true);
2✔
85
        if (type == QType::NS) {
2!
86
          if (domain == DNSName("powerdns.com.")) {
×
87
            addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
88
            addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
×
89
            addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
×
90
            addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
×
91
          }
×
92
          else {
×
93
            addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
94
            addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
×
95
            addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), {QType::A, QType::NSEC, QType::RRSIG}, 600, res->d_records);
×
96
            addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
×
97
          }
×
98
        }
×
99
        else {
2✔
100
          addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
101
          addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
2✔
102
        }
2✔
103

104
        return LWResult::Result::Success;
2✔
105
      }
2✔
106
    }
2✔
107

108
    return LWResult::Result::Timeout;
×
109
  });
2✔
110

111
  vector<DNSRecord> ret;
2✔
112
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
113
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
114
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
115
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
116
  BOOST_CHECK_EQUAL(queriesCount, 8U);
2✔
117
  BOOST_CHECK_EQUAL(dsQueriesCount, 2U);
2✔
118

119
  /* again, to test the cache */
120
  ret.clear();
2✔
121
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
122
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
123
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
124
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
125
  BOOST_CHECK_EQUAL(queriesCount, 8U);
2✔
126
  BOOST_CHECK_EQUAL(dsQueriesCount, 2U);
2✔
127
}
2✔
128

129
BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop)
130
{
2✔
131
  /* the DS for www.powerdns.com. is signed by www.powerdns.com. */
132
  std::unique_ptr<SyncRes> sr;
2✔
133
  initSR(sr, true);
2✔
134

135
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
136

137
  primeHints();
2✔
138
  const DNSName target("www.powerdns.com.");
2✔
139
  testkeysset_t keys;
2✔
140

141
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
142
  luaconfsCopy.dsAnchors.clear();
2✔
143
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
144
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
145
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
146
  generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
147

148
  g_luaconfs.setState(luaconfsCopy);
2✔
149

150
  size_t queriesCount = 0;
2✔
151

152
  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✔
153
    queriesCount++;
16✔
154

155
    if (type == QType::DS) {
16✔
156
      DNSName auth(domain);
4✔
157
      auth.chopOff();
4✔
158

159
      setLWResult(res, 0, true, false, true);
4✔
160
      if (domain == target) {
4✔
161
        addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
2✔
162
        addRRSIG(keys, res->d_records, domain, 300);
2✔
163
      }
2✔
164
      else {
2✔
165
        addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
2✔
166
        addRRSIG(keys, res->d_records, auth, 300);
2✔
167
      }
2✔
168
      return LWResult::Result::Success;
4✔
169
    }
4✔
170
    if (type == QType::DNSKEY) {
12✔
171
      setLWResult(res, 0, true, false, true);
6✔
172
      addDNSKEY(keys, domain, 300, res->d_records);
6✔
173
      addRRSIG(keys, res->d_records, domain, 300);
6✔
174
      return LWResult::Result::Success;
6✔
175
    }
6✔
176
    {
6✔
177
      if (isRootServer(address)) {
6✔
178
        setLWResult(res, 0, false, false, true);
2✔
179
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
180
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
181
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
182
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
183
        return LWResult::Result::Success;
2✔
184
      }
2✔
185
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
186
        if (domain == DNSName("com.")) {
2!
187
          setLWResult(res, 0, true, false, true);
×
188
          addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
×
189
          addRRSIG(keys, res->d_records, domain, 300);
×
190
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
191
          addRRSIG(keys, res->d_records, domain, 300);
×
192
        }
×
193
        else {
2✔
194
          setLWResult(res, 0, false, false, true);
2✔
195
          addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
196
          /* no DS */
197
          addNSECRecordToLW(domain, DNSName("z.powerdns.com."), {QType::NS}, 600, res->d_records);
2✔
198
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
199
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
200
        }
2✔
201
        return LWResult::Result::Success;
2✔
202
      }
2✔
203
      if (address == ComboAddress("192.0.2.2:53")) {
2!
204
        if (type == QType::NS) {
2!
205
          if (domain == DNSName("powerdns.com.")) {
×
206
            setLWResult(res, RCode::Refused, false, false, true);
×
207
          }
×
208
          else {
×
209
            setLWResult(res, 0, true, false, true);
×
210
            addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
211
            addRRSIG(keys, res->d_records, domain, 300);
×
212
            addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
×
213
            addRRSIG(keys, res->d_records, domain, 300);
×
214
          }
×
215
        }
×
216
        else {
2✔
217
          setLWResult(res, 0, true, false, true);
2✔
218
          addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
219
          addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
2✔
220
        }
2✔
221

222
        return LWResult::Result::Success;
2✔
223
      }
2✔
224
    }
2✔
225

226
    return LWResult::Result::Timeout;
×
227
  });
2✔
228

229
  vector<DNSRecord> ret;
2✔
230
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
231
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
232
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusSelfSignedDS);
2✔
233
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
234
  BOOST_CHECK_EQUAL(queriesCount, 8U);
2✔
235

236
  /* again, to test the cache */
237
  ret.clear();
2✔
238
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
239
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
240
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusSelfSignedDS);
2✔
241
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
242
  BOOST_CHECK_EQUAL(queriesCount, 8U);
2✔
243
}
2✔
244

245
BOOST_AUTO_TEST_CASE(test_dnssec_ds_denial_loop)
246
{
2✔
247
  /* The denial of the DS sub.insecure.powerdns comes from the child zone, so is signed by sub.insecure.powerdns.
248
     but sub.insecure.powerdns. is actually insecure (no DS for insecure.powerdns.), both sub.insecure.powerdns AND
249
     insecure.powerdns are hosted on the same server but because of a misconfiguration, the server serves DS queries
250
     for the sub.insecure.powerdns from the _child_ side.
251
  */
252
  std::unique_ptr<SyncRes> sr;
2✔
253
  initSR(sr, true);
2✔
254

255
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
256

257
  primeHints();
2✔
258
  const DNSName target("sub.insecure.powerdns.");
2✔
259
  testkeysset_t keys;
2✔
260

261
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
262
  luaconfsCopy.dsAnchors.clear();
2✔
263
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
264
  generateKeyMaterial(DNSName("powerdns."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
265
  generateKeyMaterial(DNSName("sub.insecure.powerdns."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
266

267
  g_luaconfs.setState(luaconfsCopy);
2✔
268

269
  size_t queriesCount = 0;
2✔
270

271
  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✔
272
    queriesCount++;
12✔
273

274
    if (type == QType::DNSKEY || (type == QType::DS && domain != target)) {
12!
275
      DNSName auth(domain);
6✔
276
      return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, true);
6✔
277
    }
6✔
278
    {
6✔
279
      if (isRootServer(address)) {
6✔
280
        setLWResult(res, 0, false, false, true);
2✔
281
        addRecordToLW(res, "powerdns.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
282
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
283
        addDS(DNSName("powerdns."), 300, res->d_records, keys);
2✔
284
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
285
        return LWResult::Result::Success;
2✔
286
      }
2✔
287
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
288
        setLWResult(res, 0, false, false, true);
2✔
289
        addRecordToLW(res, "insecure.powerdns.", QType::NS, "ns1.insecure.powerdns.", DNSResourceRecord::AUTHORITY, 3600);
2✔
290
        /* no DS */
291
        addNSECRecordToLW(domain, DNSName("z.powerdns."), {QType::NS}, 600, res->d_records);
2✔
292
        addRRSIG(keys, res->d_records, DNSName("powerdns."), 300);
2✔
293
        addRecordToLW(res, "ns1.insecure.powerdns.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
294
        return LWResult::Result::Success;
2✔
295
      }
2✔
296
      if (address == ComboAddress("192.0.2.2:53")) {
2!
297
        if (type == QType::DS && domain == target) {
2!
298
          /* in that case we return a NODATA signed by the DNSKEY of the child zone */
299
          setLWResult(res, 0, true, false, true);
2✔
300
          addRecordToLW(res, DNSName("sub.insecure.powerdns."), QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2✔
301
          addRRSIG(keys, res->d_records, DNSName("sub.insecure.powerdns."), 300);
2✔
302
          addNSECRecordToLW(domain, DNSName("+") + domain, {QType::RRSIG, QType::NS, QType::SOA, QType::A}, 600, res->d_records);
2✔
303
          addRRSIG(keys, res->d_records, DNSName("sub.insecure.powerdns."), 300);
2✔
304
          return LWResult::Result::Success;
2✔
305
        }
2✔
306
      }
2✔
307
    }
2✔
308

309
    return LWResult::Result::Timeout;
×
310
  });
2✔
311

312
  vector<DNSRecord> ret;
2✔
313
  int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
314
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
315
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
316
  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
2✔
317
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
318

319
  /* again, to test the cache */
320
  ret.clear();
2✔
321
  res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
322
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
323
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
324
  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
2✔
325
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
326
}
2✔
327

328
BOOST_AUTO_TEST_CASE(test_dnssec_ds_root)
329
{
2✔
330
  std::unique_ptr<SyncRes> sr;
2✔
331
  initSR(sr, true);
2✔
332

333
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
334

335
  primeHints();
2✔
336
  const DNSName target(".");
2✔
337
  testkeysset_t keys;
2✔
338

339
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
340
  luaconfsCopy.dsAnchors.clear();
2✔
341
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
342

343
  g_luaconfs.setState(luaconfsCopy);
2✔
344

345
  size_t queriesCount = 0;
2✔
346

347
  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✔
348
    queriesCount++;
4✔
349

350
    if (type == QType::DS) {
4✔
351
      setLWResult(res, 0, true, false, true);
2✔
352
      addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
353
      addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
354
      addNSECRecordToLW(domain, DNSName("aaa."), {QType::DNSKEY, QType::SOA, QType::NS, QType::NSEC, QType::RRSIG}, 600, res->d_records);
2✔
355
      addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
356
      return LWResult::Result::Success;
2✔
357
    }
2✔
358
    if (type == QType::DNSKEY) {
2!
359
      setLWResult(res, 0, true, false, true);
2✔
360
      addDNSKEY(keys, domain, 300, res->d_records);
2✔
361
      addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
362
      return LWResult::Result::Success;
2✔
363
    }
2✔
364

365
    return LWResult::Result::Timeout;
×
366
  });
2✔
367

368
  vector<DNSRecord> ret;
2✔
369
  int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
370
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
371
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
372
  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
2✔
373
  BOOST_CHECK_EQUAL(queriesCount, 2U);
2✔
374

375
  /* again, to test the cache */
376
  ret.clear();
2✔
377
  res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
378
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
379
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
380
  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
2✔
381
  BOOST_CHECK_EQUAL(queriesCount, 2U);
2✔
382
}
2✔
383

384
BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child)
385
{
2✔
386
  /* check that we don't accept a signer below us */
387
  std::unique_ptr<SyncRes> sr;
2✔
388
  initSR(sr, true);
2✔
389

390
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
391

392
  primeHints();
2✔
393
  const DNSName target("www.powerdns.com.");
2✔
394
  testkeysset_t keys;
2✔
395

396
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
397
  luaconfsCopy.dsAnchors.clear();
2✔
398
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
399
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
400
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
401
  generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
402
  generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
403

404
  g_luaconfs.setState(luaconfsCopy);
2✔
405

406
  size_t queriesCount = 0;
2✔
407

408
  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✔
409
    queriesCount++;
16✔
410

411
    if (type == QType::DS) {
16✔
412
      DNSName auth(domain);
2✔
413
      auth.chopOff();
2✔
414

415
      setLWResult(res, 0, true, false, true);
2✔
416
      addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
2✔
417
      addRRSIG(keys, res->d_records, auth, 300);
2✔
418
      return LWResult::Result::Success;
2✔
419
    }
2✔
420
    if (type == QType::DNSKEY) {
14✔
421
      setLWResult(res, 0, true, false, true);
8✔
422
      addDNSKEY(keys, domain, 300, res->d_records);
8✔
423
      if (domain == DNSName("www.powerdns.com.")) {
8✔
424
        addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
2✔
425
      }
2✔
426
      else {
6✔
427
        addRRSIG(keys, res->d_records, domain, 300);
6✔
428
      }
6✔
429
      return LWResult::Result::Success;
8✔
430
    }
8✔
431
    {
6✔
432
      if (isRootServer(address)) {
6✔
433
        setLWResult(res, 0, false, false, true);
2✔
434
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
435
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
436
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
437
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
438
        return LWResult::Result::Success;
2✔
439
      }
2✔
440
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
441
        if (domain == DNSName("com.")) {
2!
442
          setLWResult(res, 0, true, false, true);
×
443
          addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
×
444
          addRRSIG(keys, res->d_records, domain, 300);
×
445
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
446
          addRRSIG(keys, res->d_records, domain, 300);
×
447
        }
×
448
        else {
2✔
449
          setLWResult(res, 0, false, false, true);
2✔
450
          addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
451
          addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
2✔
452
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
453
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
454
        }
2✔
455
        return LWResult::Result::Success;
2✔
456
      }
2✔
457
      if (address == ComboAddress("192.0.2.2:53")) {
2!
458
        if (type == QType::NS) {
2!
459
          setLWResult(res, 0, true, false, true);
×
460
          addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
461
          addRRSIG(keys, res->d_records, domain, 300);
×
462
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
×
463
          addRRSIG(keys, res->d_records, domain, 300);
×
464
        }
×
465
        else {
2✔
466
          setLWResult(res, 0, true, false, true);
2✔
467
          addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
468
          addRRSIG(keys, res->d_records, domain, 300);
2✔
469
        }
2✔
470

471
        return LWResult::Result::Success;
2✔
472
      }
2✔
473
    }
2✔
474

475
    return LWResult::Result::Timeout;
×
476
  });
2✔
477

478
  vector<DNSRecord> ret;
2✔
479
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
480
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
481
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidRRSIG);
2✔
482
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
483
  BOOST_CHECK_EQUAL(queriesCount, 8U);
2✔
484

485
  /* again, to test the cache */
486
  ret.clear();
2✔
487
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
488
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
489
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidRRSIG);
2✔
490
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
491
  BOOST_CHECK_EQUAL(queriesCount, 8U);
2✔
492
}
2✔
493

494
BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_unpublished)
495
{
2✔
496
  /* check that we properly handle an insecure (no DS) but signed zone whose DNSKEY is not published (so NODATA) */
497
  std::unique_ptr<SyncRes> sr;
2✔
498
  initSR(sr, true);
2✔
499

500
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
501

502
  primeHints();
2✔
503
  const DNSName target("unpublished.com.");
2✔
504
  testkeysset_t keys;
2✔
505

506
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
507
  luaconfsCopy.dsAnchors.clear();
2✔
508
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
509
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
510
  generateKeyMaterial(DNSName("unpublished.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
511

512
  g_luaconfs.setState(luaconfsCopy);
2✔
513

514
  size_t queriesCount = 0;
2✔
515

516
  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✔
517
    queriesCount++;
12✔
518

519
    if (type == QType::DS) {
12✔
520
      if (domain == target) {
2!
521
        auto auth = domain;
2✔
522
        auth.chopOff();
2✔
523
        setLWResult(res, 0, true, false, true);
2✔
524
        addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2✔
525
        addRRSIG(keys, res->d_records, auth, 300, false);
2✔
526
        /* add a NSEC denying the DS and proving a cut */
527
        std::set<uint16_t> types = {QType::RRSIG, QType::NS};
2✔
528
        addNSECRecordToLW(domain, DNSName("+") + domain, types, 600, res->d_records);
2✔
529
        addRRSIG(keys, res->d_records, auth, 300, false);
2✔
530
        return LWResult::Result::Success;
2✔
531
      }
2✔
532
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true /* cut */);
×
533
    }
2✔
534
    if (type == QType::DNSKEY) {
10✔
535
      if (domain == target) {
6✔
536
        setLWResult(res, 0, true, false, true);
2✔
537
        addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2✔
538
        addRRSIG(keys, res->d_records, domain, 300, false);
2✔
539
        /* add a NSEC denying the DNSKEY */
540
        std::set<uint16_t> types = {QType::RRSIG, QType::SOA, QType::NS};
2✔
541
        addNSECRecordToLW(domain, DNSName("+") + domain, types, 600, res->d_records);
2✔
542
        addRRSIG(keys, res->d_records, domain, 300, false);
2✔
543
        return LWResult::Result::Success;
2✔
544
      }
2✔
545
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4✔
546
    }
6✔
547
    else {
4✔
548
      if (isRootServer(address)) {
4✔
549
        setLWResult(res, 0, false, false, true);
2✔
550
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
551
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
552
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
553
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
554
        return LWResult::Result::Success;
2✔
555
      }
2✔
556
      if (address == ComboAddress("192.0.2.1:53")) {
2!
557
        setLWResult(res, 0, true, false, true);
2✔
558
        addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
559
        addRRSIG(keys, res->d_records, domain, 300);
2✔
560

561
        return LWResult::Result::Success;
2✔
562
      }
2✔
563
    }
2✔
564

565
    return LWResult::Result::Timeout;
×
566
  });
10✔
567

568
  vector<DNSRecord> ret;
2✔
569
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
570
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
571
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
572
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
573
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
574

575
  /* again, to test the cache */
576
  ret.clear();
2✔
577
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
578
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
579
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
580
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
581
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
582

583
  /* now request the SOA */
584
  ret.clear();
2✔
585
  res = sr->beginResolve(target, QType(QType::SOA), QClass::IN, ret);
2✔
586
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
587
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
588
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
589
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
590
}
2✔
591

592
BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_unpublished_nsec3)
593
{
2✔
594
  /* check that we properly handle an insecure (no DS) but signed zone whose DNSKEY is not published (so NODATA) with NSEC3 this time */
595
  std::unique_ptr<SyncRes> sr;
2✔
596
  initSR(sr, true);
2✔
597

598
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
599

600
  primeHints();
2✔
601
  const DNSName target("unpublished.com.");
2✔
602
  testkeysset_t keys;
2✔
603

604
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
605
  luaconfsCopy.dsAnchors.clear();
2✔
606
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
607
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
608
  generateKeyMaterial(DNSName("unpublished.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
609

610
  g_luaconfs.setState(luaconfsCopy);
2✔
611

612
  size_t queriesCount = 0;
2✔
613

614
  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✔
615
    queriesCount++;
12✔
616

617
    if (type == QType::DS) {
12✔
618
      if (domain == target) {
2!
619
        auto auth = domain;
2✔
620
        auth.chopOff();
2✔
621
        setLWResult(res, 0, true, false, true);
2✔
622
        addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2✔
623
        addRRSIG(keys, res->d_records, auth, 300, false);
2✔
624
        /* add a NSEC denying the DS and proving a cut */
625
        std::set<uint16_t> types = {QType::RRSIG, QType::NS};
2✔
626
        addNSEC3UnhashedRecordToLW(domain, auth, (DNSName("+") + domain).toString(), types, 600, res->d_records);
2✔
627
        addRRSIG(keys, res->d_records, auth, 300, false);
2✔
628
        return LWResult::Result::Success;
2✔
629
      }
2✔
630
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true /* cut */, boost::none, true /* nsec3 */);
×
631
    }
2✔
632
    if (type == QType::DNSKEY) {
10✔
633
      if (domain == target) {
6✔
634
        setLWResult(res, 0, true, false, true);
2✔
635
        addRecordToLW(res, domain, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2✔
636
        addRRSIG(keys, res->d_records, domain, 300, false);
2✔
637
        /* add a NSEC denying the DNSKEY */
638
        std::set<uint16_t> types = {QType::RRSIG, QType::SOA, QType::NS};
2✔
639
        addNSEC3UnhashedRecordToLW(domain, domain, (DNSName("+") + domain).toString(), types, 600, res->d_records);
2✔
640
        addRRSIG(keys, res->d_records, domain, 300, false);
2✔
641
        return LWResult::Result::Success;
2✔
642
      }
2✔
643
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true /* cut */, boost::none, true /* nsec3 */);
4✔
644
    }
6✔
645
    else {
4✔
646
      if (isRootServer(address)) {
4✔
647
        setLWResult(res, 0, false, false, true);
2✔
648
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
649
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
650
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
651
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
652
        return LWResult::Result::Success;
2✔
653
      }
2✔
654
      if (address == ComboAddress("192.0.2.1:53")) {
2!
655
        setLWResult(res, 0, true, false, true);
2✔
656
        addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
657
        addRRSIG(keys, res->d_records, domain, 300);
2✔
658

659
        return LWResult::Result::Success;
2✔
660
      }
2✔
661
    }
2✔
662

663
    return LWResult::Result::Timeout;
×
664
  });
10✔
665

666
  vector<DNSRecord> ret;
2✔
667
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
668
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
669
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
670
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
671
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
672

673
  /* again, to test the cache */
674
  ret.clear();
2✔
675
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
676
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
677
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
678
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
679
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
680

681
  /* now request the SOA */
682
  ret.clear();
2✔
683
  res = sr->beginResolve(target, QType(QType::SOA), QClass::IN, ret);
2✔
684
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
685
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
686
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
687
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
688
}
2✔
689

690
BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure)
691
{
2✔
692
  std::unique_ptr<SyncRes> sr;
2✔
693
  initSR(sr, true);
2✔
694

695
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
696

697
  primeHints();
2✔
698
  const DNSName target("www.powerdns.com.");
2✔
699
  testkeysset_t keys;
2✔
700

701
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
702
  luaconfsCopy.dsAnchors.clear();
2✔
703
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
704
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
705

706
  g_luaconfs.setState(luaconfsCopy);
2✔
707

708
  size_t queriesCount = 0;
2✔
709
  size_t dsQueriesCount = 0;
2✔
710

711
  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✔
712
    queriesCount++;
14✔
713

714
    if (type == QType::DS) {
14✔
715
      DNSName auth(domain);
4✔
716
      auth.chopOff();
4✔
717
      dsQueriesCount++;
4✔
718

719
      setLWResult(res, 0, true, false, true);
4✔
720
      if (domain == DNSName("com.")) {
4✔
721
        addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
2✔
722
      }
2✔
723
      else {
2✔
724
        addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
725
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
726
        addNSECRecordToLW(domain, DNSName("powerdnt.com."), {QType::NS}, 600, res->d_records);
2✔
727
      }
2✔
728
      addRRSIG(keys, res->d_records, auth, 300);
4✔
729
      return LWResult::Result::Success;
4✔
730
    }
4✔
731
    if (type == QType::DNSKEY) {
10✔
732
      setLWResult(res, 0, true, false, true);
4✔
733
      addDNSKEY(keys, domain, 300, res->d_records);
4✔
734
      addRRSIG(keys, res->d_records, domain, 300);
4✔
735
      return LWResult::Result::Success;
4✔
736
    }
4✔
737
    {
6✔
738
      if (isRootServer(address)) {
6✔
739
        setLWResult(res, 0, false, false, true);
2✔
740
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
741
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
742
        /* No DS on referral, and no denial of the DS either */
743
        return LWResult::Result::Success;
2✔
744
      }
2✔
745
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
746
        if (domain == DNSName("com.")) {
2!
747
          setLWResult(res, 0, true, false, true);
×
748
          addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
×
749
          addRRSIG(keys, res->d_records, domain, 300);
×
750
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
751
          addRRSIG(keys, res->d_records, domain, 300);
×
752
        }
×
753
        else {
2✔
754
          setLWResult(res, 0, false, false, true);
2✔
755
          addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
756
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
757
          /* No DS on referral, and no denial of the DS either */
758
        }
2✔
759
        return LWResult::Result::Success;
2✔
760
      }
2✔
761
      if (address == ComboAddress("192.0.2.2:53")) {
2!
762
        setLWResult(res, 0, true, false, true);
2✔
763
        if (type == QType::NS) {
2!
764
          if (domain == DNSName("powerdns.com.")) {
×
765
            addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
766
            addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
×
767
          }
×
768
          else {
×
769
            addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
770
          }
×
771
        }
×
772
        else {
2✔
773
          addRecordToLW(res, domain, QType::A, "192.0.2.42");
2✔
774
        }
2✔
775
        return LWResult::Result::Success;
2✔
776
      }
2✔
777
    }
2✔
778

779
    return LWResult::Result::Timeout;
×
780
  });
2✔
781

782
  vector<DNSRecord> ret;
2✔
783
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
784
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
785
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
786
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
787
  BOOST_CHECK_EQUAL(queriesCount, 7U);
2✔
788
  BOOST_CHECK_EQUAL(dsQueriesCount, 2U);
2✔
789

790
  /* again, to test the cache */
791
  ret.clear();
2✔
792
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
793
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
794
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
795
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
796
  BOOST_CHECK_EQUAL(queriesCount, 7U);
2✔
797
  BOOST_CHECK_EQUAL(dsQueriesCount, 2U);
2✔
798
}
2✔
799

800
BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec)
801
{
2✔
802
  std::unique_ptr<SyncRes> sr;
2✔
803
  initSR(sr, true);
2✔
804

805
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
806

807
  primeHints();
2✔
808
  const DNSName target("powerdns.com.");
2✔
809
  testkeysset_t keys;
2✔
810

811
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
812
  luaconfsCopy.dsAnchors.clear();
2✔
813
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
814
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
815
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
816

817
  g_luaconfs.setState(luaconfsCopy);
2✔
818

819
  size_t queriesCount = 0;
2✔
820

821
  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✔
822
    queriesCount++;
12✔
823

824
    if (type == QType::DS || type == QType::DNSKEY) {
12!
825
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6✔
826
    }
6✔
827
    {
6✔
828
      if (isRootServer(address)) {
6✔
829
        setLWResult(res, 0, false, false, true);
2✔
830
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
831
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
832
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
833
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
834
        return LWResult::Result::Success;
2✔
835
      }
2✔
836
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
837
        if (domain == DNSName("com.")) {
2!
838
          setLWResult(res, 0, true, false, true);
×
839
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
840
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
841
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
842
        }
×
843
        else {
2✔
844
          setLWResult(res, 0, false, false, true);
2✔
845
          addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
846
          addDS(domain, 300, res->d_records, keys);
2✔
847
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
848
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
849
        }
2✔
850
        return LWResult::Result::Success;
2✔
851
      }
2✔
852
      if (address == ComboAddress("192.0.2.2:53")) {
2!
853
        setLWResult(res, 0, true, false, true);
2✔
854
        if (type == QType::NS) {
2!
855
          addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
856
          addRRSIG(keys, res->d_records, domain, 300);
×
857
        }
×
858
        else {
2✔
859
          addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
860
          addRRSIG(keys, res->d_records, domain, 300);
2✔
861
          addNSECRecordToLW(domain, DNSName("z.powerdns.com."), {QType::NS, QType::DNSKEY}, 600, res->d_records);
2✔
862
          /* NO RRSIG for the NSEC record! */
863
        }
2✔
864
        return LWResult::Result::Success;
2✔
865
      }
2✔
866
    }
2✔
867

868
    return LWResult::Result::Timeout;
×
869
  });
2✔
870

871
  /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
872
  vector<DNSRecord> ret;
2✔
873
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
874
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
875
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
2✔
876
  BOOST_CHECK_EQUAL(ret.size(), 3U);
2✔
877
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
878

879
  /* again, to test the cache */
880
  ret.clear();
2✔
881
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
882
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
883
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoRRSIG);
2✔
884
  BOOST_REQUIRE_EQUAL(ret.size(), 3U);
2✔
885
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
886
}
2✔
887

888
BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec)
889
{
2✔
890
  std::unique_ptr<SyncRes> sr;
2✔
891
  initSR(sr, true);
2✔
892

893
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
894

895
  primeHints();
2✔
896
  const DNSName target("powerdns.com.");
2✔
897
  testkeysset_t keys;
2✔
898

899
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
900
  luaconfsCopy.dsAnchors.clear();
2✔
901
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
902
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
903
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
904

905
  g_luaconfs.setState(luaconfsCopy);
2✔
906

907
  size_t queriesCount = 0;
2✔
908

909
  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✔
910
    queriesCount++;
12✔
911

912
    if (type == QType::DS || type == QType::DNSKEY) {
12!
913
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6✔
914
    }
6✔
915
    {
6✔
916
      if (isRootServer(address)) {
6✔
917
        setLWResult(res, 0, false, false, true);
2✔
918
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
919
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
920
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
921
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
922
        return LWResult::Result::Success;
2✔
923
      }
2✔
924
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
925
        if (domain == DNSName("com.")) {
2!
926
          setLWResult(res, 0, true, false, true);
×
927
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
928
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
929
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
930
        }
×
931
        else {
2✔
932
          setLWResult(res, 0, false, false, true);
2✔
933
          addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
934
          addDS(domain, 300, res->d_records, keys);
2✔
935
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
936
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
937
        }
2✔
938
        return LWResult::Result::Success;
2✔
939
      }
2✔
940
      if (address == ComboAddress("192.0.2.2:53")) {
2!
941
        setLWResult(res, 0, true, false, true);
2✔
942
        if (type == QType::NS) {
2!
943
          addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
944
          addRRSIG(keys, res->d_records, domain, 300);
×
945
        }
×
946
        else {
2✔
947
          addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
948
          addRRSIG(keys, res->d_records, domain, 300);
2✔
949

950
          /* NO NSEC record! */
951
        }
2✔
952
        return LWResult::Result::Success;
2✔
953
      }
2✔
954
    }
2✔
955

956
    return LWResult::Result::Timeout;
×
957
  });
2✔
958

959
  /* no NSEC record in a secure zone, should be Bogus! */
960
  vector<DNSRecord> ret;
2✔
961
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
962
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
963
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusInvalidDenial);
2✔
964
  BOOST_CHECK_EQUAL(ret.size(), 2U);
2✔
965
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
966

967
  /* again, to test the cache */
968
  ret.clear();
2✔
969
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
970
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
971
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusInvalidDenial);
2✔
972
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
973
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
974
}
2✔
975

976
BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure)
977
{
2✔
978
  std::unique_ptr<SyncRes> sr;
2✔
979
  initSR(sr, true);
2✔
980

981
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
982

983
  primeHints();
2✔
984
  const DNSName target("powerdns.com.");
2✔
985
  const ComboAddress targetAddr("192.0.2.42");
2✔
986
  testkeysset_t keys;
2✔
987

988
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
989
  luaconfsCopy.dsAnchors.clear();
2✔
990
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
991
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
992

993
  g_luaconfs.setState(luaconfsCopy);
2✔
994

995
  size_t queriesCount = 0;
2✔
996

997
  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✔
998
    queriesCount++;
10✔
999

1000
    if (type == QType::DS) {
10!
1001
      if (domain == target) {
×
1002
        setLWResult(res, 0, true, false, true);
×
1003
        addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
1004
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1005
        addNSECRecordToLW(domain, DNSName("z.powerdns.com."), {QType::NS}, 600, res->d_records);
×
1006
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1007
        return LWResult::Result::Success;
×
1008
      }
×
1009
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
×
1010
    }
×
1011
    if (type == QType::DNSKEY) {
10✔
1012
      if (domain == g_rootdnsname || domain == DNSName("com.")) {
4!
1013
        setLWResult(res, 0, true, false, true);
4✔
1014
        addDNSKEY(keys, domain, 300, res->d_records);
4✔
1015
        addRRSIG(keys, res->d_records, domain, 300);
4✔
1016
        return LWResult::Result::Success;
4✔
1017
      }
4✔
1018
      setLWResult(res, 0, true, false, true);
×
1019
      addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
1020
      return LWResult::Result::Success;
×
1021
    }
4✔
1022
    else {
6✔
1023
      if (isRootServer(address)) {
6✔
1024
        setLWResult(res, 0, false, false, true);
2✔
1025
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1026
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
1027
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
1028
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1029
        return LWResult::Result::Success;
2✔
1030
      }
2✔
1031
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
1032
        if (domain == DNSName("com.")) {
2!
1033
          setLWResult(res, 0, true, false, true);
×
1034
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
1035
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1036
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1037
        }
×
1038
        else {
2✔
1039
          setLWResult(res, 0, false, false, true);
2✔
1040
          addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1041
          /* no DS */
1042
          addNSECRecordToLW(domain, DNSName("z.powerdns.com."), {QType::NS}, 600, res->d_records);
2✔
1043
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1044
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1045
        }
2✔
1046
        return LWResult::Result::Success;
2✔
1047
      }
2✔
1048
      if (address == ComboAddress("192.0.2.2:53")) {
2!
1049
        setLWResult(res, 0, true, false, true);
2✔
1050
        if (type == QType::NS) {
2!
1051
          addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
1052
        }
×
1053
        else {
2✔
1054
          addRecordToLW(res, domain, QType::A, targetAddr.toString());
2✔
1055
        }
2✔
1056
        return LWResult::Result::Success;
2✔
1057
      }
2✔
1058
    }
2✔
1059

1060
    return LWResult::Result::Timeout;
×
1061
  });
10✔
1062

1063
  vector<DNSRecord> ret;
2✔
1064
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1065
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1066
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1067
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1068
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1069
  /* 2 NS: com at ., powerdns.com at com
1070
     2 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
1071
     1 query for A */
1072
  BOOST_CHECK_EQUAL(queriesCount, 5U);
2✔
1073

1074
  /* again, to test the cache */
1075
  ret.clear();
2✔
1076
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1077
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1078
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1079
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1080
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1081
  BOOST_CHECK_EQUAL(queriesCount, 5U);
2✔
1082
}
2✔
1083

1084
BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_optout)
1085
{
2✔
1086
  std::unique_ptr<SyncRes> sr;
2✔
1087
  initSR(sr, true);
2✔
1088

1089
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1090

1091
  primeHints();
2✔
1092
  const DNSName target("powerdns.com.");
2✔
1093
  const ComboAddress targetAddr("192.0.2.42");
2✔
1094
  testkeysset_t keys;
2✔
1095

1096
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1097
  luaconfsCopy.dsAnchors.clear();
2✔
1098
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1099
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1100

1101
  g_luaconfs.setState(luaconfsCopy);
2✔
1102

1103
  size_t queriesCount = 0;
2✔
1104

1105
  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✔
1106
    queriesCount++;
8✔
1107

1108
    if (type == QType::DS) {
8✔
1109
      if (domain == target) {
4✔
1110
        setLWResult(res, 0, true, false, true);
2✔
1111
        addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
1112
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1113
        /* closest encloser */
1114
        addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), DNSName("a.com.").toStringNoDot(), {QType::NS, QType::SOA}, 600, res->d_records, 10, true);
2✔
1115
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1116
        /* next closer */
1117
        addNSEC3UnhashedRecordToLW(DNSName("oowerdns.com."), DNSName("com."), DNSName("qowerdns.com.").toStringNoDot(), {QType::NS}, 600, res->d_records, 10, true);
2✔
1118
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1119
        return LWResult::Result::Success;
2✔
1120
      }
2✔
1121
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true, boost::none, true, true);
2✔
1122
    }
4✔
1123
    if (type == QType::DNSKEY) {
4!
1124
      if (domain == g_rootdnsname || domain == DNSName("com.")) {
4!
1125
        setLWResult(res, 0, true, false, true);
4✔
1126
        addDNSKEY(keys, domain, 300, res->d_records);
4✔
1127
        addRRSIG(keys, res->d_records, domain, 300);
4✔
1128
        return LWResult::Result::Success;
4✔
1129
      }
4✔
1130
      setLWResult(res, 0, true, false, true);
×
1131
      addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
1132
      return LWResult::Result::Success;
×
1133
    }
4✔
1134
    else {
×
1135
      if (isRootServer(address)) {
×
1136
        setLWResult(res, 0, false, false, true);
×
1137
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
×
1138
        addDS(DNSName("com."), 300, res->d_records, keys);
×
1139
        addRRSIG(keys, res->d_records, DNSName("."), 300);
×
1140
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1141
        return LWResult::Result::Success;
×
1142
      }
×
1143
      if (address == ComboAddress("192.0.2.1:53")) {
×
1144
        if (domain == DNSName("com.")) {
×
1145
          setLWResult(res, 0, true, false, true);
×
1146
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
1147
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1148
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1149
        }
×
1150
        else {
×
1151
          setLWResult(res, 0, false, false, true);
×
1152
          addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
×
1153
          /* no DS */
1154
          /* closest encloser */
1155
          addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), DNSName("a.com.").toStringNoDot(), {QType::NS, QType::SOA}, 600, res->d_records, 10, true);
×
1156
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1157
          /* next closer */
1158
          addNSEC3UnhashedRecordToLW(DNSName("oowerdns.com."), DNSName("com."), DNSName("qowerdns.com.").toStringNoDot(), {QType::NS}, 600, res->d_records, 10, true);
×
1159
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1160
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
×
1161
        }
×
1162
        return LWResult::Result::Success;
×
1163
      }
×
1164
      if (address == ComboAddress("192.0.2.2:53")) {
×
1165
        setLWResult(res, 0, true, false, true);
×
1166
        if (type == QType::NS) {
×
1167
          addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
1168
        }
×
1169
        else {
×
1170
          addRecordToLW(res, domain, QType::A, targetAddr.toString());
×
1171
        }
×
1172
        return LWResult::Result::Success;
×
1173
      }
×
1174
    }
×
1175

1176
    return LWResult::Result::Timeout;
×
1177
  });
4✔
1178

1179
  vector<DNSRecord> ret;
2✔
1180
  int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
1181
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1182
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1183
  BOOST_REQUIRE_EQUAL(ret.size(), 6U);
2✔
1184
  BOOST_CHECK(ret[0].d_type == QType::SOA);
2✔
1185
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1186

1187
  /* again, to test the cache */
1188
  ret.clear();
2✔
1189
  res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
1190
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1191
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1192
  BOOST_REQUIRE_EQUAL(ret.size(), 6U);
2✔
1193
  BOOST_CHECK(ret[0].d_type == QType::SOA);
2✔
1194
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1195
}
2✔
1196

1197
BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nxd_optout)
1198
{
2✔
1199
  std::unique_ptr<SyncRes> sr;
2✔
1200
  initSR(sr, true);
2✔
1201

1202
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1203

1204
  primeHints();
2✔
1205
  const DNSName target("powerdns.com.");
2✔
1206
  const ComboAddress targetAddr("192.0.2.42");
2✔
1207
  testkeysset_t keys;
2✔
1208

1209
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1210
  luaconfsCopy.dsAnchors.clear();
2✔
1211
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1212
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1213

1214
  g_luaconfs.setState(luaconfsCopy);
2✔
1215

1216
  size_t queriesCount = 0;
2✔
1217

1218
  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✔
1219
    queriesCount++;
8✔
1220

1221
    if (type == QType::DS) {
8!
1222
      if (domain == target) {
×
1223
        setLWResult(res, RCode::NXDomain, true, false, true);
×
1224
        addRecordToLW(res, DNSName("com."), QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
1225
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1226
        /* closest encloser */
1227
        addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), DNSName("a.com.").toStringNoDot(), {QType::SOA, QType::NS, QType::DS, QType::DNSKEY, QType::RRSIG, QType::NSEC3PARAM}, 600, res->d_records, 10, true);
×
1228
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1229
        /* next closer */
1230
        addNSEC3UnhashedRecordToLW(DNSName("oowerdns.com."), DNSName("com."), DNSName("qowerdns.com.").toStringNoDot(), {QType::NS}, 600, res->d_records, 10, true);
×
1231
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1232
        return LWResult::Result::Success;
×
1233
      }
×
1234
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, true, boost::none, true, true);
×
1235
    }
×
1236
    if (type == QType::DNSKEY) {
8✔
1237
      if (domain == g_rootdnsname || domain == DNSName("com.")) {
4!
1238
        setLWResult(res, 0, true, false, true);
4✔
1239
        addDNSKEY(keys, domain, 300, res->d_records);
4✔
1240
        addRRSIG(keys, res->d_records, domain, 300);
4✔
1241
        return LWResult::Result::Success;
4✔
1242
      }
4✔
1243
      setLWResult(res, 0, true, false, true);
×
1244
      addRecordToLW(res, DNSName("com."), QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
1245
      return LWResult::Result::Success;
×
1246
    }
4✔
1247
    else {
4✔
1248
      if (isRootServer(address)) {
4✔
1249
        setLWResult(res, 0, false, false, true);
2✔
1250
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1251
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
1252
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
1253
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1254
        return LWResult::Result::Success;
2✔
1255
      }
2✔
1256
      if (address == ComboAddress("192.0.2.1:53")) {
2!
1257
        if (domain == DNSName("com.")) {
2!
1258
          setLWResult(res, 0, true, false, true);
×
1259
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
1260
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1261
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1262
        }
×
1263
        else {
2✔
1264
          setLWResult(res, RCode::NXDomain, true, false, true);
2✔
1265
          addRecordToLW(res, DNSName("com."), QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
1266
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1267
          /* closest encloser */
1268
          addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), DNSName("a.com.").toStringNoDot(), {QType::SOA, QType::NS, QType::DS, QType::DNSKEY, QType::RRSIG, QType::NSEC3PARAM}, 600, res->d_records, 10, true);
2✔
1269
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1270
          /* next closer */
1271
          addNSEC3UnhashedRecordToLW(DNSName("oowerdns.com."), DNSName("com."), DNSName("qowerdns.com.").toStringNoDot(), {QType::NS}, 600, res->d_records, 10, true);
2✔
1272
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1273
        }
2✔
1274
        return LWResult::Result::Success;
2✔
1275
      }
2✔
1276
    }
2✔
1277

1278
    return LWResult::Result::Timeout;
×
1279
  });
8✔
1280

1281
  vector<DNSRecord> ret;
2✔
1282
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1283
  BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2✔
1284
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1285
  BOOST_REQUIRE_EQUAL(ret.size(), 6U);
2✔
1286
  BOOST_CHECK(ret[0].d_type == QType::SOA);
2✔
1287
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1288

1289
  /* again, to test the cache */
1290
  ret.clear();
2✔
1291
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1292
  BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2✔
1293
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1294
  BOOST_REQUIRE_EQUAL(ret.size(), 6U);
2✔
1295
  BOOST_CHECK(ret[0].d_type == QType::SOA);
2✔
1296
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1297
}
2✔
1298

1299
BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds)
1300
{
2✔
1301
  /*
1302
    Direct DS query:
1303
    - parent is secure, zone is secure: DS should be secure
1304
  */
1305
  std::unique_ptr<SyncRes> sr;
2✔
1306
  initSR(sr, true);
2✔
1307

1308
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1309

1310
  primeHints();
2✔
1311
  const DNSName target("powerdns.com.");
2✔
1312
  testkeysset_t keys;
2✔
1313

1314
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1315
  luaconfsCopy.dsAnchors.clear();
2✔
1316
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1317
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1318
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1319

1320
  g_luaconfs.setState(luaconfsCopy);
2✔
1321

1322
  size_t queriesCount = 0;
2✔
1323

1324
  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✔
1325
    queriesCount++;
8✔
1326

1327
    if (type == QType::DS || type == QType::DNSKEY) {
8!
1328
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
8✔
1329
    }
8✔
1330
    {
×
1331
      if (isRootServer(address)) {
×
1332
        setLWResult(res, 0, false, false, true);
×
1333
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
×
1334
        addDS(DNSName("com."), 300, res->d_records, keys);
×
1335
        addRRSIG(keys, res->d_records, DNSName("."), 300);
×
1336
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1337
        return LWResult::Result::Success;
×
1338
      }
×
1339
    }
×
1340

1341
    return LWResult::Result::Timeout;
×
1342
  });
×
1343

1344
  vector<DNSRecord> ret;
2✔
1345
  int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
1346
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1347
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
1348
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1349
  for (const auto& record : ret) {
4✔
1350
    BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
4✔
1351
  }
4✔
1352
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1353

1354
  /* again, to test the cache */
1355
  ret.clear();
2✔
1356
  res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
1357
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1358
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
1359
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1360
  for (const auto& record : ret) {
4✔
1361
    BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
4✔
1362
  }
4✔
1363
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1364
}
2✔
1365

1366
BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds)
1367
{
2✔
1368
  /*
1369
    Direct DS query:
1370
    - parent is secure, zone is insecure: DS denial should be secure
1371
  */
1372
  std::unique_ptr<SyncRes> sr;
2✔
1373
  initSR(sr, true);
2✔
1374

1375
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1376

1377
  primeHints();
2✔
1378
  const DNSName target("powerdns.com.");
2✔
1379
  testkeysset_t keys;
2✔
1380

1381
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1382
  luaconfsCopy.dsAnchors.clear();
2✔
1383
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1384
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1385

1386
  g_luaconfs.setState(luaconfsCopy);
2✔
1387

1388
  size_t queriesCount = 0;
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 */) {
8✔
1391
    queriesCount++;
8✔
1392

1393
    if (type == QType::DS || type == QType::DNSKEY) {
8!
1394
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
8✔
1395
    }
8✔
1396
    {
×
1397
      if (isRootServer(address)) {
×
1398
        setLWResult(res, 0, false, false, true);
×
1399
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
×
1400
        addDS(DNSName("com."), 300, res->d_records, keys);
×
1401
        addRRSIG(keys, res->d_records, DNSName("."), 300);
×
1402
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1403
        return LWResult::Result::Success;
×
1404
      }
×
1405
    }
×
1406

1407
    return LWResult::Result::Timeout;
×
1408
  });
×
1409

1410
  vector<DNSRecord> ret;
2✔
1411
  int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
1412
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1413
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
1414
  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
2✔
1415
  for (const auto& record : ret) {
8✔
1416
    BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
8✔
1417
  }
8✔
1418
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1419

1420
  /* again, to test the cache */
1421
  ret.clear();
2✔
1422
  res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
2✔
1423
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1424
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
2✔
1425
  BOOST_REQUIRE_EQUAL(ret.size(), 4U);
2✔
1426
  for (const auto& record : ret) {
8✔
1427
    BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
8✔
1428
  }
8✔
1429
  BOOST_CHECK_EQUAL(queriesCount, 4U);
2✔
1430
}
2✔
1431

1432
BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut)
1433
{
2✔
1434
  std::unique_ptr<SyncRes> sr;
2✔
1435
  initSR(sr, true);
2✔
1436

1437
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1438

1439
  primeHints();
2✔
1440
  const DNSName target("www.sub.powerdns.com.");
2✔
1441
  const ComboAddress targetAddr("192.0.2.42");
2✔
1442
  testkeysset_t keys;
2✔
1443

1444
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1445
  luaconfsCopy.dsAnchors.clear();
2✔
1446
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1447
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1448
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1449

1450
  g_luaconfs.setState(luaconfsCopy);
2✔
1451

1452
  size_t queriesCount = 0;
2✔
1453

1454
  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✔
1455
    queriesCount++;
14✔
1456

1457
    if (type == QType::DS) {
14✔
1458
      if (domain == DNSName("sub.powerdns.com.")) {
2!
1459
        setLWResult(res, 0, true, false, true);
2✔
1460
        addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2✔
1461
        addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
2✔
1462
        addNSECRecordToLW(domain, DNSName("z.powerdns.com."), {QType::NS}, 600, res->d_records);
2✔
1463
        addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
2✔
1464
        return LWResult::Result::Success;
2✔
1465
      }
2✔
1466
      if (domain == DNSName("www.sub.powerdns.com.")) {
×
1467
        setLWResult(res, 0, true, false, true);
×
1468
        addRecordToLW(res, DNSName("sub.powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
1469
        return LWResult::Result::Success;
×
1470
      }
×
1471
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
×
1472
    }
×
1473
    if (type == QType::DNSKEY) {
12✔
1474
      if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6!
1475
        setLWResult(res, 0, true, false, true);
6✔
1476
        addDNSKEY(keys, domain, 300, res->d_records);
6✔
1477
        addRRSIG(keys, res->d_records, domain, 300);
6✔
1478
        return LWResult::Result::Success;
6✔
1479
      }
6✔
1480
      setLWResult(res, 0, true, false, true);
×
1481
      addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
1482
      return LWResult::Result::Success;
×
1483
    }
6✔
1484
    {
6✔
1485
      if (isRootServer(address)) {
6✔
1486
        setLWResult(res, 0, false, false, true);
2✔
1487
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1488
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
1489
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
1490
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1491
        return LWResult::Result::Success;
2✔
1492
      }
2✔
1493
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
1494
        if (domain == DNSName("com.")) {
2!
1495
          setLWResult(res, 0, true, false, true);
×
1496
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
1497
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1498
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1499
        }
×
1500
        else {
2✔
1501
          setLWResult(res, 0, false, false, true);
2✔
1502
          addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1503
          addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
2✔
1504
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1505
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1506
        }
2✔
1507
        return LWResult::Result::Success;
2✔
1508
      }
2✔
1509
      if (address == ComboAddress("192.0.2.2:53")) {
2!
1510
        setLWResult(res, 0, true, false, true);
2✔
1511
        if (type == QType::NS) {
2!
1512
          if (domain == DNSName("www.sub.powerdns.com.")) {
×
1513
            addRecordToLW(res, DNSName("sub.powerdns.com"), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
×
1514
          }
×
1515
          else if (domain == DNSName("sub.powerdns.com.")) {
×
1516
            addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
1517
          }
×
1518
          else if (domain == DNSName("powerdns.com.")) {
×
1519
            addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
×
1520
            addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
×
1521
          }
×
1522
        }
×
1523
        else {
2✔
1524
          addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
2✔
1525
        }
2✔
1526
        return LWResult::Result::Success;
2✔
1527
      }
2✔
1528
    }
2✔
1529

1530
    return LWResult::Result::Timeout;
×
1531
  });
2✔
1532

1533
  vector<DNSRecord> ret;
2✔
1534
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1535
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1536
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1537
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1538
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1539
  BOOST_CHECK_EQUAL(queriesCount, 7U);
2✔
1540

1541
  /* again, to test the cache */
1542
  ret.clear();
2✔
1543
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1544
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1545
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1546
  BOOST_REQUIRE_EQUAL(ret.size(), 1U);
2✔
1547
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1548
  BOOST_CHECK_EQUAL(queriesCount, 7U);
2✔
1549
}
2✔
1550

1551
BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_without_ds)
1552
{
2✔
1553
  /* the last zone has signatures but the DS has not been added
1554
     to the parent zone yet, so it should be insecure */
1555
  std::unique_ptr<SyncRes> sr;
2✔
1556
  initSR(sr, true);
2✔
1557

1558
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1559

1560
  primeHints();
2✔
1561
  const DNSName target("www.powerdns.com.");
2✔
1562
  const ComboAddress targetAddr("192.0.2.42");
2✔
1563
  testkeysset_t keys;
2✔
1564

1565
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1566
  luaconfsCopy.dsAnchors.clear();
2✔
1567
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1568
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1569
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1570

1571
  g_luaconfs.setState(luaconfsCopy);
2✔
1572

1573
  size_t queriesCount = 0;
2✔
1574

1575
  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✔
1576
    queriesCount++;
12✔
1577

1578
    if (type == QType::DS) {
12!
1579
      if (domain == DNSName("powerdns.com.")) {
×
1580
        setLWResult(res, 0, true, false, true);
×
1581
        addRecordToLW(res, DNSName("com."), QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
×
1582
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1583
        addNSECRecordToLW(domain, DNSName("z") + domain, {QType::NS, QType::RRSIG}, 600, res->d_records);
×
1584
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1585
        return LWResult::Result::Success;
×
1586
      }
×
1587
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
×
1588
    }
×
1589
    if (type == QType::DNSKEY) {
12✔
1590
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6✔
1591
    }
6✔
1592
    {
6✔
1593
      if (isRootServer(address)) {
6✔
1594
        setLWResult(res, 0, false, false, true);
2✔
1595
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1596
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
1597
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
1598
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1599
        return LWResult::Result::Success;
2✔
1600
      }
2✔
1601
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
1602
        if (domain == DNSName("com.")) {
2!
1603
          setLWResult(res, 0, true, false, true);
×
1604
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
1605
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1606
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1607
        }
×
1608
        else {
2✔
1609
          setLWResult(res, 0, false, false, true);
2✔
1610
          addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1611
          /* no DS */
1612
          addNSECRecordToLW(DNSName("powerdns.com."), DNSName("z.powerdns.com."), {QType::NS, QType::RRSIG}, 600, res->d_records);
2✔
1613
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1614
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1615
        }
2✔
1616
        return LWResult::Result::Success;
2✔
1617
      }
2✔
1618
      if (address == ComboAddress("192.0.2.2:53")) {
2!
1619
        setLWResult(res, 0, true, false, true);
2✔
1620
        addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
2✔
1621
        addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
2✔
1622

1623
        return LWResult::Result::Success;
2✔
1624
      }
2✔
1625
    }
2✔
1626

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

1630
  vector<DNSRecord> ret;
2✔
1631
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1632
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1633
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1634
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1635
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1636
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
1637

1638
  /* again, to test the cache */
1639
  ret.clear();
2✔
1640
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1641
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1642
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1643
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1644
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1645
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
1646
}
2✔
1647

1648
BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_broken_without_ds)
1649
{
2✔
1650
  /* the last zone has INVALID signatures but the DS has not been added
1651
     to the parent zone yet, so it should be insecure */
1652
  std::unique_ptr<SyncRes> sr;
2✔
1653
  initSR(sr, true);
2✔
1654

1655
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1656

1657
  primeHints();
2✔
1658
  const DNSName target("www.powerdns.com.");
2✔
1659
  const ComboAddress targetAddr("192.0.2.42");
2✔
1660
  testkeysset_t keys;
2✔
1661

1662
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1663
  luaconfsCopy.dsAnchors.clear();
2✔
1664
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1665
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1666
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1667

1668
  g_luaconfs.setState(luaconfsCopy);
2✔
1669

1670
  size_t queriesCount = 0;
2✔
1671

1672
  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✔
1673
    queriesCount++;
12✔
1674

1675
    if (type == QType::DS) {
12!
1676
      if (domain == DNSName("powerdns.com.")) {
×
1677
        setLWResult(res, 0, true, false, true);
×
1678
        addRecordToLW(res, DNSName("com."), QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
×
1679
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1680
        addNSECRecordToLW(domain, DNSName("z") + domain, {QType::NS, QType::RRSIG}, 600, res->d_records);
×
1681
        addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1682
        return LWResult::Result::Success;
×
1683
      }
×
1684
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
×
1685
    }
×
1686
    if (type == QType::DNSKEY) {
12✔
1687
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6✔
1688
    }
6✔
1689
    else {
6✔
1690
      if (isRootServer(address)) {
6✔
1691
        setLWResult(res, 0, false, false, true);
2✔
1692
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1693
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
1694
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
1695
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1696
        return LWResult::Result::Success;
2✔
1697
      }
2✔
1698
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
1699
        if (domain == DNSName("com.")) {
2!
1700
          setLWResult(res, 0, true, false, true);
×
1701
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
1702
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1703
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1704
        }
×
1705
        else {
2✔
1706
          setLWResult(res, 0, false, false, true);
2✔
1707
          addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1708
          /* no DS */
1709
          addNSECRecordToLW(DNSName("powerdns.com."), DNSName("z.powerdns.com."), {QType::NS, QType::RRSIG}, 600, res->d_records);
2✔
1710
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1711
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1712
        }
2✔
1713
        return LWResult::Result::Success;
2✔
1714
      }
2✔
1715
      if (address == ComboAddress("192.0.2.2:53")) {
2!
1716
        setLWResult(res, 0, true, false, true);
2✔
1717
        addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
2✔
1718
        addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300, /* broken SIG */ true);
2✔
1719

1720
        return LWResult::Result::Success;
2✔
1721
      }
2✔
1722
    }
2✔
1723

1724
    return LWResult::Result::Timeout;
×
1725
  });
12✔
1726

1727
  vector<DNSRecord> ret;
2✔
1728
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1729
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1730
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1731
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1732
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1733
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
1734

1735
  /* again, to test the cache */
1736
  ret.clear();
2✔
1737
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1738
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1739
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1740
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1741
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1742
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
1743
}
2✔
1744

1745
BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_broken_cname_ds)
1746
{
2✔
1747
  /* Test an Insecure domain that responds with a CNAME on a DS query */
1748
  std::unique_ptr<SyncRes> sr;
2✔
1749
  initSR(sr, true);
2✔
1750

1751
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1752

1753
  primeHints();
2✔
1754
  const DNSName target("www.sub.powerdns.com.");
2✔
1755
  const ComboAddress targetAddr("192.0.2.42");
2✔
1756
  testkeysset_t keys, pdnskeys;
2✔
1757

1758
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1759
  luaconfsCopy.dsAnchors.clear();
2✔
1760

1761
  // We have two set of keys as powerdns.com and sub.powerdns.com are Insecure but still have RRSIGS
1762
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1763
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1764

1765
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, pdnskeys);
2✔
1766
  generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, pdnskeys);
2✔
1767

1768
  g_luaconfs.setState(luaconfsCopy);
2✔
1769

1770
  size_t queriesCount = 0;
2✔
1771

1772
  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✔
1773
    queriesCount++;
16✔
1774

1775
    if (type == QType::DS) {
16✔
1776
      // Return a signed CNAME on a DS query for powerdns.com and sub.powerdns.com
1777
      if (domain == DNSName("powerdns.com.") || domain == DNSName("sub.powerdns.com.")) {
2!
1778
        setLWResult(res, 0, true, false, true);
2✔
1779
        addRecordToLW(res, domain, QType::CNAME, "some.name", DNSResourceRecord::ANSWER, 300);
2✔
1780
        addRRSIG(pdnskeys, res->d_records, domain, 300);
2✔
1781
        return LWResult::Result::Success;
2✔
1782
      }
2✔
1783
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
×
1784
    }
2✔
1785
    if (type == QType::DNSKEY) {
14✔
1786
      if (domain == DNSName("powerdns.com.") || domain == DNSName("sub.powerdns.com.")) {
6!
1787
        return genericDSAndDNSKEYHandler(res, domain, domain, type, pdnskeys);
2✔
1788
      }
2✔
1789
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4✔
1790
    }
6✔
1791
    else {
8✔
1792
      if (isRootServer(address)) {
8✔
1793
        setLWResult(res, 0, false, false, true);
2✔
1794
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1795
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
1796
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
1797
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1798
        return LWResult::Result::Success;
2✔
1799
      }
2✔
1800
      if (address == ComboAddress("192.0.2.1:53")) {
6✔
1801
        if (domain == DNSName("com.")) {
2!
1802
          setLWResult(res, 0, true, false, true);
×
1803
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
1804
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1805
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1806
        }
×
1807
        else {
2✔
1808
          setLWResult(res, 0, false, false, true);
2✔
1809
          addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1810
          addNSECRecordToLW(DNSName("powerdns.com."), DNSName("z.powerdns.com."), {QType::NS, QType::RRSIG}, 600, res->d_records);
2✔
1811
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
2✔
1812
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1813
        }
2✔
1814
        return LWResult::Result::Success;
2✔
1815
      }
2✔
1816
      if (address == ComboAddress("192.0.2.2:53")) {
4✔
1817
        setLWResult(res, 0, false, false, true);
2✔
1818
        addRecordToLW(res, DNSName("sub.powerdns.com."), QType::NS, "ns1.sub.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1819
        addRRSIG(pdnskeys, res->d_records, DNSName("powerdns.com."), 300);
2✔
1820

1821
        addRecordToLW(res, "ns1.sub.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1822
        return LWResult::Result::Success;
2✔
1823
      }
2✔
1824
      if (address == ComboAddress("192.0.2.3:53")) {
2!
1825
        setLWResult(res, 0, true, false, true);
2✔
1826
        addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
2✔
1827
        addRRSIG(pdnskeys, res->d_records, DNSName("sub.powerdns.com."), 300);
2✔
1828
        return LWResult::Result::Success;
2✔
1829
      }
2✔
1830
    }
2✔
1831

1832
    return LWResult::Result::Timeout;
×
1833
  });
14✔
1834

1835
  vector<DNSRecord> ret;
2✔
1836
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1837
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1838
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1839
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1840
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1841
  BOOST_CHECK_EQUAL(queriesCount, 8U);
2✔
1842

1843
  /* again, to test the cache */
1844
  ret.clear();
2✔
1845
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1846
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1847
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
2✔
1848
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1849
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1850
  BOOST_CHECK_EQUAL(queriesCount, 8U);
2✔
1851
}
2✔
1852

1853
BOOST_AUTO_TEST_CASE(test_dnssec_bogus_cname_for_ds)
1854
{
2✔
1855
  /* Test an Secure domain that responds with a CNAME on a DS query goes Bogus */
1856
  std::unique_ptr<SyncRes> sr;
2✔
1857
  initSR(sr, true);
2✔
1858

1859
  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2✔
1860

1861
  primeHints();
2✔
1862
  const DNSName target("www.powerdns.com.");
2✔
1863
  testkeysset_t keys;
2✔
1864

1865
  auto luaconfsCopy = g_luaconfs.getCopy();
2✔
1866
  luaconfsCopy.dsAnchors.clear();
2✔
1867

1868
  generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors);
2✔
1869
  generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1870

1871
  generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys);
2✔
1872

1873
  g_luaconfs.setState(luaconfsCopy);
2✔
1874

1875
  size_t queriesCount = 0;
2✔
1876

1877
  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✔
1878
    queriesCount++;
12✔
1879

1880
    if (type == QType::DS || type == QType::DNSKEY) {
12✔
1881
      if (type == QType::DS && domain == DNSName("powerdns.com")) {
6!
1882
        // Return a signed CNAME on a DS query for powerdns.com
1883
        setLWResult(res, 0, true, false, true);
2✔
1884
        addRecordToLW(res, domain, QType::CNAME, "some.name", DNSResourceRecord::ANSWER, 300);
2✔
1885
        addRRSIG(keys, res->d_records, domain, 300);
2✔
1886
        return LWResult::Result::Success;
2✔
1887
      }
2✔
1888
      return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4✔
1889
    }
6✔
1890
    {
6✔
1891
      if (isRootServer(address)) {
6✔
1892
        setLWResult(res, 0, false, false, true);
2✔
1893
        addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1894
        addDS(DNSName("com."), 300, res->d_records, keys);
2✔
1895
        addRRSIG(keys, res->d_records, DNSName("."), 300);
2✔
1896
        addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1897
        return LWResult::Result::Success;
2✔
1898
      }
2✔
1899
      if (address == ComboAddress("192.0.2.1:53")) {
4✔
1900
        if (domain == DNSName("com.")) {
2!
1901
          setLWResult(res, 0, true, false, true);
×
1902
          addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
×
1903
          addRRSIG(keys, res->d_records, DNSName("com."), 300);
×
1904
          addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
×
1905
        }
×
1906
        else {
2✔
1907
          setLWResult(res, 0, false, false, true);
2✔
1908
          addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
2✔
1909
          addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2✔
1910
        }
2✔
1911
        return LWResult::Result::Success;
2✔
1912
      }
2✔
1913
      if (address == ComboAddress("192.0.2.2:53")) {
2!
1914
        setLWResult(res, 0, false, false, true);
2✔
1915
        addRecordToLW(res, DNSName("www.powerdns.com."), QType::A, "192.168.1.1", DNSResourceRecord::ANSWER, 3600);
2✔
1916
        addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
2✔
1917

1918
        return LWResult::Result::Success;
2✔
1919
      }
2✔
1920
    }
2✔
1921

1922
    return LWResult::Result::Timeout;
×
1923
  });
2✔
1924

1925
  vector<DNSRecord> ret;
2✔
1926
  int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1927
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1928
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusUnableToGetDSs);
2✔
1929
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1930
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1931
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
1932

1933
  /* again, to test the cache */
1934
  ret.clear();
2✔
1935
  res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2✔
1936
  BOOST_CHECK_EQUAL(res, RCode::NoError);
2✔
1937
  BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusUnableToGetDSs);
2✔
1938
  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
2✔
1939
  BOOST_CHECK(ret[0].d_type == QType::A);
2✔
1940
  BOOST_CHECK_EQUAL(queriesCount, 6U);
2✔
1941
}
2✔
1942

1943
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