]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc.cc
Merge pull request #5911 from job/improve_error_readability
[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 "arguments.hh"
6 #include "base32.hh"
7 #include "dnssecinfra.hh"
8 #include "dnsseckeeper.hh"
9 #include "lua-recursor4.hh"
10 #include "namespaces.hh"
11 #include "rec-lua-conf.hh"
12 #include "root-dnssec.hh"
13 #include "syncres.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)
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)
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 static 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=unique_ptr<DSRecordContent>(dynamic_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 if (debug) {
105 L.setName("test");
106 L.setLoglevel((Logger::Urgency)(6)); // info and up
107 L.disableSyslog(true);
108 L.toConsole(Logger::Info);
109 }
110
111 seedRandom("/dev/urandom");
112 reportAllTypes();
113
114 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
115
116 SyncRes::s_maxqperq = 50;
117 SyncRes::s_maxtotusec = 1000*7000;
118 SyncRes::s_maxdepth = 40;
119 SyncRes::s_maxnegttl = 3600;
120 SyncRes::s_maxcachettl = 86400;
121 SyncRes::s_packetcachettl = 3600;
122 SyncRes::s_packetcacheservfailttl = 60;
123 SyncRes::s_serverdownmaxfails = 64;
124 SyncRes::s_serverdownthrottletime = 60;
125 SyncRes::s_doIPv6 = true;
126 SyncRes::s_ecsipv4limit = 24;
127 SyncRes::s_ecsipv6limit = 56;
128 SyncRes::s_rootNXTrust = true;
129 SyncRes::s_minimumTTL = 0;
130 SyncRes::s_serverID = "PowerDNS Unit Tests Server ID";
131 SyncRes::clearEDNSSubnets();
132 SyncRes::clearEDNSDomains();
133 SyncRes::clearDelegationOnly();
134 SyncRes::clearDontQuery();
135
136 SyncRes::clearNSSpeeds();
137 BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0);
138 SyncRes::clearEDNSStatuses();
139 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0);
140 SyncRes::clearThrottle();
141 BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0);
142 SyncRes::clearFailedServers();
143 BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0);
144
145 auto luaconfsCopy = g_luaconfs.getCopy();
146 luaconfsCopy.dfe.clear();
147 luaconfsCopy.dsAnchors.clear();
148 for (const auto &dsRecord : rootDSs) {
149 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
150 luaconfsCopy.dsAnchors[g_rootdnsname].insert(*ds);
151 }
152 luaconfsCopy.negAnchors.clear();
153 g_luaconfs.setState(luaconfsCopy);
154
155 g_dnssecmode = DNSSECMode::Off;
156 g_dnssecLOG = debug;
157 g_maxNSEC3Iterations = 2500;
158
159 ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Unit Tests";
160 }
161
162 static void initSR(std::unique_ptr<SyncRes>& sr, bool dnssec=false, bool debug=false, time_t fakeNow=0)
163 {
164 struct timeval now;
165 if (fakeNow > 0) {
166 now.tv_sec = fakeNow;
167 now.tv_usec = 0;
168 }
169 else {
170 Utility::gettimeofday(&now, 0);
171 }
172
173 init(debug);
174
175 sr = std::unique_ptr<SyncRes>(new SyncRes(now));
176 sr->setDoEDNS0(true);
177 if (dnssec) {
178 sr->setDoDNSSEC(dnssec);
179 }
180
181 sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
182
183 SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
184 SyncRes::clearNegCache();
185 }
186
187 static void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
188 {
189 sr->setDNSSECValidationRequested(true);
190 g_dnssecmode = mode;
191 }
192
193 static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
194 {
195 res->d_rcode = rcode;
196 res->d_aabit = aa;
197 res->d_tcbit = tc;
198 res->d_haveEDNS = edns;
199 }
200
201 static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
202 {
203 addRecordToList(res->d_records, name, type, content, place, ttl);
204 }
205
206 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)
207 {
208 addRecordToLW(res, DNSName(name), type, content, place, ttl);
209 }
210
211 static bool isRootServer(const ComboAddress& ip)
212 {
213 if (ip.isIPv4()) {
214 for (size_t idx = 0; idx < rootIps4Count; idx++) {
215 if (ip.toString() == rootIps4[idx]) {
216 return true;
217 }
218 }
219 }
220 else {
221 for (size_t idx = 0; idx < rootIps6Count; idx++) {
222 if (ip.toString() == rootIps6[idx]) {
223 return true;
224 }
225 }
226 }
227
228 return false;
229 }
230
231 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)
232 {
233 time_t now = time(nullptr);
234 DNSKEYRecordContent drc = dpk.getDNSKEY();
235 const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
236
237 rrc.d_type = signQType;
238 rrc.d_labels = signQName.countLabels() - signQName.isWildcard();
239 rrc.d_originalttl = signTTL;
240 rrc.d_siginception = inception ? *inception : (now - 10);
241 rrc.d_sigexpire = now + sigValidity;
242 rrc.d_signer = signer;
243 rrc.d_tag = 0;
244 rrc.d_tag = drc.getTag();
245 rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
246
247 std::string msg = getMessageForRRSET(signQName, rrc, toSign);
248
249 rrc.d_signature = rc->sign(msg);
250 }
251
252 typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t;
253
254 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)
255 {
256 if (records.empty()) {
257 return false;
258 }
259
260 const auto it = keys.find(signer);
261 if (it == keys.cend()) {
262 throw std::runtime_error("No DNSKEY found for " + signer.toString() + ", unable to compute the requested RRSIG");
263 }
264
265 size_t recordsCount = records.size();
266 const DNSName& name = records[recordsCount-1].d_name;
267 const uint16_t type = records[recordsCount-1].d_type;
268
269 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
270 for (const auto record : records) {
271 if (record.d_name == name && record.d_type == type) {
272 recordcontents.push_back(record.d_content);
273 }
274 }
275
276 RRSIGRecordContent rrc;
277 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);
278 if (broken) {
279 rrc.d_signature[0] ^= 42;
280 }
281
282 DNSRecord rec;
283 rec.d_type = QType::RRSIG;
284 rec.d_place = records[recordsCount-1].d_place;
285 rec.d_name = records[recordsCount-1].d_name;
286 rec.d_ttl = records[recordsCount-1].d_ttl;
287
288 rec.d_content = std::make_shared<RRSIGRecordContent>(rrc);
289 records.push_back(rec);
290
291 return true;
292 }
293
294 static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records)
295 {
296 const auto it = keys.find(signer);
297 if (it == keys.cend()) {
298 throw std::runtime_error("No DNSKEY found for " + signer.toString());
299 }
300
301 DNSRecord rec;
302 rec.d_place = DNSResourceRecord::ANSWER;
303 rec.d_name = signer;
304 rec.d_type = QType::DNSKEY;
305 rec.d_ttl = ttl;
306
307 rec.d_content = std::make_shared<DNSKEYRecordContent>(it->second.first.getDNSKEY());
308 records.push_back(rec);
309 }
310
311 static bool addDS(const DNSName& domain, uint32_t ttl, std::vector<DNSRecord>& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY)
312 {
313 const auto it = keys.find(domain);
314 if (it == keys.cend()) {
315 return false;
316 }
317
318 DNSRecord rec;
319 rec.d_name = domain;
320 rec.d_type = QType::DS;
321 rec.d_place = place;
322 rec.d_ttl = ttl;
323 rec.d_content = std::make_shared<DSRecordContent>(it->second.second);
324
325 records.push_back(rec);
326 return true;
327 }
328
329 static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
330 {
331 NSECRecordContent nrc;
332 nrc.d_next = next;
333 nrc.d_set = types;
334
335 DNSRecord rec;
336 rec.d_name = domain;
337 rec.d_ttl = ttl;
338 rec.d_type = QType::NSEC;
339 rec.d_content = std::make_shared<NSECRecordContent>(nrc);
340 rec.d_place = DNSResourceRecord::AUTHORITY;
341
342 records.push_back(rec);
343 }
344
345 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)
346 {
347 NSEC3RecordContent nrc;
348 nrc.d_algorithm = 1;
349 nrc.d_flags = 0;
350 nrc.d_iterations = iterations;
351 nrc.d_salt = salt;
352 nrc.d_nexthash = hashedNext;
353 nrc.d_set = types;
354
355 DNSRecord rec;
356 rec.d_name = hashedName;
357 rec.d_ttl = ttl;
358 rec.d_type = QType::NSEC3;
359 rec.d_content = std::make_shared<NSEC3RecordContent>(nrc);
360 rec.d_place = DNSResourceRecord::AUTHORITY;
361
362 records.push_back(rec);
363 }
364
365 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)
366 {
367 static const std::string salt = "deadbeef";
368 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
369
370 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, next, salt, iterations, types, ttl, records);
371 }
372
373 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)
374 {
375 static const std::string salt = "deadbeef";
376 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
377 std::string hashedNext(hashed);
378 incrementHash(hashedNext);
379 decrementHash(hashed);
380
381 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, hashedNext, salt, iterations, types, ttl, records);
382 }
383
384 static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys)
385 {
386 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(algo));
387 dcke->create((algo <= 10) ? 2048 : dcke->getBits());
388 DNSSECPrivateKey dpk;
389 dpk.d_flags = 256;
390 dpk.setKey(dcke);
391 DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest);
392 keys[name] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk,ds);
393 }
394
395 static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map<DNSName,dsmap_t>& dsAnchors)
396 {
397 generateKeyMaterial(name, algo, digest, keys);
398 dsAnchors[name].insert(keys[name].second);
399 }
400
401 static int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut=true)
402 {
403 if (type == QType::DS) {
404 auth.chopOff();
405
406 setLWResult(res, 0, true, false, true);
407
408 if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) {
409 addRRSIG(keys, res->d_records, auth, 300);
410 }
411 else {
412 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
413
414 /* if the auth zone is signed, we need to provide a secure denial */
415 const auto it = keys.find(auth);
416 if (it != keys.cend()) {
417 /* sign the SOA */
418 addRRSIG(keys, res->d_records, auth, 300);
419 /* add a NSEC denying the DS */
420 std::set<uint16_t> types = { QType::NSEC };
421 if (proveCut) {
422 types.insert(QType::NS);
423 }
424
425 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
426 addRRSIG(keys, res->d_records, auth, 300);
427 }
428 }
429
430 return 1;
431 }
432
433 if (type == QType::DNSKEY) {
434 setLWResult(res, 0, true, false, true);
435 addDNSKEY(keys, domain, 300, res->d_records);
436 addRRSIG(keys, res->d_records, domain, 300);
437 return 1;
438 }
439
440 return 0;
441 }
442
443 /* Real tests */
444
445 BOOST_AUTO_TEST_SUITE(syncres_cc)
446
447 BOOST_AUTO_TEST_CASE(test_root_primed) {
448 std::unique_ptr<SyncRes> sr;
449 initSR(sr);
450
451 primeHints();
452
453 const DNSName target("a.root-servers.net.");
454
455 /* we are primed, we should be able to resolve A a.root-servers.net. without any query */
456 vector<DNSRecord> ret;
457 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
458 BOOST_CHECK_EQUAL(res, RCode::NoError);
459 BOOST_REQUIRE_EQUAL(ret.size(), 1);
460 BOOST_CHECK(ret[0].d_type == QType::A);
461 BOOST_CHECK_EQUAL(ret[0].d_name, target);
462
463 ret.clear();
464 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
465 BOOST_CHECK_EQUAL(res, RCode::NoError);
466 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
467 BOOST_REQUIRE_EQUAL(ret.size(), 1);
468 BOOST_CHECK(ret[0].d_type == QType::AAAA);
469 BOOST_CHECK_EQUAL(ret[0].d_name, target);
470 }
471
472 BOOST_AUTO_TEST_CASE(test_root_primed_ns) {
473 std::unique_ptr<SyncRes> sr;
474 initSR(sr);
475
476 primeHints();
477 const DNSName target(".");
478
479 /* we are primed, but we should not be able to NS . without any query
480 because the . NS entry is not stored as authoritative */
481
482 size_t queriesCount = 0;
483
484 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) {
485 queriesCount++;
486
487 if (domain == target && type == QType::NS) {
488
489 setLWResult(res, 0, true, false, true);
490 char addr[] = "a.root-servers.net.";
491 for (char idx = 'a'; idx <= 'm'; idx++) {
492 addr[0] = idx;
493 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
494 }
495
496 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
497 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
498
499 return 1;
500 }
501
502 return 0;
503 });
504
505 vector<DNSRecord> ret;
506 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
507 BOOST_CHECK_EQUAL(res, RCode::NoError);
508 BOOST_REQUIRE_EQUAL(ret.size(), 13);
509 BOOST_CHECK_EQUAL(queriesCount, 1);
510 }
511
512 BOOST_AUTO_TEST_CASE(test_root_not_primed) {
513 std::unique_ptr<SyncRes> sr;
514 initSR(sr);
515
516 size_t queriesCount = 0;
517
518 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) {
519 queriesCount++;
520
521 if (domain == g_rootdnsname && type == QType::NS) {
522 setLWResult(res, 0, true, false, true);
523 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
524 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
525 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
526
527 return 1;
528 }
529
530 return 0;
531 });
532
533 /* we are not primed yet, so SyncRes will have to call primeHints()
534 then call getRootNS(), for which at least one of the root servers needs to answer */
535 vector<DNSRecord> ret;
536 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
537 BOOST_CHECK_EQUAL(res, RCode::NoError);
538 BOOST_CHECK_EQUAL(ret.size(), 1);
539 BOOST_CHECK_EQUAL(queriesCount, 2);
540 }
541
542 BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
543 std::unique_ptr<SyncRes> sr;
544 initSR(sr);
545 std::set<ComboAddress> downServers;
546
547 /* we are not primed yet, so SyncRes will have to call primeHints()
548 then call getRootNS(), for which at least one of the root servers needs to answer.
549 None will, so it should ServFail.
550 */
551 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) {
552
553 downServers.insert(ip);
554 return 0;
555 });
556
557 vector<DNSRecord> ret;
558 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
559 BOOST_CHECK_EQUAL(res, RCode::ServFail);
560 BOOST_CHECK_EQUAL(ret.size(), 0);
561 BOOST_CHECK(downServers.size() > 0);
562 /* we explicitly refuse to mark the root servers down */
563 for (const auto& server : downServers) {
564 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
565 }
566 }
567
568 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
569 std::unique_ptr<SyncRes> sr;
570 initSR(sr);
571
572 ComboAddress noEDNSServer;
573 size_t queriesWithEDNS = 0;
574 size_t queriesWithoutEDNS = 0;
575
576 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) {
577 if (EDNS0Level != 0) {
578 queriesWithEDNS++;
579 noEDNSServer = ip;
580
581 setLWResult(res, RCode::FormErr);
582 return 1;
583 }
584
585 queriesWithoutEDNS++;
586
587 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
588 setLWResult(res, 0, true, false, false);
589 addRecordToLW(res, domain, QType::A, "192.0.2.1");
590 return 1;
591 }
592
593 return 0;
594 });
595
596 primeHints();
597
598 /* fake that the root NS doesn't handle EDNS, check that we fallback */
599 vector<DNSRecord> ret;
600 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
601 BOOST_CHECK_EQUAL(res, RCode::NoError);
602 BOOST_CHECK_EQUAL(ret.size(), 1);
603 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
604 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
605 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
606 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
607 }
608
609 BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) {
610 std::unique_ptr<SyncRes> sr;
611 initSR(sr);
612
613 size_t queriesWithEDNS = 0;
614 size_t queriesWithoutEDNS = 0;
615
616 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) {
617 if (EDNS0Level != 0) {
618 queriesWithEDNS++;
619 setLWResult(res, RCode::NotImp);
620 return 1;
621 }
622
623 queriesWithoutEDNS++;
624
625 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
626 setLWResult(res, 0, true, false, false);
627 addRecordToLW(res, domain, QType::A, "192.0.2.1");
628 return 1;
629 }
630
631 return 0;
632 });
633
634 primeHints();
635
636 /* fake that the NS doesn't handle EDNS, check that we fallback */
637 vector<DNSRecord> ret;
638 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
639 BOOST_CHECK_EQUAL(res, RCode::NoError);
640 BOOST_CHECK_EQUAL(ret.size(), 1);
641 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
642 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
643 }
644
645 BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
646 std::unique_ptr<SyncRes> sr;
647 initSR(sr);
648
649 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) {
650 if (!doTCP) {
651 setLWResult(res, 0, false, true, false);
652 return 1;
653 }
654 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
655 setLWResult(res, 0, true, false, false);
656 addRecordToLW(res, domain, QType::A, "192.0.2.1");
657 return 1;
658 }
659
660 return 0;
661 });
662
663 primeHints();
664
665 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
666 vector<DNSRecord> ret;
667 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
668 BOOST_CHECK_EQUAL(res, RCode::NoError);
669 }
670
671 BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
672 std::unique_ptr<SyncRes> sr;
673 initSR(sr);
674
675 size_t tcpQueriesCount = 0;
676
677 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) {
678 if (!doTCP) {
679 setLWResult(res, 0, true, true, false);
680 return 1;
681 }
682
683 /* first TCP query is answered with a TC response */
684 tcpQueriesCount++;
685 if (tcpQueriesCount == 1) {
686 setLWResult(res, 0, true, true, false);
687 }
688 else {
689 setLWResult(res, 0, true, false, false);
690 }
691
692 addRecordToLW(res, domain, QType::A, "192.0.2.1");
693 return 1;
694 });
695
696 primeHints();
697
698 vector<DNSRecord> ret;
699 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
700 BOOST_CHECK_EQUAL(res, RCode::NoError);
701 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
702 }
703
704 BOOST_AUTO_TEST_CASE(test_all_nss_down) {
705 std::unique_ptr<SyncRes> sr;
706 initSR(sr);
707 std::set<ComboAddress> downServers;
708
709 primeHints();
710
711 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) {
712
713 if (isRootServer(ip)) {
714 setLWResult(res, 0, false, false, true);
715 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
716 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
717 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
718 return 1;
719 }
720 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
721 setLWResult(res, 0, false, false, true);
722 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
723 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
724 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
725 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
726 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
727 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
728 return 1;
729 }
730 else {
731 downServers.insert(ip);
732 return 0;
733 }
734 });
735
736 DNSName target("powerdns.com.");
737
738 vector<DNSRecord> ret;
739 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
740 BOOST_CHECK_EQUAL(res, RCode::ServFail);
741 BOOST_CHECK_EQUAL(ret.size(), 0);
742 BOOST_CHECK_EQUAL(downServers.size(), 4);
743
744 for (const auto& server : downServers) {
745 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
746 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
747 }
748 }
749
750 BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
751 std::unique_ptr<SyncRes> sr;
752 initSR(sr);
753 std::set<ComboAddress> downServers;
754
755 primeHints();
756
757 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) {
758
759 if (isRootServer(ip)) {
760 setLWResult(res, 0, false, false, true);
761 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
762 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
763 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
764 return 1;
765 }
766 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
767 setLWResult(res, 0, false, false, true);
768 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
769 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
770 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
771 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
772 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
773 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
774 return 1;
775 }
776 else {
777 downServers.insert(ip);
778 return -1;
779 }
780 });
781
782 /* exact same test than the previous one, except instead of a time out we fake a network error */
783 DNSName target("powerdns.com.");
784
785 vector<DNSRecord> ret;
786 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
787 BOOST_CHECK_EQUAL(res, RCode::ServFail);
788 BOOST_CHECK_EQUAL(ret.size(), 0);
789 BOOST_CHECK_EQUAL(downServers.size(), 4);
790
791 for (const auto& server : downServers) {
792 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
793 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
794 ;
795 }
796 }
797
798 BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
799 std::unique_ptr<SyncRes> sr;
800 initSR(sr);
801 std::set<ComboAddress> downServers;
802
803 primeHints();
804
805 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) {
806
807 if (isRootServer(ip)) {
808 setLWResult(res, 0, false, false, true);
809 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
810 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
811 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
812 return 1;
813 }
814 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
815 setLWResult(res, 0, false, false, true);
816 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
817 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
818 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
819 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
820 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
821 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
822 return 1;
823 }
824 else {
825 if (downServers.size() < 3) {
826 /* only the last one will answer */
827 downServers.insert(ip);
828 return -2;
829 }
830 else {
831 setLWResult(res, 0, true, false, true);
832 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
833 return 1;
834 }
835 }
836 });
837
838 DNSName target("powerdns.com.");
839
840 vector<DNSRecord> ret;
841 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
842 BOOST_CHECK_EQUAL(res, RCode::NoError);
843 BOOST_CHECK_EQUAL(ret.size(), 1);
844 BOOST_CHECK_EQUAL(downServers.size(), 3);
845
846 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
847 for (const auto& server : downServers) {
848 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
849 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
850 }
851 }
852
853 BOOST_AUTO_TEST_CASE(test_glued_referral) {
854 std::unique_ptr<SyncRes> sr;
855 initSR(sr);
856
857 primeHints();
858
859 const DNSName target("powerdns.com.");
860
861 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) {
862 /* this will cause issue with qname minimization if we ever implement it */
863 if (domain != target) {
864 return 0;
865 }
866
867 if (isRootServer(ip)) {
868 setLWResult(res, 0, false, false, true);
869 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
870 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
871 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
872 return 1;
873 }
874 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
875 setLWResult(res, 0, false, false, true);
876 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
877 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
878 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
879 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
880 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
881 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
882 return 1;
883 }
884 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")) {
885 setLWResult(res, 0, true, false, true);
886 addRecordToLW(res, target, QType::A, "192.0.2.4");
887 return 1;
888 }
889 else {
890 return 0;
891 }
892 });
893
894 vector<DNSRecord> ret;
895 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
896 BOOST_CHECK_EQUAL(res, RCode::NoError);
897 BOOST_REQUIRE_EQUAL(ret.size(), 1);
898 BOOST_CHECK(ret[0].d_type == QType::A);
899 BOOST_CHECK_EQUAL(ret[0].d_name, target);
900 }
901
902 BOOST_AUTO_TEST_CASE(test_glueless_referral) {
903 std::unique_ptr<SyncRes> sr;
904 initSR(sr);
905
906 primeHints();
907
908 const DNSName target("powerdns.com.");
909
910 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) {
911
912 if (isRootServer(ip)) {
913 setLWResult(res, 0, false, false, true);
914
915 if (domain.isPartOf(DNSName("com."))) {
916 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
917 } else if (domain.isPartOf(DNSName("org."))) {
918 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
919 }
920 else {
921 setLWResult(res, RCode::NXDomain, false, false, true);
922 return 1;
923 }
924
925 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
926 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
927 return 1;
928 }
929 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
930 if (domain == target) {
931 setLWResult(res, 0, false, false, true);
932 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
933 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
934 return 1;
935 }
936 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
937 setLWResult(res, 0, true, false, true);
938 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
939 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
940 return 1;
941 }
942 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
943 setLWResult(res, 0, true, false, true);
944 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
945 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
946 return 1;
947 }
948
949 setLWResult(res, RCode::NXDomain, false, false, true);
950 return 1;
951 }
952 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")) {
953 setLWResult(res, 0, true, false, true);
954 addRecordToLW(res, target, QType::A, "192.0.2.4");
955 return 1;
956 }
957 else {
958 return 0;
959 }
960 });
961
962 vector<DNSRecord> ret;
963 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
964 BOOST_CHECK_EQUAL(res, RCode::NoError);
965 BOOST_REQUIRE_EQUAL(ret.size(), 1);
966 BOOST_CHECK(ret[0].d_type == QType::A);
967 BOOST_CHECK_EQUAL(ret[0].d_name, target);
968 }
969
970 BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
971 std::unique_ptr<SyncRes> sr;
972 initSR(sr);
973
974 primeHints();
975
976 const DNSName target("powerdns.com.");
977 SyncRes::addEDNSDomain(target);
978
979 EDNSSubnetOpts incomingECS;
980 incomingECS.source = Netmask("192.0.2.128/32");
981 sr->setIncomingECSFound(true);
982 sr->setIncomingECS(incomingECS);
983
984 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) {
985
986 BOOST_REQUIRE(srcmask);
987 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
988 return 0;
989 });
990
991 vector<DNSRecord> ret;
992 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
993 BOOST_CHECK_EQUAL(res, RCode::ServFail);
994 }
995
996 BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
997 std::unique_ptr<SyncRes> sr;
998 initSR(sr);
999
1000 primeHints();
1001
1002 const DNSName target("powerdns.com.");
1003 SyncRes::addEDNSSubnet(Netmask("192.0.2.1/32"));
1004
1005 EDNSSubnetOpts incomingECS;
1006 incomingECS.source = Netmask("2001:DB8::FF/128");
1007 sr->setIncomingECSFound(true);
1008 sr->setIncomingECS(incomingECS);
1009
1010 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) {
1011
1012 if (isRootServer(ip)) {
1013 BOOST_REQUIRE(!srcmask);
1014
1015 setLWResult(res, 0, false, false, true);
1016 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1017 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1018 return 1;
1019 } else if (ip == ComboAddress("192.0.2.1:53")) {
1020
1021 BOOST_REQUIRE(srcmask);
1022 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1023
1024 setLWResult(res, 0, true, false, false);
1025 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1026 return 1;
1027 }
1028
1029 return 0;
1030 });
1031
1032 vector<DNSRecord> ret;
1033 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1034 BOOST_CHECK_EQUAL(res, RCode::NoError);
1035 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1036 BOOST_CHECK(ret[0].d_type == QType::A);
1037 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1038 }
1039
1040 BOOST_AUTO_TEST_CASE(test_following_cname) {
1041 std::unique_ptr<SyncRes> sr;
1042 initSR(sr);
1043
1044 primeHints();
1045
1046 const DNSName target("cname.powerdns.com.");
1047 const DNSName cnameTarget("cname-target.powerdns.com");
1048
1049 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) {
1050
1051 if (isRootServer(ip)) {
1052 setLWResult(res, 0, false, false, true);
1053 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1054 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1055 return 1;
1056 } else if (ip == ComboAddress("192.0.2.1:53")) {
1057
1058 if (domain == target) {
1059 setLWResult(res, 0, true, false, false);
1060 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1061 return 1;
1062 }
1063 else if (domain == cnameTarget) {
1064 setLWResult(res, 0, true, false, false);
1065 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1066 }
1067
1068 return 1;
1069 }
1070
1071 return 0;
1072 });
1073
1074 vector<DNSRecord> ret;
1075 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1076 BOOST_CHECK_EQUAL(res, RCode::NoError);
1077 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1078 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1079 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1080 BOOST_CHECK(ret[1].d_type == QType::A);
1081 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1082 }
1083
1084 BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
1085 std::unique_ptr<SyncRes> sr;
1086 initSR(sr);
1087
1088 primeHints();
1089
1090 const DNSName target("cname.powerdns.com.");
1091 const DNSName cnameTarget("cname-target.powerdns.com");
1092
1093 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) {
1094
1095 if (isRootServer(ip)) {
1096 setLWResult(res, 0, false, false, true);
1097 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1098 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1099 return 1;
1100 } else if (ip == ComboAddress("192.0.2.1:53")) {
1101
1102 if (domain == target) {
1103 setLWResult(res, RCode::NXDomain, true, false, false);
1104 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1105 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1106 } else if (domain == cnameTarget) {
1107 setLWResult(res, RCode::NXDomain, true, false, false);
1108 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1109 return 1;
1110 }
1111
1112 return 1;
1113 }
1114
1115 return 0;
1116 });
1117
1118 vector<DNSRecord> ret;
1119 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1120 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1121 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1122 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1123 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1124 BOOST_CHECK(ret[1].d_type == QType::SOA);
1125
1126 /* a second time, to check the cache */
1127 ret.clear();
1128 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1129 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1130 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1131 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1132 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1133 BOOST_CHECK(ret[1].d_type == QType::SOA);
1134 }
1135
1136 BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1137 std::unique_ptr<SyncRes> sr;
1138 initSR(sr);
1139
1140 primeHints();
1141
1142 /* In this test we directly get the NS server for cname.powerdns.com.,
1143 and we don't know whether it's also authoritative for
1144 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1145 the additional A record for cname-target.powerdns.com. */
1146 const DNSName target("cname.powerdns.com.");
1147 const DNSName cnameTarget("cname-target.powerdns.com");
1148
1149 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) {
1150
1151 if (isRootServer(ip)) {
1152
1153 setLWResult(res, 0, false, false, true);
1154
1155 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1156 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1157 return 1;
1158 } else if (ip == ComboAddress("192.0.2.1:53")) {
1159
1160 if (domain == target) {
1161 setLWResult(res, 0, true, false, false);
1162 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1163 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1164 return 1;
1165 } else if (domain == cnameTarget) {
1166 setLWResult(res, 0, true, false, false);
1167 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
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::NoError);
1180 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1181 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1182 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1183 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1184 BOOST_REQUIRE(ret[1].d_type == QType::A);
1185 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1186 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1187 }
1188
1189 BOOST_AUTO_TEST_CASE(test_cname_loop) {
1190 std::unique_ptr<SyncRes> sr;
1191 initSR(sr);
1192
1193 primeHints();
1194
1195 size_t count = 0;
1196 const DNSName target("cname.powerdns.com.");
1197
1198 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) {
1199
1200 count++;
1201
1202 if (isRootServer(ip)) {
1203
1204 setLWResult(res, 0, false, false, true);
1205 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1206 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1207 return 1;
1208 } else if (ip == ComboAddress("192.0.2.1:53")) {
1209
1210 if (domain == target) {
1211 setLWResult(res, 0, true, false, false);
1212 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1213 return 1;
1214 }
1215
1216 return 1;
1217 }
1218
1219 return 0;
1220 });
1221
1222 vector<DNSRecord> ret;
1223 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1224 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1225 BOOST_CHECK_GT(ret.size(), 0);
1226 BOOST_CHECK_EQUAL(count, 2);
1227 }
1228
1229 BOOST_AUTO_TEST_CASE(test_cname_depth) {
1230 std::unique_ptr<SyncRes> sr;
1231 initSR(sr);
1232
1233 primeHints();
1234
1235 size_t depth = 0;
1236 const DNSName target("cname.powerdns.com.");
1237
1238 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) {
1239
1240 if (isRootServer(ip)) {
1241
1242 setLWResult(res, 0, false, false, true);
1243 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1244 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1245 return 1;
1246 } else if (ip == ComboAddress("192.0.2.1:53")) {
1247
1248 setLWResult(res, 0, true, false, false);
1249 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1250 depth++;
1251 return 1;
1252 }
1253
1254 return 0;
1255 });
1256
1257 vector<DNSRecord> ret;
1258 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1259 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1260 BOOST_CHECK_EQUAL(ret.size(), depth);
1261 /* we have an arbitrary limit at 10 when following a CNAME chain */
1262 BOOST_CHECK_EQUAL(depth, 10 + 2);
1263 }
1264
1265 BOOST_AUTO_TEST_CASE(test_time_limit) {
1266 std::unique_ptr<SyncRes> sr;
1267 initSR(sr);
1268
1269 primeHints();
1270
1271 size_t queries = 0;
1272 const DNSName target("cname.powerdns.com.");
1273
1274 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) {
1275
1276 queries++;
1277
1278 if (isRootServer(ip)) {
1279 setLWResult(res, 0, false, false, true);
1280 /* Pretend that this query took 2000 ms */
1281 res->d_usec = 2000;
1282
1283 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1284 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1285 return 1;
1286 } else if (ip == ComboAddress("192.0.2.1:53")) {
1287
1288 setLWResult(res, 0, true, false, false);
1289 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1290 return 1;
1291 }
1292
1293 return 0;
1294 });
1295
1296 /* Set the maximum time to 1 ms */
1297 SyncRes::s_maxtotusec = 1000;
1298
1299 try {
1300 vector<DNSRecord> ret;
1301 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1302 BOOST_CHECK(false);
1303 }
1304 catch(const ImmediateServFailException& e) {
1305 }
1306 BOOST_CHECK_EQUAL(queries, 1);
1307 }
1308
1309 BOOST_AUTO_TEST_CASE(test_referral_depth) {
1310 std::unique_ptr<SyncRes> sr;
1311 initSR(sr);
1312
1313 primeHints();
1314
1315 size_t queries = 0;
1316 const DNSName target("www.powerdns.com.");
1317
1318 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) {
1319
1320 queries++;
1321
1322 if (isRootServer(ip)) {
1323 setLWResult(res, 0, false, false, true);
1324
1325 if (domain == DNSName("www.powerdns.com.")) {
1326 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1327 }
1328 else if (domain == DNSName("ns.powerdns.com.")) {
1329 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1330 }
1331 else if (domain == DNSName("ns1.powerdns.org.")) {
1332 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1333 }
1334 else if (domain == DNSName("ns2.powerdns.org.")) {
1335 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1336 }
1337 else if (domain == DNSName("ns3.powerdns.org.")) {
1338 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1339 }
1340 else if (domain == DNSName("ns4.powerdns.org.")) {
1341 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1342 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1343 }
1344
1345 return 1;
1346 } else if (ip == ComboAddress("192.0.2.1:53")) {
1347
1348 setLWResult(res, 0, true, false, false);
1349 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1350 return 1;
1351 }
1352
1353 return 0;
1354 });
1355
1356 /* Set the maximum depth low */
1357 SyncRes::s_maxdepth = 10;
1358
1359 try {
1360 vector<DNSRecord> ret;
1361 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1362 BOOST_CHECK(false);
1363 }
1364 catch(const ImmediateServFailException& e) {
1365 }
1366 }
1367
1368 BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1369 std::unique_ptr<SyncRes> sr;
1370 initSR(sr);
1371
1372 primeHints();
1373
1374 size_t queries = 0;
1375 const DNSName target("cname.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) {
1378
1379 queries++;
1380
1381 if (isRootServer(ip)) {
1382
1383 setLWResult(res, 0, false, false, true);
1384 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1385 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1386 return 1;
1387 } else if (ip == ComboAddress("192.0.2.1:53")) {
1388
1389 setLWResult(res, 0, true, false, false);
1390 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1391 return 1;
1392 }
1393
1394 return 0;
1395 });
1396
1397 /* Set the maximum number of questions very low */
1398 SyncRes::s_maxqperq = 5;
1399
1400 try {
1401 vector<DNSRecord> ret;
1402 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1403 BOOST_CHECK(false);
1404 }
1405 catch(const ImmediateServFailException& e) {
1406 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1407 }
1408 }
1409
1410 BOOST_AUTO_TEST_CASE(test_throttled_server) {
1411 std::unique_ptr<SyncRes> sr;
1412 initSR(sr);
1413
1414 primeHints();
1415
1416 const DNSName target("throttled.powerdns.com.");
1417 const ComboAddress ns("192.0.2.1:53");
1418 size_t queriesToNS = 0;
1419
1420 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) {
1421
1422 if (isRootServer(ip)) {
1423
1424 setLWResult(res, 0, false, false, true);
1425 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1426 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1427 return 1;
1428 } else if (ip == ns) {
1429
1430 queriesToNS++;
1431
1432 setLWResult(res, 0, true, false, false);
1433 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1434
1435 return 1;
1436 }
1437
1438 return 0;
1439 });
1440
1441 /* mark ns as down */
1442 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, 10000);
1443
1444 vector<DNSRecord> ret;
1445 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1446 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1447 BOOST_CHECK_EQUAL(ret.size(), 0);
1448 /* we should not have sent any queries to ns */
1449 BOOST_CHECK_EQUAL(queriesToNS, 0);
1450 }
1451
1452 BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1453 std::unique_ptr<SyncRes> sr;
1454 initSR(sr);
1455
1456 primeHints();
1457
1458 const ComboAddress ns("192.0.2.1:53");
1459
1460 const size_t blocks = 10;
1461 /* mark ns as down for 'blocks' queries */
1462 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, blocks);
1463
1464 for (size_t idx = 0; idx < blocks; idx++) {
1465 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1466 }
1467
1468 /* we have been throttled 'blocks' times, we should not be throttled anymore */
1469 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1470 }
1471
1472 BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1473 std::unique_ptr<SyncRes> sr;
1474 initSR(sr);
1475
1476 primeHints();
1477
1478 const ComboAddress ns("192.0.2.1:53");
1479
1480 const size_t seconds = 1;
1481 /* mark ns as down for 'seconds' seconds */
1482 SyncRes::doThrottle(time(nullptr), ns, seconds, 10000);
1483
1484 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1485
1486 sleep(seconds + 1);
1487
1488 /* we should not be throttled anymore */
1489 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1490 }
1491
1492 BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1493 std::unique_ptr<SyncRes> sr;
1494 initSR(sr);
1495
1496 primeHints();
1497
1498 const DNSName target("throttled.powerdns.com.");
1499 const ComboAddress ns("192.0.2.1:53");
1500 size_t queriesToNS = 0;
1501
1502 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) {
1503
1504 if (isRootServer(ip)) {
1505
1506 setLWResult(res, 0, false, false, true);
1507 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1508 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1509 return 1;
1510 } else if (ip == ns) {
1511
1512 queriesToNS++;
1513
1514 setLWResult(res, 0, true, false, false);
1515 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1516
1517 return 1;
1518 }
1519
1520 return 0;
1521 });
1522
1523 /* prevent querying this NS */
1524 SyncRes::addDontQuery(Netmask(ns));
1525
1526 vector<DNSRecord> ret;
1527 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1528 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1529 BOOST_CHECK_EQUAL(ret.size(), 0);
1530 /* we should not have sent any queries to ns */
1531 BOOST_CHECK_EQUAL(queriesToNS, 0);
1532 }
1533
1534 BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1535 std::unique_ptr<SyncRes> sr;
1536 initSR(sr);
1537
1538 primeHints();
1539
1540 const DNSName target1("powerdns.com.");
1541 const DNSName target2("notpowerdns.com.");
1542 const ComboAddress ns("192.0.2.1:53");
1543 size_t queriesCount = 0;
1544
1545 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) {
1546
1547 queriesCount++;
1548
1549 if (isRootServer(ip)) {
1550
1551 if (domain == target1) {
1552 setLWResult(res, RCode::NXDomain, true, false, true);
1553 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1554 }
1555 else {
1556 setLWResult(res, 0, true, false, true);
1557 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1558 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1559 }
1560
1561 return 1;
1562 } else if (ip == ns) {
1563
1564 setLWResult(res, 0, true, false, false);
1565 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1566
1567 return 1;
1568 }
1569
1570 return 0;
1571 });
1572
1573 vector<DNSRecord> ret;
1574 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1575 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1576 BOOST_CHECK_EQUAL(ret.size(), 1);
1577 /* one for target1 and one for the entire TLD */
1578 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1579
1580 ret.clear();
1581 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1582 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1583 BOOST_CHECK_EQUAL(ret.size(), 1);
1584 /* one for target1 and one for the entire TLD */
1585 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1586
1587 /* we should have sent only one query */
1588 BOOST_CHECK_EQUAL(queriesCount, 1);
1589 }
1590
1591 BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1592 std::unique_ptr<SyncRes> sr;
1593 init();
1594 initSR(sr, true, false);
1595
1596 primeHints();
1597
1598 const DNSName target1("powerdns.com.");
1599 const DNSName target2("notpowerdns.com.");
1600 const ComboAddress ns("192.0.2.1:53");
1601 size_t queriesCount = 0;
1602
1603 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1604 We should add target1 to the negcache, but not "com.". */
1605
1606 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) {
1607
1608 queriesCount++;
1609
1610 if (isRootServer(ip)) {
1611
1612 if (domain == target1) {
1613 setLWResult(res, RCode::NXDomain, true, false, true);
1614 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1615 }
1616 else {
1617 setLWResult(res, 0, true, false, true);
1618 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1619 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1620 }
1621
1622 return 1;
1623 } else if (ip == ns) {
1624
1625 setLWResult(res, 0, true, false, false);
1626 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1627
1628 return 1;
1629 }
1630
1631 return 0;
1632 });
1633
1634 vector<DNSRecord> ret;
1635 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1636 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1637 BOOST_CHECK_EQUAL(ret.size(), 1);
1638
1639 /* even with root-nx-trust on and a NX answer from the root,
1640 we should not have cached the entire TLD this time. */
1641 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1642
1643 ret.clear();
1644 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1645 BOOST_CHECK_EQUAL(res, RCode::NoError);
1646 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1647 BOOST_REQUIRE(ret[0].d_type == QType::A);
1648 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1649 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1650
1651 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1652
1653 BOOST_CHECK_EQUAL(queriesCount, 3);
1654 }
1655
1656 BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1657 std::unique_ptr<SyncRes> sr;
1658 initSR(sr);
1659
1660 primeHints();
1661
1662 const DNSName target1("powerdns.com.");
1663 const DNSName target2("notpowerdns.com.");
1664 const ComboAddress ns("192.0.2.1:53");
1665 size_t queriesCount = 0;
1666
1667 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) {
1668
1669 queriesCount++;
1670
1671 if (isRootServer(ip)) {
1672
1673 if (domain == target1) {
1674 setLWResult(res, RCode::NXDomain, true, false, true);
1675 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1676 }
1677 else {
1678 setLWResult(res, 0, true, false, true);
1679 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1680 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1681 }
1682
1683 return 1;
1684 } else if (ip == ns) {
1685
1686 setLWResult(res, 0, true, false, false);
1687 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1688
1689 return 1;
1690 }
1691
1692 return 0;
1693 });
1694
1695 SyncRes::s_rootNXTrust = false;
1696
1697 vector<DNSRecord> ret;
1698 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1699 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1700 BOOST_CHECK_EQUAL(ret.size(), 1);
1701 /* one for target1 */
1702 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1703
1704 ret.clear();
1705 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1706 BOOST_CHECK_EQUAL(res, RCode::NoError);
1707 BOOST_CHECK_EQUAL(ret.size(), 1);
1708 /* one for target1 */
1709 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1710
1711 /* we should have sent three queries */
1712 BOOST_CHECK_EQUAL(queriesCount, 3);
1713 }
1714
1715 BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1716 std::unique_ptr<SyncRes> sr;
1717 initSR(sr);
1718
1719 primeHints();
1720
1721 const DNSName target("www.powerdns.com.");
1722 const DNSName cnameTarget("cname.powerdns.com.");
1723
1724 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
1725
1726 EDNSSubnetOpts incomingECS;
1727 incomingECS.source = Netmask("192.0.2.128/32");
1728 sr->setIncomingECSFound(true);
1729 sr->setIncomingECS(incomingECS);
1730
1731 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) {
1732
1733 BOOST_REQUIRE(srcmask);
1734 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1735
1736 if (isRootServer(ip)) {
1737 setLWResult(res, 0, false, false, true);
1738 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1739 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1740
1741 return 1;
1742 } else if (ip == ComboAddress("192.0.2.1:53")) {
1743 if (domain == target) {
1744 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
1745 setLWResult(res, RCode::NXDomain, true, false, true);
1746 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1747 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1748 }
1749 else if (domain == cnameTarget) {
1750 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
1751 but we might if we still chase the CNAME. */
1752 setLWResult(res, RCode::NXDomain, true, false, true);
1753 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1754 }
1755
1756 return 1;
1757 }
1758
1759 return 0;
1760 });
1761
1762 vector<DNSRecord> ret;
1763 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1764 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1765 BOOST_CHECK_EQUAL(ret.size(), 2);
1766 /* no negative cache entry because the response was variable */
1767 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
1768 }
1769
1770 BOOST_AUTO_TEST_CASE(test_ns_speed) {
1771 std::unique_ptr<SyncRes> sr;
1772 initSR(sr);
1773
1774 primeHints();
1775
1776 const DNSName target("powerdns.com.");
1777
1778 std::map<ComboAddress, uint64_t> nsCounts;
1779
1780 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) {
1781
1782 if (isRootServer(ip)) {
1783 setLWResult(res, 0, false, false, true);
1784 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1785 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1786 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1787
1788 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1789 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1790 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1791 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
1792 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
1793 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
1794
1795 return 1;
1796 } else {
1797 nsCounts[ip]++;
1798
1799 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
1800 BOOST_CHECK_LT(nsCounts.size(), 3);
1801
1802 /* let's time out on pdns-public-ns2.powerdns.com. */
1803 return 0;
1804 }
1805 else if (ip == ComboAddress("192.0.2.1:53")) {
1806 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1807
1808 setLWResult(res, 0, true, false, true);
1809 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1810 return 1;
1811 }
1812
1813 return 0;
1814 }
1815
1816 return 0;
1817 });
1818
1819 struct timeval now;
1820 gettimeofday(&now, 0);
1821
1822 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
1823 then pdns-public-ns1.powerdns.com. on IPv4 */
1824 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
1825 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
1826 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
1827 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
1828 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
1829 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
1830
1831 vector<DNSRecord> ret;
1832 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1833 BOOST_CHECK_EQUAL(res, RCode::NoError);
1834 BOOST_CHECK_EQUAL(ret.size(), 1);
1835 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1836 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
1837 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
1838 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
1839 }
1840
1841 BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
1842 std::unique_ptr<SyncRes> sr;
1843 initSR(sr);
1844
1845 primeHints();
1846
1847 const DNSName target("powerdns.com.");
1848
1849 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) {
1850
1851 if (isRootServer(ip)) {
1852 setLWResult(res, 0, false, false, true);
1853 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1854
1855 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1856
1857 return 1;
1858 } else if (ip == ComboAddress("192.0.2.1:53")) {
1859 setLWResult(res, 0, true, false, true);
1860 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1861 return 1;
1862 }
1863
1864 return 0;
1865 });
1866
1867 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
1868 time_t now = time(nullptr);
1869 std::vector<DNSRecord> records;
1870 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1871 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
1872
1873 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1874
1875 vector<DNSRecord> ret;
1876 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1877 BOOST_CHECK_EQUAL(res, RCode::NoError);
1878 BOOST_CHECK_EQUAL(ret.size(), 1);
1879 }
1880
1881 BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
1882 std::unique_ptr<SyncRes> sr;
1883 initSR(sr);
1884
1885 primeHints();
1886
1887 const DNSName target("powerdns.com.");
1888 size_t queriesCount = 0;
1889
1890 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) {
1891
1892 queriesCount++;
1893
1894 if (isRootServer(ip) && domain == target) {
1895 setLWResult(res, 0, false, false, true);
1896 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1897 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1898 return 1;
1899 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
1900 setLWResult(res, 0, true, false, true);
1901 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1902 return 1;
1903 }
1904
1905 return 0;
1906 });
1907
1908 vector<DNSRecord> ret;
1909 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1910 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1911 BOOST_CHECK_EQUAL(ret.size(), 0);
1912 /* one query to get NSs, then A and AAAA for each NS */
1913 BOOST_CHECK_EQUAL(queriesCount, 5);
1914 }
1915
1916 BOOST_AUTO_TEST_CASE(test_cache_hit) {
1917 std::unique_ptr<SyncRes> sr;
1918 initSR(sr);
1919
1920 primeHints();
1921
1922 const DNSName target("powerdns.com.");
1923
1924 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) {
1925
1926 return 0;
1927 });
1928
1929 /* we populate the cache with eveything we need */
1930 time_t now = time(nullptr);
1931 std::vector<DNSRecord> records;
1932 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1933
1934 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
1935 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1936
1937 vector<DNSRecord> ret;
1938 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1939 BOOST_CHECK_EQUAL(res, RCode::NoError);
1940 BOOST_CHECK_EQUAL(ret.size(), 1);
1941 }
1942
1943 BOOST_AUTO_TEST_CASE(test_no_rd) {
1944 std::unique_ptr<SyncRes> sr;
1945 initSR(sr);
1946
1947 primeHints();
1948
1949 const DNSName target("powerdns.com.");
1950 size_t queriesCount = 0;
1951
1952 sr->setCacheOnly();
1953
1954 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) {
1955
1956 queriesCount++;
1957 return 0;
1958 });
1959
1960 vector<DNSRecord> ret;
1961 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1962 BOOST_CHECK_EQUAL(res, RCode::NoError);
1963 BOOST_CHECK_EQUAL(ret.size(), 0);
1964 BOOST_CHECK_EQUAL(queriesCount, 0);
1965 }
1966
1967 BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
1968 std::unique_ptr<SyncRes> sr;
1969 initSR(sr);
1970
1971 primeHints();
1972
1973 const DNSName target("cachettl.powerdns.com.");
1974 const ComboAddress ns("192.0.2.1:53");
1975
1976 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) {
1977
1978 if (isRootServer(ip)) {
1979
1980 setLWResult(res, 0, false, false, true);
1981 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1982 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
1983 return 1;
1984 } else if (ip == ns) {
1985
1986 setLWResult(res, 0, true, false, false);
1987 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
1988
1989 return 1;
1990 }
1991
1992 return 0;
1993 });
1994
1995 const time_t now = time(nullptr);
1996 SyncRes::s_minimumTTL = 60;
1997 SyncRes::s_maxcachettl = 3600;
1998
1999 vector<DNSRecord> ret;
2000 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2001 BOOST_CHECK_EQUAL(res, RCode::NoError);
2002 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2003 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
2004
2005 const ComboAddress who;
2006 vector<DNSRecord> cached;
2007 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
2008 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2009 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2010 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
2011
2012 cached.clear();
2013 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
2014 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2015 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2016 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
2017 }
2018
2019 BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
2020 std::unique_ptr<SyncRes> sr;
2021 initSR(sr);
2022
2023 primeHints();
2024
2025 const DNSName target("powerdns.com.");
2026
2027 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) {
2028
2029 if (isRootServer(ip)) {
2030 setLWResult(res, 0, false, false, true);
2031 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2032
2033 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2034
2035 return 1;
2036 } else if (ip == ComboAddress("192.0.2.1:53")) {
2037 setLWResult(res, 0, true, false, true);
2038 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2039 return 1;
2040 }
2041
2042 return 0;
2043 });
2044
2045 /* we populate the cache with entries that expired 60s ago*/
2046 time_t now = time(nullptr);
2047 std::vector<DNSRecord> records;
2048 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2049 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
2050
2051 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
2052
2053 vector<DNSRecord> ret;
2054 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2055 BOOST_CHECK_EQUAL(res, RCode::NoError);
2056 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2057 BOOST_REQUIRE(ret[0].d_type == QType::A);
2058 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
2059 }
2060
2061 BOOST_AUTO_TEST_CASE(test_delegation_only) {
2062 std::unique_ptr<SyncRes> sr;
2063 initSR(sr);
2064
2065 primeHints();
2066
2067 /* Thanks, Verisign */
2068 SyncRes::addDelegationOnly(DNSName("com."));
2069 SyncRes::addDelegationOnly(DNSName("net."));
2070
2071 const DNSName target("nx-powerdns.com.");
2072
2073 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) {
2074
2075 if (isRootServer(ip)) {
2076 setLWResult(res, 0, false, false, true);
2077 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2078 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2079 return 1;
2080 } else if (ip == ComboAddress("192.0.2.1:53")) {
2081
2082 setLWResult(res, 0, true, false, true);
2083 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2084 return 1;
2085 }
2086
2087 return 0;
2088 });
2089
2090 vector<DNSRecord> ret;
2091 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2092 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2093 BOOST_CHECK_EQUAL(ret.size(), 0);
2094 }
2095
2096 BOOST_AUTO_TEST_CASE(test_unauth_any) {
2097 std::unique_ptr<SyncRes> sr;
2098 initSR(sr);
2099
2100 primeHints();
2101
2102 const DNSName target("powerdns.com.");
2103
2104 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) {
2105
2106 if (isRootServer(ip)) {
2107 setLWResult(res, 0, false, false, true);
2108 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2109 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2110 return 1;
2111 } else if (ip == ComboAddress("192.0.2.1:53")) {
2112
2113 setLWResult(res, 0, false, false, true);
2114 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2115 return 1;
2116 }
2117
2118 return 0;
2119 });
2120
2121 vector<DNSRecord> ret;
2122 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2123 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2124 BOOST_CHECK_EQUAL(ret.size(), 0);
2125 }
2126
2127 BOOST_AUTO_TEST_CASE(test_no_data) {
2128 std::unique_ptr<SyncRes> sr;
2129 initSR(sr);
2130
2131 primeHints();
2132
2133 const DNSName target("powerdns.com.");
2134
2135 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) {
2136
2137 setLWResult(res, 0, true, false, true);
2138 return 1;
2139 });
2140
2141 vector<DNSRecord> ret;
2142 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2143 BOOST_CHECK_EQUAL(res, RCode::NoError);
2144 BOOST_CHECK_EQUAL(ret.size(), 0);
2145 }
2146
2147 BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2148 std::unique_ptr<SyncRes> sr;
2149 initSR(sr);
2150
2151 primeHints();
2152
2153 const DNSName target("powerdns.com.");
2154
2155 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) {
2156
2157 setLWResult(res, 0, true, false, true);
2158 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2159 addRecordToLW(res, domain, QType::ANY, "0 0");
2160 addRecordToLW(res, domain, QType::OPT, "");
2161 return 1;
2162 });
2163
2164 vector<DNSRecord> ret;
2165 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2166 BOOST_CHECK_EQUAL(res, RCode::NoError);
2167 BOOST_CHECK_EQUAL(ret.size(), 1);
2168 }
2169
2170 BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2171 std::unique_ptr<SyncRes> sr;
2172 initSR(sr);
2173
2174 primeHints();
2175
2176 const DNSName target("powerdns.com.");
2177
2178 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) {
2179
2180 setLWResult(res, 0, true, false, true);
2181 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2182 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2183 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2184 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2185 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2186 return 1;
2187 });
2188
2189 vector<DNSRecord> ret;
2190 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2191 BOOST_CHECK_EQUAL(res, RCode::NoError);
2192 BOOST_CHECK_EQUAL(ret.size(), 1);
2193 }
2194
2195 BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2196 std::unique_ptr<SyncRes> sr;
2197 initSR(sr, true);
2198
2199 primeHints();
2200
2201 const DNSName target("powerdns.com.");
2202
2203 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) {
2204
2205 setLWResult(res, 0, true, false, true);
2206 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2207 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2208 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2209 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2210 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2211 return 1;
2212 });
2213
2214 vector<DNSRecord> ret;
2215 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2216 BOOST_CHECK_EQUAL(res, RCode::NoError);
2217 BOOST_CHECK_EQUAL(ret.size(), 4);
2218 }
2219
2220 BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2221 std::unique_ptr<SyncRes> sr;
2222 initSR(sr);
2223
2224 primeHints();
2225
2226 const DNSName target("powerdns.com.");
2227
2228 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) {
2229
2230 setLWResult(res, RCode::NXDomain, true, false, true);
2231 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2232 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2233 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2234 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2235 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2236 return 1;
2237 });
2238
2239 vector<DNSRecord> ret;
2240 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2241 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2242 BOOST_CHECK_EQUAL(ret.size(), 1);
2243 }
2244
2245 BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2246 std::unique_ptr<SyncRes> sr;
2247 initSR(sr, true);
2248
2249 primeHints();
2250
2251 const DNSName target("powerdns.com.");
2252
2253 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) {
2254
2255 setLWResult(res, RCode::NXDomain, true, false, true);
2256 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2257 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2258 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2259 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2260 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2261 return 1;
2262 });
2263
2264 vector<DNSRecord> ret;
2265 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2266 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2267 BOOST_CHECK_EQUAL(ret.size(), 4);
2268 }
2269
2270 BOOST_AUTO_TEST_CASE(test_qclass_none) {
2271 std::unique_ptr<SyncRes> sr;
2272 initSR(sr);
2273
2274 primeHints();
2275
2276 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2277 size_t queriesCount = 0;
2278
2279 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) {
2280
2281 queriesCount++;
2282 return 0;
2283 });
2284
2285 const DNSName target("powerdns.com.");
2286 vector<DNSRecord> ret;
2287 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2288 BOOST_CHECK_EQUAL(res, -1);
2289 BOOST_CHECK_EQUAL(ret.size(), 0);
2290 BOOST_CHECK_EQUAL(queriesCount, 0);
2291 }
2292
2293 BOOST_AUTO_TEST_CASE(test_special_types) {
2294 std::unique_ptr<SyncRes> sr;
2295 initSR(sr);
2296
2297 primeHints();
2298
2299 /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
2300 size_t queriesCount = 0;
2301
2302 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) {
2303
2304 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2305 queriesCount++;
2306 return 0;
2307 });
2308
2309 const DNSName target("powerdns.com.");
2310 vector<DNSRecord> ret;
2311 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2312 BOOST_CHECK_EQUAL(res, -1);
2313 BOOST_CHECK_EQUAL(ret.size(), 0);
2314 BOOST_CHECK_EQUAL(queriesCount, 0);
2315
2316 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2317 BOOST_CHECK_EQUAL(res, -1);
2318 BOOST_CHECK_EQUAL(ret.size(), 0);
2319 BOOST_CHECK_EQUAL(queriesCount, 0);
2320
2321 res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2322 BOOST_CHECK_EQUAL(res, -1);
2323 BOOST_CHECK_EQUAL(ret.size(), 0);
2324 BOOST_CHECK_EQUAL(queriesCount, 0);
2325
2326 res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
2327 BOOST_CHECK_EQUAL(res, -1);
2328 BOOST_CHECK_EQUAL(ret.size(), 0);
2329 BOOST_CHECK_EQUAL(queriesCount, 0);
2330 }
2331
2332 BOOST_AUTO_TEST_CASE(test_special_names) {
2333 std::unique_ptr<SyncRes> sr;
2334 initSR(sr);
2335
2336 primeHints();
2337
2338 /* special names should be handled internally */
2339
2340 size_t queriesCount = 0;
2341
2342 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) {
2343
2344 queriesCount++;
2345 return 0;
2346 });
2347
2348 vector<DNSRecord> ret;
2349 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
2350 BOOST_CHECK_EQUAL(res, RCode::NoError);
2351 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2352 BOOST_CHECK(ret[0].d_type == QType::PTR);
2353 BOOST_CHECK_EQUAL(queriesCount, 0);
2354
2355 ret.clear();
2356 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
2357 BOOST_CHECK_EQUAL(res, RCode::NoError);
2358 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2359 BOOST_CHECK(ret[0].d_type == QType::PTR);
2360 BOOST_CHECK_EQUAL(queriesCount, 0);
2361
2362 ret.clear();
2363 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);
2364 BOOST_CHECK_EQUAL(res, RCode::NoError);
2365 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2366 BOOST_CHECK(ret[0].d_type == QType::PTR);
2367 BOOST_CHECK_EQUAL(queriesCount, 0);
2368
2369 ret.clear();
2370 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);
2371 BOOST_CHECK_EQUAL(res, RCode::NoError);
2372 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2373 BOOST_CHECK(ret[0].d_type == QType::PTR);
2374 BOOST_CHECK_EQUAL(queriesCount, 0);
2375
2376 ret.clear();
2377 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
2378 BOOST_CHECK_EQUAL(res, RCode::NoError);
2379 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2380 BOOST_CHECK(ret[0].d_type == QType::A);
2381 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2382 BOOST_CHECK_EQUAL(queriesCount, 0);
2383
2384 ret.clear();
2385 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
2386 BOOST_CHECK_EQUAL(res, RCode::NoError);
2387 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2388 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2389 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2390 BOOST_CHECK_EQUAL(queriesCount, 0);
2391
2392 ret.clear();
2393 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
2394 BOOST_CHECK_EQUAL(res, RCode::NoError);
2395 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2396 for (const auto& rec : ret) {
2397 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2398 if (rec.d_type == QType::A) {
2399 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2400 }
2401 else {
2402 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2403 }
2404 }
2405 BOOST_CHECK_EQUAL(queriesCount, 0);
2406
2407 ret.clear();
2408 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
2409 BOOST_CHECK_EQUAL(res, RCode::NoError);
2410 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2411 BOOST_CHECK(ret[0].d_type == QType::TXT);
2412 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2413 BOOST_CHECK_EQUAL(queriesCount, 0);
2414
2415 ret.clear();
2416 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
2417 BOOST_CHECK_EQUAL(res, RCode::NoError);
2418 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2419 BOOST_CHECK(ret[0].d_type == QType::TXT);
2420 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2421 BOOST_CHECK_EQUAL(queriesCount, 0);
2422
2423 ret.clear();
2424 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
2425 BOOST_CHECK_EQUAL(res, RCode::NoError);
2426 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2427 BOOST_CHECK(ret[0].d_type == QType::TXT);
2428 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2429 BOOST_CHECK_EQUAL(queriesCount, 0);
2430
2431 ret.clear();
2432 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
2433 BOOST_CHECK_EQUAL(res, RCode::NoError);
2434 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2435 BOOST_CHECK(ret[0].d_type == QType::TXT);
2436 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2437 BOOST_CHECK_EQUAL(queriesCount, 0);
2438
2439 ret.clear();
2440 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
2441 BOOST_CHECK_EQUAL(res, RCode::NoError);
2442 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2443 BOOST_CHECK(ret[0].d_type == QType::TXT);
2444 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2445 BOOST_CHECK_EQUAL(queriesCount, 0);
2446
2447 ret.clear();
2448 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
2449 BOOST_CHECK_EQUAL(res, RCode::NoError);
2450 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2451 BOOST_CHECK(ret[0].d_type == QType::TXT);
2452 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2453 BOOST_CHECK_EQUAL(queriesCount, 0);
2454 }
2455
2456 BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2457 std::unique_ptr<SyncRes> sr;
2458 initSR(sr);
2459
2460 primeHints();
2461
2462 const DNSName target("rpz.powerdns.com.");
2463 const ComboAddress ns("192.0.2.1:53");
2464
2465 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) {
2466
2467 if (isRootServer(ip)) {
2468 setLWResult(res, false, true, false, true);
2469 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2470 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2471 return 1;
2472 } else if (ip == ns) {
2473
2474 setLWResult(res, 0, true, false, true);
2475 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2476 return 1;
2477 }
2478
2479 return 0;
2480 });
2481
2482 DNSFilterEngine::Policy pol;
2483 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2484 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2485 zone->setName("Unit test policy 0");
2486 zone->addNSIPTrigger(Netmask(ns, 32), pol);
2487 auto luaconfsCopy = g_luaconfs.getCopy();
2488 luaconfsCopy.dfe.addZone(zone);
2489 g_luaconfs.setState(luaconfsCopy);
2490
2491 vector<DNSRecord> ret;
2492 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2493 BOOST_CHECK_EQUAL(res, -2);
2494 BOOST_CHECK_EQUAL(ret.size(), 0);
2495 }
2496
2497 BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2498 std::unique_ptr<SyncRes> sr;
2499 initSR(sr);
2500
2501 primeHints();
2502
2503 const DNSName target("rpz.powerdns.com.");
2504 const ComboAddress ns("[2001:DB8::42]:53");
2505
2506 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) {
2507
2508 if (isRootServer(ip)) {
2509 setLWResult(res, 0, false, false, true);
2510 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2511 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2512 return 1;
2513 } else if (ip == ns) {
2514
2515 setLWResult(res, 0, true, false, true);
2516 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2517 return 1;
2518 }
2519
2520 return 0;
2521 });
2522
2523 DNSFilterEngine::Policy pol;
2524 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2525 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2526 zone->setName("Unit test policy 0");
2527 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2528 auto luaconfsCopy = g_luaconfs.getCopy();
2529 luaconfsCopy.dfe.addZone(zone);
2530 g_luaconfs.setState(luaconfsCopy);
2531
2532 vector<DNSRecord> ret;
2533 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2534 BOOST_CHECK_EQUAL(res, -2);
2535 BOOST_CHECK_EQUAL(ret.size(), 0);
2536 }
2537
2538 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2539 std::unique_ptr<SyncRes> sr;
2540 initSR(sr);
2541
2542 primeHints();
2543
2544 const DNSName target("rpz.powerdns.com.");
2545 const ComboAddress ns("192.0.2.1:53");
2546 const DNSName nsName("ns1.powerdns.com.");
2547
2548 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) {
2549
2550 if (isRootServer(ip)) {
2551 setLWResult(res, 0, false, false, true);
2552 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2553 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2554 return 1;
2555 } else if (ip == ns) {
2556
2557 setLWResult(res, 0, true, false, true);
2558 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2559 return 1;
2560 }
2561
2562 return 0;
2563 });
2564
2565 DNSFilterEngine::Policy pol;
2566 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2567 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2568 zone->setName("Unit test policy 0");
2569 zone->addNSTrigger(nsName, pol);
2570 auto luaconfsCopy = g_luaconfs.getCopy();
2571 luaconfsCopy.dfe.addZone(zone);
2572 g_luaconfs.setState(luaconfsCopy);
2573
2574 vector<DNSRecord> ret;
2575 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2576 BOOST_CHECK_EQUAL(res, -2);
2577 BOOST_CHECK_EQUAL(ret.size(), 0);
2578 }
2579
2580 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2581 std::unique_ptr<SyncRes> sr;
2582 initSR(sr);
2583
2584 primeHints();
2585
2586 const DNSName target("rpz.powerdns.com.");
2587 const ComboAddress ns("192.0.2.1:53");
2588 const DNSName nsName("ns1.powerdns.com.");
2589
2590 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) {
2591
2592 if (isRootServer(ip)) {
2593 setLWResult(res, 0, false, false, true);
2594 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2595 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2596 return 1;
2597 } else if (ip == ns) {
2598
2599 setLWResult(res, 0, true, false, true);
2600 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2601 return 1;
2602 }
2603
2604 return 0;
2605 });
2606
2607 DNSFilterEngine::Policy pol;
2608 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2609 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2610 zone->setName("Unit test policy 0");
2611 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2612 zone->addNSTrigger(nsName, pol);
2613 auto luaconfsCopy = g_luaconfs.getCopy();
2614 luaconfsCopy.dfe.addZone(zone);
2615 g_luaconfs.setState(luaconfsCopy);
2616
2617 /* RPZ is disabled for this query, we should not be blocked */
2618 sr->setWantsRPZ(false);
2619
2620 vector<DNSRecord> ret;
2621 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2622 BOOST_CHECK_EQUAL(res, RCode::NoError);
2623 BOOST_CHECK_EQUAL(ret.size(), 1);
2624 }
2625
2626 BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2627 std::unique_ptr<SyncRes> sr;
2628 initSR(sr);
2629
2630 primeHints();
2631
2632 const DNSName target("powerdns.com.");
2633 const ComboAddress ns("192.0.2.1:53");
2634 const ComboAddress forwardedNS("192.0.2.42:53");
2635
2636 SyncRes::AuthDomain ad;
2637 ad.d_rdForward = false;
2638 ad.d_servers.push_back(forwardedNS);
2639 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2640
2641 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) {
2642
2643 if (ip == forwardedNS) {
2644 BOOST_CHECK_EQUAL(sendRDQuery, false);
2645
2646 setLWResult(res, 0, true, false, true);
2647 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2648 return 1;
2649 }
2650
2651 return 0;
2652 });
2653
2654 /* simulate a no-RD query */
2655 sr->setCacheOnly();
2656
2657 vector<DNSRecord> ret;
2658 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2659 BOOST_CHECK_EQUAL(res, RCode::NoError);
2660 BOOST_CHECK_EQUAL(ret.size(), 1);
2661 }
2662
2663 BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
2664 std::unique_ptr<SyncRes> sr;
2665 initSR(sr);
2666
2667 primeHints();
2668
2669 const DNSName target("powerdns.com.");
2670 const ComboAddress ns("192.0.2.1:53");
2671 const ComboAddress forwardedNS("192.0.2.42:53");
2672
2673 SyncRes::AuthDomain ad;
2674 ad.d_rdForward = false;
2675 ad.d_servers.push_back(forwardedNS);
2676 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2677
2678 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) {
2679
2680 if (ip == forwardedNS) {
2681 BOOST_CHECK_EQUAL(sendRDQuery, false);
2682
2683 setLWResult(res, 0, true, false, true);
2684 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2685 return 1;
2686 }
2687
2688 return 0;
2689 });
2690
2691 vector<DNSRecord> ret;
2692 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2693 BOOST_CHECK_EQUAL(res, RCode::NoError);
2694 BOOST_CHECK_EQUAL(ret.size(), 1);
2695 }
2696
2697 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
2698 std::unique_ptr<SyncRes> sr;
2699 initSR(sr);
2700
2701 primeHints();
2702
2703 const DNSName target("powerdns.com.");
2704 const ComboAddress ns("192.0.2.1:53");
2705 const ComboAddress forwardedNS("192.0.2.42:53");
2706
2707 SyncRes::AuthDomain ad;
2708 ad.d_rdForward = true;
2709 ad.d_servers.push_back(forwardedNS);
2710 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2711
2712 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) {
2713
2714 if (ip == forwardedNS) {
2715 BOOST_CHECK_EQUAL(sendRDQuery, false);
2716
2717 setLWResult(res, 0, true, false, true);
2718 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2719 return 1;
2720 }
2721
2722 return 0;
2723 });
2724
2725 /* simulate a no-RD query */
2726 sr->setCacheOnly();
2727
2728 vector<DNSRecord> ret;
2729 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2730 BOOST_CHECK_EQUAL(res, RCode::NoError);
2731 BOOST_CHECK_EQUAL(ret.size(), 1);
2732 }
2733
2734 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
2735 std::unique_ptr<SyncRes> sr;
2736 initSR(sr);
2737
2738 primeHints();
2739
2740 const DNSName target("powerdns.com.");
2741 const ComboAddress ns("192.0.2.1:53");
2742 const ComboAddress forwardedNS("192.0.2.42:53");
2743
2744 SyncRes::AuthDomain ad;
2745 ad.d_rdForward = true;
2746 ad.d_servers.push_back(forwardedNS);
2747 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2748
2749 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) {
2750
2751 if (ip == forwardedNS) {
2752 BOOST_CHECK_EQUAL(sendRDQuery, true);
2753
2754 setLWResult(res, 0, true, false, true);
2755 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2756 return 1;
2757 }
2758
2759 return 0;
2760 });
2761
2762 vector<DNSRecord> ret;
2763 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2764 BOOST_CHECK_EQUAL(res, RCode::NoError);
2765 BOOST_CHECK_EQUAL(ret.size(), 1);
2766 }
2767
2768 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_oob) {
2769 std::unique_ptr<SyncRes> sr;
2770 init();
2771 initSR(sr, true, false);
2772
2773 primeHints();
2774
2775 size_t queriesCount = 0;
2776 const DNSName target("test.xx.");
2777 const ComboAddress targetAddr("127.0.0.1");
2778 const DNSName ns("localhost.");
2779 const ComboAddress nsAddr("127.0.0.1");
2780 const DNSName authZone("test.xx");
2781
2782 SyncRes::AuthDomain ad;
2783 DNSRecord dr;
2784 dr.d_place = DNSResourceRecord::ANSWER;
2785 dr.d_name = authZone;
2786 dr.d_type = QType::NS;
2787 dr.d_ttl = 1800;
2788 dr.d_content = std::make_shared<NSRecordContent>("localhost.");
2789 ad.d_records.insert(dr);
2790
2791 dr.d_place = DNSResourceRecord::ANSWER;
2792 dr.d_name = authZone;
2793 dr.d_type = QType::A;
2794 dr.d_ttl = 1800;
2795 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
2796 ad.d_records.insert(dr);
2797
2798 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2799
2800 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) {
2801 queriesCount++;
2802 return 0;
2803 });
2804
2805 vector<DNSRecord> ret;
2806 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2807 BOOST_CHECK_EQUAL(res, 0);
2808 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2809 BOOST_CHECK(ret[0].d_type == QType::A);
2810 BOOST_CHECK_EQUAL(queriesCount, 0);
2811 BOOST_CHECK(sr->wasOutOfBand());
2812
2813 /* a second time, to check that the OOB flag is set when the query cache is used */
2814 ret.clear();
2815 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2816 BOOST_CHECK_EQUAL(res, 0);
2817 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2818 BOOST_CHECK(ret[0].d_type == QType::A);
2819 BOOST_CHECK_EQUAL(queriesCount, 0);
2820 BOOST_CHECK(sr->wasOutOfBand());
2821 }
2822
2823 BOOST_AUTO_TEST_CASE(test_auth_zone) {
2824 std::unique_ptr<SyncRes> sr;
2825 initSR(sr);
2826
2827 primeHints();
2828
2829 size_t queriesCount = 0;
2830 const DNSName target("powerdns.com.");
2831 const ComboAddress addr("192.0.2.5");
2832
2833 SyncRes::AuthDomain ad;
2834 ad.d_name = target;
2835 DNSRecord dr;
2836 dr.d_place = DNSResourceRecord::ANSWER;
2837 dr.d_name = target;
2838 dr.d_type = QType::SOA;
2839 dr.d_ttl = 3600;
2840 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2841 ad.d_records.insert(dr);
2842
2843 dr.d_place = DNSResourceRecord::ANSWER;
2844 dr.d_name = target;
2845 dr.d_type = QType::A;
2846 dr.d_ttl = 3600;
2847 dr.d_content = std::make_shared<ARecordContent>(addr);
2848 ad.d_records.insert(dr);
2849
2850 auto map = std::make_shared<SyncRes::domainmap_t>();
2851 (*map)[target] = ad;
2852 SyncRes::setDomainMap(map);
2853
2854 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) {
2855
2856 queriesCount++;
2857 setLWResult(res, 0, true, false, true);
2858 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2859 return 1;
2860 });
2861
2862 vector<DNSRecord> ret;
2863 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2864 BOOST_CHECK_EQUAL(res, RCode::NoError);
2865 BOOST_CHECK_EQUAL(ret.size(), 1);
2866 BOOST_CHECK(ret[0].d_type == QType::A);
2867 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
2868 BOOST_CHECK_EQUAL(queriesCount, 0);
2869 }
2870
2871 BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
2872 std::unique_ptr<SyncRes> sr;
2873 initSR(sr);
2874
2875 primeHints();
2876
2877 size_t queriesCount = 0;
2878 const DNSName target("powerdns.com.");
2879 const DNSName authZone("internal.powerdns.com.");
2880 const ComboAddress addr("192.0.2.5");
2881
2882 SyncRes::AuthDomain ad;
2883 ad.d_name = authZone;
2884 DNSRecord dr;
2885 dr.d_place = DNSResourceRecord::ANSWER;
2886 dr.d_name = authZone;
2887 dr.d_type = QType::SOA;
2888 dr.d_ttl = 3600;
2889 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2890 ad.d_records.insert(dr);
2891
2892 dr.d_place = DNSResourceRecord::ANSWER;
2893 dr.d_name = authZone;
2894 dr.d_type = QType::A;
2895 dr.d_ttl = 3600;
2896 dr.d_content = std::make_shared<ARecordContent>(addr);
2897 ad.d_records.insert(dr);
2898
2899 auto map = std::make_shared<SyncRes::domainmap_t>();
2900 (*map)[authZone] = ad;
2901 SyncRes::setDomainMap(map);
2902
2903 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) {
2904
2905 queriesCount++;
2906
2907 if (domain == target) {
2908 setLWResult(res, 0, true, false, true);
2909 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
2910 return 1;
2911 }
2912
2913 return 0;
2914 });
2915
2916 vector<DNSRecord> ret;
2917 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2918 BOOST_CHECK_EQUAL(res, RCode::NoError);
2919 BOOST_CHECK_EQUAL(ret.size(), 2);
2920 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2921 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
2922 BOOST_CHECK(ret[1].d_type == QType::A);
2923 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
2924 BOOST_CHECK_EQUAL(queriesCount, 1);
2925 }
2926
2927 BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
2928 std::unique_ptr<SyncRes> sr;
2929 initSR(sr);
2930
2931 primeHints();
2932
2933 size_t queriesCount = 0;
2934 const DNSName target("powerdns.com.");
2935 const DNSName externalCNAME("www.open-xchange.com.");
2936 const ComboAddress addr("192.0.2.5");
2937
2938 SyncRes::AuthDomain ad;
2939 ad.d_name = target;
2940 DNSRecord dr;
2941 dr.d_place = DNSResourceRecord::ANSWER;
2942 dr.d_name = target;
2943 dr.d_type = QType::SOA;
2944 dr.d_ttl = 3600;
2945 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2946 ad.d_records.insert(dr);
2947
2948 dr.d_place = DNSResourceRecord::ANSWER;
2949 dr.d_name = target;
2950 dr.d_type = QType::CNAME;
2951 dr.d_ttl = 3600;
2952 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
2953 ad.d_records.insert(dr);
2954
2955 auto map = std::make_shared<SyncRes::domainmap_t>();
2956 (*map)[target] = ad;
2957 SyncRes::setDomainMap(map);
2958
2959 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) {
2960
2961 queriesCount++;
2962
2963 if (domain == externalCNAME) {
2964 setLWResult(res, 0, true, false, true);
2965 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
2966 return 1;
2967 }
2968
2969 return 0;
2970 });
2971
2972 vector<DNSRecord> ret;
2973 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2974 BOOST_CHECK_EQUAL(res, RCode::NoError);
2975 BOOST_CHECK_EQUAL(ret.size(), 2);
2976 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2977 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
2978 BOOST_CHECK(ret[1].d_type == QType::A);
2979 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
2980 BOOST_CHECK_EQUAL(queriesCount, 1);
2981 }
2982
2983 BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
2984 std::unique_ptr<SyncRes> sr;
2985 initSR(sr);
2986
2987 primeHints();
2988
2989 size_t queriesCount = 0;
2990 const DNSName target("nodata.powerdns.com.");
2991 const DNSName authZone("powerdns.com");
2992
2993 SyncRes::AuthDomain ad;
2994 ad.d_name = authZone;
2995 DNSRecord dr;
2996 dr.d_place = DNSResourceRecord::ANSWER;
2997 dr.d_name = target;
2998 dr.d_type = QType::A;
2999 dr.d_ttl = 3600;
3000 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3001 ad.d_records.insert(dr);
3002
3003 dr.d_place = DNSResourceRecord::ANSWER;
3004 dr.d_name = authZone;
3005 dr.d_type = QType::SOA;
3006 dr.d_ttl = 3600;
3007 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3008 ad.d_records.insert(dr);
3009
3010 auto map = std::make_shared<SyncRes::domainmap_t>();
3011 (*map)[authZone] = ad;
3012 SyncRes::setDomainMap(map);
3013
3014 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) {
3015
3016 queriesCount++;
3017
3018 return 0;
3019 });
3020
3021 vector<DNSRecord> ret;
3022 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
3023 BOOST_CHECK_EQUAL(res, RCode::NoError);
3024 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3025 BOOST_CHECK(ret[0].d_type == QType::SOA);
3026 BOOST_CHECK_EQUAL(queriesCount, 0);
3027 }
3028
3029 BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3030 std::unique_ptr<SyncRes> sr;
3031 initSR(sr);
3032
3033 primeHints();
3034
3035 size_t queriesCount = 0;
3036 const DNSName target("nx.powerdns.com.");
3037 const DNSName authZone("powerdns.com");
3038
3039 SyncRes::AuthDomain ad;
3040 ad.d_name = authZone;
3041 DNSRecord dr;
3042 dr.d_place = DNSResourceRecord::ANSWER;
3043 dr.d_name = DNSName("powerdns.com.");
3044 dr.d_type = QType::SOA;
3045 dr.d_ttl = 3600;
3046 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3047 ad.d_records.insert(dr);
3048
3049 auto map = std::make_shared<SyncRes::domainmap_t>();
3050 (*map)[authZone] = ad;
3051 SyncRes::setDomainMap(map);
3052
3053 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) {
3054
3055 queriesCount++;
3056
3057 return 0;
3058 });
3059
3060 vector<DNSRecord> ret;
3061 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3062 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3063 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3064 BOOST_CHECK(ret[0].d_type == QType::SOA);
3065 BOOST_CHECK_EQUAL(queriesCount, 0);
3066 }
3067
3068 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3069 std::unique_ptr<SyncRes> sr;
3070 initSR(sr);
3071
3072 primeHints();
3073
3074 size_t queriesCount = 0;
3075 const DNSName target("www.test.powerdns.com.");
3076 const ComboAddress targetAddr("192.0.2.2");
3077 const DNSName ns("ns1.test.powerdns.com.");
3078 const ComboAddress nsAddr("192.0.2.1");
3079 const DNSName authZone("powerdns.com");
3080
3081 SyncRes::AuthDomain ad;
3082 ad.d_name = authZone;
3083 DNSRecord dr;
3084 dr.d_place = DNSResourceRecord::ANSWER;
3085 dr.d_name = authZone;
3086 dr.d_type = QType::SOA;
3087 dr.d_ttl = 3600;
3088 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3089 ad.d_records.insert(dr);
3090
3091 dr.d_place = DNSResourceRecord::ANSWER;
3092 dr.d_name = DNSName("test.powerdns.com.");
3093 dr.d_type = QType::NS;
3094 dr.d_ttl = 3600;
3095 dr.d_content = std::make_shared<NSRecordContent>(ns);
3096 ad.d_records.insert(dr);
3097
3098 dr.d_place = DNSResourceRecord::ANSWER;
3099 dr.d_name = ns;
3100 dr.d_type = QType::A;
3101 dr.d_ttl = 3600;
3102 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3103 ad.d_records.insert(dr);
3104
3105 auto map = std::make_shared<SyncRes::domainmap_t>();
3106 (*map)[authZone] = ad;
3107 SyncRes::setDomainMap(map);
3108
3109 sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr](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) {
3110
3111 queriesCount++;
3112 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3113 setLWResult(res, 0, true, false, true);
3114 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3115 return 1;
3116 }
3117
3118 return 0;
3119 });
3120
3121 vector<DNSRecord> ret;
3122 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3123 BOOST_CHECK_EQUAL(res, RCode::NoError);
3124 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3125 BOOST_CHECK(ret[0].d_type == QType::A);
3126 BOOST_CHECK_EQUAL(queriesCount, 1);
3127 }
3128
3129 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3130 std::unique_ptr<SyncRes> sr;
3131 initSR(sr);
3132
3133 primeHints();
3134
3135 size_t queriesCount = 0;
3136 const DNSName target("test.powerdns.com.");
3137 const ComboAddress targetAddr("192.0.2.2");
3138 const DNSName ns("ns1.test.powerdns.com.");
3139 const ComboAddress nsAddr("192.0.2.1");
3140 const DNSName authZone("powerdns.com");
3141
3142 SyncRes::AuthDomain ad;
3143 ad.d_name = authZone;
3144 DNSRecord dr;
3145 dr.d_place = DNSResourceRecord::ANSWER;
3146 dr.d_name = authZone;
3147 dr.d_type = QType::SOA;
3148 dr.d_ttl = 3600;
3149 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3150 ad.d_records.insert(dr);
3151
3152 dr.d_place = DNSResourceRecord::ANSWER;
3153 dr.d_name = DNSName("test.powerdns.com.");
3154 dr.d_type = QType::NS;
3155 dr.d_ttl = 3600;
3156 dr.d_content = std::make_shared<NSRecordContent>(ns);
3157 ad.d_records.insert(dr);
3158
3159 dr.d_place = DNSResourceRecord::ANSWER;
3160 dr.d_name = ns;
3161 dr.d_type = QType::A;
3162 dr.d_ttl = 3600;
3163 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3164 ad.d_records.insert(dr);
3165
3166 auto map = std::make_shared<SyncRes::domainmap_t>();
3167 (*map)[authZone] = ad;
3168 SyncRes::setDomainMap(map);
3169
3170 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) {
3171
3172 queriesCount++;
3173
3174 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3175 setLWResult(res, 0, true, false, true);
3176 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3177 return 1;
3178 }
3179
3180 return 0;
3181 });
3182
3183 vector<DNSRecord> ret;
3184 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3185 BOOST_CHECK_EQUAL(res, RCode::NoError);
3186 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3187 BOOST_CHECK(ret[0].d_type == QType::A);
3188 BOOST_CHECK_EQUAL(queriesCount, 1);
3189 }
3190
3191 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3192 std::unique_ptr<SyncRes> sr;
3193 initSR(sr);
3194
3195 primeHints();
3196
3197 size_t queriesCount = 0;
3198 const DNSName target("test.powerdns.com.");
3199 const ComboAddress targetAddr("192.0.2.2");
3200 const DNSName authZone("powerdns.com");
3201
3202 SyncRes::AuthDomain ad;
3203 ad.d_name = authZone;
3204 DNSRecord dr;
3205 dr.d_place = DNSResourceRecord::ANSWER;
3206 dr.d_name = authZone;
3207 dr.d_type = QType::SOA;
3208 dr.d_ttl = 3600;
3209 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3210 ad.d_records.insert(dr);
3211
3212 dr.d_place = DNSResourceRecord::ANSWER;
3213 dr.d_name = DNSName("*.powerdns.com.");
3214 dr.d_type = QType::A;
3215 dr.d_ttl = 3600;
3216 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3217 ad.d_records.insert(dr);
3218
3219 auto map = std::make_shared<SyncRes::domainmap_t>();
3220 (*map)[authZone] = ad;
3221 SyncRes::setDomainMap(map);
3222
3223 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) {
3224
3225 queriesCount++;
3226
3227 return 0;
3228 });
3229
3230 vector<DNSRecord> ret;
3231 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3232 BOOST_CHECK_EQUAL(res, RCode::NoError);
3233 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3234 BOOST_CHECK(ret[0].d_type == QType::A);
3235 BOOST_CHECK_EQUAL(queriesCount, 0);
3236 }
3237
3238 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3239 std::unique_ptr<SyncRes> sr;
3240 initSR(sr);
3241
3242 primeHints();
3243
3244 size_t queriesCount = 0;
3245 const DNSName target("test.powerdns.com.");
3246 const ComboAddress targetAddr("192.0.2.2");
3247 const DNSName authZone("powerdns.com");
3248
3249 SyncRes::AuthDomain ad;
3250 ad.d_name = authZone;
3251 DNSRecord dr;
3252 dr.d_place = DNSResourceRecord::ANSWER;
3253 dr.d_name = authZone;
3254 dr.d_type = QType::SOA;
3255 dr.d_ttl = 3600;
3256 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3257 ad.d_records.insert(dr);
3258
3259 dr.d_place = DNSResourceRecord::ANSWER;
3260 dr.d_name = DNSName("*.powerdns.com.");
3261 dr.d_type = QType::A;
3262 dr.d_ttl = 3600;
3263 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3264 ad.d_records.insert(dr);
3265
3266 auto map = std::make_shared<SyncRes::domainmap_t>();
3267 (*map)[authZone] = ad;
3268 SyncRes::setDomainMap(map);
3269
3270 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) {
3271
3272 queriesCount++;
3273
3274 return 0;
3275 });
3276
3277 vector<DNSRecord> ret;
3278 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
3279 BOOST_CHECK_EQUAL(res, RCode::NoError);
3280 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3281 BOOST_CHECK(ret[0].d_type == QType::SOA);
3282 BOOST_CHECK_EQUAL(queriesCount, 0);
3283 }
3284
3285 BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3286 std::unique_ptr<SyncRes> sr;
3287 initSR(sr);
3288
3289 primeHints();
3290
3291 size_t queriesCount = 0;
3292 const DNSName target("powerdns.com.");
3293 const ComboAddress addr("192.0.2.5");
3294
3295 SyncRes::AuthDomain ad;
3296 ad.d_name = target;
3297 DNSRecord dr;
3298 dr.d_place = DNSResourceRecord::ANSWER;
3299 dr.d_name = target;
3300 dr.d_type = QType::SOA;
3301 dr.d_ttl = 3600;
3302 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3303 ad.d_records.insert(dr);
3304
3305 dr.d_place = DNSResourceRecord::ANSWER;
3306 dr.d_name = target;
3307 dr.d_type = QType::A;
3308 dr.d_ttl = 3600;
3309 dr.d_content = std::make_shared<ARecordContent>(addr);
3310 ad.d_records.insert(dr);
3311
3312 auto map = std::make_shared<SyncRes::domainmap_t>();
3313 (*map)[target] = ad;
3314 SyncRes::setDomainMap(map);
3315
3316 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) {
3317
3318 queriesCount++;
3319 setLWResult(res, 0, true, false, true);
3320 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3321 return 1;
3322 });
3323
3324 /* simulate a no-RD query */
3325 sr->setCacheOnly();
3326
3327 vector<DNSRecord> ret;
3328 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3329 BOOST_CHECK_EQUAL(res, RCode::NoError);
3330 BOOST_CHECK_EQUAL(ret.size(), 1);
3331 BOOST_CHECK(ret[0].d_type == QType::A);
3332 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3333 BOOST_CHECK_EQUAL(queriesCount, 0);
3334 }
3335
3336 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
3337 init();
3338
3339 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3340 dcke->create(dcke->getBits());
3341 // cerr<<dcke->convertToISC()<<endl;
3342 DNSSECPrivateKey dpk;
3343 dpk.d_flags = 256;
3344 dpk.setKey(dcke);
3345
3346 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3347 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3348
3349 DNSName qname("powerdns.com.");
3350
3351 time_t now = time(nullptr);
3352 RRSIGRecordContent rrc;
3353 /* this RRSIG is valid for the current second only */
3354 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
3355
3356 skeyset_t keyset;
3357 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3358
3359 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3360 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3361
3362 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
3363 }
3364
3365 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3366 std::unique_ptr<SyncRes> sr;
3367 initSR(sr, true);
3368
3369 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3370
3371 primeHints();
3372 const DNSName target(".");
3373 testkeysset_t keys;
3374
3375 auto luaconfsCopy = g_luaconfs.getCopy();
3376 luaconfsCopy.dsAnchors.clear();
3377 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3378 g_luaconfs.setState(luaconfsCopy);
3379
3380 size_t queriesCount = 0;
3381
3382 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) {
3383 queriesCount++;
3384
3385 if (domain == target && type == QType::NS) {
3386
3387 setLWResult(res, 0, true, false, true);
3388 char addr[] = "a.root-servers.net.";
3389 for (char idx = 'a'; idx <= 'm'; idx++) {
3390 addr[0] = idx;
3391 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3392 }
3393
3394 addRRSIG(keys, res->d_records, domain, 300);
3395
3396 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3397 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3398
3399 return 1;
3400 } else if (domain == target && type == QType::DNSKEY) {
3401
3402 setLWResult(res, 0, true, false, true);
3403
3404 addDNSKEY(keys, domain, 300, res->d_records);
3405 addRRSIG(keys, res->d_records, domain, 300);
3406
3407 return 1;
3408 }
3409
3410 return 0;
3411 });
3412
3413 vector<DNSRecord> ret;
3414 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3415 BOOST_CHECK_EQUAL(res, RCode::NoError);
3416 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3417 /* 13 NS + 1 RRSIG */
3418 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3419 BOOST_CHECK_EQUAL(queriesCount, 2);
3420
3421 /* again, to test the cache */
3422 ret.clear();
3423 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3424 BOOST_CHECK_EQUAL(res, RCode::NoError);
3425 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3426 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3427 BOOST_CHECK_EQUAL(queriesCount, 2);
3428 }
3429
3430 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3431 std::unique_ptr<SyncRes> sr;
3432 initSR(sr, true);
3433
3434 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3435
3436 primeHints();
3437 const DNSName target(".");
3438 testkeysset_t zskeys;
3439 testkeysset_t kskeys;
3440
3441 /* Generate key material for "." */
3442 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3443 dckeZ->create(dckeZ->getBits());
3444 DNSSECPrivateKey ksk;
3445 ksk.d_flags = 257;
3446 ksk.setKey(dckeZ);
3447 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3448
3449 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3450 dckeK->create(dckeK->getBits());
3451 DNSSECPrivateKey zsk;
3452 zsk.d_flags = 256;
3453 zsk.setKey(dckeK);
3454 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
3455
3456 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3457 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
3458
3459 /* Set the root DS */
3460 auto luaconfsCopy = g_luaconfs.getCopy();
3461 luaconfsCopy.dsAnchors.clear();
3462 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
3463 g_luaconfs.setState(luaconfsCopy);
3464
3465 size_t queriesCount = 0;
3466
3467 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) {
3468 queriesCount++;
3469
3470 if (domain == target && type == QType::NS) {
3471
3472 setLWResult(res, 0, true, false, true);
3473 char addr[] = "a.root-servers.net.";
3474 for (char idx = 'a'; idx <= 'm'; idx++) {
3475 addr[0] = idx;
3476 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3477 }
3478
3479 addRRSIG(zskeys, res->d_records, domain, 300);
3480
3481 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3482 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3483
3484 return 1;
3485 } else if (domain == target && type == QType::DNSKEY) {
3486
3487 setLWResult(res, 0, true, false, true);
3488
3489 addDNSKEY(kskeys, domain, 300, res->d_records);
3490 addDNSKEY(zskeys, domain, 300, res->d_records);
3491 addRRSIG(kskeys, res->d_records, domain, 300);
3492
3493 return 1;
3494 }
3495
3496 return 0;
3497 });
3498
3499 vector<DNSRecord> ret;
3500 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3501 BOOST_CHECK_EQUAL(res, RCode::NoError);
3502 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3503 /* 13 NS + 1 RRSIG */
3504 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3505 BOOST_CHECK_EQUAL(queriesCount, 2);
3506
3507 /* again, to test the cache */
3508 ret.clear();
3509 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3510 BOOST_CHECK_EQUAL(res, RCode::NoError);
3511 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3512 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3513 BOOST_CHECK_EQUAL(queriesCount, 2);
3514 }
3515
3516 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
3517 std::unique_ptr<SyncRes> sr;
3518 initSR(sr, true);
3519
3520 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3521
3522 primeHints();
3523 const DNSName target(".");
3524 testkeysset_t keys;
3525
3526 auto luaconfsCopy = g_luaconfs.getCopy();
3527 luaconfsCopy.dsAnchors.clear();
3528 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3529 g_luaconfs.setState(luaconfsCopy);
3530
3531 size_t queriesCount = 0;
3532
3533 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) {
3534 queriesCount++;
3535
3536 if (domain == target && type == QType::NS) {
3537
3538 setLWResult(res, 0, true, false, true);
3539 char addr[] = "a.root-servers.net.";
3540 for (char idx = 'a'; idx <= 'm'; idx++) {
3541 addr[0] = idx;
3542 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3543 }
3544
3545 addRRSIG(keys, res->d_records, domain, 300);
3546
3547 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3548 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3549
3550 return 1;
3551 } else if (domain == target && type == QType::DNSKEY) {
3552
3553 setLWResult(res, 0, true, false, true);
3554
3555 /* No DNSKEY */
3556
3557 return 1;
3558 }
3559
3560 return 0;
3561 });
3562
3563 vector<DNSRecord> ret;
3564 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3565 BOOST_CHECK_EQUAL(res, RCode::NoError);
3566 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3567 /* 13 NS + 1 RRSIG */
3568 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3569 BOOST_CHECK_EQUAL(queriesCount, 2);
3570
3571 /* again, to test the cache */
3572 ret.clear();
3573 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3574 BOOST_CHECK_EQUAL(res, RCode::NoError);
3575 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3576 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3577 BOOST_CHECK_EQUAL(queriesCount, 2);
3578 }
3579
3580 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3581 std::unique_ptr<SyncRes> sr;
3582 initSR(sr, true);
3583
3584 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3585
3586 primeHints();
3587 const DNSName target(".");
3588 testkeysset_t dskeys;
3589 testkeysset_t keys;
3590
3591 /* Generate key material for "." */
3592 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3593 dckeDS->create(dckeDS->getBits());
3594 DNSSECPrivateKey dskey;
3595 dskey.d_flags = 257;
3596 dskey.setKey(dckeDS);
3597 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3598
3599 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3600 dcke->create(dcke->getBits());
3601 DNSSECPrivateKey dpk;
3602 dpk.d_flags = 256;
3603 dpk.setKey(dcke);
3604 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3605
3606 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3607 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
3608
3609 /* Set the root DS */
3610 auto luaconfsCopy = g_luaconfs.getCopy();
3611 luaconfsCopy.dsAnchors.clear();
3612 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3613 g_luaconfs.setState(luaconfsCopy);
3614
3615 size_t queriesCount = 0;
3616
3617 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) {
3618 queriesCount++;
3619
3620 if (domain == target && type == QType::NS) {
3621
3622 setLWResult(res, 0, true, false, true);
3623 char addr[] = "a.root-servers.net.";
3624 for (char idx = 'a'; idx <= 'm'; idx++) {
3625 addr[0] = idx;
3626 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3627 }
3628
3629 addRRSIG(keys, res->d_records, domain, 300);
3630
3631 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3632 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3633
3634 return 1;
3635 } else if (domain == target && type == QType::DNSKEY) {
3636
3637 setLWResult(res, 0, true, false, true);
3638
3639 addDNSKEY(keys, domain, 300, res->d_records);
3640 addRRSIG(keys, res->d_records, domain, 300);
3641
3642 return 1;
3643 }
3644
3645 return 0;
3646 });
3647
3648 vector<DNSRecord> ret;
3649 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3650 BOOST_CHECK_EQUAL(res, RCode::NoError);
3651 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3652 /* 13 NS + 1 RRSIG */
3653 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3654 BOOST_CHECK_EQUAL(queriesCount, 2);
3655
3656 /* again, to test the cache */
3657 ret.clear();
3658 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3659 BOOST_CHECK_EQUAL(res, RCode::NoError);
3660 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3661 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3662 BOOST_CHECK_EQUAL(queriesCount, 2);
3663 }
3664
3665 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
3666 std::unique_ptr<SyncRes> sr;
3667 initSR(sr, true);
3668
3669 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3670
3671 primeHints();
3672 const DNSName target(".");
3673 testkeysset_t keys;
3674 testkeysset_t rrsigkeys;
3675
3676 auto luaconfsCopy = g_luaconfs.getCopy();
3677 luaconfsCopy.dsAnchors.clear();
3678 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3679 g_luaconfs.setState(luaconfsCopy);
3680
3681 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3682 dckeRRSIG->create(dckeRRSIG->getBits());
3683 DNSSECPrivateKey rrsigkey;
3684 rrsigkey.d_flags = 257;
3685 rrsigkey.setKey(dckeRRSIG);
3686 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
3687
3688 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
3689
3690 size_t queriesCount = 0;
3691
3692 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) {
3693 queriesCount++;
3694
3695 if (domain == target && type == QType::NS) {
3696
3697 setLWResult(res, 0, true, false, true);
3698 char addr[] = "a.root-servers.net.";
3699 for (char idx = 'a'; idx <= 'm'; idx++) {
3700 addr[0] = idx;
3701 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3702 }
3703
3704 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3705
3706 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3707 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3708
3709 return 1;
3710 } else if (domain == target && type == QType::DNSKEY) {
3711
3712 setLWResult(res, 0, true, false, true);
3713
3714 addDNSKEY(keys, domain, 300, res->d_records);
3715 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3716
3717 return 1;
3718 }
3719
3720 return 0;
3721 });
3722
3723 vector<DNSRecord> ret;
3724 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3725 BOOST_CHECK_EQUAL(res, RCode::NoError);
3726 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3727 /* 13 NS + 1 RRSIG */
3728 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3729 BOOST_CHECK_EQUAL(queriesCount, 2);
3730
3731 /* again, to test the cache */
3732 ret.clear();
3733 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3734 BOOST_CHECK_EQUAL(res, RCode::NoError);
3735 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3736 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3737 BOOST_CHECK_EQUAL(queriesCount, 2);
3738 }
3739
3740 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
3741 std::unique_ptr<SyncRes> sr;
3742 initSR(sr, true);
3743
3744 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3745
3746 primeHints();
3747 const DNSName target(".");
3748 testkeysset_t keys;
3749
3750 auto luaconfsCopy = g_luaconfs.getCopy();
3751 luaconfsCopy.dsAnchors.clear();
3752 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3753 g_luaconfs.setState(luaconfsCopy);
3754
3755 size_t queriesCount = 0;
3756
3757 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) {
3758 queriesCount++;
3759
3760 if (domain == target && type == QType::NS) {
3761
3762 setLWResult(res, 0, true, false, true);
3763 char addr[] = "a.root-servers.net.";
3764 for (char idx = 'a'; idx <= 'm'; idx++) {
3765 addr[0] = idx;
3766 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3767 }
3768
3769 /* No RRSIG */
3770
3771 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3772 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3773
3774 return 1;
3775 } else if (domain == target && type == QType::DNSKEY) {
3776
3777 setLWResult(res, 0, true, false, true);
3778
3779 addDNSKEY(keys, domain, 300, res->d_records);
3780 addRRSIG(keys, res->d_records, domain, 300);
3781
3782 return 1;
3783 }
3784
3785 return 0;
3786 });
3787
3788 vector<DNSRecord> ret;
3789 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3790 BOOST_CHECK_EQUAL(res, RCode::NoError);
3791 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3792 /* 13 NS + 0 RRSIG */
3793 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3794 /* no RRSIG so no query for DNSKEYs */
3795 BOOST_CHECK_EQUAL(queriesCount, 1);
3796
3797 /* again, to test the cache */
3798 ret.clear();
3799 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3800 BOOST_CHECK_EQUAL(res, RCode::NoError);
3801 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3802 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3803 BOOST_CHECK_EQUAL(queriesCount, 1);
3804 }
3805
3806 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
3807 std::unique_ptr<SyncRes> sr;
3808 initSR(sr, true);
3809
3810 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3811
3812 primeHints();
3813 const DNSName target(".");
3814 testkeysset_t keys;
3815
3816 /* Generate key material for "." */
3817 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3818 dcke->create(dcke->getBits());
3819 DNSSECPrivateKey dpk;
3820 dpk.d_flags = 256;
3821 dpk.setKey(dcke);
3822 /* Fake algorithm number (private) */
3823 dpk.d_algorithm = 253;
3824
3825 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3826 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
3827 /* Fake algorithm number (private) */
3828 drc.d_algorithm = 253;
3829
3830 /* Set the root DS */
3831 auto luaconfsCopy = g_luaconfs.getCopy();
3832 luaconfsCopy.dsAnchors.clear();
3833 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3834 g_luaconfs.setState(luaconfsCopy);
3835
3836 size_t queriesCount = 0;
3837
3838 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) {
3839 queriesCount++;
3840
3841 if (domain == target && type == QType::NS) {
3842
3843 setLWResult(res, 0, true, false, true);
3844 char addr[] = "a.root-servers.net.";
3845 for (char idx = 'a'; idx <= 'm'; idx++) {
3846 addr[0] = idx;
3847 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3848 }
3849
3850 addRRSIG(keys, res->d_records, domain, 300);
3851
3852 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3853 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3854
3855 return 1;
3856 } else if (domain == target && type == QType::DNSKEY) {
3857
3858 setLWResult(res, 0, true, false, true);
3859
3860 addDNSKEY(keys, domain, 300, res->d_records);
3861 addRRSIG(keys, res->d_records, domain, 300);
3862
3863 return 1;
3864 }
3865
3866 return 0;
3867 });
3868
3869 vector<DNSRecord> ret;
3870 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3871 BOOST_CHECK_EQUAL(res, RCode::NoError);
3872 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3873 /* 13 NS + 1 RRSIG */
3874 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3875 /* no supported DS so no query for DNSKEYs */
3876 BOOST_CHECK_EQUAL(queriesCount, 1);
3877
3878 /* again, to test the cache */
3879 ret.clear();
3880 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3881 BOOST_CHECK_EQUAL(res, RCode::NoError);
3882 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3883 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3884 BOOST_CHECK_EQUAL(queriesCount, 1);
3885 }
3886
3887 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
3888 std::unique_ptr<SyncRes> sr;
3889 initSR(sr, true);
3890
3891 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3892
3893 primeHints();
3894 const DNSName target(".");
3895 testkeysset_t keys;
3896
3897 /* Generate key material for "." */
3898 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3899 dcke->create(dcke->getBits());
3900 DNSSECPrivateKey dpk;
3901 dpk.d_flags = 256;
3902 dpk.setKey(dcke);
3903 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3904 /* Fake digest number (reserved) */
3905 drc.d_digesttype = 0;
3906
3907 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
3908
3909 /* Set the root DS */
3910 auto luaconfsCopy = g_luaconfs.getCopy();
3911 luaconfsCopy.dsAnchors.clear();
3912 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3913 g_luaconfs.setState(luaconfsCopy);
3914
3915 size_t queriesCount = 0;
3916
3917 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) {
3918 queriesCount++;
3919
3920 if (domain == target && type == QType::NS) {
3921
3922 setLWResult(res, 0, true, false, true);
3923 char addr[] = "a.root-servers.net.";
3924 for (char idx = 'a'; idx <= 'm'; idx++) {
3925 addr[0] = idx;
3926 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3927 }
3928
3929 addRRSIG(keys, res->d_records, domain, 300);
3930
3931 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3932 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3933
3934 return 1;
3935 } else if (domain == target && type == QType::DNSKEY) {
3936
3937 setLWResult(res, 0, true, false, true);
3938
3939 addDNSKEY(keys, domain, 300, res->d_records);
3940 addRRSIG(keys, res->d_records, domain, 300);
3941
3942 return 1;
3943 }
3944
3945 return 0;
3946 });
3947
3948 vector<DNSRecord> ret;
3949 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3950 BOOST_CHECK_EQUAL(res, RCode::NoError);
3951 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3952 /* 13 NS + 1 RRSIG */
3953 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3954 /* no supported DS so no query for DNSKEYs */
3955 BOOST_CHECK_EQUAL(queriesCount, 1);
3956
3957 /* again, to test the cache */
3958 ret.clear();
3959 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3960 BOOST_CHECK_EQUAL(res, RCode::NoError);
3961 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3962 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3963 BOOST_CHECK_EQUAL(queriesCount, 1);
3964 }
3965
3966 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
3967 std::unique_ptr<SyncRes> sr;
3968 initSR(sr, true);
3969
3970 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3971
3972 primeHints();
3973 const DNSName target(".");
3974 testkeysset_t keys;
3975
3976 auto luaconfsCopy = g_luaconfs.getCopy();
3977 luaconfsCopy.dsAnchors.clear();
3978 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3979
3980 g_luaconfs.setState(luaconfsCopy);
3981
3982 size_t queriesCount = 0;
3983
3984 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) {
3985 queriesCount++;
3986
3987 if (domain == target && type == QType::NS) {
3988
3989 setLWResult(res, 0, true, false, true);
3990 char addr[] = "a.root-servers.net.";
3991 for (char idx = 'a'; idx <= 'm'; idx++) {
3992 addr[0] = idx;
3993 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3994 }
3995
3996 addRRSIG(keys, res->d_records, domain, 300, true);
3997
3998 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3999 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4000
4001 return 1;
4002 } else if (domain == target && type == QType::DNSKEY) {
4003
4004 setLWResult(res, 0, true, false, true);
4005
4006 addDNSKEY(keys, domain, 300, res->d_records);
4007 addRRSIG(keys, res->d_records, domain, 300);
4008
4009 return 1;
4010 }
4011
4012 return 0;
4013 });
4014
4015 vector<DNSRecord> ret;
4016 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4017 BOOST_CHECK_EQUAL(res, RCode::NoError);
4018 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4019 /* 13 NS + 1 RRSIG */
4020 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4021 BOOST_CHECK_EQUAL(queriesCount, 2);
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(), Bogus);
4028 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4029 BOOST_CHECK_EQUAL(queriesCount, 2);
4030 }
4031
4032 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
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 auto luaconfsCopy = g_luaconfs.getCopy();
4043 luaconfsCopy.dsAnchors.clear();
4044 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4045
4046 g_luaconfs.setState(luaconfsCopy);
4047
4048 size_t queriesCount = 0;
4049
4050 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) {
4051 queriesCount++;
4052
4053 if (domain == target && type == QType::NS) {
4054
4055 setLWResult(res, 0, true, false, true);
4056 char addr[] = "a.root-servers.net.";
4057 for (char idx = 'a'; idx <= 'm'; idx++) {
4058 addr[0] = idx;
4059 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4060 }
4061
4062 /* FORCE WRONG ALGO */
4063 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4064
4065 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4066 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4067
4068 return 1;
4069 } else if (domain == target && type == QType::DNSKEY) {
4070
4071 setLWResult(res, 0, true, false, true);
4072
4073 addDNSKEY(keys, domain, 300, res->d_records);
4074 addRRSIG(keys, res->d_records, domain, 300);
4075
4076 return 1;
4077 }
4078
4079 return 0;
4080 });
4081
4082 vector<DNSRecord> ret;
4083 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4084 BOOST_CHECK_EQUAL(res, RCode::NoError);
4085 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4086 /* 13 NS + 1 RRSIG */
4087 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4088 BOOST_CHECK_EQUAL(queriesCount, 2);
4089
4090 /* again, to test the cache */
4091 ret.clear();
4092 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4093 BOOST_CHECK_EQUAL(res, RCode::NoError);
4094 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4095 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4096 BOOST_CHECK_EQUAL(queriesCount, 2);
4097 }
4098
4099 BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
4100 std::unique_ptr<SyncRes> sr;
4101 initSR(sr, true);
4102
4103 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4104
4105 primeHints();
4106 const DNSName target("powerdns.com.");
4107 const ComboAddress targetAddr("192.0.2.42");
4108 testkeysset_t keys;
4109
4110 auto luaconfsCopy = g_luaconfs.getCopy();
4111 luaconfsCopy.dsAnchors.clear();
4112 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4113 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4114 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
4115
4116 g_luaconfs.setState(luaconfsCopy);
4117
4118 size_t queriesCount = 0;
4119
4120 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) {
4121 queriesCount++;
4122
4123 DNSName auth = domain;
4124 if (domain == target) {
4125 auth = DNSName("powerdns.com.");
4126 }
4127
4128 if (type == QType::DS || type == QType::DNSKEY) {
4129 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4130 }
4131
4132 if (isRootServer(ip)) {
4133 setLWResult(res, 0, false, false, true);
4134 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4135 addDS(DNSName("com."), 300, res->d_records, keys);
4136 addRRSIG(keys, res->d_records, DNSName("."), 300);
4137 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4138 return 1;
4139 }
4140
4141 if (ip == ComboAddress("192.0.2.1:53")) {
4142 if (domain == DNSName("com.")) {
4143 setLWResult(res, 0, true, false, true);
4144 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4145 addRRSIG(keys, res->d_records, domain, 300);
4146 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4147 addRRSIG(keys, res->d_records, domain, 300);
4148 }
4149 else {
4150 setLWResult(res, 0, false, false, true);
4151 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4152 addDS(auth, 300, res->d_records, keys);
4153 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4154 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4155 }
4156 return 1;
4157 }
4158
4159 if (ip == ComboAddress("192.0.2.2:53")) {
4160 if (type == QType::NS) {
4161 setLWResult(res, 0, true, false, true);
4162 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4163 addRRSIG(keys, res->d_records, auth, 300);
4164 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4165 addRRSIG(keys, res->d_records, auth, 300);
4166 }
4167 else {
4168 setLWResult(res, RCode::NoError, true, false, true);
4169 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4170 addRRSIG(keys, res->d_records, auth, 300);
4171 }
4172 return 1;
4173 }
4174
4175 return 0;
4176 });
4177
4178 vector<DNSRecord> ret;
4179 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4180 BOOST_CHECK_EQUAL(res, RCode::NoError);
4181 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4182 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4183 BOOST_CHECK_EQUAL(queriesCount, 8);
4184
4185 /* again, to test the cache */
4186 ret.clear();
4187 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4188 BOOST_CHECK_EQUAL(res, RCode::NoError);
4189 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4190 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4191 BOOST_CHECK_EQUAL(queriesCount, 8);
4192 }
4193
4194 BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4195 std::unique_ptr<SyncRes> sr;
4196 initSR(sr, true);
4197
4198 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4199
4200 primeHints();
4201 const DNSName target("powerdns.com.");
4202 const ComboAddress targetAddr("192.0.2.42");
4203 testkeysset_t keys;
4204
4205 auto luaconfsCopy = g_luaconfs.getCopy();
4206 luaconfsCopy.dsAnchors.clear();
4207 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4208 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4209 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4210 g_luaconfs.setState(luaconfsCopy);
4211
4212 size_t queriesCount = 0;
4213
4214 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) {
4215 queriesCount++;
4216
4217 DNSName auth = domain;
4218 if (domain == target) {
4219 auth = DNSName("powerdns.com.");
4220 }
4221
4222 if (type == QType::DS || type == QType::DNSKEY) {
4223 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4224 }
4225
4226 if (isRootServer(ip)) {
4227 setLWResult(res, 0, false, false, true);
4228 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4229 addDS(DNSName("com."), 300, res->d_records, keys);
4230 addRRSIG(keys, res->d_records, DNSName("."), 300);
4231 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4232 return 1;
4233 }
4234
4235 if (ip == ComboAddress("192.0.2.1:53")) {
4236 if (domain == DNSName("com.")) {
4237 setLWResult(res, 0, true, false, true);
4238 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4239 addRRSIG(keys, res->d_records, domain, 300);
4240 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4241 addRRSIG(keys, res->d_records, domain, 300);
4242 }
4243 else {
4244 setLWResult(res, 0, false, false, true);
4245 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4246 addDS(auth, 300, res->d_records, keys);
4247 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4248 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4249 }
4250 return 1;
4251 }
4252
4253 if (ip == ComboAddress("192.0.2.2:53")) {
4254 if (type == QType::NS) {
4255 setLWResult(res, 0, true, false, true);
4256 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4257 addRRSIG(keys, res->d_records, auth, 300);
4258 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4259 addRRSIG(keys, res->d_records, auth, 300);
4260 }
4261 else {
4262 setLWResult(res, RCode::NoError, true, false, true);
4263 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4264 addRRSIG(keys, res->d_records, auth, 300);
4265 }
4266 return 1;
4267 }
4268
4269 return 0;
4270 });
4271
4272 vector<DNSRecord> ret;
4273 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4274 BOOST_CHECK_EQUAL(res, RCode::NoError);
4275 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4276 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4277 BOOST_CHECK_EQUAL(queriesCount, 8);
4278
4279 /* again, to test the cache */
4280 ret.clear();
4281 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4282 BOOST_CHECK_EQUAL(res, RCode::NoError);
4283 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4284 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4285 BOOST_CHECK_EQUAL(queriesCount, 8);
4286
4287 /* this time we ask for the NS that should be in the cache, to check
4288 the validation status */
4289 ret.clear();
4290 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4291 BOOST_CHECK_EQUAL(res, RCode::NoError);
4292 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4293 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4294 BOOST_CHECK_EQUAL(queriesCount, 9);
4295
4296 }
4297
4298 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4299 std::unique_ptr<SyncRes> sr;
4300 initSR(sr, true);
4301
4302 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4303
4304 primeHints();
4305 const DNSName target("powerdns.com.");
4306 const ComboAddress targetAddr("192.0.2.42");
4307 testkeysset_t keys;
4308
4309 auto luaconfsCopy = g_luaconfs.getCopy();
4310 luaconfsCopy.dsAnchors.clear();
4311 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4312 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4313 g_luaconfs.setState(luaconfsCopy);
4314
4315 size_t queriesCount = 0;
4316
4317 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) {
4318 queriesCount++;
4319
4320 DNSName auth = domain;
4321 if (domain == target) {
4322 auth = DNSName("powerdns.com.");
4323 }
4324
4325 if (type == QType::DS || type == QType::DNSKEY) {
4326 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4327 }
4328
4329 if (isRootServer(ip)) {
4330 setLWResult(res, 0, false, false, true);
4331 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4332 addDS(DNSName("com."), 300, res->d_records, keys);
4333 addRRSIG(keys, res->d_records, DNSName("."), 300);
4334 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4335 return 1;
4336 }
4337
4338 if (ip == ComboAddress("192.0.2.1:53")) {
4339 if (domain == DNSName("com.")) {
4340 setLWResult(res, 0, true, false, true);
4341 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4342 addRRSIG(keys, res->d_records, domain, 300);
4343 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4344 addRRSIG(keys, res->d_records, domain, 300);
4345 }
4346 else {
4347 setLWResult(res, 0, false, false, true);
4348 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4349 /* no DS */
4350 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4351 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4352 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4353 }
4354 return 1;
4355 }
4356
4357 if (ip == ComboAddress("192.0.2.2:53")) {
4358 if (type == QType::NS) {
4359 setLWResult(res, 0, true, false, true);
4360 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4361 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4362 }
4363 else {
4364 setLWResult(res, RCode::NoError, true, false, true);
4365 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4366 }
4367 return 1;
4368 }
4369
4370 return 0;
4371 });
4372
4373 vector<DNSRecord> ret;
4374 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4375 BOOST_CHECK_EQUAL(res, RCode::NoError);
4376 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4377 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4378 BOOST_CHECK_EQUAL(queriesCount, 7);
4379
4380 /* again, to test the cache */
4381 ret.clear();
4382 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4383 BOOST_CHECK_EQUAL(res, RCode::NoError);
4384 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4385 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4386 BOOST_CHECK_EQUAL(queriesCount, 7);
4387
4388 /* this time we ask for the NS that should be in the cache, to check
4389 the validation status */
4390 ret.clear();
4391 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4392 BOOST_CHECK_EQUAL(res, RCode::NoError);
4393 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4394 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4395 BOOST_CHECK_EQUAL(queriesCount, 8);
4396 }
4397
4398 BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
4399 std::unique_ptr<SyncRes> sr;
4400 initSR(sr, true);
4401
4402 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4403
4404 primeHints();
4405 const DNSName target("powerdns.com.");
4406 const ComboAddress targetAddr("192.0.2.42");
4407 testkeysset_t keys;
4408
4409 auto luaconfsCopy = g_luaconfs.getCopy();
4410 luaconfsCopy.dsAnchors.clear();
4411 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4412 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4413 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4414
4415 /* Add a NTA for "powerdns.com" */
4416 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4417
4418 g_luaconfs.setState(luaconfsCopy);
4419
4420 size_t queriesCount = 0;
4421
4422 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) {
4423 queriesCount++;
4424
4425 DNSName auth = domain;
4426 if (domain == target) {
4427 auth = DNSName("powerdns.com.");
4428 }
4429
4430 if (type == QType::DS || type == QType::DNSKEY) {
4431 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4432 }
4433
4434 if (isRootServer(ip)) {
4435 setLWResult(res, 0, false, false, true);
4436 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4437 addDS(DNSName("com."), 300, res->d_records, keys);
4438 addRRSIG(keys, res->d_records, DNSName("."), 300);
4439 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4440 return 1;
4441 }
4442
4443 if (ip == ComboAddress("192.0.2.1:53")) {
4444 if (domain == DNSName("com.")) {
4445 setLWResult(res, 0, true, false, true);
4446 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4447 addRRSIG(keys, res->d_records, domain, 300);
4448 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4449 addRRSIG(keys, res->d_records, domain, 300);
4450 }
4451 else {
4452 setLWResult(res, 0, false, false, true);
4453 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4454 addDS(auth, 300, res->d_records, keys);
4455 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4456 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4457 }
4458 return 1;
4459 }
4460
4461 if (ip == ComboAddress("192.0.2.2:53")) {
4462 if (type == QType::NS) {
4463 setLWResult(res, 0, true, false, true);
4464 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4465 addRRSIG(keys, res->d_records, auth, 300);
4466 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4467 addRRSIG(keys, res->d_records, auth, 300);
4468 }
4469 else {
4470 setLWResult(res, RCode::NoError, true, false, true);
4471 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4472 addRRSIG(keys, res->d_records, auth, 300);
4473 }
4474 return 1;
4475 }
4476
4477 return 0;
4478 });
4479
4480 vector<DNSRecord> ret;
4481 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4482 BOOST_CHECK_EQUAL(res, RCode::NoError);
4483 /* Should be insecure because of the NTA */
4484 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4485 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4486 BOOST_CHECK_EQUAL(queriesCount, 5);
4487
4488 /* again, to test the cache */
4489 ret.clear();
4490 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4491 BOOST_CHECK_EQUAL(res, RCode::NoError);
4492 /* Should be insecure because of the NTA */
4493 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4494 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4495 BOOST_CHECK_EQUAL(queriesCount, 5);
4496 }
4497
4498 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4499 std::unique_ptr<SyncRes> sr;
4500 initSR(sr, true);
4501
4502 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4503
4504 primeHints();
4505 const DNSName target("powerdns.com.");
4506 const ComboAddress targetAddr("192.0.2.42");
4507 testkeysset_t keys;
4508
4509 auto luaconfsCopy = g_luaconfs.getCopy();
4510 luaconfsCopy.dsAnchors.clear();
4511 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4512 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4513 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4514
4515 /* Add a NTA for "powerdns.com" */
4516 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4517
4518 g_luaconfs.setState(luaconfsCopy);
4519
4520 size_t queriesCount = 0;
4521
4522 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) {
4523 queriesCount++;
4524
4525 if (type == QType::DS || type == QType::DNSKEY) {
4526 setLWResult(res, 0, false, false, true);
4527 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4528 return 1;
4529 }
4530 else {
4531 if (isRootServer(ip)) {
4532 setLWResult(res, 0, false, false, true);
4533 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4534 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4535 return 1;
4536 }
4537 else if (ip == ComboAddress("192.0.2.1:53")) {
4538 if (domain == DNSName("com.")) {
4539 setLWResult(res, 0, true, false, true);
4540 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4541 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4542 }
4543 else {
4544 setLWResult(res, 0, false, false, true);
4545 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4546 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4547 }
4548 return 1;
4549 }
4550 else if (ip == ComboAddress("192.0.2.2:53")) {
4551 if (type == QType::NS) {
4552 setLWResult(res, 0, true, false, true);
4553 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4554 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4555 }
4556 else {
4557 setLWResult(res, RCode::NoError, true, false, true);
4558 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4559 }
4560 return 1;
4561 }
4562 }
4563
4564 return 0;
4565 });
4566
4567 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
4568 vector<DNSRecord> ret;
4569 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4570 BOOST_CHECK_EQUAL(res, RCode::NoError);
4571 /* Should be insecure because of the NTA */
4572 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4573 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4574 BOOST_CHECK_EQUAL(queriesCount, 4);
4575
4576 /* again, to test the cache */
4577 ret.clear();
4578 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4579 BOOST_CHECK_EQUAL(res, RCode::NoError);
4580 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4581 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4582 BOOST_CHECK_EQUAL(queriesCount, 4);
4583 }
4584
4585 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
4586 std::unique_ptr<SyncRes> sr;
4587 initSR(sr, true);
4588
4589 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4590
4591 primeHints();
4592 const DNSName target("powerdns.com.");
4593 testkeysset_t keys;
4594
4595 auto luaconfsCopy = g_luaconfs.getCopy();
4596 luaconfsCopy.dsAnchors.clear();
4597 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4598 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4599 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4600
4601 g_luaconfs.setState(luaconfsCopy);
4602
4603 size_t queriesCount = 0;
4604
4605 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) {
4606 queriesCount++;
4607
4608 if (type == QType::DS || type == QType::DNSKEY) {
4609 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4610 }
4611 else {
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 else if (ip == ComboAddress("192.0.2.1:53")) {
4621 if (domain == DNSName("com.")) {
4622 setLWResult(res, 0, true, false, true);
4623 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4624 addRRSIG(keys, res->d_records, domain, 300);
4625 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4626 addRRSIG(keys, res->d_records, domain, 300);
4627 }
4628 else {
4629 setLWResult(res, 0, false, false, true);
4630 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4631 addDS(domain, 300, res->d_records, keys);
4632 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4633 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4634 }
4635 return 1;
4636 }
4637 else if (ip == ComboAddress("192.0.2.2:53")) {
4638 if (type == QType::NS) {
4639 setLWResult(res, 0, true, false, true);
4640 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4641 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4642 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4643 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4644 }
4645 else {
4646 setLWResult(res, 0, true, false, true);
4647 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4648 addRRSIG(keys, res->d_records, domain, 300);
4649 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
4650 addRRSIG(keys, res->d_records, domain, 300);
4651 }
4652 return 1;
4653 }
4654 }
4655
4656 return 0;
4657 });
4658
4659 vector<DNSRecord> ret;
4660 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4661 BOOST_CHECK_EQUAL(res, RCode::NoError);
4662 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4663 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4664 BOOST_CHECK_EQUAL(queriesCount, 8);
4665
4666 /* again, to test the cache */
4667 ret.clear();
4668 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4669 BOOST_CHECK_EQUAL(res, RCode::NoError);
4670 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4671 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4672 BOOST_CHECK_EQUAL(queriesCount, 8);
4673 }
4674
4675 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
4676 std::unique_ptr<SyncRes> sr;
4677 initSR(sr, true);
4678
4679 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4680
4681 primeHints();
4682 const DNSName target("nx.powerdns.com.");
4683 testkeysset_t keys;
4684
4685 auto luaconfsCopy = g_luaconfs.getCopy();
4686 luaconfsCopy.dsAnchors.clear();
4687 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4688 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4689 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4690
4691 g_luaconfs.setState(luaconfsCopy);
4692
4693 size_t queriesCount = 0;
4694
4695 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) {
4696 queriesCount++;
4697
4698 DNSName auth = domain;
4699 if (domain == target) {
4700 auth = DNSName("powerdns.com.");
4701 }
4702 if (type == QType::DS || type == QType::DNSKEY) {
4703 if (type == QType::DS && domain == target) {
4704 setLWResult(res, RCode::NXDomain, true, false, true);
4705 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4706 addRRSIG(keys, res->d_records, auth, 300);
4707 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4708 addRRSIG(keys, res->d_records, auth, 300);
4709 return 1;
4710 }
4711 else {
4712 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4713 }
4714 }
4715 else {
4716 if (isRootServer(ip)) {
4717 setLWResult(res, 0, false, false, true);
4718 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4719 addDS(DNSName("com."), 300, res->d_records, keys);
4720 addRRSIG(keys, res->d_records, DNSName("."), 300);
4721 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4722 return 1;
4723 }
4724 else if (ip == ComboAddress("192.0.2.1:53")) {
4725 if (domain == DNSName("com.")) {
4726 setLWResult(res, 0, true, false, true);
4727 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4728 addRRSIG(keys, res->d_records, domain, 300);
4729 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4730 addRRSIG(keys, res->d_records, domain, 300);
4731 }
4732 else {
4733 setLWResult(res, 0, false, false, true);
4734 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4735 addDS(auth, 300, res->d_records, keys);
4736 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4737 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4738 }
4739 return 1;
4740 }
4741 else if (ip == ComboAddress("192.0.2.2:53")) {
4742 if (type == QType::NS) {
4743 setLWResult(res, 0, true, false, true);
4744 if (domain == DNSName("powerdns.com.")) {
4745 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4746 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4747 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4748 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4749 }
4750 else {
4751 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4752 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4753 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4754 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4755 }
4756 }
4757 else {
4758 setLWResult(res, RCode::NXDomain, true, false, true);
4759 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4760 addRRSIG(keys, res->d_records, auth, 300);
4761 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4762 addRRSIG(keys, res->d_records, auth, 300);
4763 /* add wildcard denial */
4764 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4765 addRRSIG(keys, res->d_records, auth, 300);
4766 }
4767 return 1;
4768 }
4769 }
4770
4771 return 0;
4772 });
4773
4774 vector<DNSRecord> ret;
4775 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4776 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
4777 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4778 BOOST_REQUIRE_EQUAL(ret.size(), 6);
4779 BOOST_CHECK_EQUAL(queriesCount, 9);
4780
4781 /* again, to test the cache */
4782 ret.clear();
4783 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4784 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
4785 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4786 BOOST_REQUIRE_EQUAL(ret.size(), 6);
4787 BOOST_CHECK_EQUAL(queriesCount, 9);
4788 }
4789
4790 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
4791 std::unique_ptr<SyncRes> sr;
4792 initSR(sr, true);
4793
4794 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4795
4796 primeHints();
4797 const DNSName target("www.powerdns.com.");
4798 testkeysset_t keys;
4799
4800 auto luaconfsCopy = g_luaconfs.getCopy();
4801 luaconfsCopy.dsAnchors.clear();
4802 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4803 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4804 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4805
4806 g_luaconfs.setState(luaconfsCopy);
4807
4808 size_t queriesCount = 0;
4809
4810 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) {
4811 queriesCount++;
4812
4813 if (type == QType::DS || type == QType::DNSKEY) {
4814 if (type == QType::DS && domain == target) {
4815 setLWResult(res, RCode::NoError, true, false, true);
4816 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4817 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
4818 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4819 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4820 return 1;
4821 }
4822 else {
4823 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4824 }
4825 }
4826 else {
4827 if (isRootServer(ip)) {
4828 setLWResult(res, 0, false, false, true);
4829 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4830 addDS(DNSName("com."), 300, res->d_records, keys);
4831 addRRSIG(keys, res->d_records, DNSName("."), 300);
4832 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4833 return 1;
4834 }
4835 else if (ip == ComboAddress("192.0.2.1:53")) {
4836 if (domain == DNSName("com.")) {
4837 setLWResult(res, 0, true, false, true);
4838 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4839 addRRSIG(keys, res->d_records, domain, 300);
4840 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4841 addRRSIG(keys, res->d_records, domain, 300);
4842 }
4843 else {
4844 setLWResult(res, 0, false, false, true);
4845 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4846 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
4847 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4848 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4849 }
4850 return 1;
4851 }
4852 else if (ip == ComboAddress("192.0.2.2:53")) {
4853 setLWResult(res, 0, true, false, true);
4854 if (type == QType::NS) {
4855 if (domain == DNSName("powerdns.com.")) {
4856 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4857 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4858 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4859 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4860 }
4861 else {
4862 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4863 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4864 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4865 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4866 }
4867 }
4868 else {
4869 addRecordToLW(res, domain, QType::A, "192.0.2.42");
4870 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
4871 /* we need to add the proof that this name does not exist, so the wildcard may apply */
4872 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4873 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4874 }
4875 return 1;
4876 }
4877 }
4878
4879 return 0;
4880 });
4881
4882 vector<DNSRecord> ret;
4883 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4884 BOOST_CHECK_EQUAL(res, RCode::NoError);
4885 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4886 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4887 BOOST_CHECK_EQUAL(queriesCount, 9);
4888
4889 /* again, to test the cache */
4890 ret.clear();
4891 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4892 BOOST_CHECK_EQUAL(res, RCode::NoError);
4893 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4894 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4895 BOOST_CHECK_EQUAL(queriesCount, 9);
4896 }
4897
4898 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
4899 std::unique_ptr<SyncRes> sr;
4900 initSR(sr, true);
4901
4902 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4903
4904 primeHints();
4905 const DNSName target("www.com.");
4906 testkeysset_t keys;
4907
4908 auto luaconfsCopy = g_luaconfs.getCopy();
4909 luaconfsCopy.dsAnchors.clear();
4910 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4911 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4912
4913 g_luaconfs.setState(luaconfsCopy);
4914
4915 size_t queriesCount = 0;
4916
4917 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) {
4918 queriesCount++;
4919
4920 if (type == QType::DS || type == QType::DNSKEY) {
4921 if (type == QType::DS && domain == target) {
4922 DNSName auth("com.");
4923 setLWResult(res, 0, true, false, true);
4924
4925 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
4926 addRRSIG(keys, res->d_records, auth, 300);
4927 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
4928 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
4929 addRRSIG(keys, res->d_records, auth, 300);
4930 return 1;
4931 }
4932 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4933 }
4934 else {
4935 if (isRootServer(ip)) {
4936 setLWResult(res, 0, false, false, true);
4937 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4938 addDS(DNSName("com."), 300, res->d_records, keys);
4939 addRRSIG(keys, res->d_records, DNSName("."), 300);
4940 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4941 return 1;
4942 }
4943 else if (ip == ComboAddress("192.0.2.1:53")) {
4944 setLWResult(res, 0, true, false, true);
4945 /* no data */
4946 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4947 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4948 /* no record for this name */
4949 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
4950 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4951 /* a wildcard matches but has no record for this type */
4952 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4953 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
4954 return 1;
4955 }
4956 }
4957
4958 return 0;
4959 });
4960
4961 vector<DNSRecord> ret;
4962 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4963 BOOST_CHECK_EQUAL(res, RCode::NoError);
4964 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4965 BOOST_REQUIRE_EQUAL(ret.size(), 6);
4966 BOOST_CHECK_EQUAL(queriesCount, 6);
4967
4968 /* again, to test the cache */
4969 ret.clear();
4970 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4971 BOOST_CHECK_EQUAL(res, RCode::NoError);
4972 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4973 BOOST_REQUIRE_EQUAL(ret.size(), 6);
4974 BOOST_CHECK_EQUAL(queriesCount, 6);
4975 }
4976
4977 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
4978 std::unique_ptr<SyncRes> sr;
4979 initSR(sr, true);
4980
4981 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4982
4983 primeHints();
4984 const DNSName target("www.com.");
4985 testkeysset_t keys;
4986
4987 auto luaconfsCopy = g_luaconfs.getCopy();
4988 luaconfsCopy.dsAnchors.clear();
4989 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4990 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4991
4992 g_luaconfs.setState(luaconfsCopy);
4993
4994 size_t queriesCount = 0;
4995
4996 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) {
4997 queriesCount++;
4998
4999 if (type == QType::DS || type == QType::DNSKEY) {
5000 if (type == QType::DS && domain == target) {
5001 DNSName auth("com.");
5002 setLWResult(res, 0, true, false, true);
5003
5004 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5005 addRRSIG(keys, res->d_records, auth, 300);
5006 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5007 /* first the closest encloser */
5008 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5009 addRRSIG(keys, res->d_records, auth, 300);
5010 /* then the next closer */
5011 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5012 addRRSIG(keys, res->d_records, auth, 300);
5013 /* a wildcard matches but has no record for this type */
5014 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5015 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5016 return 1;
5017 }
5018 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5019 }
5020 else {
5021 if (isRootServer(ip)) {
5022 setLWResult(res, 0, false, false, true);
5023 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5024 addDS(DNSName("com."), 300, res->d_records, keys);
5025 addRRSIG(keys, res->d_records, DNSName("."), 300);
5026 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5027 return 1;
5028 }
5029 else if (ip == ComboAddress("192.0.2.1:53")) {
5030 setLWResult(res, 0, true, false, true);
5031 /* no data */
5032 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5033 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5034 /* no record for this name */
5035 /* first the closest encloser */
5036 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5037 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5038 /* then the next closer */
5039 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5040 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5041 /* a wildcard matches but has no record for this type */
5042 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5043 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5044 return 1;
5045 }
5046 }
5047
5048 return 0;
5049 });
5050
5051 vector<DNSRecord> ret;
5052 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5053 BOOST_CHECK_EQUAL(res, RCode::NoError);
5054 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5055 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5056 BOOST_CHECK_EQUAL(queriesCount, 6);
5057
5058 /* again, to test the cache */
5059 ret.clear();
5060 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5061 BOOST_CHECK_EQUAL(res, RCode::NoError);
5062 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5063 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5064 BOOST_CHECK_EQUAL(queriesCount, 6);
5065 }
5066
5067 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5068 std::unique_ptr<SyncRes> sr;
5069 initSR(sr, true);
5070
5071 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5072
5073 primeHints();
5074 const DNSName target("www.com.");
5075 testkeysset_t keys;
5076
5077 auto luaconfsCopy = g_luaconfs.getCopy();
5078 luaconfsCopy.dsAnchors.clear();
5079 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5080 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5081
5082 g_luaconfs.setState(luaconfsCopy);
5083
5084 size_t queriesCount = 0;
5085
5086 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) {
5087 queriesCount++;
5088
5089 if (type == QType::DS || type == QType::DNSKEY) {
5090 if (type == QType::DS && domain == target) {
5091 DNSName auth("com.");
5092 setLWResult(res, 0, true, false, true);
5093
5094 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5095 addRRSIG(keys, res->d_records, auth, 300);
5096 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5097 /* first the closest encloser */
5098 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5099 addRRSIG(keys, res->d_records, auth, 300);
5100 /* then the next closer */
5101 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5102 addRRSIG(keys, res->d_records, auth, 300);
5103 /* a wildcard matches but has no record for this type */
5104 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5105 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5106 return 1;
5107 }
5108 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5109 }
5110 else {
5111 if (isRootServer(ip)) {
5112 setLWResult(res, 0, false, false, true);
5113 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5114 addDS(DNSName("com."), 300, res->d_records, keys);
5115 addRRSIG(keys, res->d_records, DNSName("."), 300);
5116 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5117 return 1;
5118 }
5119 else if (ip == ComboAddress("192.0.2.1:53")) {
5120 setLWResult(res, 0, true, false, true);
5121 /* no data */
5122 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5123 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5124 /* no record for this name */
5125 /* first the closest encloser */
5126 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5127 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5128 /* then the next closer */
5129 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5130 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5131 /* a wildcard matches but has no record for this type */
5132 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5133 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5134 return 1;
5135 }
5136 }
5137
5138 return 0;
5139 });
5140
5141 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5142 vector<DNSRecord> ret;
5143 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5144 BOOST_CHECK_EQUAL(res, RCode::NoError);
5145 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5146 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5147 BOOST_CHECK_EQUAL(queriesCount, 6);
5148
5149 /* again, to test the cache */
5150 ret.clear();
5151 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5152 BOOST_CHECK_EQUAL(res, RCode::NoError);
5153 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5154 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5155 BOOST_CHECK_EQUAL(queriesCount, 6);
5156 }
5157
5158 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5159 std::unique_ptr<SyncRes> sr;
5160 initSR(sr, true);
5161
5162 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5163
5164 primeHints();
5165 const DNSName target("www.powerdns.com.");
5166 testkeysset_t keys;
5167
5168 auto luaconfsCopy = g_luaconfs.getCopy();
5169 luaconfsCopy.dsAnchors.clear();
5170 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5171 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5172 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5173
5174 g_luaconfs.setState(luaconfsCopy);
5175
5176 size_t queriesCount = 0;
5177
5178 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) {
5179 queriesCount++;
5180
5181 if (type == QType::DS || type == QType::DNSKEY) {
5182 if (type == QType::DS && domain == target) {
5183 setLWResult(res, RCode::NoError, true, false, true);
5184 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5185 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5186 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5187 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5188 return 1;
5189 }
5190 else {
5191 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5192 }
5193 }
5194 else {
5195 if (isRootServer(ip)) {
5196 setLWResult(res, 0, false, false, true);
5197 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5198 addDS(DNSName("com."), 300, res->d_records, keys);
5199 addRRSIG(keys, res->d_records, DNSName("."), 300);
5200 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5201 return 1;
5202 }
5203 else if (ip == ComboAddress("192.0.2.1:53")) {
5204 if (domain == DNSName("com.")) {
5205 setLWResult(res, 0, true, false, true);
5206 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5207 addRRSIG(keys, res->d_records, domain, 300);
5208 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5209 addRRSIG(keys, res->d_records, domain, 300);
5210 }
5211 else {
5212 setLWResult(res, 0, false, false, true);
5213 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5214 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5215 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5216 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5217 }
5218 return 1;
5219 }
5220 else if (ip == ComboAddress("192.0.2.2:53")) {
5221 setLWResult(res, 0, true, false, true);
5222 if (type == QType::NS) {
5223 if (domain == DNSName("powerdns.com.")) {
5224 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5225 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5226 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5227 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5228 }
5229 else {
5230 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5231 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5232 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5233 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5234 }
5235 }
5236 else {
5237 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5238 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5239 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5240 /* first the closest encloser */
5241 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5242 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5243 /* then the next closer */
5244 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5245 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5246 }
5247 return 1;
5248 }
5249 }
5250
5251 return 0;
5252 });
5253
5254 vector<DNSRecord> ret;
5255 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5256 BOOST_CHECK_EQUAL(res, RCode::NoError);
5257 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5258 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5259 BOOST_CHECK_EQUAL(queriesCount, 9);
5260
5261 /* again, to test the cache */
5262 ret.clear();
5263 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5264 BOOST_CHECK_EQUAL(res, RCode::NoError);
5265 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5266 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5267 BOOST_CHECK_EQUAL(queriesCount, 9);
5268 }
5269
5270 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5271 std::unique_ptr<SyncRes> sr;
5272 initSR(sr, true);
5273
5274 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5275
5276 primeHints();
5277 const DNSName target("www.powerdns.com.");
5278 testkeysset_t keys;
5279
5280 auto luaconfsCopy = g_luaconfs.getCopy();
5281 luaconfsCopy.dsAnchors.clear();
5282 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5283 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5284 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5285
5286 g_luaconfs.setState(luaconfsCopy);
5287
5288 size_t queriesCount = 0;
5289
5290 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) {
5291 queriesCount++;
5292
5293 if (type == QType::DS || type == QType::DNSKEY) {
5294 if (type == QType::DS && domain == target) {
5295 setLWResult(res, RCode::NoError, true, false, true);
5296 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5297 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5298 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5299 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5300 return 1;
5301 }
5302 else {
5303 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5304 }
5305 }
5306 else {
5307 if (isRootServer(ip)) {
5308 setLWResult(res, 0, false, false, true);
5309 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5310 addDS(DNSName("com."), 300, res->d_records, keys);
5311 addRRSIG(keys, res->d_records, DNSName("."), 300);
5312 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5313 return 1;
5314 }
5315 else if (ip == ComboAddress("192.0.2.1:53")) {
5316 if (domain == DNSName("com.")) {
5317 setLWResult(res, 0, true, false, true);
5318 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5319 addRRSIG(keys, res->d_records, domain, 300);
5320 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5321 addRRSIG(keys, res->d_records, domain, 300);
5322 }
5323 else {
5324 setLWResult(res, 0, false, false, true);
5325 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5326 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5327 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5328 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5329 }
5330 return 1;
5331 }
5332 else if (ip == ComboAddress("192.0.2.2:53")) {
5333 setLWResult(res, 0, true, false, true);
5334 if (type == QType::NS) {
5335 if (domain == DNSName("powerdns.com.")) {
5336 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5337 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5338 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5339 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5340 }
5341 else {
5342 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5343 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5344 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5345 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5346 }
5347 }
5348 else {
5349 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5350 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5351 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5352 /* first the closest encloser */
5353 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5354 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5355 /* then the next closer */
5356 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5357 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5358 }
5359 return 1;
5360 }
5361 }
5362
5363 return 0;
5364 });
5365
5366 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5367 we should end up Insecure */
5368 vector<DNSRecord> ret;
5369 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5370 BOOST_CHECK_EQUAL(res, RCode::NoError);
5371 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5372 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5373 BOOST_CHECK_EQUAL(queriesCount, 9);
5374
5375 /* again, to test the cache */
5376 ret.clear();
5377 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5378 BOOST_CHECK_EQUAL(res, RCode::NoError);
5379 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5380 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5381 BOOST_CHECK_EQUAL(queriesCount, 9);
5382 }
5383
5384 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5385 std::unique_ptr<SyncRes> sr;
5386 initSR(sr, true);
5387
5388 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5389
5390 primeHints();
5391 const DNSName target("www.powerdns.com.");
5392 testkeysset_t keys;
5393
5394 auto luaconfsCopy = g_luaconfs.getCopy();
5395 luaconfsCopy.dsAnchors.clear();
5396 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5397 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5398 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5399
5400 g_luaconfs.setState(luaconfsCopy);
5401
5402 size_t queriesCount = 0;
5403
5404 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) {
5405 queriesCount++;
5406
5407 if (type == QType::DS || type == QType::DNSKEY) {
5408 if (type == QType::DS && domain == target) {
5409 setLWResult(res, RCode::NoError, true, false, true);
5410 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5411 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5412 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5413 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5414 return 1;
5415 }
5416 else {
5417 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5418 }
5419 }
5420 else {
5421 if (isRootServer(ip)) {
5422 setLWResult(res, 0, false, false, true);
5423 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5424 addDS(DNSName("com."), 300, res->d_records, keys);
5425 addRRSIG(keys, res->d_records, DNSName("."), 300);
5426 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5427 return 1;
5428 }
5429 else if (ip == ComboAddress("192.0.2.1:53")) {
5430 if (domain == DNSName("com.")) {
5431 setLWResult(res, 0, true, false, true);
5432 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5433 addRRSIG(keys, res->d_records, domain, 300);
5434 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5435 addRRSIG(keys, res->d_records, domain, 300);
5436 }
5437 else {
5438 setLWResult(res, 0, false, false, true);
5439 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5440 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5441 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5442 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5443 }
5444 return 1;
5445 }
5446 else if (ip == ComboAddress("192.0.2.2:53")) {
5447 setLWResult(res, 0, true, false, true);
5448 if (type == QType::NS) {
5449 if (domain == DNSName("powerdns.com.")) {
5450 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5451 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5452 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5453 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5454 }
5455 else {
5456 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5457 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5458 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5459 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5460 }
5461 }
5462 else {
5463 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5464 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5465 }
5466 return 1;
5467 }
5468 }
5469
5470 return 0;
5471 });
5472
5473 vector<DNSRecord> ret;
5474 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5475 BOOST_CHECK_EQUAL(res, RCode::NoError);
5476 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5477 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5478 BOOST_CHECK_EQUAL(queriesCount, 9);
5479
5480 /* again, to test the cache */
5481 ret.clear();
5482 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5483 BOOST_CHECK_EQUAL(res, RCode::NoError);
5484 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5485 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5486 BOOST_CHECK_EQUAL(queriesCount, 9);
5487 }
5488
5489 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5490 std::unique_ptr<SyncRes> sr;
5491 initSR(sr, true);
5492
5493 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5494
5495 primeHints();
5496 const DNSName target("www.powerdns.com.");
5497 testkeysset_t keys;
5498
5499 auto luaconfsCopy = g_luaconfs.getCopy();
5500 luaconfsCopy.dsAnchors.clear();
5501 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5502 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5503 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5504
5505 g_luaconfs.setState(luaconfsCopy);
5506
5507 size_t queriesCount = 0;
5508 size_t dsQueriesCount = 0;
5509
5510 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) {
5511 queriesCount++;
5512
5513 if (type == QType::DS) {
5514 DNSName auth(domain);
5515 auth.chopOff();
5516 dsQueriesCount++;
5517
5518 setLWResult(res, 0, true, false, true);
5519 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5520 addRRSIG(keys, res->d_records, auth, 300);
5521 return 1;
5522 }
5523 else if (type == QType::DNSKEY) {
5524 setLWResult(res, 0, true, false, true);
5525 addDNSKEY(keys, domain, 300, res->d_records);
5526 addRRSIG(keys, res->d_records, domain, 300);
5527 return 1;
5528 }
5529 else {
5530 if (isRootServer(ip)) {
5531 setLWResult(res, 0, false, false, true);
5532 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5533 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5534 /* No DS on referral, and no denial of the DS either */
5535 return 1;
5536 }
5537 else if (ip == ComboAddress("192.0.2.1:53")) {
5538 if (domain == DNSName("com.")) {
5539 setLWResult(res, 0, true, false, true);
5540 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5541 addRRSIG(keys, res->d_records, domain, 300);
5542 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5543 addRRSIG(keys, res->d_records, domain, 300);
5544 }
5545 else {
5546 setLWResult(res, 0, false, false, true);
5547 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5548 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5549 /* No DS on referral, and no denial of the DS either */
5550 }
5551 return 1;
5552 }
5553 else if (ip == ComboAddress("192.0.2.2:53")) {
5554 setLWResult(res, 0, true, false, true);
5555 if (type == QType::NS) {
5556 if (domain == DNSName("powerdns.com.")) {
5557 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5558 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5559 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5560 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5561 }
5562 else {
5563 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5564 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5565 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5566 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5567 }
5568 }
5569 else {
5570 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5571 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5572 }
5573
5574 return 1;
5575 }
5576 }
5577
5578 return 0;
5579 });
5580
5581 vector<DNSRecord> ret;
5582 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5583 BOOST_CHECK_EQUAL(res, RCode::NoError);
5584 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5585 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5586 BOOST_CHECK_EQUAL(queriesCount, 9);
5587 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5588
5589 /* again, to test the cache */
5590 ret.clear();
5591 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5592 BOOST_CHECK_EQUAL(res, RCode::NoError);
5593 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5594 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5595 BOOST_CHECK_EQUAL(queriesCount, 9);
5596 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5597 }
5598
5599 BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
5600 std::unique_ptr<SyncRes> sr;
5601 initSR(sr, true);
5602
5603 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5604
5605 primeHints();
5606 const DNSName target("www.powerdns.com.");
5607 testkeysset_t keys;
5608
5609 auto luaconfsCopy = g_luaconfs.getCopy();
5610 luaconfsCopy.dsAnchors.clear();
5611 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5612 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5613 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5614 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5615
5616 g_luaconfs.setState(luaconfsCopy);
5617
5618 size_t queriesCount = 0;
5619
5620 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) {
5621 queriesCount++;
5622
5623 if (type == QType::DS) {
5624 DNSName auth(domain);
5625 auth.chopOff();
5626
5627 setLWResult(res, 0, true, false, true);
5628 if (domain == target) {
5629 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5630 addRRSIG(keys, res->d_records, target, 300);
5631 }
5632 else {
5633 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5634 addRRSIG(keys, res->d_records, auth, 300);
5635 }
5636 return 1;
5637 }
5638 else if (type == QType::DNSKEY) {
5639 setLWResult(res, 0, true, false, true);
5640 addDNSKEY(keys, domain, 300, res->d_records);
5641 addRRSIG(keys, res->d_records, domain, 300);
5642 return 1;
5643 }
5644 else {
5645 if (isRootServer(ip)) {
5646 setLWResult(res, 0, false, false, true);
5647 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5648 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5649 addDS(DNSName("com."), 300, res->d_records, keys);
5650 addRRSIG(keys, res->d_records, DNSName("."), 300);
5651 return 1;
5652 }
5653 else if (ip == ComboAddress("192.0.2.1:53")) {
5654 if (domain == DNSName("com.")) {
5655 setLWResult(res, 0, true, false, true);
5656 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5657 addRRSIG(keys, res->d_records, domain, 300);
5658 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5659 addRRSIG(keys, res->d_records, domain, 300);
5660 }
5661 else {
5662 setLWResult(res, 0, false, false, true);
5663 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5664 /* no DS */
5665 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5666 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5667 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5668 }
5669 return 1;
5670 }
5671 else if (ip == ComboAddress("192.0.2.2:53")) {
5672 if (type == QType::NS) {
5673 if (domain == DNSName("powerdns.com.")) {
5674 setLWResult(res, RCode::Refused, false, false, true);
5675 }
5676 else {
5677 setLWResult(res, 0, true, false, true);
5678 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5679 addRRSIG(keys, res->d_records, domain, 300);
5680 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5681 addRRSIG(keys, res->d_records, domain, 300);
5682 }
5683 }
5684 else {
5685 setLWResult(res, 0, true, false, true);
5686 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5687 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
5688 }
5689
5690 return 1;
5691 }
5692 }
5693
5694 return 0;
5695 });
5696
5697 vector<DNSRecord> ret;
5698 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5699 BOOST_CHECK_EQUAL(res, RCode::NoError);
5700 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5701 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5702 BOOST_CHECK_EQUAL(queriesCount, 9);
5703
5704 /* again, to test the cache */
5705 ret.clear();
5706 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5707 BOOST_CHECK_EQUAL(res, RCode::NoError);
5708 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5709 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5710 BOOST_CHECK_EQUAL(queriesCount, 9);
5711 }
5712
5713 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
5714 std::unique_ptr<SyncRes> sr;
5715 initSR(sr, true);
5716
5717 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5718
5719 primeHints();
5720 const DNSName target("www.powerdns.com.");
5721 testkeysset_t keys;
5722
5723 auto luaconfsCopy = g_luaconfs.getCopy();
5724 luaconfsCopy.dsAnchors.clear();
5725 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5726 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5727
5728 g_luaconfs.setState(luaconfsCopy);
5729
5730 size_t queriesCount = 0;
5731 size_t dsQueriesCount = 0;
5732
5733 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) {
5734 queriesCount++;
5735
5736 if (type == QType::DS) {
5737 DNSName auth(domain);
5738 auth.chopOff();
5739 dsQueriesCount++;
5740
5741 setLWResult(res, 0, true, false, true);
5742 if (domain == DNSName("com.")) {
5743 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5744 }
5745 else {
5746 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5747 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5748 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
5749 }
5750 addRRSIG(keys, res->d_records, auth, 300);
5751 return 1;
5752 }
5753 else if (type == QType::DNSKEY) {
5754 setLWResult(res, 0, true, false, true);
5755 addDNSKEY(keys, domain, 300, res->d_records);
5756 addRRSIG(keys, res->d_records, domain, 300);
5757 return 1;
5758 }
5759 else {
5760 if (isRootServer(ip)) {
5761 setLWResult(res, 0, false, false, true);
5762 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5763 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5764 /* No DS on referral, and no denial of the DS either */
5765 return 1;
5766 }
5767 else if (ip == ComboAddress("192.0.2.1:53")) {
5768 if (domain == DNSName("com.")) {
5769 setLWResult(res, 0, true, false, true);
5770 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5771 addRRSIG(keys, res->d_records, domain, 300);
5772 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5773 addRRSIG(keys, res->d_records, domain, 300);
5774 }
5775 else {
5776 setLWResult(res, 0, false, false, true);
5777 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5778 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5779 /* No DS on referral, and no denial of the DS either */
5780 }
5781 return 1;
5782 }
5783 else if (ip == ComboAddress("192.0.2.2:53")) {
5784 setLWResult(res, 0, true, false, true);
5785 if (type == QType::NS) {
5786 if (domain == DNSName("powerdns.com.")) {
5787 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5788 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5789 }
5790 else {
5791 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5792 }
5793 }
5794 else {
5795 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5796 }
5797 return 1;
5798 }
5799 }
5800
5801 return 0;
5802 });
5803
5804 vector<DNSRecord> ret;
5805 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5806 BOOST_CHECK_EQUAL(res, RCode::NoError);
5807 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5808 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5809 BOOST_CHECK_EQUAL(queriesCount, 7);
5810 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
5811
5812 /* again, to test the cache */
5813 ret.clear();
5814 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5815 BOOST_CHECK_EQUAL(res, RCode::NoError);
5816 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5817 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5818 BOOST_CHECK_EQUAL(queriesCount, 7);
5819 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
5820 }
5821
5822 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
5823 std::unique_ptr<SyncRes> sr;
5824 initSR(sr, true);
5825
5826 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5827
5828 primeHints();
5829 const DNSName target("powerdns.com.");
5830 testkeysset_t keys;
5831
5832 auto luaconfsCopy = g_luaconfs.getCopy();
5833 luaconfsCopy.dsAnchors.clear();
5834 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5835 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5836 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5837
5838 g_luaconfs.setState(luaconfsCopy);
5839
5840 size_t queriesCount = 0;
5841
5842 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) {
5843 queriesCount++;
5844
5845 if (type == QType::DS || type == QType::DNSKEY) {
5846 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5847 }
5848 else {
5849 if (isRootServer(ip)) {
5850 setLWResult(res, 0, false, false, true);
5851 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5852 addDS(DNSName("com."), 300, res->d_records, keys);
5853 addRRSIG(keys, res->d_records, DNSName("."), 300);
5854 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5855 return 1;
5856 }
5857 else if (ip == ComboAddress("192.0.2.1:53")) {
5858 if (domain == DNSName("com.")) {
5859 setLWResult(res, 0, true, false, true);
5860 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
5861 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5862 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5863 }
5864 else {
5865 setLWResult(res, 0, false, false, true);
5866 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5867 addDS(domain, 300, res->d_records, keys);
5868 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5869 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5870 }
5871 return 1;
5872 }
5873 else if (ip == ComboAddress("192.0.2.2:53")) {
5874 setLWResult(res, 0, true, false, true);
5875 if (type == QType::NS) {
5876 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5877 addRRSIG(keys, res->d_records, domain, 300);
5878 }
5879 else {
5880 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5881 addRRSIG(keys, res->d_records, domain, 300);
5882 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
5883 /* NO RRSIG for the NSEC record! */
5884 }
5885 return 1;
5886 }
5887 }
5888
5889 return 0;
5890 });
5891
5892 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
5893 vector<DNSRecord> ret;
5894 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5895 BOOST_CHECK_EQUAL(res, RCode::NoError);
5896 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5897 BOOST_CHECK_EQUAL(ret.size(), 3);
5898 BOOST_CHECK_EQUAL(queriesCount, 8);
5899
5900 /* again, to test the cache */
5901 ret.clear();
5902 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5903 BOOST_CHECK_EQUAL(res, RCode::NoError);
5904 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5905 BOOST_REQUIRE_EQUAL(ret.size(), 3);
5906 BOOST_CHECK_EQUAL(queriesCount, 8);
5907 }
5908
5909 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
5910 std::unique_ptr<SyncRes> sr;
5911 initSR(sr, true);
5912
5913 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5914
5915 primeHints();
5916 const DNSName target("powerdns.com.");
5917 testkeysset_t keys;
5918
5919 auto luaconfsCopy = g_luaconfs.getCopy();
5920 luaconfsCopy.dsAnchors.clear();
5921 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5922 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5923 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5924
5925 g_luaconfs.setState(luaconfsCopy);
5926
5927 size_t queriesCount = 0;
5928
5929 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) {
5930 queriesCount++;
5931
5932 if (type == QType::DS || type == QType::DNSKEY) {
5933 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5934 }
5935 else {
5936 if (isRootServer(ip)) {
5937 setLWResult(res, 0, false, false, true);
5938 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5939 addDS(DNSName("com."), 300, res->d_records, keys);
5940 addRRSIG(keys, res->d_records, DNSName("."), 300);
5941 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5942 return 1;
5943 }
5944 else if (ip == ComboAddress("192.0.2.1:53")) {
5945 if (domain == DNSName("com.")) {
5946 setLWResult(res, 0, true, false, true);
5947 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
5948 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5949 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5950 }
5951 else {
5952 setLWResult(res, 0, false, false, true);
5953 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5954 addDS(domain, 300, res->d_records, keys);
5955 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5956 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5957 }
5958 return 1;
5959 }
5960 else if (ip == ComboAddress("192.0.2.2:53")) {
5961 setLWResult(res, 0, true, false, true);
5962 if (type == QType::NS) {
5963 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5964 addRRSIG(keys, res->d_records, domain, 300);
5965 }
5966 else {
5967 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5968 addRRSIG(keys, res->d_records, domain, 300);
5969
5970 /* NO NSEC record! */
5971 }
5972 return 1;
5973 }
5974 }
5975
5976 return 0;
5977 });
5978
5979 /* no NSEC record in a secure zone, should be Bogus! */
5980 vector<DNSRecord> ret;
5981 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5982 BOOST_CHECK_EQUAL(res, RCode::NoError);
5983 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5984 BOOST_CHECK_EQUAL(ret.size(), 2);
5985 BOOST_CHECK_EQUAL(queriesCount, 8);
5986
5987 /* again, to test the cache */
5988 ret.clear();
5989 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5990 BOOST_CHECK_EQUAL(res, RCode::NoError);
5991 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5992 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5993 BOOST_CHECK_EQUAL(queriesCount, 8);
5994 }
5995
5996 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
5997 std::unique_ptr<SyncRes> sr;
5998 initSR(sr, true);
5999
6000 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6001
6002 primeHints();
6003 const DNSName target("powerdns.com.");
6004 const ComboAddress targetAddr("192.0.2.42");
6005 testkeysset_t keys;
6006
6007 auto luaconfsCopy = g_luaconfs.getCopy();
6008 luaconfsCopy.dsAnchors.clear();
6009 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6010 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6011
6012 g_luaconfs.setState(luaconfsCopy);
6013
6014 size_t queriesCount = 0;
6015
6016 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) {
6017 queriesCount++;
6018
6019 if (type == QType::DS) {
6020 if (domain == target) {
6021 setLWResult(res, 0, false, false, true);
6022 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6023 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6024 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6025 return 1;
6026 } else {
6027 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6028 }
6029 }
6030 else if (type == QType::DNSKEY) {
6031 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6032 setLWResult(res, 0, true, false, true);
6033 addDNSKEY(keys, domain, 300, res->d_records);
6034 addRRSIG(keys, res->d_records, domain, 300);
6035 return 1;
6036 }
6037 else {
6038 setLWResult(res, 0, false, false, true);
6039 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6040 return 1;
6041 }
6042 }
6043 else {
6044 if (isRootServer(ip)) {
6045 setLWResult(res, 0, false, false, true);
6046 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6047 addDS(DNSName("com."), 300, res->d_records, keys);
6048 addRRSIG(keys, res->d_records, DNSName("."), 300);
6049 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6050 return 1;
6051 }
6052 else if (ip == ComboAddress("192.0.2.1:53")) {
6053 if (domain == DNSName("com.")) {
6054 setLWResult(res, 0, true, false, true);
6055 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6056 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6057 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6058 }
6059 else {
6060 setLWResult(res, 0, false, false, true);
6061 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6062 /* no DS */
6063 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6064 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6065 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6066 }
6067 return 1;
6068 }
6069 else if (ip == ComboAddress("192.0.2.2:53")) {
6070 setLWResult(res, 0, true, false, true);
6071 if (type == QType::NS) {
6072 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6073 }
6074 else {
6075 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6076 }
6077 return 1;
6078 }
6079 }
6080
6081 return 0;
6082 });
6083
6084 vector<DNSRecord> ret;
6085 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6086 BOOST_CHECK_EQUAL(res, RCode::NoError);
6087 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6088 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6089 BOOST_CHECK(ret[0].d_type == QType::A);
6090 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6091 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6092 1 query for A */
6093 BOOST_CHECK_EQUAL(queriesCount, 7);
6094
6095 /* again, to test the cache */
6096 ret.clear();
6097 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6098 BOOST_CHECK_EQUAL(res, RCode::NoError);
6099 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6100 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6101 BOOST_CHECK(ret[0].d_type == QType::A);
6102 BOOST_CHECK_EQUAL(queriesCount, 7);
6103 }
6104
6105
6106 BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6107 /*
6108 Direct DS query:
6109 - parent is secure, zone is secure: DS should be secure
6110 */
6111 std::unique_ptr<SyncRes> sr;
6112 initSR(sr, true);
6113
6114 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6115
6116 primeHints();
6117 const DNSName target("powerdns.com.");
6118 testkeysset_t keys;
6119
6120 auto luaconfsCopy = g_luaconfs.getCopy();
6121 luaconfsCopy.dsAnchors.clear();
6122 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6123 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6124 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6125
6126 g_luaconfs.setState(luaconfsCopy);
6127
6128 size_t queriesCount = 0;
6129
6130 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) {
6131 queriesCount++;
6132
6133 if (type == QType::DS || type == QType::DNSKEY) {
6134 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6135 }
6136 else {
6137 if (isRootServer(ip)) {
6138 setLWResult(res, 0, false, false, true);
6139 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6140 addDS(DNSName("com."), 300, res->d_records, keys);
6141 addRRSIG(keys, res->d_records, DNSName("."), 300);
6142 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6143 return 1;
6144 }
6145 }
6146
6147 return 0;
6148 });
6149
6150 vector<DNSRecord> ret;
6151 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6152 BOOST_CHECK_EQUAL(res, RCode::NoError);
6153 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6154 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6155 for (const auto& record : ret) {
6156 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6157 }
6158 BOOST_CHECK_EQUAL(queriesCount, 4);
6159
6160 /* again, to test the cache */
6161 ret.clear();
6162 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6163 BOOST_CHECK_EQUAL(res, RCode::NoError);
6164 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6165 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6166 for (const auto& record : ret) {
6167 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6168 }
6169 BOOST_CHECK_EQUAL(queriesCount, 4);
6170 }
6171
6172 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6173 /*
6174 Direct DS query:
6175 - parent is secure, zone is insecure: DS denial should be secure
6176 */
6177 std::unique_ptr<SyncRes> sr;
6178 initSR(sr, true);
6179
6180 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6181
6182 primeHints();
6183 const DNSName target("powerdns.com.");
6184 testkeysset_t keys;
6185
6186 auto luaconfsCopy = g_luaconfs.getCopy();
6187 luaconfsCopy.dsAnchors.clear();
6188 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6189 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6190
6191 g_luaconfs.setState(luaconfsCopy);
6192
6193 size_t queriesCount = 0;
6194
6195 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) {
6196 queriesCount++;
6197
6198 if (type == QType::DS || type == QType::DNSKEY) {
6199 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6200 }
6201 else {
6202 if (isRootServer(ip)) {
6203 setLWResult(res, 0, false, false, true);
6204 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6205 addDS(DNSName("com."), 300, res->d_records, keys);
6206 addRRSIG(keys, res->d_records, DNSName("."), 300);
6207 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6208 return 1;
6209 }
6210 }
6211
6212 return 0;
6213 });
6214
6215 vector<DNSRecord> ret;
6216 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6217 BOOST_CHECK_EQUAL(res, RCode::NoError);
6218 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6219 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6220 for (const auto& record : ret) {
6221 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6222 }
6223 BOOST_CHECK_EQUAL(queriesCount, 4);
6224
6225 /* again, to test the cache */
6226 ret.clear();
6227 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6228 BOOST_CHECK_EQUAL(res, RCode::NoError);
6229 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6230 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6231 for (const auto& record : ret) {
6232 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6233 }
6234 BOOST_CHECK_EQUAL(queriesCount, 4);
6235 }
6236
6237 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6238 std::unique_ptr<SyncRes> sr;
6239 initSR(sr, true);
6240
6241 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6242
6243 primeHints();
6244 const DNSName target("www.sub.powerdns.com.");
6245 const ComboAddress targetAddr("192.0.2.42");
6246 testkeysset_t keys;
6247
6248 auto luaconfsCopy = g_luaconfs.getCopy();
6249 luaconfsCopy.dsAnchors.clear();
6250 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6251 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6252 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6253
6254 g_luaconfs.setState(luaconfsCopy);
6255
6256 size_t queriesCount = 0;
6257
6258 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) {
6259 queriesCount++;
6260
6261 if (type == QType::DS) {
6262 if (domain == DNSName("sub.powerdns.com.")) {
6263 setLWResult(res, 0, false, false, true);
6264 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6265 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6266 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6267 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6268 return 1;
6269 }
6270 else if (domain == DNSName("www.sub.powerdns.com.")) {
6271 setLWResult(res, 0, false, false, true);
6272 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);
6273 return 1;
6274 }
6275 else {
6276 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6277 }
6278 }
6279 else if (type == QType::DNSKEY) {
6280 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6281 setLWResult(res, 0, true, false, true);
6282 addDNSKEY(keys, domain, 300, res->d_records);
6283 addRRSIG(keys, res->d_records, domain, 300);
6284 return 1;
6285 }
6286 else {
6287 setLWResult(res, 0, false, false, true);
6288 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6289 return 1;
6290 }
6291 }
6292 else {
6293 if (isRootServer(ip)) {
6294 setLWResult(res, 0, false, false, true);
6295 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6296 addDS(DNSName("com."), 300, res->d_records, keys);
6297 addRRSIG(keys, res->d_records, DNSName("."), 300);
6298 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6299 return 1;
6300 }
6301 else if (ip == ComboAddress("192.0.2.1:53")) {
6302 if (domain == DNSName("com.")) {
6303 setLWResult(res, 0, true, false, true);
6304 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6305 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6306 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6307 }
6308 else {
6309 setLWResult(res, 0, false, false, true);
6310 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6311 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6312 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6313 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6314 }
6315 return 1;
6316 }
6317 else if (ip == ComboAddress("192.0.2.2:53")) {
6318 setLWResult(res, 0, true, false, true);
6319 if (type == QType::NS) {
6320 if (domain == DNSName("www.sub.powerdns.com.")) {
6321 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);
6322 }
6323 else if (domain == DNSName("sub.powerdns.com.")) {
6324 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6325 }
6326 else if (domain == DNSName("powerdns.com.")) {
6327 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6328 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6329 }
6330 } else {
6331 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6332 }
6333 return 1;
6334 }
6335 }
6336
6337 return 0;
6338 });
6339
6340 vector<DNSRecord> ret;
6341 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6342 BOOST_CHECK_EQUAL(res, RCode::NoError);
6343 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6344 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6345 BOOST_CHECK(ret[0].d_type == QType::A);
6346 BOOST_CHECK_EQUAL(queriesCount, 9);
6347
6348 /* again, to test the cache */
6349 ret.clear();
6350 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6351 BOOST_CHECK_EQUAL(res, RCode::NoError);
6352 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6353 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6354 BOOST_CHECK(ret[0].d_type == QType::A);
6355 BOOST_CHECK_EQUAL(queriesCount, 9);
6356 }
6357
6358 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6359 std::unique_ptr<SyncRes> sr;
6360 initSR(sr, true);
6361
6362 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6363
6364 primeHints();
6365 const DNSName target("www.sub.powerdns.com.");
6366 const ComboAddress targetAddr("192.0.2.42");
6367 testkeysset_t keys;
6368
6369 auto luaconfsCopy = g_luaconfs.getCopy();
6370 luaconfsCopy.dsAnchors.clear();
6371 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6372 /* No key material for .com */
6373 /* But TA for sub.powerdns.com. */
6374 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6375 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6376 g_luaconfs.setState(luaconfsCopy);
6377
6378 size_t queriesCount = 0;
6379
6380 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) {
6381 queriesCount++;
6382
6383 if (type == QType::DS) {
6384 if (domain == DNSName("www.sub.powerdns.com")) {
6385 setLWResult(res, 0, false, false, true);
6386 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);
6387 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6388 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6389 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6390 }
6391 else {
6392 setLWResult(res, 0, false, false, true);
6393
6394 if (domain == DNSName("com.")) {
6395 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6396 /* no DS */
6397 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6398 addRRSIG(keys, res->d_records, DNSName("."), 300);
6399 }
6400 else {
6401 setLWResult(res, 0, false, false, true);
6402 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6403 }
6404 }
6405 return 1;
6406 }
6407 else if (type == QType::DNSKEY) {
6408 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
6409 setLWResult(res, 0, true, false, true);
6410 addDNSKEY(keys, domain, 300, res->d_records);
6411 addRRSIG(keys, res->d_records, domain, 300);
6412 return 1;
6413 }
6414 }
6415 else {
6416 if (isRootServer(ip)) {
6417 setLWResult(res, 0, false, false, true);
6418 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6419 /* no DS */
6420 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6421 addRRSIG(keys, res->d_records, DNSName("."), 300);
6422 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6423 return 1;
6424 }
6425 else if (ip == ComboAddress("192.0.2.1:53")) {
6426 if (domain == DNSName("com.")) {
6427 setLWResult(res, 0, true, false, true);
6428 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6429 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6430 }
6431 else if (domain.isPartOf(DNSName("powerdns.com."))) {
6432 setLWResult(res, 0, false, false, true);
6433 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6434 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6435 }
6436 return 1;
6437 }
6438 else if (ip == ComboAddress("192.0.2.2:53")) {
6439 setLWResult(res, 0, true, false, true);
6440 if (type == QType::NS) {
6441 if (domain == DNSName("www.sub.powerdns.com.")) {
6442 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);
6443 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6444 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6445 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6446 }
6447 else if (domain == DNSName("sub.powerdns.com.")) {
6448 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6449 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6450 }
6451 else if (domain == DNSName("powerdns.com.")) {
6452 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6453 }
6454 }
6455 else if (domain == DNSName("www.sub.powerdns.com.")) {
6456 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6457 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6458 }
6459 return 1;
6460 }
6461 }
6462
6463 return 0;
6464 });
6465
6466 vector<DNSRecord> ret;
6467 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6468 BOOST_CHECK_EQUAL(res, RCode::NoError);
6469 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6470 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6471 BOOST_CHECK(ret[0].d_type == QType::A);
6472 BOOST_CHECK_EQUAL(queriesCount, 7);
6473
6474 /* again, to test the cache */
6475 ret.clear();
6476 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6477 BOOST_CHECK_EQUAL(res, RCode::NoError);
6478 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6479 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6480 BOOST_CHECK(ret[0].d_type == QType::A);
6481 BOOST_CHECK_EQUAL(queriesCount, 7);
6482 }
6483
6484 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
6485 std::unique_ptr<SyncRes> sr;
6486 initSR(sr, true);
6487
6488 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6489
6490 primeHints();
6491 const DNSName target("powerdns.com.");
6492 testkeysset_t keys;
6493
6494 auto luaconfsCopy = g_luaconfs.getCopy();
6495 luaconfsCopy.dsAnchors.clear();
6496 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6497 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6498
6499 g_luaconfs.setState(luaconfsCopy);
6500
6501 size_t queriesCount = 0;
6502
6503 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) {
6504 queriesCount++;
6505
6506 if (type == QType::DS) {
6507 if (domain == target) {
6508 setLWResult(res, 0, false, false, true);
6509 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6510 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6511 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6512 return 1;
6513 }
6514 else {
6515 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6516 }
6517 }
6518 else if (type == QType::DNSKEY) {
6519 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6520 setLWResult(res, 0, true, false, true);
6521 addDNSKEY(keys, domain, 300, res->d_records);
6522 addRRSIG(keys, res->d_records, domain, 300);
6523 return 1;
6524 }
6525 else {
6526 setLWResult(res, 0, false, false, true);
6527 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6528 return 1;
6529 }
6530 }
6531 else {
6532 if (isRootServer(ip)) {
6533 setLWResult(res, 0, false, false, true);
6534 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6535 addDS(DNSName("com."), 300, res->d_records, keys);
6536 addRRSIG(keys, res->d_records, DNSName("."), 300);
6537 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6538 return 1;
6539 }
6540 else if (ip == ComboAddress("192.0.2.1:53")) {
6541 if (domain == DNSName("com.")) {
6542 setLWResult(res, 0, true, false, true);
6543 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6544 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6545 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6546 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6547 }
6548 else {
6549 setLWResult(res, 0, false, false, true);
6550 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6551 /* no DS */
6552 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6553 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6554 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6555 }
6556 return 1;
6557 }
6558 else if (ip == ComboAddress("192.0.2.2:53")) {
6559 if (type == QType::NS) {
6560 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6561 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6562 }
6563 else {
6564 setLWResult(res, 0, true, false, true);
6565 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6566 }
6567 return 1;
6568 }
6569 }
6570
6571 return 0;
6572 });
6573
6574 vector<DNSRecord> ret;
6575 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6576 BOOST_CHECK_EQUAL(res, RCode::NoError);
6577 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6578 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6579 /* 4 NS (com from root, com from com, powerdns.com from com,
6580 powerdns.com from powerdns.com)
6581 2 DNSKEY (. and com., none for powerdns.com because no DS)
6582 1 query for A
6583 */
6584 BOOST_CHECK_EQUAL(queriesCount, 7);
6585
6586 /* again, to test the cache */
6587 ret.clear();
6588 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6589 BOOST_CHECK_EQUAL(res, RCode::NoError);
6590 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6591 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6592 BOOST_CHECK_EQUAL(queriesCount, 7);
6593 }
6594
6595 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
6596 std::unique_ptr<SyncRes> sr;
6597 initSR(sr, true);
6598
6599 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6600
6601 primeHints();
6602 const DNSName target("powerdns.com.");
6603 const DNSName targetCName("power-dns.com.");
6604 const ComboAddress targetCNameAddr("192.0.2.42");
6605 testkeysset_t keys;
6606
6607 auto luaconfsCopy = g_luaconfs.getCopy();
6608 luaconfsCopy.dsAnchors.clear();
6609 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6610 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6611 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6612 g_luaconfs.setState(luaconfsCopy);
6613
6614 size_t queriesCount = 0;
6615
6616 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) {
6617 queriesCount++;
6618
6619 if (type == QType::DS) {
6620 if (domain == targetCName) {
6621 setLWResult(res, 0, false, false, true);
6622 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6623 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6624 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6625 return 1;
6626 }
6627 else {
6628 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6629 }
6630 }
6631 else if (type == QType::DNSKEY) {
6632 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6633 setLWResult(res, 0, true, false, true);
6634 addDNSKEY(keys, domain, 300, res->d_records);
6635 addRRSIG(keys, res->d_records, domain, 300);
6636 return 1;
6637 }
6638 else {
6639 setLWResult(res, 0, false, false, true);
6640 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6641 return 1;
6642 }
6643 }
6644 else {
6645 if (isRootServer(ip)) {
6646 setLWResult(res, 0, false, false, true);
6647 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6648 addDS(DNSName("com."), 300, res->d_records, keys);
6649 addRRSIG(keys, res->d_records, DNSName("."), 300);
6650 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6651 return 1;
6652 }
6653 else if (ip == ComboAddress("192.0.2.1:53")) {
6654 setLWResult(res, 0, false, false, true);
6655 if (domain == DNSName("com.")) {
6656 setLWResult(res, 0, true, false, true);
6657 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6658 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6659 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6660 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6661 }
6662 else {
6663 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6664 if (domain == DNSName("powerdns.com.")) {
6665 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6666 }
6667 else if (domain == targetCName) {
6668 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6669 }
6670 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6671 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6672 }
6673
6674 return 1;
6675 }
6676 else if (ip == ComboAddress("192.0.2.2:53")) {
6677 setLWResult(res, 0, true, false, true);
6678
6679 if (type == QType::NS) {
6680 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6681 if (domain == DNSName("powerdns.com.")) {
6682 addRRSIG(keys, res->d_records, domain, 300);
6683 }
6684 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6685 if (domain == DNSName("powerdns.com.")) {
6686 addRRSIG(keys, res->d_records, domain, 300);
6687 }
6688 }
6689 else {
6690 if (domain == DNSName("powerdns.com.")) {
6691 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6692 addRRSIG(keys, res->d_records, domain, 300);
6693 }
6694 else if (domain == targetCName) {
6695 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6696 }
6697 }
6698
6699 return 1;
6700 }
6701 }
6702
6703 return 0;
6704 });
6705
6706 vector<DNSRecord> ret;
6707 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6708 BOOST_CHECK_EQUAL(res, RCode::NoError);
6709 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6710 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6711 BOOST_CHECK_EQUAL(queriesCount, 11);
6712
6713 /* again, to test the cache */
6714 ret.clear();
6715 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6716 BOOST_CHECK_EQUAL(res, RCode::NoError);
6717 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6718 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6719 BOOST_CHECK_EQUAL(queriesCount, 11);
6720 }
6721
6722 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
6723 std::unique_ptr<SyncRes> sr;
6724 initSR(sr, true);
6725
6726 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6727
6728 primeHints();
6729 const DNSName target("power-dns.com.");
6730 const DNSName targetCName("powerdns.com.");
6731 const ComboAddress targetCNameAddr("192.0.2.42");
6732 testkeysset_t keys;
6733
6734 auto luaconfsCopy = g_luaconfs.getCopy();
6735 luaconfsCopy.dsAnchors.clear();
6736 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6737 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6738 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6739 g_luaconfs.setState(luaconfsCopy);
6740
6741 size_t queriesCount = 0;
6742
6743 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) {
6744 queriesCount++;
6745
6746 if (type == QType::DS) {
6747 if (domain == DNSName("power-dns.com.")) {
6748 setLWResult(res, 0, false, false, true);
6749 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6750 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6751 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6752 return 1;
6753 }
6754 else {
6755 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6756 }
6757 }
6758 else if (type == QType::DNSKEY) {
6759 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6760 setLWResult(res, 0, true, false, true);
6761 addDNSKEY(keys, domain, 300, res->d_records);
6762 addRRSIG(keys, res->d_records, domain, 300);
6763 return 1;
6764 }
6765 else {
6766 setLWResult(res, 0, false, false, true);
6767 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6768 return 1;
6769 }
6770 }
6771 else {
6772 if (isRootServer(ip)) {
6773 setLWResult(res, 0, false, false, true);
6774 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6775 addDS(DNSName("com."), 300, res->d_records, keys);
6776 addRRSIG(keys, res->d_records, DNSName("."), 300);
6777 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6778 return 1;
6779 }
6780 else if (ip == ComboAddress("192.0.2.1:53")) {
6781 if (domain == DNSName("com.")) {
6782 setLWResult(res, 0, true, false, true);
6783 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6784 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6785 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6786 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6787 }
6788 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
6789 setLWResult(res, 0, false, false, true);
6790 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6791 if (domain == targetCName) {
6792 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6793 }
6794 else if (domain == target) {
6795 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6796 }
6797 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6798 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6799 }
6800 return 1;
6801 }
6802 else if (ip == ComboAddress("192.0.2.2:53")) {
6803 setLWResult(res, 0, true, false, true);
6804 if (type == QType::NS) {
6805 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6806 if (domain == DNSName("powerdns.com.")) {
6807 addRRSIG(keys, res->d_records, domain, 300);
6808 }
6809 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6810 if (domain == DNSName("powerdns.com.")) {
6811 addRRSIG(keys, res->d_records, domain, 300);
6812 }
6813 }
6814 else {
6815 if (domain == target) {
6816 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6817 }
6818 else if (domain == targetCName) {
6819 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6820 addRRSIG(keys, res->d_records, domain, 300);
6821 }
6822 }
6823 return 1;
6824 }
6825 }
6826
6827 return 0;
6828 });
6829
6830 vector<DNSRecord> ret;
6831 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6832 BOOST_CHECK_EQUAL(res, RCode::NoError);
6833 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6834 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6835 BOOST_CHECK_EQUAL(queriesCount, 11);
6836
6837 /* again, to test the cache */
6838 ret.clear();
6839 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6840 BOOST_CHECK_EQUAL(res, RCode::NoError);
6841 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6842 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6843 BOOST_CHECK_EQUAL(queriesCount, 11);
6844 }
6845
6846 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
6847 std::unique_ptr<SyncRes> sr;
6848 initSR(sr, true);
6849
6850 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6851
6852 primeHints();
6853 const DNSName target("power-dns.com.");
6854 const DNSName targetCName("powerdns.com.");
6855 const ComboAddress targetCNameAddr("192.0.2.42");
6856 testkeysset_t keys;
6857
6858 auto luaconfsCopy = g_luaconfs.getCopy();
6859 luaconfsCopy.dsAnchors.clear();
6860 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6861 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6862 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6863 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6864 g_luaconfs.setState(luaconfsCopy);
6865
6866 size_t queriesCount = 0;
6867
6868 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) {
6869 queriesCount++;
6870
6871 if (type == QType::DS || type == QType::DNSKEY) {
6872 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6873 }
6874 else {
6875 if (isRootServer(ip)) {
6876 setLWResult(res, 0, false, false, true);
6877 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6878 addDS(DNSName("com."), 300, res->d_records, keys);
6879 addRRSIG(keys, res->d_records, DNSName("."), 300);
6880 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6881 return 1;
6882 }
6883 else if (ip == ComboAddress("192.0.2.1:53")) {
6884 if (domain == DNSName("com.")) {
6885 setLWResult(res, 0, true, false, true);
6886 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6887 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6888 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6889 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6890 }
6891 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
6892 setLWResult(res, 0, false, false, true);
6893 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6894 addDS(DNSName(domain), 300, res->d_records, keys);
6895 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6896 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6897 }
6898 return 1;
6899 }
6900 else if (ip == ComboAddress("192.0.2.2:53")) {
6901 setLWResult(res, 0, true, false, true);
6902 if (type == QType::NS) {
6903 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6904 addRRSIG(keys, res->d_records, domain, 300);
6905 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6906 addRRSIG(keys, res->d_records, domain, 300);
6907 }
6908 else {
6909 if (domain == target) {
6910 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6911 /* No RRSIG, leading to bogus */
6912 }
6913 else if (domain == targetCName) {
6914 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6915 addRRSIG(keys, res->d_records, domain, 300);
6916 }
6917 }
6918 return 1;
6919 }
6920 }
6921
6922 return 0;
6923 });
6924
6925 vector<DNSRecord> ret;
6926 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6927 BOOST_CHECK_EQUAL(res, RCode::NoError);
6928 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6929 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6930 BOOST_CHECK_EQUAL(queriesCount, 11);
6931
6932 /* again, to test the cache */
6933 ret.clear();
6934 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6935 BOOST_CHECK_EQUAL(res, RCode::NoError);
6936 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6937 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6938 BOOST_CHECK_EQUAL(queriesCount, 11);
6939 }
6940
6941 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
6942 std::unique_ptr<SyncRes> sr;
6943 initSR(sr, true);
6944
6945 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6946
6947 primeHints();
6948 const DNSName target("power-dns.com.");
6949 const DNSName targetCName("powerdns.com.");
6950 const ComboAddress targetCNameAddr("192.0.2.42");
6951 testkeysset_t keys;
6952
6953 auto luaconfsCopy = g_luaconfs.getCopy();
6954 luaconfsCopy.dsAnchors.clear();
6955 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6956 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6957 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6958 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6959 g_luaconfs.setState(luaconfsCopy);
6960
6961 size_t queriesCount = 0;
6962
6963 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) {
6964 queriesCount++;
6965
6966 if (type == QType::DS || type == QType::DNSKEY) {
6967 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6968 }
6969 else {
6970 if (isRootServer(ip)) {
6971 setLWResult(res, 0, false, false, true);
6972 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6973 addDS(DNSName("com."), 300, res->d_records, keys);
6974 addRRSIG(keys, res->d_records, DNSName("."), 300);
6975 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6976 return 1;
6977 }
6978 else if (ip == ComboAddress("192.0.2.1:53")) {
6979 if (domain == DNSName("com.")) {
6980 setLWResult(res, 0, true, false, true);
6981 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6982 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6983 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6984 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6985 }
6986 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
6987 setLWResult(res, 0, false, false, true);
6988 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6989 addDS(DNSName(domain), 300, res->d_records, keys);
6990 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6991 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6992 }
6993 return 1;
6994 }
6995 else if (ip == ComboAddress("192.0.2.2:53")) {
6996 setLWResult(res, 0, true, false, true);
6997 if (type == QType::NS) {
6998 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6999 addRRSIG(keys, res->d_records, domain, 300);
7000 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7001 addRRSIG(keys, res->d_records, domain, 300);
7002 }
7003 else {
7004 if (domain == target) {
7005 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7006 addRRSIG(keys, res->d_records, domain, 300);
7007 }
7008 else if (domain == targetCName) {
7009 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7010 /* No RRSIG, leading to bogus */
7011 }
7012 }
7013 return 1;
7014 }
7015 }
7016
7017 return 0;
7018 });
7019
7020 vector<DNSRecord> ret;
7021 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7022 BOOST_CHECK_EQUAL(res, RCode::NoError);
7023 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7024 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7025 BOOST_CHECK_EQUAL(queriesCount, 11);
7026
7027 /* again, to test the cache */
7028 ret.clear();
7029 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7030 BOOST_CHECK_EQUAL(res, RCode::NoError);
7031 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7032 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7033 BOOST_CHECK_EQUAL(queriesCount, 11);
7034 }
7035
7036 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
7037 std::unique_ptr<SyncRes> sr;
7038 initSR(sr, true);
7039
7040 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7041
7042 primeHints();
7043 const DNSName target("power-dns.com.");
7044 const DNSName targetCName("powerdns.com.");
7045 const ComboAddress targetCNameAddr("192.0.2.42");
7046 testkeysset_t keys;
7047
7048 auto luaconfsCopy = g_luaconfs.getCopy();
7049 luaconfsCopy.dsAnchors.clear();
7050 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7051 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7052 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7053 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7054 g_luaconfs.setState(luaconfsCopy);
7055
7056 size_t queriesCount = 0;
7057
7058 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) {
7059 queriesCount++;
7060
7061 if (type == QType::DS || type == QType::DNSKEY) {
7062 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7063 }
7064 else {
7065 if (isRootServer(ip)) {
7066 setLWResult(res, 0, false, false, true);
7067 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7068 addDS(DNSName("com."), 300, res->d_records, keys);
7069 addRRSIG(keys, res->d_records, DNSName("."), 300);
7070 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7071 return 1;
7072 }
7073 else if (ip == ComboAddress("192.0.2.1:53")) {
7074 if (domain == DNSName("com.")) {
7075 setLWResult(res, 0, true, false, true);
7076 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7077 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7078 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7079 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7080 }
7081 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7082 setLWResult(res, 0, false, false, true);
7083 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7084 addDS(DNSName(domain), 300, res->d_records, keys);
7085 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7086 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7087 }
7088 return 1;
7089 }
7090 else if (ip == ComboAddress("192.0.2.2:53")) {
7091 setLWResult(res, 0, true, false, true);
7092 if (type == QType::NS) {
7093 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7094 addRRSIG(keys, res->d_records, domain, 300);
7095 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7096 addRRSIG(keys, res->d_records, domain, 300);
7097 }
7098 else {
7099 if (domain == target) {
7100 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7101 addRRSIG(keys, res->d_records, domain, 300);
7102 }
7103 else if (domain == targetCName) {
7104 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7105 addRRSIG(keys, res->d_records, domain, 300);
7106 }
7107 }
7108 return 1;
7109 }
7110 }
7111
7112 return 0;
7113 });
7114
7115 vector<DNSRecord> ret;
7116 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7117 BOOST_CHECK_EQUAL(res, RCode::NoError);
7118 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7119 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7120 BOOST_CHECK_EQUAL(queriesCount, 12);
7121
7122 /* again, to test the cache */
7123 ret.clear();
7124 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7125 BOOST_CHECK_EQUAL(res, RCode::NoError);
7126 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7127 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7128 BOOST_CHECK_EQUAL(queriesCount, 12);
7129 }
7130
7131 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7132 std::unique_ptr<SyncRes> sr;
7133 initSR(sr, true);
7134
7135 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7136
7137 primeHints();
7138 const DNSName target("powerdns.com.");
7139 const DNSName targetCName("power-dns.com.");
7140 const ComboAddress targetCNameAddr("192.0.2.42");
7141 testkeysset_t keys;
7142
7143 auto luaconfsCopy = g_luaconfs.getCopy();
7144 luaconfsCopy.dsAnchors.clear();
7145 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7146 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7147 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7148 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7149 g_luaconfs.setState(luaconfsCopy);
7150
7151 size_t queriesCount = 0;
7152
7153 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) {
7154 queriesCount++;
7155
7156 if (type == QType::DS) {
7157 if (domain == DNSName("power-dns.com.")) {
7158 setLWResult(res, 0, false, false, true);
7159 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7160 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7161 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7162 return 1;
7163 }
7164 else {
7165 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7166 }
7167 }
7168 else if (type == QType::DNSKEY) {
7169 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7170 setLWResult(res, 0, true, false, true);
7171 addDNSKEY(keys, domain, 300, res->d_records);
7172 addRRSIG(keys, res->d_records, domain, 300);
7173 return 1;
7174 }
7175 else {
7176 setLWResult(res, 0, false, false, true);
7177 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7178 return 1;
7179 }
7180 }
7181 else {
7182 if (isRootServer(ip)) {
7183 setLWResult(res, 0, false, false, true);
7184 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7185 addDS(DNSName("com."), 300, res->d_records, keys);
7186 addRRSIG(keys, res->d_records, DNSName("."), 300);
7187 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7188 return 1;
7189 }
7190 else if (ip == ComboAddress("192.0.2.1:53")) {
7191 if (domain == DNSName("com.")) {
7192 setLWResult(res, 0, true, false, true);
7193 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7194 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7195 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7196 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7197 }
7198 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7199 setLWResult(res, 0, false, false, true);
7200 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7201 if (domain == DNSName("powerdns.com.")) {
7202 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7203 }
7204 else if (domain == targetCName) {
7205 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7206 }
7207 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7208 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7209 }
7210 return 1;
7211 }
7212 else if (ip == ComboAddress("192.0.2.2:53")) {
7213 setLWResult(res, 0, true, false, true);
7214 if (type == QType::NS) {
7215 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7216 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7217 }
7218 else {
7219 if (domain == DNSName("powerdns.com.")) {
7220 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7221 /* No RRSIG -> Bogus */
7222 }
7223 else if (domain == targetCName) {
7224 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7225 }
7226 }
7227 return 1;
7228 }
7229 }
7230
7231 return 0;
7232 });
7233
7234 vector<DNSRecord> ret;
7235 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7236 BOOST_CHECK_EQUAL(res, RCode::NoError);
7237 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7238 /* no RRSIG to show */
7239 BOOST_CHECK_EQUAL(ret.size(), 2);
7240 BOOST_CHECK_EQUAL(queriesCount, 10);
7241
7242 /* again, to test the cache */
7243 ret.clear();
7244 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7245 BOOST_CHECK_EQUAL(res, RCode::NoError);
7246 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7247 BOOST_CHECK_EQUAL(ret.size(), 2);
7248 BOOST_CHECK_EQUAL(queriesCount, 10);
7249 }
7250
7251 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7252 std::unique_ptr<SyncRes> sr;
7253 initSR(sr, true);
7254
7255 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7256
7257 primeHints();
7258 const DNSName target("powerdns.com.");
7259 const ComboAddress targetAddr("192.0.2.42");
7260 testkeysset_t keys;
7261
7262 auto luaconfsCopy = g_luaconfs.getCopy();
7263 luaconfsCopy.dsAnchors.clear();
7264 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7265 /* No key material for .com */
7266 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7267 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7268 g_luaconfs.setState(luaconfsCopy);
7269
7270 size_t queriesCount = 0;
7271
7272 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) {
7273 queriesCount++;
7274
7275 if (type == QType::DNSKEY) {
7276 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7277 setLWResult(res, 0, true, false, true);
7278 addDNSKEY(keys, domain, 300, res->d_records);
7279 addRRSIG(keys, res->d_records, domain, 300);
7280 return 1;
7281 }
7282 else if (domain == DNSName("com.")) {
7283 setLWResult(res, 0, false, false, true);
7284 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7285 return 1;
7286 }
7287 }
7288 else {
7289 if (isRootServer(ip)) {
7290 setLWResult(res, 0, false, false, true);
7291 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7292 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7293 addRRSIG(keys, res->d_records, DNSName("."), 300);
7294 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7295 return 1;
7296 }
7297 else if (ip == ComboAddress("192.0.2.1:53")) {
7298 if (target == domain) {
7299 setLWResult(res, 0, false, false, true);
7300 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7301 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7302 }
7303 else if (domain == DNSName("com.")) {
7304 setLWResult(res, 0, true, false, true);
7305 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7306 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7307 }
7308 return 1;
7309 }
7310 else if (ip == ComboAddress("192.0.2.2:53")) {
7311 setLWResult(res, 0, true, false, true);
7312 if (type == QType::NS) {
7313 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7314 }
7315 else {
7316 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7317 }
7318 addRRSIG(keys, res->d_records, domain, 300);
7319 return 1;
7320 }
7321 }
7322
7323 return 0;
7324 });
7325
7326 vector<DNSRecord> ret;
7327 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7328 BOOST_CHECK_EQUAL(res, RCode::NoError);
7329 /* should be insecure but we have a TA for powerdns.com. */
7330 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7331 /* We got a RRSIG */
7332 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7333 BOOST_CHECK(ret[0].d_type == QType::A);
7334 BOOST_CHECK_EQUAL(queriesCount, 5);
7335
7336 /* again, to test the cache */
7337 ret.clear();
7338 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7339 BOOST_CHECK_EQUAL(res, RCode::NoError);
7340 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7341 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7342 BOOST_CHECK(ret[0].d_type == QType::A);
7343 BOOST_CHECK_EQUAL(queriesCount, 5);
7344 }
7345
7346 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
7347 std::unique_ptr<SyncRes> sr;
7348 initSR(sr, true);
7349
7350 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7351
7352 primeHints();
7353 const DNSName target("powerdns.com.");
7354 const ComboAddress targetAddr("192.0.2.42");
7355 testkeysset_t keys;
7356
7357 auto luaconfsCopy = g_luaconfs.getCopy();
7358 luaconfsCopy.dsAnchors.clear();
7359 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7360 /* No key material for .com */
7361 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7362 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7363 g_luaconfs.setState(luaconfsCopy);
7364
7365 size_t queriesCount = 0;
7366
7367 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) {
7368 queriesCount++;
7369
7370 if (type == QType::DNSKEY) {
7371 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7372 setLWResult(res, 0, true, false, true);
7373 addDNSKEY(keys, domain, 300, res->d_records);
7374 addRRSIG(keys, res->d_records, domain, 300);
7375 return 1;
7376 }
7377 else if (domain == DNSName("com.")) {
7378 setLWResult(res, 0, false, false, true);
7379 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7380 return 1;
7381 }
7382 }
7383 else {
7384 if (target.isPartOf(domain) && isRootServer(ip)) {
7385 setLWResult(res, 0, false, false, true);
7386 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7387 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7388 addRRSIG(keys, res->d_records, DNSName("."), 300);
7389 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7390 return 1;
7391 }
7392 else if (ip == ComboAddress("192.0.2.1:53")) {
7393 if (target == domain) {
7394 setLWResult(res, 0, false, false, true);
7395 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7396 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7397 }
7398 else if (domain == DNSName("com.")) {
7399 setLWResult(res, 0, true, false, true);
7400 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7401 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7402 }
7403 return 1;
7404 }
7405 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
7406 setLWResult(res, 0, true, false, true);
7407 if (type == QType::NS) {
7408 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7409 }
7410 else {
7411 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7412 }
7413 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
7414 return 1;
7415 }
7416 }
7417
7418 return 0;
7419 });
7420
7421 vector<DNSRecord> ret;
7422 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7423 BOOST_CHECK_EQUAL(res, RCode::NoError);
7424 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
7425 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7426 /* No RRSIG */
7427 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7428 BOOST_CHECK(ret[0].d_type == QType::A);
7429 BOOST_CHECK_EQUAL(queriesCount, 4);
7430
7431 /* again, to test the cache */
7432 ret.clear();
7433 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7434 BOOST_CHECK_EQUAL(res, RCode::NoError);
7435 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7436 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7437 BOOST_CHECK(ret[0].d_type == QType::A);
7438 BOOST_CHECK_EQUAL(queriesCount, 4);
7439 }
7440
7441 BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
7442 std::unique_ptr<SyncRes> sr;
7443 initSR(sr, true);
7444
7445 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7446
7447 primeHints();
7448 const DNSName target(".");
7449 testkeysset_t keys;
7450
7451 auto luaconfsCopy = g_luaconfs.getCopy();
7452 luaconfsCopy.dsAnchors.clear();
7453 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7454 /* Add a NTA for "." */
7455 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
7456 g_luaconfs.setState(luaconfsCopy);
7457
7458 size_t queriesCount = 0;
7459
7460 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) {
7461 queriesCount++;
7462
7463 if (domain == target && type == QType::NS) {
7464
7465 setLWResult(res, 0, true, false, true);
7466 char addr[] = "a.root-servers.net.";
7467 for (char idx = 'a'; idx <= 'm'; idx++) {
7468 addr[0] = idx;
7469 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7470 }
7471
7472 addRRSIG(keys, res->d_records, domain, 300);
7473
7474 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7475 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
7476
7477 return 1;
7478 } else if (domain == target && type == QType::DNSKEY) {
7479
7480 setLWResult(res, 0, true, false, true);
7481
7482 /* No DNSKEY */
7483
7484 return 1;
7485 }
7486
7487 return 0;
7488 });
7489
7490 vector<DNSRecord> ret;
7491 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7492 BOOST_CHECK_EQUAL(res, RCode::NoError);
7493 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7494 /* 13 NS + 1 RRSIG */
7495 BOOST_REQUIRE_EQUAL(ret.size(), 14);
7496 BOOST_CHECK_EQUAL(queriesCount, 1);
7497
7498 /* again, to test the cache */
7499 ret.clear();
7500 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7501 BOOST_CHECK_EQUAL(res, RCode::NoError);
7502 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7503 BOOST_REQUIRE_EQUAL(ret.size(), 14);
7504 BOOST_CHECK_EQUAL(queriesCount, 1);
7505 }
7506
7507 BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
7508 std::unique_ptr<SyncRes> sr;
7509 initSR(sr, true);
7510
7511 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7512
7513 primeHints();
7514 const DNSName target(".");
7515 testkeysset_t keys;
7516
7517 /* Remove the root DS */
7518 auto luaconfsCopy = g_luaconfs.getCopy();
7519 luaconfsCopy.dsAnchors.clear();
7520 g_luaconfs.setState(luaconfsCopy);
7521
7522 size_t queriesCount = 0;
7523
7524 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) {
7525 queriesCount++;
7526
7527 if (domain == target && type == QType::NS) {
7528
7529 setLWResult(res, 0, true, false, true);
7530 char addr[] = "a.root-servers.net.";
7531 for (char idx = 'a'; idx <= 'm'; idx++) {
7532 addr[0] = idx;
7533 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7534 }
7535
7536 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7537 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
7538
7539 return 1;
7540 }
7541
7542 return 0;
7543 });
7544
7545 vector<DNSRecord> ret;
7546 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7547 BOOST_CHECK_EQUAL(res, RCode::NoError);
7548 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7549 /* 13 NS + 0 RRSIG */
7550 BOOST_REQUIRE_EQUAL(ret.size(), 13);
7551 BOOST_CHECK_EQUAL(queriesCount, 1);
7552
7553 /* again, to test the cache */
7554 ret.clear();
7555 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7556 BOOST_CHECK_EQUAL(res, RCode::NoError);
7557 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7558 BOOST_REQUIRE_EQUAL(ret.size(), 13);
7559 BOOST_CHECK_EQUAL(queriesCount, 1);
7560 }
7561
7562 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
7563 std::unique_ptr<SyncRes> sr;
7564 initSR(sr, true);
7565
7566 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7567
7568 primeHints();
7569 const DNSName target("powerdns.com.");
7570 testkeysset_t keys;
7571
7572 auto luaconfsCopy = g_luaconfs.getCopy();
7573 luaconfsCopy.dsAnchors.clear();
7574 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7575 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7576 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7577 g_luaconfs.setState(luaconfsCopy);
7578
7579 size_t queriesCount = 0;
7580
7581 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) {
7582 queriesCount++;
7583
7584 if (type == QType::DS || type == QType::DNSKEY) {
7585 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7586 }
7587 else {
7588
7589 setLWResult(res, 0, true, false, true);
7590 return 1;
7591 }
7592
7593 return 0;
7594 });
7595
7596 vector<DNSRecord> ret;
7597 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7598 BOOST_CHECK_EQUAL(res, RCode::NoError);
7599 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7600 BOOST_REQUIRE_EQUAL(ret.size(), 0);
7601 /* com|NS, powerdns.com|NS, powerdns.com|A */
7602 BOOST_CHECK_EQUAL(queriesCount, 3);
7603
7604 /* again, to test the cache */
7605 ret.clear();
7606 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7607 BOOST_CHECK_EQUAL(res, RCode::NoError);
7608 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7609 BOOST_REQUIRE_EQUAL(ret.size(), 0);
7610 /* we don't store empty results */
7611 BOOST_CHECK_EQUAL(queriesCount, 4);
7612 }
7613
7614 BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
7615 init();
7616
7617 testkeysset_t keys;
7618 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7619
7620 vector<DNSRecord> records;
7621
7622 vector<shared_ptr<DNSRecordContent>> recordContents;
7623 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7624
7625 /*
7626 No wrap test case:
7627 a.example.org. -> d.example.org. denies the existence of b.example.org.
7628 */
7629 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7630 recordContents.push_back(records.at(0).d_content);
7631 addRRSIG(keys, records, DNSName("example.org."), 300);
7632 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7633 records.clear();
7634
7635 ContentSigPair pair;
7636 pair.records = recordContents;
7637 pair.signatures = signatureContents;
7638 cspmap_t denialMap;
7639 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
7640
7641 /* add wildcard denial */
7642 recordContents.clear();
7643 signatureContents.clear();
7644 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7645 recordContents.push_back(records.at(0).d_content);
7646 addRRSIG(keys, records, DNSName("example.org."), 300);
7647 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7648 records.clear();
7649
7650 pair.records = recordContents;
7651 pair.signatures = signatureContents;
7652 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
7653
7654 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
7655 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7656
7657 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
7658 /* let's check that d.example.org. is not denied by this proof */
7659 BOOST_CHECK_EQUAL(denialState, NODATA);
7660 }
7661
7662 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
7663 init();
7664
7665 testkeysset_t keys;
7666 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7667
7668 vector<DNSRecord> records;
7669
7670 vector<shared_ptr<DNSRecordContent>> recordContents;
7671 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7672
7673 /*
7674 Wrap case 1 test case:
7675 z.example.org. -> b.example.org. denies the existence of a.example.org.
7676 */
7677 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7678 recordContents.push_back(records.at(0).d_content);
7679 addRRSIG(keys, records, DNSName("example.org."), 300);
7680 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7681 records.clear();
7682
7683 ContentSigPair pair;
7684 pair.records = recordContents;
7685 pair.signatures = signatureContents;
7686 cspmap_t denialMap;
7687 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
7688
7689 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
7690 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7691
7692 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
7693 /* let's check that d.example.org. is not denied by this proof */
7694 BOOST_CHECK_EQUAL(denialState, NODATA);
7695 }
7696
7697 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
7698 init();
7699
7700 testkeysset_t keys;
7701 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7702
7703 vector<DNSRecord> records;
7704
7705 vector<shared_ptr<DNSRecordContent>> recordContents;
7706 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7707
7708 /*
7709 Wrap case 2 test case:
7710 y.example.org. -> a.example.org. denies the existence of z.example.org.
7711 */
7712 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7713 recordContents.push_back(records.at(0).d_content);
7714 addRRSIG(keys, records, DNSName("example.org."), 300);
7715 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7716 records.clear();
7717
7718 ContentSigPair pair;
7719 pair.records = recordContents;
7720 pair.signatures = signatureContents;
7721 cspmap_t denialMap;
7722 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
7723
7724 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
7725 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7726
7727 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
7728 /* let's check that d.example.org. is not denied by this proof */
7729 BOOST_CHECK_EQUAL(denialState, NODATA);
7730 }
7731
7732 BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
7733 init();
7734
7735 testkeysset_t keys;
7736 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7737
7738 vector<DNSRecord> records;
7739
7740 vector<shared_ptr<DNSRecordContent>> recordContents;
7741 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7742
7743 /*
7744 Only one NSEC in the whole zone test case:
7745 a.example.org. -> a.example.org. denies the existence of b.example.org.
7746 */
7747 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7748 recordContents.push_back(records.at(0).d_content);
7749 addRRSIG(keys, records, DNSName("example.org."), 300);
7750 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7751 records.clear();
7752
7753 ContentSigPair pair;
7754 pair.records = recordContents;
7755 pair.signatures = signatureContents;
7756 cspmap_t denialMap;
7757 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
7758
7759 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
7760 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7761
7762 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
7763 /* let's check that d.example.org. is not denied by this proof */
7764 BOOST_CHECK_EQUAL(denialState, NODATA);
7765 }
7766
7767 BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
7768 init();
7769
7770 testkeysset_t keys;
7771 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7772
7773 vector<DNSRecord> records;
7774
7775 vector<shared_ptr<DNSRecordContent>> recordContents;
7776 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7777
7778 /*
7779 The RRSIG from "." denies the existence of anything between a. and c.,
7780 including b.
7781 */
7782 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
7783 recordContents.push_back(records.at(0).d_content);
7784 addRRSIG(keys, records, DNSName("."), 300);
7785 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7786 records.clear();
7787
7788 ContentSigPair pair;
7789 pair.records = recordContents;
7790 pair.signatures = signatureContents;
7791 cspmap_t denialMap;
7792 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
7793
7794 /* add wildcard denial */
7795 recordContents.clear();
7796 signatureContents.clear();
7797 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7798 recordContents.push_back(records.at(0).d_content);
7799 addRRSIG(keys, records, DNSName("."), 300);
7800 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7801 records.clear();
7802
7803 pair.records = recordContents;
7804 pair.signatures = signatureContents;
7805 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
7806
7807 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
7808 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7809 }
7810
7811 BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
7812 init();
7813
7814 testkeysset_t keys;
7815 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7816
7817 vector<DNSRecord> records;
7818
7819 vector<shared_ptr<DNSRecordContent>> recordContents;
7820 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7821
7822 /*
7823 The RRSIG from "." denies the existence of any type except NS at a.
7824 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
7825 signer field that is shorter than the owner name of the NSEC RR) it can't
7826 be used to deny anything except the whole name or a DS.
7827 */
7828 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
7829 recordContents.push_back(records.at(0).d_content);
7830 addRRSIG(keys, records, DNSName("."), 300);
7831 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7832 records.clear();
7833
7834 ContentSigPair pair;
7835 pair.records = recordContents;
7836 pair.signatures = signatureContents;
7837 cspmap_t denialMap;
7838 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
7839
7840 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
7841 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
7842 nonexistence of any RRs below that zone cut, which include all RRs at
7843 that (original) owner name other than DS RRs, and all RRs below that
7844 owner name regardless of type.
7845 */
7846
7847 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
7848 /* no data means the qname/qtype is not denied, because an ancestor
7849 delegation NSEC can only deny the DS */
7850 BOOST_CHECK_EQUAL(denialState, NODATA);
7851
7852 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
7853 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
7854 }
7855
7856 BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
7857 init();
7858
7859 testkeysset_t keys;
7860 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7861
7862 vector<DNSRecord> records;
7863
7864 vector<shared_ptr<DNSRecordContent>> recordContents;
7865 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7866
7867 /*
7868 * RFC 5155 section 8.9:
7869 * If there is an NSEC3 RR present in the response that matches the
7870 * delegation name, then the validator MUST ensure that the NS bit is
7871 * set and that the DS bit is not set in the Type Bit Maps field of the
7872 * NSEC3 RR.
7873 */
7874 /*
7875 The RRSIG from "." denies the existence of any type at a.
7876 NS should be set if it was proving an insecure delegation, let's check that
7877 we correctly detect that it's not.
7878 */
7879 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
7880 recordContents.push_back(records.at(0).d_content);
7881 addRRSIG(keys, records, DNSName("."), 300);
7882 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7883 records.clear();
7884
7885 ContentSigPair pair;
7886 pair.records = recordContents;
7887 pair.signatures = signatureContents;
7888 cspmap_t denialMap;
7889 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
7890
7891 /* Insecure because the NS is not set, so while it does
7892 denies the DS, it can't prove an insecure delegation */
7893 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
7894 BOOST_CHECK_EQUAL(denialState, NODATA);
7895 }
7896
7897 BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
7898 init();
7899
7900 testkeysset_t keys;
7901 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7902
7903 vector<DNSRecord> records;
7904
7905 vector<shared_ptr<DNSRecordContent>> recordContents;
7906 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7907
7908 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
7909 recordContents.push_back(records.at(0).d_content);
7910 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
7911 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7912 records.clear();
7913
7914 ContentSigPair pair;
7915 pair.records = recordContents;
7916 pair.signatures = signatureContents;
7917 cspmap_t denialMap;
7918 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
7919
7920 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
7921 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
7922 BOOST_CHECK_EQUAL(denialState, NODATA);
7923 }
7924
7925 BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
7926 init();
7927
7928 testkeysset_t keys;
7929 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7930
7931 vector<DNSRecord> records;
7932
7933 vector<shared_ptr<DNSRecordContent>> recordContents;
7934 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7935
7936 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
7937 recordContents.push_back(records.at(0).d_content);
7938 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
7939 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7940
7941 ContentSigPair pair;
7942 pair.records = recordContents;
7943 pair.signatures = signatureContents;
7944 cspmap_t denialMap;
7945 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
7946 records.clear();
7947
7948 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
7949 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
7950 BOOST_CHECK_EQUAL(denialState, NODATA);
7951 }
7952
7953 BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
7954 init();
7955
7956 testkeysset_t keys;
7957 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7958
7959 vector<DNSRecord> records;
7960
7961 vector<shared_ptr<DNSRecordContent>> recordContents;
7962 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7963
7964 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7965 recordContents.push_back(records.at(0).d_content);
7966 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
7967 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7968 records.clear();
7969
7970 ContentSigPair pair;
7971 pair.records = recordContents;
7972 pair.signatures = signatureContents;
7973 cspmap_t denialMap;
7974 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
7975
7976 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
7977 BOOST_CHECK_EQUAL(denialState, NODATA);
7978 }
7979
7980 BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
7981 init();
7982
7983 testkeysset_t keys;
7984 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7985
7986 vector<DNSRecord> records;
7987
7988 vector<shared_ptr<DNSRecordContent>> recordContents;
7989 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7990
7991 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7992 recordContents.push_back(records.at(0).d_content);
7993 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
7994 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7995
7996 ContentSigPair pair;
7997 pair.records = recordContents;
7998 pair.signatures = signatureContents;
7999 cspmap_t denialMap;
8000 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8001
8002 /* Add NSEC3 for the closest encloser */
8003 recordContents.clear();
8004 signatureContents.clear();
8005 records.clear();
8006 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8007 recordContents.push_back(records.at(0).d_content);
8008 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8009 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8010
8011 pair.records = recordContents;
8012 pair.signatures = signatureContents;
8013 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8014
8015 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8016 BOOST_CHECK_EQUAL(denialState, NODATA);
8017 }
8018
8019 BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8020 init();
8021
8022 testkeysset_t keys;
8023 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8024
8025 vector<DNSRecord> records;
8026
8027 vector<shared_ptr<DNSRecordContent>> recordContents;
8028 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8029
8030 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8031 recordContents.push_back(records.at(0).d_content);
8032 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8033 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8034 records.clear();
8035
8036 ContentSigPair pair;
8037 pair.records = recordContents;
8038 pair.signatures = signatureContents;
8039 cspmap_t denialMap;
8040 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8041
8042 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
8043 it is an ENT */
8044 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
8045 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8046
8047 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8048 it could prove a NXDOMAIN if it had an additional wildcard denial */
8049 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8050 BOOST_CHECK_EQUAL(denialState, NODATA);
8051
8052 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8053 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8054 BOOST_CHECK_EQUAL(denialState, NODATA);
8055
8056 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8057 recordContents.clear();
8058 signatureContents.clear();
8059 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8060 recordContents.push_back(records.at(0).d_content);
8061 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8062 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8063 records.clear();
8064 pair.records = recordContents;
8065 pair.signatures = signatureContents;
8066 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8067
8068 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
8069 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8070 }
8071
8072 BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8073 init();
8074
8075 testkeysset_t keys;
8076 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8077
8078 vector<DNSRecord> records;
8079
8080 vector<shared_ptr<DNSRecordContent>> recordContents;
8081 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8082
8083 /*
8084 The RRSIG from "." denies the existence of any type except NS at a.
8085 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8086 signer field that is shorter than the owner name of the NSEC RR) it can't
8087 be used to deny anything except the whole name or a DS.
8088 */
8089 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
8090 recordContents.push_back(records.at(0).d_content);
8091 addRRSIG(keys, records, DNSName("."), 300);
8092 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8093
8094 ContentSigPair pair;
8095 pair.records = recordContents;
8096 pair.signatures = signatureContents;
8097 cspmap_t denialMap;
8098 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8099 records.clear();
8100
8101 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8102 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8103 nonexistence of any RRs below that zone cut, which include all RRs at
8104 that (original) owner name other than DS RRs, and all RRs below that
8105 owner name regardless of type.
8106 */
8107
8108 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8109 /* no data means the qname/qtype is not denied, because an ancestor
8110 delegation NSEC3 can only deny the DS */
8111 BOOST_CHECK_EQUAL(denialState, NODATA);
8112
8113 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8114 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8115 }
8116
8117 BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8118 init();
8119
8120 testkeysset_t keys;
8121 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8122
8123 vector<DNSRecord> records;
8124
8125 vector<shared_ptr<DNSRecordContent>> recordContents;
8126 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8127
8128 /* adding a NSEC3 with more iterations that we support */
8129 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8130 recordContents.push_back(records.at(0).d_content);
8131 addRRSIG(keys, records, DNSName("."), 300);
8132 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8133
8134 ContentSigPair pair;
8135 pair.records = recordContents;
8136 pair.signatures = signatureContents;
8137 cspmap_t denialMap;
8138 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8139 records.clear();
8140
8141 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8142 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8143 BOOST_CHECK_EQUAL(denialState, INSECURE);
8144 }
8145
8146 BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8147 init();
8148
8149 testkeysset_t keys;
8150 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8151
8152 vector<DNSRecord> records;
8153
8154 vector<shared_ptr<DNSRecordContent>> recordContents;
8155 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8156
8157 /*
8158 * RFC 5155 section 8.9:
8159 * If there is an NSEC3 RR present in the response that matches the
8160 * delegation name, then the validator MUST ensure that the NS bit is
8161 * set and that the DS bit is not set in the Type Bit Maps field of the
8162 * NSEC3 RR.
8163 */
8164 /*
8165 The RRSIG from "." denies the existence of any type at a.
8166 NS should be set if it was proving an insecure delegation, let's check that
8167 we correctly detect that it's not.
8168 */
8169 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
8170 recordContents.push_back(records.at(0).d_content);
8171 addRRSIG(keys, records, DNSName("."), 300);
8172 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8173
8174 ContentSigPair pair;
8175 pair.records = recordContents;
8176 pair.signatures = signatureContents;
8177 cspmap_t denialMap;
8178 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8179 records.clear();
8180
8181 /* Insecure because the NS is not set, so while it does
8182 denies the DS, it can't prove an insecure delegation */
8183 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8184 BOOST_CHECK_EQUAL(denialState, NODATA);
8185 }
8186
8187 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8188 std::unique_ptr<SyncRes> sr;
8189 initSR(sr, true);
8190
8191 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8192
8193 primeHints();
8194 const DNSName target("com.");
8195 testkeysset_t keys;
8196
8197 auto luaconfsCopy = g_luaconfs.getCopy();
8198 luaconfsCopy.dsAnchors.clear();
8199 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8200 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8201 g_luaconfs.setState(luaconfsCopy);
8202
8203 size_t queriesCount = 0;
8204
8205 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) {
8206 queriesCount++;
8207
8208 DNSName auth = domain;
8209 auth.chopOff();
8210
8211 if (type == QType::DS || type == QType::DNSKEY) {
8212 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8213 }
8214 else {
8215 setLWResult(res, RCode::NoError, true, false, true);
8216 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8217 addRRSIG(keys, res->d_records, domain, 300);
8218 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8219 addRRSIG(keys, res->d_records, domain, 1);
8220 return 1;
8221 }
8222
8223 return 0;
8224 });
8225
8226 const time_t now = time(nullptr);
8227 vector<DNSRecord> ret;
8228 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8229 BOOST_CHECK_EQUAL(res, RCode::NoError);
8230 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8231 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8232 BOOST_CHECK_EQUAL(queriesCount, 4);
8233
8234 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
8235 NegCache::NegCacheEntry ne;
8236 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8237 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8238 BOOST_CHECK_EQUAL(ne.d_ttd, now + 1);
8239 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8240 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8241 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8242 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
8243
8244 /* again, to test the cache */
8245 ret.clear();
8246 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8247 BOOST_CHECK_EQUAL(res, RCode::NoError);
8248 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8249 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8250 BOOST_CHECK_EQUAL(queriesCount, 4);
8251 }
8252
8253 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
8254 std::unique_ptr<SyncRes> sr;
8255 initSR(sr, true);
8256
8257 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8258
8259 primeHints();
8260 const DNSName target("com.");
8261 const ComboAddress targetAddr("192.0.2.42");
8262 testkeysset_t keys;
8263
8264 auto luaconfsCopy = g_luaconfs.getCopy();
8265 luaconfsCopy.dsAnchors.clear();
8266 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8267 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8268 g_luaconfs.setState(luaconfsCopy);
8269
8270 size_t queriesCount = 0;
8271
8272 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) {
8273 queriesCount++;
8274
8275 DNSName auth = domain;
8276 auth.chopOff();
8277
8278 if (type == QType::DS || type == QType::DNSKEY) {
8279 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8280 }
8281 else {
8282 setLWResult(res, RCode::NoError, true, false, true);
8283 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8284 addRRSIG(keys, res->d_records, domain, 1);
8285 return 1;
8286 }
8287
8288 return 0;
8289 });
8290
8291 const time_t now = time(nullptr);
8292 vector<DNSRecord> ret;
8293 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8294 BOOST_CHECK_EQUAL(res, RCode::NoError);
8295 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8296 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8297 BOOST_CHECK_EQUAL(queriesCount, 4);
8298
8299 /* check that the entry has not been cached for longer than the RRSIG validity */
8300 const ComboAddress who;
8301 vector<DNSRecord> cached;
8302 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
8303 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
8304 BOOST_REQUIRE_EQUAL(cached.size(), 1);
8305 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
8306 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
8307
8308 /* again, to test the cache */
8309 ret.clear();
8310 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8311 BOOST_CHECK_EQUAL(res, RCode::NoError);
8312 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8313 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8314 BOOST_CHECK_EQUAL(queriesCount, 4);
8315 }
8316
8317 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
8318 /*
8319 Validation is optional, and the first query does not ask for it,
8320 so the answer is cached as Indeterminate.
8321 The second query asks for validation, answer should be marked as
8322 Secure.
8323 */
8324 std::unique_ptr<SyncRes> sr;
8325 initSR(sr, true);
8326
8327 setDNSSECValidation(sr, DNSSECMode::Process);
8328
8329 primeHints();
8330 const DNSName target("com.");
8331 testkeysset_t keys;
8332
8333 auto luaconfsCopy = g_luaconfs.getCopy();
8334 luaconfsCopy.dsAnchors.clear();
8335 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8336 g_luaconfs.setState(luaconfsCopy);
8337
8338 size_t queriesCount = 0;
8339
8340 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) {
8341 queriesCount++;
8342
8343 if (type == QType::DS || type == QType::DNSKEY) {
8344 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8345 }
8346 else {
8347 if (domain == target && type == QType::A) {
8348 setLWResult(res, 0, true, false, true);
8349 addRecordToLW(res, target, QType::A, "192.0.2.1");
8350 addRRSIG(keys, res->d_records, DNSName("."), 300);
8351 return 1;
8352 }
8353 }
8354
8355 return 0;
8356 });
8357
8358 vector<DNSRecord> ret;
8359 /* first query does not require validation */
8360 sr->setDNSSECValidationRequested(false);
8361 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8362 BOOST_CHECK_EQUAL(res, RCode::NoError);
8363 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8364 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8365 for (const auto& record : ret) {
8366 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8367 }
8368 BOOST_CHECK_EQUAL(queriesCount, 1);
8369
8370
8371 ret.clear();
8372 /* second one _does_ require validation */
8373 sr->setDNSSECValidationRequested(true);
8374 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8375 BOOST_CHECK_EQUAL(res, RCode::NoError);
8376 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8377 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8378 for (const auto& record : ret) {
8379 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8380 }
8381 BOOST_CHECK_EQUAL(queriesCount, 3);
8382 }
8383
8384 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
8385 /*
8386 Validation is optional, and the first query does not ask for it,
8387 so the answer is cached as Indeterminate.
8388 The second query asks for validation, answer should be marked as
8389 Insecure.
8390 */
8391 std::unique_ptr<SyncRes> sr;
8392 initSR(sr, true);
8393
8394 setDNSSECValidation(sr, DNSSECMode::Process);
8395
8396 primeHints();
8397 const DNSName target("com.");
8398 testkeysset_t keys;
8399
8400 auto luaconfsCopy = g_luaconfs.getCopy();
8401 luaconfsCopy.dsAnchors.clear();
8402 g_luaconfs.setState(luaconfsCopy);
8403
8404 size_t queriesCount = 0;
8405
8406 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) {
8407 queriesCount++;
8408
8409 if (type == QType::DS || type == QType::DNSKEY) {
8410 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8411 }
8412 else {
8413 if (domain == target && type == QType::A) {
8414 setLWResult(res, 0, true, false, true);
8415 addRecordToLW(res, target, QType::A, "192.0.2.1");
8416 return 1;
8417 }
8418 }
8419
8420 return 0;
8421 });
8422
8423 vector<DNSRecord> ret;
8424 /* first query does not require validation */
8425 sr->setDNSSECValidationRequested(false);
8426 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8427 BOOST_CHECK_EQUAL(res, RCode::NoError);
8428 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8429 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8430 for (const auto& record : ret) {
8431 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8432 }
8433 BOOST_CHECK_EQUAL(queriesCount, 1);
8434
8435
8436 ret.clear();
8437 /* second one _does_ require validation */
8438 sr->setDNSSECValidationRequested(true);
8439 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8440 BOOST_CHECK_EQUAL(res, RCode::NoError);
8441 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8442 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8443 for (const auto& record : ret) {
8444 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8445 }
8446 BOOST_CHECK_EQUAL(queriesCount, 1);
8447 }
8448
8449 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
8450 /*
8451 Validation is optional, and the first query does not ask for it,
8452 so the answer is cached as Indeterminate.
8453 The second query asks for validation, answer should be marked as
8454 Bogus.
8455 */
8456 std::unique_ptr<SyncRes> sr;
8457 initSR(sr, true);
8458
8459 setDNSSECValidation(sr, DNSSECMode::Process);
8460
8461 primeHints();
8462 const DNSName target("com.");
8463 testkeysset_t keys;
8464
8465 auto luaconfsCopy = g_luaconfs.getCopy();
8466 luaconfsCopy.dsAnchors.clear();
8467 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8468 g_luaconfs.setState(luaconfsCopy);
8469
8470 size_t queriesCount = 0;
8471
8472 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) {
8473 queriesCount++;
8474
8475 if (type == QType::DS || type == QType::DNSKEY) {
8476 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8477 }
8478 else {
8479 if (domain == target && type == QType::A) {
8480 setLWResult(res, 0, true, false, true);
8481 addRecordToLW(res, target, QType::A, "192.0.2.1");
8482 /* no RRSIG */
8483 return 1;
8484 }
8485 }
8486
8487 return 0;
8488 });
8489
8490 vector<DNSRecord> ret;
8491 /* first query does not require validation */
8492 sr->setDNSSECValidationRequested(false);
8493 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8494 BOOST_CHECK_EQUAL(res, RCode::NoError);
8495 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8496 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8497 for (const auto& record : ret) {
8498 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8499 }
8500 BOOST_CHECK_EQUAL(queriesCount, 1);
8501
8502
8503 ret.clear();
8504 /* second one _does_ require validation */
8505 sr->setDNSSECValidationRequested(true);
8506 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8507 BOOST_CHECK_EQUAL(res, RCode::NoError);
8508 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8509 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8510 for (const auto& record : ret) {
8511 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8512 }
8513 BOOST_CHECK_EQUAL(queriesCount, 3);
8514 }
8515
8516 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
8517 /*
8518 Validation is optional, and the first query does not ask for it,
8519 so the answer is negatively cached as Indeterminate.
8520 The second query asks for validation, answer should be marked as
8521 Secure.
8522 */
8523 std::unique_ptr<SyncRes> sr;
8524 initSR(sr, true);
8525
8526 setDNSSECValidation(sr, DNSSECMode::Process);
8527
8528 primeHints();
8529 const DNSName target("com.");
8530 testkeysset_t keys;
8531
8532 auto luaconfsCopy = g_luaconfs.getCopy();
8533 luaconfsCopy.dsAnchors.clear();
8534 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8535 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8536 g_luaconfs.setState(luaconfsCopy);
8537
8538 size_t queriesCount = 0;
8539
8540 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) {
8541 queriesCount++;
8542
8543 DNSName auth = domain;
8544 auth.chopOff();
8545
8546 if (type == QType::DS || type == QType::DNSKEY) {
8547 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8548 }
8549 else {
8550 setLWResult(res, RCode::NoError, true, false, true);
8551 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8552 addRRSIG(keys, res->d_records, domain, 300);
8553 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8554 addRRSIG(keys, res->d_records, domain, 1);
8555 return 1;
8556 }
8557
8558 return 0;
8559 });
8560
8561 vector<DNSRecord> ret;
8562 /* first query does not require validation */
8563 sr->setDNSSECValidationRequested(false);
8564 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8565 BOOST_CHECK_EQUAL(res, RCode::NoError);
8566 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8567 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8568 BOOST_CHECK_EQUAL(queriesCount, 1);
8569
8570 ret.clear();
8571 /* second one _does_ require validation */
8572 sr->setDNSSECValidationRequested(true);
8573 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8574 BOOST_CHECK_EQUAL(res, RCode::NoError);
8575 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8576 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8577 BOOST_CHECK_EQUAL(queriesCount, 4);
8578 }
8579
8580 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
8581 /*
8582 Validation is optional, and the first query does not ask for it,
8583 so the answer is negatively cached as Indeterminate.
8584 The second query asks for validation, answer should be marked as
8585 Insecure.
8586 */
8587 std::unique_ptr<SyncRes> sr;
8588 initSR(sr, true);
8589
8590 setDNSSECValidation(sr, DNSSECMode::Process);
8591
8592 primeHints();
8593 const DNSName target("com.");
8594 testkeysset_t keys;
8595
8596 auto luaconfsCopy = g_luaconfs.getCopy();
8597 luaconfsCopy.dsAnchors.clear();
8598 g_luaconfs.setState(luaconfsCopy);
8599
8600 size_t queriesCount = 0;
8601
8602 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) {
8603 queriesCount++;
8604
8605 DNSName auth = domain;
8606 auth.chopOff();
8607
8608 if (type == QType::DS || type == QType::DNSKEY) {
8609 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8610 }
8611 else {
8612 setLWResult(res, RCode::NoError, true, false, true);
8613 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8614 return 1;
8615 }
8616
8617 return 0;
8618 });
8619
8620 vector<DNSRecord> ret;
8621 /* first query does not require validation */
8622 sr->setDNSSECValidationRequested(false);
8623 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8624 BOOST_CHECK_EQUAL(res, RCode::NoError);
8625 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8626 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8627 BOOST_CHECK_EQUAL(queriesCount, 1);
8628
8629 ret.clear();
8630 /* second one _does_ require validation */
8631 sr->setDNSSECValidationRequested(true);
8632 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8633 BOOST_CHECK_EQUAL(res, RCode::NoError);
8634 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8635 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8636 BOOST_CHECK_EQUAL(queriesCount, 1);
8637 }
8638
8639 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
8640 /*
8641 Validation is optional, and the first query does not ask for it,
8642 so the answer is negatively cached as Indeterminate.
8643 The second query asks for validation, answer should be marked as
8644 Bogus.
8645 */
8646 std::unique_ptr<SyncRes> sr;
8647 initSR(sr, true);
8648
8649 setDNSSECValidation(sr, DNSSECMode::Process);
8650
8651 primeHints();
8652 const DNSName target("com.");
8653 testkeysset_t keys;
8654
8655 auto luaconfsCopy = g_luaconfs.getCopy();
8656 luaconfsCopy.dsAnchors.clear();
8657 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8658 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8659 g_luaconfs.setState(luaconfsCopy);
8660
8661 size_t queriesCount = 0;
8662
8663 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) {
8664 queriesCount++;
8665
8666 DNSName auth = domain;
8667 auth.chopOff();
8668
8669 if (type == QType::DS || type == QType::DNSKEY) {
8670 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8671 }
8672 else {
8673 setLWResult(res, RCode::NoError, true, false, true);
8674 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8675 addRRSIG(keys, res->d_records, domain, 300);
8676 /* no denial */
8677 return 1;
8678 }
8679
8680 return 0;
8681 });
8682
8683 vector<DNSRecord> ret;
8684 /* first query does not require validation */
8685 sr->setDNSSECValidationRequested(false);
8686 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8687 BOOST_CHECK_EQUAL(res, RCode::NoError);
8688 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8689 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8690 BOOST_CHECK_EQUAL(queriesCount, 1);
8691
8692 ret.clear();
8693 /* second one _does_ require validation */
8694 sr->setDNSSECValidationRequested(true);
8695 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8696 BOOST_CHECK_EQUAL(res, RCode::NoError);
8697 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8698 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8699 BOOST_CHECK_EQUAL(queriesCount, 4);
8700 }
8701
8702 BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
8703 g_lowercaseOutgoing = true;
8704 std::unique_ptr<SyncRes> sr;
8705 initSR(sr);
8706
8707 primeHints();
8708
8709 vector<DNSName> sentOutQnames;
8710
8711 const DNSName target("WWW.POWERDNS.COM");
8712 const DNSName cname("WWW.PowerDNS.org");
8713
8714 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) {
8715
8716 sentOutQnames.push_back(domain);
8717
8718 if (isRootServer(ip)) {
8719 if (domain == target) {
8720 setLWResult(res, 0, false, false, true);
8721 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
8722 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8723 return 1;
8724 }
8725 if (domain == cname) {
8726 setLWResult(res, 0, false, false, true);
8727 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
8728 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8729 return 1;
8730 }
8731 } else if (ip == ComboAddress("192.0.2.1:53")) {
8732 if (domain == target) {
8733 setLWResult(res, 0, true, false, false);
8734 addRecordToLW(res, domain, QType::CNAME, cname.toString());
8735 return 1;
8736 }
8737 } else if (ip == ComboAddress("192.0.2.2:53")) {
8738 if (domain == cname) {
8739 setLWResult(res, 0, true, false, false);
8740 addRecordToLW(res, domain, QType::A, "127.0.0.1");
8741 return 1;
8742 }
8743 }
8744 return 0;
8745 });
8746
8747 vector<DNSRecord> ret;
8748 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8749
8750 BOOST_CHECK_EQUAL(res, RCode::NoError);
8751
8752 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8753 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
8754
8755 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
8756 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
8757 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
8758 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
8759 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
8760
8761 g_lowercaseOutgoing = false;
8762 }
8763
8764 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
8765 std::unique_ptr<SyncRes> sr;
8766 initSR(sr, true);
8767
8768 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8769
8770 primeHints();
8771 const DNSName target("com.");
8772 testkeysset_t keys, keys2;
8773
8774 auto luaconfsCopy = g_luaconfs.getCopy();
8775 luaconfsCopy.dsAnchors.clear();
8776 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8777 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8778 g_luaconfs.setState(luaconfsCopy);
8779
8780 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
8781 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
8782 // But add the existing root key otherwise no RRSIG can be created
8783 auto rootkey = keys.find(g_rootdnsname);
8784 keys2.insert(*rootkey);
8785
8786 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) {
8787 DNSName auth = domain;
8788 auth.chopOff();
8789 if (type == QType::DS || type == QType::DNSKEY) {
8790 if (domain == target) {
8791 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
8792 return 0;
8793 }
8794 }
8795 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8796 }
8797 return 0;
8798 });
8799
8800 dsmap_t ds;
8801 auto state = sr->getDSRecords(target, ds, false, 0, false);
8802 BOOST_CHECK_EQUAL(state, Secure);
8803 BOOST_REQUIRE_EQUAL(ds.size(), 1);
8804 for (const auto& i : ds) {
8805 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
8806 }
8807 }
8808
8809 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
8810 std::unique_ptr<SyncRes> sr;
8811 initSR(sr, true);
8812
8813 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8814
8815 primeHints();
8816 const DNSName target("com.");
8817 testkeysset_t keys, keys2, keys3;
8818
8819 auto luaconfsCopy = g_luaconfs.getCopy();
8820 luaconfsCopy.dsAnchors.clear();
8821 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8822 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8823 g_luaconfs.setState(luaconfsCopy);
8824
8825 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
8826 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
8827 // But add the existing root key otherwise no RRSIG can be created
8828 auto rootkey = keys.find(g_rootdnsname);
8829 keys2.insert(*rootkey);
8830
8831 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
8832 // But add the existing root key otherwise no RRSIG can be created
8833 keys3.insert(*rootkey);
8834
8835 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) {
8836 DNSName auth = domain;
8837 auth.chopOff();
8838 if (type == QType::DS || type == QType::DNSKEY) {
8839 if (domain == target) {
8840 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
8841 return 0;
8842 }
8843 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
8844 return 0;
8845 }
8846 }
8847 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8848 }
8849 return 0;
8850 });
8851
8852 dsmap_t ds;
8853 auto state = sr->getDSRecords(target, ds, false, 0, false);
8854 BOOST_CHECK_EQUAL(state, Secure);
8855 BOOST_REQUIRE_EQUAL(ds.size(), 1);
8856 for (const auto& i : ds) {
8857 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
8858 }
8859 }
8860
8861 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
8862 std::unique_ptr<SyncRes> sr;
8863 initSR(sr, true);
8864
8865 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8866
8867 primeHints();
8868 const DNSName target("com.");
8869 testkeysset_t keys, keys2, keys3;
8870
8871 auto luaconfsCopy = g_luaconfs.getCopy();
8872 luaconfsCopy.dsAnchors.clear();
8873 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8874 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8875 g_luaconfs.setState(luaconfsCopy);
8876
8877 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
8878 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
8879 // But add the existing root key otherwise no RRSIG can be created
8880 auto rootkey = keys.find(g_rootdnsname);
8881 keys2.insert(*rootkey);
8882
8883 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
8884 // But add the existing root key otherwise no RRSIG can be created
8885 keys3.insert(*rootkey);
8886
8887 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) {
8888 DNSName auth = domain;
8889 auth.chopOff();
8890 if (type == QType::DS || type == QType::DNSKEY) {
8891 if (domain == target) {
8892 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
8893 return 0;
8894 }
8895 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
8896 return 0;
8897 }
8898 }
8899 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8900 }
8901 return 0;
8902 });
8903
8904 dsmap_t ds;
8905 auto state = sr->getDSRecords(target, ds, false, 0, false);
8906 BOOST_CHECK_EQUAL(state, Secure);
8907 BOOST_REQUIRE_EQUAL(ds.size(), 2);
8908 for (const auto& i : ds) {
8909 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
8910 }
8911 }
8912
8913 #ifdef HAVE_BOTAN
8914 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) {
8915 std::unique_ptr<SyncRes> sr;
8916 initSR(sr, true);
8917
8918 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8919
8920 primeHints();
8921 const DNSName target("com.");
8922 testkeysset_t keys, keys2;
8923
8924 auto luaconfsCopy = g_luaconfs.getCopy();
8925 luaconfsCopy.dsAnchors.clear();
8926 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8927 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys);
8928 g_luaconfs.setState(luaconfsCopy);
8929
8930 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
8931 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
8932 // But add the existing root key otherwise no RRSIG can be created
8933 auto rootkey = keys.find(g_rootdnsname);
8934 keys2.insert(*rootkey);
8935
8936 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) {
8937 DNSName auth = domain;
8938 auth.chopOff();
8939 if (type == QType::DS || type == QType::DNSKEY) {
8940 if (domain == target) {
8941 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
8942 return 0;
8943 }
8944 }
8945 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8946 }
8947 return 0;
8948 });
8949
8950 dsmap_t ds;
8951 auto state = sr->getDSRecords(target, ds, false, 0, false);
8952 BOOST_CHECK_EQUAL(state, Secure);
8953 BOOST_REQUIRE_EQUAL(ds.size(), 1);
8954 for (const auto& i : ds) {
8955 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
8956 }
8957 }
8958
8959 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) {
8960 std::unique_ptr<SyncRes> sr;
8961 initSR(sr, true);
8962
8963 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8964
8965 primeHints();
8966 const DNSName target("com.");
8967 testkeysset_t keys, keys2;
8968
8969 auto luaconfsCopy = g_luaconfs.getCopy();
8970 luaconfsCopy.dsAnchors.clear();
8971 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8972 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8973 g_luaconfs.setState(luaconfsCopy);
8974
8975 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
8976 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
8977 // But add the existing root key otherwise no RRSIG can be created
8978 auto rootkey = keys.find(g_rootdnsname);
8979 keys2.insert(*rootkey);
8980
8981 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) {
8982 DNSName auth = domain;
8983 auth.chopOff();
8984 if (type == QType::DS || type == QType::DNSKEY) {
8985 if (domain == target) {
8986 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
8987 return 0;
8988 }
8989 }
8990 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8991 }
8992 return 0;
8993 });
8994
8995 dsmap_t ds;
8996 auto state = sr->getDSRecords(target, ds, false, 0, false);
8997 BOOST_CHECK_EQUAL(state, Secure);
8998 BOOST_REQUIRE_EQUAL(ds.size(), 1);
8999 for (const auto& i : ds) {
9000 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9001 }
9002 }
9003
9004 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) {
9005 std::unique_ptr<SyncRes> sr;
9006 initSR(sr, true);
9007
9008 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9009
9010 primeHints();
9011 const DNSName target("com.");
9012 testkeysset_t keys, keys2;
9013
9014 auto luaconfsCopy = g_luaconfs.getCopy();
9015 luaconfsCopy.dsAnchors.clear();
9016 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9017 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys);
9018 g_luaconfs.setState(luaconfsCopy);
9019
9020 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9021 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9022 // But add the existing root key otherwise no RRSIG can be created
9023 auto rootkey = keys.find(g_rootdnsname);
9024 keys2.insert(*rootkey);
9025
9026 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) {
9027 DNSName auth = domain;
9028 auth.chopOff();
9029 if (type == QType::DS || type == QType::DNSKEY) {
9030 if (domain == target) {
9031 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9032 return 0;
9033 }
9034 }
9035 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9036 }
9037 return 0;
9038 });
9039
9040 dsmap_t ds;
9041 auto state = sr->getDSRecords(target, ds, false, 0, false);
9042 BOOST_CHECK_EQUAL(state, Secure);
9043 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9044 for (const auto& i : ds) {
9045 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST);
9046 }
9047 }
9048 #endif // HAVE_BOTAN110
9049
9050 /*
9051 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
9052
9053 - check out of band support
9054
9055 - check preoutquery
9056
9057 */
9058
9059 BOOST_AUTO_TEST_SUITE_END()