]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc.cc
03f424ca211a6b4a30701877882cadc18250737f
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc.cc
1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
3 #include <boost/test/unit_test.hpp>
4
5 #include "syncres.hh"
6 #include "arguments.hh"
7 #include "base32.hh"
8 #include "dnssecinfra.hh"
9 #include "dnsseckeeper.hh"
10 #include "lua-recursor4.hh"
11 #include "namespaces.hh"
12 #include "rec-lua-conf.hh"
13 #include "root-dnssec.hh"
14 #include "test-common.hh"
15 #include "utility.hh"
16 #include "validate-recursor.hh"
17
18 RecursorStats g_stats;
19 GlobalStateHolder<LuaConfigItems> g_luaconfs;
20 thread_local std::unique_ptr<MemRecursorCache> t_RC{nullptr};
21 unsigned int g_numThreads = 1;
22 bool g_lowercaseOutgoing = false;
23
24 /* Fake some required functions we didn't want the trouble to
25 link with */
26 ArgvMap &arg()
27 {
28 static ArgvMap theArg;
29 return theArg;
30 }
31
32 int getMTaskerTID()
33 {
34 return 0;
35 }
36
37 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
38 {
39 return false;
40 }
41
42 int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained)
43 {
44 return 0;
45 }
46
47 /* primeHints() is only here for now because it
48 was way too much trouble to link with the real one.
49 We should fix this, empty functions are one thing, but this is
50 bad.
51 */
52
53 #include "root-addresses.hh"
54
55 void primeHints(void)
56 {
57 vector<DNSRecord> nsset;
58 if(!t_RC)
59 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
60
61 DNSRecord arr, aaaarr, nsrr;
62 nsrr.d_name=g_rootdnsname;
63 arr.d_type=QType::A;
64 aaaarr.d_type=QType::AAAA;
65 nsrr.d_type=QType::NS;
66 arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(nullptr)+3600000;
67
68 for(char c='a';c<='m';++c) {
69 char templ[40];
70 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
71 templ[sizeof(templ)-1] = '\0';
72 *templ=c;
73 aaaarr.d_name=arr.d_name=DNSName(templ);
74 nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
75 arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
76 vector<DNSRecord> aset;
77 aset.push_back(arr);
78 t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
79 if (rootIps6[c-'a'] != NULL) {
80 aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
81
82 vector<DNSRecord> aaaaset;
83 aaaaset.push_back(aaaarr);
84 t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
85 }
86
87 nsset.push_back(nsrr);
88 }
89 t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
90 }
91
92 LuaConfigItems::LuaConfigItems()
93 {
94 for (const auto &dsRecord : rootDSs) {
95 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
96 dsAnchors[g_rootdnsname].insert(*ds);
97 }
98 }
99
100 /* Some helpers functions */
101
102 static void init(bool debug=false)
103 {
104 L.setName("test");
105 L.disableSyslog(true);
106
107 if (debug) {
108 L.setLoglevel((Logger::Urgency)(6)); // info and up
109 L.toConsole(Logger::Info);
110 }
111 else {
112 L.setLoglevel(Logger::None);
113 L.toConsole(Logger::Error);
114 }
115
116 seedRandom("/dev/urandom");
117 reportAllTypes();
118
119 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
120
121 SyncRes::s_maxqperq = 50;
122 SyncRes::s_maxtotusec = 1000*7000;
123 SyncRes::s_maxdepth = 40;
124 SyncRes::s_maxnegttl = 3600;
125 SyncRes::s_maxcachettl = 86400;
126 SyncRes::s_packetcachettl = 3600;
127 SyncRes::s_packetcacheservfailttl = 60;
128 SyncRes::s_serverdownmaxfails = 64;
129 SyncRes::s_serverdownthrottletime = 60;
130 SyncRes::s_doIPv6 = true;
131 SyncRes::s_ecsipv4limit = 24;
132 SyncRes::s_ecsipv6limit = 56;
133 SyncRes::s_rootNXTrust = true;
134 SyncRes::s_minimumTTL = 0;
135 SyncRes::s_serverID = "PowerDNS Unit Tests Server ID";
136 SyncRes::clearEDNSSubnets();
137 SyncRes::clearEDNSDomains();
138 SyncRes::clearDelegationOnly();
139 SyncRes::clearDontQuery();
140
141 SyncRes::clearNSSpeeds();
142 BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0);
143 SyncRes::clearEDNSStatuses();
144 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0);
145 SyncRes::clearThrottle();
146 BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0);
147 SyncRes::clearFailedServers();
148 BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0);
149
150 auto luaconfsCopy = g_luaconfs.getCopy();
151 luaconfsCopy.dfe.clear();
152 luaconfsCopy.dsAnchors.clear();
153 for (const auto &dsRecord : rootDSs) {
154 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
155 luaconfsCopy.dsAnchors[g_rootdnsname].insert(*ds);
156 }
157 luaconfsCopy.negAnchors.clear();
158 g_luaconfs.setState(luaconfsCopy);
159
160 g_dnssecmode = DNSSECMode::Off;
161 g_dnssecLOG = debug;
162 g_maxNSEC3Iterations = 2500;
163
164 ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Unit Tests";
165 }
166
167 static void initSR(std::unique_ptr<SyncRes>& sr, bool dnssec=false, bool debug=false, time_t fakeNow=0)
168 {
169 struct timeval now;
170 if (fakeNow > 0) {
171 now.tv_sec = fakeNow;
172 now.tv_usec = 0;
173 }
174 else {
175 Utility::gettimeofday(&now, 0);
176 }
177
178 init(debug);
179
180 sr = std::unique_ptr<SyncRes>(new SyncRes(now));
181 sr->setDoEDNS0(true);
182 if (dnssec) {
183 sr->setDoDNSSEC(dnssec);
184 }
185
186 sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
187
188 SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
189 SyncRes::clearNegCache();
190 }
191
192 static void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
193 {
194 sr->setDNSSECValidationRequested(true);
195 g_dnssecmode = mode;
196 }
197
198 static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
199 {
200 res->d_rcode = rcode;
201 res->d_aabit = aa;
202 res->d_tcbit = tc;
203 res->d_haveEDNS = edns;
204 }
205
206 static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
207 {
208 addRecordToList(res->d_records, name, type, content, place, ttl);
209 }
210
211 static void addRecordToLW(LWResult* res, const std::string& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
212 {
213 addRecordToLW(res, DNSName(name), type, content, place, ttl);
214 }
215
216 static bool isRootServer(const ComboAddress& ip)
217 {
218 if (ip.isIPv4()) {
219 for (size_t idx = 0; idx < rootIps4Count; idx++) {
220 if (ip.toString() == rootIps4[idx]) {
221 return true;
222 }
223 }
224 }
225 else {
226 for (size_t idx = 0; idx < rootIps6Count; idx++) {
227 if (ip.toString() == rootIps6[idx]) {
228 return true;
229 }
230 }
231 }
232
233 return false;
234 }
235
236 static void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign, boost::optional<uint8_t> algo=boost::none, boost::optional<uint32_t> inception=boost::none)
237 {
238 time_t now = time(nullptr);
239 DNSKEYRecordContent drc = dpk.getDNSKEY();
240 const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
241
242 rrc.d_type = signQType;
243 rrc.d_labels = signQName.countLabels() - signQName.isWildcard();
244 rrc.d_originalttl = signTTL;
245 rrc.d_siginception = inception ? *inception : (now - 10);
246 rrc.d_sigexpire = now + sigValidity;
247 rrc.d_signer = signer;
248 rrc.d_tag = 0;
249 rrc.d_tag = drc.getTag();
250 rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
251
252 std::string msg = getMessageForRRSET(signQName, rrc, toSign);
253
254 rrc.d_signature = rc->sign(msg);
255 }
256
257 typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t;
258
259 static bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional<uint8_t> algo=boost::none, boost::optional<DNSName> wildcard=boost::none)
260 {
261 if (records.empty()) {
262 return false;
263 }
264
265 const auto it = keys.find(signer);
266 if (it == keys.cend()) {
267 throw std::runtime_error("No DNSKEY found for " + signer.toString() + ", unable to compute the requested RRSIG");
268 }
269
270 size_t recordsCount = records.size();
271 const DNSName& name = records[recordsCount-1].d_name;
272 const uint16_t type = records[recordsCount-1].d_type;
273
274 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
275 for (const auto record : records) {
276 if (record.d_name == name && record.d_type == type) {
277 recordcontents.push_back(record.d_content);
278 }
279 }
280
281 RRSIGRecordContent rrc;
282 computeRRSIG(it->second.first, signer, wildcard ? *wildcard : records[recordsCount-1].d_name, records[recordsCount-1].d_type, records[recordsCount-1].d_ttl, sigValidity, rrc, recordcontents, algo);
283 if (broken) {
284 rrc.d_signature[0] ^= 42;
285 }
286
287 DNSRecord rec;
288 rec.d_type = QType::RRSIG;
289 rec.d_place = records[recordsCount-1].d_place;
290 rec.d_name = records[recordsCount-1].d_name;
291 rec.d_ttl = records[recordsCount-1].d_ttl;
292
293 rec.d_content = std::make_shared<RRSIGRecordContent>(rrc);
294 records.push_back(rec);
295
296 return true;
297 }
298
299 static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records)
300 {
301 const auto it = keys.find(signer);
302 if (it == keys.cend()) {
303 throw std::runtime_error("No DNSKEY found for " + signer.toString());
304 }
305
306 DNSRecord rec;
307 rec.d_place = DNSResourceRecord::ANSWER;
308 rec.d_name = signer;
309 rec.d_type = QType::DNSKEY;
310 rec.d_ttl = ttl;
311
312 rec.d_content = std::make_shared<DNSKEYRecordContent>(it->second.first.getDNSKEY());
313 records.push_back(rec);
314 }
315
316 static bool addDS(const DNSName& domain, uint32_t ttl, std::vector<DNSRecord>& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY)
317 {
318 const auto it = keys.find(domain);
319 if (it == keys.cend()) {
320 return false;
321 }
322
323 DNSRecord rec;
324 rec.d_name = domain;
325 rec.d_type = QType::DS;
326 rec.d_place = place;
327 rec.d_ttl = ttl;
328 rec.d_content = std::make_shared<DSRecordContent>(it->second.second);
329
330 records.push_back(rec);
331 return true;
332 }
333
334 static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
335 {
336 NSECRecordContent nrc;
337 nrc.d_next = next;
338 nrc.d_set = types;
339
340 DNSRecord rec;
341 rec.d_name = domain;
342 rec.d_ttl = ttl;
343 rec.d_type = QType::NSEC;
344 rec.d_content = std::make_shared<NSECRecordContent>(nrc);
345 rec.d_place = DNSResourceRecord::AUTHORITY;
346
347 records.push_back(rec);
348 }
349
350 static void addNSEC3RecordToLW(const DNSName& hashedName, const std::string& hashedNext, const std::string& salt, unsigned int iterations, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
351 {
352 NSEC3RecordContent nrc;
353 nrc.d_algorithm = 1;
354 nrc.d_flags = 0;
355 nrc.d_iterations = iterations;
356 nrc.d_salt = salt;
357 nrc.d_nexthash = hashedNext;
358 nrc.d_set = types;
359
360 DNSRecord rec;
361 rec.d_name = hashedName;
362 rec.d_ttl = ttl;
363 rec.d_type = QType::NSEC3;
364 rec.d_content = std::make_shared<NSEC3RecordContent>(nrc);
365 rec.d_place = DNSResourceRecord::AUTHORITY;
366
367 records.push_back(rec);
368 }
369
370 static void addNSEC3UnhashedRecordToLW(const DNSName& domain, const DNSName& zone, const std::string& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records, unsigned int iterations=10)
371 {
372 static const std::string salt = "deadbeef";
373 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
374
375 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, next, salt, iterations, types, ttl, records);
376 }
377
378 static void addNSEC3NarrowRecordToLW(const DNSName& domain, const DNSName& zone, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records, unsigned int iterations=10)
379 {
380 static const std::string salt = "deadbeef";
381 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
382 std::string hashedNext(hashed);
383 incrementHash(hashedNext);
384 decrementHash(hashed);
385
386 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, hashedNext, salt, iterations, types, ttl, records);
387 }
388
389 static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys)
390 {
391 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(algo));
392 dcke->create((algo <= 10) ? 2048 : dcke->getBits());
393 DNSSECPrivateKey dpk;
394 dpk.d_flags = 256;
395 dpk.setKey(dcke);
396 DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest);
397 keys[name] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk,ds);
398 }
399
400 static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map<DNSName,dsmap_t>& dsAnchors)
401 {
402 generateKeyMaterial(name, algo, digest, keys);
403 dsAnchors[name].insert(keys[name].second);
404 }
405
406 static int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut=true)
407 {
408 if (type == QType::DS) {
409 auth.chopOff();
410
411 setLWResult(res, 0, true, false, true);
412
413 if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) {
414 addRRSIG(keys, res->d_records, auth, 300);
415 }
416 else {
417 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
418
419 /* if the auth zone is signed, we need to provide a secure denial */
420 const auto it = keys.find(auth);
421 if (it != keys.cend()) {
422 /* sign the SOA */
423 addRRSIG(keys, res->d_records, auth, 300);
424 /* add a NSEC denying the DS */
425 std::set<uint16_t> types = { QType::NSEC };
426 if (proveCut) {
427 types.insert(QType::NS);
428 }
429
430 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
431 addRRSIG(keys, res->d_records, auth, 300);
432 }
433 }
434
435 return 1;
436 }
437
438 if (type == QType::DNSKEY) {
439 setLWResult(res, 0, true, false, true);
440 addDNSKEY(keys, domain, 300, res->d_records);
441 addRRSIG(keys, res->d_records, domain, 300);
442 return 1;
443 }
444
445 return 0;
446 }
447
448 /* Real tests */
449
450 BOOST_AUTO_TEST_SUITE(syncres_cc)
451
452 BOOST_AUTO_TEST_CASE(test_root_primed) {
453 std::unique_ptr<SyncRes> sr;
454 initSR(sr);
455
456 primeHints();
457
458 const DNSName target("a.root-servers.net.");
459
460 /* we are primed, we should be able to resolve A a.root-servers.net. without any query */
461 vector<DNSRecord> ret;
462 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
463 BOOST_CHECK_EQUAL(res, RCode::NoError);
464 BOOST_REQUIRE_EQUAL(ret.size(), 1);
465 BOOST_CHECK(ret[0].d_type == QType::A);
466 BOOST_CHECK_EQUAL(ret[0].d_name, target);
467
468 ret.clear();
469 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
470 BOOST_CHECK_EQUAL(res, RCode::NoError);
471 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
472 BOOST_REQUIRE_EQUAL(ret.size(), 1);
473 BOOST_CHECK(ret[0].d_type == QType::AAAA);
474 BOOST_CHECK_EQUAL(ret[0].d_name, target);
475 }
476
477 BOOST_AUTO_TEST_CASE(test_root_primed_ns) {
478 std::unique_ptr<SyncRes> sr;
479 initSR(sr);
480
481 primeHints();
482 const DNSName target(".");
483
484 /* we are primed, but we should not be able to NS . without any query
485 because the . NS entry is not stored as authoritative */
486
487 size_t queriesCount = 0;
488
489 sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
490 queriesCount++;
491
492 if (domain == target && type == QType::NS) {
493
494 setLWResult(res, 0, true, false, true);
495 char addr[] = "a.root-servers.net.";
496 for (char idx = 'a'; idx <= 'm'; idx++) {
497 addr[0] = idx;
498 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
499 }
500
501 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
502 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
503
504 return 1;
505 }
506
507 return 0;
508 });
509
510 vector<DNSRecord> ret;
511 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
512 BOOST_CHECK_EQUAL(res, RCode::NoError);
513 BOOST_REQUIRE_EQUAL(ret.size(), 13);
514 BOOST_CHECK_EQUAL(queriesCount, 1);
515 }
516
517 BOOST_AUTO_TEST_CASE(test_root_not_primed) {
518 std::unique_ptr<SyncRes> sr;
519 initSR(sr);
520
521 size_t queriesCount = 0;
522
523 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
524 queriesCount++;
525
526 if (domain == g_rootdnsname && type == QType::NS) {
527 setLWResult(res, 0, true, false, true);
528 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
529 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
530 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
531
532 return 1;
533 }
534
535 return 0;
536 });
537
538 /* we are not primed yet, so SyncRes will have to call primeHints()
539 then call getRootNS(), for which at least one of the root servers needs to answer */
540 vector<DNSRecord> ret;
541 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
542 BOOST_CHECK_EQUAL(res, RCode::NoError);
543 BOOST_CHECK_EQUAL(ret.size(), 1);
544 BOOST_CHECK_EQUAL(queriesCount, 2);
545 }
546
547 BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
548 std::unique_ptr<SyncRes> sr;
549 initSR(sr);
550 std::set<ComboAddress> downServers;
551
552 /* we are not primed yet, so SyncRes will have to call primeHints()
553 then call getRootNS(), for which at least one of the root servers needs to answer.
554 None will, so it should ServFail.
555 */
556 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
557
558 downServers.insert(ip);
559 return 0;
560 });
561
562 vector<DNSRecord> ret;
563 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
564 BOOST_CHECK_EQUAL(res, RCode::ServFail);
565 BOOST_CHECK_EQUAL(ret.size(), 0);
566 BOOST_CHECK(downServers.size() > 0);
567 /* we explicitly refuse to mark the root servers down */
568 for (const auto& server : downServers) {
569 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
570 }
571 }
572
573 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
574 std::unique_ptr<SyncRes> sr;
575 initSR(sr);
576
577 ComboAddress noEDNSServer;
578 size_t queriesWithEDNS = 0;
579 size_t queriesWithoutEDNS = 0;
580
581 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &noEDNSServer](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
582 if (EDNS0Level != 0) {
583 queriesWithEDNS++;
584 noEDNSServer = ip;
585
586 setLWResult(res, RCode::FormErr);
587 return 1;
588 }
589
590 queriesWithoutEDNS++;
591
592 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
593 setLWResult(res, 0, true, false, false);
594 addRecordToLW(res, domain, QType::A, "192.0.2.1");
595 return 1;
596 }
597
598 return 0;
599 });
600
601 primeHints();
602
603 /* fake that the root NS doesn't handle EDNS, check that we fallback */
604 vector<DNSRecord> ret;
605 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
606 BOOST_CHECK_EQUAL(res, RCode::NoError);
607 BOOST_CHECK_EQUAL(ret.size(), 1);
608 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
609 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
610 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
611 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
612 }
613
614 BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) {
615 std::unique_ptr<SyncRes> sr;
616 initSR(sr);
617
618 size_t queriesWithEDNS = 0;
619 size_t queriesWithoutEDNS = 0;
620
621 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
622 if (EDNS0Level != 0) {
623 queriesWithEDNS++;
624 setLWResult(res, RCode::NotImp);
625 return 1;
626 }
627
628 queriesWithoutEDNS++;
629
630 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
631 setLWResult(res, 0, true, false, false);
632 addRecordToLW(res, domain, QType::A, "192.0.2.1");
633 return 1;
634 }
635
636 return 0;
637 });
638
639 primeHints();
640
641 /* fake that the NS doesn't handle EDNS, check that we fallback */
642 vector<DNSRecord> ret;
643 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
644 BOOST_CHECK_EQUAL(res, RCode::NoError);
645 BOOST_CHECK_EQUAL(ret.size(), 1);
646 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
647 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
648 }
649
650 BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
651 std::unique_ptr<SyncRes> sr;
652 initSR(sr);
653
654 sr->setAsyncCallback([](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
655 if (!doTCP) {
656 setLWResult(res, 0, false, true, false);
657 return 1;
658 }
659 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
660 setLWResult(res, 0, true, false, false);
661 addRecordToLW(res, domain, QType::A, "192.0.2.1");
662 return 1;
663 }
664
665 return 0;
666 });
667
668 primeHints();
669
670 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
671 vector<DNSRecord> ret;
672 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
673 BOOST_CHECK_EQUAL(res, RCode::NoError);
674 }
675
676 BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
677 std::unique_ptr<SyncRes> sr;
678 initSR(sr);
679
680 size_t tcpQueriesCount = 0;
681
682 sr->setAsyncCallback([&tcpQueriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
683 if (!doTCP) {
684 setLWResult(res, 0, true, true, false);
685 return 1;
686 }
687
688 /* first TCP query is answered with a TC response */
689 tcpQueriesCount++;
690 if (tcpQueriesCount == 1) {
691 setLWResult(res, 0, true, true, false);
692 }
693 else {
694 setLWResult(res, 0, true, false, false);
695 }
696
697 addRecordToLW(res, domain, QType::A, "192.0.2.1");
698 return 1;
699 });
700
701 primeHints();
702
703 vector<DNSRecord> ret;
704 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
705 BOOST_CHECK_EQUAL(res, RCode::NoError);
706 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
707 }
708
709 BOOST_AUTO_TEST_CASE(test_all_nss_down) {
710 std::unique_ptr<SyncRes> sr;
711 initSR(sr);
712 std::set<ComboAddress> downServers;
713
714 primeHints();
715
716 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
717
718 if (isRootServer(ip)) {
719 setLWResult(res, 0, false, false, true);
720 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
721 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
722 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
723 return 1;
724 }
725 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
726 setLWResult(res, 0, false, false, true);
727 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
728 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
729 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
730 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
731 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
732 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
733 return 1;
734 }
735 else {
736 downServers.insert(ip);
737 return 0;
738 }
739 });
740
741 DNSName target("powerdns.com.");
742
743 vector<DNSRecord> ret;
744 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
745 BOOST_CHECK_EQUAL(res, RCode::ServFail);
746 BOOST_CHECK_EQUAL(ret.size(), 0);
747 BOOST_CHECK_EQUAL(downServers.size(), 4);
748
749 for (const auto& server : downServers) {
750 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
751 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
752 }
753 }
754
755 BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
756 std::unique_ptr<SyncRes> sr;
757 initSR(sr);
758 std::set<ComboAddress> downServers;
759
760 primeHints();
761
762 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
763
764 if (isRootServer(ip)) {
765 setLWResult(res, 0, false, false, true);
766 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
767 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
768 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
769 return 1;
770 }
771 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
772 setLWResult(res, 0, false, false, true);
773 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
774 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
775 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
776 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
777 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
778 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
779 return 1;
780 }
781 else {
782 downServers.insert(ip);
783 return 0;
784 }
785 });
786
787 /* exact same test than the previous one, except instead of a time out we fake a network error */
788 DNSName target("powerdns.com.");
789
790 vector<DNSRecord> ret;
791 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
792 BOOST_CHECK_EQUAL(res, RCode::ServFail);
793 BOOST_CHECK_EQUAL(ret.size(), 0);
794 BOOST_CHECK_EQUAL(downServers.size(), 4);
795
796 for (const auto& server : downServers) {
797 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
798 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
799 }
800 }
801
802 BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) {
803 std::unique_ptr<SyncRes> sr;
804 initSR(sr);
805
806 primeHints();
807
808 DNSName target("www.powerdns.com.");
809
810 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
811
812 if (isRootServer(ip)) {
813 setLWResult(res, 0, false, false, true);
814 if (domain == target) {
815 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
816 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
817 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
818 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
819 }
820 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
821 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
822 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
823 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
824 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
825 }
826 return 1;
827 }
828 else if (ip == ComboAddress("192.0.2.3:53")) {
829 setLWResult(res, 0, true, false, true);
830 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
831 if (type == QType::A) {
832 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
833 }
834 else if (type == QType::AAAA) {
835 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
836 }
837 }
838 else if (domain == target) {
839 if (type == QType::A) {
840 addRecordToLW(res, domain, QType::A, "192.0.2.1");
841 }
842 else if (type == QType::AAAA) {
843 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
844 }
845 }
846 return 1;
847 }
848 return 0;
849 });
850
851 vector<DNSRecord> ret;
852 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
853 BOOST_CHECK_EQUAL(res, RCode::NoError);
854 BOOST_CHECK_EQUAL(ret.size(), 1);
855 }
856
857 BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
858 std::unique_ptr<SyncRes> sr;
859 initSR(sr);
860 std::set<ComboAddress> downServers;
861
862 primeHints();
863
864 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
865
866 if (isRootServer(ip)) {
867 setLWResult(res, 0, false, false, true);
868 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
869 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
870 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
871 return 1;
872 }
873 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
874 setLWResult(res, 0, false, false, true);
875 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
876 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
877 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
878 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
879 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
880 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
881 return 1;
882 }
883 else {
884 if (downServers.size() < 3) {
885 /* only the last one will answer */
886 downServers.insert(ip);
887 return -2;
888 }
889 else {
890 setLWResult(res, 0, true, false, true);
891 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
892 return 1;
893 }
894 }
895 });
896
897 DNSName target("powerdns.com.");
898
899 vector<DNSRecord> ret;
900 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
901 BOOST_CHECK_EQUAL(res, RCode::NoError);
902 BOOST_CHECK_EQUAL(ret.size(), 1);
903 BOOST_CHECK_EQUAL(downServers.size(), 3);
904
905 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
906 for (const auto& server : downServers) {
907 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
908 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
909 }
910 }
911
912 BOOST_AUTO_TEST_CASE(test_glued_referral) {
913 std::unique_ptr<SyncRes> sr;
914 initSR(sr);
915
916 primeHints();
917
918 const DNSName target("powerdns.com.");
919
920 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
921 /* this will cause issue with qname minimization if we ever implement it */
922 if (domain != target) {
923 return 0;
924 }
925
926 if (isRootServer(ip)) {
927 setLWResult(res, 0, false, false, true);
928 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
929 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
930 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
931 return 1;
932 }
933 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
934 setLWResult(res, 0, false, false, true);
935 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
936 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
937 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
938 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
939 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
940 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
941 return 1;
942 }
943 else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) {
944 setLWResult(res, 0, true, false, true);
945 addRecordToLW(res, target, QType::A, "192.0.2.4");
946 return 1;
947 }
948 else {
949 return 0;
950 }
951 });
952
953 vector<DNSRecord> ret;
954 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
955 BOOST_CHECK_EQUAL(res, RCode::NoError);
956 BOOST_REQUIRE_EQUAL(ret.size(), 1);
957 BOOST_CHECK(ret[0].d_type == QType::A);
958 BOOST_CHECK_EQUAL(ret[0].d_name, target);
959 }
960
961 BOOST_AUTO_TEST_CASE(test_glueless_referral) {
962 std::unique_ptr<SyncRes> sr;
963 initSR(sr);
964
965 primeHints();
966
967 const DNSName target("powerdns.com.");
968
969 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
970
971 if (isRootServer(ip)) {
972 setLWResult(res, 0, false, false, true);
973
974 if (domain.isPartOf(DNSName("com."))) {
975 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
976 } else if (domain.isPartOf(DNSName("org."))) {
977 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
978 }
979 else {
980 setLWResult(res, RCode::NXDomain, false, false, true);
981 return 1;
982 }
983
984 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
985 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
986 return 1;
987 }
988 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
989 if (domain == target) {
990 setLWResult(res, 0, false, false, true);
991 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
992 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
993 return 1;
994 }
995 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
996 setLWResult(res, 0, true, false, true);
997 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
998 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
999 return 1;
1000 }
1001 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
1002 setLWResult(res, 0, true, false, true);
1003 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
1004 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
1005 return 1;
1006 }
1007
1008 setLWResult(res, RCode::NXDomain, false, false, true);
1009 return 1;
1010 }
1011 else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) {
1012 setLWResult(res, 0, true, false, true);
1013 addRecordToLW(res, target, QType::A, "192.0.2.4");
1014 return 1;
1015 }
1016 else {
1017 return 0;
1018 }
1019 });
1020
1021 vector<DNSRecord> ret;
1022 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1023 BOOST_CHECK_EQUAL(res, RCode::NoError);
1024 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1025 BOOST_CHECK(ret[0].d_type == QType::A);
1026 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1027 }
1028
1029 BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
1030 std::unique_ptr<SyncRes> sr;
1031 initSR(sr);
1032
1033 primeHints();
1034
1035 const DNSName target("powerdns.com.");
1036 SyncRes::addEDNSDomain(target);
1037
1038 EDNSSubnetOpts incomingECS;
1039 incomingECS.source = Netmask("192.0.2.128/32");
1040 sr->setIncomingECSFound(true);
1041 sr->setIncomingECS(incomingECS);
1042
1043 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1044
1045 BOOST_REQUIRE(srcmask);
1046 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1047 return 0;
1048 });
1049
1050 vector<DNSRecord> ret;
1051 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1052 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1053 }
1054
1055 BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
1056 std::unique_ptr<SyncRes> sr;
1057 initSR(sr);
1058
1059 primeHints();
1060
1061 const DNSName target("powerdns.com.");
1062 SyncRes::addEDNSSubnet(Netmask("192.0.2.1/32"));
1063
1064 EDNSSubnetOpts incomingECS;
1065 incomingECS.source = Netmask("2001:DB8::FF/128");
1066 sr->setIncomingECSFound(true);
1067 sr->setIncomingECS(incomingECS);
1068
1069 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1070
1071 if (isRootServer(ip)) {
1072 BOOST_REQUIRE(!srcmask);
1073
1074 setLWResult(res, 0, false, false, true);
1075 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1076 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1077 return 1;
1078 } else if (ip == ComboAddress("192.0.2.1:53")) {
1079
1080 BOOST_REQUIRE(srcmask);
1081 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1082
1083 setLWResult(res, 0, true, false, false);
1084 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1085 return 1;
1086 }
1087
1088 return 0;
1089 });
1090
1091 vector<DNSRecord> ret;
1092 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1093 BOOST_CHECK_EQUAL(res, RCode::NoError);
1094 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1095 BOOST_CHECK(ret[0].d_type == QType::A);
1096 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1097 }
1098
1099 BOOST_AUTO_TEST_CASE(test_following_cname) {
1100 std::unique_ptr<SyncRes> sr;
1101 initSR(sr);
1102
1103 primeHints();
1104
1105 const DNSName target("cname.powerdns.com.");
1106 const DNSName cnameTarget("cname-target.powerdns.com");
1107
1108 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1109
1110 if (isRootServer(ip)) {
1111 setLWResult(res, 0, false, false, true);
1112 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1113 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1114 return 1;
1115 } else if (ip == ComboAddress("192.0.2.1:53")) {
1116
1117 if (domain == target) {
1118 setLWResult(res, 0, true, false, false);
1119 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1120 return 1;
1121 }
1122 else if (domain == cnameTarget) {
1123 setLWResult(res, 0, true, false, false);
1124 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1125 }
1126
1127 return 1;
1128 }
1129
1130 return 0;
1131 });
1132
1133 vector<DNSRecord> ret;
1134 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1135 BOOST_CHECK_EQUAL(res, RCode::NoError);
1136 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1137 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1138 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1139 BOOST_CHECK(ret[1].d_type == QType::A);
1140 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1141 }
1142
1143 BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
1144 std::unique_ptr<SyncRes> sr;
1145 initSR(sr);
1146
1147 primeHints();
1148
1149 const DNSName target("cname.powerdns.com.");
1150 const DNSName cnameTarget("cname-target.powerdns.com");
1151
1152 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1153
1154 if (isRootServer(ip)) {
1155 setLWResult(res, 0, false, false, true);
1156 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1157 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1158 return 1;
1159 } else if (ip == ComboAddress("192.0.2.1:53")) {
1160
1161 if (domain == target) {
1162 setLWResult(res, RCode::NXDomain, true, false, false);
1163 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1164 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1165 } else if (domain == cnameTarget) {
1166 setLWResult(res, RCode::NXDomain, true, false, false);
1167 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1168 return 1;
1169 }
1170
1171 return 1;
1172 }
1173
1174 return 0;
1175 });
1176
1177 vector<DNSRecord> ret;
1178 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1179 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1180 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1181 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1182 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1183 BOOST_CHECK(ret[1].d_type == QType::SOA);
1184
1185 /* a second time, to check the cache */
1186 ret.clear();
1187 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1188 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1189 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1190 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1191 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1192 BOOST_CHECK(ret[1].d_type == QType::SOA);
1193 }
1194
1195 BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1196 std::unique_ptr<SyncRes> sr;
1197 initSR(sr);
1198
1199 primeHints();
1200
1201 /* In this test we directly get the NS server for cname.powerdns.com.,
1202 and we don't know whether it's also authoritative for
1203 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1204 the additional A record for cname-target.powerdns.com. */
1205 const DNSName target("cname.powerdns.com.");
1206 const DNSName cnameTarget("cname-target.powerdns.com");
1207
1208 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1209
1210 if (isRootServer(ip)) {
1211
1212 setLWResult(res, 0, false, false, true);
1213
1214 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1215 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1216 return 1;
1217 } else if (ip == ComboAddress("192.0.2.1:53")) {
1218
1219 if (domain == target) {
1220 setLWResult(res, 0, true, false, false);
1221 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1222 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1223 return 1;
1224 } else if (domain == cnameTarget) {
1225 setLWResult(res, 0, true, false, false);
1226 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1227 return 1;
1228 }
1229
1230 return 1;
1231 }
1232
1233 return 0;
1234 });
1235
1236 vector<DNSRecord> ret;
1237 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1238 BOOST_CHECK_EQUAL(res, RCode::NoError);
1239 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1240 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1241 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1242 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1243 BOOST_REQUIRE(ret[1].d_type == QType::A);
1244 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1245 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1246 }
1247
1248 BOOST_AUTO_TEST_CASE(test_cname_loop) {
1249 std::unique_ptr<SyncRes> sr;
1250 initSR(sr);
1251
1252 primeHints();
1253
1254 size_t count = 0;
1255 const DNSName target("cname.powerdns.com.");
1256
1257 sr->setAsyncCallback([target,&count](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1258
1259 count++;
1260
1261 if (isRootServer(ip)) {
1262
1263 setLWResult(res, 0, false, false, true);
1264 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1265 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1266 return 1;
1267 } else if (ip == ComboAddress("192.0.2.1:53")) {
1268
1269 if (domain == target) {
1270 setLWResult(res, 0, true, false, false);
1271 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1272 return 1;
1273 }
1274
1275 return 1;
1276 }
1277
1278 return 0;
1279 });
1280
1281 vector<DNSRecord> ret;
1282 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1283 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1284 BOOST_CHECK_GT(ret.size(), 0);
1285 BOOST_CHECK_EQUAL(count, 2);
1286 }
1287
1288 BOOST_AUTO_TEST_CASE(test_cname_depth) {
1289 std::unique_ptr<SyncRes> sr;
1290 initSR(sr);
1291
1292 primeHints();
1293
1294 size_t depth = 0;
1295 const DNSName target("cname.powerdns.com.");
1296
1297 sr->setAsyncCallback([target,&depth](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1298
1299 if (isRootServer(ip)) {
1300
1301 setLWResult(res, 0, false, false, true);
1302 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1303 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1304 return 1;
1305 } else if (ip == ComboAddress("192.0.2.1:53")) {
1306
1307 setLWResult(res, 0, true, false, false);
1308 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1309 depth++;
1310 return 1;
1311 }
1312
1313 return 0;
1314 });
1315
1316 vector<DNSRecord> ret;
1317 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1318 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1319 BOOST_CHECK_EQUAL(ret.size(), depth);
1320 /* we have an arbitrary limit at 10 when following a CNAME chain */
1321 BOOST_CHECK_EQUAL(depth, 10 + 2);
1322 }
1323
1324 BOOST_AUTO_TEST_CASE(test_time_limit) {
1325 std::unique_ptr<SyncRes> sr;
1326 initSR(sr);
1327
1328 primeHints();
1329
1330 size_t queries = 0;
1331 const DNSName target("cname.powerdns.com.");
1332
1333 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1334
1335 queries++;
1336
1337 if (isRootServer(ip)) {
1338 setLWResult(res, 0, false, false, true);
1339 /* Pretend that this query took 2000 ms */
1340 res->d_usec = 2000;
1341
1342 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1343 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1344 return 1;
1345 } else if (ip == ComboAddress("192.0.2.1:53")) {
1346
1347 setLWResult(res, 0, true, false, false);
1348 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1349 return 1;
1350 }
1351
1352 return 0;
1353 });
1354
1355 /* Set the maximum time to 1 ms */
1356 SyncRes::s_maxtotusec = 1000;
1357
1358 try {
1359 vector<DNSRecord> ret;
1360 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1361 BOOST_CHECK(false);
1362 }
1363 catch(const ImmediateServFailException& e) {
1364 }
1365 BOOST_CHECK_EQUAL(queries, 1);
1366 }
1367
1368 BOOST_AUTO_TEST_CASE(test_referral_depth) {
1369 std::unique_ptr<SyncRes> sr;
1370 initSR(sr);
1371
1372 primeHints();
1373
1374 size_t queries = 0;
1375 const DNSName target("www.powerdns.com.");
1376
1377 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1378
1379 queries++;
1380
1381 if (isRootServer(ip)) {
1382 setLWResult(res, 0, false, false, true);
1383
1384 if (domain == DNSName("www.powerdns.com.")) {
1385 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1386 }
1387 else if (domain == DNSName("ns.powerdns.com.")) {
1388 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1389 }
1390 else if (domain == DNSName("ns1.powerdns.org.")) {
1391 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1392 }
1393 else if (domain == DNSName("ns2.powerdns.org.")) {
1394 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1395 }
1396 else if (domain == DNSName("ns3.powerdns.org.")) {
1397 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1398 }
1399 else if (domain == DNSName("ns4.powerdns.org.")) {
1400 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1401 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1402 }
1403
1404 return 1;
1405 } else if (ip == ComboAddress("192.0.2.1:53")) {
1406
1407 setLWResult(res, 0, true, false, false);
1408 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1409 return 1;
1410 }
1411
1412 return 0;
1413 });
1414
1415 /* Set the maximum depth low */
1416 SyncRes::s_maxdepth = 10;
1417
1418 try {
1419 vector<DNSRecord> ret;
1420 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1421 BOOST_CHECK(false);
1422 }
1423 catch(const ImmediateServFailException& e) {
1424 }
1425 }
1426
1427 BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1428 std::unique_ptr<SyncRes> sr;
1429 initSR(sr);
1430
1431 primeHints();
1432
1433 size_t queries = 0;
1434 const DNSName target("cname.powerdns.com.");
1435
1436 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1437
1438 queries++;
1439
1440 if (isRootServer(ip)) {
1441
1442 setLWResult(res, 0, false, false, true);
1443 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1444 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1445 return 1;
1446 } else if (ip == ComboAddress("192.0.2.1:53")) {
1447
1448 setLWResult(res, 0, true, false, false);
1449 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1450 return 1;
1451 }
1452
1453 return 0;
1454 });
1455
1456 /* Set the maximum number of questions very low */
1457 SyncRes::s_maxqperq = 5;
1458
1459 try {
1460 vector<DNSRecord> ret;
1461 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1462 BOOST_CHECK(false);
1463 }
1464 catch(const ImmediateServFailException& e) {
1465 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1466 }
1467 }
1468
1469 BOOST_AUTO_TEST_CASE(test_throttled_server) {
1470 std::unique_ptr<SyncRes> sr;
1471 initSR(sr);
1472
1473 primeHints();
1474
1475 const DNSName target("throttled.powerdns.com.");
1476 const ComboAddress ns("192.0.2.1:53");
1477 size_t queriesToNS = 0;
1478
1479 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1480
1481 if (isRootServer(ip)) {
1482
1483 setLWResult(res, 0, false, false, true);
1484 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1485 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1486 return 1;
1487 } else if (ip == ns) {
1488
1489 queriesToNS++;
1490
1491 setLWResult(res, 0, true, false, false);
1492 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1493
1494 return 1;
1495 }
1496
1497 return 0;
1498 });
1499
1500 /* mark ns as down */
1501 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, 10000);
1502
1503 vector<DNSRecord> ret;
1504 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1505 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1506 BOOST_CHECK_EQUAL(ret.size(), 0);
1507 /* we should not have sent any queries to ns */
1508 BOOST_CHECK_EQUAL(queriesToNS, 0);
1509 }
1510
1511 BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1512 std::unique_ptr<SyncRes> sr;
1513 initSR(sr);
1514
1515 primeHints();
1516
1517 const ComboAddress ns("192.0.2.1:53");
1518
1519 const size_t blocks = 10;
1520 /* mark ns as down for 'blocks' queries */
1521 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, blocks);
1522
1523 for (size_t idx = 0; idx < blocks; idx++) {
1524 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1525 }
1526
1527 /* we have been throttled 'blocks' times, we should not be throttled anymore */
1528 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1529 }
1530
1531 BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1532 std::unique_ptr<SyncRes> sr;
1533 initSR(sr);
1534
1535 primeHints();
1536
1537 const ComboAddress ns("192.0.2.1:53");
1538
1539 const size_t seconds = 1;
1540 /* mark ns as down for 'seconds' seconds */
1541 SyncRes::doThrottle(time(nullptr), ns, seconds, 10000);
1542
1543 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1544
1545 sleep(seconds + 1);
1546
1547 /* we should not be throttled anymore */
1548 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1549 }
1550
1551 BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1552 std::unique_ptr<SyncRes> sr;
1553 initSR(sr);
1554
1555 primeHints();
1556
1557 const DNSName target("throttled.powerdns.com.");
1558 const ComboAddress ns("192.0.2.1:53");
1559 size_t queriesToNS = 0;
1560
1561 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1562
1563 if (isRootServer(ip)) {
1564
1565 setLWResult(res, 0, false, false, true);
1566 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1567 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1568 return 1;
1569 } else if (ip == ns) {
1570
1571 queriesToNS++;
1572
1573 setLWResult(res, 0, true, false, false);
1574 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1575
1576 return 1;
1577 }
1578
1579 return 0;
1580 });
1581
1582 /* prevent querying this NS */
1583 SyncRes::addDontQuery(Netmask(ns));
1584
1585 vector<DNSRecord> ret;
1586 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1587 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1588 BOOST_CHECK_EQUAL(ret.size(), 0);
1589 /* we should not have sent any queries to ns */
1590 BOOST_CHECK_EQUAL(queriesToNS, 0);
1591 }
1592
1593 BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1594 std::unique_ptr<SyncRes> sr;
1595 initSR(sr);
1596
1597 primeHints();
1598
1599 const DNSName target1("powerdns.com.");
1600 const DNSName target2("notpowerdns.com.");
1601 const ComboAddress ns("192.0.2.1:53");
1602 size_t queriesCount = 0;
1603
1604 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1605
1606 queriesCount++;
1607
1608 if (isRootServer(ip)) {
1609
1610 if (domain == target1) {
1611 setLWResult(res, RCode::NXDomain, true, false, true);
1612 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1613 }
1614 else {
1615 setLWResult(res, 0, true, false, true);
1616 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1617 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1618 }
1619
1620 return 1;
1621 } else if (ip == ns) {
1622
1623 setLWResult(res, 0, true, false, false);
1624 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1625
1626 return 1;
1627 }
1628
1629 return 0;
1630 });
1631
1632 vector<DNSRecord> ret;
1633 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1634 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1635 BOOST_CHECK_EQUAL(ret.size(), 1);
1636 /* one for target1 and one for the entire TLD */
1637 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1638
1639 ret.clear();
1640 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1641 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1642 BOOST_CHECK_EQUAL(ret.size(), 1);
1643 /* one for target1 and one for the entire TLD */
1644 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1645
1646 /* we should have sent only one query */
1647 BOOST_CHECK_EQUAL(queriesCount, 1);
1648 }
1649
1650 BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1651 std::unique_ptr<SyncRes> sr;
1652 init();
1653 initSR(sr, true, false);
1654
1655 primeHints();
1656
1657 const DNSName target1("powerdns.com.");
1658 const DNSName target2("notpowerdns.com.");
1659 const ComboAddress ns("192.0.2.1:53");
1660 size_t queriesCount = 0;
1661
1662 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1663 We should add target1 to the negcache, but not "com.". */
1664
1665 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1666
1667 queriesCount++;
1668
1669 if (isRootServer(ip)) {
1670
1671 if (domain == target1) {
1672 setLWResult(res, RCode::NXDomain, true, false, true);
1673 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1674 }
1675 else {
1676 setLWResult(res, 0, true, false, true);
1677 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1678 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1679 }
1680
1681 return 1;
1682 } else if (ip == ns) {
1683
1684 setLWResult(res, 0, true, false, false);
1685 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1686
1687 return 1;
1688 }
1689
1690 return 0;
1691 });
1692
1693 vector<DNSRecord> ret;
1694 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1695 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1696 BOOST_CHECK_EQUAL(ret.size(), 1);
1697
1698 /* even with root-nx-trust on and a NX answer from the root,
1699 we should not have cached the entire TLD this time. */
1700 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1701
1702 ret.clear();
1703 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1704 BOOST_CHECK_EQUAL(res, RCode::NoError);
1705 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1706 BOOST_REQUIRE(ret[0].d_type == QType::A);
1707 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1708 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1709
1710 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1711
1712 BOOST_CHECK_EQUAL(queriesCount, 3);
1713 }
1714
1715 BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1716 std::unique_ptr<SyncRes> sr;
1717 initSR(sr);
1718
1719 primeHints();
1720
1721 const DNSName target1("powerdns.com.");
1722 const DNSName target2("notpowerdns.com.");
1723 const ComboAddress ns("192.0.2.1:53");
1724 size_t queriesCount = 0;
1725
1726 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1727
1728 queriesCount++;
1729
1730 if (isRootServer(ip)) {
1731
1732 if (domain == target1) {
1733 setLWResult(res, RCode::NXDomain, true, false, true);
1734 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1735 }
1736 else {
1737 setLWResult(res, 0, true, false, true);
1738 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1739 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1740 }
1741
1742 return 1;
1743 } else if (ip == ns) {
1744
1745 setLWResult(res, 0, true, false, false);
1746 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1747
1748 return 1;
1749 }
1750
1751 return 0;
1752 });
1753
1754 SyncRes::s_rootNXTrust = false;
1755
1756 vector<DNSRecord> ret;
1757 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1758 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1759 BOOST_CHECK_EQUAL(ret.size(), 1);
1760 /* one for target1 */
1761 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1762
1763 ret.clear();
1764 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1765 BOOST_CHECK_EQUAL(res, RCode::NoError);
1766 BOOST_CHECK_EQUAL(ret.size(), 1);
1767 /* one for target1 */
1768 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1769
1770 /* we should have sent three queries */
1771 BOOST_CHECK_EQUAL(queriesCount, 3);
1772 }
1773
1774 BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1775 std::unique_ptr<SyncRes> sr;
1776 initSR(sr);
1777
1778 primeHints();
1779
1780 const DNSName target("www.powerdns.com.");
1781 const DNSName cnameTarget("cname.powerdns.com.");
1782
1783 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
1784
1785 EDNSSubnetOpts incomingECS;
1786 incomingECS.source = Netmask("192.0.2.128/32");
1787 sr->setIncomingECSFound(true);
1788 sr->setIncomingECS(incomingECS);
1789
1790 sr->setAsyncCallback([target,cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1791
1792 BOOST_REQUIRE(srcmask);
1793 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1794
1795 if (isRootServer(ip)) {
1796 setLWResult(res, 0, false, false, true);
1797 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1798 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1799
1800 return 1;
1801 } else if (ip == ComboAddress("192.0.2.1:53")) {
1802 if (domain == target) {
1803 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
1804 setLWResult(res, RCode::NXDomain, true, false, true);
1805 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1806 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1807 }
1808 else if (domain == cnameTarget) {
1809 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
1810 but we might if we still chase the CNAME. */
1811 setLWResult(res, RCode::NXDomain, true, false, true);
1812 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1813 }
1814
1815 return 1;
1816 }
1817
1818 return 0;
1819 });
1820
1821 vector<DNSRecord> ret;
1822 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1823 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1824 BOOST_CHECK_EQUAL(ret.size(), 2);
1825 /* no negative cache entry because the response was variable */
1826 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
1827 }
1828
1829 BOOST_AUTO_TEST_CASE(test_ns_speed) {
1830 std::unique_ptr<SyncRes> sr;
1831 initSR(sr);
1832
1833 primeHints();
1834
1835 const DNSName target("powerdns.com.");
1836
1837 std::map<ComboAddress, uint64_t> nsCounts;
1838
1839 sr->setAsyncCallback([target,&nsCounts](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1840
1841 if (isRootServer(ip)) {
1842 setLWResult(res, 0, false, false, true);
1843 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1844 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1845 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1846
1847 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1848 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1849 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1850 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
1851 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
1852 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
1853
1854 return 1;
1855 } else {
1856 nsCounts[ip]++;
1857
1858 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
1859 BOOST_CHECK_LT(nsCounts.size(), 3);
1860
1861 /* let's time out on pdns-public-ns2.powerdns.com. */
1862 return 0;
1863 }
1864 else if (ip == ComboAddress("192.0.2.1:53")) {
1865 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1866
1867 setLWResult(res, 0, true, false, true);
1868 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1869 return 1;
1870 }
1871
1872 return 0;
1873 }
1874
1875 return 0;
1876 });
1877
1878 struct timeval now;
1879 gettimeofday(&now, 0);
1880
1881 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
1882 then pdns-public-ns1.powerdns.com. on IPv4 */
1883 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
1884 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
1885 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
1886 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
1887 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
1888 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
1889
1890 vector<DNSRecord> ret;
1891 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1892 BOOST_CHECK_EQUAL(res, RCode::NoError);
1893 BOOST_CHECK_EQUAL(ret.size(), 1);
1894 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1895 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
1896 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
1897 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
1898 }
1899
1900 BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
1901 std::unique_ptr<SyncRes> sr;
1902 initSR(sr);
1903
1904 primeHints();
1905
1906 const DNSName target("powerdns.com.");
1907
1908 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1909
1910 if (isRootServer(ip)) {
1911 setLWResult(res, 0, false, false, true);
1912 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1913
1914 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1915
1916 return 1;
1917 } else if (ip == ComboAddress("192.0.2.1:53")) {
1918 setLWResult(res, 0, true, false, true);
1919 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1920 return 1;
1921 }
1922
1923 return 0;
1924 });
1925
1926 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
1927 time_t now = sr->getNow().tv_sec;
1928 std::vector<DNSRecord> records;
1929 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1930 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
1931
1932 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1933
1934 vector<DNSRecord> ret;
1935 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1936 BOOST_CHECK_EQUAL(res, RCode::NoError);
1937 BOOST_CHECK_EQUAL(ret.size(), 1);
1938 }
1939
1940 BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
1941 std::unique_ptr<SyncRes> sr;
1942 initSR(sr);
1943
1944 primeHints();
1945
1946 const DNSName target("powerdns.com.");
1947 size_t queriesCount = 0;
1948
1949 sr->setAsyncCallback([&queriesCount,target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1950
1951 queriesCount++;
1952
1953 if (isRootServer(ip) && domain == target) {
1954 setLWResult(res, 0, false, false, true);
1955 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1956 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1957 return 1;
1958 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
1959 setLWResult(res, 0, true, false, true);
1960 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1961 return 1;
1962 }
1963
1964 return 0;
1965 });
1966
1967 vector<DNSRecord> ret;
1968 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1969 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1970 BOOST_CHECK_EQUAL(ret.size(), 0);
1971 /* one query to get NSs, then A and AAAA for each NS */
1972 BOOST_CHECK_EQUAL(queriesCount, 5);
1973 }
1974
1975 BOOST_AUTO_TEST_CASE(test_cache_hit) {
1976 std::unique_ptr<SyncRes> sr;
1977 initSR(sr);
1978
1979 primeHints();
1980
1981 const DNSName target("powerdns.com.");
1982
1983 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1984
1985 return 0;
1986 });
1987
1988 /* we populate the cache with eveything we need */
1989 time_t now = sr->getNow().tv_sec;
1990 std::vector<DNSRecord> records;
1991 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1992
1993 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
1994 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1995
1996 vector<DNSRecord> ret;
1997 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1998 BOOST_CHECK_EQUAL(res, RCode::NoError);
1999 BOOST_CHECK_EQUAL(ret.size(), 1);
2000 }
2001
2002 BOOST_AUTO_TEST_CASE(test_no_rd) {
2003 std::unique_ptr<SyncRes> sr;
2004 initSR(sr);
2005
2006 primeHints();
2007
2008 const DNSName target("powerdns.com.");
2009 size_t queriesCount = 0;
2010
2011 sr->setCacheOnly();
2012
2013 sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2014
2015 queriesCount++;
2016 return 0;
2017 });
2018
2019 vector<DNSRecord> ret;
2020 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2021 BOOST_CHECK_EQUAL(res, RCode::NoError);
2022 BOOST_CHECK_EQUAL(ret.size(), 0);
2023 BOOST_CHECK_EQUAL(queriesCount, 0);
2024 }
2025
2026 BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
2027 std::unique_ptr<SyncRes> sr;
2028 initSR(sr);
2029
2030 primeHints();
2031
2032 const DNSName target("cachettl.powerdns.com.");
2033 const ComboAddress ns("192.0.2.1:53");
2034
2035 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2036
2037 if (isRootServer(ip)) {
2038
2039 setLWResult(res, 0, false, false, true);
2040 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2041 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
2042 return 1;
2043 } else if (ip == ns) {
2044
2045 setLWResult(res, 0, true, false, false);
2046 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2047
2048 return 1;
2049 }
2050
2051 return 0;
2052 });
2053
2054 const time_t now = sr->getNow().tv_sec;
2055 SyncRes::s_minimumTTL = 60;
2056 SyncRes::s_maxcachettl = 3600;
2057
2058 vector<DNSRecord> ret;
2059 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2060 BOOST_CHECK_EQUAL(res, RCode::NoError);
2061 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2062 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
2063
2064 const ComboAddress who;
2065 vector<DNSRecord> cached;
2066 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
2067 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2068 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2069 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
2070
2071 cached.clear();
2072 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
2073 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2074 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2075 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
2076 }
2077
2078 BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
2079 std::unique_ptr<SyncRes> sr;
2080 initSR(sr);
2081
2082 primeHints();
2083
2084 const DNSName target("powerdns.com.");
2085
2086 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2087
2088 if (isRootServer(ip)) {
2089 setLWResult(res, 0, false, false, true);
2090 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2091
2092 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2093
2094 return 1;
2095 } else if (ip == ComboAddress("192.0.2.1:53")) {
2096 setLWResult(res, 0, true, false, true);
2097 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2098 return 1;
2099 }
2100
2101 return 0;
2102 });
2103
2104 /* we populate the cache with entries that expired 60s ago*/
2105 time_t now = sr->getNow().tv_sec;
2106 std::vector<DNSRecord> records;
2107 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2108 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
2109
2110 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
2111
2112 vector<DNSRecord> ret;
2113 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2114 BOOST_CHECK_EQUAL(res, RCode::NoError);
2115 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2116 BOOST_REQUIRE(ret[0].d_type == QType::A);
2117 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
2118 }
2119
2120 BOOST_AUTO_TEST_CASE(test_delegation_only) {
2121 std::unique_ptr<SyncRes> sr;
2122 initSR(sr);
2123
2124 primeHints();
2125
2126 /* Thanks, Verisign */
2127 SyncRes::addDelegationOnly(DNSName("com."));
2128 SyncRes::addDelegationOnly(DNSName("net."));
2129
2130 const DNSName target("nx-powerdns.com.");
2131
2132 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2133
2134 if (isRootServer(ip)) {
2135 setLWResult(res, 0, false, false, true);
2136 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2137 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2138 return 1;
2139 } else if (ip == ComboAddress("192.0.2.1:53")) {
2140
2141 setLWResult(res, 0, true, false, true);
2142 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2143 return 1;
2144 }
2145
2146 return 0;
2147 });
2148
2149 vector<DNSRecord> ret;
2150 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2151 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2152 BOOST_CHECK_EQUAL(ret.size(), 0);
2153 }
2154
2155 BOOST_AUTO_TEST_CASE(test_unauth_any) {
2156 std::unique_ptr<SyncRes> sr;
2157 initSR(sr);
2158
2159 primeHints();
2160
2161 const DNSName target("powerdns.com.");
2162
2163 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2164
2165 if (isRootServer(ip)) {
2166 setLWResult(res, 0, false, false, true);
2167 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2168 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2169 return 1;
2170 } else if (ip == ComboAddress("192.0.2.1:53")) {
2171
2172 setLWResult(res, 0, false, false, true);
2173 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2174 return 1;
2175 }
2176
2177 return 0;
2178 });
2179
2180 vector<DNSRecord> ret;
2181 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2182 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2183 BOOST_CHECK_EQUAL(ret.size(), 0);
2184 }
2185
2186 BOOST_AUTO_TEST_CASE(test_no_data) {
2187 std::unique_ptr<SyncRes> sr;
2188 initSR(sr);
2189
2190 primeHints();
2191
2192 const DNSName target("powerdns.com.");
2193
2194 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2195
2196 setLWResult(res, 0, true, false, true);
2197 return 1;
2198 });
2199
2200 vector<DNSRecord> ret;
2201 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2202 BOOST_CHECK_EQUAL(res, RCode::NoError);
2203 BOOST_CHECK_EQUAL(ret.size(), 0);
2204 }
2205
2206 BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2207 std::unique_ptr<SyncRes> sr;
2208 initSR(sr);
2209
2210 primeHints();
2211
2212 const DNSName target("powerdns.com.");
2213
2214 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2215
2216 setLWResult(res, 0, true, false, true);
2217 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2218 addRecordToLW(res, domain, QType::ANY, "0 0");
2219 addRecordToLW(res, domain, QType::OPT, "");
2220 return 1;
2221 });
2222
2223 vector<DNSRecord> ret;
2224 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2225 BOOST_CHECK_EQUAL(res, RCode::NoError);
2226 BOOST_CHECK_EQUAL(ret.size(), 1);
2227 }
2228
2229 BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2230 std::unique_ptr<SyncRes> sr;
2231 initSR(sr);
2232
2233 primeHints();
2234
2235 const DNSName target("powerdns.com.");
2236
2237 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2238
2239 setLWResult(res, 0, true, false, true);
2240 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2241 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2242 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2243 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2244 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2245 return 1;
2246 });
2247
2248 vector<DNSRecord> ret;
2249 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2250 BOOST_CHECK_EQUAL(res, RCode::NoError);
2251 BOOST_CHECK_EQUAL(ret.size(), 1);
2252 }
2253
2254 BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2255 std::unique_ptr<SyncRes> sr;
2256 initSR(sr, true);
2257
2258 primeHints();
2259
2260 const DNSName target("powerdns.com.");
2261
2262 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2263
2264 setLWResult(res, 0, true, false, true);
2265 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2266 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2267 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2268 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2269 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2270 return 1;
2271 });
2272
2273 vector<DNSRecord> ret;
2274 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2275 BOOST_CHECK_EQUAL(res, RCode::NoError);
2276 BOOST_CHECK_EQUAL(ret.size(), 4);
2277 }
2278
2279 BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2280 std::unique_ptr<SyncRes> sr;
2281 initSR(sr);
2282
2283 primeHints();
2284
2285 const DNSName target("powerdns.com.");
2286
2287 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2288
2289 setLWResult(res, RCode::NXDomain, true, false, true);
2290 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2291 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2292 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2293 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2294 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2295 return 1;
2296 });
2297
2298 vector<DNSRecord> ret;
2299 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2300 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2301 BOOST_CHECK_EQUAL(ret.size(), 1);
2302 }
2303
2304 BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2305 std::unique_ptr<SyncRes> sr;
2306 initSR(sr, true);
2307
2308 primeHints();
2309
2310 const DNSName target("powerdns.com.");
2311
2312 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2313
2314 setLWResult(res, RCode::NXDomain, true, false, true);
2315 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2316 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2317 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2318 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2319 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2320 return 1;
2321 });
2322
2323 vector<DNSRecord> ret;
2324 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2325 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2326 BOOST_CHECK_EQUAL(ret.size(), 4);
2327 }
2328
2329 BOOST_AUTO_TEST_CASE(test_qclass_none) {
2330 std::unique_ptr<SyncRes> sr;
2331 initSR(sr);
2332
2333 primeHints();
2334
2335 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2336 size_t queriesCount = 0;
2337
2338 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2339
2340 queriesCount++;
2341 return 0;
2342 });
2343
2344 const DNSName target("powerdns.com.");
2345 vector<DNSRecord> ret;
2346 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2347 BOOST_CHECK_EQUAL(res, -1);
2348 BOOST_CHECK_EQUAL(ret.size(), 0);
2349 BOOST_CHECK_EQUAL(queriesCount, 0);
2350 }
2351
2352 BOOST_AUTO_TEST_CASE(test_special_types) {
2353 std::unique_ptr<SyncRes> sr;
2354 initSR(sr);
2355
2356 primeHints();
2357
2358 /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
2359 size_t queriesCount = 0;
2360
2361 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2362
2363 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2364 queriesCount++;
2365 return 0;
2366 });
2367
2368 const DNSName target("powerdns.com.");
2369 vector<DNSRecord> ret;
2370 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2371 BOOST_CHECK_EQUAL(res, -1);
2372 BOOST_CHECK_EQUAL(ret.size(), 0);
2373 BOOST_CHECK_EQUAL(queriesCount, 0);
2374
2375 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2376 BOOST_CHECK_EQUAL(res, -1);
2377 BOOST_CHECK_EQUAL(ret.size(), 0);
2378 BOOST_CHECK_EQUAL(queriesCount, 0);
2379
2380 res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2381 BOOST_CHECK_EQUAL(res, -1);
2382 BOOST_CHECK_EQUAL(ret.size(), 0);
2383 BOOST_CHECK_EQUAL(queriesCount, 0);
2384
2385 res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
2386 BOOST_CHECK_EQUAL(res, -1);
2387 BOOST_CHECK_EQUAL(ret.size(), 0);
2388 BOOST_CHECK_EQUAL(queriesCount, 0);
2389 }
2390
2391 BOOST_AUTO_TEST_CASE(test_special_names) {
2392 std::unique_ptr<SyncRes> sr;
2393 initSR(sr);
2394
2395 primeHints();
2396
2397 /* special names should be handled internally */
2398
2399 size_t queriesCount = 0;
2400
2401 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2402
2403 queriesCount++;
2404 return 0;
2405 });
2406
2407 vector<DNSRecord> ret;
2408 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
2409 BOOST_CHECK_EQUAL(res, RCode::NoError);
2410 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2411 BOOST_CHECK(ret[0].d_type == QType::PTR);
2412 BOOST_CHECK_EQUAL(queriesCount, 0);
2413
2414 ret.clear();
2415 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
2416 BOOST_CHECK_EQUAL(res, RCode::NoError);
2417 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2418 BOOST_CHECK(ret[0].d_type == QType::PTR);
2419 BOOST_CHECK_EQUAL(queriesCount, 0);
2420
2421 ret.clear();
2422 res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::PTR), QClass::IN, ret);
2423 BOOST_CHECK_EQUAL(res, RCode::NoError);
2424 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2425 BOOST_CHECK(ret[0].d_type == QType::PTR);
2426 BOOST_CHECK_EQUAL(queriesCount, 0);
2427
2428 ret.clear();
2429 res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::ANY), QClass::IN, ret);
2430 BOOST_CHECK_EQUAL(res, RCode::NoError);
2431 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2432 BOOST_CHECK(ret[0].d_type == QType::PTR);
2433 BOOST_CHECK_EQUAL(queriesCount, 0);
2434
2435 ret.clear();
2436 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
2437 BOOST_CHECK_EQUAL(res, RCode::NoError);
2438 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2439 BOOST_CHECK(ret[0].d_type == QType::A);
2440 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2441 BOOST_CHECK_EQUAL(queriesCount, 0);
2442
2443 ret.clear();
2444 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
2445 BOOST_CHECK_EQUAL(res, RCode::NoError);
2446 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2447 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2448 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2449 BOOST_CHECK_EQUAL(queriesCount, 0);
2450
2451 ret.clear();
2452 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
2453 BOOST_CHECK_EQUAL(res, RCode::NoError);
2454 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2455 for (const auto& rec : ret) {
2456 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2457 if (rec.d_type == QType::A) {
2458 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2459 }
2460 else {
2461 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2462 }
2463 }
2464 BOOST_CHECK_EQUAL(queriesCount, 0);
2465
2466 ret.clear();
2467 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
2468 BOOST_CHECK_EQUAL(res, RCode::NoError);
2469 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2470 BOOST_CHECK(ret[0].d_type == QType::TXT);
2471 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2472 BOOST_CHECK_EQUAL(queriesCount, 0);
2473
2474 ret.clear();
2475 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
2476 BOOST_CHECK_EQUAL(res, RCode::NoError);
2477 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2478 BOOST_CHECK(ret[0].d_type == QType::TXT);
2479 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2480 BOOST_CHECK_EQUAL(queriesCount, 0);
2481
2482 ret.clear();
2483 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
2484 BOOST_CHECK_EQUAL(res, RCode::NoError);
2485 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2486 BOOST_CHECK(ret[0].d_type == QType::TXT);
2487 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2488 BOOST_CHECK_EQUAL(queriesCount, 0);
2489
2490 ret.clear();
2491 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
2492 BOOST_CHECK_EQUAL(res, RCode::NoError);
2493 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2494 BOOST_CHECK(ret[0].d_type == QType::TXT);
2495 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2496 BOOST_CHECK_EQUAL(queriesCount, 0);
2497
2498 ret.clear();
2499 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
2500 BOOST_CHECK_EQUAL(res, RCode::NoError);
2501 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2502 BOOST_CHECK(ret[0].d_type == QType::TXT);
2503 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2504 BOOST_CHECK_EQUAL(queriesCount, 0);
2505
2506 ret.clear();
2507 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
2508 BOOST_CHECK_EQUAL(res, RCode::NoError);
2509 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2510 BOOST_CHECK(ret[0].d_type == QType::TXT);
2511 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2512 BOOST_CHECK_EQUAL(queriesCount, 0);
2513 }
2514
2515 BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2516 std::unique_ptr<SyncRes> sr;
2517 initSR(sr);
2518
2519 primeHints();
2520
2521 const DNSName target("rpz.powerdns.com.");
2522 const ComboAddress ns("192.0.2.1:53");
2523
2524 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2525
2526 if (isRootServer(ip)) {
2527 setLWResult(res, false, true, false, true);
2528 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2529 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2530 return 1;
2531 } else if (ip == ns) {
2532
2533 setLWResult(res, 0, true, false, true);
2534 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2535 return 1;
2536 }
2537
2538 return 0;
2539 });
2540
2541 DNSFilterEngine::Policy pol;
2542 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2543 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2544 zone->setName("Unit test policy 0");
2545 zone->addNSIPTrigger(Netmask(ns, 32), pol);
2546 auto luaconfsCopy = g_luaconfs.getCopy();
2547 luaconfsCopy.dfe.addZone(zone);
2548 g_luaconfs.setState(luaconfsCopy);
2549
2550 vector<DNSRecord> ret;
2551 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2552 BOOST_CHECK_EQUAL(res, -2);
2553 BOOST_CHECK_EQUAL(ret.size(), 0);
2554 }
2555
2556 BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2557 std::unique_ptr<SyncRes> sr;
2558 initSR(sr);
2559
2560 primeHints();
2561
2562 const DNSName target("rpz.powerdns.com.");
2563 const ComboAddress ns("[2001:DB8::42]:53");
2564
2565 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2566
2567 if (isRootServer(ip)) {
2568 setLWResult(res, 0, false, false, true);
2569 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2570 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2571 return 1;
2572 } else if (ip == ns) {
2573
2574 setLWResult(res, 0, true, false, true);
2575 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2576 return 1;
2577 }
2578
2579 return 0;
2580 });
2581
2582 DNSFilterEngine::Policy pol;
2583 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2584 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2585 zone->setName("Unit test policy 0");
2586 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2587 auto luaconfsCopy = g_luaconfs.getCopy();
2588 luaconfsCopy.dfe.addZone(zone);
2589 g_luaconfs.setState(luaconfsCopy);
2590
2591 vector<DNSRecord> ret;
2592 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2593 BOOST_CHECK_EQUAL(res, -2);
2594 BOOST_CHECK_EQUAL(ret.size(), 0);
2595 }
2596
2597 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2598 std::unique_ptr<SyncRes> sr;
2599 initSR(sr);
2600
2601 primeHints();
2602
2603 const DNSName target("rpz.powerdns.com.");
2604 const ComboAddress ns("192.0.2.1:53");
2605 const DNSName nsName("ns1.powerdns.com.");
2606
2607 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2608
2609 if (isRootServer(ip)) {
2610 setLWResult(res, 0, false, false, true);
2611 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2612 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2613 return 1;
2614 } else if (ip == ns) {
2615
2616 setLWResult(res, 0, true, false, true);
2617 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2618 return 1;
2619 }
2620
2621 return 0;
2622 });
2623
2624 DNSFilterEngine::Policy pol;
2625 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2626 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2627 zone->setName("Unit test policy 0");
2628 zone->addNSTrigger(nsName, pol);
2629 auto luaconfsCopy = g_luaconfs.getCopy();
2630 luaconfsCopy.dfe.addZone(zone);
2631 g_luaconfs.setState(luaconfsCopy);
2632
2633 vector<DNSRecord> ret;
2634 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2635 BOOST_CHECK_EQUAL(res, -2);
2636 BOOST_CHECK_EQUAL(ret.size(), 0);
2637 }
2638
2639 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2640 std::unique_ptr<SyncRes> sr;
2641 initSR(sr);
2642
2643 primeHints();
2644
2645 const DNSName target("rpz.powerdns.com.");
2646 const ComboAddress ns("192.0.2.1:53");
2647 const DNSName nsName("ns1.powerdns.com.");
2648
2649 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2650
2651 if (isRootServer(ip)) {
2652 setLWResult(res, 0, false, false, true);
2653 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2654 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2655 return 1;
2656 } else if (ip == ns) {
2657
2658 setLWResult(res, 0, true, false, true);
2659 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2660 return 1;
2661 }
2662
2663 return 0;
2664 });
2665
2666 DNSFilterEngine::Policy pol;
2667 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2668 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2669 zone->setName("Unit test policy 0");
2670 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2671 zone->addNSTrigger(nsName, pol);
2672 auto luaconfsCopy = g_luaconfs.getCopy();
2673 luaconfsCopy.dfe.addZone(zone);
2674 g_luaconfs.setState(luaconfsCopy);
2675
2676 /* RPZ is disabled for this query, we should not be blocked */
2677 sr->setWantsRPZ(false);
2678
2679 vector<DNSRecord> ret;
2680 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2681 BOOST_CHECK_EQUAL(res, RCode::NoError);
2682 BOOST_CHECK_EQUAL(ret.size(), 1);
2683 }
2684
2685 BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2686 std::unique_ptr<SyncRes> sr;
2687 initSR(sr);
2688
2689 primeHints();
2690
2691 const DNSName target("powerdns.com.");
2692 const ComboAddress ns("192.0.2.1:53");
2693 const ComboAddress forwardedNS("192.0.2.42:53");
2694
2695 SyncRes::AuthDomain ad;
2696 ad.d_rdForward = false;
2697 ad.d_servers.push_back(forwardedNS);
2698 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2699
2700 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2701
2702 if (ip == forwardedNS) {
2703 BOOST_CHECK_EQUAL(sendRDQuery, false);
2704
2705 setLWResult(res, 0, true, false, true);
2706 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2707 return 1;
2708 }
2709
2710 return 0;
2711 });
2712
2713 /* simulate a no-RD query */
2714 sr->setCacheOnly();
2715
2716 vector<DNSRecord> ret;
2717 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2718 BOOST_CHECK_EQUAL(res, RCode::NoError);
2719 BOOST_CHECK_EQUAL(ret.size(), 1);
2720 }
2721
2722 BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
2723 std::unique_ptr<SyncRes> sr;
2724 initSR(sr);
2725
2726 primeHints();
2727
2728 const DNSName target("powerdns.com.");
2729 const ComboAddress ns("192.0.2.1:53");
2730 const ComboAddress forwardedNS("192.0.2.42:53");
2731
2732 SyncRes::AuthDomain ad;
2733 ad.d_rdForward = false;
2734 ad.d_servers.push_back(forwardedNS);
2735 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2736
2737 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2738
2739 if (ip == forwardedNS) {
2740 BOOST_CHECK_EQUAL(sendRDQuery, false);
2741
2742 setLWResult(res, 0, true, false, true);
2743 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2744 return 1;
2745 }
2746
2747 return 0;
2748 });
2749
2750 vector<DNSRecord> ret;
2751 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2752 BOOST_CHECK_EQUAL(res, RCode::NoError);
2753 BOOST_CHECK_EQUAL(ret.size(), 1);
2754 }
2755
2756 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
2757 std::unique_ptr<SyncRes> sr;
2758 initSR(sr);
2759
2760 primeHints();
2761
2762 const DNSName target("powerdns.com.");
2763 const ComboAddress ns("192.0.2.1:53");
2764 const ComboAddress forwardedNS("192.0.2.42:53");
2765
2766 SyncRes::AuthDomain ad;
2767 ad.d_rdForward = true;
2768 ad.d_servers.push_back(forwardedNS);
2769 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2770
2771 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2772
2773 if (ip == forwardedNS) {
2774 BOOST_CHECK_EQUAL(sendRDQuery, false);
2775
2776 setLWResult(res, 0, true, false, true);
2777 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2778 return 1;
2779 }
2780
2781 return 0;
2782 });
2783
2784 /* simulate a no-RD query */
2785 sr->setCacheOnly();
2786
2787 vector<DNSRecord> ret;
2788 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2789 BOOST_CHECK_EQUAL(res, RCode::NoError);
2790 BOOST_CHECK_EQUAL(ret.size(), 1);
2791 }
2792
2793 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
2794 std::unique_ptr<SyncRes> sr;
2795 initSR(sr);
2796
2797 primeHints();
2798
2799 const DNSName target("powerdns.com.");
2800 const ComboAddress ns("192.0.2.1:53");
2801 const ComboAddress forwardedNS("192.0.2.42:53");
2802
2803 SyncRes::AuthDomain ad;
2804 ad.d_rdForward = true;
2805 ad.d_servers.push_back(forwardedNS);
2806 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2807
2808 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2809
2810 if (ip == forwardedNS) {
2811 BOOST_CHECK_EQUAL(sendRDQuery, true);
2812
2813 setLWResult(res, 0, true, false, true);
2814 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2815 return 1;
2816 }
2817
2818 return 0;
2819 });
2820
2821 vector<DNSRecord> ret;
2822 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2823 BOOST_CHECK_EQUAL(res, RCode::NoError);
2824 BOOST_CHECK_EQUAL(ret.size(), 1);
2825 }
2826
2827 BOOST_AUTO_TEST_CASE(test_auth_zone_oob) {
2828 std::unique_ptr<SyncRes> sr;
2829 initSR(sr, true);
2830
2831 primeHints();
2832
2833 size_t queriesCount = 0;
2834 const DNSName target("test.xx.");
2835 const ComboAddress targetAddr("127.0.0.1");
2836 const DNSName authZone("test.xx");
2837
2838 SyncRes::AuthDomain ad;
2839 DNSRecord dr;
2840
2841 dr.d_place = DNSResourceRecord::ANSWER;
2842 dr.d_name = target;
2843 dr.d_type = QType::A;
2844 dr.d_ttl = 1800;
2845 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
2846 ad.d_records.insert(dr);
2847
2848 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2849
2850 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2851 queriesCount++;
2852 return 0;
2853 });
2854
2855 vector<DNSRecord> ret;
2856 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2857 BOOST_CHECK_EQUAL(res, 0);
2858 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2859 BOOST_CHECK(ret[0].d_type == QType::A);
2860 BOOST_CHECK_EQUAL(queriesCount, 0);
2861 BOOST_CHECK(sr->wasOutOfBand());
2862 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2863
2864 /* a second time, to check that the OOB flag is set when the query cache is used */
2865 ret.clear();
2866 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2867 BOOST_CHECK_EQUAL(res, 0);
2868 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2869 BOOST_CHECK(ret[0].d_type == QType::A);
2870 BOOST_CHECK_EQUAL(queriesCount, 0);
2871 BOOST_CHECK(sr->wasOutOfBand());
2872 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2873
2874 /* a third time, to check that the validation is disabled when the OOB flag is set */
2875 ret.clear();
2876 sr->setDNSSECValidationRequested(true);
2877 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2878 BOOST_CHECK_EQUAL(res, 0);
2879 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2880 BOOST_CHECK(ret[0].d_type == QType::A);
2881 BOOST_CHECK_EQUAL(queriesCount, 0);
2882 BOOST_CHECK(sr->wasOutOfBand());
2883 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2884 }
2885
2886 BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) {
2887 std::unique_ptr<SyncRes> sr;
2888 initSR(sr, true);
2889
2890 primeHints();
2891
2892 size_t queriesCount = 0;
2893 const DNSName target("cname.test.xx.");
2894 const DNSName targetCname("cname-target.test.xx.");
2895 const ComboAddress targetCnameAddr("127.0.0.1");
2896 const DNSName authZone("test.xx");
2897
2898 SyncRes::AuthDomain ad;
2899 DNSRecord dr;
2900
2901 dr.d_place = DNSResourceRecord::ANSWER;
2902 dr.d_name = target;
2903 dr.d_type = QType::CNAME;
2904 dr.d_ttl = 1800;
2905 dr.d_content = std::make_shared<CNAMERecordContent>(targetCname);
2906 ad.d_records.insert(dr);
2907
2908 dr.d_place = DNSResourceRecord::ANSWER;
2909 dr.d_name = targetCname;
2910 dr.d_type = QType::A;
2911 dr.d_ttl = 1800;
2912 dr.d_content = std::make_shared<ARecordContent>(targetCnameAddr);
2913 ad.d_records.insert(dr);
2914
2915 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2916
2917 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2918 queriesCount++;
2919 return 0;
2920 });
2921
2922 vector<DNSRecord> ret;
2923 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2924 BOOST_CHECK_EQUAL(res, 0);
2925 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2926 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2927 BOOST_CHECK(ret[1].d_type == QType::A);
2928 BOOST_CHECK_EQUAL(queriesCount, 0);
2929 BOOST_CHECK(sr->wasOutOfBand());
2930 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2931
2932 /* a second time, to check that the OOB flag is set when the query cache is used */
2933 ret.clear();
2934 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2935 BOOST_CHECK_EQUAL(res, 0);
2936 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2937 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2938 BOOST_CHECK(ret[1].d_type == QType::A);
2939 BOOST_CHECK_EQUAL(queriesCount, 0);
2940 BOOST_CHECK(sr->wasOutOfBand());
2941 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2942
2943 /* a third time, to check that the validation is disabled when the OOB flag is set */
2944 ret.clear();
2945 sr->setDNSSECValidationRequested(true);
2946 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2947 BOOST_CHECK_EQUAL(res, 0);
2948 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2949 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2950 BOOST_CHECK(ret[1].d_type == QType::A);
2951 BOOST_CHECK_EQUAL(queriesCount, 0);
2952 BOOST_CHECK(sr->wasOutOfBand());
2953 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2954 }
2955
2956 BOOST_AUTO_TEST_CASE(test_auth_zone) {
2957 std::unique_ptr<SyncRes> sr;
2958 initSR(sr);
2959
2960 primeHints();
2961
2962 size_t queriesCount = 0;
2963 const DNSName target("powerdns.com.");
2964 const ComboAddress addr("192.0.2.5");
2965
2966 SyncRes::AuthDomain ad;
2967 ad.d_name = target;
2968 DNSRecord dr;
2969 dr.d_place = DNSResourceRecord::ANSWER;
2970 dr.d_name = target;
2971 dr.d_type = QType::SOA;
2972 dr.d_ttl = 3600;
2973 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2974 ad.d_records.insert(dr);
2975
2976 dr.d_place = DNSResourceRecord::ANSWER;
2977 dr.d_name = target;
2978 dr.d_type = QType::A;
2979 dr.d_ttl = 3600;
2980 dr.d_content = std::make_shared<ARecordContent>(addr);
2981 ad.d_records.insert(dr);
2982
2983 auto map = std::make_shared<SyncRes::domainmap_t>();
2984 (*map)[target] = ad;
2985 SyncRes::setDomainMap(map);
2986
2987 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2988
2989 queriesCount++;
2990 setLWResult(res, 0, true, false, true);
2991 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2992 return 1;
2993 });
2994
2995 vector<DNSRecord> ret;
2996 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2997 BOOST_CHECK_EQUAL(res, RCode::NoError);
2998 BOOST_CHECK_EQUAL(ret.size(), 1);
2999 BOOST_CHECK(ret[0].d_type == QType::A);
3000 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3001 BOOST_CHECK_EQUAL(queriesCount, 0);
3002 }
3003
3004 BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
3005 std::unique_ptr<SyncRes> sr;
3006 initSR(sr);
3007
3008 primeHints();
3009
3010 size_t queriesCount = 0;
3011 const DNSName target("powerdns.com.");
3012 const DNSName authZone("internal.powerdns.com.");
3013 const ComboAddress addr("192.0.2.5");
3014
3015 SyncRes::AuthDomain ad;
3016 ad.d_name = authZone;
3017 DNSRecord dr;
3018 dr.d_place = DNSResourceRecord::ANSWER;
3019 dr.d_name = authZone;
3020 dr.d_type = QType::SOA;
3021 dr.d_ttl = 3600;
3022 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3023 ad.d_records.insert(dr);
3024
3025 dr.d_place = DNSResourceRecord::ANSWER;
3026 dr.d_name = authZone;
3027 dr.d_type = QType::A;
3028 dr.d_ttl = 3600;
3029 dr.d_content = std::make_shared<ARecordContent>(addr);
3030 ad.d_records.insert(dr);
3031
3032 auto map = std::make_shared<SyncRes::domainmap_t>();
3033 (*map)[authZone] = ad;
3034 SyncRes::setDomainMap(map);
3035
3036 sr->setAsyncCallback([&queriesCount,target,authZone](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3037
3038 queriesCount++;
3039
3040 if (domain == target) {
3041 setLWResult(res, 0, true, false, true);
3042 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
3043 return 1;
3044 }
3045
3046 return 0;
3047 });
3048
3049 vector<DNSRecord> ret;
3050 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3051 BOOST_CHECK_EQUAL(res, RCode::NoError);
3052 BOOST_CHECK_EQUAL(ret.size(), 2);
3053 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3054 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
3055 BOOST_CHECK(ret[1].d_type == QType::A);
3056 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3057 BOOST_CHECK_EQUAL(queriesCount, 1);
3058 }
3059
3060 BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
3061 std::unique_ptr<SyncRes> sr;
3062 initSR(sr);
3063
3064 primeHints();
3065
3066 size_t queriesCount = 0;
3067 const DNSName target("powerdns.com.");
3068 const DNSName externalCNAME("www.open-xchange.com.");
3069 const ComboAddress addr("192.0.2.5");
3070
3071 SyncRes::AuthDomain ad;
3072 ad.d_name = target;
3073 DNSRecord dr;
3074 dr.d_place = DNSResourceRecord::ANSWER;
3075 dr.d_name = target;
3076 dr.d_type = QType::SOA;
3077 dr.d_ttl = 3600;
3078 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3079 ad.d_records.insert(dr);
3080
3081 dr.d_place = DNSResourceRecord::ANSWER;
3082 dr.d_name = target;
3083 dr.d_type = QType::CNAME;
3084 dr.d_ttl = 3600;
3085 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
3086 ad.d_records.insert(dr);
3087
3088 auto map = std::make_shared<SyncRes::domainmap_t>();
3089 (*map)[target] = ad;
3090 SyncRes::setDomainMap(map);
3091
3092 sr->setAsyncCallback([&queriesCount,externalCNAME,addr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3093
3094 queriesCount++;
3095
3096 if (domain == externalCNAME) {
3097 setLWResult(res, 0, true, false, true);
3098 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
3099 return 1;
3100 }
3101
3102 return 0;
3103 });
3104
3105 vector<DNSRecord> ret;
3106 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3107 BOOST_CHECK_EQUAL(res, RCode::NoError);
3108 BOOST_CHECK_EQUAL(ret.size(), 2);
3109 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3110 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
3111 BOOST_CHECK(ret[1].d_type == QType::A);
3112 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3113 BOOST_CHECK_EQUAL(queriesCount, 1);
3114 }
3115
3116 BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
3117 std::unique_ptr<SyncRes> sr;
3118 initSR(sr);
3119
3120 primeHints();
3121
3122 size_t queriesCount = 0;
3123 const DNSName target("nodata.powerdns.com.");
3124 const DNSName authZone("powerdns.com");
3125
3126 SyncRes::AuthDomain ad;
3127 ad.d_name = authZone;
3128 DNSRecord dr;
3129 dr.d_place = DNSResourceRecord::ANSWER;
3130 dr.d_name = target;
3131 dr.d_type = QType::A;
3132 dr.d_ttl = 3600;
3133 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3134 ad.d_records.insert(dr);
3135
3136 dr.d_place = DNSResourceRecord::ANSWER;
3137 dr.d_name = authZone;
3138 dr.d_type = QType::SOA;
3139 dr.d_ttl = 3600;
3140 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3141 ad.d_records.insert(dr);
3142
3143 auto map = std::make_shared<SyncRes::domainmap_t>();
3144 (*map)[authZone] = ad;
3145 SyncRes::setDomainMap(map);
3146
3147 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3148
3149 queriesCount++;
3150
3151 return 0;
3152 });
3153
3154 vector<DNSRecord> ret;
3155 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
3156 BOOST_CHECK_EQUAL(res, RCode::NoError);
3157 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3158 BOOST_CHECK(ret[0].d_type == QType::SOA);
3159 BOOST_CHECK_EQUAL(queriesCount, 0);
3160 }
3161
3162 BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3163 std::unique_ptr<SyncRes> sr;
3164 initSR(sr);
3165
3166 primeHints();
3167
3168 size_t queriesCount = 0;
3169 const DNSName target("nx.powerdns.com.");
3170 const DNSName authZone("powerdns.com");
3171
3172 SyncRes::AuthDomain ad;
3173 ad.d_name = authZone;
3174 DNSRecord dr;
3175 dr.d_place = DNSResourceRecord::ANSWER;
3176 dr.d_name = DNSName("powerdns.com.");
3177 dr.d_type = QType::SOA;
3178 dr.d_ttl = 3600;
3179 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3180 ad.d_records.insert(dr);
3181
3182 auto map = std::make_shared<SyncRes::domainmap_t>();
3183 (*map)[authZone] = ad;
3184 SyncRes::setDomainMap(map);
3185
3186 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3187
3188 queriesCount++;
3189
3190 return 0;
3191 });
3192
3193 vector<DNSRecord> ret;
3194 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3195 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3196 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3197 BOOST_CHECK(ret[0].d_type == QType::SOA);
3198 BOOST_CHECK_EQUAL(queriesCount, 0);
3199 }
3200
3201 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3202 std::unique_ptr<SyncRes> sr;
3203 initSR(sr, true, false);
3204
3205 primeHints();
3206
3207 size_t queriesCount = 0;
3208 const DNSName target("www.test.powerdns.com.");
3209 const ComboAddress targetAddr("192.0.2.2");
3210 const DNSName ns("ns1.test.powerdns.com.");
3211 const ComboAddress nsAddr("192.0.2.1");
3212 const DNSName authZone("powerdns.com");
3213
3214 SyncRes::AuthDomain ad;
3215 ad.d_name = authZone;
3216 DNSRecord dr;
3217 dr.d_place = DNSResourceRecord::ANSWER;
3218 dr.d_name = authZone;
3219 dr.d_type = QType::SOA;
3220 dr.d_ttl = 3600;
3221 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3222 ad.d_records.insert(dr);
3223
3224 dr.d_place = DNSResourceRecord::ANSWER;
3225 dr.d_name = DNSName("test.powerdns.com.");
3226 dr.d_type = QType::NS;
3227 dr.d_ttl = 3600;
3228 dr.d_content = std::make_shared<NSRecordContent>(ns);
3229 ad.d_records.insert(dr);
3230
3231 dr.d_place = DNSResourceRecord::ANSWER;
3232 dr.d_name = ns;
3233 dr.d_type = QType::A;
3234 dr.d_ttl = 3600;
3235 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3236 ad.d_records.insert(dr);
3237
3238 auto map = std::make_shared<SyncRes::domainmap_t>();
3239 (*map)[authZone] = ad;
3240 SyncRes::setDomainMap(map);
3241
3242 testkeysset_t keys;
3243 auto luaconfsCopy = g_luaconfs.getCopy();
3244 luaconfsCopy.dsAnchors.clear();
3245 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3246 g_luaconfs.setState(luaconfsCopy);
3247
3248 sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr,authZone,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3249
3250 queriesCount++;
3251 if (type == QType::DS || type == QType::DNSKEY) {
3252 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone);
3253 }
3254
3255 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3256 setLWResult(res, 0, true, false, true);
3257 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3258 return 1;
3259 }
3260
3261 return 0;
3262 });
3263
3264 sr->setDNSSECValidationRequested(true);
3265 vector<DNSRecord> ret;
3266 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3267 BOOST_CHECK_EQUAL(res, RCode::NoError);
3268 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3269 BOOST_CHECK(ret[0].d_type == QType::A);
3270 BOOST_CHECK_EQUAL(queriesCount, 4);
3271 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3272 }
3273
3274 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3275 std::unique_ptr<SyncRes> sr;
3276 initSR(sr);
3277
3278 primeHints();
3279
3280 size_t queriesCount = 0;
3281 const DNSName target("test.powerdns.com.");
3282 const ComboAddress targetAddr("192.0.2.2");
3283 const DNSName ns("ns1.test.powerdns.com.");
3284 const ComboAddress nsAddr("192.0.2.1");
3285 const DNSName authZone("powerdns.com");
3286
3287 SyncRes::AuthDomain ad;
3288 ad.d_name = authZone;
3289 DNSRecord dr;
3290 dr.d_place = DNSResourceRecord::ANSWER;
3291 dr.d_name = authZone;
3292 dr.d_type = QType::SOA;
3293 dr.d_ttl = 3600;
3294 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3295 ad.d_records.insert(dr);
3296
3297 dr.d_place = DNSResourceRecord::ANSWER;
3298 dr.d_name = DNSName("test.powerdns.com.");
3299 dr.d_type = QType::NS;
3300 dr.d_ttl = 3600;
3301 dr.d_content = std::make_shared<NSRecordContent>(ns);
3302 ad.d_records.insert(dr);
3303
3304 dr.d_place = DNSResourceRecord::ANSWER;
3305 dr.d_name = ns;
3306 dr.d_type = QType::A;
3307 dr.d_ttl = 3600;
3308 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3309 ad.d_records.insert(dr);
3310
3311 auto map = std::make_shared<SyncRes::domainmap_t>();
3312 (*map)[authZone] = ad;
3313 SyncRes::setDomainMap(map);
3314
3315 sr->setAsyncCallback([&queriesCount,nsAddr,target,targetAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3316
3317 queriesCount++;
3318
3319 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3320 setLWResult(res, 0, true, false, true);
3321 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3322 return 1;
3323 }
3324
3325 return 0;
3326 });
3327
3328 vector<DNSRecord> ret;
3329 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3330 BOOST_CHECK_EQUAL(res, RCode::NoError);
3331 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3332 BOOST_CHECK(ret[0].d_type == QType::A);
3333 BOOST_CHECK_EQUAL(queriesCount, 1);
3334 }
3335
3336 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3337 std::unique_ptr<SyncRes> sr;
3338 initSR(sr);
3339
3340 primeHints();
3341
3342 size_t queriesCount = 0;
3343 const DNSName target("test.powerdns.com.");
3344 const ComboAddress targetAddr("192.0.2.2");
3345 const DNSName authZone("powerdns.com");
3346
3347 SyncRes::AuthDomain ad;
3348 ad.d_name = authZone;
3349 DNSRecord dr;
3350 dr.d_place = DNSResourceRecord::ANSWER;
3351 dr.d_name = authZone;
3352 dr.d_type = QType::SOA;
3353 dr.d_ttl = 3600;
3354 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3355 ad.d_records.insert(dr);
3356
3357 dr.d_place = DNSResourceRecord::ANSWER;
3358 dr.d_name = DNSName("*.powerdns.com.");
3359 dr.d_type = QType::A;
3360 dr.d_ttl = 3600;
3361 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3362 ad.d_records.insert(dr);
3363
3364 auto map = std::make_shared<SyncRes::domainmap_t>();
3365 (*map)[authZone] = ad;
3366 SyncRes::setDomainMap(map);
3367
3368 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3369
3370 queriesCount++;
3371
3372 return 0;
3373 });
3374
3375 vector<DNSRecord> ret;
3376 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3377 BOOST_CHECK_EQUAL(res, RCode::NoError);
3378 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3379 BOOST_CHECK(ret[0].d_type == QType::A);
3380 BOOST_CHECK_EQUAL(queriesCount, 0);
3381 }
3382
3383 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3384 std::unique_ptr<SyncRes> sr;
3385 initSR(sr);
3386
3387 primeHints();
3388
3389 size_t queriesCount = 0;
3390 const DNSName target("test.powerdns.com.");
3391 const ComboAddress targetAddr("192.0.2.2");
3392 const DNSName authZone("powerdns.com");
3393
3394 SyncRes::AuthDomain ad;
3395 ad.d_name = authZone;
3396 DNSRecord dr;
3397 dr.d_place = DNSResourceRecord::ANSWER;
3398 dr.d_name = authZone;
3399 dr.d_type = QType::SOA;
3400 dr.d_ttl = 3600;
3401 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3402 ad.d_records.insert(dr);
3403
3404 dr.d_place = DNSResourceRecord::ANSWER;
3405 dr.d_name = DNSName("*.powerdns.com.");
3406 dr.d_type = QType::A;
3407 dr.d_ttl = 3600;
3408 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3409 ad.d_records.insert(dr);
3410
3411 auto map = std::make_shared<SyncRes::domainmap_t>();
3412 (*map)[authZone] = ad;
3413 SyncRes::setDomainMap(map);
3414
3415 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3416
3417 queriesCount++;
3418
3419 return 0;
3420 });
3421
3422 vector<DNSRecord> ret;
3423 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
3424 BOOST_CHECK_EQUAL(res, RCode::NoError);
3425 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3426 BOOST_CHECK(ret[0].d_type == QType::SOA);
3427 BOOST_CHECK_EQUAL(queriesCount, 0);
3428 }
3429
3430 BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3431 std::unique_ptr<SyncRes> sr;
3432 initSR(sr);
3433
3434 primeHints();
3435
3436 size_t queriesCount = 0;
3437 const DNSName target("powerdns.com.");
3438 const ComboAddress addr("192.0.2.5");
3439
3440 SyncRes::AuthDomain ad;
3441 ad.d_name = target;
3442 DNSRecord dr;
3443 dr.d_place = DNSResourceRecord::ANSWER;
3444 dr.d_name = target;
3445 dr.d_type = QType::SOA;
3446 dr.d_ttl = 3600;
3447 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3448 ad.d_records.insert(dr);
3449
3450 dr.d_place = DNSResourceRecord::ANSWER;
3451 dr.d_name = target;
3452 dr.d_type = QType::A;
3453 dr.d_ttl = 3600;
3454 dr.d_content = std::make_shared<ARecordContent>(addr);
3455 ad.d_records.insert(dr);
3456
3457 auto map = std::make_shared<SyncRes::domainmap_t>();
3458 (*map)[target] = ad;
3459 SyncRes::setDomainMap(map);
3460
3461 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3462
3463 queriesCount++;
3464 setLWResult(res, 0, true, false, true);
3465 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3466 return 1;
3467 });
3468
3469 /* simulate a no-RD query */
3470 sr->setCacheOnly();
3471
3472 vector<DNSRecord> ret;
3473 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3474 BOOST_CHECK_EQUAL(res, RCode::NoError);
3475 BOOST_CHECK_EQUAL(ret.size(), 1);
3476 BOOST_CHECK(ret[0].d_type == QType::A);
3477 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3478 BOOST_CHECK_EQUAL(queriesCount, 0);
3479 }
3480
3481 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
3482 init();
3483
3484 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3485 dcke->create(dcke->getBits());
3486 // cerr<<dcke->convertToISC()<<endl;
3487 DNSSECPrivateKey dpk;
3488 dpk.d_flags = 256;
3489 dpk.setKey(dcke);
3490
3491 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3492 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3493
3494 DNSName qname("powerdns.com.");
3495
3496 time_t now = time(nullptr);
3497 RRSIGRecordContent rrc;
3498 /* this RRSIG is valid for the current second only */
3499 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
3500
3501 skeyset_t keyset;
3502 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3503
3504 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3505 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3506
3507 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
3508 }
3509
3510 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3511 std::unique_ptr<SyncRes> sr;
3512 initSR(sr, true);
3513
3514 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3515
3516 primeHints();
3517 const DNSName target(".");
3518 testkeysset_t keys;
3519
3520 auto luaconfsCopy = g_luaconfs.getCopy();
3521 luaconfsCopy.dsAnchors.clear();
3522 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3523 g_luaconfs.setState(luaconfsCopy);
3524
3525 size_t queriesCount = 0;
3526
3527 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3528 queriesCount++;
3529
3530 if (domain == target && type == QType::NS) {
3531
3532 setLWResult(res, 0, true, false, true);
3533 char addr[] = "a.root-servers.net.";
3534 for (char idx = 'a'; idx <= 'm'; idx++) {
3535 addr[0] = idx;
3536 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3537 }
3538
3539 addRRSIG(keys, res->d_records, domain, 300);
3540
3541 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3542 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3543
3544 return 1;
3545 } else if (domain == target && type == QType::DNSKEY) {
3546
3547 setLWResult(res, 0, true, false, true);
3548
3549 addDNSKEY(keys, domain, 300, res->d_records);
3550 addRRSIG(keys, res->d_records, domain, 300);
3551
3552 return 1;
3553 }
3554
3555 return 0;
3556 });
3557
3558 vector<DNSRecord> ret;
3559 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3560 BOOST_CHECK_EQUAL(res, RCode::NoError);
3561 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3562 /* 13 NS + 1 RRSIG */
3563 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3564 BOOST_CHECK_EQUAL(queriesCount, 2);
3565
3566 /* again, to test the cache */
3567 ret.clear();
3568 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3569 BOOST_CHECK_EQUAL(res, RCode::NoError);
3570 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3571 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3572 BOOST_CHECK_EQUAL(queriesCount, 2);
3573 }
3574
3575 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3576 std::unique_ptr<SyncRes> sr;
3577 initSR(sr, true);
3578
3579 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3580
3581 primeHints();
3582 const DNSName target(".");
3583 testkeysset_t zskeys;
3584 testkeysset_t kskeys;
3585
3586 /* Generate key material for "." */
3587 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3588 dckeZ->create(dckeZ->getBits());
3589 DNSSECPrivateKey ksk;
3590 ksk.d_flags = 257;
3591 ksk.setKey(dckeZ);
3592 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3593
3594 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3595 dckeK->create(dckeK->getBits());
3596 DNSSECPrivateKey zsk;
3597 zsk.d_flags = 256;
3598 zsk.setKey(dckeK);
3599 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
3600
3601 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3602 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
3603
3604 /* Set the root DS */
3605 auto luaconfsCopy = g_luaconfs.getCopy();
3606 luaconfsCopy.dsAnchors.clear();
3607 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
3608 g_luaconfs.setState(luaconfsCopy);
3609
3610 size_t queriesCount = 0;
3611
3612 sr->setAsyncCallback([target,&queriesCount,zskeys,kskeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3613 queriesCount++;
3614
3615 if (domain == target && type == QType::NS) {
3616
3617 setLWResult(res, 0, true, false, true);
3618 char addr[] = "a.root-servers.net.";
3619 for (char idx = 'a'; idx <= 'm'; idx++) {
3620 addr[0] = idx;
3621 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3622 }
3623
3624 addRRSIG(zskeys, res->d_records, domain, 300);
3625
3626 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3627 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3628
3629 return 1;
3630 } else if (domain == target && type == QType::DNSKEY) {
3631
3632 setLWResult(res, 0, true, false, true);
3633
3634 addDNSKEY(kskeys, domain, 300, res->d_records);
3635 addDNSKEY(zskeys, domain, 300, res->d_records);
3636 addRRSIG(kskeys, res->d_records, domain, 300);
3637
3638 return 1;
3639 }
3640
3641 return 0;
3642 });
3643
3644 vector<DNSRecord> ret;
3645 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3646 BOOST_CHECK_EQUAL(res, RCode::NoError);
3647 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3648 /* 13 NS + 1 RRSIG */
3649 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3650 BOOST_CHECK_EQUAL(queriesCount, 2);
3651
3652 /* again, to test the cache */
3653 ret.clear();
3654 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3655 BOOST_CHECK_EQUAL(res, RCode::NoError);
3656 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3657 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3658 BOOST_CHECK_EQUAL(queriesCount, 2);
3659 }
3660
3661 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
3662 std::unique_ptr<SyncRes> sr;
3663 initSR(sr, true);
3664
3665 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3666
3667 primeHints();
3668 const DNSName target(".");
3669 testkeysset_t keys;
3670
3671 auto luaconfsCopy = g_luaconfs.getCopy();
3672 luaconfsCopy.dsAnchors.clear();
3673 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3674 g_luaconfs.setState(luaconfsCopy);
3675
3676 size_t queriesCount = 0;
3677
3678 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3679 queriesCount++;
3680
3681 if (domain == target && type == QType::NS) {
3682
3683 setLWResult(res, 0, true, false, true);
3684 char addr[] = "a.root-servers.net.";
3685 for (char idx = 'a'; idx <= 'm'; idx++) {
3686 addr[0] = idx;
3687 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3688 }
3689
3690 addRRSIG(keys, res->d_records, domain, 300);
3691
3692 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3693 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3694
3695 return 1;
3696 } else if (domain == target && type == QType::DNSKEY) {
3697
3698 setLWResult(res, 0, true, false, true);
3699
3700 /* No DNSKEY */
3701
3702 return 1;
3703 }
3704
3705 return 0;
3706 });
3707
3708 vector<DNSRecord> ret;
3709 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3710 BOOST_CHECK_EQUAL(res, RCode::NoError);
3711 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3712 /* 13 NS + 1 RRSIG */
3713 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3714 BOOST_CHECK_EQUAL(queriesCount, 2);
3715
3716 /* again, to test the cache */
3717 ret.clear();
3718 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3719 BOOST_CHECK_EQUAL(res, RCode::NoError);
3720 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3721 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3722 BOOST_CHECK_EQUAL(queriesCount, 2);
3723 }
3724
3725 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3726 std::unique_ptr<SyncRes> sr;
3727 initSR(sr, true);
3728
3729 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3730
3731 primeHints();
3732 const DNSName target(".");
3733 testkeysset_t dskeys;
3734 testkeysset_t keys;
3735
3736 /* Generate key material for "." */
3737 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3738 dckeDS->create(dckeDS->getBits());
3739 DNSSECPrivateKey dskey;
3740 dskey.d_flags = 257;
3741 dskey.setKey(dckeDS);
3742 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3743
3744 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3745 dcke->create(dcke->getBits());
3746 DNSSECPrivateKey dpk;
3747 dpk.d_flags = 256;
3748 dpk.setKey(dcke);
3749 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3750
3751 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3752 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
3753
3754 /* Set the root DS */
3755 auto luaconfsCopy = g_luaconfs.getCopy();
3756 luaconfsCopy.dsAnchors.clear();
3757 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3758 g_luaconfs.setState(luaconfsCopy);
3759
3760 size_t queriesCount = 0;
3761
3762 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3763 queriesCount++;
3764
3765 if (domain == target && type == QType::NS) {
3766
3767 setLWResult(res, 0, true, false, true);
3768 char addr[] = "a.root-servers.net.";
3769 for (char idx = 'a'; idx <= 'm'; idx++) {
3770 addr[0] = idx;
3771 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3772 }
3773
3774 addRRSIG(keys, res->d_records, domain, 300);
3775
3776 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3777 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3778
3779 return 1;
3780 } else if (domain == target && type == QType::DNSKEY) {
3781
3782 setLWResult(res, 0, true, false, true);
3783
3784 addDNSKEY(keys, domain, 300, res->d_records);
3785 addRRSIG(keys, res->d_records, domain, 300);
3786
3787 return 1;
3788 }
3789
3790 return 0;
3791 });
3792
3793 vector<DNSRecord> ret;
3794 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3795 BOOST_CHECK_EQUAL(res, RCode::NoError);
3796 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3797 /* 13 NS + 1 RRSIG */
3798 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3799 BOOST_CHECK_EQUAL(queriesCount, 2);
3800
3801 /* again, to test the cache */
3802 ret.clear();
3803 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3804 BOOST_CHECK_EQUAL(res, RCode::NoError);
3805 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3806 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3807 BOOST_CHECK_EQUAL(queriesCount, 2);
3808 }
3809
3810 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
3811 std::unique_ptr<SyncRes> sr;
3812 initSR(sr, true);
3813
3814 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3815
3816 primeHints();
3817 const DNSName target(".");
3818 testkeysset_t keys;
3819 testkeysset_t rrsigkeys;
3820
3821 auto luaconfsCopy = g_luaconfs.getCopy();
3822 luaconfsCopy.dsAnchors.clear();
3823 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3824 g_luaconfs.setState(luaconfsCopy);
3825
3826 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3827 dckeRRSIG->create(dckeRRSIG->getBits());
3828 DNSSECPrivateKey rrsigkey;
3829 rrsigkey.d_flags = 257;
3830 rrsigkey.setKey(dckeRRSIG);
3831 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
3832
3833 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
3834
3835 size_t queriesCount = 0;
3836
3837 sr->setAsyncCallback([target,&queriesCount,keys,rrsigkeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3838 queriesCount++;
3839
3840 if (domain == target && type == QType::NS) {
3841
3842 setLWResult(res, 0, true, false, true);
3843 char addr[] = "a.root-servers.net.";
3844 for (char idx = 'a'; idx <= 'm'; idx++) {
3845 addr[0] = idx;
3846 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3847 }
3848
3849 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3850
3851 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3852 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3853
3854 return 1;
3855 } else if (domain == target && type == QType::DNSKEY) {
3856
3857 setLWResult(res, 0, true, false, true);
3858
3859 addDNSKEY(keys, domain, 300, res->d_records);
3860 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3861
3862 return 1;
3863 }
3864
3865 return 0;
3866 });
3867
3868 vector<DNSRecord> ret;
3869 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3870 BOOST_CHECK_EQUAL(res, RCode::NoError);
3871 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3872 /* 13 NS + 1 RRSIG */
3873 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3874 BOOST_CHECK_EQUAL(queriesCount, 2);
3875
3876 /* again, to test the cache */
3877 ret.clear();
3878 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3879 BOOST_CHECK_EQUAL(res, RCode::NoError);
3880 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3881 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3882 BOOST_CHECK_EQUAL(queriesCount, 2);
3883 }
3884
3885 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
3886 std::unique_ptr<SyncRes> sr;
3887 initSR(sr, true);
3888
3889 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3890
3891 primeHints();
3892 const DNSName target(".");
3893 testkeysset_t keys;
3894
3895 auto luaconfsCopy = g_luaconfs.getCopy();
3896 luaconfsCopy.dsAnchors.clear();
3897 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3898 g_luaconfs.setState(luaconfsCopy);
3899
3900 size_t queriesCount = 0;
3901
3902 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3903 queriesCount++;
3904
3905 if (domain == target && type == QType::NS) {
3906
3907 setLWResult(res, 0, true, false, true);
3908 char addr[] = "a.root-servers.net.";
3909 for (char idx = 'a'; idx <= 'm'; idx++) {
3910 addr[0] = idx;
3911 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3912 }
3913
3914 /* No RRSIG */
3915
3916 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3917 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3918
3919 return 1;
3920 } else if (domain == target && type == QType::DNSKEY) {
3921
3922 setLWResult(res, 0, true, false, true);
3923
3924 addDNSKEY(keys, domain, 300, res->d_records);
3925 addRRSIG(keys, res->d_records, domain, 300);
3926
3927 return 1;
3928 }
3929
3930 return 0;
3931 });
3932
3933 vector<DNSRecord> ret;
3934 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3935 BOOST_CHECK_EQUAL(res, RCode::NoError);
3936 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3937 /* 13 NS + 0 RRSIG */
3938 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3939 /* no RRSIG so no query for DNSKEYs */
3940 BOOST_CHECK_EQUAL(queriesCount, 1);
3941
3942 /* again, to test the cache */
3943 ret.clear();
3944 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3945 BOOST_CHECK_EQUAL(res, RCode::NoError);
3946 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3947 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3948 BOOST_CHECK_EQUAL(queriesCount, 1);
3949 }
3950
3951 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
3952 std::unique_ptr<SyncRes> sr;
3953 initSR(sr, true);
3954
3955 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3956
3957 primeHints();
3958 const DNSName target(".");
3959 testkeysset_t keys;
3960
3961 /* Generate key material for "." */
3962 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3963 dcke->create(dcke->getBits());
3964 DNSSECPrivateKey dpk;
3965 dpk.d_flags = 256;
3966 dpk.setKey(dcke);
3967 /* Fake algorithm number (private) */
3968 dpk.d_algorithm = 253;
3969
3970 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3971 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
3972 /* Fake algorithm number (private) */
3973 drc.d_algorithm = 253;
3974
3975 /* Set the root DS */
3976 auto luaconfsCopy = g_luaconfs.getCopy();
3977 luaconfsCopy.dsAnchors.clear();
3978 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3979 g_luaconfs.setState(luaconfsCopy);
3980
3981 size_t queriesCount = 0;
3982
3983 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3984 queriesCount++;
3985
3986 if (domain == target && type == QType::NS) {
3987
3988 setLWResult(res, 0, true, false, true);
3989 char addr[] = "a.root-servers.net.";
3990 for (char idx = 'a'; idx <= 'm'; idx++) {
3991 addr[0] = idx;
3992 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3993 }
3994
3995 addRRSIG(keys, res->d_records, domain, 300);
3996
3997 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3998 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3999
4000 return 1;
4001 } else if (domain == target && type == QType::DNSKEY) {
4002
4003 setLWResult(res, 0, true, false, true);
4004
4005 addDNSKEY(keys, domain, 300, res->d_records);
4006 addRRSIG(keys, res->d_records, domain, 300);
4007
4008 return 1;
4009 }
4010
4011 return 0;
4012 });
4013
4014 vector<DNSRecord> ret;
4015 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4016 BOOST_CHECK_EQUAL(res, RCode::NoError);
4017 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4018 /* 13 NS + 1 RRSIG */
4019 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4020 /* no supported DS so no query for DNSKEYs */
4021 BOOST_CHECK_EQUAL(queriesCount, 1);
4022
4023 /* again, to test the cache */
4024 ret.clear();
4025 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4026 BOOST_CHECK_EQUAL(res, RCode::NoError);
4027 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4028 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4029 BOOST_CHECK_EQUAL(queriesCount, 1);
4030 }
4031
4032 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
4033 std::unique_ptr<SyncRes> sr;
4034 initSR(sr, true);
4035
4036 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4037
4038 primeHints();
4039 const DNSName target(".");
4040 testkeysset_t keys;
4041
4042 /* Generate key material for "." */
4043 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4044 dcke->create(dcke->getBits());
4045 DNSSECPrivateKey dpk;
4046 dpk.d_flags = 256;
4047 dpk.setKey(dcke);
4048 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
4049 /* Fake digest number (reserved) */
4050 drc.d_digesttype = 0;
4051
4052 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
4053
4054 /* Set the root DS */
4055 auto luaconfsCopy = g_luaconfs.getCopy();
4056 luaconfsCopy.dsAnchors.clear();
4057 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4058 g_luaconfs.setState(luaconfsCopy);
4059
4060 size_t queriesCount = 0;
4061
4062 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4063 queriesCount++;
4064
4065 if (domain == target && type == QType::NS) {
4066
4067 setLWResult(res, 0, true, false, true);
4068 char addr[] = "a.root-servers.net.";
4069 for (char idx = 'a'; idx <= 'm'; idx++) {
4070 addr[0] = idx;
4071 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4072 }
4073
4074 addRRSIG(keys, res->d_records, domain, 300);
4075
4076 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4077 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4078
4079 return 1;
4080 } else if (domain == target && type == QType::DNSKEY) {
4081
4082 setLWResult(res, 0, true, false, true);
4083
4084 addDNSKEY(keys, domain, 300, res->d_records);
4085 addRRSIG(keys, res->d_records, domain, 300);
4086
4087 return 1;
4088 }
4089
4090 return 0;
4091 });
4092
4093 vector<DNSRecord> ret;
4094 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4095 BOOST_CHECK_EQUAL(res, RCode::NoError);
4096 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4097 /* 13 NS + 1 RRSIG */
4098 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4099 /* no supported DS so no query for DNSKEYs */
4100 BOOST_CHECK_EQUAL(queriesCount, 1);
4101
4102 /* again, to test the cache */
4103 ret.clear();
4104 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4105 BOOST_CHECK_EQUAL(res, RCode::NoError);
4106 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4107 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4108 BOOST_CHECK_EQUAL(queriesCount, 1);
4109 }
4110
4111 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
4112 std::unique_ptr<SyncRes> sr;
4113 initSR(sr, true);
4114
4115 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4116
4117 primeHints();
4118 const DNSName target(".");
4119 testkeysset_t keys;
4120
4121 auto luaconfsCopy = g_luaconfs.getCopy();
4122 luaconfsCopy.dsAnchors.clear();
4123 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4124
4125 g_luaconfs.setState(luaconfsCopy);
4126
4127 size_t queriesCount = 0;
4128
4129 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4130 queriesCount++;
4131
4132 if (domain == target && type == QType::NS) {
4133
4134 setLWResult(res, 0, true, false, true);
4135 char addr[] = "a.root-servers.net.";
4136 for (char idx = 'a'; idx <= 'm'; idx++) {
4137 addr[0] = idx;
4138 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4139 }
4140
4141 addRRSIG(keys, res->d_records, domain, 300, true);
4142
4143 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4144 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4145
4146 return 1;
4147 } else if (domain == target && type == QType::DNSKEY) {
4148
4149 setLWResult(res, 0, true, false, true);
4150
4151 addDNSKEY(keys, domain, 300, res->d_records);
4152 addRRSIG(keys, res->d_records, domain, 300);
4153
4154 return 1;
4155 }
4156
4157 return 0;
4158 });
4159
4160 vector<DNSRecord> ret;
4161 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4162 BOOST_CHECK_EQUAL(res, RCode::NoError);
4163 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4164 /* 13 NS + 1 RRSIG */
4165 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4166 BOOST_CHECK_EQUAL(queriesCount, 2);
4167
4168 /* again, to test the cache */
4169 ret.clear();
4170 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4171 BOOST_CHECK_EQUAL(res, RCode::NoError);
4172 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4173 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4174 BOOST_CHECK_EQUAL(queriesCount, 2);
4175 }
4176
4177 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
4178 std::unique_ptr<SyncRes> sr;
4179 initSR(sr, true);
4180
4181 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4182
4183 primeHints();
4184 const DNSName target(".");
4185 testkeysset_t keys;
4186
4187 auto luaconfsCopy = g_luaconfs.getCopy();
4188 luaconfsCopy.dsAnchors.clear();
4189 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4190
4191 g_luaconfs.setState(luaconfsCopy);
4192
4193 size_t queriesCount = 0;
4194
4195 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4196 queriesCount++;
4197
4198 if (domain == target && type == QType::NS) {
4199
4200 setLWResult(res, 0, true, false, true);
4201 char addr[] = "a.root-servers.net.";
4202 for (char idx = 'a'; idx <= 'm'; idx++) {
4203 addr[0] = idx;
4204 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4205 }
4206
4207 /* FORCE WRONG ALGO */
4208 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4209
4210 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4211 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4212
4213 return 1;
4214 } else if (domain == target && type == QType::DNSKEY) {
4215
4216 setLWResult(res, 0, true, false, true);
4217
4218 addDNSKEY(keys, domain, 300, res->d_records);
4219 addRRSIG(keys, res->d_records, domain, 300);
4220
4221 return 1;
4222 }
4223
4224 return 0;
4225 });
4226
4227 vector<DNSRecord> ret;
4228 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4229 BOOST_CHECK_EQUAL(res, RCode::NoError);
4230 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4231 /* 13 NS + 1 RRSIG */
4232 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4233 BOOST_CHECK_EQUAL(queriesCount, 2);
4234
4235 /* again, to test the cache */
4236 ret.clear();
4237 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4238 BOOST_CHECK_EQUAL(res, RCode::NoError);
4239 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4240 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4241 BOOST_CHECK_EQUAL(queriesCount, 2);
4242 }
4243
4244 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds) {
4245 std::unique_ptr<SyncRes> sr;
4246 initSR(sr, true);
4247
4248 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4249
4250 primeHints();
4251 const DNSName target("com.");
4252 const ComboAddress targetAddr("192.0.2.42");
4253 testkeysset_t keys;
4254
4255 auto luaconfsCopy = g_luaconfs.getCopy();
4256 luaconfsCopy.dsAnchors.clear();
4257 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4258 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4259
4260 g_luaconfs.setState(luaconfsCopy);
4261
4262 size_t queriesCount = 0;
4263
4264 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4265 queriesCount++;
4266
4267 DNSName auth = domain;
4268
4269 if (type == QType::DS || type == QType::DNSKEY) {
4270 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4271 return 0;
4272 }
4273
4274 if (type == QType::DS && domain == target) {
4275 /* remove the last record, which is the DS's RRSIG */
4276 res->d_records.pop_back();
4277 }
4278
4279 return 1;
4280 }
4281
4282 if (isRootServer(ip)) {
4283 setLWResult(res, 0, false, false, true);
4284 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4285 /* Include the DS but omit the RRSIG*/
4286 addDS(DNSName("com."), 300, res->d_records, keys);
4287 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4288 return 1;
4289 }
4290
4291 if (ip == ComboAddress("192.0.2.1:53")) {
4292 setLWResult(res, RCode::NoError, true, false, true);
4293 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4294 addRRSIG(keys, res->d_records, auth, 300);
4295 return 1;
4296 }
4297
4298 return 0;
4299 });
4300
4301 vector<DNSRecord> ret;
4302 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4303 BOOST_CHECK_EQUAL(res, RCode::NoError);
4304 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4305 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4306 BOOST_CHECK_EQUAL(queriesCount, 4);
4307
4308 /* again, to test the cache */
4309 ret.clear();
4310 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4311 BOOST_CHECK_EQUAL(res, RCode::NoError);
4312 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4313 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4314 BOOST_CHECK_EQUAL(queriesCount, 4);
4315
4316 /* now we ask directly for the DS */
4317 ret.clear();
4318 res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4319 BOOST_CHECK_EQUAL(res, RCode::NoError);
4320 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4321 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4322 BOOST_CHECK_EQUAL(queriesCount, 4);
4323 }
4324
4325 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds_direct) {
4326 std::unique_ptr<SyncRes> sr;
4327 initSR(sr, true);
4328
4329 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4330
4331 primeHints();
4332 const DNSName target("com.");
4333 testkeysset_t keys;
4334
4335 auto luaconfsCopy = g_luaconfs.getCopy();
4336 luaconfsCopy.dsAnchors.clear();
4337 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4338 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4339
4340 g_luaconfs.setState(luaconfsCopy);
4341
4342 size_t queriesCount = 0;
4343
4344 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4345 queriesCount++;
4346
4347 DNSName auth = domain;
4348
4349 if (type == QType::DS || type == QType::DNSKEY) {
4350 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4351 return 0;
4352 }
4353
4354 if (type == QType::DS && domain == target) {
4355 /* remove the last record, which is the DS's RRSIG */
4356 res->d_records.pop_back();
4357 }
4358
4359 return 1;
4360 }
4361
4362 if (isRootServer(ip)) {
4363 setLWResult(res, 0, false, false, true);
4364 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4365 /* Include the DS but omit the RRSIG*/
4366 addDS(DNSName("com."), 300, res->d_records, keys);
4367 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4368 return 1;
4369 }
4370
4371 return 0;
4372 });
4373
4374 vector<DNSRecord> ret;
4375 int res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4376 BOOST_CHECK_EQUAL(res, RCode::NoError);
4377 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4378 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4379 BOOST_CHECK_EQUAL(queriesCount, 1);
4380 }
4381
4382 BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
4383 std::unique_ptr<SyncRes> sr;
4384 initSR(sr, true);
4385
4386 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4387
4388 primeHints();
4389 const DNSName target("powerdns.com.");
4390 const ComboAddress targetAddr("192.0.2.42");
4391 testkeysset_t keys;
4392
4393 auto luaconfsCopy = g_luaconfs.getCopy();
4394 luaconfsCopy.dsAnchors.clear();
4395 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4396 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4397 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
4398
4399 g_luaconfs.setState(luaconfsCopy);
4400
4401 size_t queriesCount = 0;
4402
4403 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4404 queriesCount++;
4405
4406 DNSName auth = domain;
4407 if (domain == target) {
4408 auth = DNSName("powerdns.com.");
4409 }
4410
4411 if (type == QType::DS || type == QType::DNSKEY) {
4412 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4413 }
4414
4415 if (isRootServer(ip)) {
4416 setLWResult(res, 0, false, false, true);
4417 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4418 addDS(DNSName("com."), 300, res->d_records, keys);
4419 addRRSIG(keys, res->d_records, DNSName("."), 300);
4420 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4421 return 1;
4422 }
4423
4424 if (ip == ComboAddress("192.0.2.1:53")) {
4425 if (domain == DNSName("com.")) {
4426 setLWResult(res, 0, true, false, true);
4427 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4428 addRRSIG(keys, res->d_records, domain, 300);
4429 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4430 addRRSIG(keys, res->d_records, domain, 300);
4431 }
4432 else {
4433 setLWResult(res, 0, false, false, true);
4434 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4435 addDS(auth, 300, res->d_records, keys);
4436 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4437 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4438 }
4439 return 1;
4440 }
4441
4442 if (ip == ComboAddress("192.0.2.2:53")) {
4443 if (type == QType::NS) {
4444 setLWResult(res, 0, true, false, true);
4445 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4446 addRRSIG(keys, res->d_records, auth, 300);
4447 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4448 addRRSIG(keys, res->d_records, auth, 300);
4449 }
4450 else {
4451 setLWResult(res, RCode::NoError, true, false, true);
4452 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4453 addRRSIG(keys, res->d_records, auth, 300);
4454 }
4455 return 1;
4456 }
4457
4458 return 0;
4459 });
4460
4461 vector<DNSRecord> ret;
4462 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4463 BOOST_CHECK_EQUAL(res, RCode::NoError);
4464 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4465 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4466 BOOST_CHECK_EQUAL(queriesCount, 8);
4467
4468 /* again, to test the cache */
4469 ret.clear();
4470 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4471 BOOST_CHECK_EQUAL(res, RCode::NoError);
4472 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4473 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4474 BOOST_CHECK_EQUAL(queriesCount, 8);
4475 }
4476
4477 BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4478 std::unique_ptr<SyncRes> sr;
4479 initSR(sr, true);
4480
4481 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4482
4483 primeHints();
4484 const DNSName target("powerdns.com.");
4485 const ComboAddress targetAddr("192.0.2.42");
4486 testkeysset_t keys;
4487
4488 auto luaconfsCopy = g_luaconfs.getCopy();
4489 luaconfsCopy.dsAnchors.clear();
4490 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4491 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4492 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4493 g_luaconfs.setState(luaconfsCopy);
4494
4495 size_t queriesCount = 0;
4496
4497 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4498 queriesCount++;
4499
4500 DNSName auth = domain;
4501 if (domain == target) {
4502 auth = DNSName("powerdns.com.");
4503 }
4504
4505 if (type == QType::DS || type == QType::DNSKEY) {
4506 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4507 }
4508
4509 if (isRootServer(ip)) {
4510 setLWResult(res, 0, false, false, true);
4511 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4512 addDS(DNSName("com."), 300, res->d_records, keys);
4513 addRRSIG(keys, res->d_records, DNSName("."), 300);
4514 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4515 return 1;
4516 }
4517
4518 if (ip == ComboAddress("192.0.2.1:53")) {
4519 if (domain == DNSName("com.")) {
4520 setLWResult(res, 0, true, false, true);
4521 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4522 addRRSIG(keys, res->d_records, domain, 300);
4523 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4524 addRRSIG(keys, res->d_records, domain, 300);
4525 }
4526 else {
4527 setLWResult(res, 0, false, false, true);
4528 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4529 addDS(auth, 300, res->d_records, keys);
4530 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4531 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4532 }
4533 return 1;
4534 }
4535
4536 if (ip == ComboAddress("192.0.2.2:53")) {
4537 if (type == QType::NS) {
4538 setLWResult(res, 0, true, false, true);
4539 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4540 addRRSIG(keys, res->d_records, auth, 300);
4541 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4542 addRRSIG(keys, res->d_records, auth, 300);
4543 }
4544 else {
4545 setLWResult(res, RCode::NoError, true, false, true);
4546 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4547 addRRSIG(keys, res->d_records, auth, 300);
4548 }
4549 return 1;
4550 }
4551
4552 return 0;
4553 });
4554
4555 vector<DNSRecord> ret;
4556 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4557 BOOST_CHECK_EQUAL(res, RCode::NoError);
4558 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4559 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4560 BOOST_CHECK_EQUAL(queriesCount, 8);
4561
4562 /* again, to test the cache */
4563 ret.clear();
4564 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4565 BOOST_CHECK_EQUAL(res, RCode::NoError);
4566 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4567 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4568 BOOST_CHECK_EQUAL(queriesCount, 8);
4569
4570 /* this time we ask for the NS that should be in the cache, to check
4571 the validation status */
4572 ret.clear();
4573 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4574 BOOST_CHECK_EQUAL(res, RCode::NoError);
4575 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4576 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4577 BOOST_CHECK_EQUAL(queriesCount, 9);
4578
4579 }
4580
4581 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4582 std::unique_ptr<SyncRes> sr;
4583 initSR(sr, true);
4584
4585 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4586
4587 primeHints();
4588 const DNSName target("powerdns.com.");
4589 const ComboAddress targetAddr("192.0.2.42");
4590 testkeysset_t keys;
4591
4592 auto luaconfsCopy = g_luaconfs.getCopy();
4593 luaconfsCopy.dsAnchors.clear();
4594 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4595 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4596 g_luaconfs.setState(luaconfsCopy);
4597
4598 size_t queriesCount = 0;
4599
4600 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4601 queriesCount++;
4602
4603 DNSName auth = domain;
4604 if (domain == target) {
4605 auth = DNSName("powerdns.com.");
4606 }
4607
4608 if (type == QType::DS || type == QType::DNSKEY) {
4609 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4610 }
4611
4612 if (isRootServer(ip)) {
4613 setLWResult(res, 0, false, false, true);
4614 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4615 addDS(DNSName("com."), 300, res->d_records, keys);
4616 addRRSIG(keys, res->d_records, DNSName("."), 300);
4617 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4618 return 1;
4619 }
4620
4621 if (ip == ComboAddress("192.0.2.1:53")) {
4622 if (domain == DNSName("com.")) {
4623 setLWResult(res, 0, true, false, true);
4624 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4625 addRRSIG(keys, res->d_records, domain, 300);
4626 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4627 addRRSIG(keys, res->d_records, domain, 300);
4628 }
4629 else {
4630 setLWResult(res, 0, false, false, true);
4631 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4632 /* no DS */
4633 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4634 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4635 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4636 }
4637 return 1;
4638 }
4639
4640 if (ip == ComboAddress("192.0.2.2:53")) {
4641 if (type == QType::NS) {
4642 setLWResult(res, 0, true, false, true);
4643 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4644 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4645 }
4646 else {
4647 setLWResult(res, RCode::NoError, true, false, true);
4648 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4649 }
4650 return 1;
4651 }
4652
4653 return 0;
4654 });
4655
4656 vector<DNSRecord> ret;
4657 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4658 BOOST_CHECK_EQUAL(res, RCode::NoError);
4659 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4660 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4661 BOOST_CHECK_EQUAL(queriesCount, 7);
4662
4663 /* again, to test the cache */
4664 ret.clear();
4665 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4666 BOOST_CHECK_EQUAL(res, RCode::NoError);
4667 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4668 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4669 BOOST_CHECK_EQUAL(queriesCount, 7);
4670
4671 /* this time we ask for the NS that should be in the cache, to check
4672 the validation status */
4673 ret.clear();
4674 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4675 BOOST_CHECK_EQUAL(res, RCode::NoError);
4676 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4677 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4678 BOOST_CHECK_EQUAL(queriesCount, 8);
4679 }
4680
4681 BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
4682 std::unique_ptr<SyncRes> sr;
4683 initSR(sr, true);
4684
4685 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4686
4687 primeHints();
4688 const DNSName target("powerdns.com.");
4689 const ComboAddress targetAddr("192.0.2.42");
4690 testkeysset_t keys;
4691
4692 auto luaconfsCopy = g_luaconfs.getCopy();
4693 luaconfsCopy.dsAnchors.clear();
4694 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4695 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4696 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4697
4698 /* Add a NTA for "powerdns.com" */
4699 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4700
4701 g_luaconfs.setState(luaconfsCopy);
4702
4703 size_t queriesCount = 0;
4704
4705 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4706 queriesCount++;
4707
4708 DNSName auth = domain;
4709 if (domain == target) {
4710 auth = DNSName("powerdns.com.");
4711 }
4712
4713 if (type == QType::DS || type == QType::DNSKEY) {
4714 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4715 }
4716
4717 if (isRootServer(ip)) {
4718 setLWResult(res, 0, false, false, true);
4719 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4720 addDS(DNSName("com."), 300, res->d_records, keys);
4721 addRRSIG(keys, res->d_records, DNSName("."), 300);
4722 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4723 return 1;
4724 }
4725
4726 if (ip == ComboAddress("192.0.2.1:53")) {
4727 if (domain == DNSName("com.")) {
4728 setLWResult(res, 0, true, false, true);
4729 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4730 addRRSIG(keys, res->d_records, domain, 300);
4731 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4732 addRRSIG(keys, res->d_records, domain, 300);
4733 }
4734 else {
4735 setLWResult(res, 0, false, false, true);
4736 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4737 addDS(auth, 300, res->d_records, keys);
4738 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4739 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4740 }
4741 return 1;
4742 }
4743
4744 if (ip == ComboAddress("192.0.2.2:53")) {
4745 if (type == QType::NS) {
4746 setLWResult(res, 0, true, false, true);
4747 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4748 addRRSIG(keys, res->d_records, auth, 300);
4749 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4750 addRRSIG(keys, res->d_records, auth, 300);
4751 }
4752 else {
4753 setLWResult(res, RCode::NoError, true, false, true);
4754 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4755 addRRSIG(keys, res->d_records, auth, 300);
4756 }
4757 return 1;
4758 }
4759
4760 return 0;
4761 });
4762
4763 vector<DNSRecord> ret;
4764 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4765 BOOST_CHECK_EQUAL(res, RCode::NoError);
4766 /* Should be insecure because of the NTA */
4767 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4768 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4769 BOOST_CHECK_EQUAL(queriesCount, 5);
4770
4771 /* again, to test the cache */
4772 ret.clear();
4773 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4774 BOOST_CHECK_EQUAL(res, RCode::NoError);
4775 /* Should be insecure because of the NTA */
4776 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4777 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4778 BOOST_CHECK_EQUAL(queriesCount, 5);
4779 }
4780
4781 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4782 std::unique_ptr<SyncRes> sr;
4783 initSR(sr, true);
4784
4785 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4786
4787 primeHints();
4788 const DNSName target("powerdns.com.");
4789 const ComboAddress targetAddr("192.0.2.42");
4790 testkeysset_t keys;
4791
4792 auto luaconfsCopy = g_luaconfs.getCopy();
4793 luaconfsCopy.dsAnchors.clear();
4794 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4795 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4796 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4797
4798 /* Add a NTA for "powerdns.com" */
4799 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4800
4801 g_luaconfs.setState(luaconfsCopy);
4802
4803 size_t queriesCount = 0;
4804
4805 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4806 queriesCount++;
4807
4808 if (type == QType::DS || type == QType::DNSKEY) {
4809 setLWResult(res, 0, false, false, true);
4810 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4811 return 1;
4812 }
4813 else {
4814 if (isRootServer(ip)) {
4815 setLWResult(res, 0, false, false, true);
4816 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4817 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4818 return 1;
4819 }
4820 else if (ip == ComboAddress("192.0.2.1:53")) {
4821 if (domain == DNSName("com.")) {
4822 setLWResult(res, 0, true, false, true);
4823 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4824 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4825 }
4826 else {
4827 setLWResult(res, 0, false, false, true);
4828 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4829 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4830 }
4831 return 1;
4832 }
4833 else if (ip == ComboAddress("192.0.2.2:53")) {
4834 if (type == QType::NS) {
4835 setLWResult(res, 0, true, false, true);
4836 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4837 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4838 }
4839 else {
4840 setLWResult(res, RCode::NoError, true, false, true);
4841 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4842 }
4843 return 1;
4844 }
4845 }
4846
4847 return 0;
4848 });
4849
4850 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
4851 vector<DNSRecord> ret;
4852 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4853 BOOST_CHECK_EQUAL(res, RCode::NoError);
4854 /* Should be insecure because of the NTA */
4855 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4856 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4857 BOOST_CHECK_EQUAL(queriesCount, 4);
4858
4859 /* again, to test the cache */
4860 ret.clear();
4861 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4862 BOOST_CHECK_EQUAL(res, RCode::NoError);
4863 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4864 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4865 BOOST_CHECK_EQUAL(queriesCount, 4);
4866 }
4867
4868 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
4869 std::unique_ptr<SyncRes> sr;
4870 initSR(sr, true);
4871
4872 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4873
4874 primeHints();
4875 const DNSName target("powerdns.com.");
4876 testkeysset_t keys;
4877
4878 auto luaconfsCopy = g_luaconfs.getCopy();
4879 luaconfsCopy.dsAnchors.clear();
4880 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4881 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4882 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4883
4884 g_luaconfs.setState(luaconfsCopy);
4885
4886 size_t queriesCount = 0;
4887
4888 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4889 queriesCount++;
4890
4891 if (type == QType::DS || type == QType::DNSKEY) {
4892 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4893 }
4894 else {
4895 if (isRootServer(ip)) {
4896 setLWResult(res, 0, false, false, true);
4897 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4898 addDS(DNSName("com."), 300, res->d_records, keys);
4899 addRRSIG(keys, res->d_records, DNSName("."), 300);
4900 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4901 return 1;
4902 }
4903 else if (ip == ComboAddress("192.0.2.1:53")) {
4904 if (domain == DNSName("com.")) {
4905 setLWResult(res, 0, true, false, true);
4906 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4907 addRRSIG(keys, res->d_records, domain, 300);
4908 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4909 addRRSIG(keys, res->d_records, domain, 300);
4910 }
4911 else {
4912 setLWResult(res, 0, false, false, true);
4913 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4914 addDS(domain, 300, res->d_records, keys);
4915 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4916 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4917 }
4918 return 1;
4919 }
4920 else if (ip == ComboAddress("192.0.2.2:53")) {
4921 if (type == QType::NS) {
4922 setLWResult(res, 0, true, false, true);
4923 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4924 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4925 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4926 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4927 }
4928 else {
4929 setLWResult(res, 0, true, false, true);
4930 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4931 addRRSIG(keys, res->d_records, domain, 300);
4932 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
4933 addRRSIG(keys, res->d_records, domain, 300);
4934 }
4935 return 1;
4936 }
4937 }
4938
4939 return 0;
4940 });
4941
4942 vector<DNSRecord> ret;
4943 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4944 BOOST_CHECK_EQUAL(res, RCode::NoError);
4945 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4946 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4947 BOOST_CHECK_EQUAL(queriesCount, 8);
4948
4949 /* again, to test the cache */
4950 ret.clear();
4951 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4952 BOOST_CHECK_EQUAL(res, RCode::NoError);
4953 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4954 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4955 BOOST_CHECK_EQUAL(queriesCount, 8);
4956 }
4957
4958 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
4959 std::unique_ptr<SyncRes> sr;
4960 initSR(sr, true);
4961
4962 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4963
4964 primeHints();
4965 const DNSName target("nx.powerdns.com.");
4966 testkeysset_t keys;
4967
4968 auto luaconfsCopy = g_luaconfs.getCopy();
4969 luaconfsCopy.dsAnchors.clear();
4970 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4971 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4972 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4973
4974 g_luaconfs.setState(luaconfsCopy);
4975
4976 size_t queriesCount = 0;
4977
4978 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4979 queriesCount++;
4980
4981 DNSName auth = domain;
4982 if (domain == target) {
4983 auth = DNSName("powerdns.com.");
4984 }
4985 if (type == QType::DS || type == QType::DNSKEY) {
4986 if (type == QType::DS && domain == target) {
4987 setLWResult(res, RCode::NXDomain, true, false, true);
4988 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4989 addRRSIG(keys, res->d_records, auth, 300);
4990 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4991 addRRSIG(keys, res->d_records, auth, 300);
4992 return 1;
4993 }
4994 else {
4995 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4996 }
4997 }
4998 else {
4999 if (isRootServer(ip)) {
5000 setLWResult(res, 0, false, false, true);
5001 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5002 addDS(DNSName("com."), 300, res->d_records, keys);
5003 addRRSIG(keys, res->d_records, DNSName("."), 300);
5004 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5005 return 1;
5006 }
5007 else if (ip == ComboAddress("192.0.2.1:53")) {
5008 if (domain == DNSName("com.")) {
5009 setLWResult(res, 0, true, false, true);
5010 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5011 addRRSIG(keys, res->d_records, domain, 300);
5012 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5013 addRRSIG(keys, res->d_records, domain, 300);
5014 }
5015 else {
5016 setLWResult(res, 0, false, false, true);
5017 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5018 addDS(auth, 300, res->d_records, keys);
5019 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5020 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5021 }
5022 return 1;
5023 }
5024 else if (ip == ComboAddress("192.0.2.2:53")) {
5025 if (type == QType::NS) {
5026 setLWResult(res, 0, true, false, true);
5027 if (domain == DNSName("powerdns.com.")) {
5028 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5029 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5030 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5031 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5032 }
5033 else {
5034 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5035 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5036 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5037 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5038 }
5039 }
5040 else {
5041 setLWResult(res, RCode::NXDomain, true, false, true);
5042 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5043 addRRSIG(keys, res->d_records, auth, 300);
5044 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5045 addRRSIG(keys, res->d_records, auth, 300);
5046 /* add wildcard denial */
5047 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5048 addRRSIG(keys, res->d_records, auth, 300);
5049 }
5050 return 1;
5051 }
5052 }
5053
5054 return 0;
5055 });
5056
5057 vector<DNSRecord> ret;
5058 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5059 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5060 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5061 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5062 BOOST_CHECK_EQUAL(queriesCount, 9);
5063
5064 /* again, to test the cache */
5065 ret.clear();
5066 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5067 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5068 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5069 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5070 BOOST_CHECK_EQUAL(queriesCount, 9);
5071 }
5072
5073 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
5074 std::unique_ptr<SyncRes> sr;
5075 initSR(sr, true);
5076
5077 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5078
5079 primeHints();
5080 const DNSName target("www.powerdns.com.");
5081 testkeysset_t keys;
5082
5083 auto luaconfsCopy = g_luaconfs.getCopy();
5084 luaconfsCopy.dsAnchors.clear();
5085 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5086 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5087 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5088
5089 g_luaconfs.setState(luaconfsCopy);
5090
5091 size_t queriesCount = 0;
5092
5093 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5094 queriesCount++;
5095
5096 if (type == QType::DS || type == QType::DNSKEY) {
5097 if (type == QType::DS && domain == target) {
5098 setLWResult(res, RCode::NoError, true, false, true);
5099 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5100 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5101 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5102 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5103 return 1;
5104 }
5105 else {
5106 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5107 }
5108 }
5109 else {
5110 if (isRootServer(ip)) {
5111 setLWResult(res, 0, false, false, true);
5112 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5113 addDS(DNSName("com."), 300, res->d_records, keys);
5114 addRRSIG(keys, res->d_records, DNSName("."), 300);
5115 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5116 return 1;
5117 }
5118 else if (ip == ComboAddress("192.0.2.1:53")) {
5119 if (domain == DNSName("com.")) {
5120 setLWResult(res, 0, true, false, true);
5121 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5122 addRRSIG(keys, res->d_records, domain, 300);
5123 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5124 addRRSIG(keys, res->d_records, domain, 300);
5125 }
5126 else {
5127 setLWResult(res, 0, false, false, true);
5128 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5129 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5130 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5131 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5132 }
5133 return 1;
5134 }
5135 else if (ip == ComboAddress("192.0.2.2:53")) {
5136 setLWResult(res, 0, true, false, true);
5137 if (type == QType::NS) {
5138 if (domain == DNSName("powerdns.com.")) {
5139 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5140 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5141 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5142 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5143 }
5144 else {
5145 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5146 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5147 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5148 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5149 }
5150 }
5151 else {
5152 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5153 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5154 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5155 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5156 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5157 }
5158 return 1;
5159 }
5160 }
5161
5162 return 0;
5163 });
5164
5165 vector<DNSRecord> ret;
5166 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5167 BOOST_CHECK_EQUAL(res, RCode::NoError);
5168 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5169 BOOST_REQUIRE_EQUAL(ret.size(), 4);
5170 BOOST_CHECK_EQUAL(queriesCount, 9);
5171
5172 /* again, to test the cache */
5173 ret.clear();
5174 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5175 BOOST_CHECK_EQUAL(res, RCode::NoError);
5176 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5177 BOOST_REQUIRE_EQUAL(ret.size(), 4);
5178 BOOST_CHECK_EQUAL(queriesCount, 9);
5179 }
5180
5181 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
5182 std::unique_ptr<SyncRes> sr;
5183 initSR(sr, true);
5184
5185 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5186
5187 primeHints();
5188 const DNSName target("www.com.");
5189 testkeysset_t keys;
5190
5191 auto luaconfsCopy = g_luaconfs.getCopy();
5192 luaconfsCopy.dsAnchors.clear();
5193 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5194 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5195
5196 g_luaconfs.setState(luaconfsCopy);
5197
5198 size_t queriesCount = 0;
5199
5200 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5201 queriesCount++;
5202
5203 if (type == QType::DS || type == QType::DNSKEY) {
5204 if (type == QType::DS && domain == target) {
5205 DNSName auth("com.");
5206 setLWResult(res, 0, true, false, true);
5207
5208 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5209 addRRSIG(keys, res->d_records, auth, 300);
5210 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
5211 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
5212 addRRSIG(keys, res->d_records, auth, 300);
5213 return 1;
5214 }
5215 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5216 }
5217 else {
5218 if (isRootServer(ip)) {
5219 setLWResult(res, 0, false, false, true);
5220 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5221 addDS(DNSName("com."), 300, res->d_records, keys);
5222 addRRSIG(keys, res->d_records, DNSName("."), 300);
5223 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5224 return 1;
5225 }
5226 else if (ip == ComboAddress("192.0.2.1:53")) {
5227 setLWResult(res, 0, true, false, true);
5228 /* no data */
5229 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5230 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5231 /* no record for this name */
5232 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
5233 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5234 /* a wildcard matches but has no record for this type */
5235 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5236 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5237 return 1;
5238 }
5239 }
5240
5241 return 0;
5242 });
5243
5244 vector<DNSRecord> ret;
5245 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5246 BOOST_CHECK_EQUAL(res, RCode::NoError);
5247 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5248 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5249 BOOST_CHECK_EQUAL(queriesCount, 6);
5250
5251 /* again, to test the cache */
5252 ret.clear();
5253 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5254 BOOST_CHECK_EQUAL(res, RCode::NoError);
5255 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5256 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5257 BOOST_CHECK_EQUAL(queriesCount, 6);
5258 }
5259
5260 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
5261 std::unique_ptr<SyncRes> sr;
5262 initSR(sr, true);
5263
5264 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5265
5266 primeHints();
5267 const DNSName target("www.com.");
5268 testkeysset_t keys;
5269
5270 auto luaconfsCopy = g_luaconfs.getCopy();
5271 luaconfsCopy.dsAnchors.clear();
5272 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5273 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5274
5275 g_luaconfs.setState(luaconfsCopy);
5276
5277 size_t queriesCount = 0;
5278
5279 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5280 queriesCount++;
5281
5282 if (type == QType::DS || type == QType::DNSKEY) {
5283 if (type == QType::DS && domain == target) {
5284 DNSName auth("com.");
5285 setLWResult(res, 0, true, false, true);
5286
5287 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5288 addRRSIG(keys, res->d_records, auth, 300);
5289 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5290 /* first the closest encloser */
5291 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5292 addRRSIG(keys, res->d_records, auth, 300);
5293 /* then the next closer */
5294 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5295 addRRSIG(keys, res->d_records, auth, 300);
5296 /* a wildcard matches but has no record for this type */
5297 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5298 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5299 return 1;
5300 }
5301 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5302 }
5303 else {
5304 if (isRootServer(ip)) {
5305 setLWResult(res, 0, false, false, true);
5306 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5307 addDS(DNSName("com."), 300, res->d_records, keys);
5308 addRRSIG(keys, res->d_records, DNSName("."), 300);
5309 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5310 return 1;
5311 }
5312 else if (ip == ComboAddress("192.0.2.1:53")) {
5313 setLWResult(res, 0, true, false, true);
5314 /* no data */
5315 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5316 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5317 /* no record for this name */
5318 /* first the closest encloser */
5319 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5320 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5321 /* then the next closer */
5322 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5323 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5324 /* a wildcard matches but has no record for this type */
5325 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5326 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5327 return 1;
5328 }
5329 }
5330
5331 return 0;
5332 });
5333
5334 vector<DNSRecord> ret;
5335 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5336 BOOST_CHECK_EQUAL(res, RCode::NoError);
5337 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5338 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5339 BOOST_CHECK_EQUAL(queriesCount, 6);
5340
5341 /* again, to test the cache */
5342 ret.clear();
5343 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5344 BOOST_CHECK_EQUAL(res, RCode::NoError);
5345 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5346 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5347 BOOST_CHECK_EQUAL(queriesCount, 6);
5348 }
5349
5350 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5351 std::unique_ptr<SyncRes> sr;
5352 initSR(sr, true);
5353
5354 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5355
5356 primeHints();
5357 const DNSName target("www.com.");
5358 testkeysset_t keys;
5359
5360 auto luaconfsCopy = g_luaconfs.getCopy();
5361 luaconfsCopy.dsAnchors.clear();
5362 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5363 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5364
5365 g_luaconfs.setState(luaconfsCopy);
5366
5367 size_t queriesCount = 0;
5368
5369 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5370 queriesCount++;
5371
5372 if (type == QType::DS || type == QType::DNSKEY) {
5373 if (type == QType::DS && domain == target) {
5374 DNSName auth("com.");
5375 setLWResult(res, 0, true, false, true);
5376
5377 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5378 addRRSIG(keys, res->d_records, auth, 300);
5379 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5380 /* first the closest encloser */
5381 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5382 addRRSIG(keys, res->d_records, auth, 300);
5383 /* then the next closer */
5384 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5385 addRRSIG(keys, res->d_records, auth, 300);
5386 /* a wildcard matches but has no record for this type */
5387 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5388 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5389 return 1;
5390 }
5391 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5392 }
5393 else {
5394 if (isRootServer(ip)) {
5395 setLWResult(res, 0, false, false, true);
5396 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5397 addDS(DNSName("com."), 300, res->d_records, keys);
5398 addRRSIG(keys, res->d_records, DNSName("."), 300);
5399 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5400 return 1;
5401 }
5402 else if (ip == ComboAddress("192.0.2.1:53")) {
5403 setLWResult(res, 0, true, false, true);
5404 /* no data */
5405 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5406 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5407 /* no record for this name */
5408 /* first the closest encloser */
5409 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5410 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5411 /* then the next closer */
5412 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5413 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5414 /* a wildcard matches but has no record for this type */
5415 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5416 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5417 return 1;
5418 }
5419 }
5420
5421 return 0;
5422 });
5423
5424 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5425 vector<DNSRecord> ret;
5426 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5427 BOOST_CHECK_EQUAL(res, RCode::NoError);
5428 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5429 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5430 BOOST_CHECK_EQUAL(queriesCount, 6);
5431
5432 /* again, to test the cache */
5433 ret.clear();
5434 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5435 BOOST_CHECK_EQUAL(res, RCode::NoError);
5436 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5437 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5438 BOOST_CHECK_EQUAL(queriesCount, 6);
5439 }
5440
5441 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5442 std::unique_ptr<SyncRes> sr;
5443 initSR(sr, true);
5444
5445 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5446
5447 primeHints();
5448 const DNSName target("www.sub.powerdns.com.");
5449 testkeysset_t keys;
5450
5451 auto luaconfsCopy = g_luaconfs.getCopy();
5452 luaconfsCopy.dsAnchors.clear();
5453 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5454 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5455 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5456
5457 g_luaconfs.setState(luaconfsCopy);
5458
5459 size_t queriesCount = 0;
5460
5461 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5462 queriesCount++;
5463
5464 if (type == QType::DS || type == QType::DNSKEY) {
5465 if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) {
5466 setLWResult(res, RCode::NoError, true, false, true);
5467 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5468 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5469 if (domain == DNSName("sub.powerdns.com")) {
5470 addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5471 }
5472 else if (domain == target) {
5473 addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5474 }
5475 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5476 return 1;
5477 }
5478 else {
5479 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5480 }
5481 }
5482 else {
5483 if (isRootServer(ip)) {
5484 setLWResult(res, 0, false, false, true);
5485 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5486 addDS(DNSName("com."), 300, res->d_records, keys);
5487 addRRSIG(keys, res->d_records, DNSName("."), 300);
5488 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5489 return 1;
5490 }
5491 else if (ip == ComboAddress("192.0.2.1:53")) {
5492 if (domain == DNSName("com.")) {
5493 setLWResult(res, 0, true, false, true);
5494 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5495 addRRSIG(keys, res->d_records, domain, 300);
5496 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5497 addRRSIG(keys, res->d_records, domain, 300);
5498 }
5499 else {
5500 setLWResult(res, 0, false, false, true);
5501 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5502 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5503 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5504 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5505 }
5506 return 1;
5507 }
5508 else if (ip == ComboAddress("192.0.2.2:53")) {
5509 setLWResult(res, 0, true, false, true);
5510 if (type == QType::NS) {
5511 if (domain == DNSName("powerdns.com.")) {
5512 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5513 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5514 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5515 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5516 }
5517 else {
5518 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5519 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5520 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5521 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5522 }
5523 }
5524 else {
5525 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5526 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5527 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5528 /* first the closest encloser */
5529 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5530 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5531 /* then the next closer */
5532 addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5533 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5534 }
5535 return 1;
5536 }
5537 }
5538
5539 return 0;
5540 });
5541
5542 vector<DNSRecord> ret;
5543 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5544 BOOST_CHECK_EQUAL(res, RCode::NoError);
5545 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5546 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5547 BOOST_CHECK_EQUAL(queriesCount, 10);
5548
5549 /* again, to test the cache */
5550 ret.clear();
5551 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5552 BOOST_CHECK_EQUAL(res, RCode::NoError);
5553 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5554 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5555 BOOST_CHECK_EQUAL(queriesCount, 10);
5556 }
5557
5558 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5559 std::unique_ptr<SyncRes> sr;
5560 initSR(sr, true);
5561
5562 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5563
5564 primeHints();
5565 const DNSName target("www.powerdns.com.");
5566 testkeysset_t keys;
5567
5568 auto luaconfsCopy = g_luaconfs.getCopy();
5569 luaconfsCopy.dsAnchors.clear();
5570 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5571 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5572 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5573
5574 g_luaconfs.setState(luaconfsCopy);
5575
5576 size_t queriesCount = 0;
5577
5578 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5579 queriesCount++;
5580
5581 if (type == QType::DS || type == QType::DNSKEY) {
5582 if (type == QType::DS && domain == target) {
5583 setLWResult(res, RCode::NoError, true, false, true);
5584 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5585 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5586 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5587 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5588 return 1;
5589 }
5590 else {
5591 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5592 }
5593 }
5594 else {
5595 if (isRootServer(ip)) {
5596 setLWResult(res, 0, false, false, true);
5597 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5598 addDS(DNSName("com."), 300, res->d_records, keys);
5599 addRRSIG(keys, res->d_records, DNSName("."), 300);
5600 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5601 return 1;
5602 }
5603 else if (ip == ComboAddress("192.0.2.1:53")) {
5604 if (domain == DNSName("com.")) {
5605 setLWResult(res, 0, true, false, true);
5606 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5607 addRRSIG(keys, res->d_records, domain, 300);
5608 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5609 addRRSIG(keys, res->d_records, domain, 300);
5610 }
5611 else {
5612 setLWResult(res, 0, false, false, true);
5613 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5614 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5615 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5616 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5617 }
5618 return 1;
5619 }
5620 else if (ip == ComboAddress("192.0.2.2:53")) {
5621 setLWResult(res, 0, true, false, true);
5622 if (type == QType::NS) {
5623 if (domain == DNSName("powerdns.com.")) {
5624 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5625 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5626 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5627 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5628 }
5629 else {
5630 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5631 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5632 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5633 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5634 }
5635 }
5636 else {
5637 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5638 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5639 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5640 /* first the closest encloser */
5641 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5642 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5643 /* then the next closer */
5644 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5645 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5646 }
5647 return 1;
5648 }
5649 }
5650
5651 return 0;
5652 });
5653
5654 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5655 we should end up Insecure */
5656 vector<DNSRecord> ret;
5657 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5658 BOOST_CHECK_EQUAL(res, RCode::NoError);
5659 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5660 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5661 BOOST_CHECK_EQUAL(queriesCount, 9);
5662
5663 /* again, to test the cache */
5664 ret.clear();
5665 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5666 BOOST_CHECK_EQUAL(res, RCode::NoError);
5667 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5668 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5669 BOOST_CHECK_EQUAL(queriesCount, 9);
5670 }
5671
5672 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5673 std::unique_ptr<SyncRes> sr;
5674 initSR(sr, true);
5675
5676 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5677
5678 primeHints();
5679 const DNSName target("www.powerdns.com.");
5680 testkeysset_t keys;
5681
5682 auto luaconfsCopy = g_luaconfs.getCopy();
5683 luaconfsCopy.dsAnchors.clear();
5684 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5685 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5686 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5687
5688 g_luaconfs.setState(luaconfsCopy);
5689
5690 size_t queriesCount = 0;
5691
5692 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5693 queriesCount++;
5694
5695 if (type == QType::DS || type == QType::DNSKEY) {
5696 if (type == QType::DS && domain == target) {
5697 setLWResult(res, RCode::NoError, true, false, true);
5698 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5699 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5700 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5701 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5702 return 1;
5703 }
5704 else {
5705 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5706 }
5707 }
5708 else {
5709 if (isRootServer(ip)) {
5710 setLWResult(res, 0, false, false, true);
5711 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5712 addDS(DNSName("com."), 300, res->d_records, keys);
5713 addRRSIG(keys, res->d_records, DNSName("."), 300);
5714 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5715 return 1;
5716 }
5717 else if (ip == ComboAddress("192.0.2.1:53")) {
5718 if (domain == DNSName("com.")) {
5719 setLWResult(res, 0, true, false, true);
5720 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5721 addRRSIG(keys, res->d_records, domain, 300);
5722 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5723 addRRSIG(keys, res->d_records, domain, 300);
5724 }
5725 else {
5726 setLWResult(res, 0, false, false, true);
5727 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5728 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5729 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5730 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5731 }
5732 return 1;
5733 }
5734 else if (ip == ComboAddress("192.0.2.2:53")) {
5735 setLWResult(res, 0, true, false, true);
5736 if (type == QType::NS) {
5737 if (domain == DNSName("powerdns.com.")) {
5738 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5739 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5740 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5741 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5742 }
5743 else {
5744 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5745 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5746 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5747 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5748 }
5749 }
5750 else {
5751 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5752 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5753 }
5754 return 1;
5755 }
5756 }
5757
5758 return 0;
5759 });
5760
5761 vector<DNSRecord> ret;
5762 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5763 BOOST_CHECK_EQUAL(res, RCode::NoError);
5764 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5765 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5766 BOOST_CHECK_EQUAL(queriesCount, 9);
5767
5768 /* again, to test the cache */
5769 ret.clear();
5770 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5771 BOOST_CHECK_EQUAL(res, RCode::NoError);
5772 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5773 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5774 BOOST_CHECK_EQUAL(queriesCount, 9);
5775 }
5776
5777 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5778 std::unique_ptr<SyncRes> sr;
5779 initSR(sr, true);
5780
5781 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5782
5783 primeHints();
5784 const DNSName target("www.powerdns.com.");
5785 testkeysset_t keys;
5786
5787 auto luaconfsCopy = g_luaconfs.getCopy();
5788 luaconfsCopy.dsAnchors.clear();
5789 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5790 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5791 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5792
5793 g_luaconfs.setState(luaconfsCopy);
5794
5795 size_t queriesCount = 0;
5796 size_t dsQueriesCount = 0;
5797
5798 sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5799 queriesCount++;
5800
5801 if (type == QType::DS) {
5802 DNSName auth(domain);
5803 auth.chopOff();
5804 dsQueriesCount++;
5805
5806 setLWResult(res, 0, true, false, true);
5807 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5808 addRRSIG(keys, res->d_records, auth, 300);
5809 return 1;
5810 }
5811 else if (type == QType::DNSKEY) {
5812 setLWResult(res, 0, true, false, true);
5813 addDNSKEY(keys, domain, 300, res->d_records);
5814 addRRSIG(keys, res->d_records, domain, 300);
5815 return 1;
5816 }
5817 else {
5818 if (isRootServer(ip)) {
5819 setLWResult(res, 0, false, false, true);
5820 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5821 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5822 /* No DS on referral, and no denial of the DS either */
5823 return 1;
5824 }
5825 else if (ip == ComboAddress("192.0.2.1:53")) {
5826 if (domain == DNSName("com.")) {
5827 setLWResult(res, 0, true, false, true);
5828 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5829 addRRSIG(keys, res->d_records, domain, 300);
5830 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5831 addRRSIG(keys, res->d_records, domain, 300);
5832 }
5833 else {
5834 setLWResult(res, 0, false, false, true);
5835 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5836 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5837 /* No DS on referral, and no denial of the DS either */
5838 }
5839 return 1;
5840 }
5841 else if (ip == ComboAddress("192.0.2.2:53")) {
5842 setLWResult(res, 0, true, false, true);
5843 if (type == QType::NS) {
5844 if (domain == DNSName("powerdns.com.")) {
5845 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5846 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5847 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5848 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5849 }
5850 else {
5851 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5852 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5853 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5854 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5855 }
5856 }
5857 else {
5858 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5859 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5860 }
5861
5862 return 1;
5863 }
5864 }
5865
5866 return 0;
5867 });
5868
5869 vector<DNSRecord> ret;
5870 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5871 BOOST_CHECK_EQUAL(res, RCode::NoError);
5872 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5873 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5874 BOOST_CHECK_EQUAL(queriesCount, 9);
5875 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5876
5877 /* again, to test the cache */
5878 ret.clear();
5879 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5880 BOOST_CHECK_EQUAL(res, RCode::NoError);
5881 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5882 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5883 BOOST_CHECK_EQUAL(queriesCount, 9);
5884 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5885 }
5886
5887 BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
5888 std::unique_ptr<SyncRes> sr;
5889 initSR(sr, true);
5890
5891 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5892
5893 primeHints();
5894 const DNSName target("www.powerdns.com.");
5895 testkeysset_t keys;
5896
5897 auto luaconfsCopy = g_luaconfs.getCopy();
5898 luaconfsCopy.dsAnchors.clear();
5899 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5900 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5901 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5902 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5903
5904 g_luaconfs.setState(luaconfsCopy);
5905
5906 size_t queriesCount = 0;
5907
5908 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5909 queriesCount++;
5910
5911 if (type == QType::DS) {
5912 DNSName auth(domain);
5913 auth.chopOff();
5914
5915 setLWResult(res, 0, true, false, true);
5916 if (domain == target) {
5917 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5918 addRRSIG(keys, res->d_records, target, 300);
5919 }
5920 else {
5921 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5922 addRRSIG(keys, res->d_records, auth, 300);
5923 }
5924 return 1;
5925 }
5926 else if (type == QType::DNSKEY) {
5927 setLWResult(res, 0, true, false, true);
5928 addDNSKEY(keys, domain, 300, res->d_records);
5929 addRRSIG(keys, res->d_records, domain, 300);
5930 return 1;
5931 }
5932 else {
5933 if (isRootServer(ip)) {
5934 setLWResult(res, 0, false, false, true);
5935 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5936 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5937 addDS(DNSName("com."), 300, res->d_records, keys);
5938 addRRSIG(keys, res->d_records, DNSName("."), 300);
5939 return 1;
5940 }
5941 else if (ip == ComboAddress("192.0.2.1:53")) {
5942 if (domain == DNSName("com.")) {
5943 setLWResult(res, 0, true, false, true);
5944 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5945 addRRSIG(keys, res->d_records, domain, 300);
5946 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5947 addRRSIG(keys, res->d_records, domain, 300);
5948 }
5949 else {
5950 setLWResult(res, 0, false, false, true);
5951 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5952 /* no DS */
5953 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5954 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5955 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5956 }
5957 return 1;
5958 }
5959 else if (ip == ComboAddress("192.0.2.2:53")) {
5960 if (type == QType::NS) {
5961 if (domain == DNSName("powerdns.com.")) {
5962 setLWResult(res, RCode::Refused, false, false, true);
5963 }
5964 else {
5965 setLWResult(res, 0, true, false, true);
5966 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5967 addRRSIG(keys, res->d_records, domain, 300);
5968 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5969 addRRSIG(keys, res->d_records, domain, 300);
5970 }
5971 }
5972 else {
5973 setLWResult(res, 0, true, false, true);
5974 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5975 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
5976 }
5977
5978 return 1;
5979 }
5980 }
5981
5982 return 0;
5983 });
5984
5985 vector<DNSRecord> ret;
5986 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5987 BOOST_CHECK_EQUAL(res, RCode::NoError);
5988 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5989 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5990 BOOST_CHECK_EQUAL(queriesCount, 9);
5991
5992 /* again, to test the cache */
5993 ret.clear();
5994 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5995 BOOST_CHECK_EQUAL(res, RCode::NoError);
5996 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5997 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5998 BOOST_CHECK_EQUAL(queriesCount, 9);
5999 }
6000
6001 BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) {
6002 /* check that we don't accept a signer below us */
6003 std::unique_ptr<SyncRes> sr;
6004 initSR(sr, true);
6005
6006 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6007
6008 primeHints();
6009 const DNSName target("www.powerdns.com.");
6010 testkeysset_t keys;
6011
6012 auto luaconfsCopy = g_luaconfs.getCopy();
6013 luaconfsCopy.dsAnchors.clear();
6014 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6015 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6016 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6017 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6018 generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6019
6020 g_luaconfs.setState(luaconfsCopy);
6021
6022 size_t queriesCount = 0;
6023
6024 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6025 queriesCount++;
6026
6027 if (type == QType::DS) {
6028 DNSName auth(domain);
6029 auth.chopOff();
6030
6031 setLWResult(res, 0, true, false, true);
6032 if (domain == target) {
6033 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6034 addRRSIG(keys, res->d_records, target, 300);
6035 }
6036 else {
6037 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6038 addRRSIG(keys, res->d_records, auth, 300);
6039 }
6040 return 1;
6041 }
6042 else if (type == QType::DNSKEY) {
6043 setLWResult(res, 0, true, false, true);
6044 addDNSKEY(keys, domain, 300, res->d_records);
6045 if (domain == DNSName("www.powerdns.com.")) {
6046 addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
6047 }
6048 else {
6049 addRRSIG(keys, res->d_records, domain, 300);
6050 }
6051 return 1;
6052 }
6053 else {
6054 if (isRootServer(ip)) {
6055 setLWResult(res, 0, false, false, true);
6056 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6057 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6058 addDS(DNSName("com."), 300, res->d_records, keys);
6059 addRRSIG(keys, res->d_records, DNSName("."), 300);
6060 return 1;
6061 }
6062 else if (ip == ComboAddress("192.0.2.1:53")) {
6063 if (domain == DNSName("com.")) {
6064 setLWResult(res, 0, true, false, true);
6065 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6066 addRRSIG(keys, res->d_records, domain, 300);
6067 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6068 addRRSIG(keys, res->d_records, domain, 300);
6069 }
6070 else {
6071 setLWResult(res, 0, false, false, true);
6072 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6073 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6074 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6075 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6076 }
6077 return 1;
6078 }
6079 else if (ip == ComboAddress("192.0.2.2:53")) {
6080 if (type == QType::NS) {
6081 setLWResult(res, 0, true, false, true);
6082 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6083 addRRSIG(keys, res->d_records, domain, 300);
6084 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6085 addRRSIG(keys, res->d_records, domain, 300);
6086 }
6087 else {
6088 setLWResult(res, 0, true, false, true);
6089 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6090 addRRSIG(keys, res->d_records, domain, 300);
6091 }
6092
6093 return 1;
6094 }
6095 }
6096
6097 return 0;
6098 });
6099
6100 vector<DNSRecord> ret;
6101 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6102 BOOST_CHECK_EQUAL(res, RCode::NoError);
6103 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6104 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6105 BOOST_CHECK_EQUAL(queriesCount, 9);
6106
6107 /* again, to test the cache */
6108 ret.clear();
6109 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6110 BOOST_CHECK_EQUAL(res, RCode::NoError);
6111 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6112 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6113 BOOST_CHECK_EQUAL(queriesCount, 9);
6114 }
6115
6116 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
6117 std::unique_ptr<SyncRes> sr;
6118 initSR(sr, true);
6119
6120 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6121
6122 primeHints();
6123 const DNSName target("www.powerdns.com.");
6124 testkeysset_t keys;
6125
6126 auto luaconfsCopy = g_luaconfs.getCopy();
6127 luaconfsCopy.dsAnchors.clear();
6128 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6129 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6130
6131 g_luaconfs.setState(luaconfsCopy);
6132
6133 size_t queriesCount = 0;
6134 size_t dsQueriesCount = 0;
6135
6136 sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6137 queriesCount++;
6138
6139 if (type == QType::DS) {
6140 DNSName auth(domain);
6141 auth.chopOff();
6142 dsQueriesCount++;
6143
6144 setLWResult(res, 0, true, false, true);
6145 if (domain == DNSName("com.")) {
6146 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6147 }
6148 else {
6149 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6150 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6151 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
6152 }
6153 addRRSIG(keys, res->d_records, auth, 300);
6154 return 1;
6155 }
6156 else if (type == QType::DNSKEY) {
6157 setLWResult(res, 0, true, false, true);
6158 addDNSKEY(keys, domain, 300, res->d_records);
6159 addRRSIG(keys, res->d_records, domain, 300);
6160 return 1;
6161 }
6162 else {
6163 if (isRootServer(ip)) {
6164 setLWResult(res, 0, false, false, true);
6165 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6166 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6167 /* No DS on referral, and no denial of the DS either */
6168 return 1;
6169 }
6170 else if (ip == ComboAddress("192.0.2.1:53")) {
6171 if (domain == DNSName("com.")) {
6172 setLWResult(res, 0, true, false, true);
6173 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6174 addRRSIG(keys, res->d_records, domain, 300);
6175 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6176 addRRSIG(keys, res->d_records, domain, 300);
6177 }
6178 else {
6179 setLWResult(res, 0, false, false, true);
6180 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6181 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6182 /* No DS on referral, and no denial of the DS either */
6183 }
6184 return 1;
6185 }
6186 else if (ip == ComboAddress("192.0.2.2:53")) {
6187 setLWResult(res, 0, true, false, true);
6188 if (type == QType::NS) {
6189 if (domain == DNSName("powerdns.com.")) {
6190 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6191 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6192 }
6193 else {
6194 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6195 }
6196 }
6197 else {
6198 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6199 }
6200 return 1;
6201 }
6202 }
6203
6204 return 0;
6205 });
6206
6207 vector<DNSRecord> ret;
6208 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6209 BOOST_CHECK_EQUAL(res, RCode::NoError);
6210 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6211 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6212 BOOST_CHECK_EQUAL(queriesCount, 7);
6213 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6214
6215 /* again, to test the cache */
6216 ret.clear();
6217 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6218 BOOST_CHECK_EQUAL(res, RCode::NoError);
6219 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6220 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6221 BOOST_CHECK_EQUAL(queriesCount, 7);
6222 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6223 }
6224
6225 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
6226 std::unique_ptr<SyncRes> sr;
6227 initSR(sr, true);
6228
6229 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6230
6231 primeHints();
6232 const DNSName target("powerdns.com.");
6233 testkeysset_t keys;
6234
6235 auto luaconfsCopy = g_luaconfs.getCopy();
6236 luaconfsCopy.dsAnchors.clear();
6237 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6238 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6239 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6240
6241 g_luaconfs.setState(luaconfsCopy);
6242
6243 size_t queriesCount = 0;
6244
6245 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6246 queriesCount++;
6247
6248 if (type == QType::DS || type == QType::DNSKEY) {
6249 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6250 }
6251 else {
6252 if (isRootServer(ip)) {
6253 setLWResult(res, 0, false, false, true);
6254 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6255 addDS(DNSName("com."), 300, res->d_records, keys);
6256 addRRSIG(keys, res->d_records, DNSName("."), 300);
6257 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6258 return 1;
6259 }
6260 else if (ip == ComboAddress("192.0.2.1:53")) {
6261 if (domain == DNSName("com.")) {
6262 setLWResult(res, 0, true, false, true);
6263 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6264 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6265 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6266 }
6267 else {
6268 setLWResult(res, 0, false, false, true);
6269 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6270 addDS(domain, 300, res->d_records, keys);
6271 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6272 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6273 }
6274 return 1;
6275 }
6276 else if (ip == ComboAddress("192.0.2.2:53")) {
6277 setLWResult(res, 0, true, false, true);
6278 if (type == QType::NS) {
6279 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6280 addRRSIG(keys, res->d_records, domain, 300);
6281 }
6282 else {
6283 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6284 addRRSIG(keys, res->d_records, domain, 300);
6285 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
6286 /* NO RRSIG for the NSEC record! */
6287 }
6288 return 1;
6289 }
6290 }
6291
6292 return 0;
6293 });
6294
6295 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
6296 vector<DNSRecord> ret;
6297 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6298 BOOST_CHECK_EQUAL(res, RCode::NoError);
6299 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6300 BOOST_CHECK_EQUAL(ret.size(), 3);
6301 BOOST_CHECK_EQUAL(queriesCount, 8);
6302
6303 /* again, to test the cache */
6304 ret.clear();
6305 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6306 BOOST_CHECK_EQUAL(res, RCode::NoError);
6307 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6308 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6309 BOOST_CHECK_EQUAL(queriesCount, 8);
6310 }
6311
6312 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
6313 std::unique_ptr<SyncRes> sr;
6314 initSR(sr, true);
6315
6316 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6317
6318 primeHints();
6319 const DNSName target("powerdns.com.");
6320 testkeysset_t keys;
6321
6322 auto luaconfsCopy = g_luaconfs.getCopy();
6323 luaconfsCopy.dsAnchors.clear();
6324 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6325 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6326 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6327
6328 g_luaconfs.setState(luaconfsCopy);
6329
6330 size_t queriesCount = 0;
6331
6332 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6333 queriesCount++;
6334
6335 if (type == QType::DS || type == QType::DNSKEY) {
6336 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6337 }
6338 else {
6339 if (isRootServer(ip)) {
6340 setLWResult(res, 0, false, false, true);
6341 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6342 addDS(DNSName("com."), 300, res->d_records, keys);
6343 addRRSIG(keys, res->d_records, DNSName("."), 300);
6344 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6345 return 1;
6346 }
6347 else if (ip == ComboAddress("192.0.2.1:53")) {
6348 if (domain == DNSName("com.")) {
6349 setLWResult(res, 0, true, false, true);
6350 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6351 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6352 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6353 }
6354 else {
6355 setLWResult(res, 0, false, false, true);
6356 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6357 addDS(domain, 300, res->d_records, keys);
6358 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6359 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6360 }
6361 return 1;
6362 }
6363 else if (ip == ComboAddress("192.0.2.2:53")) {
6364 setLWResult(res, 0, true, false, true);
6365 if (type == QType::NS) {
6366 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6367 addRRSIG(keys, res->d_records, domain, 300);
6368 }
6369 else {
6370 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6371 addRRSIG(keys, res->d_records, domain, 300);
6372
6373 /* NO NSEC record! */
6374 }
6375 return 1;
6376 }
6377 }
6378
6379 return 0;
6380 });
6381
6382 /* no NSEC record in a secure zone, should be Bogus! */
6383 vector<DNSRecord> ret;
6384 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6385 BOOST_CHECK_EQUAL(res, RCode::NoError);
6386 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6387 BOOST_CHECK_EQUAL(ret.size(), 2);
6388 BOOST_CHECK_EQUAL(queriesCount, 8);
6389
6390 /* again, to test the cache */
6391 ret.clear();
6392 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6393 BOOST_CHECK_EQUAL(res, RCode::NoError);
6394 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6395 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6396 BOOST_CHECK_EQUAL(queriesCount, 8);
6397 }
6398
6399 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6400 std::unique_ptr<SyncRes> sr;
6401 initSR(sr, true);
6402
6403 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6404
6405 primeHints();
6406 const DNSName target("powerdns.com.");
6407 const ComboAddress targetAddr("192.0.2.42");
6408 testkeysset_t keys;
6409
6410 auto luaconfsCopy = g_luaconfs.getCopy();
6411 luaconfsCopy.dsAnchors.clear();
6412 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6413 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6414
6415 g_luaconfs.setState(luaconfsCopy);
6416
6417 size_t queriesCount = 0;
6418
6419 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6420 queriesCount++;
6421
6422 if (type == QType::DS) {
6423 if (domain == target) {
6424 setLWResult(res, 0, false, false, true);
6425 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6426 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6427 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6428 return 1;
6429 } else {
6430 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6431 }
6432 }
6433 else if (type == QType::DNSKEY) {
6434 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6435 setLWResult(res, 0, true, false, true);
6436 addDNSKEY(keys, domain, 300, res->d_records);
6437 addRRSIG(keys, res->d_records, domain, 300);
6438 return 1;
6439 }
6440 else {
6441 setLWResult(res, 0, false, false, true);
6442 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6443 return 1;
6444 }
6445 }
6446 else {
6447 if (isRootServer(ip)) {
6448 setLWResult(res, 0, false, false, true);
6449 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6450 addDS(DNSName("com."), 300, res->d_records, keys);
6451 addRRSIG(keys, res->d_records, DNSName("."), 300);
6452 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6453 return 1;
6454 }
6455 else if (ip == ComboAddress("192.0.2.1:53")) {
6456 if (domain == DNSName("com.")) {
6457 setLWResult(res, 0, true, false, true);
6458 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6459 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6460 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6461 }
6462 else {
6463 setLWResult(res, 0, false, false, true);
6464 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6465 /* no DS */
6466 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6467 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6468 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6469 }
6470 return 1;
6471 }
6472 else if (ip == ComboAddress("192.0.2.2:53")) {
6473 setLWResult(res, 0, true, false, true);
6474 if (type == QType::NS) {
6475 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6476 }
6477 else {
6478 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6479 }
6480 return 1;
6481 }
6482 }
6483
6484 return 0;
6485 });
6486
6487 vector<DNSRecord> ret;
6488 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6489 BOOST_CHECK_EQUAL(res, RCode::NoError);
6490 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6491 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6492 BOOST_CHECK(ret[0].d_type == QType::A);
6493 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6494 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6495 1 query for A */
6496 BOOST_CHECK_EQUAL(queriesCount, 7);
6497
6498 /* again, to test the cache */
6499 ret.clear();
6500 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6501 BOOST_CHECK_EQUAL(res, RCode::NoError);
6502 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6503 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6504 BOOST_CHECK(ret[0].d_type == QType::A);
6505 BOOST_CHECK_EQUAL(queriesCount, 7);
6506 }
6507
6508
6509 BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6510 /*
6511 Direct DS query:
6512 - parent is secure, zone is secure: DS should be secure
6513 */
6514 std::unique_ptr<SyncRes> sr;
6515 initSR(sr, true);
6516
6517 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6518
6519 primeHints();
6520 const DNSName target("powerdns.com.");
6521 testkeysset_t keys;
6522
6523 auto luaconfsCopy = g_luaconfs.getCopy();
6524 luaconfsCopy.dsAnchors.clear();
6525 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6526 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6527 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6528
6529 g_luaconfs.setState(luaconfsCopy);
6530
6531 size_t queriesCount = 0;
6532
6533 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6534 queriesCount++;
6535
6536 if (type == QType::DS || type == QType::DNSKEY) {
6537 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6538 }
6539 else {
6540 if (isRootServer(ip)) {
6541 setLWResult(res, 0, false, false, true);
6542 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6543 addDS(DNSName("com."), 300, res->d_records, keys);
6544 addRRSIG(keys, res->d_records, DNSName("."), 300);
6545 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6546 return 1;
6547 }
6548 }
6549
6550 return 0;
6551 });
6552
6553 vector<DNSRecord> ret;
6554 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6555 BOOST_CHECK_EQUAL(res, RCode::NoError);
6556 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6557 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6558 for (const auto& record : ret) {
6559 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6560 }
6561 BOOST_CHECK_EQUAL(queriesCount, 4);
6562
6563 /* again, to test the cache */
6564 ret.clear();
6565 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6566 BOOST_CHECK_EQUAL(res, RCode::NoError);
6567 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6568 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6569 for (const auto& record : ret) {
6570 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6571 }
6572 BOOST_CHECK_EQUAL(queriesCount, 4);
6573 }
6574
6575 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6576 /*
6577 Direct DS query:
6578 - parent is secure, zone is insecure: DS denial should be secure
6579 */
6580 std::unique_ptr<SyncRes> sr;
6581 initSR(sr, true);
6582
6583 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6584
6585 primeHints();
6586 const DNSName target("powerdns.com.");
6587 testkeysset_t keys;
6588
6589 auto luaconfsCopy = g_luaconfs.getCopy();
6590 luaconfsCopy.dsAnchors.clear();
6591 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6592 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6593
6594 g_luaconfs.setState(luaconfsCopy);
6595
6596 size_t queriesCount = 0;
6597
6598 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6599 queriesCount++;
6600
6601 if (type == QType::DS || type == QType::DNSKEY) {
6602 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6603 }
6604 else {
6605 if (isRootServer(ip)) {
6606 setLWResult(res, 0, false, false, true);
6607 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6608 addDS(DNSName("com."), 300, res->d_records, keys);
6609 addRRSIG(keys, res->d_records, DNSName("."), 300);
6610 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6611 return 1;
6612 }
6613 }
6614
6615 return 0;
6616 });
6617
6618 vector<DNSRecord> ret;
6619 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6620 BOOST_CHECK_EQUAL(res, RCode::NoError);
6621 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6622 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6623 for (const auto& record : ret) {
6624 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6625 }
6626 BOOST_CHECK_EQUAL(queriesCount, 4);
6627
6628 /* again, to test the cache */
6629 ret.clear();
6630 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6631 BOOST_CHECK_EQUAL(res, RCode::NoError);
6632 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6633 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6634 for (const auto& record : ret) {
6635 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6636 }
6637 BOOST_CHECK_EQUAL(queriesCount, 4);
6638 }
6639
6640 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6641 std::unique_ptr<SyncRes> sr;
6642 initSR(sr, true);
6643
6644 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6645
6646 primeHints();
6647 const DNSName target("www.sub.powerdns.com.");
6648 const ComboAddress targetAddr("192.0.2.42");
6649 testkeysset_t keys;
6650
6651 auto luaconfsCopy = g_luaconfs.getCopy();
6652 luaconfsCopy.dsAnchors.clear();
6653 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6654 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6655 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6656
6657 g_luaconfs.setState(luaconfsCopy);
6658
6659 size_t queriesCount = 0;
6660
6661 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6662 queriesCount++;
6663
6664 if (type == QType::DS) {
6665 if (domain == DNSName("sub.powerdns.com.")) {
6666 setLWResult(res, 0, false, false, true);
6667 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6668 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6669 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6670 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6671 return 1;
6672 }
6673 else if (domain == DNSName("www.sub.powerdns.com.")) {
6674 setLWResult(res, 0, false, false, true);
6675 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);
6676 return 1;
6677 }
6678 else {
6679 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6680 }
6681 }
6682 else if (type == QType::DNSKEY) {
6683 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6684 setLWResult(res, 0, true, false, true);
6685 addDNSKEY(keys, domain, 300, res->d_records);
6686 addRRSIG(keys, res->d_records, domain, 300);
6687 return 1;
6688 }
6689 else {
6690 setLWResult(res, 0, false, false, true);
6691 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6692 return 1;
6693 }
6694 }
6695 else {
6696 if (isRootServer(ip)) {
6697 setLWResult(res, 0, false, false, true);
6698 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6699 addDS(DNSName("com."), 300, res->d_records, keys);
6700 addRRSIG(keys, res->d_records, DNSName("."), 300);
6701 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6702 return 1;
6703 }
6704 else if (ip == ComboAddress("192.0.2.1:53")) {
6705 if (domain == DNSName("com.")) {
6706 setLWResult(res, 0, true, false, true);
6707 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6708 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6709 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6710 }
6711 else {
6712 setLWResult(res, 0, false, false, true);
6713 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6714 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6715 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6716 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6717 }
6718 return 1;
6719 }
6720 else if (ip == ComboAddress("192.0.2.2:53")) {
6721 setLWResult(res, 0, true, false, true);
6722 if (type == QType::NS) {
6723 if (domain == DNSName("www.sub.powerdns.com.")) {
6724 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);
6725 }
6726 else if (domain == DNSName("sub.powerdns.com.")) {
6727 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6728 }
6729 else if (domain == DNSName("powerdns.com.")) {
6730 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6731 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6732 }
6733 } else {
6734 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6735 }
6736 return 1;
6737 }
6738 }
6739
6740 return 0;
6741 });
6742
6743 vector<DNSRecord> ret;
6744 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6745 BOOST_CHECK_EQUAL(res, RCode::NoError);
6746 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6747 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6748 BOOST_CHECK(ret[0].d_type == QType::A);
6749 BOOST_CHECK_EQUAL(queriesCount, 9);
6750
6751 /* again, to test the cache */
6752 ret.clear();
6753 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6754 BOOST_CHECK_EQUAL(res, RCode::NoError);
6755 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6756 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6757 BOOST_CHECK(ret[0].d_type == QType::A);
6758 BOOST_CHECK_EQUAL(queriesCount, 9);
6759 }
6760
6761 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6762 std::unique_ptr<SyncRes> sr;
6763 initSR(sr, true);
6764
6765 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6766
6767 primeHints();
6768 const DNSName target("www.sub.powerdns.com.");
6769 const ComboAddress targetAddr("192.0.2.42");
6770 testkeysset_t keys;
6771
6772 auto luaconfsCopy = g_luaconfs.getCopy();
6773 luaconfsCopy.dsAnchors.clear();
6774 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6775 /* No key material for .com */
6776 /* But TA for sub.powerdns.com. */
6777 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6778 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6779 g_luaconfs.setState(luaconfsCopy);
6780
6781 size_t queriesCount = 0;
6782
6783 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6784 queriesCount++;
6785
6786 if (type == QType::DS) {
6787 if (domain == DNSName("www.sub.powerdns.com")) {
6788 setLWResult(res, 0, false, false, true);
6789 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);
6790 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6791 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6792 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6793 }
6794 else {
6795 setLWResult(res, 0, false, false, true);
6796
6797 if (domain == DNSName("com.")) {
6798 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6799 /* no DS */
6800 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6801 addRRSIG(keys, res->d_records, DNSName("."), 300);
6802 }
6803 else {
6804 setLWResult(res, 0, false, false, true);
6805 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6806 }
6807 }
6808 return 1;
6809 }
6810 else if (type == QType::DNSKEY) {
6811 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
6812 setLWResult(res, 0, true, false, true);
6813 addDNSKEY(keys, domain, 300, res->d_records);
6814 addRRSIG(keys, res->d_records, domain, 300);
6815 return 1;
6816 }
6817 }
6818 else {
6819 if (isRootServer(ip)) {
6820 setLWResult(res, 0, false, false, true);
6821 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6822 /* no DS */
6823 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6824 addRRSIG(keys, res->d_records, DNSName("."), 300);
6825 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6826 return 1;
6827 }
6828 else if (ip == ComboAddress("192.0.2.1:53")) {
6829 if (domain == DNSName("com.")) {
6830 setLWResult(res, 0, true, false, true);
6831 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6832 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6833 }
6834 else if (domain.isPartOf(DNSName("powerdns.com."))) {
6835 setLWResult(res, 0, false, false, true);
6836 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6837 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6838 }
6839 return 1;
6840 }
6841 else if (ip == ComboAddress("192.0.2.2:53")) {
6842 setLWResult(res, 0, true, false, true);
6843 if (type == QType::NS) {
6844 if (domain == DNSName("www.sub.powerdns.com.")) {
6845 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);
6846 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6847 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6848 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6849 }
6850 else if (domain == DNSName("sub.powerdns.com.")) {
6851 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6852 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6853 }
6854 else if (domain == DNSName("powerdns.com.")) {
6855 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6856 }
6857 }
6858 else if (domain == DNSName("www.sub.powerdns.com.")) {
6859 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6860 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6861 }
6862 return 1;
6863 }
6864 }
6865
6866 return 0;
6867 });
6868
6869 vector<DNSRecord> ret;
6870 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6871 BOOST_CHECK_EQUAL(res, RCode::NoError);
6872 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6873 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6874 BOOST_CHECK(ret[0].d_type == QType::A);
6875 BOOST_CHECK_EQUAL(queriesCount, 7);
6876
6877 /* again, to test the cache */
6878 ret.clear();
6879 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6880 BOOST_CHECK_EQUAL(res, RCode::NoError);
6881 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6882 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6883 BOOST_CHECK(ret[0].d_type == QType::A);
6884 BOOST_CHECK_EQUAL(queriesCount, 7);
6885 }
6886
6887 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
6888 std::unique_ptr<SyncRes> sr;
6889 initSR(sr, true);
6890
6891 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6892
6893 primeHints();
6894 const DNSName target("powerdns.com.");
6895 testkeysset_t keys;
6896
6897 auto luaconfsCopy = g_luaconfs.getCopy();
6898 luaconfsCopy.dsAnchors.clear();
6899 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6900 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6901
6902 g_luaconfs.setState(luaconfsCopy);
6903
6904 size_t queriesCount = 0;
6905
6906 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6907 queriesCount++;
6908
6909 if (type == QType::DS) {
6910 if (domain == target) {
6911 setLWResult(res, 0, false, false, true);
6912 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6913 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6914 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6915 return 1;
6916 }
6917 else {
6918 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6919 }
6920 }
6921 else if (type == QType::DNSKEY) {
6922 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6923 setLWResult(res, 0, true, false, true);
6924 addDNSKEY(keys, domain, 300, res->d_records);
6925 addRRSIG(keys, res->d_records, domain, 300);
6926 return 1;
6927 }
6928 else {
6929 setLWResult(res, 0, false, false, true);
6930 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6931 return 1;
6932 }
6933 }
6934 else {
6935 if (isRootServer(ip)) {
6936 setLWResult(res, 0, false, false, true);
6937 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6938 addDS(DNSName("com."), 300, res->d_records, keys);
6939 addRRSIG(keys, res->d_records, DNSName("."), 300);
6940 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6941 return 1;
6942 }
6943 else if (ip == ComboAddress("192.0.2.1:53")) {
6944 if (domain == DNSName("com.")) {
6945 setLWResult(res, 0, true, false, true);
6946 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6947 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6948 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6949 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6950 }
6951 else {
6952 setLWResult(res, 0, false, false, true);
6953 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6954 /* no DS */
6955 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6956 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6957 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6958 }
6959 return 1;
6960 }
6961 else if (ip == ComboAddress("192.0.2.2:53")) {
6962 if (type == QType::NS) {
6963 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6964 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6965 }
6966 else {
6967 setLWResult(res, 0, true, false, true);
6968 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6969 }
6970 return 1;
6971 }
6972 }
6973
6974 return 0;
6975 });
6976
6977 vector<DNSRecord> ret;
6978 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6979 BOOST_CHECK_EQUAL(res, RCode::NoError);
6980 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6981 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6982 /* 4 NS (com from root, com from com, powerdns.com from com,
6983 powerdns.com from powerdns.com)
6984 2 DNSKEY (. and com., none for powerdns.com because no DS)
6985 1 query for A
6986 */
6987 BOOST_CHECK_EQUAL(queriesCount, 7);
6988
6989 /* again, to test the cache */
6990 ret.clear();
6991 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6992 BOOST_CHECK_EQUAL(res, RCode::NoError);
6993 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6994 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6995 BOOST_CHECK_EQUAL(queriesCount, 7);
6996 }
6997
6998 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
6999 std::unique_ptr<SyncRes> sr;
7000 initSR(sr, true);
7001
7002 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7003
7004 primeHints();
7005 const DNSName target("powerdns.com.");
7006 const DNSName targetCName("power-dns.com.");
7007 const ComboAddress targetCNameAddr("192.0.2.42");
7008 testkeysset_t keys;
7009
7010 auto luaconfsCopy = g_luaconfs.getCopy();
7011 luaconfsCopy.dsAnchors.clear();
7012 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7013 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7014 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7015 g_luaconfs.setState(luaconfsCopy);
7016
7017 size_t queriesCount = 0;
7018
7019 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7020 queriesCount++;
7021
7022 if (type == QType::DS) {
7023 if (domain == targetCName) {
7024 setLWResult(res, 0, false, false, true);
7025 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7026 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7027 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7028 return 1;
7029 }
7030 else {
7031 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7032 }
7033 }
7034 else if (type == QType::DNSKEY) {
7035 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7036 setLWResult(res, 0, true, false, true);
7037 addDNSKEY(keys, domain, 300, res->d_records);
7038 addRRSIG(keys, res->d_records, domain, 300);
7039 return 1;
7040 }
7041 else {
7042 setLWResult(res, 0, false, false, true);
7043 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7044 return 1;
7045 }
7046 }
7047 else {
7048 if (isRootServer(ip)) {
7049 setLWResult(res, 0, false, false, true);
7050 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7051 addDS(DNSName("com."), 300, res->d_records, keys);
7052 addRRSIG(keys, res->d_records, DNSName("."), 300);
7053 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7054 return 1;
7055 }
7056 else if (ip == ComboAddress("192.0.2.1:53")) {
7057 setLWResult(res, 0, false, false, true);
7058 if (domain == DNSName("com.")) {
7059 setLWResult(res, 0, true, false, true);
7060 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7061 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7062 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7063 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7064 }
7065 else {
7066 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7067 if (domain == DNSName("powerdns.com.")) {
7068 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7069 }
7070 else if (domain == targetCName) {
7071 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7072 }
7073 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7074 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7075 }
7076
7077 return 1;
7078 }
7079 else if (ip == ComboAddress("192.0.2.2:53")) {
7080 setLWResult(res, 0, true, false, true);
7081
7082 if (type == QType::NS) {
7083 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7084 if (domain == DNSName("powerdns.com.")) {
7085 addRRSIG(keys, res->d_records, domain, 300);
7086 }
7087 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7088 if (domain == DNSName("powerdns.com.")) {
7089 addRRSIG(keys, res->d_records, domain, 300);
7090 }
7091 }
7092 else {
7093 if (domain == DNSName("powerdns.com.")) {
7094 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7095 addRRSIG(keys, res->d_records, domain, 300);
7096 }
7097 else if (domain == targetCName) {
7098 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7099 }
7100 }
7101
7102 return 1;
7103 }
7104 }
7105
7106 return 0;
7107 });
7108
7109 vector<DNSRecord> ret;
7110 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7111 BOOST_CHECK_EQUAL(res, RCode::NoError);
7112 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7113 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7114 BOOST_CHECK_EQUAL(queriesCount, 11);
7115
7116 /* again, to test the cache */
7117 ret.clear();
7118 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7119 BOOST_CHECK_EQUAL(res, RCode::NoError);
7120 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7121 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7122 BOOST_CHECK_EQUAL(queriesCount, 11);
7123 }
7124
7125 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname_glue) {
7126 std::unique_ptr<SyncRes> sr;
7127 initSR(sr, true);
7128
7129 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7130
7131 primeHints();
7132 const DNSName target("powerdns.com.");
7133 const DNSName targetCName1("cname.sub.powerdns.com.");
7134 const DNSName targetCName2("cname2.sub.powerdns.com.");
7135 const ComboAddress targetCName2Addr("192.0.2.42");
7136 testkeysset_t keys;
7137
7138 auto luaconfsCopy = g_luaconfs.getCopy();
7139 luaconfsCopy.dsAnchors.clear();
7140 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7141 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7142 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7143 g_luaconfs.setState(luaconfsCopy);
7144
7145 size_t queriesCount = 0;
7146
7147 sr->setAsyncCallback([target,targetCName1,targetCName2,targetCName2Addr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7148 queriesCount++;
7149
7150 if (type == QType::DS || type == QType::DNSKEY) {
7151 if (domain == DNSName("sub.powerdns.com")) {
7152 setLWResult(res, 0, false, false, true);
7153 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7154 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7155 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7156 return 1;
7157 }
7158 else {
7159 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7160 }
7161 }
7162 else {
7163 if (isRootServer(ip)) {
7164 setLWResult(res, 0, false, false, true);
7165 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7166 addDS(DNSName("com."), 300, res->d_records, keys);
7167 addRRSIG(keys, res->d_records, DNSName("."), 300);
7168 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7169 return 1;
7170 }
7171 else if (ip == ComboAddress("192.0.2.1:53")) {
7172 setLWResult(res, 0, false, false, true);
7173 if (domain == DNSName("com.")) {
7174 setLWResult(res, 0, true, false, true);
7175 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7176 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7177 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7178 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7179 }
7180 else {
7181 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7182 if (domain == DNSName("powerdns.com.")) {
7183 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7184 }
7185 else if (domain == DNSName("sub.powerdns.com")) {
7186 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7187 }
7188 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7189 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7190 }
7191
7192 return 1;
7193 }
7194 else if (ip == ComboAddress("192.0.2.2:53")) {
7195 setLWResult(res, 0, true, false, true);
7196
7197 if (type == QType::NS) {
7198 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7199 if (domain == DNSName("powerdns.com.")) {
7200 addRRSIG(keys, res->d_records, domain, 300);
7201 }
7202 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7203 if (domain == DNSName("powerdns.com.")) {
7204 addRRSIG(keys, res->d_records, domain, 300);
7205 }
7206 }
7207 else {
7208 if (domain == DNSName("powerdns.com.")) {
7209 addRecordToLW(res, domain, QType::CNAME, targetCName1.toString());
7210 addRRSIG(keys, res->d_records, domain, 300);
7211 /* add the CNAME target as a glue, with no RRSIG since the sub zone is insecure */
7212 addRecordToLW(res, targetCName1, QType::CNAME, targetCName2.toString());
7213 addRecordToLW(res, targetCName2, QType::A, targetCName2Addr.toString());
7214 }
7215 else if (domain == targetCName1) {
7216 addRecordToLW(res, domain, QType::CNAME, targetCName2.toString());
7217 }
7218 else if (domain == targetCName2) {
7219 addRecordToLW(res, domain, QType::A, targetCName2Addr.toString());
7220 }
7221 }
7222
7223 return 1;
7224 }
7225 }
7226
7227 return 0;
7228 });
7229
7230 vector<DNSRecord> ret;
7231 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7232 BOOST_CHECK_EQUAL(res, RCode::NoError);
7233 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7234 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7235 BOOST_CHECK_EQUAL(queriesCount, 11);
7236
7237 /* again, to test the cache */
7238 ret.clear();
7239 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7240 BOOST_CHECK_EQUAL(res, RCode::NoError);
7241 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7242 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7243 BOOST_CHECK_EQUAL(queriesCount, 11);
7244 }
7245
7246 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
7247 std::unique_ptr<SyncRes> sr;
7248 initSR(sr, true);
7249
7250 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7251
7252 primeHints();
7253 const DNSName target("power-dns.com.");
7254 const DNSName targetCName("powerdns.com.");
7255 const ComboAddress targetCNameAddr("192.0.2.42");
7256 testkeysset_t keys;
7257
7258 auto luaconfsCopy = g_luaconfs.getCopy();
7259 luaconfsCopy.dsAnchors.clear();
7260 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7261 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7262 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7263 g_luaconfs.setState(luaconfsCopy);
7264
7265 size_t queriesCount = 0;
7266
7267 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7268 queriesCount++;
7269
7270 if (type == QType::DS) {
7271 if (domain == DNSName("power-dns.com.")) {
7272 setLWResult(res, 0, false, false, true);
7273 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7274 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7275 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7276 return 1;
7277 }
7278 else {
7279 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7280 }
7281 }
7282 else if (type == QType::DNSKEY) {
7283 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7284 setLWResult(res, 0, true, false, true);
7285 addDNSKEY(keys, domain, 300, res->d_records);
7286 addRRSIG(keys, res->d_records, domain, 300);
7287 return 1;
7288 }
7289 else {
7290 setLWResult(res, 0, false, false, true);
7291 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7292 return 1;
7293 }
7294 }
7295 else {
7296 if (isRootServer(ip)) {
7297 setLWResult(res, 0, false, false, true);
7298 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7299 addDS(DNSName("com."), 300, res->d_records, keys);
7300 addRRSIG(keys, res->d_records, DNSName("."), 300);
7301 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7302 return 1;
7303 }
7304 else if (ip == ComboAddress("192.0.2.1:53")) {
7305 if (domain == DNSName("com.")) {
7306 setLWResult(res, 0, true, false, true);
7307 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7308 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7309 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7310 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7311 }
7312 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7313 setLWResult(res, 0, false, false, true);
7314 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7315 if (domain == targetCName) {
7316 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7317 }
7318 else if (domain == target) {
7319 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7320 }
7321 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7322 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7323 }
7324 return 1;
7325 }
7326 else if (ip == ComboAddress("192.0.2.2:53")) {
7327 setLWResult(res, 0, true, false, true);
7328 if (type == QType::NS) {
7329 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7330 if (domain == DNSName("powerdns.com.")) {
7331 addRRSIG(keys, res->d_records, domain, 300);
7332 }
7333 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7334 if (domain == DNSName("powerdns.com.")) {
7335 addRRSIG(keys, res->d_records, domain, 300);
7336 }
7337 }
7338 else {
7339 if (domain == target) {
7340 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7341 }
7342 else if (domain == targetCName) {
7343 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7344 addRRSIG(keys, res->d_records, domain, 300);
7345 }
7346 }
7347 return 1;
7348 }
7349 }
7350
7351 return 0;
7352 });
7353
7354 vector<DNSRecord> ret;
7355 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7356 BOOST_CHECK_EQUAL(res, RCode::NoError);
7357 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7358 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7359 BOOST_CHECK_EQUAL(queriesCount, 11);
7360
7361 /* again, to test the cache */
7362 ret.clear();
7363 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7364 BOOST_CHECK_EQUAL(res, RCode::NoError);
7365 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7366 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7367 BOOST_CHECK_EQUAL(queriesCount, 11);
7368 }
7369
7370 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
7371 std::unique_ptr<SyncRes> sr;
7372 initSR(sr, true);
7373
7374 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7375
7376 primeHints();
7377 const DNSName target("power-dns.com.");
7378 const DNSName targetCName("powerdns.com.");
7379 const ComboAddress targetCNameAddr("192.0.2.42");
7380 testkeysset_t keys;
7381
7382 auto luaconfsCopy = g_luaconfs.getCopy();
7383 luaconfsCopy.dsAnchors.clear();
7384 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7385 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7386 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7387 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7388 g_luaconfs.setState(luaconfsCopy);
7389
7390 size_t queriesCount = 0;
7391
7392 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7393 queriesCount++;
7394
7395 if (type == QType::DS || type == QType::DNSKEY) {
7396 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7397 }
7398 else {
7399 if (isRootServer(ip)) {
7400 setLWResult(res, 0, false, false, true);
7401 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7402 addDS(DNSName("com."), 300, res->d_records, keys);
7403 addRRSIG(keys, res->d_records, DNSName("."), 300);
7404 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7405 return 1;
7406 }
7407 else if (ip == ComboAddress("192.0.2.1:53")) {
7408 if (domain == DNSName("com.")) {
7409 setLWResult(res, 0, true, false, true);
7410 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7411 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7412 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7413 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7414 }
7415 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7416 setLWResult(res, 0, false, false, true);
7417 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7418 addDS(DNSName(domain), 300, res->d_records, keys);
7419 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7420 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7421 }
7422 return 1;
7423 }
7424 else if (ip == ComboAddress("192.0.2.2:53")) {
7425 setLWResult(res, 0, true, false, true);
7426 if (type == QType::NS) {
7427 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7428 addRRSIG(keys, res->d_records, domain, 300);
7429 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7430 addRRSIG(keys, res->d_records, domain, 300);
7431 }
7432 else {
7433 if (domain == target) {
7434 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7435 /* No RRSIG, leading to bogus */
7436 }
7437 else if (domain == targetCName) {
7438 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7439 addRRSIG(keys, res->d_records, domain, 300);
7440 }
7441 }
7442 return 1;
7443 }
7444 }
7445
7446 return 0;
7447 });
7448
7449 vector<DNSRecord> ret;
7450 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7451 BOOST_CHECK_EQUAL(res, RCode::NoError);
7452 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7453 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7454 BOOST_CHECK_EQUAL(queriesCount, 11);
7455
7456 /* again, to test the cache */
7457 ret.clear();
7458 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7459 BOOST_CHECK_EQUAL(res, RCode::NoError);
7460 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7461 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7462 BOOST_CHECK_EQUAL(queriesCount, 11);
7463 }
7464
7465 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7466 std::unique_ptr<SyncRes> sr;
7467 initSR(sr, true);
7468
7469 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7470
7471 primeHints();
7472 const DNSName target("power-dns.com.");
7473 const DNSName targetCName("powerdns.com.");
7474 const ComboAddress targetCNameAddr("192.0.2.42");
7475 testkeysset_t keys;
7476
7477 auto luaconfsCopy = g_luaconfs.getCopy();
7478 luaconfsCopy.dsAnchors.clear();
7479 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7480 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7481 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7482 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7483 g_luaconfs.setState(luaconfsCopy);
7484
7485 size_t queriesCount = 0;
7486
7487 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7488 queriesCount++;
7489
7490 if (type == QType::DS || type == QType::DNSKEY) {
7491 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7492 }
7493 else {
7494 if (isRootServer(ip)) {
7495 setLWResult(res, 0, false, false, true);
7496 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7497 addDS(DNSName("com."), 300, res->d_records, keys);
7498 addRRSIG(keys, res->d_records, DNSName("."), 300);
7499 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7500 return 1;
7501 }
7502 else if (ip == ComboAddress("192.0.2.1:53")) {
7503 if (domain == DNSName("com.")) {
7504 setLWResult(res, 0, true, false, true);
7505 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7506 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7507 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7508 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7509 }
7510 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7511 setLWResult(res, 0, false, false, true);
7512 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7513 addDS(DNSName(domain), 300, res->d_records, keys);
7514 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7515 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7516 }
7517 return 1;
7518 }
7519 else if (ip == ComboAddress("192.0.2.2:53")) {
7520 setLWResult(res, 0, true, false, true);
7521 if (type == QType::NS) {
7522 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7523 addRRSIG(keys, res->d_records, domain, 300);
7524 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7525 addRRSIG(keys, res->d_records, domain, 300);
7526 }
7527 else {
7528 if (domain == target) {
7529 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7530 addRRSIG(keys, res->d_records, domain, 300);
7531 }
7532 else if (domain == targetCName) {
7533 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7534 /* No RRSIG, leading to bogus */
7535 }
7536 }
7537 return 1;
7538 }
7539 }
7540
7541 return 0;
7542 });
7543
7544 vector<DNSRecord> ret;
7545 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7546 BOOST_CHECK_EQUAL(res, RCode::NoError);
7547 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7548 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7549 BOOST_CHECK_EQUAL(queriesCount, 11);
7550
7551 /* again, to test the cache */
7552 ret.clear();
7553 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7554 BOOST_CHECK_EQUAL(res, RCode::NoError);
7555 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7556 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7557 BOOST_CHECK_EQUAL(queriesCount, 11);
7558 }
7559
7560 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
7561 std::unique_ptr<SyncRes> sr;
7562 initSR(sr, true);
7563
7564 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7565
7566 primeHints();
7567 const DNSName target("power-dns.com.");
7568 const DNSName targetCName("powerdns.com.");
7569 const ComboAddress targetCNameAddr("192.0.2.42");
7570 testkeysset_t keys;
7571
7572 auto luaconfsCopy = g_luaconfs.getCopy();
7573 luaconfsCopy.dsAnchors.clear();
7574 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7575 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7576 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7577 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7578 g_luaconfs.setState(luaconfsCopy);
7579
7580 size_t queriesCount = 0;
7581
7582 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7583 queriesCount++;
7584
7585 if (type == QType::DS || type == QType::DNSKEY) {
7586 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7587 }
7588 else {
7589 if (isRootServer(ip)) {
7590 setLWResult(res, 0, false, false, true);
7591 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7592 addDS(DNSName("com."), 300, res->d_records, keys);
7593 addRRSIG(keys, res->d_records, DNSName("."), 300);
7594 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7595 return 1;
7596 }
7597 else if (ip == ComboAddress("192.0.2.1:53")) {
7598 if (domain == DNSName("com.")) {
7599 setLWResult(res, 0, true, false, true);
7600 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7601 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7602 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7603 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7604 }
7605 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7606 setLWResult(res, 0, false, false, true);
7607 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7608 addDS(DNSName(domain), 300, res->d_records, keys);
7609 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7610 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7611 }
7612 return 1;
7613 }
7614 else if (ip == ComboAddress("192.0.2.2:53")) {
7615 setLWResult(res, 0, true, false, true);
7616 if (type == QType::NS) {
7617 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7618 addRRSIG(keys, res->d_records, domain, 300);
7619 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7620 addRRSIG(keys, res->d_records, domain, 300);
7621 }
7622 else {
7623 if (domain == target) {
7624 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7625 addRRSIG(keys, res->d_records, domain, 300);
7626 }
7627 else if (domain == targetCName) {
7628 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7629 addRRSIG(keys, res->d_records, domain, 300);
7630 }
7631 }
7632 return 1;
7633 }
7634 }
7635
7636 return 0;
7637 });
7638
7639 vector<DNSRecord> ret;
7640 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7641 BOOST_CHECK_EQUAL(res, RCode::NoError);
7642 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7643 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7644 BOOST_CHECK_EQUAL(queriesCount, 12);
7645
7646 /* again, to test the cache */
7647 ret.clear();
7648 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7649 BOOST_CHECK_EQUAL(res, RCode::NoError);
7650 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7651 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7652 BOOST_CHECK_EQUAL(queriesCount, 12);
7653 }
7654
7655 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7656 std::unique_ptr<SyncRes> sr;
7657 initSR(sr, true);
7658
7659 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7660
7661 primeHints();
7662 const DNSName target("powerdns.com.");
7663 const DNSName targetCName("power-dns.com.");
7664 const ComboAddress targetCNameAddr("192.0.2.42");
7665 testkeysset_t keys;
7666
7667 auto luaconfsCopy = g_luaconfs.getCopy();
7668 luaconfsCopy.dsAnchors.clear();
7669 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7670 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7671 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7672 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7673 g_luaconfs.setState(luaconfsCopy);
7674
7675 size_t queriesCount = 0;
7676
7677 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7678 queriesCount++;
7679
7680 if (type == QType::DS) {
7681 if (domain == DNSName("power-dns.com.")) {
7682 setLWResult(res, 0, false, false, true);
7683 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7684 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7685 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7686 return 1;
7687 }
7688 else {
7689 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7690 }
7691 }
7692 else if (type == QType::DNSKEY) {
7693 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7694 setLWResult(res, 0, true, false, true);
7695 addDNSKEY(keys, domain, 300, res->d_records);
7696 addRRSIG(keys, res->d_records, domain, 300);
7697 return 1;
7698 }
7699 else {
7700 setLWResult(res, 0, false, false, true);
7701 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7702 return 1;
7703 }
7704 }
7705 else {
7706 if (isRootServer(ip)) {
7707 setLWResult(res, 0, false, false, true);
7708 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7709 addDS(DNSName("com."), 300, res->d_records, keys);
7710 addRRSIG(keys, res->d_records, DNSName("."), 300);
7711 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7712 return 1;
7713 }
7714 else if (ip == ComboAddress("192.0.2.1:53")) {
7715 if (domain == DNSName("com.")) {
7716 setLWResult(res, 0, true, false, true);
7717 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7718 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7719 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7720 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7721 }
7722 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7723 setLWResult(res, 0, false, false, true);
7724 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7725 if (domain == DNSName("powerdns.com.")) {
7726 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7727 }
7728 else if (domain == targetCName) {
7729 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7730 }
7731 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7732 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7733 }
7734 return 1;
7735 }
7736 else if (ip == ComboAddress("192.0.2.2:53")) {
7737 setLWResult(res, 0, true, false, true);
7738 if (type == QType::NS) {
7739 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7740 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7741 }
7742 else {
7743 if (domain == DNSName("powerdns.com.")) {
7744 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7745 /* No RRSIG -> Bogus */
7746 }
7747 else if (domain == targetCName) {
7748 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7749 }
7750 }
7751 return 1;
7752 }
7753 }
7754
7755 return 0;
7756 });
7757
7758 vector<DNSRecord> ret;
7759 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7760 BOOST_CHECK_EQUAL(res, RCode::NoError);
7761 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7762 /* no RRSIG to show */
7763 BOOST_CHECK_EQUAL(ret.size(), 2);
7764 BOOST_CHECK_EQUAL(queriesCount, 10);
7765
7766 /* again, to test the cache */
7767 ret.clear();
7768 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7769 BOOST_CHECK_EQUAL(res, RCode::NoError);
7770 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7771 BOOST_CHECK_EQUAL(ret.size(), 2);
7772 BOOST_CHECK_EQUAL(queriesCount, 10);
7773 }
7774
7775 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7776 std::unique_ptr<SyncRes> sr;
7777 initSR(sr, true);
7778
7779 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7780
7781 primeHints();
7782 const DNSName target("powerdns.com.");
7783 const ComboAddress targetAddr("192.0.2.42");
7784 testkeysset_t keys;
7785
7786 auto luaconfsCopy = g_luaconfs.getCopy();
7787 luaconfsCopy.dsAnchors.clear();
7788 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7789 /* No key material for .com */
7790 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7791 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7792 g_luaconfs.setState(luaconfsCopy);
7793
7794 size_t queriesCount = 0;
7795
7796 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7797 queriesCount++;
7798
7799 if (type == QType::DNSKEY) {
7800 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7801 setLWResult(res, 0, true, false, true);
7802 addDNSKEY(keys, domain, 300, res->d_records);
7803 addRRSIG(keys, res->d_records, domain, 300);
7804 return 1;
7805 }
7806 else if (domain == DNSName("com.")) {
7807 setLWResult(res, 0, false, false, true);
7808 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7809 return 1;
7810 }
7811 }
7812 else {
7813 if (isRootServer(ip)) {
7814 setLWResult(res, 0, false, false, true);
7815 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7816 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7817 addRRSIG(keys, res->d_records, DNSName("."), 300);
7818 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7819 return 1;
7820 }
7821 else if (ip == ComboAddress("192.0.2.1:53")) {
7822 if (target == domain) {
7823 setLWResult(res, 0, false, false, true);
7824 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7825 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7826 }
7827 else if (domain == DNSName("com.")) {
7828 setLWResult(res, 0, true, false, true);
7829 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7830 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7831 }
7832 return 1;
7833 }
7834 else if (ip == ComboAddress("192.0.2.2:53")) {
7835 setLWResult(res, 0, true, false, true);
7836 if (type == QType::NS) {
7837 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7838 }
7839 else {
7840 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7841 }
7842 addRRSIG(keys, res->d_records, domain, 300);
7843 return 1;
7844 }
7845 }
7846
7847 return 0;
7848 });
7849
7850 vector<DNSRecord> ret;
7851 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7852 BOOST_CHECK_EQUAL(res, RCode::NoError);
7853 /* should be insecure but we have a TA for powerdns.com. */
7854 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7855 /* We got a RRSIG */
7856 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7857 BOOST_CHECK(ret[0].d_type == QType::A);
7858 BOOST_CHECK_EQUAL(queriesCount, 5);
7859
7860 /* again, to test the cache */
7861 ret.clear();
7862 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7863 BOOST_CHECK_EQUAL(res, RCode::NoError);
7864 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7865 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7866 BOOST_CHECK(ret[0].d_type == QType::A);
7867 BOOST_CHECK_EQUAL(queriesCount, 5);
7868 }
7869
7870 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
7871 std::unique_ptr<SyncRes> sr;
7872 initSR(sr, true);
7873
7874 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7875
7876 primeHints();
7877 const DNSName target("powerdns.com.");
7878 const ComboAddress targetAddr("192.0.2.42");
7879 testkeysset_t keys;
7880
7881 auto luaconfsCopy = g_luaconfs.getCopy();
7882 luaconfsCopy.dsAnchors.clear();
7883 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7884 /* No key material for .com */
7885 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7886 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7887 g_luaconfs.setState(luaconfsCopy);
7888
7889 size_t queriesCount = 0;
7890
7891 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7892 queriesCount++;
7893
7894 if (type == QType::DNSKEY) {
7895 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7896 setLWResult(res, 0, true, false, true);
7897 addDNSKEY(keys, domain, 300, res->d_records);
7898 addRRSIG(keys, res->d_records, domain, 300);
7899 return 1;
7900 }
7901 else if (domain == DNSName("com.")) {
7902 setLWResult(res, 0, false, false, true);
7903 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7904 return 1;
7905 }
7906 }
7907 else {
7908 if (target.isPartOf(domain) && isRootServer(ip)) {
7909 setLWResult(res, 0, false, false, true);
7910 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7911 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7912 addRRSIG(keys, res->d_records, DNSName("."), 300);
7913 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7914 return 1;
7915 }
7916 else if (ip == ComboAddress("192.0.2.1:53")) {
7917 if (target == domain) {
7918 setLWResult(res, 0, false, false, true);
7919 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7920 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7921 }
7922 else if (domain == DNSName("com.")) {
7923 setLWResult(res, 0, true, false, true);
7924 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7925 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7926 }
7927 return 1;
7928 }
7929 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
7930 setLWResult(res, 0, true, false, true);
7931 if (type == QType::NS) {
7932 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7933 }
7934 else {
7935 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7936 }
7937 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
7938 return 1;
7939 }
7940 }
7941
7942 return 0;
7943 });
7944
7945 vector<DNSRecord> ret;
7946 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7947 BOOST_CHECK_EQUAL(res, RCode::NoError);
7948 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
7949 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7950 /* No RRSIG */
7951 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7952 BOOST_CHECK(ret[0].d_type == QType::A);
7953 BOOST_CHECK_EQUAL(queriesCount, 4);
7954
7955 /* again, to test the cache */
7956 ret.clear();
7957 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7958 BOOST_CHECK_EQUAL(res, RCode::NoError);
7959 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7960 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7961 BOOST_CHECK(ret[0].d_type == QType::A);
7962 BOOST_CHECK_EQUAL(queriesCount, 4);
7963 }
7964
7965 BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
7966 std::unique_ptr<SyncRes> sr;
7967 initSR(sr, true);
7968
7969 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7970
7971 primeHints();
7972 const DNSName target(".");
7973 testkeysset_t keys;
7974
7975 auto luaconfsCopy = g_luaconfs.getCopy();
7976 luaconfsCopy.dsAnchors.clear();
7977 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7978 /* Add a NTA for "." */
7979 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
7980 g_luaconfs.setState(luaconfsCopy);
7981
7982 size_t queriesCount = 0;
7983
7984 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7985 queriesCount++;
7986
7987 if (domain == target && type == QType::NS) {
7988
7989 setLWResult(res, 0, true, false, true);
7990 char addr[] = "a.root-servers.net.";
7991 for (char idx = 'a'; idx <= 'm'; idx++) {
7992 addr[0] = idx;
7993 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7994 }
7995
7996 addRRSIG(keys, res->d_records, domain, 300);
7997
7998 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7999 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8000
8001 return 1;
8002 } else if (domain == target && type == QType::DNSKEY) {
8003
8004 setLWResult(res, 0, true, false, true);
8005
8006 /* No DNSKEY */
8007
8008 return 1;
8009 }
8010
8011 return 0;
8012 });
8013
8014 vector<DNSRecord> ret;
8015 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8016 BOOST_CHECK_EQUAL(res, RCode::NoError);
8017 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8018 /* 13 NS + 1 RRSIG */
8019 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8020 BOOST_CHECK_EQUAL(queriesCount, 1);
8021
8022 /* again, to test the cache */
8023 ret.clear();
8024 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8025 BOOST_CHECK_EQUAL(res, RCode::NoError);
8026 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8027 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8028 BOOST_CHECK_EQUAL(queriesCount, 1);
8029 }
8030
8031 BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
8032 std::unique_ptr<SyncRes> sr;
8033 initSR(sr, true);
8034
8035 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8036
8037 primeHints();
8038 const DNSName target(".");
8039 testkeysset_t keys;
8040
8041 /* Remove the root DS */
8042 auto luaconfsCopy = g_luaconfs.getCopy();
8043 luaconfsCopy.dsAnchors.clear();
8044 g_luaconfs.setState(luaconfsCopy);
8045
8046 size_t queriesCount = 0;
8047
8048 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8049 queriesCount++;
8050
8051 if (domain == target && type == QType::NS) {
8052
8053 setLWResult(res, 0, true, false, true);
8054 char addr[] = "a.root-servers.net.";
8055 for (char idx = 'a'; idx <= 'm'; idx++) {
8056 addr[0] = idx;
8057 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8058 }
8059
8060 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8061 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8062
8063 return 1;
8064 }
8065
8066 return 0;
8067 });
8068
8069 vector<DNSRecord> ret;
8070 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8071 BOOST_CHECK_EQUAL(res, RCode::NoError);
8072 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8073 /* 13 NS + 0 RRSIG */
8074 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8075 BOOST_CHECK_EQUAL(queriesCount, 1);
8076
8077 /* again, to test the cache */
8078 ret.clear();
8079 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8080 BOOST_CHECK_EQUAL(res, RCode::NoError);
8081 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8082 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8083 BOOST_CHECK_EQUAL(queriesCount, 1);
8084 }
8085
8086 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
8087 std::unique_ptr<SyncRes> sr;
8088 initSR(sr, true);
8089
8090 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8091
8092 primeHints();
8093 const DNSName target("powerdns.com.");
8094 testkeysset_t keys;
8095
8096 auto luaconfsCopy = g_luaconfs.getCopy();
8097 luaconfsCopy.dsAnchors.clear();
8098 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8099 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8100 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8101 g_luaconfs.setState(luaconfsCopy);
8102
8103 size_t queriesCount = 0;
8104
8105 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8106 queriesCount++;
8107
8108 if (type == QType::DS || type == QType::DNSKEY) {
8109 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
8110 }
8111 else {
8112
8113 setLWResult(res, 0, true, false, true);
8114 return 1;
8115 }
8116
8117 return 0;
8118 });
8119
8120 vector<DNSRecord> ret;
8121 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8122 BOOST_CHECK_EQUAL(res, RCode::NoError);
8123 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8124 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8125 /* com|NS, powerdns.com|NS, powerdns.com|A */
8126 BOOST_CHECK_EQUAL(queriesCount, 3);
8127
8128 /* again, to test the cache */
8129 ret.clear();
8130 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8131 BOOST_CHECK_EQUAL(res, RCode::NoError);
8132 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8133 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8134 /* we don't store empty results */
8135 BOOST_CHECK_EQUAL(queriesCount, 4);
8136 }
8137
8138 BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
8139 init();
8140
8141 testkeysset_t keys;
8142 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8143
8144 vector<DNSRecord> records;
8145
8146 vector<shared_ptr<DNSRecordContent>> recordContents;
8147 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8148
8149 /*
8150 No wrap test case:
8151 a.example.org. -> d.example.org. denies the existence of b.example.org.
8152 */
8153 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8154 recordContents.push_back(records.at(0).d_content);
8155 addRRSIG(keys, records, DNSName("example.org."), 300);
8156 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8157 records.clear();
8158
8159 ContentSigPair pair;
8160 pair.records = recordContents;
8161 pair.signatures = signatureContents;
8162 cspmap_t denialMap;
8163 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8164
8165 /* add wildcard denial */
8166 recordContents.clear();
8167 signatureContents.clear();
8168 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8169 recordContents.push_back(records.at(0).d_content);
8170 addRRSIG(keys, records, DNSName("example.org."), 300);
8171 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8172 records.clear();
8173
8174 pair.records = recordContents;
8175 pair.signatures = signatureContents;
8176 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
8177
8178 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
8179 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8180
8181 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
8182 /* let's check that d.example.org. is not denied by this proof */
8183 BOOST_CHECK_EQUAL(denialState, NODATA);
8184 }
8185
8186 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
8187 init();
8188
8189 testkeysset_t keys;
8190 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8191
8192 vector<DNSRecord> records;
8193
8194 vector<shared_ptr<DNSRecordContent>> recordContents;
8195 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8196
8197 /*
8198 Wrap case 1 test case:
8199 z.example.org. -> b.example.org. denies the existence of a.example.org.
8200 */
8201 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8202 recordContents.push_back(records.at(0).d_content);
8203 addRRSIG(keys, records, DNSName("example.org."), 300);
8204 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8205 records.clear();
8206
8207 ContentSigPair pair;
8208 pair.records = recordContents;
8209 pair.signatures = signatureContents;
8210 cspmap_t denialMap;
8211 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
8212
8213 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
8214 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8215
8216 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
8217 /* let's check that d.example.org. is not denied by this proof */
8218 BOOST_CHECK_EQUAL(denialState, NODATA);
8219 }
8220
8221 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
8222 init();
8223
8224 testkeysset_t keys;
8225 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8226
8227 vector<DNSRecord> records;
8228
8229 vector<shared_ptr<DNSRecordContent>> recordContents;
8230 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8231
8232 /*
8233 Wrap case 2 test case:
8234 y.example.org. -> a.example.org. denies the existence of z.example.org.
8235 */
8236 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8237 recordContents.push_back(records.at(0).d_content);
8238 addRRSIG(keys, records, DNSName("example.org."), 300);
8239 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8240 records.clear();
8241
8242 ContentSigPair pair;
8243 pair.records = recordContents;
8244 pair.signatures = signatureContents;
8245 cspmap_t denialMap;
8246 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
8247
8248 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
8249 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8250
8251 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
8252 /* let's check that d.example.org. is not denied by this proof */
8253 BOOST_CHECK_EQUAL(denialState, NODATA);
8254 }
8255
8256 BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
8257 init();
8258
8259 testkeysset_t keys;
8260 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8261
8262 vector<DNSRecord> records;
8263
8264 vector<shared_ptr<DNSRecordContent>> recordContents;
8265 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8266
8267 /*
8268 Only one NSEC in the whole zone test case:
8269 a.example.org. -> a.example.org. denies the existence of b.example.org.
8270 */
8271 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8272 recordContents.push_back(records.at(0).d_content);
8273 addRRSIG(keys, records, DNSName("example.org."), 300);
8274 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8275 records.clear();
8276
8277 ContentSigPair pair;
8278 pair.records = recordContents;
8279 pair.signatures = signatureContents;
8280 cspmap_t denialMap;
8281 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8282
8283 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
8284 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8285
8286 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
8287 /* let's check that d.example.org. is not denied by this proof */
8288 BOOST_CHECK_EQUAL(denialState, NODATA);
8289 }
8290
8291 BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
8292 init();
8293
8294 testkeysset_t keys;
8295 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8296
8297 vector<DNSRecord> records;
8298
8299 vector<shared_ptr<DNSRecordContent>> recordContents;
8300 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8301
8302 /*
8303 The RRSIG from "." denies the existence of anything between a. and c.,
8304 including b.
8305 */
8306 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
8307 recordContents.push_back(records.at(0).d_content);
8308 addRRSIG(keys, records, DNSName("."), 300);
8309 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8310 records.clear();
8311
8312 ContentSigPair pair;
8313 pair.records = recordContents;
8314 pair.signatures = signatureContents;
8315 cspmap_t denialMap;
8316 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8317
8318 /* add wildcard denial */
8319 recordContents.clear();
8320 signatureContents.clear();
8321 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8322 recordContents.push_back(records.at(0).d_content);
8323 addRRSIG(keys, records, DNSName("."), 300);
8324 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8325 records.clear();
8326
8327 pair.records = recordContents;
8328 pair.signatures = signatureContents;
8329 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
8330
8331 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
8332 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8333 }
8334
8335 BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
8336 init();
8337
8338 testkeysset_t keys;
8339 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8340
8341 vector<DNSRecord> records;
8342
8343 vector<shared_ptr<DNSRecordContent>> recordContents;
8344 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8345
8346 /*
8347 The RRSIG from "." denies the existence of any type except NS at a.
8348 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8349 signer field that is shorter than the owner name of the NSEC RR) it can't
8350 be used to deny anything except the whole name or a DS.
8351 */
8352 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
8353 recordContents.push_back(records.at(0).d_content);
8354 addRRSIG(keys, records, DNSName("."), 300);
8355 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8356 records.clear();
8357
8358 ContentSigPair pair;
8359 pair.records = recordContents;
8360 pair.signatures = signatureContents;
8361 cspmap_t denialMap;
8362 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8363
8364 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8365 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8366 nonexistence of any RRs below that zone cut, which include all RRs at
8367 that (original) owner name other than DS RRs, and all RRs below that
8368 owner name regardless of type.
8369 */
8370
8371 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
8372 /* no data means the qname/qtype is not denied, because an ancestor
8373 delegation NSEC can only deny the DS */
8374 BOOST_CHECK_EQUAL(denialState, NODATA);
8375
8376 /* it can not be used to deny any RRs below that owner name either */
8377 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false);
8378 BOOST_CHECK_EQUAL(denialState, NODATA);
8379
8380 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8381 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8382 }
8383
8384 BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
8385 init();
8386
8387 testkeysset_t keys;
8388 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8389
8390 vector<DNSRecord> records;
8391
8392 vector<shared_ptr<DNSRecordContent>> recordContents;
8393 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8394
8395 /*
8396 * RFC 5155 section 8.9:
8397 * If there is an NSEC3 RR present in the response that matches the
8398 * delegation name, then the validator MUST ensure that the NS bit is
8399 * set and that the DS bit is not set in the Type Bit Maps field of the
8400 * NSEC3 RR.
8401 */
8402 /*
8403 The RRSIG from "." denies the existence of any type at a.
8404 NS should be set if it was proving an insecure delegation, let's check that
8405 we correctly detect that it's not.
8406 */
8407 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
8408 recordContents.push_back(records.at(0).d_content);
8409 addRRSIG(keys, records, DNSName("."), 300);
8410 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8411 records.clear();
8412
8413 ContentSigPair pair;
8414 pair.records = recordContents;
8415 pair.signatures = signatureContents;
8416 cspmap_t denialMap;
8417 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8418
8419 /* Insecure because the NS is not set, so while it does
8420 denies the DS, it can't prove an insecure delegation */
8421 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8422 BOOST_CHECK_EQUAL(denialState, NODATA);
8423 }
8424
8425 BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
8426 init();
8427
8428 testkeysset_t keys;
8429 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8430
8431 vector<DNSRecord> records;
8432
8433 vector<shared_ptr<DNSRecordContent>> recordContents;
8434 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8435
8436 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
8437 recordContents.push_back(records.at(0).d_content);
8438 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8439 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8440 records.clear();
8441
8442 ContentSigPair pair;
8443 pair.records = recordContents;
8444 pair.signatures = signatureContents;
8445 cspmap_t denialMap;
8446 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8447
8448 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8449 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
8450 BOOST_CHECK_EQUAL(denialState, NODATA);
8451 }
8452
8453 BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
8454 init();
8455
8456 testkeysset_t keys;
8457 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8458
8459 vector<DNSRecord> records;
8460
8461 vector<shared_ptr<DNSRecordContent>> recordContents;
8462 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8463
8464 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
8465 recordContents.push_back(records.at(0).d_content);
8466 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8467 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8468
8469 ContentSigPair pair;
8470 pair.records = recordContents;
8471 pair.signatures = signatureContents;
8472 cspmap_t denialMap;
8473 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8474 records.clear();
8475
8476 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8477 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8478 BOOST_CHECK_EQUAL(denialState, NODATA);
8479 }
8480
8481 BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8482 init();
8483
8484 testkeysset_t keys;
8485 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8486
8487 vector<DNSRecord> records;
8488
8489 vector<shared_ptr<DNSRecordContent>> recordContents;
8490 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8491
8492 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8493 recordContents.push_back(records.at(0).d_content);
8494 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8495 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8496 records.clear();
8497
8498 ContentSigPair pair;
8499 pair.records = recordContents;
8500 pair.signatures = signatureContents;
8501 cspmap_t denialMap;
8502 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8503
8504 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8505 BOOST_CHECK_EQUAL(denialState, NODATA);
8506 }
8507
8508 BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
8509 init();
8510
8511 testkeysset_t keys;
8512 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8513
8514 vector<DNSRecord> records;
8515
8516 vector<shared_ptr<DNSRecordContent>> recordContents;
8517 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8518
8519 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8520 recordContents.push_back(records.at(0).d_content);
8521 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8522 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8523
8524 ContentSigPair pair;
8525 pair.records = recordContents;
8526 pair.signatures = signatureContents;
8527 cspmap_t denialMap;
8528 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8529
8530 /* Add NSEC3 for the closest encloser */
8531 recordContents.clear();
8532 signatureContents.clear();
8533 records.clear();
8534 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8535 recordContents.push_back(records.at(0).d_content);
8536 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8537 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8538
8539 pair.records = recordContents;
8540 pair.signatures = signatureContents;
8541 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8542
8543 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8544 BOOST_CHECK_EQUAL(denialState, NODATA);
8545 }
8546
8547 BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8548 init();
8549
8550 testkeysset_t keys;
8551 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8552
8553 vector<DNSRecord> records;
8554
8555 vector<shared_ptr<DNSRecordContent>> recordContents;
8556 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8557
8558 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8559 recordContents.push_back(records.at(0).d_content);
8560 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8561 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8562 records.clear();
8563
8564 ContentSigPair pair;
8565 pair.records = recordContents;
8566 pair.signatures = signatureContents;
8567 cspmap_t denialMap;
8568 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8569
8570 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
8571 it is an ENT */
8572 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
8573 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8574
8575 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8576 it could prove a NXDOMAIN if it had an additional wildcard denial */
8577 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8578 BOOST_CHECK_EQUAL(denialState, NODATA);
8579
8580 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8581 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8582 BOOST_CHECK_EQUAL(denialState, NODATA);
8583
8584 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8585 recordContents.clear();
8586 signatureContents.clear();
8587 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8588 recordContents.push_back(records.at(0).d_content);
8589 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8590 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8591 records.clear();
8592 pair.records = recordContents;
8593 pair.signatures = signatureContents;
8594 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8595
8596 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
8597 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8598 }
8599
8600 BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8601 init();
8602
8603 testkeysset_t keys;
8604 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8605
8606 vector<DNSRecord> records;
8607
8608 vector<shared_ptr<DNSRecordContent>> recordContents;
8609 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8610
8611 /*
8612 The RRSIG from "." denies the existence of any type except NS at a.
8613 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8614 signer field that is shorter than the owner name of the NSEC RR) it can't
8615 be used to deny anything except the whole name or a DS.
8616 */
8617 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
8618 recordContents.push_back(records.at(0).d_content);
8619 addRRSIG(keys, records, DNSName("."), 300);
8620 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8621
8622 ContentSigPair pair;
8623 pair.records = recordContents;
8624 pair.signatures = signatureContents;
8625 cspmap_t denialMap;
8626 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8627 records.clear();
8628
8629 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8630 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8631 nonexistence of any RRs below that zone cut, which include all RRs at
8632 that (original) owner name other than DS RRs, and all RRs below that
8633 owner name regardless of type.
8634 */
8635
8636 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8637 /* no data means the qname/qtype is not denied, because an ancestor
8638 delegation NSEC3 can only deny the DS */
8639 BOOST_CHECK_EQUAL(denialState, NODATA);
8640
8641 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8642 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8643
8644 /* it can not be used to deny any RRs below that owner name either */
8645 /* Add NSEC3 for the next closer */
8646 recordContents.clear();
8647 signatureContents.clear();
8648 records.clear();
8649 addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8650 recordContents.push_back(records.at(0).d_content);
8651 addRRSIG(keys, records, DNSName("."), 300);
8652 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8653
8654 pair.records = recordContents;
8655 pair.signatures = signatureContents;
8656 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8657
8658 /* add wildcard denial */
8659 recordContents.clear();
8660 signatureContents.clear();
8661 records.clear();
8662 addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8663 recordContents.push_back(records.at(0).d_content);
8664 addRRSIG(keys, records, DNSName("."), 300);
8665 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8666
8667 pair.records = recordContents;
8668 pair.signatures = signatureContents;
8669 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8670
8671 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true);
8672 BOOST_CHECK_EQUAL(denialState, NODATA);
8673 }
8674
8675 BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8676 init();
8677
8678 testkeysset_t keys;
8679 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8680
8681 vector<DNSRecord> records;
8682
8683 vector<shared_ptr<DNSRecordContent>> recordContents;
8684 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8685
8686 /* adding a NSEC3 with more iterations that we support */
8687 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8688 recordContents.push_back(records.at(0).d_content);
8689 addRRSIG(keys, records, DNSName("."), 300);
8690 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8691
8692 ContentSigPair pair;
8693 pair.records = recordContents;
8694 pair.signatures = signatureContents;
8695 cspmap_t denialMap;
8696 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8697 records.clear();
8698
8699 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8700 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8701 BOOST_CHECK_EQUAL(denialState, INSECURE);
8702 }
8703
8704 BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8705 init();
8706
8707 testkeysset_t keys;
8708 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8709
8710 vector<DNSRecord> records;
8711
8712 vector<shared_ptr<DNSRecordContent>> recordContents;
8713 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8714
8715 /*
8716 * RFC 5155 section 8.9:
8717 * If there is an NSEC3 RR present in the response that matches the
8718 * delegation name, then the validator MUST ensure that the NS bit is
8719 * set and that the DS bit is not set in the Type Bit Maps field of the
8720 * NSEC3 RR.
8721 */
8722 /*
8723 The RRSIG from "." denies the existence of any type at a.
8724 NS should be set if it was proving an insecure delegation, let's check that
8725 we correctly detect that it's not.
8726 */
8727 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
8728 recordContents.push_back(records.at(0).d_content);
8729 addRRSIG(keys, records, DNSName("."), 300);
8730 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8731
8732 ContentSigPair pair;
8733 pair.records = recordContents;
8734 pair.signatures = signatureContents;
8735 cspmap_t denialMap;
8736 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8737 records.clear();
8738
8739 /* Insecure because the NS is not set, so while it does
8740 denies the DS, it can't prove an insecure delegation */
8741 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8742 BOOST_CHECK_EQUAL(denialState, NODATA);
8743 }
8744
8745 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8746 std::unique_ptr<SyncRes> sr;
8747 initSR(sr, true);
8748
8749 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8750
8751 primeHints();
8752 const DNSName target("com.");
8753 testkeysset_t keys;
8754
8755 auto luaconfsCopy = g_luaconfs.getCopy();
8756 luaconfsCopy.dsAnchors.clear();
8757 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8758 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8759 g_luaconfs.setState(luaconfsCopy);
8760
8761 size_t queriesCount = 0;
8762
8763 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8764 queriesCount++;
8765
8766 DNSName auth = domain;
8767 auth.chopOff();
8768
8769 if (type == QType::DS || type == QType::DNSKEY) {
8770 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8771 }
8772 else {
8773 setLWResult(res, RCode::NoError, true, false, true);
8774 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8775 addRRSIG(keys, res->d_records, domain, 300);
8776 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8777 addRRSIG(keys, res->d_records, domain, 1);
8778 return 1;
8779 }
8780
8781 return 0;
8782 });
8783
8784 const time_t now = sr->getNow().tv_sec;
8785 vector<DNSRecord> ret;
8786 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8787 BOOST_CHECK_EQUAL(res, RCode::NoError);
8788 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8789 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8790 BOOST_CHECK_EQUAL(queriesCount, 4);
8791
8792 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
8793 NegCache::NegCacheEntry ne;
8794 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8795 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8796 BOOST_CHECK_EQUAL(ne.d_ttd, now + 1);
8797 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
8798 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8799 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8800 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8801 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
8802
8803 /* again, to test the cache */
8804 ret.clear();
8805 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8806 BOOST_CHECK_EQUAL(res, RCode::NoError);
8807 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8808 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8809 BOOST_CHECK_EQUAL(queriesCount, 4);
8810 }
8811
8812 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
8813 std::unique_ptr<SyncRes> sr;
8814 initSR(sr, true);
8815
8816 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8817
8818 primeHints();
8819 const DNSName target("com.");
8820 const ComboAddress targetAddr("192.0.2.42");
8821 testkeysset_t keys;
8822
8823 auto luaconfsCopy = g_luaconfs.getCopy();
8824 luaconfsCopy.dsAnchors.clear();
8825 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8826 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8827 g_luaconfs.setState(luaconfsCopy);
8828
8829 size_t queriesCount = 0;
8830
8831 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8832 queriesCount++;
8833
8834 DNSName auth = domain;
8835 auth.chopOff();
8836
8837 if (type == QType::DS || type == QType::DNSKEY) {
8838 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8839 }
8840 else {
8841 setLWResult(res, RCode::NoError, true, false, true);
8842 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8843 addRRSIG(keys, res->d_records, domain, 1);
8844 return 1;
8845 }
8846
8847 return 0;
8848 });
8849
8850 const time_t now = sr->getNow().tv_sec;
8851 vector<DNSRecord> ret;
8852 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8853 BOOST_CHECK_EQUAL(res, RCode::NoError);
8854 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8855 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8856 BOOST_CHECK_EQUAL(queriesCount, 4);
8857
8858 /* check that the entry has not been cached for longer than the RRSIG validity */
8859 const ComboAddress who;
8860 vector<DNSRecord> cached;
8861 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
8862 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
8863 BOOST_REQUIRE_EQUAL(cached.size(), 1);
8864 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
8865 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
8866
8867 /* again, to test the cache */
8868 ret.clear();
8869 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8870 BOOST_CHECK_EQUAL(res, RCode::NoError);
8871 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8872 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8873 BOOST_CHECK_EQUAL(queriesCount, 4);
8874 }
8875
8876 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
8877 /*
8878 Validation is optional, and the first query does not ask for it,
8879 so the answer is cached as Indeterminate.
8880 The second query asks for validation, answer should be marked as
8881 Secure.
8882 */
8883 std::unique_ptr<SyncRes> sr;
8884 initSR(sr, true);
8885
8886 setDNSSECValidation(sr, DNSSECMode::Process);
8887
8888 primeHints();
8889 const DNSName target("com.");
8890 testkeysset_t keys;
8891
8892 auto luaconfsCopy = g_luaconfs.getCopy();
8893 luaconfsCopy.dsAnchors.clear();
8894 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8895 g_luaconfs.setState(luaconfsCopy);
8896
8897 size_t queriesCount = 0;
8898
8899 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8900 queriesCount++;
8901
8902 if (type == QType::DS || type == QType::DNSKEY) {
8903 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8904 }
8905 else {
8906 if (domain == target && type == QType::A) {
8907 setLWResult(res, 0, true, false, true);
8908 addRecordToLW(res, target, QType::A, "192.0.2.1");
8909 addRRSIG(keys, res->d_records, DNSName("."), 300);
8910 return 1;
8911 }
8912 }
8913
8914 return 0;
8915 });
8916
8917 vector<DNSRecord> ret;
8918 /* first query does not require validation */
8919 sr->setDNSSECValidationRequested(false);
8920 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8921 BOOST_CHECK_EQUAL(res, RCode::NoError);
8922 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8923 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8924 for (const auto& record : ret) {
8925 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8926 }
8927 BOOST_CHECK_EQUAL(queriesCount, 1);
8928
8929
8930 ret.clear();
8931 /* second one _does_ require validation */
8932 sr->setDNSSECValidationRequested(true);
8933 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8934 BOOST_CHECK_EQUAL(res, RCode::NoError);
8935 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8936 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8937 for (const auto& record : ret) {
8938 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8939 }
8940 BOOST_CHECK_EQUAL(queriesCount, 3);
8941 }
8942
8943 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
8944 /*
8945 Validation is optional, and the first query does not ask for it,
8946 so the answer is cached as Indeterminate.
8947 The second query asks for validation, answer should be marked as
8948 Insecure.
8949 */
8950 std::unique_ptr<SyncRes> sr;
8951 initSR(sr, true);
8952
8953 setDNSSECValidation(sr, DNSSECMode::Process);
8954
8955 primeHints();
8956 const DNSName target("com.");
8957 testkeysset_t keys;
8958
8959 auto luaconfsCopy = g_luaconfs.getCopy();
8960 luaconfsCopy.dsAnchors.clear();
8961 g_luaconfs.setState(luaconfsCopy);
8962
8963 size_t queriesCount = 0;
8964
8965 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8966 queriesCount++;
8967
8968 if (type == QType::DS || type == QType::DNSKEY) {
8969 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8970 }
8971 else {
8972 if (domain == target && type == QType::A) {
8973 setLWResult(res, 0, true, false, true);
8974 addRecordToLW(res, target, QType::A, "192.0.2.1");
8975 return 1;
8976 }
8977 }
8978
8979 return 0;
8980 });
8981
8982 vector<DNSRecord> ret;
8983 /* first query does not require validation */
8984 sr->setDNSSECValidationRequested(false);
8985 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8986 BOOST_CHECK_EQUAL(res, RCode::NoError);
8987 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8988 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8989 for (const auto& record : ret) {
8990 BOOST_CHECK(record.d_type == QType::A);
8991 }
8992 BOOST_CHECK_EQUAL(queriesCount, 1);
8993
8994
8995 ret.clear();
8996 /* second one _does_ require validation */
8997 sr->setDNSSECValidationRequested(true);
8998 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8999 BOOST_CHECK_EQUAL(res, RCode::NoError);
9000 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9001 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9002 for (const auto& record : ret) {
9003 BOOST_CHECK(record.d_type == QType::A);
9004 }
9005 BOOST_CHECK_EQUAL(queriesCount, 1);
9006 }
9007
9008 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
9009 /*
9010 Validation is optional, and the first query does not ask for it,
9011 so the answer is cached as Indeterminate.
9012 The second query asks for validation, answer should be marked as
9013 Bogus.
9014 */
9015 std::unique_ptr<SyncRes> sr;
9016 initSR(sr, true);
9017
9018 setDNSSECValidation(sr, DNSSECMode::Process);
9019
9020 primeHints();
9021 const DNSName target("com.");
9022 testkeysset_t keys;
9023
9024 auto luaconfsCopy = g_luaconfs.getCopy();
9025 luaconfsCopy.dsAnchors.clear();
9026 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9027 g_luaconfs.setState(luaconfsCopy);
9028
9029 size_t queriesCount = 0;
9030
9031 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9032 queriesCount++;
9033
9034 if (type == QType::DS || type == QType::DNSKEY) {
9035 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9036 }
9037 else {
9038 if (domain == target && type == QType::A) {
9039 setLWResult(res, 0, true, false, true);
9040 addRecordToLW(res, target, QType::A, "192.0.2.1");
9041 /* no RRSIG */
9042 return 1;
9043 }
9044 }
9045
9046 return 0;
9047 });
9048
9049 vector<DNSRecord> ret;
9050 /* first query does not require validation */
9051 sr->setDNSSECValidationRequested(false);
9052 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9053 BOOST_CHECK_EQUAL(res, RCode::NoError);
9054 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9055 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9056 for (const auto& record : ret) {
9057 BOOST_CHECK(record.d_type == QType::A);
9058 }
9059 BOOST_CHECK_EQUAL(queriesCount, 1);
9060
9061
9062 ret.clear();
9063 /* second one _does_ require validation */
9064 sr->setDNSSECValidationRequested(true);
9065 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9066 BOOST_CHECK_EQUAL(res, RCode::NoError);
9067 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9068 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9069 for (const auto& record : ret) {
9070 BOOST_CHECK(record.d_type == QType::A);
9071 }
9072 BOOST_CHECK_EQUAL(queriesCount, 3);
9073 }
9074
9075 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
9076 /*
9077 Validation is optional, and the first query does not ask for it,
9078 so the answer is cached as Indeterminate.
9079 The second query asks for validation, answer should be marked as
9080 Secure.
9081 */
9082 std::unique_ptr<SyncRes> sr;
9083 initSR(sr, true);
9084
9085 setDNSSECValidation(sr, DNSSECMode::Process);
9086
9087 primeHints();
9088 const DNSName target("com.");
9089 const DNSName cnameTarget("cname-com.");
9090 testkeysset_t keys;
9091
9092 auto luaconfsCopy = g_luaconfs.getCopy();
9093 luaconfsCopy.dsAnchors.clear();
9094 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9095 g_luaconfs.setState(luaconfsCopy);
9096
9097 size_t queriesCount = 0;
9098
9099 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9100 queriesCount++;
9101
9102 if (type == QType::DS || type == QType::DNSKEY) {
9103 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9104 }
9105 else {
9106 if (domain == target && type == QType::A) {
9107 setLWResult(res, 0, true, false, true);
9108 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9109 addRRSIG(keys, res->d_records, DNSName("."), 300);
9110 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9111 addRRSIG(keys, res->d_records, DNSName("."), 300);
9112 return 1;
9113 } else if (domain == cnameTarget && type == QType::A) {
9114 setLWResult(res, 0, true, false, true);
9115 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9116 addRRSIG(keys, res->d_records, DNSName("."), 300);
9117 return 1;
9118 }
9119 }
9120
9121 return 0;
9122 });
9123
9124 vector<DNSRecord> ret;
9125 /* first query does not require validation */
9126 sr->setDNSSECValidationRequested(false);
9127 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9128 BOOST_CHECK_EQUAL(res, RCode::NoError);
9129 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9130 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9131 for (const auto& record : ret) {
9132 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9133 }
9134 BOOST_CHECK_EQUAL(queriesCount, 2);
9135
9136
9137 ret.clear();
9138 /* second one _does_ require validation */
9139 sr->setDNSSECValidationRequested(true);
9140 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9141 BOOST_CHECK_EQUAL(res, RCode::NoError);
9142 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9143 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9144 for (const auto& record : ret) {
9145 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9146 }
9147 BOOST_CHECK_EQUAL(queriesCount, 5);
9148 }
9149
9150 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
9151 /*
9152 Validation is optional, and the first query does not ask for it,
9153 so the answer is cached as Indeterminate.
9154 The second query asks for validation, answer should be marked as
9155 Insecure.
9156 */
9157 std::unique_ptr<SyncRes> sr;
9158 initSR(sr, true);
9159
9160 setDNSSECValidation(sr, DNSSECMode::Process);
9161
9162 primeHints();
9163 const DNSName target("com.");
9164 const DNSName cnameTarget("cname-com.");
9165 testkeysset_t keys;
9166
9167 auto luaconfsCopy = g_luaconfs.getCopy();
9168 luaconfsCopy.dsAnchors.clear();
9169 g_luaconfs.setState(luaconfsCopy);
9170
9171 size_t queriesCount = 0;
9172
9173 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9174 queriesCount++;
9175
9176 if (type == QType::DS || type == QType::DNSKEY) {
9177 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9178 }
9179 else {
9180 if (domain == target && type == QType::A) {
9181 setLWResult(res, 0, true, false, true);
9182 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9183 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9184 return 1;
9185 } else if (domain == cnameTarget && type == QType::A) {
9186 setLWResult(res, 0, true, false, true);
9187 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9188 return 1;
9189 }
9190 }
9191
9192 return 0;
9193 });
9194
9195 vector<DNSRecord> ret;
9196 /* first query does not require validation */
9197 sr->setDNSSECValidationRequested(false);
9198 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9199 BOOST_CHECK_EQUAL(res, RCode::NoError);
9200 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9201 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9202 for (const auto& record : ret) {
9203 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9204 }
9205 BOOST_CHECK_EQUAL(queriesCount, 2);
9206
9207
9208 ret.clear();
9209 /* second one _does_ require validation */
9210 sr->setDNSSECValidationRequested(true);
9211 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9212 BOOST_CHECK_EQUAL(res, RCode::NoError);
9213 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9214 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9215 for (const auto& record : ret) {
9216 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9217 }
9218 BOOST_CHECK_EQUAL(queriesCount, 2);
9219 }
9220
9221 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
9222 /*
9223 Validation is optional, and the first query does not ask for it,
9224 so the answer is cached as Indeterminate.
9225 The second query asks for validation, answer should be marked as
9226 Bogus.
9227 */
9228 std::unique_ptr<SyncRes> sr;
9229 initSR(sr, true);
9230
9231 setDNSSECValidation(sr, DNSSECMode::Process);
9232
9233 primeHints();
9234 const DNSName target("com.");
9235 const DNSName cnameTarget("cname-com.");
9236 testkeysset_t keys;
9237
9238 auto luaconfsCopy = g_luaconfs.getCopy();
9239 luaconfsCopy.dsAnchors.clear();
9240 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9241 g_luaconfs.setState(luaconfsCopy);
9242
9243 size_t queriesCount = 0;
9244
9245 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9246 queriesCount++;
9247
9248 if (type == QType::DS || type == QType::DNSKEY) {
9249 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9250 }
9251 else {
9252 if (domain == target && type == QType::A) {
9253 setLWResult(res, 0, true, false, true);
9254 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9255 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9256 /* no RRSIG */
9257 return 1;
9258 } else if (domain == cnameTarget && type == QType::A) {
9259 setLWResult(res, 0, true, false, true);
9260 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9261 /* no RRSIG */
9262 return 1;
9263 }
9264 }
9265
9266 return 0;
9267 });
9268
9269 vector<DNSRecord> ret;
9270 /* first query does not require validation */
9271 sr->setDNSSECValidationRequested(false);
9272 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9273 BOOST_CHECK_EQUAL(res, RCode::NoError);
9274 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9275 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9276 for (const auto& record : ret) {
9277 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9278 }
9279 BOOST_CHECK_EQUAL(queriesCount, 2);
9280
9281
9282 ret.clear();
9283 /* second one _does_ require validation */
9284 sr->setDNSSECValidationRequested(true);
9285 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9286 BOOST_CHECK_EQUAL(res, RCode::NoError);
9287 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9288 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9289 for (const auto& record : ret) {
9290 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9291 }
9292 BOOST_CHECK_EQUAL(queriesCount, 5);
9293 }
9294
9295 BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) {
9296 /*
9297 We get a record from a secure zone in the additional section, without
9298 the corresponding RRSIG. The record should not be marked as authoritative
9299 and should be correctly validated.
9300 */
9301 std::unique_ptr<SyncRes> sr;
9302 initSR(sr, true);
9303
9304 setDNSSECValidation(sr, DNSSECMode::Process);
9305
9306 primeHints();
9307 const DNSName target("com.");
9308 const DNSName addTarget("nsX.com.");
9309 testkeysset_t keys;
9310
9311 auto luaconfsCopy = g_luaconfs.getCopy();
9312 luaconfsCopy.dsAnchors.clear();
9313 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9314 g_luaconfs.setState(luaconfsCopy);
9315
9316 size_t queriesCount = 0;
9317
9318 sr->setAsyncCallback([target,addTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9319 queriesCount++;
9320
9321 if (type == QType::DS || type == QType::DNSKEY) {
9322 if (domain == addTarget) {
9323 DNSName auth(domain);
9324 /* no DS for com, auth will be . */
9325 auth.chopOff();
9326 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false);
9327 }
9328 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9329 }
9330 else {
9331 if (domain == target && type == QType::A) {
9332 setLWResult(res, 0, true, false, true);
9333 addRecordToLW(res, target, QType::A, "192.0.2.1");
9334 addRRSIG(keys, res->d_records, DNSName("."), 300);
9335 addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL);
9336 /* no RRSIG for the additional record */
9337 return 1;
9338 } else if (domain == addTarget && type == QType::A) {
9339 setLWResult(res, 0, true, false, true);
9340 addRecordToLW(res, addTarget, QType::A, "192.0.2.42");
9341 addRRSIG(keys, res->d_records, DNSName("."), 300);
9342 return 1;
9343 }
9344 }
9345
9346 return 0;
9347 });
9348
9349 vector<DNSRecord> ret;
9350 /* first query for target/A, will pick up the additional record as non-auth / unvalidated */
9351 sr->setDNSSECValidationRequested(false);
9352 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9353 BOOST_CHECK_EQUAL(res, RCode::NoError);
9354 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9355 BOOST_CHECK_EQUAL(ret.size(), 2);
9356 for (const auto& record : ret) {
9357 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9358 }
9359 BOOST_CHECK_EQUAL(queriesCount, 1);
9360
9361 ret.clear();
9362 /* ask for the additional record directly, we should not use
9363 the non-auth one and issue a new query, properly validated */
9364 sr->setDNSSECValidationRequested(true);
9365 res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret);
9366 BOOST_CHECK_EQUAL(res, RCode::NoError);
9367 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9368 BOOST_CHECK_EQUAL(ret.size(), 2);
9369 for (const auto& record : ret) {
9370 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9371 }
9372 BOOST_CHECK_EQUAL(queriesCount, 5);
9373 }
9374
9375 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
9376 /*
9377 Validation is optional, and the first query does not ask for it,
9378 so the answer is negatively cached as Indeterminate.
9379 The second query asks for validation, answer should be marked as
9380 Secure.
9381 */
9382 std::unique_ptr<SyncRes> sr;
9383 initSR(sr, true);
9384
9385 setDNSSECValidation(sr, DNSSECMode::Process);
9386
9387 primeHints();
9388 const DNSName target("com.");
9389 testkeysset_t keys;
9390
9391 auto luaconfsCopy = g_luaconfs.getCopy();
9392 luaconfsCopy.dsAnchors.clear();
9393 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9394 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9395 g_luaconfs.setState(luaconfsCopy);
9396
9397 size_t queriesCount = 0;
9398
9399 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9400 queriesCount++;
9401
9402 DNSName auth = domain;
9403 auth.chopOff();
9404
9405 if (type == QType::DS || type == QType::DNSKEY) {
9406 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9407 }
9408 else {
9409 setLWResult(res, RCode::NoError, true, false, true);
9410 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9411 addRRSIG(keys, res->d_records, domain, 300);
9412 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
9413 addRRSIG(keys, res->d_records, domain, 1);
9414 return 1;
9415 }
9416
9417 return 0;
9418 });
9419
9420 vector<DNSRecord> ret;
9421 /* first query does not require validation */
9422 sr->setDNSSECValidationRequested(false);
9423 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9424 BOOST_CHECK_EQUAL(res, RCode::NoError);
9425 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9426 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9427 BOOST_CHECK_EQUAL(queriesCount, 1);
9428 /* check that the entry has not been negatively cached */
9429 NegCache::NegCacheEntry ne;
9430 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9431 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9432 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9433 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9434 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9435 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9436 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
9437
9438 ret.clear();
9439 /* second one _does_ require validation */
9440 sr->setDNSSECValidationRequested(true);
9441 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9442 BOOST_CHECK_EQUAL(res, RCode::NoError);
9443 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9444 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9445 BOOST_CHECK_EQUAL(queriesCount, 4);
9446 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9447 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9448 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
9449 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9450 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9451 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9452 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
9453 }
9454
9455 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
9456 /*
9457 Validation is optional, and the first query does not ask for it,
9458 so the answer is negatively cached as Indeterminate.
9459 The second query asks for validation, answer should be marked as
9460 Secure.
9461 The difference with test_dnssec_validation_from_negcache_secure is
9462 that have one more level here, so we are going to look for the proof
9463 that the DS does not exist for the last level. Since there is no cut,
9464 we should accept the fact that the NSEC denies DS and NS both.
9465 */
9466 std::unique_ptr<SyncRes> sr;
9467 initSR(sr, true);
9468
9469 setDNSSECValidation(sr, DNSSECMode::Process);
9470
9471 primeHints();
9472 const DNSName target("www.com.");
9473 testkeysset_t keys;
9474
9475 auto luaconfsCopy = g_luaconfs.getCopy();
9476 luaconfsCopy.dsAnchors.clear();
9477 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9478 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9479 g_luaconfs.setState(luaconfsCopy);
9480
9481 size_t queriesCount = 0;
9482
9483 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9484 queriesCount++;
9485
9486 if (type == QType::DS || type == QType::DNSKEY) {
9487 if (domain == target) {
9488 /* there is no cut */
9489 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9490 }
9491 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
9492 }
9493
9494 return 0;
9495 });
9496
9497 vector<DNSRecord> ret;
9498 /* first query does not require validation */
9499 sr->setDNSSECValidationRequested(false);
9500 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9501 BOOST_CHECK_EQUAL(res, RCode::NoError);
9502 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9503 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9504 BOOST_CHECK_EQUAL(queriesCount, 1);
9505
9506 ret.clear();
9507 /* second one _does_ require validation */
9508 sr->setDNSSECValidationRequested(true);
9509 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9510 BOOST_CHECK_EQUAL(res, RCode::NoError);
9511 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9512 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9513 BOOST_CHECK_EQUAL(queriesCount, 4);
9514 }
9515
9516 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
9517 /*
9518 Validation is optional, and the first query does not ask for it,
9519 so the answer is negatively cached as Indeterminate.
9520 The second query asks for validation, answer should be marked as
9521 Insecure.
9522 */
9523 std::unique_ptr<SyncRes> sr;
9524 initSR(sr, true);
9525
9526 setDNSSECValidation(sr, DNSSECMode::Process);
9527
9528 primeHints();
9529 const DNSName target("com.");
9530 testkeysset_t keys;
9531
9532 auto luaconfsCopy = g_luaconfs.getCopy();
9533 luaconfsCopy.dsAnchors.clear();
9534 g_luaconfs.setState(luaconfsCopy);
9535
9536 size_t queriesCount = 0;
9537
9538 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9539 queriesCount++;
9540
9541 DNSName auth = domain;
9542 auth.chopOff();
9543
9544 if (type == QType::DS || type == QType::DNSKEY) {
9545 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9546 }
9547 else {
9548 setLWResult(res, RCode::NoError, true, false, true);
9549 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9550 return 1;
9551 }
9552
9553 return 0;
9554 });
9555
9556 vector<DNSRecord> ret;
9557 /* first query does not require validation */
9558 sr->setDNSSECValidationRequested(false);
9559 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9560 BOOST_CHECK_EQUAL(res, RCode::NoError);
9561 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9562 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9563 BOOST_CHECK_EQUAL(queriesCount, 1);
9564 /* check that the entry has not been negatively cached */
9565 NegCache::NegCacheEntry ne;
9566 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9567 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9568 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9569 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9570 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9571 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9572 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9573
9574 ret.clear();
9575 /* second one _does_ require validation */
9576 sr->setDNSSECValidationRequested(true);
9577 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9578 BOOST_CHECK_EQUAL(res, RCode::NoError);
9579 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9580 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9581 BOOST_CHECK_EQUAL(queriesCount, 1);
9582 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9583 BOOST_CHECK_EQUAL(ne.d_validationState, Insecure);
9584 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9585 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9586 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9587 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9588 }
9589
9590 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
9591 /*
9592 Validation is optional, and the first query does not ask for it,
9593 so the answer is negatively cached as Indeterminate.
9594 The second query asks for validation, answer should be marked as
9595 Bogus.
9596 */
9597 std::unique_ptr<SyncRes> sr;
9598 initSR(sr, true);
9599
9600 setDNSSECValidation(sr, DNSSECMode::Process);
9601
9602 primeHints();
9603 const DNSName target("com.");
9604 testkeysset_t keys;
9605
9606 auto luaconfsCopy = g_luaconfs.getCopy();
9607 luaconfsCopy.dsAnchors.clear();
9608 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9609 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9610 g_luaconfs.setState(luaconfsCopy);
9611
9612 size_t queriesCount = 0;
9613
9614 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9615 queriesCount++;
9616
9617 DNSName auth = domain;
9618 auth.chopOff();
9619
9620 if (type == QType::DS || type == QType::DNSKEY) {
9621 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9622 }
9623 else {
9624 setLWResult(res, RCode::NoError, true, false, true);
9625 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9626 addRRSIG(keys, res->d_records, domain, 300);
9627 /* no denial */
9628 return 1;
9629 }
9630
9631 return 0;
9632 });
9633
9634 vector<DNSRecord> ret;
9635 /* first query does not require validation */
9636 sr->setDNSSECValidationRequested(false);
9637 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9638 BOOST_CHECK_EQUAL(res, RCode::NoError);
9639 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9640 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9641 BOOST_CHECK_EQUAL(queriesCount, 1);
9642 NegCache::NegCacheEntry ne;
9643 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9644 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9645 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9646 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9647 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9648 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9649 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9650
9651 ret.clear();
9652 /* second one _does_ require validation */
9653 sr->setDNSSECValidationRequested(true);
9654 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9655 BOOST_CHECK_EQUAL(res, RCode::NoError);
9656 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9657 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9658 BOOST_CHECK_EQUAL(queriesCount, 4);
9659 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9660 BOOST_CHECK_EQUAL(ne.d_validationState, Bogus);
9661 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9662 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9663 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9664 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9665 }
9666
9667 BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
9668 g_lowercaseOutgoing = true;
9669 std::unique_ptr<SyncRes> sr;
9670 initSR(sr);
9671
9672 primeHints();
9673
9674 vector<DNSName> sentOutQnames;
9675
9676 const DNSName target("WWW.POWERDNS.COM");
9677 const DNSName cname("WWW.PowerDNS.org");
9678
9679 sr->setAsyncCallback([target, cname, &sentOutQnames](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9680
9681 sentOutQnames.push_back(domain);
9682
9683 if (isRootServer(ip)) {
9684 if (domain == target) {
9685 setLWResult(res, 0, false, false, true);
9686 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
9687 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
9688 return 1;
9689 }
9690 if (domain == cname) {
9691 setLWResult(res, 0, false, false, true);
9692 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
9693 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
9694 return 1;
9695 }
9696 } else if (ip == ComboAddress("192.0.2.1:53")) {
9697 if (domain == target) {
9698 setLWResult(res, 0, true, false, false);
9699 addRecordToLW(res, domain, QType::CNAME, cname.toString());
9700 return 1;
9701 }
9702 } else if (ip == ComboAddress("192.0.2.2:53")) {
9703 if (domain == cname) {
9704 setLWResult(res, 0, true, false, false);
9705 addRecordToLW(res, domain, QType::A, "127.0.0.1");
9706 return 1;
9707 }
9708 }
9709 return 0;
9710 });
9711
9712 vector<DNSRecord> ret;
9713 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9714
9715 BOOST_CHECK_EQUAL(res, RCode::NoError);
9716
9717 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9718 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
9719
9720 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
9721 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
9722 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
9723 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
9724 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
9725
9726 g_lowercaseOutgoing = false;
9727 }
9728
9729 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
9730 std::unique_ptr<SyncRes> sr;
9731 initSR(sr, true);
9732
9733 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9734
9735 primeHints();
9736 const DNSName target("com.");
9737 testkeysset_t keys, keys2;
9738
9739 auto luaconfsCopy = g_luaconfs.getCopy();
9740 luaconfsCopy.dsAnchors.clear();
9741 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9742 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9743 g_luaconfs.setState(luaconfsCopy);
9744
9745 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9746 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9747 // But add the existing root key otherwise no RRSIG can be created
9748 auto rootkey = keys.find(g_rootdnsname);
9749 keys2.insert(*rootkey);
9750
9751 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9752 DNSName auth = domain;
9753 auth.chopOff();
9754 if (type == QType::DS || type == QType::DNSKEY) {
9755 if (domain == target) {
9756 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9757 return 0;
9758 }
9759 }
9760 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9761 }
9762 return 0;
9763 });
9764
9765 dsmap_t ds;
9766 auto state = sr->getDSRecords(target, ds, false, 0, false);
9767 BOOST_CHECK_EQUAL(state, Secure);
9768 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9769 for (const auto& i : ds) {
9770 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9771 }
9772 }
9773
9774 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
9775 std::unique_ptr<SyncRes> sr;
9776 initSR(sr, true);
9777
9778 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9779
9780 primeHints();
9781 const DNSName target("com.");
9782 testkeysset_t keys, keys2, keys3;
9783
9784 auto luaconfsCopy = g_luaconfs.getCopy();
9785 luaconfsCopy.dsAnchors.clear();
9786 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9787 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9788 g_luaconfs.setState(luaconfsCopy);
9789
9790 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9791 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9792 // But add the existing root key otherwise no RRSIG can be created
9793 auto rootkey = keys.find(g_rootdnsname);
9794 keys2.insert(*rootkey);
9795
9796 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
9797 // But add the existing root key otherwise no RRSIG can be created
9798 keys3.insert(*rootkey);
9799
9800 sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9801 DNSName auth = domain;
9802 auth.chopOff();
9803 if (type == QType::DS || type == QType::DNSKEY) {
9804 if (domain == target) {
9805 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9806 return 0;
9807 }
9808 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9809 return 0;
9810 }
9811 }
9812 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9813 }
9814 return 0;
9815 });
9816
9817 dsmap_t ds;
9818 auto state = sr->getDSRecords(target, ds, false, 0, false);
9819 BOOST_CHECK_EQUAL(state, Secure);
9820 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9821 for (const auto& i : ds) {
9822 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9823 }
9824 }
9825
9826 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
9827 std::unique_ptr<SyncRes> sr;
9828 initSR(sr, true);
9829
9830 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9831
9832 primeHints();
9833 const DNSName target("com.");
9834 testkeysset_t keys, keys2, keys3;
9835
9836 auto luaconfsCopy = g_luaconfs.getCopy();
9837 luaconfsCopy.dsAnchors.clear();
9838 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9839 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9840 g_luaconfs.setState(luaconfsCopy);
9841
9842 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9843 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
9844 // But add the existing root key otherwise no RRSIG can be created
9845 auto rootkey = keys.find(g_rootdnsname);
9846 keys2.insert(*rootkey);
9847
9848 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
9849 // But add the existing root key otherwise no RRSIG can be created
9850 keys3.insert(*rootkey);
9851
9852 sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9853 DNSName auth = domain;
9854 auth.chopOff();
9855 if (type == QType::DS || type == QType::DNSKEY) {
9856 if (domain == target) {
9857 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9858 return 0;
9859 }
9860 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9861 return 0;
9862 }
9863 }
9864 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9865 }
9866 return 0;
9867 });
9868
9869 dsmap_t ds;
9870 auto state = sr->getDSRecords(target, ds, false, 0, false);
9871 BOOST_CHECK_EQUAL(state, Secure);
9872 BOOST_REQUIRE_EQUAL(ds.size(), 2);
9873 for (const auto& i : ds) {
9874 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9875 }
9876 }
9877
9878 #ifdef HAVE_BOTAN
9879 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) {
9880 std::unique_ptr<SyncRes> sr;
9881 initSR(sr, true);
9882
9883 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9884
9885 primeHints();
9886 const DNSName target("com.");
9887 testkeysset_t keys, keys2;
9888
9889 auto luaconfsCopy = g_luaconfs.getCopy();
9890 luaconfsCopy.dsAnchors.clear();
9891 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9892 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys);
9893 g_luaconfs.setState(luaconfsCopy);
9894
9895 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9896 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9897 // But add the existing root key otherwise no RRSIG can be created
9898 auto rootkey = keys.find(g_rootdnsname);
9899 keys2.insert(*rootkey);
9900
9901 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9902 DNSName auth = domain;
9903 auth.chopOff();
9904 if (type == QType::DS || type == QType::DNSKEY) {
9905 if (domain == target) {
9906 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9907 return 0;
9908 }
9909 }
9910 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9911 }
9912 return 0;
9913 });
9914
9915 dsmap_t ds;
9916 auto state = sr->getDSRecords(target, ds, false, 0, false);
9917 BOOST_CHECK_EQUAL(state, Secure);
9918 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9919 for (const auto& i : ds) {
9920 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9921 }
9922 }
9923
9924 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) {
9925 std::unique_ptr<SyncRes> sr;
9926 initSR(sr, true);
9927
9928 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9929
9930 primeHints();
9931 const DNSName target("com.");
9932 testkeysset_t keys, keys2;
9933
9934 auto luaconfsCopy = g_luaconfs.getCopy();
9935 luaconfsCopy.dsAnchors.clear();
9936 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9937 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9938 g_luaconfs.setState(luaconfsCopy);
9939
9940 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9941 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9942 // But add the existing root key otherwise no RRSIG can be created
9943 auto rootkey = keys.find(g_rootdnsname);
9944 keys2.insert(*rootkey);
9945
9946 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9947 DNSName auth = domain;
9948 auth.chopOff();
9949 if (type == QType::DS || type == QType::DNSKEY) {
9950 if (domain == target) {
9951 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9952 return 0;
9953 }
9954 }
9955 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9956 }
9957 return 0;
9958 });
9959
9960 dsmap_t ds;
9961 auto state = sr->getDSRecords(target, ds, false, 0, false);
9962 BOOST_CHECK_EQUAL(state, Secure);
9963 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9964 for (const auto& i : ds) {
9965 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9966 }
9967 }
9968
9969 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) {
9970 std::unique_ptr<SyncRes> sr;
9971 initSR(sr, true);
9972
9973 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9974
9975 primeHints();
9976 const DNSName target("com.");
9977 testkeysset_t keys, keys2;
9978
9979 auto luaconfsCopy = g_luaconfs.getCopy();
9980 luaconfsCopy.dsAnchors.clear();
9981 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9982 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys);
9983 g_luaconfs.setState(luaconfsCopy);
9984
9985 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9986 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9987 // But add the existing root key otherwise no RRSIG can be created
9988 auto rootkey = keys.find(g_rootdnsname);
9989 keys2.insert(*rootkey);
9990
9991 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9992 DNSName auth = domain;
9993 auth.chopOff();
9994 if (type == QType::DS || type == QType::DNSKEY) {
9995 if (domain == target) {
9996 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9997 return 0;
9998 }
9999 }
10000 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10001 }
10002 return 0;
10003 });
10004
10005 dsmap_t ds;
10006 auto state = sr->getDSRecords(target, ds, false, 0, false);
10007 BOOST_CHECK_EQUAL(state, Secure);
10008 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10009 for (const auto& i : ds) {
10010 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST);
10011 }
10012 }
10013 #endif // HAVE_BOTAN
10014
10015 BOOST_AUTO_TEST_CASE(test_cname_plus_authority_auth) {
10016 std::unique_ptr<SyncRes> sr;
10017 initSR(sr);
10018
10019 primeHints();
10020
10021 const DNSName target("cname.powerdns.com.");
10022 const DNSName cnameTarget("cname-target.powerdns.com");
10023 size_t queriesCount = 0;
10024
10025 sr->setAsyncCallback([target, cnameTarget, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
10026
10027 queriesCount++;
10028
10029 if (isRootServer(ip)) {
10030 setLWResult(res, 0, false, false, true);
10031 addRecordToLW(res, DNSName("powerdns.com"), QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
10032 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
10033 return 1;
10034 } else if (ip == ComboAddress("192.0.2.1:53")) {
10035
10036 if (domain == target) {
10037 setLWResult(res, 0, true, false, false);
10038 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
10039 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2");
10040 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 42);
10041 addRecordToLW(res, DNSName("add.powerdns.com."), QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 42);
10042 return 1;
10043 }
10044 else if (domain == cnameTarget) {
10045 setLWResult(res, 0, true, false, false);
10046 addRecordToLW(res, domain, QType::A, "192.0.2.2");
10047 }
10048
10049 return 1;
10050 }
10051
10052 return 0;
10053 });
10054
10055 const time_t now = sr->getNow().tv_sec;
10056 vector<DNSRecord> ret;
10057 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10058 BOOST_CHECK_EQUAL(res, RCode::NoError);
10059 BOOST_REQUIRE_EQUAL(ret.size(), 2);
10060 BOOST_CHECK(ret[0].d_type == QType::CNAME);
10061 BOOST_CHECK_EQUAL(ret[0].d_name, target);
10062 BOOST_CHECK(ret[1].d_type == QType::A);
10063 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
10064
10065 /* check that the NS in authority has been replaced in the cache
10066 with auth=1, but that the part in additional is still not auth */
10067 const ComboAddress who;
10068 vector<DNSRecord> cached;
10069 bool wasAuth = false;
10070
10071 BOOST_REQUIRE_GE(t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth), 1);
10072 BOOST_CHECK_EQUAL(cached.size(), 1);
10073 BOOST_CHECK_EQUAL(wasAuth, true);
10074
10075 cached.clear();
10076 BOOST_REQUIRE_GE(t_RC->get(now, DNSName("add.powerdns.com."), QType(QType::A), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth), 1);
10077 BOOST_CHECK_EQUAL(cached.size(), 1);
10078 BOOST_CHECK_EQUAL(wasAuth, false);
10079 }
10080
10081 /*
10082 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
10083
10084 - check out of band support
10085
10086 - check preoutquery
10087
10088 */
10089
10090 BOOST_AUTO_TEST_SUITE_END()