]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc.cc
rec: Refuse queries for all meta-types
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc.cc
1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
3 #include <boost/test/unit_test.hpp>
4
5 #include "syncres.hh"
6 #include "arguments.hh"
7 #include "base32.hh"
8 #include "dnssecinfra.hh"
9 #include "dnsseckeeper.hh"
10 #include "lua-recursor4.hh"
11 #include "namespaces.hh"
12 #include "rec-lua-conf.hh"
13 #include "root-dnssec.hh"
14 #include "test-common.hh"
15 #include "utility.hh"
16 #include "validate-recursor.hh"
17
18 RecursorStats g_stats;
19 GlobalStateHolder<LuaConfigItems> g_luaconfs;
20 thread_local std::unique_ptr<MemRecursorCache> t_RC{nullptr};
21 unsigned int g_numThreads = 1;
22 bool g_lowercaseOutgoing = false;
23
24 /* Fake some required functions we didn't want the trouble to
25 link with */
26 ArgvMap &arg()
27 {
28 static ArgvMap theArg;
29 return theArg;
30 }
31
32 int getMTaskerTID()
33 {
34 return 0;
35 }
36
37 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
38 {
39 return false;
40 }
41
42 int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained)
43 {
44 return 0;
45 }
46
47 /* primeHints() is only here for now because it
48 was way too much trouble to link with the real one.
49 We should fix this, empty functions are one thing, but this is
50 bad.
51 */
52
53 #include "root-addresses.hh"
54
55 void primeHints(void)
56 {
57 vector<DNSRecord> nsset;
58 if(!t_RC)
59 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
60
61 DNSRecord arr, aaaarr, nsrr;
62 nsrr.d_name=g_rootdnsname;
63 arr.d_type=QType::A;
64 aaaarr.d_type=QType::AAAA;
65 nsrr.d_type=QType::NS;
66 arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(nullptr)+3600000;
67
68 for(char c='a';c<='m';++c) {
69 char templ[40];
70 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
71 templ[sizeof(templ)-1] = '\0';
72 *templ=c;
73 aaaarr.d_name=arr.d_name=DNSName(templ);
74 nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
75 arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
76 vector<DNSRecord> aset;
77 aset.push_back(arr);
78 t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
79 if (rootIps6[c-'a'] != NULL) {
80 aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
81
82 vector<DNSRecord> aaaaset;
83 aaaaset.push_back(aaaarr);
84 t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
85 }
86
87 nsset.push_back(nsrr);
88 }
89 t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
90 }
91
92 LuaConfigItems::LuaConfigItems()
93 {
94 for (const auto &dsRecord : rootDSs) {
95 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
96 dsAnchors[g_rootdnsname].insert(*ds);
97 }
98 }
99
100 /* Some helpers functions */
101
102 static void init(bool debug=false)
103 {
104 L.setName("test");
105 L.disableSyslog(true);
106
107 if (debug) {
108 L.setLoglevel((Logger::Urgency)(6)); // info and up
109 L.toConsole(Logger::Info);
110 }
111 else {
112 L.setLoglevel(Logger::None);
113 L.toConsole(Logger::Error);
114 }
115
116 seedRandom("/dev/urandom");
117 reportAllTypes();
118
119 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
120
121 SyncRes::s_maxqperq = 50;
122 SyncRes::s_maxtotusec = 1000*7000;
123 SyncRes::s_maxdepth = 40;
124 SyncRes::s_maxnegttl = 3600;
125 SyncRes::s_maxcachettl = 86400;
126 SyncRes::s_packetcachettl = 3600;
127 SyncRes::s_packetcacheservfailttl = 60;
128 SyncRes::s_serverdownmaxfails = 64;
129 SyncRes::s_serverdownthrottletime = 60;
130 SyncRes::s_doIPv6 = true;
131 SyncRes::s_ecsipv4limit = 24;
132 SyncRes::s_ecsipv6limit = 56;
133 SyncRes::s_rootNXTrust = true;
134 SyncRes::s_minimumTTL = 0;
135 SyncRes::s_serverID = "PowerDNS Unit Tests Server ID";
136 SyncRes::clearEDNSSubnets();
137 SyncRes::clearEDNSDomains();
138 SyncRes::clearDelegationOnly();
139 SyncRes::clearDontQuery();
140
141 SyncRes::clearNSSpeeds();
142 BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0);
143 SyncRes::clearEDNSStatuses();
144 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0);
145 SyncRes::clearThrottle();
146 BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0);
147 SyncRes::clearFailedServers();
148 BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0);
149
150 auto luaconfsCopy = g_luaconfs.getCopy();
151 luaconfsCopy.dfe.clear();
152 luaconfsCopy.dsAnchors.clear();
153 for (const auto &dsRecord : rootDSs) {
154 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
155 luaconfsCopy.dsAnchors[g_rootdnsname].insert(*ds);
156 }
157 luaconfsCopy.negAnchors.clear();
158 g_luaconfs.setState(luaconfsCopy);
159
160 g_dnssecmode = DNSSECMode::Off;
161 g_dnssecLOG = debug;
162 g_maxNSEC3Iterations = 2500;
163
164 ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Unit Tests";
165 }
166
167 static void initSR(std::unique_ptr<SyncRes>& sr, bool dnssec=false, bool debug=false, time_t fakeNow=0)
168 {
169 struct timeval now;
170 if (fakeNow > 0) {
171 now.tv_sec = fakeNow;
172 now.tv_usec = 0;
173 }
174 else {
175 Utility::gettimeofday(&now, 0);
176 }
177
178 init(debug);
179
180 sr = std::unique_ptr<SyncRes>(new SyncRes(now));
181 sr->setDoEDNS0(true);
182 if (dnssec) {
183 sr->setDoDNSSEC(dnssec);
184 }
185
186 sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
187
188 SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
189 SyncRes::clearNegCache();
190 }
191
192 static void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
193 {
194 sr->setDNSSECValidationRequested(true);
195 g_dnssecmode = mode;
196 }
197
198 static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
199 {
200 res->d_rcode = rcode;
201 res->d_aabit = aa;
202 res->d_tcbit = tc;
203 res->d_haveEDNS = edns;
204 }
205
206 static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
207 {
208 addRecordToList(res->d_records, name, type, content, place, ttl);
209 }
210
211 static void addRecordToLW(LWResult* res, const std::string& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
212 {
213 addRecordToLW(res, DNSName(name), type, content, place, ttl);
214 }
215
216 static bool isRootServer(const ComboAddress& ip)
217 {
218 if (ip.isIPv4()) {
219 for (size_t idx = 0; idx < rootIps4Count; idx++) {
220 if (ip.toString() == rootIps4[idx]) {
221 return true;
222 }
223 }
224 }
225 else {
226 for (size_t idx = 0; idx < rootIps6Count; idx++) {
227 if (ip.toString() == rootIps6[idx]) {
228 return true;
229 }
230 }
231 }
232
233 return false;
234 }
235
236 static void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign, boost::optional<uint8_t> algo=boost::none, boost::optional<uint32_t> inception=boost::none)
237 {
238 time_t now = time(nullptr);
239 DNSKEYRecordContent drc = dpk.getDNSKEY();
240 const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
241
242 rrc.d_type = signQType;
243 rrc.d_labels = signQName.countLabels() - signQName.isWildcard();
244 rrc.d_originalttl = signTTL;
245 rrc.d_siginception = inception ? *inception : (now - 10);
246 rrc.d_sigexpire = now + sigValidity;
247 rrc.d_signer = signer;
248 rrc.d_tag = 0;
249 rrc.d_tag = drc.getTag();
250 rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
251
252 std::string msg = getMessageForRRSET(signQName, rrc, toSign);
253
254 rrc.d_signature = rc->sign(msg);
255 }
256
257 typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t;
258
259 static bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional<uint8_t> algo=boost::none, boost::optional<DNSName> wildcard=boost::none)
260 {
261 if (records.empty()) {
262 return false;
263 }
264
265 const auto it = keys.find(signer);
266 if (it == keys.cend()) {
267 throw std::runtime_error("No DNSKEY found for " + signer.toString() + ", unable to compute the requested RRSIG");
268 }
269
270 size_t recordsCount = records.size();
271 const DNSName& name = records[recordsCount-1].d_name;
272 const uint16_t type = records[recordsCount-1].d_type;
273
274 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
275 for (const auto record : records) {
276 if (record.d_name == name && record.d_type == type) {
277 recordcontents.push_back(record.d_content);
278 }
279 }
280
281 RRSIGRecordContent rrc;
282 computeRRSIG(it->second.first, signer, wildcard ? *wildcard : records[recordsCount-1].d_name, records[recordsCount-1].d_type, records[recordsCount-1].d_ttl, sigValidity, rrc, recordcontents, algo);
283 if (broken) {
284 rrc.d_signature[0] ^= 42;
285 }
286
287 DNSRecord rec;
288 rec.d_type = QType::RRSIG;
289 rec.d_place = records[recordsCount-1].d_place;
290 rec.d_name = records[recordsCount-1].d_name;
291 rec.d_ttl = records[recordsCount-1].d_ttl;
292
293 rec.d_content = std::make_shared<RRSIGRecordContent>(rrc);
294 records.push_back(rec);
295
296 return true;
297 }
298
299 static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records)
300 {
301 const auto it = keys.find(signer);
302 if (it == keys.cend()) {
303 throw std::runtime_error("No DNSKEY found for " + signer.toString());
304 }
305
306 DNSRecord rec;
307 rec.d_place = DNSResourceRecord::ANSWER;
308 rec.d_name = signer;
309 rec.d_type = QType::DNSKEY;
310 rec.d_ttl = ttl;
311
312 rec.d_content = std::make_shared<DNSKEYRecordContent>(it->second.first.getDNSKEY());
313 records.push_back(rec);
314 }
315
316 static bool addDS(const DNSName& domain, uint32_t ttl, std::vector<DNSRecord>& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY)
317 {
318 const auto it = keys.find(domain);
319 if (it == keys.cend()) {
320 return false;
321 }
322
323 DNSRecord rec;
324 rec.d_name = domain;
325 rec.d_type = QType::DS;
326 rec.d_place = place;
327 rec.d_ttl = ttl;
328 rec.d_content = std::make_shared<DSRecordContent>(it->second.second);
329
330 records.push_back(rec);
331 return true;
332 }
333
334 static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
335 {
336 NSECRecordContent nrc;
337 nrc.d_next = next;
338 nrc.d_set = types;
339
340 DNSRecord rec;
341 rec.d_name = domain;
342 rec.d_ttl = ttl;
343 rec.d_type = QType::NSEC;
344 rec.d_content = std::make_shared<NSECRecordContent>(nrc);
345 rec.d_place = DNSResourceRecord::AUTHORITY;
346
347 records.push_back(rec);
348 }
349
350 static void addNSEC3RecordToLW(const DNSName& hashedName, const std::string& hashedNext, const std::string& salt, unsigned int iterations, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
351 {
352 NSEC3RecordContent nrc;
353 nrc.d_algorithm = 1;
354 nrc.d_flags = 0;
355 nrc.d_iterations = iterations;
356 nrc.d_salt = salt;
357 nrc.d_nexthash = hashedNext;
358 nrc.d_set = types;
359
360 DNSRecord rec;
361 rec.d_name = hashedName;
362 rec.d_ttl = ttl;
363 rec.d_type = QType::NSEC3;
364 rec.d_content = std::make_shared<NSEC3RecordContent>(nrc);
365 rec.d_place = DNSResourceRecord::AUTHORITY;
366
367 records.push_back(rec);
368 }
369
370 static void addNSEC3UnhashedRecordToLW(const DNSName& domain, const DNSName& zone, const std::string& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records, unsigned int iterations=10)
371 {
372 static const std::string salt = "deadbeef";
373 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
374
375 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, next, salt, iterations, types, ttl, records);
376 }
377
378 static void addNSEC3NarrowRecordToLW(const DNSName& domain, const DNSName& zone, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records, unsigned int iterations=10)
379 {
380 static const std::string salt = "deadbeef";
381 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
382 std::string hashedNext(hashed);
383 incrementHash(hashedNext);
384 decrementHash(hashed);
385
386 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, hashedNext, salt, iterations, types, ttl, records);
387 }
388
389 static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys)
390 {
391 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(algo));
392 dcke->create((algo <= 10) ? 2048 : dcke->getBits());
393 DNSSECPrivateKey dpk;
394 dpk.d_flags = 256;
395 dpk.setKey(dcke);
396 DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest);
397 keys[name] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk,ds);
398 }
399
400 static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map<DNSName,dsmap_t>& dsAnchors)
401 {
402 generateKeyMaterial(name, algo, digest, keys);
403 dsAnchors[name].insert(keys[name].second);
404 }
405
406 static int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut=true)
407 {
408 if (type == QType::DS) {
409 auth.chopOff();
410
411 setLWResult(res, 0, true, false, true);
412
413 if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) {
414 addRRSIG(keys, res->d_records, auth, 300);
415 }
416 else {
417 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
418
419 /* if the auth zone is signed, we need to provide a secure denial */
420 const auto it = keys.find(auth);
421 if (it != keys.cend()) {
422 /* sign the SOA */
423 addRRSIG(keys, res->d_records, auth, 300);
424 /* add a NSEC denying the DS */
425 std::set<uint16_t> types = { QType::NSEC };
426 if (proveCut) {
427 types.insert(QType::NS);
428 }
429
430 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
431 addRRSIG(keys, res->d_records, auth, 300);
432 }
433 }
434
435 return 1;
436 }
437
438 if (type == QType::DNSKEY) {
439 setLWResult(res, 0, true, false, true);
440 addDNSKEY(keys, domain, 300, res->d_records);
441 addRRSIG(keys, res->d_records, domain, 300);
442 return 1;
443 }
444
445 return 0;
446 }
447
448 /* Real tests */
449
450 BOOST_AUTO_TEST_SUITE(syncres_cc)
451
452 BOOST_AUTO_TEST_CASE(test_root_primed) {
453 std::unique_ptr<SyncRes> sr;
454 initSR(sr);
455
456 primeHints();
457
458 const DNSName target("a.root-servers.net.");
459
460 /* we are primed, we should be able to resolve A a.root-servers.net. without any query */
461 vector<DNSRecord> ret;
462 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
463 BOOST_CHECK_EQUAL(res, RCode::NoError);
464 BOOST_REQUIRE_EQUAL(ret.size(), 1);
465 BOOST_CHECK(ret[0].d_type == QType::A);
466 BOOST_CHECK_EQUAL(ret[0].d_name, target);
467
468 ret.clear();
469 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
470 BOOST_CHECK_EQUAL(res, RCode::NoError);
471 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
472 BOOST_REQUIRE_EQUAL(ret.size(), 1);
473 BOOST_CHECK(ret[0].d_type == QType::AAAA);
474 BOOST_CHECK_EQUAL(ret[0].d_name, target);
475 }
476
477 BOOST_AUTO_TEST_CASE(test_root_primed_ns) {
478 std::unique_ptr<SyncRes> sr;
479 initSR(sr);
480
481 primeHints();
482 const DNSName target(".");
483
484 /* we are primed, but we should not be able to NS . without any query
485 because the . NS entry is not stored as authoritative */
486
487 size_t queriesCount = 0;
488
489 sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
490 queriesCount++;
491
492 if (domain == target && type == QType::NS) {
493
494 setLWResult(res, 0, true, false, true);
495 char addr[] = "a.root-servers.net.";
496 for (char idx = 'a'; idx <= 'm'; idx++) {
497 addr[0] = idx;
498 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
499 }
500
501 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
502 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
503
504 return 1;
505 }
506
507 return 0;
508 });
509
510 vector<DNSRecord> ret;
511 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
512 BOOST_CHECK_EQUAL(res, RCode::NoError);
513 BOOST_REQUIRE_EQUAL(ret.size(), 13);
514 BOOST_CHECK_EQUAL(queriesCount, 1);
515 }
516
517 BOOST_AUTO_TEST_CASE(test_root_not_primed) {
518 std::unique_ptr<SyncRes> sr;
519 initSR(sr);
520
521 size_t queriesCount = 0;
522
523 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
524 queriesCount++;
525
526 if (domain == g_rootdnsname && type == QType::NS) {
527 setLWResult(res, 0, true, false, true);
528 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
529 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
530 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
531
532 return 1;
533 }
534
535 return 0;
536 });
537
538 /* we are not primed yet, so SyncRes will have to call primeHints()
539 then call getRootNS(), for which at least one of the root servers needs to answer */
540 vector<DNSRecord> ret;
541 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
542 BOOST_CHECK_EQUAL(res, RCode::NoError);
543 BOOST_CHECK_EQUAL(ret.size(), 1);
544 BOOST_CHECK_EQUAL(queriesCount, 2);
545 }
546
547 BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
548 std::unique_ptr<SyncRes> sr;
549 initSR(sr);
550 std::set<ComboAddress> downServers;
551
552 /* we are not primed yet, so SyncRes will have to call primeHints()
553 then call getRootNS(), for which at least one of the root servers needs to answer.
554 None will, so it should ServFail.
555 */
556 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
557
558 downServers.insert(ip);
559 return 0;
560 });
561
562 vector<DNSRecord> ret;
563 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
564 BOOST_CHECK_EQUAL(res, RCode::ServFail);
565 BOOST_CHECK_EQUAL(ret.size(), 0);
566 BOOST_CHECK(downServers.size() > 0);
567 /* we explicitly refuse to mark the root servers down */
568 for (const auto& server : downServers) {
569 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
570 }
571 }
572
573 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
574 std::unique_ptr<SyncRes> sr;
575 initSR(sr);
576
577 ComboAddress noEDNSServer;
578 size_t queriesWithEDNS = 0;
579 size_t queriesWithoutEDNS = 0;
580
581 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &noEDNSServer](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
582 if (EDNS0Level != 0) {
583 queriesWithEDNS++;
584 noEDNSServer = ip;
585
586 setLWResult(res, RCode::FormErr);
587 return 1;
588 }
589
590 queriesWithoutEDNS++;
591
592 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
593 setLWResult(res, 0, true, false, false);
594 addRecordToLW(res, domain, QType::A, "192.0.2.1");
595 return 1;
596 }
597
598 return 0;
599 });
600
601 primeHints();
602
603 /* fake that the root NS doesn't handle EDNS, check that we fallback */
604 vector<DNSRecord> ret;
605 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
606 BOOST_CHECK_EQUAL(res, RCode::NoError);
607 BOOST_CHECK_EQUAL(ret.size(), 1);
608 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
609 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
610 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
611 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
612 }
613
614 BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) {
615 std::unique_ptr<SyncRes> sr;
616 initSR(sr);
617
618 size_t queriesWithEDNS = 0;
619 size_t queriesWithoutEDNS = 0;
620
621 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
622 if (EDNS0Level != 0) {
623 queriesWithEDNS++;
624 setLWResult(res, RCode::NotImp);
625 return 1;
626 }
627
628 queriesWithoutEDNS++;
629
630 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
631 setLWResult(res, 0, true, false, false);
632 addRecordToLW(res, domain, QType::A, "192.0.2.1");
633 return 1;
634 }
635
636 return 0;
637 });
638
639 primeHints();
640
641 /* fake that the NS doesn't handle EDNS, check that we fallback */
642 vector<DNSRecord> ret;
643 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
644 BOOST_CHECK_EQUAL(res, RCode::NoError);
645 BOOST_CHECK_EQUAL(ret.size(), 1);
646 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
647 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
648 }
649
650 BOOST_AUTO_TEST_CASE(test_edns_formerr_but_edns_enabled) {
651 std::unique_ptr<SyncRes> sr;
652 initSR(sr);
653
654 /* in this test, the auth answers with FormErr to an EDNS-enabled
655 query, but the response does contain EDNS so we should not mark
656 it as EDNS ignorant or intolerant.
657 */
658 size_t queriesWithEDNS = 0;
659 size_t queriesWithoutEDNS = 0;
660 std::set<ComboAddress> usedServers;
661
662 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &usedServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
663
664 if (EDNS0Level > 0) {
665 queriesWithEDNS++;
666 }
667 else {
668 queriesWithoutEDNS++;
669 }
670 usedServers.insert(ip);
671
672 if (type == QType::DNAME) {
673 setLWResult(res, RCode::FormErr);
674 if (EDNS0Level > 0) {
675 res->d_haveEDNS = true;
676 }
677 return 1;
678 }
679
680 return 0;
681 });
682
683 primeHints();
684
685 vector<DNSRecord> ret;
686 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::DNAME), QClass::IN, ret);
687 BOOST_CHECK_EQUAL(res, RCode::ServFail);
688 BOOST_CHECK_EQUAL(ret.size(), 0);
689 BOOST_CHECK_EQUAL(queriesWithEDNS, 26);
690 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 0);
691 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 26);
692 BOOST_CHECK_EQUAL(usedServers.size(), 26);
693 for (const auto& server : usedServers) {
694 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
695 }
696 }
697
698 BOOST_AUTO_TEST_CASE(test_meta_types) {
699 std::unique_ptr<SyncRes> sr;
700 initSR(sr);
701
702 static const std::set<uint16_t> invalidTypes = { 128, QType::AXFR, QType::IXFR, QType::RRSIG, QType::NSEC3, QType::OPT, QType::TSIG, QType::TKEY, QType::MAILA, QType::MAILB, 65535 };
703
704 for (const auto qtype : invalidTypes) {
705 size_t queriesCount = 0;
706
707 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
708
709 queriesCount++;
710 return 0;
711 });
712
713 primeHints();
714
715 vector<DNSRecord> ret;
716 int res = sr->beginResolve(DNSName("powerdns.com."), QType(qtype), QClass::IN, ret);
717 BOOST_CHECK_EQUAL(res, -1);
718 BOOST_CHECK_EQUAL(ret.size(), 0);
719 BOOST_CHECK_EQUAL(queriesCount, 0);
720 }
721 }
722
723 BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
724 std::unique_ptr<SyncRes> sr;
725 initSR(sr);
726
727 sr->setAsyncCallback([](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
728 if (!doTCP) {
729 setLWResult(res, 0, false, true, false);
730 return 1;
731 }
732 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
733 setLWResult(res, 0, true, false, false);
734 addRecordToLW(res, domain, QType::A, "192.0.2.1");
735 return 1;
736 }
737
738 return 0;
739 });
740
741 primeHints();
742
743 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
744 vector<DNSRecord> ret;
745 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
746 BOOST_CHECK_EQUAL(res, RCode::NoError);
747 }
748
749 BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
750 std::unique_ptr<SyncRes> sr;
751 initSR(sr);
752
753 size_t tcpQueriesCount = 0;
754
755 sr->setAsyncCallback([&tcpQueriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
756 if (!doTCP) {
757 setLWResult(res, 0, true, true, false);
758 return 1;
759 }
760
761 /* first TCP query is answered with a TC response */
762 tcpQueriesCount++;
763 if (tcpQueriesCount == 1) {
764 setLWResult(res, 0, true, true, false);
765 }
766 else {
767 setLWResult(res, 0, true, false, false);
768 }
769
770 addRecordToLW(res, domain, QType::A, "192.0.2.1");
771 return 1;
772 });
773
774 primeHints();
775
776 vector<DNSRecord> ret;
777 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
778 BOOST_CHECK_EQUAL(res, RCode::NoError);
779 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
780 }
781
782 BOOST_AUTO_TEST_CASE(test_all_nss_down) {
783 std::unique_ptr<SyncRes> sr;
784 initSR(sr);
785 std::set<ComboAddress> downServers;
786
787 primeHints();
788
789 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
790
791 if (isRootServer(ip)) {
792 setLWResult(res, 0, false, false, true);
793 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
794 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
795 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
796 return 1;
797 }
798 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
799 setLWResult(res, 0, false, false, true);
800 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
801 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
802 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
803 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
804 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
805 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
806 return 1;
807 }
808 else {
809 downServers.insert(ip);
810 return 0;
811 }
812 });
813
814 DNSName target("powerdns.com.");
815
816 vector<DNSRecord> ret;
817 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
818 BOOST_CHECK_EQUAL(res, RCode::ServFail);
819 BOOST_CHECK_EQUAL(ret.size(), 0);
820 BOOST_CHECK_EQUAL(downServers.size(), 4);
821
822 for (const auto& server : downServers) {
823 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
824 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
825 }
826 }
827
828 BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
829 std::unique_ptr<SyncRes> sr;
830 initSR(sr);
831 std::set<ComboAddress> downServers;
832
833 primeHints();
834
835 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
836
837 if (isRootServer(ip)) {
838 setLWResult(res, 0, false, false, true);
839 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
840 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
841 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
842 return 1;
843 }
844 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
845 setLWResult(res, 0, false, false, true);
846 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
847 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
848 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
849 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
850 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
851 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
852 return 1;
853 }
854 else {
855 downServers.insert(ip);
856 return 0;
857 }
858 });
859
860 /* exact same test than the previous one, except instead of a time out we fake a network error */
861 DNSName target("powerdns.com.");
862
863 vector<DNSRecord> ret;
864 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
865 BOOST_CHECK_EQUAL(res, RCode::ServFail);
866 BOOST_CHECK_EQUAL(ret.size(), 0);
867 BOOST_CHECK_EQUAL(downServers.size(), 4);
868
869 for (const auto& server : downServers) {
870 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
871 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
872 }
873 }
874
875 BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) {
876 std::unique_ptr<SyncRes> sr;
877 initSR(sr);
878
879 primeHints();
880
881 DNSName target("www.powerdns.com.");
882
883 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
884
885 if (isRootServer(ip)) {
886 setLWResult(res, 0, false, false, true);
887 if (domain == target) {
888 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
889 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
890 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
891 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
892 }
893 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
894 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
895 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
896 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
897 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
898 }
899 return 1;
900 }
901 else if (ip == ComboAddress("192.0.2.3:53")) {
902 setLWResult(res, 0, true, false, true);
903 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
904 if (type == QType::A) {
905 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
906 }
907 else if (type == QType::AAAA) {
908 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
909 }
910 }
911 else if (domain == target) {
912 if (type == QType::A) {
913 addRecordToLW(res, domain, QType::A, "192.0.2.1");
914 }
915 else if (type == QType::AAAA) {
916 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
917 }
918 }
919 return 1;
920 }
921 return 0;
922 });
923
924 vector<DNSRecord> ret;
925 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
926 BOOST_CHECK_EQUAL(res, RCode::NoError);
927 BOOST_CHECK_EQUAL(ret.size(), 1);
928 }
929
930 BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
931 std::unique_ptr<SyncRes> sr;
932 initSR(sr);
933 std::set<ComboAddress> downServers;
934
935 primeHints();
936
937 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
938
939 if (isRootServer(ip)) {
940 setLWResult(res, 0, false, false, true);
941 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
942 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
943 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
944 return 1;
945 }
946 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
947 setLWResult(res, 0, false, false, true);
948 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
949 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
950 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
951 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
952 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
953 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
954 return 1;
955 }
956 else {
957 if (downServers.size() < 3) {
958 /* only the last one will answer */
959 downServers.insert(ip);
960 return -2;
961 }
962 else {
963 setLWResult(res, 0, true, false, true);
964 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
965 return 1;
966 }
967 }
968 });
969
970 DNSName target("powerdns.com.");
971
972 vector<DNSRecord> ret;
973 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
974 BOOST_CHECK_EQUAL(res, RCode::NoError);
975 BOOST_CHECK_EQUAL(ret.size(), 1);
976 BOOST_CHECK_EQUAL(downServers.size(), 3);
977
978 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
979 for (const auto& server : downServers) {
980 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
981 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
982 }
983 }
984
985 BOOST_AUTO_TEST_CASE(test_glued_referral) {
986 std::unique_ptr<SyncRes> sr;
987 initSR(sr);
988
989 primeHints();
990
991 const DNSName target("powerdns.com.");
992
993 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
994 /* this will cause issue with qname minimization if we ever implement it */
995 if (domain != target) {
996 return 0;
997 }
998
999 if (isRootServer(ip)) {
1000 setLWResult(res, 0, false, false, true);
1001 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1002 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1003 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1004 return 1;
1005 }
1006 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
1007 setLWResult(res, 0, false, false, true);
1008 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1009 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1010 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
1011 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
1012 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
1013 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
1014 return 1;
1015 }
1016 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")) {
1017 setLWResult(res, 0, true, false, true);
1018 addRecordToLW(res, target, QType::A, "192.0.2.4");
1019 return 1;
1020 }
1021 else {
1022 return 0;
1023 }
1024 });
1025
1026 vector<DNSRecord> ret;
1027 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1028 BOOST_CHECK_EQUAL(res, RCode::NoError);
1029 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1030 BOOST_CHECK(ret[0].d_type == QType::A);
1031 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1032 }
1033
1034 BOOST_AUTO_TEST_CASE(test_glueless_referral) {
1035 std::unique_ptr<SyncRes> sr;
1036 initSR(sr);
1037
1038 primeHints();
1039
1040 const DNSName target("powerdns.com.");
1041
1042 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1043
1044 if (isRootServer(ip)) {
1045 setLWResult(res, 0, false, false, true);
1046
1047 if (domain.isPartOf(DNSName("com."))) {
1048 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1049 } else if (domain.isPartOf(DNSName("org."))) {
1050 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1051 }
1052 else {
1053 setLWResult(res, RCode::NXDomain, false, false, true);
1054 return 1;
1055 }
1056
1057 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1058 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1059 return 1;
1060 }
1061 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
1062 if (domain == target) {
1063 setLWResult(res, 0, false, false, true);
1064 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1065 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1066 return 1;
1067 }
1068 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
1069 setLWResult(res, 0, true, false, true);
1070 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
1071 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
1072 return 1;
1073 }
1074 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
1075 setLWResult(res, 0, true, false, true);
1076 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
1077 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
1078 return 1;
1079 }
1080
1081 setLWResult(res, RCode::NXDomain, false, false, true);
1082 return 1;
1083 }
1084 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")) {
1085 setLWResult(res, 0, true, false, true);
1086 addRecordToLW(res, target, QType::A, "192.0.2.4");
1087 return 1;
1088 }
1089 else {
1090 return 0;
1091 }
1092 });
1093
1094 vector<DNSRecord> ret;
1095 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1096 BOOST_CHECK_EQUAL(res, RCode::NoError);
1097 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1098 BOOST_CHECK(ret[0].d_type == QType::A);
1099 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1100 }
1101
1102 BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
1103 std::unique_ptr<SyncRes> sr;
1104 initSR(sr);
1105
1106 primeHints();
1107
1108 const DNSName target("powerdns.com.");
1109 SyncRes::addEDNSDomain(target);
1110
1111 EDNSSubnetOpts incomingECS;
1112 incomingECS.source = Netmask("192.0.2.128/32");
1113 sr->setIncomingECSFound(true);
1114 sr->setIncomingECS(incomingECS);
1115
1116 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1117
1118 BOOST_REQUIRE(srcmask);
1119 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1120 return 0;
1121 });
1122
1123 vector<DNSRecord> ret;
1124 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1125 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1126 }
1127
1128 BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
1129 std::unique_ptr<SyncRes> sr;
1130 initSR(sr);
1131
1132 primeHints();
1133
1134 const DNSName target("powerdns.com.");
1135 SyncRes::addEDNSSubnet(Netmask("192.0.2.1/32"));
1136
1137 EDNSSubnetOpts incomingECS;
1138 incomingECS.source = Netmask("2001:DB8::FF/128");
1139 sr->setIncomingECSFound(true);
1140 sr->setIncomingECS(incomingECS);
1141
1142 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1143
1144 if (isRootServer(ip)) {
1145 BOOST_REQUIRE(!srcmask);
1146
1147 setLWResult(res, 0, false, false, true);
1148 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1149 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1150 return 1;
1151 } else if (ip == ComboAddress("192.0.2.1:53")) {
1152
1153 BOOST_REQUIRE(srcmask);
1154 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1155
1156 setLWResult(res, 0, true, false, false);
1157 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1158 return 1;
1159 }
1160
1161 return 0;
1162 });
1163
1164 vector<DNSRecord> ret;
1165 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1166 BOOST_CHECK_EQUAL(res, RCode::NoError);
1167 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1168 BOOST_CHECK(ret[0].d_type == QType::A);
1169 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1170 }
1171
1172 BOOST_AUTO_TEST_CASE(test_following_cname) {
1173 std::unique_ptr<SyncRes> sr;
1174 initSR(sr);
1175
1176 primeHints();
1177
1178 const DNSName target("cname.powerdns.com.");
1179 const DNSName cnameTarget("cname-target.powerdns.com");
1180
1181 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1182
1183 if (isRootServer(ip)) {
1184 setLWResult(res, 0, false, false, true);
1185 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1186 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1187 return 1;
1188 } else if (ip == ComboAddress("192.0.2.1:53")) {
1189
1190 if (domain == target) {
1191 setLWResult(res, 0, true, false, false);
1192 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1193 return 1;
1194 }
1195 else if (domain == cnameTarget) {
1196 setLWResult(res, 0, true, false, false);
1197 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1198 }
1199
1200 return 1;
1201 }
1202
1203 return 0;
1204 });
1205
1206 vector<DNSRecord> ret;
1207 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1208 BOOST_CHECK_EQUAL(res, RCode::NoError);
1209 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1210 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1211 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1212 BOOST_CHECK(ret[1].d_type == QType::A);
1213 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1214 }
1215
1216 BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
1217 std::unique_ptr<SyncRes> sr;
1218 initSR(sr);
1219
1220 primeHints();
1221
1222 const DNSName target("cname.powerdns.com.");
1223 const DNSName cnameTarget("cname-target.powerdns.com");
1224
1225 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1226
1227 if (isRootServer(ip)) {
1228 setLWResult(res, 0, false, false, true);
1229 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1230 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1231 return 1;
1232 } else if (ip == ComboAddress("192.0.2.1:53")) {
1233
1234 if (domain == target) {
1235 setLWResult(res, RCode::NXDomain, true, false, false);
1236 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1237 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1238 } else if (domain == cnameTarget) {
1239 setLWResult(res, RCode::NXDomain, true, false, false);
1240 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1241 return 1;
1242 }
1243
1244 return 1;
1245 }
1246
1247 return 0;
1248 });
1249
1250 vector<DNSRecord> ret;
1251 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1252 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1253 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1254 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1255 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1256 BOOST_CHECK(ret[1].d_type == QType::SOA);
1257
1258 /* a second time, to check the cache */
1259 ret.clear();
1260 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1261 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1262 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1263 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1264 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1265 BOOST_CHECK(ret[1].d_type == QType::SOA);
1266 }
1267
1268 BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1269 std::unique_ptr<SyncRes> sr;
1270 initSR(sr);
1271
1272 primeHints();
1273
1274 /* In this test we directly get the NS server for cname.powerdns.com.,
1275 and we don't know whether it's also authoritative for
1276 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1277 the additional A record for cname-target.powerdns.com. */
1278 const DNSName target("cname.powerdns.com.");
1279 const DNSName cnameTarget("cname-target.powerdns.com");
1280
1281 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1282
1283 if (isRootServer(ip)) {
1284
1285 setLWResult(res, 0, false, false, true);
1286
1287 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1288 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1289 return 1;
1290 } else if (ip == ComboAddress("192.0.2.1:53")) {
1291
1292 if (domain == target) {
1293 setLWResult(res, 0, true, false, false);
1294 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1295 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1296 return 1;
1297 } else if (domain == cnameTarget) {
1298 setLWResult(res, 0, true, false, false);
1299 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1300 return 1;
1301 }
1302
1303 return 1;
1304 }
1305
1306 return 0;
1307 });
1308
1309 vector<DNSRecord> ret;
1310 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1311 BOOST_CHECK_EQUAL(res, RCode::NoError);
1312 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1313 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1314 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1315 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1316 BOOST_REQUIRE(ret[1].d_type == QType::A);
1317 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1318 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1319 }
1320
1321 BOOST_AUTO_TEST_CASE(test_cname_loop) {
1322 std::unique_ptr<SyncRes> sr;
1323 initSR(sr);
1324
1325 primeHints();
1326
1327 size_t count = 0;
1328 const DNSName target("cname.powerdns.com.");
1329
1330 sr->setAsyncCallback([target,&count](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1331
1332 count++;
1333
1334 if (isRootServer(ip)) {
1335
1336 setLWResult(res, 0, false, false, true);
1337 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1338 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1339 return 1;
1340 } else if (ip == ComboAddress("192.0.2.1:53")) {
1341
1342 if (domain == target) {
1343 setLWResult(res, 0, true, false, false);
1344 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1345 return 1;
1346 }
1347
1348 return 1;
1349 }
1350
1351 return 0;
1352 });
1353
1354 vector<DNSRecord> ret;
1355 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1356 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1357 BOOST_CHECK_GT(ret.size(), 0);
1358 BOOST_CHECK_EQUAL(count, 2);
1359 }
1360
1361 BOOST_AUTO_TEST_CASE(test_cname_depth) {
1362 std::unique_ptr<SyncRes> sr;
1363 initSR(sr);
1364
1365 primeHints();
1366
1367 size_t depth = 0;
1368 const DNSName target("cname.powerdns.com.");
1369
1370 sr->setAsyncCallback([target,&depth](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1371
1372 if (isRootServer(ip)) {
1373
1374 setLWResult(res, 0, false, false, true);
1375 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1376 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1377 return 1;
1378 } else if (ip == ComboAddress("192.0.2.1:53")) {
1379
1380 setLWResult(res, 0, true, false, false);
1381 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1382 depth++;
1383 return 1;
1384 }
1385
1386 return 0;
1387 });
1388
1389 vector<DNSRecord> ret;
1390 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1391 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1392 BOOST_CHECK_EQUAL(ret.size(), depth);
1393 /* we have an arbitrary limit at 10 when following a CNAME chain */
1394 BOOST_CHECK_EQUAL(depth, 10 + 2);
1395 }
1396
1397 BOOST_AUTO_TEST_CASE(test_time_limit) {
1398 std::unique_ptr<SyncRes> sr;
1399 initSR(sr);
1400
1401 primeHints();
1402
1403 size_t queries = 0;
1404 const DNSName target("cname.powerdns.com.");
1405
1406 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1407
1408 queries++;
1409
1410 if (isRootServer(ip)) {
1411 setLWResult(res, 0, false, false, true);
1412 /* Pretend that this query took 2000 ms */
1413 res->d_usec = 2000;
1414
1415 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1416 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1417 return 1;
1418 } else if (ip == ComboAddress("192.0.2.1:53")) {
1419
1420 setLWResult(res, 0, true, false, false);
1421 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1422 return 1;
1423 }
1424
1425 return 0;
1426 });
1427
1428 /* Set the maximum time to 1 ms */
1429 SyncRes::s_maxtotusec = 1000;
1430
1431 try {
1432 vector<DNSRecord> ret;
1433 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1434 BOOST_CHECK(false);
1435 }
1436 catch(const ImmediateServFailException& e) {
1437 }
1438 BOOST_CHECK_EQUAL(queries, 1);
1439 }
1440
1441 BOOST_AUTO_TEST_CASE(test_referral_depth) {
1442 std::unique_ptr<SyncRes> sr;
1443 initSR(sr);
1444
1445 primeHints();
1446
1447 size_t queries = 0;
1448 const DNSName target("www.powerdns.com.");
1449
1450 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1451
1452 queries++;
1453
1454 if (isRootServer(ip)) {
1455 setLWResult(res, 0, false, false, true);
1456
1457 if (domain == DNSName("www.powerdns.com.")) {
1458 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1459 }
1460 else if (domain == DNSName("ns.powerdns.com.")) {
1461 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1462 }
1463 else if (domain == DNSName("ns1.powerdns.org.")) {
1464 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1465 }
1466 else if (domain == DNSName("ns2.powerdns.org.")) {
1467 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1468 }
1469 else if (domain == DNSName("ns3.powerdns.org.")) {
1470 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1471 }
1472 else if (domain == DNSName("ns4.powerdns.org.")) {
1473 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1474 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1475 }
1476
1477 return 1;
1478 } else if (ip == ComboAddress("192.0.2.1:53")) {
1479
1480 setLWResult(res, 0, true, false, false);
1481 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1482 return 1;
1483 }
1484
1485 return 0;
1486 });
1487
1488 /* Set the maximum depth low */
1489 SyncRes::s_maxdepth = 10;
1490
1491 try {
1492 vector<DNSRecord> ret;
1493 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1494 BOOST_CHECK(false);
1495 }
1496 catch(const ImmediateServFailException& e) {
1497 }
1498 }
1499
1500 BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1501 std::unique_ptr<SyncRes> sr;
1502 initSR(sr);
1503
1504 primeHints();
1505
1506 size_t queries = 0;
1507 const DNSName target("cname.powerdns.com.");
1508
1509 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1510
1511 queries++;
1512
1513 if (isRootServer(ip)) {
1514
1515 setLWResult(res, 0, false, false, true);
1516 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1517 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1518 return 1;
1519 } else if (ip == ComboAddress("192.0.2.1:53")) {
1520
1521 setLWResult(res, 0, true, false, false);
1522 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1523 return 1;
1524 }
1525
1526 return 0;
1527 });
1528
1529 /* Set the maximum number of questions very low */
1530 SyncRes::s_maxqperq = 5;
1531
1532 try {
1533 vector<DNSRecord> ret;
1534 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1535 BOOST_CHECK(false);
1536 }
1537 catch(const ImmediateServFailException& e) {
1538 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1539 }
1540 }
1541
1542 BOOST_AUTO_TEST_CASE(test_throttled_server) {
1543 std::unique_ptr<SyncRes> sr;
1544 initSR(sr);
1545
1546 primeHints();
1547
1548 const DNSName target("throttled.powerdns.com.");
1549 const ComboAddress ns("192.0.2.1:53");
1550 size_t queriesToNS = 0;
1551
1552 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1553
1554 if (isRootServer(ip)) {
1555
1556 setLWResult(res, 0, false, 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 return 1;
1560 } else if (ip == ns) {
1561
1562 queriesToNS++;
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 /* mark ns as down */
1574 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, 10000);
1575
1576 vector<DNSRecord> ret;
1577 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1578 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1579 BOOST_CHECK_EQUAL(ret.size(), 0);
1580 /* we should not have sent any queries to ns */
1581 BOOST_CHECK_EQUAL(queriesToNS, 0);
1582 }
1583
1584 BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1585 std::unique_ptr<SyncRes> sr;
1586 initSR(sr);
1587
1588 primeHints();
1589
1590 const ComboAddress ns("192.0.2.1:53");
1591
1592 const size_t blocks = 10;
1593 /* mark ns as down for 'blocks' queries */
1594 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, blocks);
1595
1596 for (size_t idx = 0; idx < blocks; idx++) {
1597 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1598 }
1599
1600 /* we have been throttled 'blocks' times, we should not be throttled anymore */
1601 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1602 }
1603
1604 BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1605 std::unique_ptr<SyncRes> sr;
1606 initSR(sr);
1607
1608 primeHints();
1609
1610 const ComboAddress ns("192.0.2.1:53");
1611
1612 const size_t seconds = 1;
1613 /* mark ns as down for 'seconds' seconds */
1614 SyncRes::doThrottle(time(nullptr), ns, seconds, 10000);
1615
1616 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1617
1618 sleep(seconds + 1);
1619
1620 /* we should not be throttled anymore */
1621 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1622 }
1623
1624 BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1625 std::unique_ptr<SyncRes> sr;
1626 initSR(sr);
1627
1628 primeHints();
1629
1630 const DNSName target("throttled.powerdns.com.");
1631 const ComboAddress ns("192.0.2.1:53");
1632 size_t queriesToNS = 0;
1633
1634 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1635
1636 if (isRootServer(ip)) {
1637
1638 setLWResult(res, 0, false, false, true);
1639 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1640 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1641 return 1;
1642 } else if (ip == ns) {
1643
1644 queriesToNS++;
1645
1646 setLWResult(res, 0, true, false, false);
1647 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1648
1649 return 1;
1650 }
1651
1652 return 0;
1653 });
1654
1655 /* prevent querying this NS */
1656 SyncRes::addDontQuery(Netmask(ns));
1657
1658 vector<DNSRecord> ret;
1659 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1660 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1661 BOOST_CHECK_EQUAL(ret.size(), 0);
1662 /* we should not have sent any queries to ns */
1663 BOOST_CHECK_EQUAL(queriesToNS, 0);
1664 }
1665
1666 BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1667 std::unique_ptr<SyncRes> sr;
1668 initSR(sr);
1669
1670 primeHints();
1671
1672 const DNSName target1("powerdns.com.");
1673 const DNSName target2("notpowerdns.com.");
1674 const ComboAddress ns("192.0.2.1:53");
1675 size_t queriesCount = 0;
1676
1677 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1678
1679 queriesCount++;
1680
1681 if (isRootServer(ip)) {
1682
1683 if (domain == target1) {
1684 setLWResult(res, RCode::NXDomain, true, false, true);
1685 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1686 }
1687 else {
1688 setLWResult(res, 0, true, false, true);
1689 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1690 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1691 }
1692
1693 return 1;
1694 } else if (ip == ns) {
1695
1696 setLWResult(res, 0, true, false, false);
1697 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1698
1699 return 1;
1700 }
1701
1702 return 0;
1703 });
1704
1705 vector<DNSRecord> ret;
1706 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1707 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1708 BOOST_CHECK_EQUAL(ret.size(), 1);
1709 /* one for target1 and one for the entire TLD */
1710 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1711
1712 ret.clear();
1713 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1714 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1715 BOOST_CHECK_EQUAL(ret.size(), 1);
1716 /* one for target1 and one for the entire TLD */
1717 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1718
1719 /* we should have sent only one query */
1720 BOOST_CHECK_EQUAL(queriesCount, 1);
1721 }
1722
1723 BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1724 std::unique_ptr<SyncRes> sr;
1725 init();
1726 initSR(sr, true, false);
1727
1728 primeHints();
1729
1730 const DNSName target1("powerdns.com.");
1731 const DNSName target2("notpowerdns.com.");
1732 const ComboAddress ns("192.0.2.1:53");
1733 size_t queriesCount = 0;
1734
1735 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1736 We should add target1 to the negcache, but not "com.". */
1737
1738 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1739
1740 queriesCount++;
1741
1742 if (isRootServer(ip)) {
1743
1744 if (domain == target1) {
1745 setLWResult(res, RCode::NXDomain, true, false, true);
1746 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1747 }
1748 else {
1749 setLWResult(res, 0, true, false, true);
1750 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1751 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1752 }
1753
1754 return 1;
1755 } else if (ip == ns) {
1756
1757 setLWResult(res, 0, true, false, false);
1758 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1759
1760 return 1;
1761 }
1762
1763 return 0;
1764 });
1765
1766 vector<DNSRecord> ret;
1767 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1768 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1769 BOOST_CHECK_EQUAL(ret.size(), 1);
1770
1771 /* even with root-nx-trust on and a NX answer from the root,
1772 we should not have cached the entire TLD this time. */
1773 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1774
1775 ret.clear();
1776 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1777 BOOST_CHECK_EQUAL(res, RCode::NoError);
1778 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1779 BOOST_REQUIRE(ret[0].d_type == QType::A);
1780 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1781 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1782
1783 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1784
1785 BOOST_CHECK_EQUAL(queriesCount, 3);
1786 }
1787
1788 BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1789 std::unique_ptr<SyncRes> sr;
1790 initSR(sr);
1791
1792 primeHints();
1793
1794 const DNSName target1("powerdns.com.");
1795 const DNSName target2("notpowerdns.com.");
1796 const ComboAddress ns("192.0.2.1:53");
1797 size_t queriesCount = 0;
1798
1799 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1800
1801 queriesCount++;
1802
1803 if (isRootServer(ip)) {
1804
1805 if (domain == target1) {
1806 setLWResult(res, RCode::NXDomain, true, false, true);
1807 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1808 }
1809 else {
1810 setLWResult(res, 0, true, false, true);
1811 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1812 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1813 }
1814
1815 return 1;
1816 } else if (ip == ns) {
1817
1818 setLWResult(res, 0, true, false, false);
1819 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1820
1821 return 1;
1822 }
1823
1824 return 0;
1825 });
1826
1827 SyncRes::s_rootNXTrust = false;
1828
1829 vector<DNSRecord> ret;
1830 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1831 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1832 BOOST_CHECK_EQUAL(ret.size(), 1);
1833 /* one for target1 */
1834 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1835
1836 ret.clear();
1837 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1838 BOOST_CHECK_EQUAL(res, RCode::NoError);
1839 BOOST_CHECK_EQUAL(ret.size(), 1);
1840 /* one for target1 */
1841 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1842
1843 /* we should have sent three queries */
1844 BOOST_CHECK_EQUAL(queriesCount, 3);
1845 }
1846
1847 BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1848 std::unique_ptr<SyncRes> sr;
1849 initSR(sr);
1850
1851 primeHints();
1852
1853 const DNSName target("www.powerdns.com.");
1854 const DNSName cnameTarget("cname.powerdns.com.");
1855
1856 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
1857
1858 EDNSSubnetOpts incomingECS;
1859 incomingECS.source = Netmask("192.0.2.128/32");
1860 sr->setIncomingECSFound(true);
1861 sr->setIncomingECS(incomingECS);
1862
1863 sr->setAsyncCallback([target,cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1864
1865 BOOST_REQUIRE(srcmask);
1866 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1867
1868 if (isRootServer(ip)) {
1869 setLWResult(res, 0, false, false, true);
1870 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1871 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1872
1873 return 1;
1874 } else if (ip == ComboAddress("192.0.2.1:53")) {
1875 if (domain == target) {
1876 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
1877 setLWResult(res, RCode::NXDomain, true, false, true);
1878 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1879 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1880 }
1881 else if (domain == cnameTarget) {
1882 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
1883 but we might if we still chase the CNAME. */
1884 setLWResult(res, RCode::NXDomain, true, false, true);
1885 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1886 }
1887
1888 return 1;
1889 }
1890
1891 return 0;
1892 });
1893
1894 vector<DNSRecord> ret;
1895 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1896 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1897 BOOST_CHECK_EQUAL(ret.size(), 2);
1898 /* no negative cache entry because the response was variable */
1899 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
1900 }
1901
1902 BOOST_AUTO_TEST_CASE(test_ns_speed) {
1903 std::unique_ptr<SyncRes> sr;
1904 initSR(sr);
1905
1906 primeHints();
1907
1908 const DNSName target("powerdns.com.");
1909
1910 std::map<ComboAddress, uint64_t> nsCounts;
1911
1912 sr->setAsyncCallback([target,&nsCounts](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1913
1914 if (isRootServer(ip)) {
1915 setLWResult(res, 0, false, false, true);
1916 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1917 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1918 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1919
1920 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1921 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1922 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1923 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
1924 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
1925 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
1926
1927 return 1;
1928 } else {
1929 nsCounts[ip]++;
1930
1931 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
1932 BOOST_CHECK_LT(nsCounts.size(), 3);
1933
1934 /* let's time out on pdns-public-ns2.powerdns.com. */
1935 return 0;
1936 }
1937 else if (ip == ComboAddress("192.0.2.1:53")) {
1938 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1939
1940 setLWResult(res, 0, true, false, true);
1941 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1942 return 1;
1943 }
1944
1945 return 0;
1946 }
1947
1948 return 0;
1949 });
1950
1951 struct timeval now;
1952 gettimeofday(&now, 0);
1953
1954 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
1955 then pdns-public-ns1.powerdns.com. on IPv4 */
1956 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
1957 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
1958 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
1959 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
1960 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
1961 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
1962
1963 vector<DNSRecord> ret;
1964 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1965 BOOST_CHECK_EQUAL(res, RCode::NoError);
1966 BOOST_CHECK_EQUAL(ret.size(), 1);
1967 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1968 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
1969 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
1970 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
1971 }
1972
1973 BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
1974 std::unique_ptr<SyncRes> sr;
1975 initSR(sr);
1976
1977 primeHints();
1978
1979 const DNSName target("powerdns.com.");
1980
1981 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
1982
1983 if (isRootServer(ip)) {
1984 setLWResult(res, 0, false, false, true);
1985 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1986
1987 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1988
1989 return 1;
1990 } else if (ip == ComboAddress("192.0.2.1:53")) {
1991 setLWResult(res, 0, true, false, true);
1992 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1993 return 1;
1994 }
1995
1996 return 0;
1997 });
1998
1999 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
2000 time_t now = sr->getNow().tv_sec;
2001 std::vector<DNSRecord> records;
2002 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2003 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
2004
2005 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
2006
2007 vector<DNSRecord> ret;
2008 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2009 BOOST_CHECK_EQUAL(res, RCode::NoError);
2010 BOOST_CHECK_EQUAL(ret.size(), 1);
2011 }
2012
2013 BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
2014 std::unique_ptr<SyncRes> sr;
2015 initSR(sr);
2016
2017 primeHints();
2018
2019 const DNSName target("powerdns.com.");
2020 size_t queriesCount = 0;
2021
2022 sr->setAsyncCallback([&queriesCount,target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2023
2024 queriesCount++;
2025
2026 if (isRootServer(ip) && domain == target) {
2027 setLWResult(res, 0, false, false, true);
2028 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2029 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2030 return 1;
2031 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
2032 setLWResult(res, 0, true, false, true);
2033 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2034 return 1;
2035 }
2036
2037 return 0;
2038 });
2039
2040 vector<DNSRecord> ret;
2041 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2042 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2043 BOOST_CHECK_EQUAL(ret.size(), 0);
2044 /* one query to get NSs, then A and AAAA for each NS */
2045 BOOST_CHECK_EQUAL(queriesCount, 5);
2046 }
2047
2048 BOOST_AUTO_TEST_CASE(test_cache_hit) {
2049 std::unique_ptr<SyncRes> sr;
2050 initSR(sr);
2051
2052 primeHints();
2053
2054 const DNSName target("powerdns.com.");
2055
2056 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2057
2058 return 0;
2059 });
2060
2061 /* we populate the cache with eveything we need */
2062 time_t now = sr->getNow().tv_sec;
2063 std::vector<DNSRecord> records;
2064 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2065
2066 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
2067 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
2068
2069 vector<DNSRecord> ret;
2070 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2071 BOOST_CHECK_EQUAL(res, RCode::NoError);
2072 BOOST_CHECK_EQUAL(ret.size(), 1);
2073 }
2074
2075 BOOST_AUTO_TEST_CASE(test_no_rd) {
2076 std::unique_ptr<SyncRes> sr;
2077 initSR(sr);
2078
2079 primeHints();
2080
2081 const DNSName target("powerdns.com.");
2082 size_t queriesCount = 0;
2083
2084 sr->setCacheOnly();
2085
2086 sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2087
2088 queriesCount++;
2089 return 0;
2090 });
2091
2092 vector<DNSRecord> ret;
2093 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2094 BOOST_CHECK_EQUAL(res, RCode::NoError);
2095 BOOST_CHECK_EQUAL(ret.size(), 0);
2096 BOOST_CHECK_EQUAL(queriesCount, 0);
2097 }
2098
2099 BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
2100 std::unique_ptr<SyncRes> sr;
2101 initSR(sr);
2102
2103 primeHints();
2104
2105 const DNSName target("cachettl.powerdns.com.");
2106 const ComboAddress ns("192.0.2.1:53");
2107
2108 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2109
2110 if (isRootServer(ip)) {
2111
2112 setLWResult(res, 0, false, false, true);
2113 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2114 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
2115 return 1;
2116 } else if (ip == ns) {
2117
2118 setLWResult(res, 0, true, false, false);
2119 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2120
2121 return 1;
2122 }
2123
2124 return 0;
2125 });
2126
2127 const time_t now = sr->getNow().tv_sec;
2128 SyncRes::s_minimumTTL = 60;
2129 SyncRes::s_maxcachettl = 3600;
2130
2131 vector<DNSRecord> ret;
2132 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2133 BOOST_CHECK_EQUAL(res, RCode::NoError);
2134 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2135 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
2136
2137 const ComboAddress who;
2138 vector<DNSRecord> cached;
2139 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
2140 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2141 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2142 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
2143
2144 cached.clear();
2145 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
2146 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2147 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2148 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
2149 }
2150
2151 BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
2152 std::unique_ptr<SyncRes> sr;
2153 initSR(sr);
2154
2155 primeHints();
2156
2157 const DNSName target("powerdns.com.");
2158
2159 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2160
2161 if (isRootServer(ip)) {
2162 setLWResult(res, 0, false, false, true);
2163 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2164
2165 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2166
2167 return 1;
2168 } else if (ip == ComboAddress("192.0.2.1:53")) {
2169 setLWResult(res, 0, true, false, true);
2170 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2171 return 1;
2172 }
2173
2174 return 0;
2175 });
2176
2177 /* we populate the cache with entries that expired 60s ago*/
2178 time_t now = sr->getNow().tv_sec;
2179 std::vector<DNSRecord> records;
2180 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2181 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
2182
2183 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
2184
2185 vector<DNSRecord> ret;
2186 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2187 BOOST_CHECK_EQUAL(res, RCode::NoError);
2188 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2189 BOOST_REQUIRE(ret[0].d_type == QType::A);
2190 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
2191 }
2192
2193 BOOST_AUTO_TEST_CASE(test_delegation_only) {
2194 std::unique_ptr<SyncRes> sr;
2195 initSR(sr);
2196
2197 primeHints();
2198
2199 /* Thanks, Verisign */
2200 SyncRes::addDelegationOnly(DNSName("com."));
2201 SyncRes::addDelegationOnly(DNSName("net."));
2202
2203 const DNSName target("nx-powerdns.com.");
2204
2205 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2206
2207 if (isRootServer(ip)) {
2208 setLWResult(res, 0, false, false, true);
2209 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2210 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2211 return 1;
2212 } else if (ip == ComboAddress("192.0.2.1:53")) {
2213
2214 setLWResult(res, 0, true, false, true);
2215 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2216 return 1;
2217 }
2218
2219 return 0;
2220 });
2221
2222 vector<DNSRecord> ret;
2223 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2224 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2225 BOOST_CHECK_EQUAL(ret.size(), 0);
2226 }
2227
2228 BOOST_AUTO_TEST_CASE(test_unauth_any) {
2229 std::unique_ptr<SyncRes> sr;
2230 initSR(sr);
2231
2232 primeHints();
2233
2234 const DNSName target("powerdns.com.");
2235
2236 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2237
2238 if (isRootServer(ip)) {
2239 setLWResult(res, 0, false, false, true);
2240 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2241 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2242 return 1;
2243 } else if (ip == ComboAddress("192.0.2.1:53")) {
2244
2245 setLWResult(res, 0, false, false, true);
2246 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2247 return 1;
2248 }
2249
2250 return 0;
2251 });
2252
2253 vector<DNSRecord> ret;
2254 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2255 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2256 BOOST_CHECK_EQUAL(ret.size(), 0);
2257 }
2258
2259 BOOST_AUTO_TEST_CASE(test_no_data) {
2260 std::unique_ptr<SyncRes> sr;
2261 initSR(sr);
2262
2263 primeHints();
2264
2265 const DNSName target("powerdns.com.");
2266
2267 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2268
2269 setLWResult(res, 0, true, false, true);
2270 return 1;
2271 });
2272
2273 vector<DNSRecord> ret;
2274 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2275 BOOST_CHECK_EQUAL(res, RCode::NoError);
2276 BOOST_CHECK_EQUAL(ret.size(), 0);
2277 }
2278
2279 BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2280 std::unique_ptr<SyncRes> sr;
2281 initSR(sr);
2282
2283 primeHints();
2284
2285 const DNSName target("powerdns.com.");
2286
2287 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2288
2289 setLWResult(res, 0, true, false, true);
2290 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2291 addRecordToLW(res, domain, QType::ANY, "0 0");
2292 addRecordToLW(res, domain, QType::OPT, "");
2293 return 1;
2294 });
2295
2296 vector<DNSRecord> ret;
2297 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2298 BOOST_CHECK_EQUAL(res, RCode::NoError);
2299 BOOST_CHECK_EQUAL(ret.size(), 1);
2300 }
2301
2302 BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2303 std::unique_ptr<SyncRes> sr;
2304 initSR(sr);
2305
2306 primeHints();
2307
2308 const DNSName target("powerdns.com.");
2309
2310 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2311
2312 setLWResult(res, 0, true, false, true);
2313 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2314 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2315 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2316 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2317 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2318 return 1;
2319 });
2320
2321 vector<DNSRecord> ret;
2322 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2323 BOOST_CHECK_EQUAL(res, RCode::NoError);
2324 BOOST_CHECK_EQUAL(ret.size(), 1);
2325 }
2326
2327 BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2328 std::unique_ptr<SyncRes> sr;
2329 initSR(sr, true);
2330
2331 primeHints();
2332
2333 const DNSName target("powerdns.com.");
2334
2335 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2336
2337 setLWResult(res, 0, true, false, true);
2338 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2339 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2340 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2341 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2342 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2343 return 1;
2344 });
2345
2346 vector<DNSRecord> ret;
2347 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2348 BOOST_CHECK_EQUAL(res, RCode::NoError);
2349 BOOST_CHECK_EQUAL(ret.size(), 4);
2350 }
2351
2352 BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2353 std::unique_ptr<SyncRes> sr;
2354 initSR(sr);
2355
2356 primeHints();
2357
2358 const DNSName target("powerdns.com.");
2359
2360 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2361
2362 setLWResult(res, RCode::NXDomain, true, false, true);
2363 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2364 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2365 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2366 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2367 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2368 return 1;
2369 });
2370
2371 vector<DNSRecord> ret;
2372 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2373 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2374 BOOST_CHECK_EQUAL(ret.size(), 1);
2375 }
2376
2377 BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2378 std::unique_ptr<SyncRes> sr;
2379 initSR(sr, true);
2380
2381 primeHints();
2382
2383 const DNSName target("powerdns.com.");
2384
2385 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2386
2387 setLWResult(res, RCode::NXDomain, true, false, true);
2388 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2389 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2390 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2391 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2392 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2393 return 1;
2394 });
2395
2396 vector<DNSRecord> ret;
2397 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2398 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2399 BOOST_CHECK_EQUAL(ret.size(), 4);
2400 }
2401
2402 BOOST_AUTO_TEST_CASE(test_qclass_none) {
2403 std::unique_ptr<SyncRes> sr;
2404 initSR(sr);
2405
2406 primeHints();
2407
2408 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2409 size_t queriesCount = 0;
2410
2411 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2412
2413 queriesCount++;
2414 return 0;
2415 });
2416
2417 const DNSName target("powerdns.com.");
2418 vector<DNSRecord> ret;
2419 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2420 BOOST_CHECK_EQUAL(res, -1);
2421 BOOST_CHECK_EQUAL(ret.size(), 0);
2422 BOOST_CHECK_EQUAL(queriesCount, 0);
2423 }
2424
2425 BOOST_AUTO_TEST_CASE(test_special_types) {
2426 std::unique_ptr<SyncRes> sr;
2427 initSR(sr);
2428
2429 primeHints();
2430
2431 /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
2432 size_t queriesCount = 0;
2433
2434 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2435
2436 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2437 queriesCount++;
2438 return 0;
2439 });
2440
2441 const DNSName target("powerdns.com.");
2442 vector<DNSRecord> ret;
2443 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2444 BOOST_CHECK_EQUAL(res, -1);
2445 BOOST_CHECK_EQUAL(ret.size(), 0);
2446 BOOST_CHECK_EQUAL(queriesCount, 0);
2447
2448 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2449 BOOST_CHECK_EQUAL(res, -1);
2450 BOOST_CHECK_EQUAL(ret.size(), 0);
2451 BOOST_CHECK_EQUAL(queriesCount, 0);
2452
2453 res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2454 BOOST_CHECK_EQUAL(res, -1);
2455 BOOST_CHECK_EQUAL(ret.size(), 0);
2456 BOOST_CHECK_EQUAL(queriesCount, 0);
2457
2458 res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
2459 BOOST_CHECK_EQUAL(res, -1);
2460 BOOST_CHECK_EQUAL(ret.size(), 0);
2461 BOOST_CHECK_EQUAL(queriesCount, 0);
2462 }
2463
2464 BOOST_AUTO_TEST_CASE(test_special_names) {
2465 std::unique_ptr<SyncRes> sr;
2466 initSR(sr);
2467
2468 primeHints();
2469
2470 /* special names should be handled internally */
2471
2472 size_t queriesCount = 0;
2473
2474 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2475
2476 queriesCount++;
2477 return 0;
2478 });
2479
2480 vector<DNSRecord> ret;
2481 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
2482 BOOST_CHECK_EQUAL(res, RCode::NoError);
2483 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2484 BOOST_CHECK(ret[0].d_type == QType::PTR);
2485 BOOST_CHECK_EQUAL(queriesCount, 0);
2486
2487 ret.clear();
2488 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
2489 BOOST_CHECK_EQUAL(res, RCode::NoError);
2490 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2491 BOOST_CHECK(ret[0].d_type == QType::PTR);
2492 BOOST_CHECK_EQUAL(queriesCount, 0);
2493
2494 ret.clear();
2495 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);
2496 BOOST_CHECK_EQUAL(res, RCode::NoError);
2497 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2498 BOOST_CHECK(ret[0].d_type == QType::PTR);
2499 BOOST_CHECK_EQUAL(queriesCount, 0);
2500
2501 ret.clear();
2502 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);
2503 BOOST_CHECK_EQUAL(res, RCode::NoError);
2504 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2505 BOOST_CHECK(ret[0].d_type == QType::PTR);
2506 BOOST_CHECK_EQUAL(queriesCount, 0);
2507
2508 ret.clear();
2509 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
2510 BOOST_CHECK_EQUAL(res, RCode::NoError);
2511 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2512 BOOST_CHECK(ret[0].d_type == QType::A);
2513 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2514 BOOST_CHECK_EQUAL(queriesCount, 0);
2515
2516 ret.clear();
2517 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
2518 BOOST_CHECK_EQUAL(res, RCode::NoError);
2519 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2520 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2521 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2522 BOOST_CHECK_EQUAL(queriesCount, 0);
2523
2524 ret.clear();
2525 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
2526 BOOST_CHECK_EQUAL(res, RCode::NoError);
2527 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2528 for (const auto& rec : ret) {
2529 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2530 if (rec.d_type == QType::A) {
2531 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2532 }
2533 else {
2534 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2535 }
2536 }
2537 BOOST_CHECK_EQUAL(queriesCount, 0);
2538
2539 ret.clear();
2540 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
2541 BOOST_CHECK_EQUAL(res, RCode::NoError);
2542 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2543 BOOST_CHECK(ret[0].d_type == QType::TXT);
2544 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2545 BOOST_CHECK_EQUAL(queriesCount, 0);
2546
2547 ret.clear();
2548 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
2549 BOOST_CHECK_EQUAL(res, RCode::NoError);
2550 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2551 BOOST_CHECK(ret[0].d_type == QType::TXT);
2552 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2553 BOOST_CHECK_EQUAL(queriesCount, 0);
2554
2555 ret.clear();
2556 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
2557 BOOST_CHECK_EQUAL(res, RCode::NoError);
2558 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2559 BOOST_CHECK(ret[0].d_type == QType::TXT);
2560 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2561 BOOST_CHECK_EQUAL(queriesCount, 0);
2562
2563 ret.clear();
2564 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
2565 BOOST_CHECK_EQUAL(res, RCode::NoError);
2566 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2567 BOOST_CHECK(ret[0].d_type == QType::TXT);
2568 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2569 BOOST_CHECK_EQUAL(queriesCount, 0);
2570
2571 ret.clear();
2572 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
2573 BOOST_CHECK_EQUAL(res, RCode::NoError);
2574 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2575 BOOST_CHECK(ret[0].d_type == QType::TXT);
2576 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2577 BOOST_CHECK_EQUAL(queriesCount, 0);
2578
2579 ret.clear();
2580 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
2581 BOOST_CHECK_EQUAL(res, RCode::NoError);
2582 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2583 BOOST_CHECK(ret[0].d_type == QType::TXT);
2584 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2585 BOOST_CHECK_EQUAL(queriesCount, 0);
2586 }
2587
2588 BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2589 std::unique_ptr<SyncRes> sr;
2590 initSR(sr);
2591
2592 primeHints();
2593
2594 const DNSName target("rpz.powerdns.com.");
2595 const ComboAddress ns("192.0.2.1:53");
2596
2597 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2598
2599 if (isRootServer(ip)) {
2600 setLWResult(res, false, true, false, true);
2601 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2602 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2603 return 1;
2604 } else if (ip == ns) {
2605
2606 setLWResult(res, 0, true, false, true);
2607 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2608 return 1;
2609 }
2610
2611 return 0;
2612 });
2613
2614 DNSFilterEngine::Policy pol;
2615 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2616 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2617 zone->setName("Unit test policy 0");
2618 zone->addNSIPTrigger(Netmask(ns, 32), pol);
2619 auto luaconfsCopy = g_luaconfs.getCopy();
2620 luaconfsCopy.dfe.addZone(zone);
2621 g_luaconfs.setState(luaconfsCopy);
2622
2623 vector<DNSRecord> ret;
2624 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2625 BOOST_CHECK_EQUAL(res, -2);
2626 BOOST_CHECK_EQUAL(ret.size(), 0);
2627 }
2628
2629 BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2630 std::unique_ptr<SyncRes> sr;
2631 initSR(sr);
2632
2633 primeHints();
2634
2635 const DNSName target("rpz.powerdns.com.");
2636 const ComboAddress ns("[2001:DB8::42]:53");
2637
2638 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2639
2640 if (isRootServer(ip)) {
2641 setLWResult(res, 0, false, false, true);
2642 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2643 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2644 return 1;
2645 } else if (ip == ns) {
2646
2647 setLWResult(res, 0, true, false, true);
2648 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2649 return 1;
2650 }
2651
2652 return 0;
2653 });
2654
2655 DNSFilterEngine::Policy pol;
2656 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2657 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2658 zone->setName("Unit test policy 0");
2659 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2660 auto luaconfsCopy = g_luaconfs.getCopy();
2661 luaconfsCopy.dfe.addZone(zone);
2662 g_luaconfs.setState(luaconfsCopy);
2663
2664 vector<DNSRecord> ret;
2665 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2666 BOOST_CHECK_EQUAL(res, -2);
2667 BOOST_CHECK_EQUAL(ret.size(), 0);
2668 }
2669
2670 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2671 std::unique_ptr<SyncRes> sr;
2672 initSR(sr);
2673
2674 primeHints();
2675
2676 const DNSName target("rpz.powerdns.com.");
2677 const ComboAddress ns("192.0.2.1:53");
2678 const DNSName nsName("ns1.powerdns.com.");
2679
2680 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2681
2682 if (isRootServer(ip)) {
2683 setLWResult(res, 0, false, false, true);
2684 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2685 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2686 return 1;
2687 } else if (ip == ns) {
2688
2689 setLWResult(res, 0, true, false, true);
2690 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2691 return 1;
2692 }
2693
2694 return 0;
2695 });
2696
2697 DNSFilterEngine::Policy pol;
2698 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2699 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2700 zone->setName("Unit test policy 0");
2701 zone->addNSTrigger(nsName, pol);
2702 auto luaconfsCopy = g_luaconfs.getCopy();
2703 luaconfsCopy.dfe.addZone(zone);
2704 g_luaconfs.setState(luaconfsCopy);
2705
2706 vector<DNSRecord> ret;
2707 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2708 BOOST_CHECK_EQUAL(res, -2);
2709 BOOST_CHECK_EQUAL(ret.size(), 0);
2710 }
2711
2712 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2713 std::unique_ptr<SyncRes> sr;
2714 initSR(sr);
2715
2716 primeHints();
2717
2718 const DNSName target("rpz.powerdns.com.");
2719 const ComboAddress ns("192.0.2.1:53");
2720 const DNSName nsName("ns1.powerdns.com.");
2721
2722 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2723
2724 if (isRootServer(ip)) {
2725 setLWResult(res, 0, false, false, true);
2726 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2727 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2728 return 1;
2729 } else if (ip == ns) {
2730
2731 setLWResult(res, 0, true, false, true);
2732 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2733 return 1;
2734 }
2735
2736 return 0;
2737 });
2738
2739 DNSFilterEngine::Policy pol;
2740 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2741 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2742 zone->setName("Unit test policy 0");
2743 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2744 zone->addNSTrigger(nsName, pol);
2745 auto luaconfsCopy = g_luaconfs.getCopy();
2746 luaconfsCopy.dfe.addZone(zone);
2747 g_luaconfs.setState(luaconfsCopy);
2748
2749 /* RPZ is disabled for this query, we should not be blocked */
2750 sr->setWantsRPZ(false);
2751
2752 vector<DNSRecord> ret;
2753 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2754 BOOST_CHECK_EQUAL(res, RCode::NoError);
2755 BOOST_CHECK_EQUAL(ret.size(), 1);
2756 }
2757
2758 BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2759 std::unique_ptr<SyncRes> sr;
2760 initSR(sr);
2761
2762 primeHints();
2763
2764 const DNSName target("powerdns.com.");
2765 const ComboAddress ns("192.0.2.1:53");
2766 const ComboAddress forwardedNS("192.0.2.42:53");
2767
2768 SyncRes::AuthDomain ad;
2769 ad.d_rdForward = false;
2770 ad.d_servers.push_back(forwardedNS);
2771 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2772
2773 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2774
2775 if (ip == forwardedNS) {
2776 BOOST_CHECK_EQUAL(sendRDQuery, false);
2777
2778 setLWResult(res, 0, true, false, true);
2779 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2780 return 1;
2781 }
2782
2783 return 0;
2784 });
2785
2786 /* simulate a no-RD query */
2787 sr->setCacheOnly();
2788
2789 vector<DNSRecord> ret;
2790 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2791 BOOST_CHECK_EQUAL(res, RCode::NoError);
2792 BOOST_CHECK_EQUAL(ret.size(), 1);
2793 }
2794
2795 BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
2796 std::unique_ptr<SyncRes> sr;
2797 initSR(sr);
2798
2799 primeHints();
2800
2801 const DNSName target("powerdns.com.");
2802 const ComboAddress ns("192.0.2.1:53");
2803 const ComboAddress forwardedNS("192.0.2.42:53");
2804
2805 size_t queriesCount = 0;
2806 SyncRes::AuthDomain ad;
2807 ad.d_rdForward = true;
2808 ad.d_servers.push_back(forwardedNS);
2809 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2810
2811 sr->setAsyncCallback([forwardedNS, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2812
2813 queriesCount++;
2814
2815 if (ip == forwardedNS) {
2816 BOOST_CHECK_EQUAL(sendRDQuery, true);
2817
2818 /* set AA=0, we are a recursor */
2819 setLWResult(res, 0, false, false, true);
2820 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2821 return 1;
2822 }
2823
2824 return 0;
2825 });
2826
2827 vector<DNSRecord> ret;
2828 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2829 BOOST_CHECK_EQUAL(res, RCode::NoError);
2830 BOOST_CHECK_EQUAL(ret.size(), 1);
2831 BOOST_CHECK_EQUAL(queriesCount, 1);
2832
2833 /* now make sure we can resolve from the cache (see #6340
2834 where the entries were added to the cache but not retrieved,
2835 because the recursor doesn't set the AA bit and we require
2836 it. We fixed it by not requiring the AA bit for forward-recurse
2837 answers. */
2838 ret.clear();
2839 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2840 BOOST_CHECK_EQUAL(res, RCode::NoError);
2841 BOOST_CHECK_EQUAL(ret.size(), 1);
2842 BOOST_CHECK_EQUAL(queriesCount, 1);
2843 }
2844
2845 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
2846 std::unique_ptr<SyncRes> sr;
2847 initSR(sr);
2848
2849 primeHints();
2850
2851 const DNSName target("powerdns.com.");
2852 const ComboAddress ns("192.0.2.1:53");
2853 const ComboAddress forwardedNS("192.0.2.42:53");
2854
2855 SyncRes::AuthDomain ad;
2856 ad.d_rdForward = true;
2857 ad.d_servers.push_back(forwardedNS);
2858 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2859
2860 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2861
2862 if (ip == forwardedNS) {
2863 BOOST_CHECK_EQUAL(sendRDQuery, false);
2864
2865 setLWResult(res, 0, true, false, true);
2866 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2867 return 1;
2868 }
2869
2870 return 0;
2871 });
2872
2873 /* simulate a no-RD query */
2874 sr->setCacheOnly();
2875
2876 vector<DNSRecord> ret;
2877 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2878 BOOST_CHECK_EQUAL(res, RCode::NoError);
2879 BOOST_CHECK_EQUAL(ret.size(), 1);
2880 }
2881
2882 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
2883 std::unique_ptr<SyncRes> sr;
2884 initSR(sr);
2885
2886 primeHints();
2887
2888 const DNSName target("powerdns.com.");
2889 const ComboAddress ns("192.0.2.1:53");
2890 const ComboAddress forwardedNS("192.0.2.42:53");
2891
2892 SyncRes::AuthDomain ad;
2893 ad.d_rdForward = true;
2894 ad.d_servers.push_back(forwardedNS);
2895 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2896
2897 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2898
2899 if (ip == forwardedNS) {
2900 BOOST_CHECK_EQUAL(sendRDQuery, true);
2901
2902 setLWResult(res, 0, true, false, true);
2903 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2904 return 1;
2905 }
2906
2907 return 0;
2908 });
2909
2910 vector<DNSRecord> ret;
2911 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2912 BOOST_CHECK_EQUAL(res, RCode::NoError);
2913 BOOST_CHECK_EQUAL(ret.size(), 1);
2914 }
2915
2916 BOOST_AUTO_TEST_CASE(test_auth_zone_oob) {
2917 std::unique_ptr<SyncRes> sr;
2918 initSR(sr, true);
2919
2920 primeHints();
2921
2922 size_t queriesCount = 0;
2923 const DNSName target("test.xx.");
2924 const ComboAddress targetAddr("127.0.0.1");
2925 const DNSName authZone("test.xx");
2926
2927 SyncRes::AuthDomain ad;
2928 DNSRecord dr;
2929
2930 dr.d_place = DNSResourceRecord::ANSWER;
2931 dr.d_name = target;
2932 dr.d_type = QType::A;
2933 dr.d_ttl = 1800;
2934 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
2935 ad.d_records.insert(dr);
2936
2937 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2938
2939 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2940 queriesCount++;
2941 return 0;
2942 });
2943
2944 vector<DNSRecord> ret;
2945 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2946 BOOST_CHECK_EQUAL(res, 0);
2947 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2948 BOOST_CHECK(ret[0].d_type == QType::A);
2949 BOOST_CHECK_EQUAL(queriesCount, 0);
2950 BOOST_CHECK(sr->wasOutOfBand());
2951 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2952
2953 /* a second time, to check that the OOB flag is set when the query cache is used */
2954 ret.clear();
2955 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2956 BOOST_CHECK_EQUAL(res, 0);
2957 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2958 BOOST_CHECK(ret[0].d_type == QType::A);
2959 BOOST_CHECK_EQUAL(queriesCount, 0);
2960 BOOST_CHECK(sr->wasOutOfBand());
2961 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2962
2963 /* a third time, to check that the validation is disabled when the OOB flag is set */
2964 ret.clear();
2965 sr->setDNSSECValidationRequested(true);
2966 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2967 BOOST_CHECK_EQUAL(res, 0);
2968 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2969 BOOST_CHECK(ret[0].d_type == QType::A);
2970 BOOST_CHECK_EQUAL(queriesCount, 0);
2971 BOOST_CHECK(sr->wasOutOfBand());
2972 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2973 }
2974
2975 BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) {
2976 std::unique_ptr<SyncRes> sr;
2977 initSR(sr, true);
2978
2979 primeHints();
2980
2981 size_t queriesCount = 0;
2982 const DNSName target("cname.test.xx.");
2983 const DNSName targetCname("cname-target.test.xx.");
2984 const ComboAddress targetCnameAddr("127.0.0.1");
2985 const DNSName authZone("test.xx");
2986
2987 SyncRes::AuthDomain ad;
2988 DNSRecord dr;
2989
2990 dr.d_place = DNSResourceRecord::ANSWER;
2991 dr.d_name = target;
2992 dr.d_type = QType::CNAME;
2993 dr.d_ttl = 1800;
2994 dr.d_content = std::make_shared<CNAMERecordContent>(targetCname);
2995 ad.d_records.insert(dr);
2996
2997 dr.d_place = DNSResourceRecord::ANSWER;
2998 dr.d_name = targetCname;
2999 dr.d_type = QType::A;
3000 dr.d_ttl = 1800;
3001 dr.d_content = std::make_shared<ARecordContent>(targetCnameAddr);
3002 ad.d_records.insert(dr);
3003
3004 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
3005
3006 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3007 queriesCount++;
3008 return 0;
3009 });
3010
3011 vector<DNSRecord> ret;
3012 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3013 BOOST_CHECK_EQUAL(res, 0);
3014 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3015 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3016 BOOST_CHECK(ret[1].d_type == QType::A);
3017 BOOST_CHECK_EQUAL(queriesCount, 0);
3018 BOOST_CHECK(sr->wasOutOfBand());
3019 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3020
3021 /* a second time, to check that the OOB flag is set when the query cache is used */
3022 ret.clear();
3023 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3024 BOOST_CHECK_EQUAL(res, 0);
3025 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3026 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3027 BOOST_CHECK(ret[1].d_type == QType::A);
3028 BOOST_CHECK_EQUAL(queriesCount, 0);
3029 BOOST_CHECK(sr->wasOutOfBand());
3030 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3031
3032 /* a third time, to check that the validation is disabled when the OOB flag is set */
3033 ret.clear();
3034 sr->setDNSSECValidationRequested(true);
3035 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3036 BOOST_CHECK_EQUAL(res, 0);
3037 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3038 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3039 BOOST_CHECK(ret[1].d_type == QType::A);
3040 BOOST_CHECK_EQUAL(queriesCount, 0);
3041 BOOST_CHECK(sr->wasOutOfBand());
3042 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3043 }
3044
3045 BOOST_AUTO_TEST_CASE(test_auth_zone) {
3046 std::unique_ptr<SyncRes> sr;
3047 initSR(sr);
3048
3049 primeHints();
3050
3051 size_t queriesCount = 0;
3052 const DNSName target("powerdns.com.");
3053 const ComboAddress addr("192.0.2.5");
3054
3055 SyncRes::AuthDomain ad;
3056 ad.d_name = target;
3057 DNSRecord dr;
3058 dr.d_place = DNSResourceRecord::ANSWER;
3059 dr.d_name = target;
3060 dr.d_type = QType::SOA;
3061 dr.d_ttl = 3600;
3062 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3063 ad.d_records.insert(dr);
3064
3065 dr.d_place = DNSResourceRecord::ANSWER;
3066 dr.d_name = target;
3067 dr.d_type = QType::A;
3068 dr.d_ttl = 3600;
3069 dr.d_content = std::make_shared<ARecordContent>(addr);
3070 ad.d_records.insert(dr);
3071
3072 auto map = std::make_shared<SyncRes::domainmap_t>();
3073 (*map)[target] = ad;
3074 SyncRes::setDomainMap(map);
3075
3076 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3077
3078 queriesCount++;
3079 setLWResult(res, 0, true, false, true);
3080 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3081 return 1;
3082 });
3083
3084 vector<DNSRecord> ret;
3085 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3086 BOOST_CHECK_EQUAL(res, RCode::NoError);
3087 BOOST_CHECK_EQUAL(ret.size(), 1);
3088 BOOST_CHECK(ret[0].d_type == QType::A);
3089 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3090 BOOST_CHECK_EQUAL(queriesCount, 0);
3091 }
3092
3093 BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
3094 std::unique_ptr<SyncRes> sr;
3095 initSR(sr);
3096
3097 primeHints();
3098
3099 size_t queriesCount = 0;
3100 const DNSName target("powerdns.com.");
3101 const DNSName authZone("internal.powerdns.com.");
3102 const ComboAddress addr("192.0.2.5");
3103
3104 SyncRes::AuthDomain ad;
3105 ad.d_name = authZone;
3106 DNSRecord dr;
3107 dr.d_place = DNSResourceRecord::ANSWER;
3108 dr.d_name = authZone;
3109 dr.d_type = QType::SOA;
3110 dr.d_ttl = 3600;
3111 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3112 ad.d_records.insert(dr);
3113
3114 dr.d_place = DNSResourceRecord::ANSWER;
3115 dr.d_name = authZone;
3116 dr.d_type = QType::A;
3117 dr.d_ttl = 3600;
3118 dr.d_content = std::make_shared<ARecordContent>(addr);
3119 ad.d_records.insert(dr);
3120
3121 auto map = std::make_shared<SyncRes::domainmap_t>();
3122 (*map)[authZone] = ad;
3123 SyncRes::setDomainMap(map);
3124
3125 sr->setAsyncCallback([&queriesCount,target,authZone](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3126
3127 queriesCount++;
3128
3129 if (domain == target) {
3130 setLWResult(res, 0, true, false, true);
3131 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
3132 return 1;
3133 }
3134
3135 return 0;
3136 });
3137
3138 vector<DNSRecord> ret;
3139 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3140 BOOST_CHECK_EQUAL(res, RCode::NoError);
3141 BOOST_CHECK_EQUAL(ret.size(), 2);
3142 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3143 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
3144 BOOST_CHECK(ret[1].d_type == QType::A);
3145 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3146 BOOST_CHECK_EQUAL(queriesCount, 1);
3147 }
3148
3149 BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
3150 std::unique_ptr<SyncRes> sr;
3151 initSR(sr);
3152
3153 primeHints();
3154
3155 size_t queriesCount = 0;
3156 const DNSName target("powerdns.com.");
3157 const DNSName externalCNAME("www.open-xchange.com.");
3158 const ComboAddress addr("192.0.2.5");
3159
3160 SyncRes::AuthDomain ad;
3161 ad.d_name = target;
3162 DNSRecord dr;
3163 dr.d_place = DNSResourceRecord::ANSWER;
3164 dr.d_name = target;
3165 dr.d_type = QType::SOA;
3166 dr.d_ttl = 3600;
3167 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3168 ad.d_records.insert(dr);
3169
3170 dr.d_place = DNSResourceRecord::ANSWER;
3171 dr.d_name = target;
3172 dr.d_type = QType::CNAME;
3173 dr.d_ttl = 3600;
3174 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
3175 ad.d_records.insert(dr);
3176
3177 auto map = std::make_shared<SyncRes::domainmap_t>();
3178 (*map)[target] = ad;
3179 SyncRes::setDomainMap(map);
3180
3181 sr->setAsyncCallback([&queriesCount,externalCNAME,addr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3182
3183 queriesCount++;
3184
3185 if (domain == externalCNAME) {
3186 setLWResult(res, 0, true, false, true);
3187 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
3188 return 1;
3189 }
3190
3191 return 0;
3192 });
3193
3194 vector<DNSRecord> ret;
3195 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3196 BOOST_CHECK_EQUAL(res, RCode::NoError);
3197 BOOST_CHECK_EQUAL(ret.size(), 2);
3198 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3199 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
3200 BOOST_CHECK(ret[1].d_type == QType::A);
3201 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3202 BOOST_CHECK_EQUAL(queriesCount, 1);
3203 }
3204
3205 BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
3206 std::unique_ptr<SyncRes> sr;
3207 initSR(sr);
3208
3209 primeHints();
3210
3211 size_t queriesCount = 0;
3212 const DNSName target("nodata.powerdns.com.");
3213 const DNSName authZone("powerdns.com");
3214
3215 SyncRes::AuthDomain ad;
3216 ad.d_name = authZone;
3217 DNSRecord dr;
3218 dr.d_place = DNSResourceRecord::ANSWER;
3219 dr.d_name = target;
3220 dr.d_type = QType::A;
3221 dr.d_ttl = 3600;
3222 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3223 ad.d_records.insert(dr);
3224
3225 dr.d_place = DNSResourceRecord::ANSWER;
3226 dr.d_name = authZone;
3227 dr.d_type = QType::SOA;
3228 dr.d_ttl = 3600;
3229 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3230 ad.d_records.insert(dr);
3231
3232 auto map = std::make_shared<SyncRes::domainmap_t>();
3233 (*map)[authZone] = ad;
3234 SyncRes::setDomainMap(map);
3235
3236 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3237
3238 queriesCount++;
3239
3240 return 0;
3241 });
3242
3243 vector<DNSRecord> ret;
3244 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
3245 BOOST_CHECK_EQUAL(res, RCode::NoError);
3246 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3247 BOOST_CHECK(ret[0].d_type == QType::SOA);
3248 BOOST_CHECK_EQUAL(queriesCount, 0);
3249 }
3250
3251 BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3252 std::unique_ptr<SyncRes> sr;
3253 initSR(sr);
3254
3255 primeHints();
3256
3257 size_t queriesCount = 0;
3258 const DNSName target("nx.powerdns.com.");
3259 const DNSName authZone("powerdns.com");
3260
3261 SyncRes::AuthDomain ad;
3262 ad.d_name = authZone;
3263 DNSRecord dr;
3264 dr.d_place = DNSResourceRecord::ANSWER;
3265 dr.d_name = DNSName("powerdns.com.");
3266 dr.d_type = QType::SOA;
3267 dr.d_ttl = 3600;
3268 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3269 ad.d_records.insert(dr);
3270
3271 auto map = std::make_shared<SyncRes::domainmap_t>();
3272 (*map)[authZone] = ad;
3273 SyncRes::setDomainMap(map);
3274
3275 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3276
3277 queriesCount++;
3278
3279 return 0;
3280 });
3281
3282 vector<DNSRecord> ret;
3283 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3284 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3285 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3286 BOOST_CHECK(ret[0].d_type == QType::SOA);
3287 BOOST_CHECK_EQUAL(queriesCount, 0);
3288 }
3289
3290 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3291 std::unique_ptr<SyncRes> sr;
3292 initSR(sr, true, false);
3293
3294 primeHints();
3295
3296 size_t queriesCount = 0;
3297 const DNSName target("www.test.powerdns.com.");
3298 const ComboAddress targetAddr("192.0.2.2");
3299 const DNSName ns("ns1.test.powerdns.com.");
3300 const ComboAddress nsAddr("192.0.2.1");
3301 const DNSName authZone("powerdns.com");
3302
3303 SyncRes::AuthDomain ad;
3304 ad.d_name = authZone;
3305 DNSRecord dr;
3306 dr.d_place = DNSResourceRecord::ANSWER;
3307 dr.d_name = authZone;
3308 dr.d_type = QType::SOA;
3309 dr.d_ttl = 3600;
3310 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3311 ad.d_records.insert(dr);
3312
3313 dr.d_place = DNSResourceRecord::ANSWER;
3314 dr.d_name = DNSName("test.powerdns.com.");
3315 dr.d_type = QType::NS;
3316 dr.d_ttl = 3600;
3317 dr.d_content = std::make_shared<NSRecordContent>(ns);
3318 ad.d_records.insert(dr);
3319
3320 dr.d_place = DNSResourceRecord::ANSWER;
3321 dr.d_name = ns;
3322 dr.d_type = QType::A;
3323 dr.d_ttl = 3600;
3324 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3325 ad.d_records.insert(dr);
3326
3327 auto map = std::make_shared<SyncRes::domainmap_t>();
3328 (*map)[authZone] = ad;
3329 SyncRes::setDomainMap(map);
3330
3331 testkeysset_t keys;
3332 auto luaconfsCopy = g_luaconfs.getCopy();
3333 luaconfsCopy.dsAnchors.clear();
3334 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3335 g_luaconfs.setState(luaconfsCopy);
3336
3337 sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr,authZone,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3338
3339 queriesCount++;
3340 if (type == QType::DS || type == QType::DNSKEY) {
3341 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone);
3342 }
3343
3344 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3345 setLWResult(res, 0, true, false, true);
3346 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3347 return 1;
3348 }
3349
3350 return 0;
3351 });
3352
3353 sr->setDNSSECValidationRequested(true);
3354 vector<DNSRecord> ret;
3355 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3356 BOOST_CHECK_EQUAL(res, RCode::NoError);
3357 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3358 BOOST_CHECK(ret[0].d_type == QType::A);
3359 BOOST_CHECK_EQUAL(queriesCount, 4);
3360 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3361 }
3362
3363 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3364 std::unique_ptr<SyncRes> sr;
3365 initSR(sr);
3366
3367 primeHints();
3368
3369 size_t queriesCount = 0;
3370 const DNSName target("test.powerdns.com.");
3371 const ComboAddress targetAddr("192.0.2.2");
3372 const DNSName ns("ns1.test.powerdns.com.");
3373 const ComboAddress nsAddr("192.0.2.1");
3374 const DNSName authZone("powerdns.com");
3375
3376 SyncRes::AuthDomain ad;
3377 ad.d_name = authZone;
3378 DNSRecord dr;
3379 dr.d_place = DNSResourceRecord::ANSWER;
3380 dr.d_name = authZone;
3381 dr.d_type = QType::SOA;
3382 dr.d_ttl = 3600;
3383 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3384 ad.d_records.insert(dr);
3385
3386 dr.d_place = DNSResourceRecord::ANSWER;
3387 dr.d_name = DNSName("test.powerdns.com.");
3388 dr.d_type = QType::NS;
3389 dr.d_ttl = 3600;
3390 dr.d_content = std::make_shared<NSRecordContent>(ns);
3391 ad.d_records.insert(dr);
3392
3393 dr.d_place = DNSResourceRecord::ANSWER;
3394 dr.d_name = ns;
3395 dr.d_type = QType::A;
3396 dr.d_ttl = 3600;
3397 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3398 ad.d_records.insert(dr);
3399
3400 auto map = std::make_shared<SyncRes::domainmap_t>();
3401 (*map)[authZone] = ad;
3402 SyncRes::setDomainMap(map);
3403
3404 sr->setAsyncCallback([&queriesCount,nsAddr,target,targetAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3405
3406 queriesCount++;
3407
3408 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3409 setLWResult(res, 0, true, false, true);
3410 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3411 return 1;
3412 }
3413
3414 return 0;
3415 });
3416
3417 vector<DNSRecord> ret;
3418 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3419 BOOST_CHECK_EQUAL(res, RCode::NoError);
3420 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3421 BOOST_CHECK(ret[0].d_type == QType::A);
3422 BOOST_CHECK_EQUAL(queriesCount, 1);
3423 }
3424
3425 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3426 std::unique_ptr<SyncRes> sr;
3427 initSR(sr);
3428
3429 primeHints();
3430
3431 size_t queriesCount = 0;
3432 const DNSName target("test.powerdns.com.");
3433 const ComboAddress targetAddr("192.0.2.2");
3434 const DNSName authZone("powerdns.com");
3435
3436 SyncRes::AuthDomain ad;
3437 ad.d_name = authZone;
3438 DNSRecord dr;
3439 dr.d_place = DNSResourceRecord::ANSWER;
3440 dr.d_name = authZone;
3441 dr.d_type = QType::SOA;
3442 dr.d_ttl = 3600;
3443 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3444 ad.d_records.insert(dr);
3445
3446 dr.d_place = DNSResourceRecord::ANSWER;
3447 dr.d_name = DNSName("*.powerdns.com.");
3448 dr.d_type = QType::A;
3449 dr.d_ttl = 3600;
3450 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3451 ad.d_records.insert(dr);
3452
3453 auto map = std::make_shared<SyncRes::domainmap_t>();
3454 (*map)[authZone] = ad;
3455 SyncRes::setDomainMap(map);
3456
3457 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3458
3459 queriesCount++;
3460
3461 return 0;
3462 });
3463
3464 vector<DNSRecord> ret;
3465 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3466 BOOST_CHECK_EQUAL(res, RCode::NoError);
3467 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3468 BOOST_CHECK(ret[0].d_type == QType::A);
3469 BOOST_CHECK_EQUAL(queriesCount, 0);
3470 }
3471
3472 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3473 std::unique_ptr<SyncRes> sr;
3474 initSR(sr);
3475
3476 primeHints();
3477
3478 size_t queriesCount = 0;
3479 const DNSName target("test.powerdns.com.");
3480 const ComboAddress targetAddr("192.0.2.2");
3481 const DNSName authZone("powerdns.com");
3482
3483 SyncRes::AuthDomain ad;
3484 ad.d_name = authZone;
3485 DNSRecord dr;
3486 dr.d_place = DNSResourceRecord::ANSWER;
3487 dr.d_name = authZone;
3488 dr.d_type = QType::SOA;
3489 dr.d_ttl = 3600;
3490 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3491 ad.d_records.insert(dr);
3492
3493 dr.d_place = DNSResourceRecord::ANSWER;
3494 dr.d_name = DNSName("*.powerdns.com.");
3495 dr.d_type = QType::A;
3496 dr.d_ttl = 3600;
3497 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3498 ad.d_records.insert(dr);
3499
3500 auto map = std::make_shared<SyncRes::domainmap_t>();
3501 (*map)[authZone] = ad;
3502 SyncRes::setDomainMap(map);
3503
3504 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3505
3506 queriesCount++;
3507
3508 return 0;
3509 });
3510
3511 vector<DNSRecord> ret;
3512 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
3513 BOOST_CHECK_EQUAL(res, RCode::NoError);
3514 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3515 BOOST_CHECK(ret[0].d_type == QType::SOA);
3516 BOOST_CHECK_EQUAL(queriesCount, 0);
3517 }
3518
3519 BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3520 std::unique_ptr<SyncRes> sr;
3521 initSR(sr);
3522
3523 primeHints();
3524
3525 size_t queriesCount = 0;
3526 const DNSName target("powerdns.com.");
3527 const ComboAddress addr("192.0.2.5");
3528
3529 SyncRes::AuthDomain ad;
3530 ad.d_name = target;
3531 DNSRecord dr;
3532 dr.d_place = DNSResourceRecord::ANSWER;
3533 dr.d_name = target;
3534 dr.d_type = QType::SOA;
3535 dr.d_ttl = 3600;
3536 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3537 ad.d_records.insert(dr);
3538
3539 dr.d_place = DNSResourceRecord::ANSWER;
3540 dr.d_name = target;
3541 dr.d_type = QType::A;
3542 dr.d_ttl = 3600;
3543 dr.d_content = std::make_shared<ARecordContent>(addr);
3544 ad.d_records.insert(dr);
3545
3546 auto map = std::make_shared<SyncRes::domainmap_t>();
3547 (*map)[target] = ad;
3548 SyncRes::setDomainMap(map);
3549
3550 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3551
3552 queriesCount++;
3553 setLWResult(res, 0, true, false, true);
3554 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3555 return 1;
3556 });
3557
3558 /* simulate a no-RD query */
3559 sr->setCacheOnly();
3560
3561 vector<DNSRecord> ret;
3562 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3563 BOOST_CHECK_EQUAL(res, RCode::NoError);
3564 BOOST_CHECK_EQUAL(ret.size(), 1);
3565 BOOST_CHECK(ret[0].d_type == QType::A);
3566 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3567 BOOST_CHECK_EQUAL(queriesCount, 0);
3568 }
3569
3570 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
3571 init();
3572
3573 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3574 dcke->create(dcke->getBits());
3575 // cerr<<dcke->convertToISC()<<endl;
3576 DNSSECPrivateKey dpk;
3577 dpk.d_flags = 256;
3578 dpk.setKey(dcke);
3579
3580 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3581 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3582
3583 DNSName qname("powerdns.com.");
3584
3585 time_t now = time(nullptr);
3586 RRSIGRecordContent rrc;
3587 /* this RRSIG is valid for the current second only */
3588 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
3589
3590 skeyset_t keyset;
3591 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3592
3593 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3594 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3595
3596 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
3597 }
3598
3599 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3600 std::unique_ptr<SyncRes> sr;
3601 initSR(sr, true);
3602
3603 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3604
3605 primeHints();
3606 const DNSName target(".");
3607 testkeysset_t keys;
3608
3609 auto luaconfsCopy = g_luaconfs.getCopy();
3610 luaconfsCopy.dsAnchors.clear();
3611 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3612 g_luaconfs.setState(luaconfsCopy);
3613
3614 size_t queriesCount = 0;
3615
3616 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3617 queriesCount++;
3618
3619 if (domain == target && type == QType::NS) {
3620
3621 setLWResult(res, 0, true, false, true);
3622 char addr[] = "a.root-servers.net.";
3623 for (char idx = 'a'; idx <= 'm'; idx++) {
3624 addr[0] = idx;
3625 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3626 }
3627
3628 addRRSIG(keys, res->d_records, domain, 300);
3629
3630 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3631 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3632
3633 return 1;
3634 } else if (domain == target && type == QType::DNSKEY) {
3635
3636 setLWResult(res, 0, true, false, true);
3637
3638 addDNSKEY(keys, domain, 300, res->d_records);
3639 addRRSIG(keys, res->d_records, domain, 300);
3640
3641 return 1;
3642 }
3643
3644 return 0;
3645 });
3646
3647 vector<DNSRecord> ret;
3648 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3649 BOOST_CHECK_EQUAL(res, RCode::NoError);
3650 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3651 /* 13 NS + 1 RRSIG */
3652 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3653 BOOST_CHECK_EQUAL(queriesCount, 2);
3654
3655 /* again, to test the cache */
3656 ret.clear();
3657 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3658 BOOST_CHECK_EQUAL(res, RCode::NoError);
3659 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3660 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3661 BOOST_CHECK_EQUAL(queriesCount, 2);
3662 }
3663
3664 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3665 std::unique_ptr<SyncRes> sr;
3666 initSR(sr, true);
3667
3668 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3669
3670 primeHints();
3671 const DNSName target(".");
3672 testkeysset_t zskeys;
3673 testkeysset_t kskeys;
3674
3675 /* Generate key material for "." */
3676 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3677 dckeZ->create(dckeZ->getBits());
3678 DNSSECPrivateKey ksk;
3679 ksk.d_flags = 257;
3680 ksk.setKey(dckeZ);
3681 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3682
3683 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3684 dckeK->create(dckeK->getBits());
3685 DNSSECPrivateKey zsk;
3686 zsk.d_flags = 256;
3687 zsk.setKey(dckeK);
3688 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
3689
3690 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3691 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
3692
3693 /* Set the root DS */
3694 auto luaconfsCopy = g_luaconfs.getCopy();
3695 luaconfsCopy.dsAnchors.clear();
3696 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
3697 g_luaconfs.setState(luaconfsCopy);
3698
3699 size_t queriesCount = 0;
3700
3701 sr->setAsyncCallback([target,&queriesCount,zskeys,kskeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3702 queriesCount++;
3703
3704 if (domain == target && type == QType::NS) {
3705
3706 setLWResult(res, 0, true, false, true);
3707 char addr[] = "a.root-servers.net.";
3708 for (char idx = 'a'; idx <= 'm'; idx++) {
3709 addr[0] = idx;
3710 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3711 }
3712
3713 addRRSIG(zskeys, res->d_records, domain, 300);
3714
3715 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3716 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3717
3718 return 1;
3719 } else if (domain == target && type == QType::DNSKEY) {
3720
3721 setLWResult(res, 0, true, false, true);
3722
3723 addDNSKEY(kskeys, domain, 300, res->d_records);
3724 addDNSKEY(zskeys, domain, 300, res->d_records);
3725 addRRSIG(kskeys, res->d_records, domain, 300);
3726
3727 return 1;
3728 }
3729
3730 return 0;
3731 });
3732
3733 vector<DNSRecord> ret;
3734 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3735 BOOST_CHECK_EQUAL(res, RCode::NoError);
3736 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3737 /* 13 NS + 1 RRSIG */
3738 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3739 BOOST_CHECK_EQUAL(queriesCount, 2);
3740
3741 /* again, to test the cache */
3742 ret.clear();
3743 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3744 BOOST_CHECK_EQUAL(res, RCode::NoError);
3745 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3746 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3747 BOOST_CHECK_EQUAL(queriesCount, 2);
3748 }
3749
3750 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
3751 std::unique_ptr<SyncRes> sr;
3752 initSR(sr, true);
3753
3754 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3755
3756 primeHints();
3757 const DNSName target(".");
3758 testkeysset_t keys;
3759
3760 auto luaconfsCopy = g_luaconfs.getCopy();
3761 luaconfsCopy.dsAnchors.clear();
3762 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3763 g_luaconfs.setState(luaconfsCopy);
3764
3765 size_t queriesCount = 0;
3766
3767 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3768 queriesCount++;
3769
3770 if (domain == target && type == QType::NS) {
3771
3772 setLWResult(res, 0, true, false, true);
3773 char addr[] = "a.root-servers.net.";
3774 for (char idx = 'a'; idx <= 'm'; idx++) {
3775 addr[0] = idx;
3776 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3777 }
3778
3779 addRRSIG(keys, res->d_records, domain, 300);
3780
3781 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3782 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3783
3784 return 1;
3785 } else if (domain == target && type == QType::DNSKEY) {
3786
3787 setLWResult(res, 0, true, false, true);
3788
3789 /* No DNSKEY */
3790
3791 return 1;
3792 }
3793
3794 return 0;
3795 });
3796
3797 vector<DNSRecord> ret;
3798 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3799 BOOST_CHECK_EQUAL(res, RCode::NoError);
3800 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3801 /* 13 NS + 1 RRSIG */
3802 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3803 BOOST_CHECK_EQUAL(queriesCount, 2);
3804
3805 /* again, to test the cache */
3806 ret.clear();
3807 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3808 BOOST_CHECK_EQUAL(res, RCode::NoError);
3809 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3810 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3811 BOOST_CHECK_EQUAL(queriesCount, 2);
3812 }
3813
3814 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3815 std::unique_ptr<SyncRes> sr;
3816 initSR(sr, true);
3817
3818 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3819
3820 primeHints();
3821 const DNSName target(".");
3822 testkeysset_t dskeys;
3823 testkeysset_t keys;
3824
3825 /* Generate key material for "." */
3826 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3827 dckeDS->create(dckeDS->getBits());
3828 DNSSECPrivateKey dskey;
3829 dskey.d_flags = 257;
3830 dskey.setKey(dckeDS);
3831 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3832
3833 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3834 dcke->create(dcke->getBits());
3835 DNSSECPrivateKey dpk;
3836 dpk.d_flags = 256;
3837 dpk.setKey(dcke);
3838 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3839
3840 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3841 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
3842
3843 /* Set the root DS */
3844 auto luaconfsCopy = g_luaconfs.getCopy();
3845 luaconfsCopy.dsAnchors.clear();
3846 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3847 g_luaconfs.setState(luaconfsCopy);
3848
3849 size_t queriesCount = 0;
3850
3851 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3852 queriesCount++;
3853
3854 if (domain == target && type == QType::NS) {
3855
3856 setLWResult(res, 0, true, false, true);
3857 char addr[] = "a.root-servers.net.";
3858 for (char idx = 'a'; idx <= 'm'; idx++) {
3859 addr[0] = idx;
3860 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3861 }
3862
3863 addRRSIG(keys, res->d_records, domain, 300);
3864
3865 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3866 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3867
3868 return 1;
3869 } else if (domain == target && type == QType::DNSKEY) {
3870
3871 setLWResult(res, 0, true, false, true);
3872
3873 addDNSKEY(keys, domain, 300, res->d_records);
3874 addRRSIG(keys, res->d_records, domain, 300);
3875
3876 return 1;
3877 }
3878
3879 return 0;
3880 });
3881
3882 vector<DNSRecord> ret;
3883 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3884 BOOST_CHECK_EQUAL(res, RCode::NoError);
3885 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3886 /* 13 NS + 1 RRSIG */
3887 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3888 BOOST_CHECK_EQUAL(queriesCount, 2);
3889
3890 /* again, to test the cache */
3891 ret.clear();
3892 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3893 BOOST_CHECK_EQUAL(res, RCode::NoError);
3894 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3895 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3896 BOOST_CHECK_EQUAL(queriesCount, 2);
3897 }
3898
3899 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
3900 std::unique_ptr<SyncRes> sr;
3901 initSR(sr, true);
3902
3903 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3904
3905 primeHints();
3906 const DNSName target(".");
3907 testkeysset_t keys;
3908 testkeysset_t rrsigkeys;
3909
3910 auto luaconfsCopy = g_luaconfs.getCopy();
3911 luaconfsCopy.dsAnchors.clear();
3912 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3913 g_luaconfs.setState(luaconfsCopy);
3914
3915 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3916 dckeRRSIG->create(dckeRRSIG->getBits());
3917 DNSSECPrivateKey rrsigkey;
3918 rrsigkey.d_flags = 257;
3919 rrsigkey.setKey(dckeRRSIG);
3920 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
3921
3922 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
3923
3924 size_t queriesCount = 0;
3925
3926 sr->setAsyncCallback([target,&queriesCount,keys,rrsigkeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3927 queriesCount++;
3928
3929 if (domain == target && type == QType::NS) {
3930
3931 setLWResult(res, 0, true, false, true);
3932 char addr[] = "a.root-servers.net.";
3933 for (char idx = 'a'; idx <= 'm'; idx++) {
3934 addr[0] = idx;
3935 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3936 }
3937
3938 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3939
3940 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3941 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3942
3943 return 1;
3944 } else if (domain == target && type == QType::DNSKEY) {
3945
3946 setLWResult(res, 0, true, false, true);
3947
3948 addDNSKEY(keys, domain, 300, res->d_records);
3949 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3950
3951 return 1;
3952 }
3953
3954 return 0;
3955 });
3956
3957 vector<DNSRecord> ret;
3958 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3959 BOOST_CHECK_EQUAL(res, RCode::NoError);
3960 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3961 /* 13 NS + 1 RRSIG */
3962 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3963 BOOST_CHECK_EQUAL(queriesCount, 2);
3964
3965 /* again, to test the cache */
3966 ret.clear();
3967 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3968 BOOST_CHECK_EQUAL(res, RCode::NoError);
3969 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3970 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3971 BOOST_CHECK_EQUAL(queriesCount, 2);
3972 }
3973
3974 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
3975 std::unique_ptr<SyncRes> sr;
3976 initSR(sr, true);
3977
3978 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3979
3980 primeHints();
3981 const DNSName target(".");
3982 testkeysset_t keys;
3983
3984 auto luaconfsCopy = g_luaconfs.getCopy();
3985 luaconfsCopy.dsAnchors.clear();
3986 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3987 g_luaconfs.setState(luaconfsCopy);
3988
3989 size_t queriesCount = 0;
3990
3991 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3992 queriesCount++;
3993
3994 if (domain == target && type == QType::NS) {
3995
3996 setLWResult(res, 0, true, false, true);
3997 char addr[] = "a.root-servers.net.";
3998 for (char idx = 'a'; idx <= 'm'; idx++) {
3999 addr[0] = idx;
4000 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4001 }
4002
4003 /* No RRSIG */
4004
4005 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4006 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4007
4008 return 1;
4009 } else if (domain == target && type == QType::DNSKEY) {
4010
4011 setLWResult(res, 0, true, false, true);
4012
4013 addDNSKEY(keys, domain, 300, res->d_records);
4014 addRRSIG(keys, res->d_records, domain, 300);
4015
4016 return 1;
4017 }
4018
4019 return 0;
4020 });
4021
4022 vector<DNSRecord> ret;
4023 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4024 BOOST_CHECK_EQUAL(res, RCode::NoError);
4025 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4026 /* 13 NS + 0 RRSIG */
4027 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4028 /* no RRSIG so no query for DNSKEYs */
4029 BOOST_CHECK_EQUAL(queriesCount, 1);
4030
4031 /* again, to test the cache */
4032 ret.clear();
4033 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4034 BOOST_CHECK_EQUAL(res, RCode::NoError);
4035 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4036 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4037 BOOST_CHECK_EQUAL(queriesCount, 1);
4038 }
4039
4040 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
4041 std::unique_ptr<SyncRes> sr;
4042 initSR(sr, true);
4043
4044 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4045
4046 primeHints();
4047 const DNSName target(".");
4048 testkeysset_t keys;
4049
4050 /* Generate key material for "." */
4051 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4052 dcke->create(dcke->getBits());
4053 DNSSECPrivateKey dpk;
4054 dpk.d_flags = 256;
4055 dpk.setKey(dcke);
4056 /* Fake algorithm number (private) */
4057 dpk.d_algorithm = 253;
4058
4059 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
4060 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
4061 /* Fake algorithm number (private) */
4062 drc.d_algorithm = 253;
4063
4064 /* Set the root DS */
4065 auto luaconfsCopy = g_luaconfs.getCopy();
4066 luaconfsCopy.dsAnchors.clear();
4067 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4068 g_luaconfs.setState(luaconfsCopy);
4069
4070 size_t queriesCount = 0;
4071
4072 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4073 queriesCount++;
4074
4075 if (domain == target && type == QType::NS) {
4076
4077 setLWResult(res, 0, true, false, true);
4078 char addr[] = "a.root-servers.net.";
4079 for (char idx = 'a'; idx <= 'm'; idx++) {
4080 addr[0] = idx;
4081 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4082 }
4083
4084 addRRSIG(keys, res->d_records, domain, 300);
4085
4086 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4087 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4088
4089 return 1;
4090 } else if (domain == target && type == QType::DNSKEY) {
4091
4092 setLWResult(res, 0, true, false, true);
4093
4094 addDNSKEY(keys, domain, 300, res->d_records);
4095 addRRSIG(keys, res->d_records, domain, 300);
4096
4097 return 1;
4098 }
4099
4100 return 0;
4101 });
4102
4103 vector<DNSRecord> ret;
4104 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4105 BOOST_CHECK_EQUAL(res, RCode::NoError);
4106 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4107 /* 13 NS + 1 RRSIG */
4108 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4109 /* no supported DS so no query for DNSKEYs */
4110 BOOST_CHECK_EQUAL(queriesCount, 1);
4111
4112 /* again, to test the cache */
4113 ret.clear();
4114 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4115 BOOST_CHECK_EQUAL(res, RCode::NoError);
4116 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4117 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4118 BOOST_CHECK_EQUAL(queriesCount, 1);
4119 }
4120
4121 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
4122 std::unique_ptr<SyncRes> sr;
4123 initSR(sr, true);
4124
4125 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4126
4127 primeHints();
4128 const DNSName target(".");
4129 testkeysset_t keys;
4130
4131 /* Generate key material for "." */
4132 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4133 dcke->create(dcke->getBits());
4134 DNSSECPrivateKey dpk;
4135 dpk.d_flags = 256;
4136 dpk.setKey(dcke);
4137 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
4138 /* Fake digest number (reserved) */
4139 drc.d_digesttype = 0;
4140
4141 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
4142
4143 /* Set the root DS */
4144 auto luaconfsCopy = g_luaconfs.getCopy();
4145 luaconfsCopy.dsAnchors.clear();
4146 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4147 g_luaconfs.setState(luaconfsCopy);
4148
4149 size_t queriesCount = 0;
4150
4151 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4152 queriesCount++;
4153
4154 if (domain == target && type == QType::NS) {
4155
4156 setLWResult(res, 0, true, false, true);
4157 char addr[] = "a.root-servers.net.";
4158 for (char idx = 'a'; idx <= 'm'; idx++) {
4159 addr[0] = idx;
4160 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4161 }
4162
4163 addRRSIG(keys, res->d_records, domain, 300);
4164
4165 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4166 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4167
4168 return 1;
4169 } else if (domain == target && type == QType::DNSKEY) {
4170
4171 setLWResult(res, 0, true, false, true);
4172
4173 addDNSKEY(keys, domain, 300, res->d_records);
4174 addRRSIG(keys, res->d_records, domain, 300);
4175
4176 return 1;
4177 }
4178
4179 return 0;
4180 });
4181
4182 vector<DNSRecord> ret;
4183 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4184 BOOST_CHECK_EQUAL(res, RCode::NoError);
4185 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4186 /* 13 NS + 1 RRSIG */
4187 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4188 /* no supported DS so no query for DNSKEYs */
4189 BOOST_CHECK_EQUAL(queriesCount, 1);
4190
4191 /* again, to test the cache */
4192 ret.clear();
4193 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4194 BOOST_CHECK_EQUAL(res, RCode::NoError);
4195 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4196 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4197 BOOST_CHECK_EQUAL(queriesCount, 1);
4198 }
4199
4200 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
4201 std::unique_ptr<SyncRes> sr;
4202 initSR(sr, true);
4203
4204 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4205
4206 primeHints();
4207 const DNSName target(".");
4208 testkeysset_t keys;
4209
4210 auto luaconfsCopy = g_luaconfs.getCopy();
4211 luaconfsCopy.dsAnchors.clear();
4212 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4213
4214 g_luaconfs.setState(luaconfsCopy);
4215
4216 size_t queriesCount = 0;
4217
4218 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4219 queriesCount++;
4220
4221 if (domain == target && type == QType::NS) {
4222
4223 setLWResult(res, 0, true, false, true);
4224 char addr[] = "a.root-servers.net.";
4225 for (char idx = 'a'; idx <= 'm'; idx++) {
4226 addr[0] = idx;
4227 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4228 }
4229
4230 addRRSIG(keys, res->d_records, domain, 300, true);
4231
4232 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4233 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4234
4235 return 1;
4236 } else if (domain == target && type == QType::DNSKEY) {
4237
4238 setLWResult(res, 0, true, false, true);
4239
4240 addDNSKEY(keys, domain, 300, res->d_records);
4241 addRRSIG(keys, res->d_records, domain, 300);
4242
4243 return 1;
4244 }
4245
4246 return 0;
4247 });
4248
4249 vector<DNSRecord> ret;
4250 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4251 BOOST_CHECK_EQUAL(res, RCode::NoError);
4252 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4253 /* 13 NS + 1 RRSIG */
4254 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4255 BOOST_CHECK_EQUAL(queriesCount, 2);
4256
4257 /* again, to test the cache */
4258 ret.clear();
4259 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4260 BOOST_CHECK_EQUAL(res, RCode::NoError);
4261 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4262 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4263 BOOST_CHECK_EQUAL(queriesCount, 2);
4264 }
4265
4266 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
4267 std::unique_ptr<SyncRes> sr;
4268 initSR(sr, true);
4269
4270 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4271
4272 primeHints();
4273 const DNSName target(".");
4274 testkeysset_t keys;
4275
4276 auto luaconfsCopy = g_luaconfs.getCopy();
4277 luaconfsCopy.dsAnchors.clear();
4278 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4279
4280 g_luaconfs.setState(luaconfsCopy);
4281
4282 size_t queriesCount = 0;
4283
4284 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4285 queriesCount++;
4286
4287 if (domain == target && type == QType::NS) {
4288
4289 setLWResult(res, 0, true, false, true);
4290 char addr[] = "a.root-servers.net.";
4291 for (char idx = 'a'; idx <= 'm'; idx++) {
4292 addr[0] = idx;
4293 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4294 }
4295
4296 /* FORCE WRONG ALGO */
4297 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4298
4299 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4300 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4301
4302 return 1;
4303 } else if (domain == target && type == QType::DNSKEY) {
4304
4305 setLWResult(res, 0, true, false, true);
4306
4307 addDNSKEY(keys, domain, 300, res->d_records);
4308 addRRSIG(keys, res->d_records, domain, 300);
4309
4310 return 1;
4311 }
4312
4313 return 0;
4314 });
4315
4316 vector<DNSRecord> ret;
4317 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4318 BOOST_CHECK_EQUAL(res, RCode::NoError);
4319 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4320 /* 13 NS + 1 RRSIG */
4321 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4322 BOOST_CHECK_EQUAL(queriesCount, 2);
4323
4324 /* again, to test the cache */
4325 ret.clear();
4326 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4327 BOOST_CHECK_EQUAL(res, RCode::NoError);
4328 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4329 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4330 BOOST_CHECK_EQUAL(queriesCount, 2);
4331 }
4332
4333 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds) {
4334 std::unique_ptr<SyncRes> sr;
4335 initSR(sr, true);
4336
4337 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4338
4339 primeHints();
4340 const DNSName target("com.");
4341 const ComboAddress targetAddr("192.0.2.42");
4342 testkeysset_t keys;
4343
4344 auto luaconfsCopy = g_luaconfs.getCopy();
4345 luaconfsCopy.dsAnchors.clear();
4346 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4347 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4348
4349 g_luaconfs.setState(luaconfsCopy);
4350
4351 size_t queriesCount = 0;
4352
4353 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4354 queriesCount++;
4355
4356 DNSName auth = domain;
4357
4358 if (type == QType::DS || type == QType::DNSKEY) {
4359 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4360 return 0;
4361 }
4362
4363 if (type == QType::DS && domain == target) {
4364 /* remove the last record, which is the DS's RRSIG */
4365 res->d_records.pop_back();
4366 }
4367
4368 return 1;
4369 }
4370
4371 if (isRootServer(ip)) {
4372 setLWResult(res, 0, false, false, true);
4373 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4374 /* Include the DS but omit the RRSIG*/
4375 addDS(DNSName("com."), 300, res->d_records, keys);
4376 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4377 return 1;
4378 }
4379
4380 if (ip == ComboAddress("192.0.2.1:53")) {
4381 setLWResult(res, RCode::NoError, true, false, true);
4382 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4383 addRRSIG(keys, res->d_records, auth, 300);
4384 return 1;
4385 }
4386
4387 return 0;
4388 });
4389
4390 vector<DNSRecord> ret;
4391 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4392 BOOST_CHECK_EQUAL(res, RCode::NoError);
4393 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4394 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4395 BOOST_CHECK_EQUAL(queriesCount, 4);
4396
4397 /* again, to test the cache */
4398 ret.clear();
4399 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4400 BOOST_CHECK_EQUAL(res, RCode::NoError);
4401 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4402 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4403 BOOST_CHECK_EQUAL(queriesCount, 4);
4404
4405 /* now we ask directly for the DS */
4406 ret.clear();
4407 res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4408 BOOST_CHECK_EQUAL(res, RCode::NoError);
4409 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4410 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4411 BOOST_CHECK_EQUAL(queriesCount, 4);
4412 }
4413
4414 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds_direct) {
4415 std::unique_ptr<SyncRes> sr;
4416 initSR(sr, true);
4417
4418 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4419
4420 primeHints();
4421 const DNSName target("com.");
4422 testkeysset_t keys;
4423
4424 auto luaconfsCopy = g_luaconfs.getCopy();
4425 luaconfsCopy.dsAnchors.clear();
4426 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4427 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4428
4429 g_luaconfs.setState(luaconfsCopy);
4430
4431 size_t queriesCount = 0;
4432
4433 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4434 queriesCount++;
4435
4436 DNSName auth = domain;
4437
4438 if (type == QType::DS || type == QType::DNSKEY) {
4439 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4440 return 0;
4441 }
4442
4443 if (type == QType::DS && domain == target) {
4444 /* remove the last record, which is the DS's RRSIG */
4445 res->d_records.pop_back();
4446 }
4447
4448 return 1;
4449 }
4450
4451 if (isRootServer(ip)) {
4452 setLWResult(res, 0, false, false, true);
4453 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4454 /* Include the DS but omit the RRSIG*/
4455 addDS(DNSName("com."), 300, res->d_records, keys);
4456 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4457 return 1;
4458 }
4459
4460 return 0;
4461 });
4462
4463 vector<DNSRecord> ret;
4464 int res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4465 BOOST_CHECK_EQUAL(res, RCode::NoError);
4466 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4467 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4468 BOOST_CHECK_EQUAL(queriesCount, 1);
4469 }
4470
4471 BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
4472 std::unique_ptr<SyncRes> sr;
4473 initSR(sr, true);
4474
4475 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4476
4477 primeHints();
4478 const DNSName target("powerdns.com.");
4479 const ComboAddress targetAddr("192.0.2.42");
4480 testkeysset_t keys;
4481
4482 auto luaconfsCopy = g_luaconfs.getCopy();
4483 luaconfsCopy.dsAnchors.clear();
4484 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4485 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4486 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
4487
4488 g_luaconfs.setState(luaconfsCopy);
4489
4490 size_t queriesCount = 0;
4491
4492 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4493 queriesCount++;
4494
4495 DNSName auth = domain;
4496 if (domain == target) {
4497 auth = DNSName("powerdns.com.");
4498 }
4499
4500 if (type == QType::DS || type == QType::DNSKEY) {
4501 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4502 }
4503
4504 if (isRootServer(ip)) {
4505 setLWResult(res, 0, false, false, true);
4506 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4507 addDS(DNSName("com."), 300, res->d_records, keys);
4508 addRRSIG(keys, res->d_records, DNSName("."), 300);
4509 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4510 return 1;
4511 }
4512
4513 if (ip == ComboAddress("192.0.2.1:53")) {
4514 if (domain == DNSName("com.")) {
4515 setLWResult(res, 0, true, false, true);
4516 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4517 addRRSIG(keys, res->d_records, domain, 300);
4518 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4519 addRRSIG(keys, res->d_records, domain, 300);
4520 }
4521 else {
4522 setLWResult(res, 0, false, false, true);
4523 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4524 addDS(auth, 300, res->d_records, keys);
4525 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4526 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4527 }
4528 return 1;
4529 }
4530
4531 if (ip == ComboAddress("192.0.2.2:53")) {
4532 if (type == QType::NS) {
4533 setLWResult(res, 0, true, false, true);
4534 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4535 addRRSIG(keys, res->d_records, auth, 300);
4536 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4537 addRRSIG(keys, res->d_records, auth, 300);
4538 }
4539 else {
4540 setLWResult(res, RCode::NoError, true, false, true);
4541 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4542 addRRSIG(keys, res->d_records, auth, 300);
4543 }
4544 return 1;
4545 }
4546
4547 return 0;
4548 });
4549
4550 vector<DNSRecord> ret;
4551 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4552 BOOST_CHECK_EQUAL(res, RCode::NoError);
4553 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4554 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4555 BOOST_CHECK_EQUAL(queriesCount, 8);
4556
4557 /* again, to test the cache */
4558 ret.clear();
4559 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4560 BOOST_CHECK_EQUAL(res, RCode::NoError);
4561 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4562 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4563 BOOST_CHECK_EQUAL(queriesCount, 8);
4564 }
4565
4566 BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4567 std::unique_ptr<SyncRes> sr;
4568 initSR(sr, true);
4569
4570 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4571
4572 primeHints();
4573 const DNSName target("powerdns.com.");
4574 const ComboAddress targetAddr("192.0.2.42");
4575 testkeysset_t keys;
4576
4577 auto luaconfsCopy = g_luaconfs.getCopy();
4578 luaconfsCopy.dsAnchors.clear();
4579 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4580 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4581 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4582 g_luaconfs.setState(luaconfsCopy);
4583
4584 size_t queriesCount = 0;
4585
4586 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4587 queriesCount++;
4588
4589 DNSName auth = domain;
4590 if (domain == target) {
4591 auth = DNSName("powerdns.com.");
4592 }
4593
4594 if (type == QType::DS || type == QType::DNSKEY) {
4595 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4596 }
4597
4598 if (isRootServer(ip)) {
4599 setLWResult(res, 0, false, false, true);
4600 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4601 addDS(DNSName("com."), 300, res->d_records, keys);
4602 addRRSIG(keys, res->d_records, DNSName("."), 300);
4603 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4604 return 1;
4605 }
4606
4607 if (ip == ComboAddress("192.0.2.1:53")) {
4608 if (domain == DNSName("com.")) {
4609 setLWResult(res, 0, true, false, true);
4610 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4611 addRRSIG(keys, res->d_records, domain, 300);
4612 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4613 addRRSIG(keys, res->d_records, domain, 300);
4614 }
4615 else {
4616 setLWResult(res, 0, false, false, true);
4617 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4618 addDS(auth, 300, res->d_records, keys);
4619 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4620 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4621 }
4622 return 1;
4623 }
4624
4625 if (ip == ComboAddress("192.0.2.2:53")) {
4626 if (type == QType::NS) {
4627 setLWResult(res, 0, true, false, true);
4628 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4629 addRRSIG(keys, res->d_records, auth, 300);
4630 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4631 addRRSIG(keys, res->d_records, auth, 300);
4632 }
4633 else {
4634 setLWResult(res, RCode::NoError, true, false, true);
4635 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4636 addRRSIG(keys, res->d_records, auth, 300);
4637 }
4638 return 1;
4639 }
4640
4641 return 0;
4642 });
4643
4644 vector<DNSRecord> ret;
4645 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4646 BOOST_CHECK_EQUAL(res, RCode::NoError);
4647 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4648 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4649 BOOST_CHECK_EQUAL(queriesCount, 8);
4650
4651 /* again, to test the cache */
4652 ret.clear();
4653 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4654 BOOST_CHECK_EQUAL(res, RCode::NoError);
4655 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4656 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4657 BOOST_CHECK_EQUAL(queriesCount, 8);
4658
4659 /* this time we ask for the NS that should be in the cache, to check
4660 the validation status */
4661 ret.clear();
4662 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4663 BOOST_CHECK_EQUAL(res, RCode::NoError);
4664 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4665 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4666 BOOST_CHECK_EQUAL(queriesCount, 9);
4667
4668 }
4669
4670 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4671 std::unique_ptr<SyncRes> sr;
4672 initSR(sr, true);
4673
4674 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4675
4676 primeHints();
4677 const DNSName target("powerdns.com.");
4678 const ComboAddress targetAddr("192.0.2.42");
4679 testkeysset_t keys;
4680
4681 auto luaconfsCopy = g_luaconfs.getCopy();
4682 luaconfsCopy.dsAnchors.clear();
4683 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4684 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4685 g_luaconfs.setState(luaconfsCopy);
4686
4687 size_t queriesCount = 0;
4688
4689 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4690 queriesCount++;
4691
4692 DNSName auth = domain;
4693 if (domain == target) {
4694 auth = DNSName("powerdns.com.");
4695 }
4696
4697 if (type == QType::DS || type == QType::DNSKEY) {
4698 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4699 }
4700
4701 if (isRootServer(ip)) {
4702 setLWResult(res, 0, false, false, true);
4703 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4704 addDS(DNSName("com."), 300, res->d_records, keys);
4705 addRRSIG(keys, res->d_records, DNSName("."), 300);
4706 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4707 return 1;
4708 }
4709
4710 if (ip == ComboAddress("192.0.2.1:53")) {
4711 if (domain == DNSName("com.")) {
4712 setLWResult(res, 0, true, false, true);
4713 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4714 addRRSIG(keys, res->d_records, domain, 300);
4715 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4716 addRRSIG(keys, res->d_records, domain, 300);
4717 }
4718 else {
4719 setLWResult(res, 0, false, false, true);
4720 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4721 /* no DS */
4722 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4723 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4724 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4725 }
4726 return 1;
4727 }
4728
4729 if (ip == ComboAddress("192.0.2.2:53")) {
4730 if (type == QType::NS) {
4731 setLWResult(res, 0, true, false, true);
4732 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4733 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4734 }
4735 else {
4736 setLWResult(res, RCode::NoError, true, false, true);
4737 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4738 }
4739 return 1;
4740 }
4741
4742 return 0;
4743 });
4744
4745 vector<DNSRecord> ret;
4746 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4747 BOOST_CHECK_EQUAL(res, RCode::NoError);
4748 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4749 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4750 BOOST_CHECK_EQUAL(queriesCount, 7);
4751
4752 /* again, to test the cache */
4753 ret.clear();
4754 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4755 BOOST_CHECK_EQUAL(res, RCode::NoError);
4756 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4757 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4758 BOOST_CHECK_EQUAL(queriesCount, 7);
4759
4760 /* this time we ask for the NS that should be in the cache, to check
4761 the validation status */
4762 ret.clear();
4763 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4764 BOOST_CHECK_EQUAL(res, RCode::NoError);
4765 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4766 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4767 BOOST_CHECK_EQUAL(queriesCount, 8);
4768 }
4769
4770 BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
4771 std::unique_ptr<SyncRes> sr;
4772 initSR(sr, true);
4773
4774 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4775
4776 primeHints();
4777 const DNSName target("powerdns.com.");
4778 const ComboAddress targetAddr("192.0.2.42");
4779 testkeysset_t keys;
4780
4781 auto luaconfsCopy = g_luaconfs.getCopy();
4782 luaconfsCopy.dsAnchors.clear();
4783 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4784 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4785 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4786
4787 /* Add a NTA for "powerdns.com" */
4788 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4789
4790 g_luaconfs.setState(luaconfsCopy);
4791
4792 size_t queriesCount = 0;
4793
4794 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4795 queriesCount++;
4796
4797 DNSName auth = domain;
4798 if (domain == target) {
4799 auth = DNSName("powerdns.com.");
4800 }
4801
4802 if (type == QType::DS || type == QType::DNSKEY) {
4803 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4804 }
4805
4806 if (isRootServer(ip)) {
4807 setLWResult(res, 0, false, false, true);
4808 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4809 addDS(DNSName("com."), 300, res->d_records, keys);
4810 addRRSIG(keys, res->d_records, DNSName("."), 300);
4811 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4812 return 1;
4813 }
4814
4815 if (ip == ComboAddress("192.0.2.1:53")) {
4816 if (domain == DNSName("com.")) {
4817 setLWResult(res, 0, true, false, true);
4818 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4819 addRRSIG(keys, res->d_records, domain, 300);
4820 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4821 addRRSIG(keys, res->d_records, domain, 300);
4822 }
4823 else {
4824 setLWResult(res, 0, false, false, true);
4825 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4826 addDS(auth, 300, res->d_records, keys);
4827 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4828 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4829 }
4830 return 1;
4831 }
4832
4833 if (ip == ComboAddress("192.0.2.2:53")) {
4834 if (type == QType::NS) {
4835 setLWResult(res, 0, true, false, true);
4836 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4837 addRRSIG(keys, res->d_records, auth, 300);
4838 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4839 addRRSIG(keys, res->d_records, auth, 300);
4840 }
4841 else {
4842 setLWResult(res, RCode::NoError, true, false, true);
4843 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4844 addRRSIG(keys, res->d_records, auth, 300);
4845 }
4846 return 1;
4847 }
4848
4849 return 0;
4850 });
4851
4852 vector<DNSRecord> ret;
4853 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4854 BOOST_CHECK_EQUAL(res, RCode::NoError);
4855 /* Should be insecure because of the NTA */
4856 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4857 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4858 BOOST_CHECK_EQUAL(queriesCount, 5);
4859
4860 /* again, to test the cache */
4861 ret.clear();
4862 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4863 BOOST_CHECK_EQUAL(res, RCode::NoError);
4864 /* Should be insecure because of the NTA */
4865 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4866 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4867 BOOST_CHECK_EQUAL(queriesCount, 5);
4868 }
4869
4870 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4871 std::unique_ptr<SyncRes> sr;
4872 initSR(sr, true);
4873
4874 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4875
4876 primeHints();
4877 const DNSName target("powerdns.com.");
4878 const ComboAddress targetAddr("192.0.2.42");
4879 testkeysset_t keys;
4880
4881 auto luaconfsCopy = g_luaconfs.getCopy();
4882 luaconfsCopy.dsAnchors.clear();
4883 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4884 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4885 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4886
4887 /* Add a NTA for "powerdns.com" */
4888 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4889
4890 g_luaconfs.setState(luaconfsCopy);
4891
4892 size_t queriesCount = 0;
4893
4894 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4895 queriesCount++;
4896
4897 if (type == QType::DS || type == QType::DNSKEY) {
4898 setLWResult(res, 0, false, false, true);
4899 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4900 return 1;
4901 }
4902 else {
4903 if (isRootServer(ip)) {
4904 setLWResult(res, 0, false, false, true);
4905 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4906 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4907 return 1;
4908 }
4909 else if (ip == ComboAddress("192.0.2.1:53")) {
4910 if (domain == DNSName("com.")) {
4911 setLWResult(res, 0, true, false, true);
4912 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4913 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4914 }
4915 else {
4916 setLWResult(res, 0, false, false, true);
4917 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4918 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4919 }
4920 return 1;
4921 }
4922 else if (ip == ComboAddress("192.0.2.2:53")) {
4923 if (type == QType::NS) {
4924 setLWResult(res, 0, true, false, true);
4925 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4926 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4927 }
4928 else {
4929 setLWResult(res, RCode::NoError, true, false, true);
4930 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4931 }
4932 return 1;
4933 }
4934 }
4935
4936 return 0;
4937 });
4938
4939 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
4940 vector<DNSRecord> ret;
4941 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4942 BOOST_CHECK_EQUAL(res, RCode::NoError);
4943 /* Should be insecure because of the NTA */
4944 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4945 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4946 BOOST_CHECK_EQUAL(queriesCount, 4);
4947
4948 /* again, to test the cache */
4949 ret.clear();
4950 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4951 BOOST_CHECK_EQUAL(res, RCode::NoError);
4952 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4953 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4954 BOOST_CHECK_EQUAL(queriesCount, 4);
4955 }
4956
4957 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
4958 std::unique_ptr<SyncRes> sr;
4959 initSR(sr, true);
4960
4961 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4962
4963 primeHints();
4964 const DNSName target("powerdns.com.");
4965 testkeysset_t keys;
4966
4967 auto luaconfsCopy = g_luaconfs.getCopy();
4968 luaconfsCopy.dsAnchors.clear();
4969 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4970 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4971 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4972
4973 g_luaconfs.setState(luaconfsCopy);
4974
4975 size_t queriesCount = 0;
4976
4977 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4978 queriesCount++;
4979
4980 if (type == QType::DS || type == QType::DNSKEY) {
4981 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4982 }
4983 else {
4984 if (isRootServer(ip)) {
4985 setLWResult(res, 0, false, false, true);
4986 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4987 addDS(DNSName("com."), 300, res->d_records, keys);
4988 addRRSIG(keys, res->d_records, DNSName("."), 300);
4989 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4990 return 1;
4991 }
4992 else if (ip == ComboAddress("192.0.2.1:53")) {
4993 if (domain == DNSName("com.")) {
4994 setLWResult(res, 0, true, false, true);
4995 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4996 addRRSIG(keys, res->d_records, domain, 300);
4997 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4998 addRRSIG(keys, res->d_records, domain, 300);
4999 }
5000 else {
5001 setLWResult(res, 0, false, false, true);
5002 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5003 addDS(domain, 300, res->d_records, keys);
5004 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5005 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5006 }
5007 return 1;
5008 }
5009 else if (ip == ComboAddress("192.0.2.2:53")) {
5010 if (type == QType::NS) {
5011 setLWResult(res, 0, true, false, true);
5012 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5013 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5014 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5015 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5016 }
5017 else {
5018 setLWResult(res, 0, true, false, true);
5019 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5020 addRRSIG(keys, res->d_records, domain, 300);
5021 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
5022 addRRSIG(keys, res->d_records, domain, 300);
5023 }
5024 return 1;
5025 }
5026 }
5027
5028 return 0;
5029 });
5030
5031 vector<DNSRecord> ret;
5032 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5033 BOOST_CHECK_EQUAL(res, RCode::NoError);
5034 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5035 BOOST_REQUIRE_EQUAL(ret.size(), 4);
5036 BOOST_CHECK_EQUAL(queriesCount, 8);
5037
5038 /* again, to test the cache */
5039 ret.clear();
5040 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5041 BOOST_CHECK_EQUAL(res, RCode::NoError);
5042 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5043 BOOST_REQUIRE_EQUAL(ret.size(), 4);
5044 BOOST_CHECK_EQUAL(queriesCount, 8);
5045 }
5046
5047 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
5048 std::unique_ptr<SyncRes> sr;
5049 initSR(sr, true);
5050
5051 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5052
5053 primeHints();
5054 const DNSName target("nx.powerdns.com.");
5055 testkeysset_t keys;
5056
5057 auto luaconfsCopy = g_luaconfs.getCopy();
5058 luaconfsCopy.dsAnchors.clear();
5059 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5060 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5061 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5062
5063 g_luaconfs.setState(luaconfsCopy);
5064
5065 size_t queriesCount = 0;
5066
5067 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5068 queriesCount++;
5069
5070 DNSName auth = domain;
5071 if (domain == target) {
5072 auth = DNSName("powerdns.com.");
5073 }
5074 if (type == QType::DS || type == QType::DNSKEY) {
5075 if (type == QType::DS && domain == target) {
5076 setLWResult(res, RCode::NXDomain, true, false, true);
5077 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5078 addRRSIG(keys, res->d_records, auth, 300);
5079 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5080 addRRSIG(keys, res->d_records, auth, 300);
5081 return 1;
5082 }
5083 else {
5084 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
5085 }
5086 }
5087 else {
5088 if (isRootServer(ip)) {
5089 setLWResult(res, 0, false, false, true);
5090 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5091 addDS(DNSName("com."), 300, res->d_records, keys);
5092 addRRSIG(keys, res->d_records, DNSName("."), 300);
5093 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5094 return 1;
5095 }
5096 else if (ip == ComboAddress("192.0.2.1:53")) {
5097 if (domain == DNSName("com.")) {
5098 setLWResult(res, 0, true, false, true);
5099 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5100 addRRSIG(keys, res->d_records, domain, 300);
5101 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5102 addRRSIG(keys, res->d_records, domain, 300);
5103 }
5104 else {
5105 setLWResult(res, 0, false, false, true);
5106 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5107 addDS(auth, 300, res->d_records, keys);
5108 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5109 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5110 }
5111 return 1;
5112 }
5113 else if (ip == ComboAddress("192.0.2.2:53")) {
5114 if (type == QType::NS) {
5115 setLWResult(res, 0, true, false, true);
5116 if (domain == DNSName("powerdns.com.")) {
5117 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5118 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5119 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5120 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5121 }
5122 else {
5123 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5124 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5125 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5126 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5127 }
5128 }
5129 else {
5130 setLWResult(res, RCode::NXDomain, true, false, true);
5131 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5132 addRRSIG(keys, res->d_records, auth, 300);
5133 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5134 addRRSIG(keys, res->d_records, auth, 300);
5135 /* add wildcard denial */
5136 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5137 addRRSIG(keys, res->d_records, auth, 300);
5138 }
5139 return 1;
5140 }
5141 }
5142
5143 return 0;
5144 });
5145
5146 vector<DNSRecord> ret;
5147 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5148 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5149 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5150 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5151 BOOST_CHECK_EQUAL(queriesCount, 9);
5152
5153 /* again, to test the cache */
5154 ret.clear();
5155 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5156 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5157 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5158 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5159 BOOST_CHECK_EQUAL(queriesCount, 9);
5160 }
5161
5162 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
5163 std::unique_ptr<SyncRes> sr;
5164 initSR(sr, true);
5165
5166 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5167
5168 primeHints();
5169 const DNSName target("www.powerdns.com.");
5170 testkeysset_t keys;
5171
5172 auto luaconfsCopy = g_luaconfs.getCopy();
5173 luaconfsCopy.dsAnchors.clear();
5174 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5175 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5176 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5177
5178 g_luaconfs.setState(luaconfsCopy);
5179
5180 size_t queriesCount = 0;
5181
5182 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5183 queriesCount++;
5184
5185 if (type == QType::DS || type == QType::DNSKEY) {
5186 if (type == QType::DS && domain == target) {
5187 setLWResult(res, RCode::NoError, true, false, true);
5188 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5189 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5190 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5191 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5192 return 1;
5193 }
5194 else {
5195 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5196 }
5197 }
5198 else {
5199 if (isRootServer(ip)) {
5200 setLWResult(res, 0, false, false, true);
5201 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5202 addDS(DNSName("com."), 300, res->d_records, keys);
5203 addRRSIG(keys, res->d_records, DNSName("."), 300);
5204 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5205 return 1;
5206 }
5207 else if (ip == ComboAddress("192.0.2.1:53")) {
5208 if (domain == DNSName("com.")) {
5209 setLWResult(res, 0, true, false, true);
5210 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5211 addRRSIG(keys, res->d_records, domain, 300);
5212 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5213 addRRSIG(keys, res->d_records, domain, 300);
5214 }
5215 else {
5216 setLWResult(res, 0, false, false, true);
5217 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5218 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5219 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5220 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5221 }
5222 return 1;
5223 }
5224 else if (ip == ComboAddress("192.0.2.2:53")) {
5225 setLWResult(res, 0, true, false, true);
5226 if (type == QType::NS) {
5227 if (domain == DNSName("powerdns.com.")) {
5228 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5229 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5230 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5231 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5232 }
5233 else {
5234 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5235 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5236 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5237 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5238 }
5239 }
5240 else {
5241 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5242 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5243 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5244 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 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(), 4);
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(), 4);
5267 BOOST_CHECK_EQUAL(queriesCount, 9);
5268 }
5269
5270 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
5271 std::unique_ptr<SyncRes> sr;
5272 initSR(sr, true);
5273
5274 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5275
5276 primeHints();
5277 const DNSName target("www.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
5285 g_luaconfs.setState(luaconfsCopy);
5286
5287 size_t queriesCount = 0;
5288
5289 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5290 queriesCount++;
5291
5292 if (type == QType::DS || type == QType::DNSKEY) {
5293 if (type == QType::DS && domain == target) {
5294 DNSName auth("com.");
5295 setLWResult(res, 0, true, false, true);
5296
5297 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5298 addRRSIG(keys, res->d_records, auth, 300);
5299 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
5300 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
5301 addRRSIG(keys, res->d_records, auth, 300);
5302 return 1;
5303 }
5304 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
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 setLWResult(res, 0, true, false, true);
5317 /* no data */
5318 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5319 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5320 /* no record for this name */
5321 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
5322 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5323 /* a wildcard matches but has no record for this type */
5324 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5325 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5326 return 1;
5327 }
5328 }
5329
5330 return 0;
5331 });
5332
5333 vector<DNSRecord> ret;
5334 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5335 BOOST_CHECK_EQUAL(res, RCode::NoError);
5336 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5337 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5338 BOOST_CHECK_EQUAL(queriesCount, 6);
5339
5340 /* again, to test the cache */
5341 ret.clear();
5342 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5343 BOOST_CHECK_EQUAL(res, RCode::NoError);
5344 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5345 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5346 BOOST_CHECK_EQUAL(queriesCount, 6);
5347 }
5348
5349 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
5350 std::unique_ptr<SyncRes> sr;
5351 initSR(sr, true);
5352
5353 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5354
5355 primeHints();
5356 const DNSName target("www.com.");
5357 testkeysset_t keys;
5358
5359 auto luaconfsCopy = g_luaconfs.getCopy();
5360 luaconfsCopy.dsAnchors.clear();
5361 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5362 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5363
5364 g_luaconfs.setState(luaconfsCopy);
5365
5366 size_t queriesCount = 0;
5367
5368 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5369 queriesCount++;
5370
5371 if (type == QType::DS || type == QType::DNSKEY) {
5372 if (type == QType::DS && domain == target) {
5373 DNSName auth("com.");
5374 setLWResult(res, 0, true, false, true);
5375
5376 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5377 addRRSIG(keys, res->d_records, auth, 300);
5378 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5379 /* first the closest encloser */
5380 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5381 addRRSIG(keys, res->d_records, auth, 300);
5382 /* then the next closer */
5383 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5384 addRRSIG(keys, res->d_records, auth, 300);
5385 /* a wildcard matches but has no record for this type */
5386 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5387 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5388 return 1;
5389 }
5390 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5391 }
5392 else {
5393 if (isRootServer(ip)) {
5394 setLWResult(res, 0, false, false, true);
5395 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5396 addDS(DNSName("com."), 300, res->d_records, keys);
5397 addRRSIG(keys, res->d_records, DNSName("."), 300);
5398 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5399 return 1;
5400 }
5401 else if (ip == ComboAddress("192.0.2.1:53")) {
5402 setLWResult(res, 0, true, false, true);
5403 /* no data */
5404 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5405 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5406 /* no record for this name */
5407 /* first the closest encloser */
5408 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5409 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5410 /* then the next closer */
5411 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5412 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5413 /* a wildcard matches but has no record for this type */
5414 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5415 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5416 return 1;
5417 }
5418 }
5419
5420 return 0;
5421 });
5422
5423 vector<DNSRecord> ret;
5424 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5425 BOOST_CHECK_EQUAL(res, RCode::NoError);
5426 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5427 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5428 BOOST_CHECK_EQUAL(queriesCount, 6);
5429
5430 /* again, to test the cache */
5431 ret.clear();
5432 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5433 BOOST_CHECK_EQUAL(res, RCode::NoError);
5434 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5435 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5436 BOOST_CHECK_EQUAL(queriesCount, 6);
5437 }
5438
5439 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5440 std::unique_ptr<SyncRes> sr;
5441 initSR(sr, true);
5442
5443 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5444
5445 primeHints();
5446 const DNSName target("www.com.");
5447 testkeysset_t keys;
5448
5449 auto luaconfsCopy = g_luaconfs.getCopy();
5450 luaconfsCopy.dsAnchors.clear();
5451 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5452 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5453
5454 g_luaconfs.setState(luaconfsCopy);
5455
5456 size_t queriesCount = 0;
5457
5458 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5459 queriesCount++;
5460
5461 if (type == QType::DS || type == QType::DNSKEY) {
5462 if (type == QType::DS && domain == target) {
5463 DNSName auth("com.");
5464 setLWResult(res, 0, true, false, true);
5465
5466 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5467 addRRSIG(keys, res->d_records, auth, 300);
5468 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5469 /* first the closest encloser */
5470 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5471 addRRSIG(keys, res->d_records, auth, 300);
5472 /* then the next closer */
5473 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5474 addRRSIG(keys, res->d_records, auth, 300);
5475 /* a wildcard matches but has no record for this type */
5476 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5477 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5478 return 1;
5479 }
5480 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5481 }
5482 else {
5483 if (isRootServer(ip)) {
5484 setLWResult(res, 0, false, false, true);
5485 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5486 addDS(DNSName("com."), 300, res->d_records, keys);
5487 addRRSIG(keys, res->d_records, DNSName("."), 300);
5488 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5489 return 1;
5490 }
5491 else if (ip == ComboAddress("192.0.2.1:53")) {
5492 setLWResult(res, 0, true, false, true);
5493 /* no data */
5494 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5495 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5496 /* no record for this name */
5497 /* first the closest encloser */
5498 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5499 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5500 /* then the next closer */
5501 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5502 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5503 /* a wildcard matches but has no record for this type */
5504 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5505 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5506 return 1;
5507 }
5508 }
5509
5510 return 0;
5511 });
5512
5513 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5514 vector<DNSRecord> ret;
5515 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5516 BOOST_CHECK_EQUAL(res, RCode::NoError);
5517 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5518 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5519 BOOST_CHECK_EQUAL(queriesCount, 6);
5520
5521 /* again, to test the cache */
5522 ret.clear();
5523 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5524 BOOST_CHECK_EQUAL(res, RCode::NoError);
5525 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5526 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5527 BOOST_CHECK_EQUAL(queriesCount, 6);
5528 }
5529
5530 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5531 std::unique_ptr<SyncRes> sr;
5532 initSR(sr, true);
5533
5534 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5535
5536 primeHints();
5537 const DNSName target("www.sub.powerdns.com.");
5538 testkeysset_t keys;
5539
5540 auto luaconfsCopy = g_luaconfs.getCopy();
5541 luaconfsCopy.dsAnchors.clear();
5542 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5543 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5544 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5545
5546 g_luaconfs.setState(luaconfsCopy);
5547
5548 size_t queriesCount = 0;
5549
5550 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5551 queriesCount++;
5552
5553 if (type == QType::DS || type == QType::DNSKEY) {
5554 if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) {
5555 setLWResult(res, RCode::NoError, true, false, true);
5556 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5557 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5558 if (domain == DNSName("sub.powerdns.com")) {
5559 addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5560 }
5561 else if (domain == target) {
5562 addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5563 }
5564 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5565 return 1;
5566 }
5567 else {
5568 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5569 }
5570 }
5571 else {
5572 if (isRootServer(ip)) {
5573 setLWResult(res, 0, false, false, true);
5574 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5575 addDS(DNSName("com."), 300, res->d_records, keys);
5576 addRRSIG(keys, res->d_records, DNSName("."), 300);
5577 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5578 return 1;
5579 }
5580 else if (ip == ComboAddress("192.0.2.1:53")) {
5581 if (domain == DNSName("com.")) {
5582 setLWResult(res, 0, true, false, true);
5583 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5584 addRRSIG(keys, res->d_records, domain, 300);
5585 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5586 addRRSIG(keys, res->d_records, domain, 300);
5587 }
5588 else {
5589 setLWResult(res, 0, false, false, true);
5590 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5591 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5592 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5593 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5594 }
5595 return 1;
5596 }
5597 else if (ip == ComboAddress("192.0.2.2:53")) {
5598 setLWResult(res, 0, true, false, true);
5599 if (type == QType::NS) {
5600 if (domain == DNSName("powerdns.com.")) {
5601 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5602 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5603 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5604 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5605 }
5606 else {
5607 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5608 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5609 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5610 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5611 }
5612 }
5613 else {
5614 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5615 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5616 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5617 /* first the closest encloser */
5618 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5619 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5620 /* then the next closer */
5621 addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5622 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5623 }
5624 return 1;
5625 }
5626 }
5627
5628 return 0;
5629 });
5630
5631 vector<DNSRecord> ret;
5632 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5633 BOOST_CHECK_EQUAL(res, RCode::NoError);
5634 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5635 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5636 BOOST_CHECK_EQUAL(queriesCount, 10);
5637
5638 /* again, to test the cache */
5639 ret.clear();
5640 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5641 BOOST_CHECK_EQUAL(res, RCode::NoError);
5642 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5643 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5644 BOOST_CHECK_EQUAL(queriesCount, 10);
5645 }
5646
5647 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5648 std::unique_ptr<SyncRes> sr;
5649 initSR(sr, true);
5650
5651 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5652
5653 primeHints();
5654 const DNSName target("www.powerdns.com.");
5655 testkeysset_t keys;
5656
5657 auto luaconfsCopy = g_luaconfs.getCopy();
5658 luaconfsCopy.dsAnchors.clear();
5659 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5660 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5661 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5662
5663 g_luaconfs.setState(luaconfsCopy);
5664
5665 size_t queriesCount = 0;
5666
5667 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5668 queriesCount++;
5669
5670 if (type == QType::DS || type == QType::DNSKEY) {
5671 if (type == QType::DS && domain == target) {
5672 setLWResult(res, RCode::NoError, true, false, true);
5673 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5674 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5675 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5676 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5677 return 1;
5678 }
5679 else {
5680 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5681 }
5682 }
5683 else {
5684 if (isRootServer(ip)) {
5685 setLWResult(res, 0, false, false, true);
5686 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5687 addDS(DNSName("com."), 300, res->d_records, keys);
5688 addRRSIG(keys, res->d_records, DNSName("."), 300);
5689 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5690 return 1;
5691 }
5692 else if (ip == ComboAddress("192.0.2.1:53")) {
5693 if (domain == DNSName("com.")) {
5694 setLWResult(res, 0, true, false, true);
5695 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5696 addRRSIG(keys, res->d_records, domain, 300);
5697 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5698 addRRSIG(keys, res->d_records, domain, 300);
5699 }
5700 else {
5701 setLWResult(res, 0, false, false, true);
5702 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5703 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5704 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5705 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5706 }
5707 return 1;
5708 }
5709 else if (ip == ComboAddress("192.0.2.2:53")) {
5710 setLWResult(res, 0, true, false, true);
5711 if (type == QType::NS) {
5712 if (domain == DNSName("powerdns.com.")) {
5713 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5714 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5715 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5716 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5717 }
5718 else {
5719 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5720 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5721 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5722 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5723 }
5724 }
5725 else {
5726 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5727 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5728 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5729 /* first the closest encloser */
5730 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5731 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5732 /* then the next closer */
5733 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5734 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5735 }
5736 return 1;
5737 }
5738 }
5739
5740 return 0;
5741 });
5742
5743 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5744 we should end up Insecure */
5745 vector<DNSRecord> ret;
5746 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5747 BOOST_CHECK_EQUAL(res, RCode::NoError);
5748 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5749 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5750 BOOST_CHECK_EQUAL(queriesCount, 9);
5751
5752 /* again, to test the cache */
5753 ret.clear();
5754 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5755 BOOST_CHECK_EQUAL(res, RCode::NoError);
5756 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5757 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5758 BOOST_CHECK_EQUAL(queriesCount, 9);
5759 }
5760
5761 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5762 std::unique_ptr<SyncRes> sr;
5763 initSR(sr, true);
5764
5765 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5766
5767 primeHints();
5768 const DNSName target("www.powerdns.com.");
5769 testkeysset_t keys;
5770
5771 auto luaconfsCopy = g_luaconfs.getCopy();
5772 luaconfsCopy.dsAnchors.clear();
5773 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5774 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5775 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5776
5777 g_luaconfs.setState(luaconfsCopy);
5778
5779 size_t queriesCount = 0;
5780
5781 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5782 queriesCount++;
5783
5784 if (type == QType::DS || type == QType::DNSKEY) {
5785 if (type == QType::DS && domain == target) {
5786 setLWResult(res, RCode::NoError, true, false, true);
5787 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5788 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5789 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5790 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5791 return 1;
5792 }
5793 else {
5794 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5795 }
5796 }
5797 else {
5798 if (isRootServer(ip)) {
5799 setLWResult(res, 0, false, false, true);
5800 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5801 addDS(DNSName("com."), 300, res->d_records, keys);
5802 addRRSIG(keys, res->d_records, DNSName("."), 300);
5803 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5804 return 1;
5805 }
5806 else if (ip == ComboAddress("192.0.2.1:53")) {
5807 if (domain == DNSName("com.")) {
5808 setLWResult(res, 0, true, false, true);
5809 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5810 addRRSIG(keys, res->d_records, domain, 300);
5811 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5812 addRRSIG(keys, res->d_records, domain, 300);
5813 }
5814 else {
5815 setLWResult(res, 0, false, false, true);
5816 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5817 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5818 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5819 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5820 }
5821 return 1;
5822 }
5823 else if (ip == ComboAddress("192.0.2.2:53")) {
5824 setLWResult(res, 0, true, false, true);
5825 if (type == QType::NS) {
5826 if (domain == DNSName("powerdns.com.")) {
5827 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5828 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5829 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5830 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5831 }
5832 else {
5833 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5834 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5835 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5836 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5837 }
5838 }
5839 else {
5840 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5841 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5842 }
5843 return 1;
5844 }
5845 }
5846
5847 return 0;
5848 });
5849
5850 vector<DNSRecord> ret;
5851 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5852 BOOST_CHECK_EQUAL(res, RCode::NoError);
5853 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5854 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5855 BOOST_CHECK_EQUAL(queriesCount, 9);
5856
5857 /* again, to test the cache */
5858 ret.clear();
5859 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5860 BOOST_CHECK_EQUAL(res, RCode::NoError);
5861 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5862 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5863 BOOST_CHECK_EQUAL(queriesCount, 9);
5864 }
5865
5866 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5867 std::unique_ptr<SyncRes> sr;
5868 initSR(sr, true);
5869
5870 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5871
5872 primeHints();
5873 const DNSName target("www.powerdns.com.");
5874 testkeysset_t keys;
5875
5876 auto luaconfsCopy = g_luaconfs.getCopy();
5877 luaconfsCopy.dsAnchors.clear();
5878 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5879 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5880 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5881
5882 g_luaconfs.setState(luaconfsCopy);
5883
5884 size_t queriesCount = 0;
5885 size_t dsQueriesCount = 0;
5886
5887 sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5888 queriesCount++;
5889
5890 if (type == QType::DS) {
5891 DNSName auth(domain);
5892 auth.chopOff();
5893 dsQueriesCount++;
5894
5895 setLWResult(res, 0, true, false, true);
5896 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5897 addRRSIG(keys, res->d_records, auth, 300);
5898 return 1;
5899 }
5900 else if (type == QType::DNSKEY) {
5901 setLWResult(res, 0, true, false, true);
5902 addDNSKEY(keys, domain, 300, res->d_records);
5903 addRRSIG(keys, res->d_records, domain, 300);
5904 return 1;
5905 }
5906 else {
5907 if (isRootServer(ip)) {
5908 setLWResult(res, 0, false, false, true);
5909 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5910 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5911 /* No DS on referral, and no denial of the DS either */
5912 return 1;
5913 }
5914 else if (ip == ComboAddress("192.0.2.1:53")) {
5915 if (domain == DNSName("com.")) {
5916 setLWResult(res, 0, true, false, true);
5917 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5918 addRRSIG(keys, res->d_records, domain, 300);
5919 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5920 addRRSIG(keys, res->d_records, domain, 300);
5921 }
5922 else {
5923 setLWResult(res, 0, false, false, true);
5924 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5925 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5926 /* No DS on referral, and no denial of the DS either */
5927 }
5928 return 1;
5929 }
5930 else if (ip == ComboAddress("192.0.2.2:53")) {
5931 setLWResult(res, 0, true, false, true);
5932 if (type == QType::NS) {
5933 if (domain == DNSName("powerdns.com.")) {
5934 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5935 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5936 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5937 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5938 }
5939 else {
5940 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5941 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5942 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5943 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5944 }
5945 }
5946 else {
5947 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5948 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5949 }
5950
5951 return 1;
5952 }
5953 }
5954
5955 return 0;
5956 });
5957
5958 vector<DNSRecord> ret;
5959 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5960 BOOST_CHECK_EQUAL(res, RCode::NoError);
5961 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5962 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5963 BOOST_CHECK_EQUAL(queriesCount, 9);
5964 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5965
5966 /* again, to test the cache */
5967 ret.clear();
5968 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5969 BOOST_CHECK_EQUAL(res, RCode::NoError);
5970 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5971 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5972 BOOST_CHECK_EQUAL(queriesCount, 9);
5973 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5974 }
5975
5976 BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
5977 std::unique_ptr<SyncRes> sr;
5978 initSR(sr, true);
5979
5980 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5981
5982 primeHints();
5983 const DNSName target("www.powerdns.com.");
5984 testkeysset_t keys;
5985
5986 auto luaconfsCopy = g_luaconfs.getCopy();
5987 luaconfsCopy.dsAnchors.clear();
5988 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5989 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5990 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5991 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5992
5993 g_luaconfs.setState(luaconfsCopy);
5994
5995 size_t queriesCount = 0;
5996
5997 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
5998 queriesCount++;
5999
6000 if (type == QType::DS) {
6001 DNSName auth(domain);
6002 auth.chopOff();
6003
6004 setLWResult(res, 0, true, false, true);
6005 if (domain == target) {
6006 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6007 addRRSIG(keys, res->d_records, target, 300);
6008 }
6009 else {
6010 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6011 addRRSIG(keys, res->d_records, auth, 300);
6012 }
6013 return 1;
6014 }
6015 else if (type == QType::DNSKEY) {
6016 setLWResult(res, 0, true, false, true);
6017 addDNSKEY(keys, domain, 300, res->d_records);
6018 addRRSIG(keys, res->d_records, domain, 300);
6019 return 1;
6020 }
6021 else {
6022 if (isRootServer(ip)) {
6023 setLWResult(res, 0, false, false, true);
6024 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6025 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6026 addDS(DNSName("com."), 300, res->d_records, keys);
6027 addRRSIG(keys, res->d_records, DNSName("."), 300);
6028 return 1;
6029 }
6030 else if (ip == ComboAddress("192.0.2.1:53")) {
6031 if (domain == DNSName("com.")) {
6032 setLWResult(res, 0, true, false, true);
6033 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6034 addRRSIG(keys, res->d_records, domain, 300);
6035 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6036 addRRSIG(keys, res->d_records, domain, 300);
6037 }
6038 else {
6039 setLWResult(res, 0, false, false, true);
6040 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6041 /* no DS */
6042 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6043 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6044 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6045 }
6046 return 1;
6047 }
6048 else if (ip == ComboAddress("192.0.2.2:53")) {
6049 if (type == QType::NS) {
6050 if (domain == DNSName("powerdns.com.")) {
6051 setLWResult(res, RCode::Refused, false, false, true);
6052 }
6053 else {
6054 setLWResult(res, 0, true, false, true);
6055 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6056 addRRSIG(keys, res->d_records, domain, 300);
6057 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6058 addRRSIG(keys, res->d_records, domain, 300);
6059 }
6060 }
6061 else {
6062 setLWResult(res, 0, true, false, true);
6063 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6064 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
6065 }
6066
6067 return 1;
6068 }
6069 }
6070
6071 return 0;
6072 });
6073
6074 vector<DNSRecord> ret;
6075 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6076 BOOST_CHECK_EQUAL(res, RCode::NoError);
6077 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6078 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6079 BOOST_CHECK_EQUAL(queriesCount, 9);
6080
6081 /* again, to test the cache */
6082 ret.clear();
6083 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6084 BOOST_CHECK_EQUAL(res, RCode::NoError);
6085 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6086 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6087 BOOST_CHECK_EQUAL(queriesCount, 9);
6088 }
6089
6090 BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) {
6091 /* check that we don't accept a signer below us */
6092 std::unique_ptr<SyncRes> sr;
6093 initSR(sr, true);
6094
6095 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6096
6097 primeHints();
6098 const DNSName target("www.powerdns.com.");
6099 testkeysset_t keys;
6100
6101 auto luaconfsCopy = g_luaconfs.getCopy();
6102 luaconfsCopy.dsAnchors.clear();
6103 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6104 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6105 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6106 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6107 generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6108
6109 g_luaconfs.setState(luaconfsCopy);
6110
6111 size_t queriesCount = 0;
6112
6113 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6114 queriesCount++;
6115
6116 if (type == QType::DS) {
6117 DNSName auth(domain);
6118 auth.chopOff();
6119
6120 setLWResult(res, 0, true, false, true);
6121 if (domain == target) {
6122 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6123 addRRSIG(keys, res->d_records, target, 300);
6124 }
6125 else {
6126 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6127 addRRSIG(keys, res->d_records, auth, 300);
6128 }
6129 return 1;
6130 }
6131 else if (type == QType::DNSKEY) {
6132 setLWResult(res, 0, true, false, true);
6133 addDNSKEY(keys, domain, 300, res->d_records);
6134 if (domain == DNSName("www.powerdns.com.")) {
6135 addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
6136 }
6137 else {
6138 addRRSIG(keys, res->d_records, domain, 300);
6139 }
6140 return 1;
6141 }
6142 else {
6143 if (isRootServer(ip)) {
6144 setLWResult(res, 0, false, false, true);
6145 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6146 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6147 addDS(DNSName("com."), 300, res->d_records, keys);
6148 addRRSIG(keys, res->d_records, DNSName("."), 300);
6149 return 1;
6150 }
6151 else if (ip == ComboAddress("192.0.2.1:53")) {
6152 if (domain == DNSName("com.")) {
6153 setLWResult(res, 0, true, false, true);
6154 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6155 addRRSIG(keys, res->d_records, domain, 300);
6156 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6157 addRRSIG(keys, res->d_records, domain, 300);
6158 }
6159 else {
6160 setLWResult(res, 0, false, false, true);
6161 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6162 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6163 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6164 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6165 }
6166 return 1;
6167 }
6168 else if (ip == ComboAddress("192.0.2.2:53")) {
6169 if (type == QType::NS) {
6170 setLWResult(res, 0, true, false, true);
6171 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6172 addRRSIG(keys, res->d_records, domain, 300);
6173 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6174 addRRSIG(keys, res->d_records, domain, 300);
6175 }
6176 else {
6177 setLWResult(res, 0, true, false, true);
6178 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6179 addRRSIG(keys, res->d_records, domain, 300);
6180 }
6181
6182 return 1;
6183 }
6184 }
6185
6186 return 0;
6187 });
6188
6189 vector<DNSRecord> ret;
6190 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6191 BOOST_CHECK_EQUAL(res, RCode::NoError);
6192 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6193 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6194 BOOST_CHECK_EQUAL(queriesCount, 9);
6195
6196 /* again, to test the cache */
6197 ret.clear();
6198 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6199 BOOST_CHECK_EQUAL(res, RCode::NoError);
6200 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6201 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6202 BOOST_CHECK_EQUAL(queriesCount, 9);
6203 }
6204
6205 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
6206 std::unique_ptr<SyncRes> sr;
6207 initSR(sr, true);
6208
6209 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6210
6211 primeHints();
6212 const DNSName target("www.powerdns.com.");
6213 testkeysset_t keys;
6214
6215 auto luaconfsCopy = g_luaconfs.getCopy();
6216 luaconfsCopy.dsAnchors.clear();
6217 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6218 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6219
6220 g_luaconfs.setState(luaconfsCopy);
6221
6222 size_t queriesCount = 0;
6223 size_t dsQueriesCount = 0;
6224
6225 sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6226 queriesCount++;
6227
6228 if (type == QType::DS) {
6229 DNSName auth(domain);
6230 auth.chopOff();
6231 dsQueriesCount++;
6232
6233 setLWResult(res, 0, true, false, true);
6234 if (domain == DNSName("com.")) {
6235 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6236 }
6237 else {
6238 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6239 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6240 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
6241 }
6242 addRRSIG(keys, res->d_records, auth, 300);
6243 return 1;
6244 }
6245 else if (type == QType::DNSKEY) {
6246 setLWResult(res, 0, true, false, true);
6247 addDNSKEY(keys, domain, 300, res->d_records);
6248 addRRSIG(keys, res->d_records, domain, 300);
6249 return 1;
6250 }
6251 else {
6252 if (isRootServer(ip)) {
6253 setLWResult(res, 0, false, false, true);
6254 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6255 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6256 /* No DS on referral, and no denial of the DS either */
6257 return 1;
6258 }
6259 else if (ip == ComboAddress("192.0.2.1:53")) {
6260 if (domain == DNSName("com.")) {
6261 setLWResult(res, 0, true, false, true);
6262 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6263 addRRSIG(keys, res->d_records, domain, 300);
6264 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6265 addRRSIG(keys, res->d_records, domain, 300);
6266 }
6267 else {
6268 setLWResult(res, 0, false, false, true);
6269 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6270 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6271 /* No DS on referral, and no denial of the DS either */
6272 }
6273 return 1;
6274 }
6275 else if (ip == ComboAddress("192.0.2.2:53")) {
6276 setLWResult(res, 0, true, false, true);
6277 if (type == QType::NS) {
6278 if (domain == DNSName("powerdns.com.")) {
6279 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6280 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6281 }
6282 else {
6283 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6284 }
6285 }
6286 else {
6287 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6288 }
6289 return 1;
6290 }
6291 }
6292
6293 return 0;
6294 });
6295
6296 vector<DNSRecord> ret;
6297 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6298 BOOST_CHECK_EQUAL(res, RCode::NoError);
6299 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6300 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6301 BOOST_CHECK_EQUAL(queriesCount, 7);
6302 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6303
6304 /* again, to test the cache */
6305 ret.clear();
6306 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6307 BOOST_CHECK_EQUAL(res, RCode::NoError);
6308 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6309 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6310 BOOST_CHECK_EQUAL(queriesCount, 7);
6311 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6312 }
6313
6314 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
6315 std::unique_ptr<SyncRes> sr;
6316 initSR(sr, true);
6317
6318 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6319
6320 primeHints();
6321 const DNSName target("powerdns.com.");
6322 testkeysset_t keys;
6323
6324 auto luaconfsCopy = g_luaconfs.getCopy();
6325 luaconfsCopy.dsAnchors.clear();
6326 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6327 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6328 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6329
6330 g_luaconfs.setState(luaconfsCopy);
6331
6332 size_t queriesCount = 0;
6333
6334 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6335 queriesCount++;
6336
6337 if (type == QType::DS || type == QType::DNSKEY) {
6338 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6339 }
6340 else {
6341 if (isRootServer(ip)) {
6342 setLWResult(res, 0, false, false, true);
6343 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6344 addDS(DNSName("com."), 300, res->d_records, keys);
6345 addRRSIG(keys, res->d_records, DNSName("."), 300);
6346 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6347 return 1;
6348 }
6349 else if (ip == ComboAddress("192.0.2.1:53")) {
6350 if (domain == DNSName("com.")) {
6351 setLWResult(res, 0, true, false, true);
6352 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6353 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6354 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6355 }
6356 else {
6357 setLWResult(res, 0, false, false, true);
6358 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6359 addDS(domain, 300, res->d_records, keys);
6360 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6361 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6362 }
6363 return 1;
6364 }
6365 else if (ip == ComboAddress("192.0.2.2:53")) {
6366 setLWResult(res, 0, true, false, true);
6367 if (type == QType::NS) {
6368 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6369 addRRSIG(keys, res->d_records, domain, 300);
6370 }
6371 else {
6372 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6373 addRRSIG(keys, res->d_records, domain, 300);
6374 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
6375 /* NO RRSIG for the NSEC record! */
6376 }
6377 return 1;
6378 }
6379 }
6380
6381 return 0;
6382 });
6383
6384 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
6385 vector<DNSRecord> ret;
6386 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6387 BOOST_CHECK_EQUAL(res, RCode::NoError);
6388 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6389 BOOST_CHECK_EQUAL(ret.size(), 3);
6390 BOOST_CHECK_EQUAL(queriesCount, 8);
6391
6392 /* again, to test the cache */
6393 ret.clear();
6394 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6395 BOOST_CHECK_EQUAL(res, RCode::NoError);
6396 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6397 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6398 BOOST_CHECK_EQUAL(queriesCount, 8);
6399 }
6400
6401 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
6402 std::unique_ptr<SyncRes> sr;
6403 initSR(sr, true);
6404
6405 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6406
6407 primeHints();
6408 const DNSName target("powerdns.com.");
6409 testkeysset_t keys;
6410
6411 auto luaconfsCopy = g_luaconfs.getCopy();
6412 luaconfsCopy.dsAnchors.clear();
6413 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6414 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6415 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6416
6417 g_luaconfs.setState(luaconfsCopy);
6418
6419 size_t queriesCount = 0;
6420
6421 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6422 queriesCount++;
6423
6424 if (type == QType::DS || type == QType::DNSKEY) {
6425 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6426 }
6427 else {
6428 if (isRootServer(ip)) {
6429 setLWResult(res, 0, false, false, true);
6430 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6431 addDS(DNSName("com."), 300, res->d_records, keys);
6432 addRRSIG(keys, res->d_records, DNSName("."), 300);
6433 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6434 return 1;
6435 }
6436 else if (ip == ComboAddress("192.0.2.1:53")) {
6437 if (domain == DNSName("com.")) {
6438 setLWResult(res, 0, true, false, true);
6439 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6440 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6441 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6442 }
6443 else {
6444 setLWResult(res, 0, false, false, true);
6445 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6446 addDS(domain, 300, res->d_records, keys);
6447 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6448 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6449 }
6450 return 1;
6451 }
6452 else if (ip == ComboAddress("192.0.2.2:53")) {
6453 setLWResult(res, 0, true, false, true);
6454 if (type == QType::NS) {
6455 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6456 addRRSIG(keys, res->d_records, domain, 300);
6457 }
6458 else {
6459 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6460 addRRSIG(keys, res->d_records, domain, 300);
6461
6462 /* NO NSEC record! */
6463 }
6464 return 1;
6465 }
6466 }
6467
6468 return 0;
6469 });
6470
6471 /* no NSEC record in a secure zone, should be Bogus! */
6472 vector<DNSRecord> ret;
6473 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6474 BOOST_CHECK_EQUAL(res, RCode::NoError);
6475 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6476 BOOST_CHECK_EQUAL(ret.size(), 2);
6477 BOOST_CHECK_EQUAL(queriesCount, 8);
6478
6479 /* again, to test the cache */
6480 ret.clear();
6481 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6482 BOOST_CHECK_EQUAL(res, RCode::NoError);
6483 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6484 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6485 BOOST_CHECK_EQUAL(queriesCount, 8);
6486 }
6487
6488 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6489 std::unique_ptr<SyncRes> sr;
6490 initSR(sr, true);
6491
6492 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6493
6494 primeHints();
6495 const DNSName target("powerdns.com.");
6496 const ComboAddress targetAddr("192.0.2.42");
6497 testkeysset_t keys;
6498
6499 auto luaconfsCopy = g_luaconfs.getCopy();
6500 luaconfsCopy.dsAnchors.clear();
6501 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6502 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6503
6504 g_luaconfs.setState(luaconfsCopy);
6505
6506 size_t queriesCount = 0;
6507
6508 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6509 queriesCount++;
6510
6511 if (type == QType::DS) {
6512 if (domain == target) {
6513 setLWResult(res, 0, false, false, true);
6514 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6515 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6516 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6517 return 1;
6518 } else {
6519 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6520 }
6521 }
6522 else if (type == QType::DNSKEY) {
6523 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6524 setLWResult(res, 0, true, false, true);
6525 addDNSKEY(keys, domain, 300, res->d_records);
6526 addRRSIG(keys, res->d_records, domain, 300);
6527 return 1;
6528 }
6529 else {
6530 setLWResult(res, 0, false, false, true);
6531 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6532 return 1;
6533 }
6534 }
6535 else {
6536 if (isRootServer(ip)) {
6537 setLWResult(res, 0, false, false, true);
6538 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6539 addDS(DNSName("com."), 300, res->d_records, keys);
6540 addRRSIG(keys, res->d_records, DNSName("."), 300);
6541 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6542 return 1;
6543 }
6544 else if (ip == ComboAddress("192.0.2.1:53")) {
6545 if (domain == DNSName("com.")) {
6546 setLWResult(res, 0, true, false, true);
6547 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6548 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6549 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6550 }
6551 else {
6552 setLWResult(res, 0, false, false, true);
6553 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6554 /* no DS */
6555 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6556 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6557 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6558 }
6559 return 1;
6560 }
6561 else if (ip == ComboAddress("192.0.2.2:53")) {
6562 setLWResult(res, 0, true, false, true);
6563 if (type == QType::NS) {
6564 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6565 }
6566 else {
6567 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6568 }
6569 return 1;
6570 }
6571 }
6572
6573 return 0;
6574 });
6575
6576 vector<DNSRecord> ret;
6577 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6578 BOOST_CHECK_EQUAL(res, RCode::NoError);
6579 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6580 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6581 BOOST_CHECK(ret[0].d_type == QType::A);
6582 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6583 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6584 1 query for A */
6585 BOOST_CHECK_EQUAL(queriesCount, 7);
6586
6587 /* again, to test the cache */
6588 ret.clear();
6589 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6590 BOOST_CHECK_EQUAL(res, RCode::NoError);
6591 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6592 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6593 BOOST_CHECK(ret[0].d_type == QType::A);
6594 BOOST_CHECK_EQUAL(queriesCount, 7);
6595 }
6596
6597
6598 BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6599 /*
6600 Direct DS query:
6601 - parent is secure, zone is secure: DS should be secure
6602 */
6603 std::unique_ptr<SyncRes> sr;
6604 initSR(sr, true);
6605
6606 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6607
6608 primeHints();
6609 const DNSName target("powerdns.com.");
6610 testkeysset_t keys;
6611
6612 auto luaconfsCopy = g_luaconfs.getCopy();
6613 luaconfsCopy.dsAnchors.clear();
6614 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6615 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6616 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6617
6618 g_luaconfs.setState(luaconfsCopy);
6619
6620 size_t queriesCount = 0;
6621
6622 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6623 queriesCount++;
6624
6625 if (type == QType::DS || type == QType::DNSKEY) {
6626 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6627 }
6628 else {
6629 if (isRootServer(ip)) {
6630 setLWResult(res, 0, false, false, true);
6631 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6632 addDS(DNSName("com."), 300, res->d_records, keys);
6633 addRRSIG(keys, res->d_records, DNSName("."), 300);
6634 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6635 return 1;
6636 }
6637 }
6638
6639 return 0;
6640 });
6641
6642 vector<DNSRecord> ret;
6643 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6644 BOOST_CHECK_EQUAL(res, RCode::NoError);
6645 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6646 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6647 for (const auto& record : ret) {
6648 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6649 }
6650 BOOST_CHECK_EQUAL(queriesCount, 4);
6651
6652 /* again, to test the cache */
6653 ret.clear();
6654 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6655 BOOST_CHECK_EQUAL(res, RCode::NoError);
6656 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6657 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6658 for (const auto& record : ret) {
6659 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6660 }
6661 BOOST_CHECK_EQUAL(queriesCount, 4);
6662 }
6663
6664 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6665 /*
6666 Direct DS query:
6667 - parent is secure, zone is insecure: DS denial should be secure
6668 */
6669 std::unique_ptr<SyncRes> sr;
6670 initSR(sr, true);
6671
6672 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6673
6674 primeHints();
6675 const DNSName target("powerdns.com.");
6676 testkeysset_t keys;
6677
6678 auto luaconfsCopy = g_luaconfs.getCopy();
6679 luaconfsCopy.dsAnchors.clear();
6680 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6681 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6682
6683 g_luaconfs.setState(luaconfsCopy);
6684
6685 size_t queriesCount = 0;
6686
6687 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6688 queriesCount++;
6689
6690 if (type == QType::DS || type == QType::DNSKEY) {
6691 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6692 }
6693 else {
6694 if (isRootServer(ip)) {
6695 setLWResult(res, 0, false, false, true);
6696 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6697 addDS(DNSName("com."), 300, res->d_records, keys);
6698 addRRSIG(keys, res->d_records, DNSName("."), 300);
6699 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6700 return 1;
6701 }
6702 }
6703
6704 return 0;
6705 });
6706
6707 vector<DNSRecord> ret;
6708 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6709 BOOST_CHECK_EQUAL(res, RCode::NoError);
6710 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6711 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6712 for (const auto& record : ret) {
6713 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6714 }
6715 BOOST_CHECK_EQUAL(queriesCount, 4);
6716
6717 /* again, to test the cache */
6718 ret.clear();
6719 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6720 BOOST_CHECK_EQUAL(res, RCode::NoError);
6721 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6722 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6723 for (const auto& record : ret) {
6724 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6725 }
6726 BOOST_CHECK_EQUAL(queriesCount, 4);
6727 }
6728
6729 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6730 std::unique_ptr<SyncRes> sr;
6731 initSR(sr, true);
6732
6733 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6734
6735 primeHints();
6736 const DNSName target("www.sub.powerdns.com.");
6737 const ComboAddress targetAddr("192.0.2.42");
6738 testkeysset_t keys;
6739
6740 auto luaconfsCopy = g_luaconfs.getCopy();
6741 luaconfsCopy.dsAnchors.clear();
6742 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6743 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6744 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6745
6746 g_luaconfs.setState(luaconfsCopy);
6747
6748 size_t queriesCount = 0;
6749
6750 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6751 queriesCount++;
6752
6753 if (type == QType::DS) {
6754 if (domain == DNSName("sub.powerdns.com.")) {
6755 setLWResult(res, 0, false, false, true);
6756 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6757 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6758 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6759 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6760 return 1;
6761 }
6762 else if (domain == DNSName("www.sub.powerdns.com.")) {
6763 setLWResult(res, 0, false, false, true);
6764 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);
6765 return 1;
6766 }
6767 else {
6768 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6769 }
6770 }
6771 else if (type == QType::DNSKEY) {
6772 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6773 setLWResult(res, 0, true, false, true);
6774 addDNSKEY(keys, domain, 300, res->d_records);
6775 addRRSIG(keys, res->d_records, domain, 300);
6776 return 1;
6777 }
6778 else {
6779 setLWResult(res, 0, false, false, true);
6780 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6781 return 1;
6782 }
6783 }
6784 else {
6785 if (isRootServer(ip)) {
6786 setLWResult(res, 0, false, false, true);
6787 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6788 addDS(DNSName("com."), 300, res->d_records, keys);
6789 addRRSIG(keys, res->d_records, DNSName("."), 300);
6790 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6791 return 1;
6792 }
6793 else if (ip == ComboAddress("192.0.2.1:53")) {
6794 if (domain == DNSName("com.")) {
6795 setLWResult(res, 0, true, false, true);
6796 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6797 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6798 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6799 }
6800 else {
6801 setLWResult(res, 0, false, false, true);
6802 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6803 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6804 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6805 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6806 }
6807 return 1;
6808 }
6809 else if (ip == ComboAddress("192.0.2.2:53")) {
6810 setLWResult(res, 0, true, false, true);
6811 if (type == QType::NS) {
6812 if (domain == DNSName("www.sub.powerdns.com.")) {
6813 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);
6814 }
6815 else if (domain == DNSName("sub.powerdns.com.")) {
6816 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6817 }
6818 else if (domain == DNSName("powerdns.com.")) {
6819 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6820 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6821 }
6822 } else {
6823 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6824 }
6825 return 1;
6826 }
6827 }
6828
6829 return 0;
6830 });
6831
6832 vector<DNSRecord> ret;
6833 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6834 BOOST_CHECK_EQUAL(res, RCode::NoError);
6835 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6836 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6837 BOOST_CHECK(ret[0].d_type == QType::A);
6838 BOOST_CHECK_EQUAL(queriesCount, 9);
6839
6840 /* again, to test the cache */
6841 ret.clear();
6842 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6843 BOOST_CHECK_EQUAL(res, RCode::NoError);
6844 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6845 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6846 BOOST_CHECK(ret[0].d_type == QType::A);
6847 BOOST_CHECK_EQUAL(queriesCount, 9);
6848 }
6849
6850 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6851 std::unique_ptr<SyncRes> sr;
6852 initSR(sr, true);
6853
6854 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6855
6856 primeHints();
6857 const DNSName target("www.sub.powerdns.com.");
6858 const ComboAddress targetAddr("192.0.2.42");
6859 testkeysset_t keys;
6860
6861 auto luaconfsCopy = g_luaconfs.getCopy();
6862 luaconfsCopy.dsAnchors.clear();
6863 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6864 /* No key material for .com */
6865 /* But TA for sub.powerdns.com. */
6866 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6867 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6868 g_luaconfs.setState(luaconfsCopy);
6869
6870 size_t queriesCount = 0;
6871
6872 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6873 queriesCount++;
6874
6875 if (type == QType::DS) {
6876 if (domain == DNSName("www.sub.powerdns.com")) {
6877 setLWResult(res, 0, false, false, true);
6878 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);
6879 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6880 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6881 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6882 }
6883 else {
6884 setLWResult(res, 0, false, false, true);
6885
6886 if (domain == DNSName("com.")) {
6887 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6888 /* no DS */
6889 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6890 addRRSIG(keys, res->d_records, DNSName("."), 300);
6891 }
6892 else {
6893 setLWResult(res, 0, false, false, true);
6894 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6895 }
6896 }
6897 return 1;
6898 }
6899 else if (type == QType::DNSKEY) {
6900 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
6901 setLWResult(res, 0, true, false, true);
6902 addDNSKEY(keys, domain, 300, res->d_records);
6903 addRRSIG(keys, res->d_records, domain, 300);
6904 return 1;
6905 }
6906 }
6907 else {
6908 if (isRootServer(ip)) {
6909 setLWResult(res, 0, false, false, true);
6910 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6911 /* no DS */
6912 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6913 addRRSIG(keys, res->d_records, DNSName("."), 300);
6914 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6915 return 1;
6916 }
6917 else if (ip == ComboAddress("192.0.2.1:53")) {
6918 if (domain == DNSName("com.")) {
6919 setLWResult(res, 0, true, false, true);
6920 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6921 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6922 }
6923 else if (domain.isPartOf(DNSName("powerdns.com."))) {
6924 setLWResult(res, 0, false, false, true);
6925 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6926 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6927 }
6928 return 1;
6929 }
6930 else if (ip == ComboAddress("192.0.2.2:53")) {
6931 setLWResult(res, 0, true, false, true);
6932 if (type == QType::NS) {
6933 if (domain == DNSName("www.sub.powerdns.com.")) {
6934 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);
6935 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6936 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6937 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6938 }
6939 else if (domain == DNSName("sub.powerdns.com.")) {
6940 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6941 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6942 }
6943 else if (domain == DNSName("powerdns.com.")) {
6944 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6945 }
6946 }
6947 else if (domain == DNSName("www.sub.powerdns.com.")) {
6948 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6949 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6950 }
6951 return 1;
6952 }
6953 }
6954
6955 return 0;
6956 });
6957
6958 vector<DNSRecord> ret;
6959 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6960 BOOST_CHECK_EQUAL(res, RCode::NoError);
6961 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6962 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6963 BOOST_CHECK(ret[0].d_type == QType::A);
6964 BOOST_CHECK_EQUAL(queriesCount, 7);
6965
6966 /* again, to test the cache */
6967 ret.clear();
6968 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6969 BOOST_CHECK_EQUAL(res, RCode::NoError);
6970 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6971 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6972 BOOST_CHECK(ret[0].d_type == QType::A);
6973 BOOST_CHECK_EQUAL(queriesCount, 7);
6974 }
6975
6976 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
6977 std::unique_ptr<SyncRes> sr;
6978 initSR(sr, true);
6979
6980 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6981
6982 primeHints();
6983 const DNSName target("powerdns.com.");
6984 testkeysset_t keys;
6985
6986 auto luaconfsCopy = g_luaconfs.getCopy();
6987 luaconfsCopy.dsAnchors.clear();
6988 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6989 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6990
6991 g_luaconfs.setState(luaconfsCopy);
6992
6993 size_t queriesCount = 0;
6994
6995 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
6996 queriesCount++;
6997
6998 if (type == QType::DS) {
6999 if (domain == target) {
7000 setLWResult(res, 0, false, false, true);
7001 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7002 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7003 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7004 return 1;
7005 }
7006 else {
7007 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7008 }
7009 }
7010 else if (type == QType::DNSKEY) {
7011 if (domain == g_rootdnsname || domain == DNSName("com.")) {
7012 setLWResult(res, 0, true, false, true);
7013 addDNSKEY(keys, domain, 300, res->d_records);
7014 addRRSIG(keys, res->d_records, domain, 300);
7015 return 1;
7016 }
7017 else {
7018 setLWResult(res, 0, false, false, true);
7019 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7020 return 1;
7021 }
7022 }
7023 else {
7024 if (isRootServer(ip)) {
7025 setLWResult(res, 0, false, false, true);
7026 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7027 addDS(DNSName("com."), 300, res->d_records, keys);
7028 addRRSIG(keys, res->d_records, DNSName("."), 300);
7029 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7030 return 1;
7031 }
7032 else if (ip == ComboAddress("192.0.2.1:53")) {
7033 if (domain == DNSName("com.")) {
7034 setLWResult(res, 0, true, false, true);
7035 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7036 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7037 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7038 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7039 }
7040 else {
7041 setLWResult(res, 0, false, false, true);
7042 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7043 /* no DS */
7044 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7045 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7046 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7047 }
7048 return 1;
7049 }
7050 else if (ip == ComboAddress("192.0.2.2:53")) {
7051 if (type == QType::NS) {
7052 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7053 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7054 }
7055 else {
7056 setLWResult(res, 0, true, false, true);
7057 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7058 }
7059 return 1;
7060 }
7061 }
7062
7063 return 0;
7064 });
7065
7066 vector<DNSRecord> ret;
7067 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7068 BOOST_CHECK_EQUAL(res, RCode::NoError);
7069 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7070 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7071 /* 4 NS (com from root, com from com, powerdns.com from com,
7072 powerdns.com from powerdns.com)
7073 2 DNSKEY (. and com., none for powerdns.com because no DS)
7074 1 query for A
7075 */
7076 BOOST_CHECK_EQUAL(queriesCount, 7);
7077
7078 /* again, to test the cache */
7079 ret.clear();
7080 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7081 BOOST_CHECK_EQUAL(res, RCode::NoError);
7082 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7083 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7084 BOOST_CHECK_EQUAL(queriesCount, 7);
7085 }
7086
7087 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
7088 std::unique_ptr<SyncRes> sr;
7089 initSR(sr, true);
7090
7091 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7092
7093 primeHints();
7094 const DNSName target("powerdns.com.");
7095 const DNSName targetCName("power-dns.com.");
7096 const ComboAddress targetCNameAddr("192.0.2.42");
7097 testkeysset_t keys;
7098
7099 auto luaconfsCopy = g_luaconfs.getCopy();
7100 luaconfsCopy.dsAnchors.clear();
7101 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7102 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7103 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7104 g_luaconfs.setState(luaconfsCopy);
7105
7106 size_t queriesCount = 0;
7107
7108 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7109 queriesCount++;
7110
7111 if (type == QType::DS) {
7112 if (domain == targetCName) {
7113 setLWResult(res, 0, false, false, true);
7114 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7115 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7116 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7117 return 1;
7118 }
7119 else {
7120 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7121 }
7122 }
7123 else if (type == QType::DNSKEY) {
7124 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7125 setLWResult(res, 0, true, false, true);
7126 addDNSKEY(keys, domain, 300, res->d_records);
7127 addRRSIG(keys, res->d_records, domain, 300);
7128 return 1;
7129 }
7130 else {
7131 setLWResult(res, 0, false, false, true);
7132 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7133 return 1;
7134 }
7135 }
7136 else {
7137 if (isRootServer(ip)) {
7138 setLWResult(res, 0, false, false, true);
7139 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7140 addDS(DNSName("com."), 300, res->d_records, keys);
7141 addRRSIG(keys, res->d_records, DNSName("."), 300);
7142 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7143 return 1;
7144 }
7145 else if (ip == ComboAddress("192.0.2.1:53")) {
7146 setLWResult(res, 0, false, false, true);
7147 if (domain == DNSName("com.")) {
7148 setLWResult(res, 0, true, false, true);
7149 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7150 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7151 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7152 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7153 }
7154 else {
7155 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7156 if (domain == DNSName("powerdns.com.")) {
7157 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7158 }
7159 else if (domain == targetCName) {
7160 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7161 }
7162 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7163 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7164 }
7165
7166 return 1;
7167 }
7168 else if (ip == ComboAddress("192.0.2.2:53")) {
7169 setLWResult(res, 0, true, false, true);
7170
7171 if (type == QType::NS) {
7172 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7173 if (domain == DNSName("powerdns.com.")) {
7174 addRRSIG(keys, res->d_records, domain, 300);
7175 }
7176 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7177 if (domain == DNSName("powerdns.com.")) {
7178 addRRSIG(keys, res->d_records, domain, 300);
7179 }
7180 }
7181 else {
7182 if (domain == DNSName("powerdns.com.")) {
7183 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7184 addRRSIG(keys, res->d_records, domain, 300);
7185 }
7186 else if (domain == targetCName) {
7187 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7188 }
7189 }
7190
7191 return 1;
7192 }
7193 }
7194
7195 return 0;
7196 });
7197
7198 vector<DNSRecord> ret;
7199 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7200 BOOST_CHECK_EQUAL(res, RCode::NoError);
7201 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7202 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7203 BOOST_CHECK_EQUAL(queriesCount, 11);
7204
7205 /* again, to test the cache */
7206 ret.clear();
7207 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7208 BOOST_CHECK_EQUAL(res, RCode::NoError);
7209 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7210 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7211 BOOST_CHECK_EQUAL(queriesCount, 11);
7212 }
7213
7214 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname_glue) {
7215 std::unique_ptr<SyncRes> sr;
7216 initSR(sr, true);
7217
7218 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7219
7220 primeHints();
7221 const DNSName target("powerdns.com.");
7222 const DNSName targetCName1("cname.sub.powerdns.com.");
7223 const DNSName targetCName2("cname2.sub.powerdns.com.");
7224 const ComboAddress targetCName2Addr("192.0.2.42");
7225 testkeysset_t keys;
7226
7227 auto luaconfsCopy = g_luaconfs.getCopy();
7228 luaconfsCopy.dsAnchors.clear();
7229 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7230 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7231 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7232 g_luaconfs.setState(luaconfsCopy);
7233
7234 size_t queriesCount = 0;
7235
7236 sr->setAsyncCallback([target,targetCName1,targetCName2,targetCName2Addr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7237 queriesCount++;
7238
7239 if (type == QType::DS || type == QType::DNSKEY) {
7240 if (domain == DNSName("sub.powerdns.com")) {
7241 setLWResult(res, 0, false, false, true);
7242 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7243 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7244 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7245 return 1;
7246 }
7247 else {
7248 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7249 }
7250 }
7251 else {
7252 if (isRootServer(ip)) {
7253 setLWResult(res, 0, false, false, true);
7254 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7255 addDS(DNSName("com."), 300, res->d_records, keys);
7256 addRRSIG(keys, res->d_records, DNSName("."), 300);
7257 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7258 return 1;
7259 }
7260 else if (ip == ComboAddress("192.0.2.1:53")) {
7261 setLWResult(res, 0, false, false, true);
7262 if (domain == DNSName("com.")) {
7263 setLWResult(res, 0, true, false, true);
7264 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7265 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7266 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7267 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7268 }
7269 else {
7270 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7271 if (domain == DNSName("powerdns.com.")) {
7272 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7273 }
7274 else if (domain == DNSName("sub.powerdns.com")) {
7275 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7276 }
7277 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7278 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7279 }
7280
7281 return 1;
7282 }
7283 else if (ip == ComboAddress("192.0.2.2:53")) {
7284 setLWResult(res, 0, true, false, true);
7285
7286 if (type == QType::NS) {
7287 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7288 if (domain == DNSName("powerdns.com.")) {
7289 addRRSIG(keys, res->d_records, domain, 300);
7290 }
7291 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7292 if (domain == DNSName("powerdns.com.")) {
7293 addRRSIG(keys, res->d_records, domain, 300);
7294 }
7295 }
7296 else {
7297 if (domain == DNSName("powerdns.com.")) {
7298 addRecordToLW(res, domain, QType::CNAME, targetCName1.toString());
7299 addRRSIG(keys, res->d_records, domain, 300);
7300 /* add the CNAME target as a glue, with no RRSIG since the sub zone is insecure */
7301 addRecordToLW(res, targetCName1, QType::CNAME, targetCName2.toString());
7302 addRecordToLW(res, targetCName2, QType::A, targetCName2Addr.toString());
7303 }
7304 else if (domain == targetCName1) {
7305 addRecordToLW(res, domain, QType::CNAME, targetCName2.toString());
7306 }
7307 else if (domain == targetCName2) {
7308 addRecordToLW(res, domain, QType::A, targetCName2Addr.toString());
7309 }
7310 }
7311
7312 return 1;
7313 }
7314 }
7315
7316 return 0;
7317 });
7318
7319 vector<DNSRecord> ret;
7320 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7321 BOOST_CHECK_EQUAL(res, RCode::NoError);
7322 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7323 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7324 BOOST_CHECK_EQUAL(queriesCount, 11);
7325
7326 /* again, to test the cache */
7327 ret.clear();
7328 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7329 BOOST_CHECK_EQUAL(res, RCode::NoError);
7330 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7331 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7332 BOOST_CHECK_EQUAL(queriesCount, 11);
7333 }
7334
7335 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
7336 std::unique_ptr<SyncRes> sr;
7337 initSR(sr, true);
7338
7339 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7340
7341 primeHints();
7342 const DNSName target("power-dns.com.");
7343 const DNSName targetCName("powerdns.com.");
7344 const ComboAddress targetCNameAddr("192.0.2.42");
7345 testkeysset_t keys;
7346
7347 auto luaconfsCopy = g_luaconfs.getCopy();
7348 luaconfsCopy.dsAnchors.clear();
7349 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7350 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7351 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7352 g_luaconfs.setState(luaconfsCopy);
7353
7354 size_t queriesCount = 0;
7355
7356 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7357 queriesCount++;
7358
7359 if (type == QType::DS) {
7360 if (domain == DNSName("power-dns.com.")) {
7361 setLWResult(res, 0, false, false, true);
7362 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7363 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7364 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7365 return 1;
7366 }
7367 else {
7368 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7369 }
7370 }
7371 else if (type == QType::DNSKEY) {
7372 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7373 setLWResult(res, 0, true, false, true);
7374 addDNSKEY(keys, domain, 300, res->d_records);
7375 addRRSIG(keys, res->d_records, domain, 300);
7376 return 1;
7377 }
7378 else {
7379 setLWResult(res, 0, false, false, true);
7380 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7381 return 1;
7382 }
7383 }
7384 else {
7385 if (isRootServer(ip)) {
7386 setLWResult(res, 0, false, false, true);
7387 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7388 addDS(DNSName("com."), 300, res->d_records, keys);
7389 addRRSIG(keys, res->d_records, DNSName("."), 300);
7390 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7391 return 1;
7392 }
7393 else if (ip == ComboAddress("192.0.2.1:53")) {
7394 if (domain == DNSName("com.")) {
7395 setLWResult(res, 0, true, false, true);
7396 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7397 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7398 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7399 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7400 }
7401 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7402 setLWResult(res, 0, false, false, true);
7403 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7404 if (domain == targetCName) {
7405 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7406 }
7407 else if (domain == target) {
7408 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7409 }
7410 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7411 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7412 }
7413 return 1;
7414 }
7415 else if (ip == ComboAddress("192.0.2.2:53")) {
7416 setLWResult(res, 0, true, false, true);
7417 if (type == QType::NS) {
7418 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7419 if (domain == DNSName("powerdns.com.")) {
7420 addRRSIG(keys, res->d_records, domain, 300);
7421 }
7422 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7423 if (domain == DNSName("powerdns.com.")) {
7424 addRRSIG(keys, res->d_records, domain, 300);
7425 }
7426 }
7427 else {
7428 if (domain == target) {
7429 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7430 }
7431 else if (domain == targetCName) {
7432 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7433 addRRSIG(keys, res->d_records, domain, 300);
7434 }
7435 }
7436 return 1;
7437 }
7438 }
7439
7440 return 0;
7441 });
7442
7443 vector<DNSRecord> ret;
7444 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7445 BOOST_CHECK_EQUAL(res, RCode::NoError);
7446 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7447 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7448 BOOST_CHECK_EQUAL(queriesCount, 11);
7449
7450 /* again, to test the cache */
7451 ret.clear();
7452 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7453 BOOST_CHECK_EQUAL(res, RCode::NoError);
7454 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7455 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7456 BOOST_CHECK_EQUAL(queriesCount, 11);
7457 }
7458
7459 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
7460 std::unique_ptr<SyncRes> sr;
7461 initSR(sr, true);
7462
7463 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7464
7465 primeHints();
7466 const DNSName target("power-dns.com.");
7467 const DNSName targetCName("powerdns.com.");
7468 const ComboAddress targetCNameAddr("192.0.2.42");
7469 testkeysset_t keys;
7470
7471 auto luaconfsCopy = g_luaconfs.getCopy();
7472 luaconfsCopy.dsAnchors.clear();
7473 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7474 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7475 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7476 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7477 g_luaconfs.setState(luaconfsCopy);
7478
7479 size_t queriesCount = 0;
7480
7481 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7482 queriesCount++;
7483
7484 if (type == QType::DS || type == QType::DNSKEY) {
7485 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7486 }
7487 else {
7488 if (isRootServer(ip)) {
7489 setLWResult(res, 0, false, false, true);
7490 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7491 addDS(DNSName("com."), 300, res->d_records, keys);
7492 addRRSIG(keys, res->d_records, DNSName("."), 300);
7493 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7494 return 1;
7495 }
7496 else if (ip == ComboAddress("192.0.2.1:53")) {
7497 if (domain == DNSName("com.")) {
7498 setLWResult(res, 0, true, false, true);
7499 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7500 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7501 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7502 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7503 }
7504 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7505 setLWResult(res, 0, false, false, true);
7506 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7507 addDS(DNSName(domain), 300, res->d_records, keys);
7508 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7509 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7510 }
7511 return 1;
7512 }
7513 else if (ip == ComboAddress("192.0.2.2:53")) {
7514 setLWResult(res, 0, true, false, true);
7515 if (type == QType::NS) {
7516 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7517 addRRSIG(keys, res->d_records, domain, 300);
7518 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7519 addRRSIG(keys, res->d_records, domain, 300);
7520 }
7521 else {
7522 if (domain == target) {
7523 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7524 /* No RRSIG, leading to bogus */
7525 }
7526 else if (domain == targetCName) {
7527 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7528 addRRSIG(keys, res->d_records, domain, 300);
7529 }
7530 }
7531 return 1;
7532 }
7533 }
7534
7535 return 0;
7536 });
7537
7538 vector<DNSRecord> ret;
7539 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7540 BOOST_CHECK_EQUAL(res, RCode::NoError);
7541 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7542 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7543 BOOST_CHECK_EQUAL(queriesCount, 11);
7544
7545 /* again, to test the cache */
7546 ret.clear();
7547 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7548 BOOST_CHECK_EQUAL(res, RCode::NoError);
7549 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7550 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7551 BOOST_CHECK_EQUAL(queriesCount, 11);
7552 }
7553
7554 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7555 std::unique_ptr<SyncRes> sr;
7556 initSR(sr, true);
7557
7558 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7559
7560 primeHints();
7561 const DNSName target("power-dns.com.");
7562 const DNSName targetCName("powerdns.com.");
7563 const ComboAddress targetCNameAddr("192.0.2.42");
7564 testkeysset_t keys;
7565
7566 auto luaconfsCopy = g_luaconfs.getCopy();
7567 luaconfsCopy.dsAnchors.clear();
7568 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7569 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7570 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7571 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7572 g_luaconfs.setState(luaconfsCopy);
7573
7574 size_t queriesCount = 0;
7575
7576 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7577 queriesCount++;
7578
7579 if (type == QType::DS || type == QType::DNSKEY) {
7580 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7581 }
7582 else {
7583 if (isRootServer(ip)) {
7584 setLWResult(res, 0, false, false, true);
7585 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7586 addDS(DNSName("com."), 300, res->d_records, keys);
7587 addRRSIG(keys, res->d_records, DNSName("."), 300);
7588 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7589 return 1;
7590 }
7591 else if (ip == ComboAddress("192.0.2.1:53")) {
7592 if (domain == DNSName("com.")) {
7593 setLWResult(res, 0, true, false, true);
7594 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7595 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7596 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7597 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7598 }
7599 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7600 setLWResult(res, 0, false, false, true);
7601 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7602 addDS(DNSName(domain), 300, res->d_records, keys);
7603 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7604 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7605 }
7606 return 1;
7607 }
7608 else if (ip == ComboAddress("192.0.2.2:53")) {
7609 setLWResult(res, 0, true, false, true);
7610 if (type == QType::NS) {
7611 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7612 addRRSIG(keys, res->d_records, domain, 300);
7613 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7614 addRRSIG(keys, res->d_records, domain, 300);
7615 }
7616 else {
7617 if (domain == target) {
7618 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7619 addRRSIG(keys, res->d_records, domain, 300);
7620 }
7621 else if (domain == targetCName) {
7622 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7623 /* No RRSIG, leading to bogus */
7624 }
7625 }
7626 return 1;
7627 }
7628 }
7629
7630 return 0;
7631 });
7632
7633 vector<DNSRecord> ret;
7634 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7635 BOOST_CHECK_EQUAL(res, RCode::NoError);
7636 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7637 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7638 BOOST_CHECK_EQUAL(queriesCount, 11);
7639
7640 /* again, to test the cache */
7641 ret.clear();
7642 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7643 BOOST_CHECK_EQUAL(res, RCode::NoError);
7644 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7645 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7646 BOOST_CHECK_EQUAL(queriesCount, 11);
7647 }
7648
7649 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
7650 std::unique_ptr<SyncRes> sr;
7651 initSR(sr, true);
7652
7653 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7654
7655 primeHints();
7656 const DNSName target("power-dns.com.");
7657 const DNSName targetCName("powerdns.com.");
7658 const ComboAddress targetCNameAddr("192.0.2.42");
7659 testkeysset_t keys;
7660
7661 auto luaconfsCopy = g_luaconfs.getCopy();
7662 luaconfsCopy.dsAnchors.clear();
7663 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7664 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7665 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7666 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7667 g_luaconfs.setState(luaconfsCopy);
7668
7669 size_t queriesCount = 0;
7670
7671 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7672 queriesCount++;
7673
7674 if (type == QType::DS || type == QType::DNSKEY) {
7675 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7676 }
7677 else {
7678 if (isRootServer(ip)) {
7679 setLWResult(res, 0, false, false, true);
7680 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7681 addDS(DNSName("com."), 300, res->d_records, keys);
7682 addRRSIG(keys, res->d_records, DNSName("."), 300);
7683 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7684 return 1;
7685 }
7686 else if (ip == ComboAddress("192.0.2.1:53")) {
7687 if (domain == DNSName("com.")) {
7688 setLWResult(res, 0, true, false, true);
7689 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7690 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7691 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7692 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7693 }
7694 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7695 setLWResult(res, 0, false, false, true);
7696 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7697 addDS(DNSName(domain), 300, res->d_records, keys);
7698 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7699 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7700 }
7701 return 1;
7702 }
7703 else if (ip == ComboAddress("192.0.2.2:53")) {
7704 setLWResult(res, 0, true, false, true);
7705 if (type == QType::NS) {
7706 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7707 addRRSIG(keys, res->d_records, domain, 300);
7708 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7709 addRRSIG(keys, res->d_records, domain, 300);
7710 }
7711 else {
7712 if (domain == target) {
7713 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7714 addRRSIG(keys, res->d_records, domain, 300);
7715 }
7716 else if (domain == targetCName) {
7717 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7718 addRRSIG(keys, res->d_records, domain, 300);
7719 }
7720 }
7721 return 1;
7722 }
7723 }
7724
7725 return 0;
7726 });
7727
7728 vector<DNSRecord> ret;
7729 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7730 BOOST_CHECK_EQUAL(res, RCode::NoError);
7731 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7732 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7733 BOOST_CHECK_EQUAL(queriesCount, 12);
7734
7735 /* again, to test the cache */
7736 ret.clear();
7737 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7738 BOOST_CHECK_EQUAL(res, RCode::NoError);
7739 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7740 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7741 BOOST_CHECK_EQUAL(queriesCount, 12);
7742 }
7743
7744 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7745 std::unique_ptr<SyncRes> sr;
7746 initSR(sr, true);
7747
7748 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7749
7750 primeHints();
7751 const DNSName target("powerdns.com.");
7752 const DNSName targetCName("power-dns.com.");
7753 const ComboAddress targetCNameAddr("192.0.2.42");
7754 testkeysset_t keys;
7755
7756 auto luaconfsCopy = g_luaconfs.getCopy();
7757 luaconfsCopy.dsAnchors.clear();
7758 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7759 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7760 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7761 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7762 g_luaconfs.setState(luaconfsCopy);
7763
7764 size_t queriesCount = 0;
7765
7766 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7767 queriesCount++;
7768
7769 if (type == QType::DS) {
7770 if (domain == DNSName("power-dns.com.")) {
7771 setLWResult(res, 0, false, false, true);
7772 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7773 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7774 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7775 return 1;
7776 }
7777 else {
7778 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7779 }
7780 }
7781 else if (type == QType::DNSKEY) {
7782 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7783 setLWResult(res, 0, true, false, true);
7784 addDNSKEY(keys, domain, 300, res->d_records);
7785 addRRSIG(keys, res->d_records, domain, 300);
7786 return 1;
7787 }
7788 else {
7789 setLWResult(res, 0, false, false, true);
7790 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7791 return 1;
7792 }
7793 }
7794 else {
7795 if (isRootServer(ip)) {
7796 setLWResult(res, 0, false, false, true);
7797 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7798 addDS(DNSName("com."), 300, res->d_records, keys);
7799 addRRSIG(keys, res->d_records, DNSName("."), 300);
7800 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7801 return 1;
7802 }
7803 else if (ip == ComboAddress("192.0.2.1:53")) {
7804 if (domain == DNSName("com.")) {
7805 setLWResult(res, 0, true, false, true);
7806 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7807 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7808 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7809 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7810 }
7811 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7812 setLWResult(res, 0, false, false, true);
7813 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7814 if (domain == DNSName("powerdns.com.")) {
7815 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7816 }
7817 else if (domain == targetCName) {
7818 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7819 }
7820 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7821 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7822 }
7823 return 1;
7824 }
7825 else if (ip == ComboAddress("192.0.2.2:53")) {
7826 setLWResult(res, 0, true, false, true);
7827 if (type == QType::NS) {
7828 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7829 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7830 }
7831 else {
7832 if (domain == DNSName("powerdns.com.")) {
7833 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7834 /* No RRSIG -> Bogus */
7835 }
7836 else if (domain == targetCName) {
7837 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7838 }
7839 }
7840 return 1;
7841 }
7842 }
7843
7844 return 0;
7845 });
7846
7847 vector<DNSRecord> ret;
7848 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7849 BOOST_CHECK_EQUAL(res, RCode::NoError);
7850 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7851 /* no RRSIG to show */
7852 BOOST_CHECK_EQUAL(ret.size(), 2);
7853 BOOST_CHECK_EQUAL(queriesCount, 10);
7854
7855 /* again, to test the cache */
7856 ret.clear();
7857 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7858 BOOST_CHECK_EQUAL(res, RCode::NoError);
7859 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7860 BOOST_CHECK_EQUAL(ret.size(), 2);
7861 BOOST_CHECK_EQUAL(queriesCount, 10);
7862 }
7863
7864 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7865 std::unique_ptr<SyncRes> sr;
7866 initSR(sr, true);
7867
7868 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7869
7870 primeHints();
7871 const DNSName target("powerdns.com.");
7872 const ComboAddress targetAddr("192.0.2.42");
7873 testkeysset_t keys;
7874
7875 auto luaconfsCopy = g_luaconfs.getCopy();
7876 luaconfsCopy.dsAnchors.clear();
7877 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7878 /* No key material for .com */
7879 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7880 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7881 g_luaconfs.setState(luaconfsCopy);
7882
7883 size_t queriesCount = 0;
7884
7885 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7886 queriesCount++;
7887
7888 if (type == QType::DNSKEY) {
7889 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7890 setLWResult(res, 0, true, false, true);
7891 addDNSKEY(keys, domain, 300, res->d_records);
7892 addRRSIG(keys, res->d_records, domain, 300);
7893 return 1;
7894 }
7895 else if (domain == DNSName("com.")) {
7896 setLWResult(res, 0, false, false, true);
7897 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7898 return 1;
7899 }
7900 }
7901 else {
7902 if (isRootServer(ip)) {
7903 setLWResult(res, 0, false, false, true);
7904 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7905 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7906 addRRSIG(keys, res->d_records, DNSName("."), 300);
7907 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7908 return 1;
7909 }
7910 else if (ip == ComboAddress("192.0.2.1:53")) {
7911 if (target == domain) {
7912 setLWResult(res, 0, false, false, true);
7913 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7914 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7915 }
7916 else if (domain == DNSName("com.")) {
7917 setLWResult(res, 0, true, false, true);
7918 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7919 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7920 }
7921 return 1;
7922 }
7923 else if (ip == ComboAddress("192.0.2.2:53")) {
7924 setLWResult(res, 0, true, false, true);
7925 if (type == QType::NS) {
7926 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7927 }
7928 else {
7929 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7930 }
7931 addRRSIG(keys, res->d_records, domain, 300);
7932 return 1;
7933 }
7934 }
7935
7936 return 0;
7937 });
7938
7939 vector<DNSRecord> ret;
7940 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7941 BOOST_CHECK_EQUAL(res, RCode::NoError);
7942 /* should be insecure but we have a TA for powerdns.com. */
7943 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7944 /* We got a RRSIG */
7945 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7946 BOOST_CHECK(ret[0].d_type == QType::A);
7947 BOOST_CHECK_EQUAL(queriesCount, 5);
7948
7949 /* again, to test the cache */
7950 ret.clear();
7951 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7952 BOOST_CHECK_EQUAL(res, RCode::NoError);
7953 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7954 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7955 BOOST_CHECK(ret[0].d_type == QType::A);
7956 BOOST_CHECK_EQUAL(queriesCount, 5);
7957 }
7958
7959 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
7960 std::unique_ptr<SyncRes> sr;
7961 initSR(sr, true);
7962
7963 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7964
7965 primeHints();
7966 const DNSName target("powerdns.com.");
7967 const ComboAddress targetAddr("192.0.2.42");
7968 testkeysset_t keys;
7969
7970 auto luaconfsCopy = g_luaconfs.getCopy();
7971 luaconfsCopy.dsAnchors.clear();
7972 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7973 /* No key material for .com */
7974 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7975 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7976 g_luaconfs.setState(luaconfsCopy);
7977
7978 size_t queriesCount = 0;
7979
7980 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
7981 queriesCount++;
7982
7983 if (type == QType::DNSKEY) {
7984 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7985 setLWResult(res, 0, true, false, true);
7986 addDNSKEY(keys, domain, 300, res->d_records);
7987 addRRSIG(keys, res->d_records, domain, 300);
7988 return 1;
7989 }
7990 else if (domain == DNSName("com.")) {
7991 setLWResult(res, 0, false, false, true);
7992 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7993 return 1;
7994 }
7995 }
7996 else {
7997 if (target.isPartOf(domain) && isRootServer(ip)) {
7998 setLWResult(res, 0, false, false, true);
7999 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8000 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
8001 addRRSIG(keys, res->d_records, DNSName("."), 300);
8002 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8003 return 1;
8004 }
8005 else if (ip == ComboAddress("192.0.2.1:53")) {
8006 if (target == domain) {
8007 setLWResult(res, 0, false, false, true);
8008 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8009 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8010 }
8011 else if (domain == DNSName("com.")) {
8012 setLWResult(res, 0, true, false, true);
8013 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
8014 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8015 }
8016 return 1;
8017 }
8018 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
8019 setLWResult(res, 0, true, false, true);
8020 if (type == QType::NS) {
8021 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8022 }
8023 else {
8024 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8025 }
8026 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
8027 return 1;
8028 }
8029 }
8030
8031 return 0;
8032 });
8033
8034 vector<DNSRecord> ret;
8035 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8036 BOOST_CHECK_EQUAL(res, RCode::NoError);
8037 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
8038 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8039 /* No RRSIG */
8040 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8041 BOOST_CHECK(ret[0].d_type == QType::A);
8042 BOOST_CHECK_EQUAL(queriesCount, 4);
8043
8044 /* again, to test the cache */
8045 ret.clear();
8046 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8047 BOOST_CHECK_EQUAL(res, RCode::NoError);
8048 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8049 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8050 BOOST_CHECK(ret[0].d_type == QType::A);
8051 BOOST_CHECK_EQUAL(queriesCount, 4);
8052 }
8053
8054 BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
8055 std::unique_ptr<SyncRes> sr;
8056 initSR(sr, true);
8057
8058 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8059
8060 primeHints();
8061 const DNSName target(".");
8062 testkeysset_t keys;
8063
8064 auto luaconfsCopy = g_luaconfs.getCopy();
8065 luaconfsCopy.dsAnchors.clear();
8066 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8067 /* Add a NTA for "." */
8068 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
8069 g_luaconfs.setState(luaconfsCopy);
8070
8071 size_t queriesCount = 0;
8072
8073 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8074 queriesCount++;
8075
8076 if (domain == target && type == QType::NS) {
8077
8078 setLWResult(res, 0, true, false, true);
8079 char addr[] = "a.root-servers.net.";
8080 for (char idx = 'a'; idx <= 'm'; idx++) {
8081 addr[0] = idx;
8082 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8083 }
8084
8085 addRRSIG(keys, res->d_records, domain, 300);
8086
8087 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8088 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8089
8090 return 1;
8091 } else if (domain == target && type == QType::DNSKEY) {
8092
8093 setLWResult(res, 0, true, false, true);
8094
8095 /* No DNSKEY */
8096
8097 return 1;
8098 }
8099
8100 return 0;
8101 });
8102
8103 vector<DNSRecord> ret;
8104 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8105 BOOST_CHECK_EQUAL(res, RCode::NoError);
8106 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8107 /* 13 NS + 1 RRSIG */
8108 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8109 BOOST_CHECK_EQUAL(queriesCount, 1);
8110
8111 /* again, to test the cache */
8112 ret.clear();
8113 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8114 BOOST_CHECK_EQUAL(res, RCode::NoError);
8115 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8116 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8117 BOOST_CHECK_EQUAL(queriesCount, 1);
8118 }
8119
8120 BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
8121 std::unique_ptr<SyncRes> sr;
8122 initSR(sr, true);
8123
8124 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8125
8126 primeHints();
8127 const DNSName target(".");
8128 testkeysset_t keys;
8129
8130 /* Remove the root DS */
8131 auto luaconfsCopy = g_luaconfs.getCopy();
8132 luaconfsCopy.dsAnchors.clear();
8133 g_luaconfs.setState(luaconfsCopy);
8134
8135 size_t queriesCount = 0;
8136
8137 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8138 queriesCount++;
8139
8140 if (domain == target && type == QType::NS) {
8141
8142 setLWResult(res, 0, true, false, true);
8143 char addr[] = "a.root-servers.net.";
8144 for (char idx = 'a'; idx <= 'm'; idx++) {
8145 addr[0] = idx;
8146 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8147 }
8148
8149 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8150 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8151
8152 return 1;
8153 }
8154
8155 return 0;
8156 });
8157
8158 vector<DNSRecord> ret;
8159 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8160 BOOST_CHECK_EQUAL(res, RCode::NoError);
8161 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8162 /* 13 NS + 0 RRSIG */
8163 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8164 BOOST_CHECK_EQUAL(queriesCount, 1);
8165
8166 /* again, to test the cache */
8167 ret.clear();
8168 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8169 BOOST_CHECK_EQUAL(res, RCode::NoError);
8170 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8171 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8172 BOOST_CHECK_EQUAL(queriesCount, 1);
8173 }
8174
8175 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
8176 std::unique_ptr<SyncRes> sr;
8177 initSR(sr, true);
8178
8179 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8180
8181 primeHints();
8182 const DNSName target("powerdns.com.");
8183 testkeysset_t keys;
8184
8185 auto luaconfsCopy = g_luaconfs.getCopy();
8186 luaconfsCopy.dsAnchors.clear();
8187 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8188 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8189 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8190 g_luaconfs.setState(luaconfsCopy);
8191
8192 size_t queriesCount = 0;
8193
8194 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8195 queriesCount++;
8196
8197 if (type == QType::DS || type == QType::DNSKEY) {
8198 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
8199 }
8200 else {
8201
8202 setLWResult(res, 0, true, false, true);
8203 return 1;
8204 }
8205
8206 return 0;
8207 });
8208
8209 vector<DNSRecord> ret;
8210 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8211 BOOST_CHECK_EQUAL(res, RCode::NoError);
8212 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8213 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8214 /* com|NS, powerdns.com|NS, powerdns.com|A */
8215 BOOST_CHECK_EQUAL(queriesCount, 3);
8216
8217 /* again, to test the cache */
8218 ret.clear();
8219 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8220 BOOST_CHECK_EQUAL(res, RCode::NoError);
8221 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8222 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8223 /* we don't store empty results */
8224 BOOST_CHECK_EQUAL(queriesCount, 4);
8225 }
8226
8227 BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
8228 init();
8229
8230 testkeysset_t keys;
8231 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8232
8233 vector<DNSRecord> records;
8234
8235 vector<shared_ptr<DNSRecordContent>> recordContents;
8236 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8237
8238 /*
8239 No wrap test case:
8240 a.example.org. -> d.example.org. denies the existence of b.example.org.
8241 */
8242 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8243 recordContents.push_back(records.at(0).d_content);
8244 addRRSIG(keys, records, DNSName("example.org."), 300);
8245 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8246 records.clear();
8247
8248 ContentSigPair pair;
8249 pair.records = recordContents;
8250 pair.signatures = signatureContents;
8251 cspmap_t denialMap;
8252 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8253
8254 /* add wildcard denial */
8255 recordContents.clear();
8256 signatureContents.clear();
8257 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8258 recordContents.push_back(records.at(0).d_content);
8259 addRRSIG(keys, records, DNSName("example.org."), 300);
8260 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8261 records.clear();
8262
8263 pair.records = recordContents;
8264 pair.signatures = signatureContents;
8265 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
8266
8267 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
8268 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8269
8270 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
8271 /* let's check that d.example.org. is not denied by this proof */
8272 BOOST_CHECK_EQUAL(denialState, NODATA);
8273 }
8274
8275 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
8276 init();
8277
8278 testkeysset_t keys;
8279 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8280
8281 vector<DNSRecord> records;
8282
8283 vector<shared_ptr<DNSRecordContent>> recordContents;
8284 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8285
8286 /*
8287 Wrap case 1 test case:
8288 z.example.org. -> b.example.org. denies the existence of a.example.org.
8289 */
8290 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8291 recordContents.push_back(records.at(0).d_content);
8292 addRRSIG(keys, records, DNSName("example.org."), 300);
8293 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8294 records.clear();
8295
8296 ContentSigPair pair;
8297 pair.records = recordContents;
8298 pair.signatures = signatureContents;
8299 cspmap_t denialMap;
8300 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
8301
8302 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
8303 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8304
8305 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
8306 /* let's check that d.example.org. is not denied by this proof */
8307 BOOST_CHECK_EQUAL(denialState, NODATA);
8308 }
8309
8310 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
8311 init();
8312
8313 testkeysset_t keys;
8314 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8315
8316 vector<DNSRecord> records;
8317
8318 vector<shared_ptr<DNSRecordContent>> recordContents;
8319 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8320
8321 /*
8322 Wrap case 2 test case:
8323 y.example.org. -> a.example.org. denies the existence of z.example.org.
8324 */
8325 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8326 recordContents.push_back(records.at(0).d_content);
8327 addRRSIG(keys, records, DNSName("example.org."), 300);
8328 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8329 records.clear();
8330
8331 ContentSigPair pair;
8332 pair.records = recordContents;
8333 pair.signatures = signatureContents;
8334 cspmap_t denialMap;
8335 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
8336
8337 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
8338 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8339
8340 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
8341 /* let's check that d.example.org. is not denied by this proof */
8342 BOOST_CHECK_EQUAL(denialState, NODATA);
8343 }
8344
8345 BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
8346 init();
8347
8348 testkeysset_t keys;
8349 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8350
8351 vector<DNSRecord> records;
8352
8353 vector<shared_ptr<DNSRecordContent>> recordContents;
8354 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8355
8356 /*
8357 Only one NSEC in the whole zone test case:
8358 a.example.org. -> a.example.org. denies the existence of b.example.org.
8359 */
8360 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8361 recordContents.push_back(records.at(0).d_content);
8362 addRRSIG(keys, records, DNSName("example.org."), 300);
8363 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8364 records.clear();
8365
8366 ContentSigPair pair;
8367 pair.records = recordContents;
8368 pair.signatures = signatureContents;
8369 cspmap_t denialMap;
8370 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8371
8372 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
8373 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8374
8375 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
8376 /* let's check that d.example.org. is not denied by this proof */
8377 BOOST_CHECK_EQUAL(denialState, NODATA);
8378 }
8379
8380 BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
8381 init();
8382
8383 testkeysset_t keys;
8384 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8385
8386 vector<DNSRecord> records;
8387
8388 vector<shared_ptr<DNSRecordContent>> recordContents;
8389 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8390
8391 /*
8392 The RRSIG from "." denies the existence of anything between a. and c.,
8393 including b.
8394 */
8395 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
8396 recordContents.push_back(records.at(0).d_content);
8397 addRRSIG(keys, records, DNSName("."), 300);
8398 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8399 records.clear();
8400
8401 ContentSigPair pair;
8402 pair.records = recordContents;
8403 pair.signatures = signatureContents;
8404 cspmap_t denialMap;
8405 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8406
8407 /* add wildcard denial */
8408 recordContents.clear();
8409 signatureContents.clear();
8410 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8411 recordContents.push_back(records.at(0).d_content);
8412 addRRSIG(keys, records, DNSName("."), 300);
8413 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8414 records.clear();
8415
8416 pair.records = recordContents;
8417 pair.signatures = signatureContents;
8418 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
8419
8420 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
8421 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8422 }
8423
8424 BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
8425 init();
8426
8427 testkeysset_t keys;
8428 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8429
8430 vector<DNSRecord> records;
8431
8432 vector<shared_ptr<DNSRecordContent>> recordContents;
8433 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8434
8435 /*
8436 The RRSIG from "." denies the existence of any type except NS at a.
8437 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8438 signer field that is shorter than the owner name of the NSEC RR) it can't
8439 be used to deny anything except the whole name or a DS.
8440 */
8441 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
8442 recordContents.push_back(records.at(0).d_content);
8443 addRRSIG(keys, records, DNSName("."), 300);
8444 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8445 records.clear();
8446
8447 ContentSigPair pair;
8448 pair.records = recordContents;
8449 pair.signatures = signatureContents;
8450 cspmap_t denialMap;
8451 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8452
8453 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8454 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8455 nonexistence of any RRs below that zone cut, which include all RRs at
8456 that (original) owner name other than DS RRs, and all RRs below that
8457 owner name regardless of type.
8458 */
8459
8460 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
8461 /* no data means the qname/qtype is not denied, because an ancestor
8462 delegation NSEC can only deny the DS */
8463 BOOST_CHECK_EQUAL(denialState, NODATA);
8464
8465 /* it can not be used to deny any RRs below that owner name either */
8466 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false);
8467 BOOST_CHECK_EQUAL(denialState, NODATA);
8468
8469 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8470 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8471 }
8472
8473 BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
8474 init();
8475
8476 testkeysset_t keys;
8477 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8478
8479 vector<DNSRecord> records;
8480
8481 vector<shared_ptr<DNSRecordContent>> recordContents;
8482 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8483
8484 /*
8485 * RFC 5155 section 8.9:
8486 * If there is an NSEC3 RR present in the response that matches the
8487 * delegation name, then the validator MUST ensure that the NS bit is
8488 * set and that the DS bit is not set in the Type Bit Maps field of the
8489 * NSEC3 RR.
8490 */
8491 /*
8492 The RRSIG from "." denies the existence of any type at a.
8493 NS should be set if it was proving an insecure delegation, let's check that
8494 we correctly detect that it's not.
8495 */
8496 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
8497 recordContents.push_back(records.at(0).d_content);
8498 addRRSIG(keys, records, DNSName("."), 300);
8499 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8500 records.clear();
8501
8502 ContentSigPair pair;
8503 pair.records = recordContents;
8504 pair.signatures = signatureContents;
8505 cspmap_t denialMap;
8506 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8507
8508 /* Insecure because the NS is not set, so while it does
8509 denies the DS, it can't prove an insecure delegation */
8510 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8511 BOOST_CHECK_EQUAL(denialState, NODATA);
8512 }
8513
8514 BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
8515 init();
8516
8517 testkeysset_t keys;
8518 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8519
8520 vector<DNSRecord> records;
8521
8522 vector<shared_ptr<DNSRecordContent>> recordContents;
8523 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8524
8525 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
8526 recordContents.push_back(records.at(0).d_content);
8527 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8528 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8529 records.clear();
8530
8531 ContentSigPair pair;
8532 pair.records = recordContents;
8533 pair.signatures = signatureContents;
8534 cspmap_t denialMap;
8535 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8536
8537 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8538 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
8539 BOOST_CHECK_EQUAL(denialState, NODATA);
8540 }
8541
8542 BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
8543 init();
8544
8545 testkeysset_t keys;
8546 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8547
8548 vector<DNSRecord> records;
8549
8550 vector<shared_ptr<DNSRecordContent>> recordContents;
8551 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8552
8553 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
8554 recordContents.push_back(records.at(0).d_content);
8555 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8556 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8557
8558 ContentSigPair pair;
8559 pair.records = recordContents;
8560 pair.signatures = signatureContents;
8561 cspmap_t denialMap;
8562 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8563 records.clear();
8564
8565 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8566 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8567 BOOST_CHECK_EQUAL(denialState, NODATA);
8568 }
8569
8570 BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8571 init();
8572
8573 testkeysset_t keys;
8574 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8575
8576 vector<DNSRecord> records;
8577
8578 vector<shared_ptr<DNSRecordContent>> recordContents;
8579 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8580
8581 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8582 recordContents.push_back(records.at(0).d_content);
8583 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8584 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8585 records.clear();
8586
8587 ContentSigPair pair;
8588 pair.records = recordContents;
8589 pair.signatures = signatureContents;
8590 cspmap_t denialMap;
8591 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8592
8593 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8594 BOOST_CHECK_EQUAL(denialState, NODATA);
8595 }
8596
8597 BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
8598 init();
8599
8600 testkeysset_t keys;
8601 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8602
8603 vector<DNSRecord> records;
8604
8605 vector<shared_ptr<DNSRecordContent>> recordContents;
8606 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8607
8608 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8609 recordContents.push_back(records.at(0).d_content);
8610 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8611 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8612
8613 ContentSigPair pair;
8614 pair.records = recordContents;
8615 pair.signatures = signatureContents;
8616 cspmap_t denialMap;
8617 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8618
8619 /* Add NSEC3 for the closest encloser */
8620 recordContents.clear();
8621 signatureContents.clear();
8622 records.clear();
8623 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8624 recordContents.push_back(records.at(0).d_content);
8625 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8626 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8627
8628 pair.records = recordContents;
8629 pair.signatures = signatureContents;
8630 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8631
8632 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8633 BOOST_CHECK_EQUAL(denialState, NODATA);
8634 }
8635
8636 BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8637 init();
8638
8639 testkeysset_t keys;
8640 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8641
8642 vector<DNSRecord> records;
8643
8644 vector<shared_ptr<DNSRecordContent>> recordContents;
8645 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8646
8647 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8648 recordContents.push_back(records.at(0).d_content);
8649 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8650 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8651 records.clear();
8652
8653 ContentSigPair pair;
8654 pair.records = recordContents;
8655 pair.signatures = signatureContents;
8656 cspmap_t denialMap;
8657 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8658
8659 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
8660 it is an ENT */
8661 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
8662 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8663
8664 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8665 it could prove a NXDOMAIN if it had an additional wildcard denial */
8666 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8667 BOOST_CHECK_EQUAL(denialState, NODATA);
8668
8669 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8670 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8671 BOOST_CHECK_EQUAL(denialState, NODATA);
8672
8673 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8674 recordContents.clear();
8675 signatureContents.clear();
8676 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8677 recordContents.push_back(records.at(0).d_content);
8678 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8679 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8680 records.clear();
8681 pair.records = recordContents;
8682 pair.signatures = signatureContents;
8683 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8684
8685 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
8686 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8687 }
8688
8689 BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8690 init();
8691
8692 testkeysset_t keys;
8693 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8694
8695 vector<DNSRecord> records;
8696
8697 vector<shared_ptr<DNSRecordContent>> recordContents;
8698 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8699
8700 /*
8701 The RRSIG from "." denies the existence of any type except NS at a.
8702 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8703 signer field that is shorter than the owner name of the NSEC RR) it can't
8704 be used to deny anything except the whole name or a DS.
8705 */
8706 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
8707 recordContents.push_back(records.at(0).d_content);
8708 addRRSIG(keys, records, DNSName("."), 300);
8709 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8710
8711 ContentSigPair pair;
8712 pair.records = recordContents;
8713 pair.signatures = signatureContents;
8714 cspmap_t denialMap;
8715 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8716 records.clear();
8717
8718 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8719 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8720 nonexistence of any RRs below that zone cut, which include all RRs at
8721 that (original) owner name other than DS RRs, and all RRs below that
8722 owner name regardless of type.
8723 */
8724
8725 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8726 /* no data means the qname/qtype is not denied, because an ancestor
8727 delegation NSEC3 can only deny the DS */
8728 BOOST_CHECK_EQUAL(denialState, NODATA);
8729
8730 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8731 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8732
8733 /* it can not be used to deny any RRs below that owner name either */
8734 /* Add NSEC3 for the next closer */
8735 recordContents.clear();
8736 signatureContents.clear();
8737 records.clear();
8738 addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8739 recordContents.push_back(records.at(0).d_content);
8740 addRRSIG(keys, records, DNSName("."), 300);
8741 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8742
8743 pair.records = recordContents;
8744 pair.signatures = signatureContents;
8745 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8746
8747 /* add wildcard denial */
8748 recordContents.clear();
8749 signatureContents.clear();
8750 records.clear();
8751 addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8752 recordContents.push_back(records.at(0).d_content);
8753 addRRSIG(keys, records, DNSName("."), 300);
8754 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8755
8756 pair.records = recordContents;
8757 pair.signatures = signatureContents;
8758 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8759
8760 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true);
8761 BOOST_CHECK_EQUAL(denialState, NODATA);
8762 }
8763
8764 BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8765 init();
8766
8767 testkeysset_t keys;
8768 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8769
8770 vector<DNSRecord> records;
8771
8772 vector<shared_ptr<DNSRecordContent>> recordContents;
8773 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8774
8775 /* adding a NSEC3 with more iterations that we support */
8776 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8777 recordContents.push_back(records.at(0).d_content);
8778 addRRSIG(keys, records, DNSName("."), 300);
8779 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8780
8781 ContentSigPair pair;
8782 pair.records = recordContents;
8783 pair.signatures = signatureContents;
8784 cspmap_t denialMap;
8785 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8786 records.clear();
8787
8788 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8789 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8790 BOOST_CHECK_EQUAL(denialState, INSECURE);
8791 }
8792
8793 BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8794 init();
8795
8796 testkeysset_t keys;
8797 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8798
8799 vector<DNSRecord> records;
8800
8801 vector<shared_ptr<DNSRecordContent>> recordContents;
8802 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8803
8804 /*
8805 * RFC 5155 section 8.9:
8806 * If there is an NSEC3 RR present in the response that matches the
8807 * delegation name, then the validator MUST ensure that the NS bit is
8808 * set and that the DS bit is not set in the Type Bit Maps field of the
8809 * NSEC3 RR.
8810 */
8811 /*
8812 The RRSIG from "." denies the existence of any type at a.
8813 NS should be set if it was proving an insecure delegation, let's check that
8814 we correctly detect that it's not.
8815 */
8816 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
8817 recordContents.push_back(records.at(0).d_content);
8818 addRRSIG(keys, records, DNSName("."), 300);
8819 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8820
8821 ContentSigPair pair;
8822 pair.records = recordContents;
8823 pair.signatures = signatureContents;
8824 cspmap_t denialMap;
8825 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8826 records.clear();
8827
8828 /* Insecure because the NS is not set, so while it does
8829 denies the DS, it can't prove an insecure delegation */
8830 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8831 BOOST_CHECK_EQUAL(denialState, NODATA);
8832 }
8833
8834 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8835 std::unique_ptr<SyncRes> sr;
8836 initSR(sr, true);
8837
8838 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8839
8840 primeHints();
8841 const DNSName target("com.");
8842 testkeysset_t keys;
8843
8844 auto luaconfsCopy = g_luaconfs.getCopy();
8845 luaconfsCopy.dsAnchors.clear();
8846 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8847 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8848 g_luaconfs.setState(luaconfsCopy);
8849
8850 size_t queriesCount = 0;
8851
8852 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8853 queriesCount++;
8854
8855 DNSName auth = domain;
8856 auth.chopOff();
8857
8858 if (type == QType::DS || type == QType::DNSKEY) {
8859 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8860 }
8861 else {
8862 setLWResult(res, RCode::NoError, true, false, true);
8863 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8864 addRRSIG(keys, res->d_records, domain, 300);
8865 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8866 addRRSIG(keys, res->d_records, domain, 1);
8867 return 1;
8868 }
8869
8870 return 0;
8871 });
8872
8873 const time_t now = sr->getNow().tv_sec;
8874 vector<DNSRecord> ret;
8875 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8876 BOOST_CHECK_EQUAL(res, RCode::NoError);
8877 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8878 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8879 BOOST_CHECK_EQUAL(queriesCount, 4);
8880
8881 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
8882 NegCache::NegCacheEntry ne;
8883 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8884 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8885 BOOST_CHECK_EQUAL(ne.d_ttd, now + 1);
8886 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
8887 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8888 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8889 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8890 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
8891
8892 /* again, to test the cache */
8893 ret.clear();
8894 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8895 BOOST_CHECK_EQUAL(res, RCode::NoError);
8896 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8897 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8898 BOOST_CHECK_EQUAL(queriesCount, 4);
8899 }
8900
8901 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
8902 std::unique_ptr<SyncRes> sr;
8903 initSR(sr, true);
8904
8905 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8906
8907 primeHints();
8908 const DNSName target("com.");
8909 const ComboAddress targetAddr("192.0.2.42");
8910 testkeysset_t keys;
8911
8912 auto luaconfsCopy = g_luaconfs.getCopy();
8913 luaconfsCopy.dsAnchors.clear();
8914 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8915 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8916 g_luaconfs.setState(luaconfsCopy);
8917
8918 size_t queriesCount = 0;
8919
8920 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8921 queriesCount++;
8922
8923 DNSName auth = domain;
8924 auth.chopOff();
8925
8926 if (type == QType::DS || type == QType::DNSKEY) {
8927 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8928 }
8929 else {
8930 setLWResult(res, RCode::NoError, true, false, true);
8931 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8932 addRRSIG(keys, res->d_records, domain, 1);
8933 return 1;
8934 }
8935
8936 return 0;
8937 });
8938
8939 const time_t now = sr->getNow().tv_sec;
8940 vector<DNSRecord> ret;
8941 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8942 BOOST_CHECK_EQUAL(res, RCode::NoError);
8943 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8944 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8945 BOOST_CHECK_EQUAL(queriesCount, 4);
8946
8947 /* check that the entry has not been cached for longer than the RRSIG validity */
8948 const ComboAddress who;
8949 vector<DNSRecord> cached;
8950 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
8951 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
8952 BOOST_REQUIRE_EQUAL(cached.size(), 1);
8953 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
8954 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
8955
8956 /* again, to test the cache */
8957 ret.clear();
8958 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8959 BOOST_CHECK_EQUAL(res, RCode::NoError);
8960 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8961 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8962 BOOST_CHECK_EQUAL(queriesCount, 4);
8963 }
8964
8965 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
8966 /*
8967 Validation is optional, and the first query does not ask for it,
8968 so the answer is cached as Indeterminate.
8969 The second query asks for validation, answer should be marked as
8970 Secure.
8971 */
8972 std::unique_ptr<SyncRes> sr;
8973 initSR(sr, true);
8974
8975 setDNSSECValidation(sr, DNSSECMode::Process);
8976
8977 primeHints();
8978 const DNSName target("com.");
8979 testkeysset_t keys;
8980
8981 auto luaconfsCopy = g_luaconfs.getCopy();
8982 luaconfsCopy.dsAnchors.clear();
8983 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8984 g_luaconfs.setState(luaconfsCopy);
8985
8986 size_t queriesCount = 0;
8987
8988 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8989 queriesCount++;
8990
8991 if (type == QType::DS || type == QType::DNSKEY) {
8992 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8993 }
8994 else {
8995 if (domain == target && type == QType::A) {
8996 setLWResult(res, 0, true, false, true);
8997 addRecordToLW(res, target, QType::A, "192.0.2.1");
8998 addRRSIG(keys, res->d_records, DNSName("."), 300);
8999 return 1;
9000 }
9001 }
9002
9003 return 0;
9004 });
9005
9006 vector<DNSRecord> ret;
9007 /* first query does not require validation */
9008 sr->setDNSSECValidationRequested(false);
9009 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9010 BOOST_CHECK_EQUAL(res, RCode::NoError);
9011 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9012 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9013 for (const auto& record : ret) {
9014 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
9015 }
9016 BOOST_CHECK_EQUAL(queriesCount, 1);
9017
9018
9019 ret.clear();
9020 /* second one _does_ require validation */
9021 sr->setDNSSECValidationRequested(true);
9022 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9023 BOOST_CHECK_EQUAL(res, RCode::NoError);
9024 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9025 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9026 for (const auto& record : ret) {
9027 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
9028 }
9029 BOOST_CHECK_EQUAL(queriesCount, 3);
9030 }
9031
9032 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
9033 /*
9034 Validation is optional, and the first query does not ask for it,
9035 so the answer is cached as Indeterminate.
9036 The second query asks for validation, answer should be marked as
9037 Insecure.
9038 */
9039 std::unique_ptr<SyncRes> sr;
9040 initSR(sr, true);
9041
9042 setDNSSECValidation(sr, DNSSECMode::Process);
9043
9044 primeHints();
9045 const DNSName target("com.");
9046 testkeysset_t keys;
9047
9048 auto luaconfsCopy = g_luaconfs.getCopy();
9049 luaconfsCopy.dsAnchors.clear();
9050 g_luaconfs.setState(luaconfsCopy);
9051
9052 size_t queriesCount = 0;
9053
9054 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9055 queriesCount++;
9056
9057 if (type == QType::DS || type == QType::DNSKEY) {
9058 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9059 }
9060 else {
9061 if (domain == target && type == QType::A) {
9062 setLWResult(res, 0, true, false, true);
9063 addRecordToLW(res, target, QType::A, "192.0.2.1");
9064 return 1;
9065 }
9066 }
9067
9068 return 0;
9069 });
9070
9071 vector<DNSRecord> ret;
9072 /* first query does not require validation */
9073 sr->setDNSSECValidationRequested(false);
9074 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9075 BOOST_CHECK_EQUAL(res, RCode::NoError);
9076 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9077 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9078 for (const auto& record : ret) {
9079 BOOST_CHECK(record.d_type == QType::A);
9080 }
9081 BOOST_CHECK_EQUAL(queriesCount, 1);
9082
9083
9084 ret.clear();
9085 /* second one _does_ require validation */
9086 sr->setDNSSECValidationRequested(true);
9087 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9088 BOOST_CHECK_EQUAL(res, RCode::NoError);
9089 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9090 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9091 for (const auto& record : ret) {
9092 BOOST_CHECK(record.d_type == QType::A);
9093 }
9094 BOOST_CHECK_EQUAL(queriesCount, 1);
9095 }
9096
9097 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
9098 /*
9099 Validation is optional, and the first query does not ask for it,
9100 so the answer is cached as Indeterminate.
9101 The second query asks for validation, answer should be marked as
9102 Bogus.
9103 */
9104 std::unique_ptr<SyncRes> sr;
9105 initSR(sr, true);
9106
9107 setDNSSECValidation(sr, DNSSECMode::Process);
9108
9109 primeHints();
9110 const DNSName target("com.");
9111 testkeysset_t keys;
9112
9113 auto luaconfsCopy = g_luaconfs.getCopy();
9114 luaconfsCopy.dsAnchors.clear();
9115 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9116 g_luaconfs.setState(luaconfsCopy);
9117
9118 size_t queriesCount = 0;
9119
9120 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9121 queriesCount++;
9122
9123 if (type == QType::DS || type == QType::DNSKEY) {
9124 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9125 }
9126 else {
9127 if (domain == target && type == QType::A) {
9128 setLWResult(res, 0, true, false, true);
9129 addRecordToLW(res, target, QType::A, "192.0.2.1");
9130 /* no RRSIG */
9131 return 1;
9132 }
9133 }
9134
9135 return 0;
9136 });
9137
9138 vector<DNSRecord> ret;
9139 /* first query does not require validation */
9140 sr->setDNSSECValidationRequested(false);
9141 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9142 BOOST_CHECK_EQUAL(res, RCode::NoError);
9143 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9144 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9145 for (const auto& record : ret) {
9146 BOOST_CHECK(record.d_type == QType::A);
9147 }
9148 BOOST_CHECK_EQUAL(queriesCount, 1);
9149
9150
9151 ret.clear();
9152 /* second one _does_ require validation */
9153 sr->setDNSSECValidationRequested(true);
9154 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9155 BOOST_CHECK_EQUAL(res, RCode::NoError);
9156 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9157 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9158 for (const auto& record : ret) {
9159 BOOST_CHECK(record.d_type == QType::A);
9160 }
9161 BOOST_CHECK_EQUAL(queriesCount, 3);
9162 }
9163
9164 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
9165 /*
9166 Validation is optional, and the first query does not ask for it,
9167 so the answer is cached as Indeterminate.
9168 The second query asks for validation, answer should be marked as
9169 Secure.
9170 */
9171 std::unique_ptr<SyncRes> sr;
9172 initSR(sr, true);
9173
9174 setDNSSECValidation(sr, DNSSECMode::Process);
9175
9176 primeHints();
9177 const DNSName target("com.");
9178 const DNSName cnameTarget("cname-com.");
9179 testkeysset_t keys;
9180
9181 auto luaconfsCopy = g_luaconfs.getCopy();
9182 luaconfsCopy.dsAnchors.clear();
9183 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9184 g_luaconfs.setState(luaconfsCopy);
9185
9186 size_t queriesCount = 0;
9187
9188 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9189 queriesCount++;
9190
9191 if (type == QType::DS || type == QType::DNSKEY) {
9192 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9193 }
9194 else {
9195 if (domain == target && type == QType::A) {
9196 setLWResult(res, 0, true, false, true);
9197 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9198 addRRSIG(keys, res->d_records, DNSName("."), 300);
9199 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9200 addRRSIG(keys, res->d_records, DNSName("."), 300);
9201 return 1;
9202 } else if (domain == cnameTarget && type == QType::A) {
9203 setLWResult(res, 0, true, false, true);
9204 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9205 addRRSIG(keys, res->d_records, DNSName("."), 300);
9206 return 1;
9207 }
9208 }
9209
9210 return 0;
9211 });
9212
9213 vector<DNSRecord> ret;
9214 /* first query does not require validation */
9215 sr->setDNSSECValidationRequested(false);
9216 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9217 BOOST_CHECK_EQUAL(res, RCode::NoError);
9218 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9219 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9220 for (const auto& record : ret) {
9221 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9222 }
9223 BOOST_CHECK_EQUAL(queriesCount, 2);
9224
9225
9226 ret.clear();
9227 /* second one _does_ require validation */
9228 sr->setDNSSECValidationRequested(true);
9229 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9230 BOOST_CHECK_EQUAL(res, RCode::NoError);
9231 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9232 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9233 for (const auto& record : ret) {
9234 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9235 }
9236 BOOST_CHECK_EQUAL(queriesCount, 5);
9237 }
9238
9239 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
9240 /*
9241 Validation is optional, and the first query does not ask for it,
9242 so the answer is cached as Indeterminate.
9243 The second query asks for validation, answer should be marked as
9244 Insecure.
9245 */
9246 std::unique_ptr<SyncRes> sr;
9247 initSR(sr, true);
9248
9249 setDNSSECValidation(sr, DNSSECMode::Process);
9250
9251 primeHints();
9252 const DNSName target("com.");
9253 const DNSName cnameTarget("cname-com.");
9254 testkeysset_t keys;
9255
9256 auto luaconfsCopy = g_luaconfs.getCopy();
9257 luaconfsCopy.dsAnchors.clear();
9258 g_luaconfs.setState(luaconfsCopy);
9259
9260 size_t queriesCount = 0;
9261
9262 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9263 queriesCount++;
9264
9265 if (type == QType::DS || type == QType::DNSKEY) {
9266 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9267 }
9268 else {
9269 if (domain == target && type == QType::A) {
9270 setLWResult(res, 0, true, false, true);
9271 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9272 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9273 return 1;
9274 } else if (domain == cnameTarget && type == QType::A) {
9275 setLWResult(res, 0, true, false, true);
9276 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9277 return 1;
9278 }
9279 }
9280
9281 return 0;
9282 });
9283
9284 vector<DNSRecord> ret;
9285 /* first query does not require validation */
9286 sr->setDNSSECValidationRequested(false);
9287 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9288 BOOST_CHECK_EQUAL(res, RCode::NoError);
9289 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9290 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9291 for (const auto& record : ret) {
9292 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9293 }
9294 BOOST_CHECK_EQUAL(queriesCount, 2);
9295
9296
9297 ret.clear();
9298 /* second one _does_ require validation */
9299 sr->setDNSSECValidationRequested(true);
9300 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9301 BOOST_CHECK_EQUAL(res, RCode::NoError);
9302 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9303 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9304 for (const auto& record : ret) {
9305 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9306 }
9307 BOOST_CHECK_EQUAL(queriesCount, 2);
9308 }
9309
9310 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
9311 /*
9312 Validation is optional, and the first query does not ask for it,
9313 so the answer is cached as Indeterminate.
9314 The second query asks for validation, answer should be marked as
9315 Bogus.
9316 */
9317 std::unique_ptr<SyncRes> sr;
9318 initSR(sr, true);
9319
9320 setDNSSECValidation(sr, DNSSECMode::Process);
9321
9322 primeHints();
9323 const DNSName target("com.");
9324 const DNSName cnameTarget("cname-com.");
9325 testkeysset_t keys;
9326
9327 auto luaconfsCopy = g_luaconfs.getCopy();
9328 luaconfsCopy.dsAnchors.clear();
9329 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9330 g_luaconfs.setState(luaconfsCopy);
9331
9332 size_t queriesCount = 0;
9333
9334 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9335 queriesCount++;
9336
9337 if (type == QType::DS || type == QType::DNSKEY) {
9338 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9339 }
9340 else {
9341 if (domain == target && type == QType::A) {
9342 setLWResult(res, 0, true, false, true);
9343 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9344 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9345 /* no RRSIG */
9346 return 1;
9347 } else if (domain == cnameTarget && type == QType::A) {
9348 setLWResult(res, 0, true, false, true);
9349 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9350 /* no RRSIG */
9351 return 1;
9352 }
9353 }
9354
9355 return 0;
9356 });
9357
9358 vector<DNSRecord> ret;
9359 /* first query does not require validation */
9360 sr->setDNSSECValidationRequested(false);
9361 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9362 BOOST_CHECK_EQUAL(res, RCode::NoError);
9363 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9364 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9365 for (const auto& record : ret) {
9366 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9367 }
9368 BOOST_CHECK_EQUAL(queriesCount, 2);
9369
9370
9371 ret.clear();
9372 /* second one _does_ require validation */
9373 sr->setDNSSECValidationRequested(true);
9374 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9375 BOOST_CHECK_EQUAL(res, RCode::NoError);
9376 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9377 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9378 for (const auto& record : ret) {
9379 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9380 }
9381 BOOST_CHECK_EQUAL(queriesCount, 5);
9382 }
9383
9384 BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) {
9385 /*
9386 We get a record from a secure zone in the additional section, without
9387 the corresponding RRSIG. The record should not be marked as authoritative
9388 and should be correctly validated.
9389 */
9390 std::unique_ptr<SyncRes> sr;
9391 initSR(sr, true);
9392
9393 setDNSSECValidation(sr, DNSSECMode::Process);
9394
9395 primeHints();
9396 const DNSName target("com.");
9397 const DNSName addTarget("nsX.com.");
9398 testkeysset_t keys;
9399
9400 auto luaconfsCopy = g_luaconfs.getCopy();
9401 luaconfsCopy.dsAnchors.clear();
9402 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9403 g_luaconfs.setState(luaconfsCopy);
9404
9405 size_t queriesCount = 0;
9406
9407 sr->setAsyncCallback([target,addTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9408 queriesCount++;
9409
9410 if (type == QType::DS || type == QType::DNSKEY) {
9411 if (domain == addTarget) {
9412 DNSName auth(domain);
9413 /* no DS for com, auth will be . */
9414 auth.chopOff();
9415 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false);
9416 }
9417 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9418 }
9419 else {
9420 if (domain == target && type == QType::A) {
9421 setLWResult(res, 0, true, false, true);
9422 addRecordToLW(res, target, QType::A, "192.0.2.1");
9423 addRRSIG(keys, res->d_records, DNSName("."), 300);
9424 addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL);
9425 /* no RRSIG for the additional record */
9426 return 1;
9427 } else if (domain == addTarget && type == QType::A) {
9428 setLWResult(res, 0, true, false, true);
9429 addRecordToLW(res, addTarget, QType::A, "192.0.2.42");
9430 addRRSIG(keys, res->d_records, DNSName("."), 300);
9431 return 1;
9432 }
9433 }
9434
9435 return 0;
9436 });
9437
9438 vector<DNSRecord> ret;
9439 /* first query for target/A, will pick up the additional record as non-auth / unvalidated */
9440 sr->setDNSSECValidationRequested(false);
9441 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9442 BOOST_CHECK_EQUAL(res, RCode::NoError);
9443 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9444 BOOST_CHECK_EQUAL(ret.size(), 2);
9445 for (const auto& record : ret) {
9446 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9447 }
9448 BOOST_CHECK_EQUAL(queriesCount, 1);
9449
9450 ret.clear();
9451 /* ask for the additional record directly, we should not use
9452 the non-auth one and issue a new query, properly validated */
9453 sr->setDNSSECValidationRequested(true);
9454 res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret);
9455 BOOST_CHECK_EQUAL(res, RCode::NoError);
9456 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9457 BOOST_CHECK_EQUAL(ret.size(), 2);
9458 for (const auto& record : ret) {
9459 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9460 }
9461 BOOST_CHECK_EQUAL(queriesCount, 5);
9462 }
9463
9464 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
9465 /*
9466 Validation is optional, and the first query does not ask for it,
9467 so the answer is negatively cached as Indeterminate.
9468 The second query asks for validation, answer should be marked as
9469 Secure.
9470 */
9471 std::unique_ptr<SyncRes> sr;
9472 initSR(sr, true);
9473
9474 setDNSSECValidation(sr, DNSSECMode::Process);
9475
9476 primeHints();
9477 const DNSName target("com.");
9478 testkeysset_t keys;
9479
9480 auto luaconfsCopy = g_luaconfs.getCopy();
9481 luaconfsCopy.dsAnchors.clear();
9482 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9483 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9484 g_luaconfs.setState(luaconfsCopy);
9485
9486 size_t queriesCount = 0;
9487
9488 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9489 queriesCount++;
9490
9491 DNSName auth = domain;
9492 auth.chopOff();
9493
9494 if (type == QType::DS || type == QType::DNSKEY) {
9495 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9496 }
9497 else {
9498 setLWResult(res, RCode::NoError, true, false, true);
9499 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9500 addRRSIG(keys, res->d_records, domain, 300);
9501 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
9502 addRRSIG(keys, res->d_records, domain, 1);
9503 return 1;
9504 }
9505
9506 return 0;
9507 });
9508
9509 vector<DNSRecord> ret;
9510 /* first query does not require validation */
9511 sr->setDNSSECValidationRequested(false);
9512 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9513 BOOST_CHECK_EQUAL(res, RCode::NoError);
9514 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9515 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9516 BOOST_CHECK_EQUAL(queriesCount, 1);
9517 /* check that the entry has not been negatively cached */
9518 NegCache::NegCacheEntry ne;
9519 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9520 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9521 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9522 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9523 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9524 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9525 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
9526
9527 ret.clear();
9528 /* second one _does_ require validation */
9529 sr->setDNSSECValidationRequested(true);
9530 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9531 BOOST_CHECK_EQUAL(res, RCode::NoError);
9532 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9533 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9534 BOOST_CHECK_EQUAL(queriesCount, 4);
9535 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9536 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9537 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
9538 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9539 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9540 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9541 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
9542 }
9543
9544 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
9545 /*
9546 Validation is optional, and the first query does not ask for it,
9547 so the answer is negatively cached as Indeterminate.
9548 The second query asks for validation, answer should be marked as
9549 Secure.
9550 The difference with test_dnssec_validation_from_negcache_secure is
9551 that have one more level here, so we are going to look for the proof
9552 that the DS does not exist for the last level. Since there is no cut,
9553 we should accept the fact that the NSEC denies DS and NS both.
9554 */
9555 std::unique_ptr<SyncRes> sr;
9556 initSR(sr, true);
9557
9558 setDNSSECValidation(sr, DNSSECMode::Process);
9559
9560 primeHints();
9561 const DNSName target("www.com.");
9562 testkeysset_t keys;
9563
9564 auto luaconfsCopy = g_luaconfs.getCopy();
9565 luaconfsCopy.dsAnchors.clear();
9566 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9567 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9568 g_luaconfs.setState(luaconfsCopy);
9569
9570 size_t queriesCount = 0;
9571
9572 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9573 queriesCount++;
9574
9575 if (type == QType::DS || type == QType::DNSKEY) {
9576 if (domain == target) {
9577 /* there is no cut */
9578 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9579 }
9580 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
9581 }
9582
9583 return 0;
9584 });
9585
9586 vector<DNSRecord> ret;
9587 /* first query does not require validation */
9588 sr->setDNSSECValidationRequested(false);
9589 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9590 BOOST_CHECK_EQUAL(res, RCode::NoError);
9591 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9592 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9593 BOOST_CHECK_EQUAL(queriesCount, 1);
9594
9595 ret.clear();
9596 /* second one _does_ require validation */
9597 sr->setDNSSECValidationRequested(true);
9598 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9599 BOOST_CHECK_EQUAL(res, RCode::NoError);
9600 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9601 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9602 BOOST_CHECK_EQUAL(queriesCount, 4);
9603 }
9604
9605 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
9606 /*
9607 Validation is optional, and the first query does not ask for it,
9608 so the answer is negatively cached as Indeterminate.
9609 The second query asks for validation, answer should be marked as
9610 Insecure.
9611 */
9612 std::unique_ptr<SyncRes> sr;
9613 initSR(sr, true);
9614
9615 setDNSSECValidation(sr, DNSSECMode::Process);
9616
9617 primeHints();
9618 const DNSName target("com.");
9619 testkeysset_t keys;
9620
9621 auto luaconfsCopy = g_luaconfs.getCopy();
9622 luaconfsCopy.dsAnchors.clear();
9623 g_luaconfs.setState(luaconfsCopy);
9624
9625 size_t queriesCount = 0;
9626
9627 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9628 queriesCount++;
9629
9630 DNSName auth = domain;
9631 auth.chopOff();
9632
9633 if (type == QType::DS || type == QType::DNSKEY) {
9634 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9635 }
9636 else {
9637 setLWResult(res, RCode::NoError, true, false, true);
9638 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9639 return 1;
9640 }
9641
9642 return 0;
9643 });
9644
9645 vector<DNSRecord> ret;
9646 /* first query does not require validation */
9647 sr->setDNSSECValidationRequested(false);
9648 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9649 BOOST_CHECK_EQUAL(res, RCode::NoError);
9650 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9651 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9652 BOOST_CHECK_EQUAL(queriesCount, 1);
9653 /* check that the entry has not been negatively cached */
9654 NegCache::NegCacheEntry ne;
9655 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9656 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9657 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9658 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9659 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9660 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9661 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9662
9663 ret.clear();
9664 /* second one _does_ require validation */
9665 sr->setDNSSECValidationRequested(true);
9666 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9667 BOOST_CHECK_EQUAL(res, RCode::NoError);
9668 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9669 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9670 BOOST_CHECK_EQUAL(queriesCount, 1);
9671 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9672 BOOST_CHECK_EQUAL(ne.d_validationState, Insecure);
9673 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9674 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9675 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9676 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9677 }
9678
9679 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
9680 /*
9681 Validation is optional, and the first query does not ask for it,
9682 so the answer is negatively cached as Indeterminate.
9683 The second query asks for validation, answer should be marked as
9684 Bogus.
9685 */
9686 std::unique_ptr<SyncRes> sr;
9687 initSR(sr, true);
9688
9689 setDNSSECValidation(sr, DNSSECMode::Process);
9690
9691 primeHints();
9692 const DNSName target("com.");
9693 testkeysset_t keys;
9694
9695 auto luaconfsCopy = g_luaconfs.getCopy();
9696 luaconfsCopy.dsAnchors.clear();
9697 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9698 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9699 g_luaconfs.setState(luaconfsCopy);
9700
9701 size_t queriesCount = 0;
9702
9703 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9704 queriesCount++;
9705
9706 DNSName auth = domain;
9707 auth.chopOff();
9708
9709 if (type == QType::DS || type == QType::DNSKEY) {
9710 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9711 }
9712 else {
9713 setLWResult(res, RCode::NoError, true, false, true);
9714 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9715 addRRSIG(keys, res->d_records, domain, 300);
9716 /* no denial */
9717 return 1;
9718 }
9719
9720 return 0;
9721 });
9722
9723 vector<DNSRecord> ret;
9724 /* first query does not require validation */
9725 sr->setDNSSECValidationRequested(false);
9726 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9727 BOOST_CHECK_EQUAL(res, RCode::NoError);
9728 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9729 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9730 BOOST_CHECK_EQUAL(queriesCount, 1);
9731 NegCache::NegCacheEntry ne;
9732 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9733 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9734 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9735 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9736 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9737 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9738 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9739
9740 ret.clear();
9741 /* second one _does_ require validation */
9742 sr->setDNSSECValidationRequested(true);
9743 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9744 BOOST_CHECK_EQUAL(res, RCode::NoError);
9745 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9746 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9747 BOOST_CHECK_EQUAL(queriesCount, 4);
9748 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9749 BOOST_CHECK_EQUAL(ne.d_validationState, Bogus);
9750 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9751 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9752 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9753 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9754 }
9755
9756 BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
9757 g_lowercaseOutgoing = true;
9758 std::unique_ptr<SyncRes> sr;
9759 initSR(sr);
9760
9761 primeHints();
9762
9763 vector<DNSName> sentOutQnames;
9764
9765 const DNSName target("WWW.POWERDNS.COM");
9766 const DNSName cname("WWW.PowerDNS.org");
9767
9768 sr->setAsyncCallback([target, cname, &sentOutQnames](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9769
9770 sentOutQnames.push_back(domain);
9771
9772 if (isRootServer(ip)) {
9773 if (domain == target) {
9774 setLWResult(res, 0, false, false, true);
9775 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
9776 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
9777 return 1;
9778 }
9779 if (domain == cname) {
9780 setLWResult(res, 0, false, false, true);
9781 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
9782 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
9783 return 1;
9784 }
9785 } else if (ip == ComboAddress("192.0.2.1:53")) {
9786 if (domain == target) {
9787 setLWResult(res, 0, true, false, false);
9788 addRecordToLW(res, domain, QType::CNAME, cname.toString());
9789 return 1;
9790 }
9791 } else if (ip == ComboAddress("192.0.2.2:53")) {
9792 if (domain == cname) {
9793 setLWResult(res, 0, true, false, false);
9794 addRecordToLW(res, domain, QType::A, "127.0.0.1");
9795 return 1;
9796 }
9797 }
9798 return 0;
9799 });
9800
9801 vector<DNSRecord> ret;
9802 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9803
9804 BOOST_CHECK_EQUAL(res, RCode::NoError);
9805
9806 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9807 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
9808
9809 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
9810 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
9811 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
9812 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
9813 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
9814
9815 g_lowercaseOutgoing = false;
9816 }
9817
9818 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
9819 std::unique_ptr<SyncRes> sr;
9820 initSR(sr, true);
9821
9822 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9823
9824 primeHints();
9825 const DNSName target("com.");
9826 testkeysset_t keys, keys2;
9827
9828 auto luaconfsCopy = g_luaconfs.getCopy();
9829 luaconfsCopy.dsAnchors.clear();
9830 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9831 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9832 g_luaconfs.setState(luaconfsCopy);
9833
9834 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9835 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9836 // But add the existing root key otherwise no RRSIG can be created
9837 auto rootkey = keys.find(g_rootdnsname);
9838 keys2.insert(*rootkey);
9839
9840 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9841 DNSName auth = domain;
9842 auth.chopOff();
9843 if (type == QType::DS || type == QType::DNSKEY) {
9844 if (domain == target) {
9845 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9846 return 0;
9847 }
9848 }
9849 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9850 }
9851 return 0;
9852 });
9853
9854 dsmap_t ds;
9855 auto state = sr->getDSRecords(target, ds, false, 0, false);
9856 BOOST_CHECK_EQUAL(state, Secure);
9857 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9858 for (const auto& i : ds) {
9859 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9860 }
9861 }
9862
9863 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
9864 std::unique_ptr<SyncRes> sr;
9865 initSR(sr, true);
9866
9867 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9868
9869 primeHints();
9870 const DNSName target("com.");
9871 testkeysset_t keys, keys2, keys3;
9872
9873 auto luaconfsCopy = g_luaconfs.getCopy();
9874 luaconfsCopy.dsAnchors.clear();
9875 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9876 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9877 g_luaconfs.setState(luaconfsCopy);
9878
9879 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9880 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9881 // But add the existing root key otherwise no RRSIG can be created
9882 auto rootkey = keys.find(g_rootdnsname);
9883 keys2.insert(*rootkey);
9884
9885 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
9886 // But add the existing root key otherwise no RRSIG can be created
9887 keys3.insert(*rootkey);
9888
9889 sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9890 DNSName auth = domain;
9891 auth.chopOff();
9892 if (type == QType::DS || type == QType::DNSKEY) {
9893 if (domain == target) {
9894 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9895 return 0;
9896 }
9897 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9898 return 0;
9899 }
9900 }
9901 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9902 }
9903 return 0;
9904 });
9905
9906 dsmap_t ds;
9907 auto state = sr->getDSRecords(target, ds, false, 0, false);
9908 BOOST_CHECK_EQUAL(state, Secure);
9909 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9910 for (const auto& i : ds) {
9911 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9912 }
9913 }
9914
9915 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
9916 std::unique_ptr<SyncRes> sr;
9917 initSR(sr, true);
9918
9919 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9920
9921 primeHints();
9922 const DNSName target("com.");
9923 testkeysset_t keys, keys2, keys3;
9924
9925 auto luaconfsCopy = g_luaconfs.getCopy();
9926 luaconfsCopy.dsAnchors.clear();
9927 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9928 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9929 g_luaconfs.setState(luaconfsCopy);
9930
9931 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9932 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
9933 // But add the existing root key otherwise no RRSIG can be created
9934 auto rootkey = keys.find(g_rootdnsname);
9935 keys2.insert(*rootkey);
9936
9937 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
9938 // But add the existing root key otherwise no RRSIG can be created
9939 keys3.insert(*rootkey);
9940
9941 sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9942 DNSName auth = domain;
9943 auth.chopOff();
9944 if (type == QType::DS || type == QType::DNSKEY) {
9945 if (domain == target) {
9946 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9947 return 0;
9948 }
9949 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9950 return 0;
9951 }
9952 }
9953 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9954 }
9955 return 0;
9956 });
9957
9958 dsmap_t ds;
9959 auto state = sr->getDSRecords(target, ds, false, 0, false);
9960 BOOST_CHECK_EQUAL(state, Secure);
9961 BOOST_REQUIRE_EQUAL(ds.size(), 2);
9962 for (const auto& i : ds) {
9963 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9964 }
9965 }
9966
9967 #ifdef HAVE_BOTAN
9968 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) {
9969 std::unique_ptr<SyncRes> sr;
9970 initSR(sr, true);
9971
9972 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9973
9974 primeHints();
9975 const DNSName target("com.");
9976 testkeysset_t keys, keys2;
9977
9978 auto luaconfsCopy = g_luaconfs.getCopy();
9979 luaconfsCopy.dsAnchors.clear();
9980 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9981 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys);
9982 g_luaconfs.setState(luaconfsCopy);
9983
9984 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9985 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9986 // But add the existing root key otherwise no RRSIG can be created
9987 auto rootkey = keys.find(g_rootdnsname);
9988 keys2.insert(*rootkey);
9989
9990 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9991 DNSName auth = domain;
9992 auth.chopOff();
9993 if (type == QType::DS || type == QType::DNSKEY) {
9994 if (domain == target) {
9995 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9996 return 0;
9997 }
9998 }
9999 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10000 }
10001 return 0;
10002 });
10003
10004 dsmap_t ds;
10005 auto state = sr->getDSRecords(target, ds, false, 0, false);
10006 BOOST_CHECK_EQUAL(state, Secure);
10007 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10008 for (const auto& i : ds) {
10009 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
10010 }
10011 }
10012
10013 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) {
10014 std::unique_ptr<SyncRes> sr;
10015 initSR(sr, true);
10016
10017 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10018
10019 primeHints();
10020 const DNSName target("com.");
10021 testkeysset_t keys, keys2;
10022
10023 auto luaconfsCopy = g_luaconfs.getCopy();
10024 luaconfsCopy.dsAnchors.clear();
10025 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10026 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10027 g_luaconfs.setState(luaconfsCopy);
10028
10029 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10030 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
10031 // But add the existing root key otherwise no RRSIG can be created
10032 auto rootkey = keys.find(g_rootdnsname);
10033 keys2.insert(*rootkey);
10034
10035 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
10036 DNSName auth = domain;
10037 auth.chopOff();
10038 if (type == QType::DS || type == QType::DNSKEY) {
10039 if (domain == target) {
10040 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10041 return 0;
10042 }
10043 }
10044 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10045 }
10046 return 0;
10047 });
10048
10049 dsmap_t ds;
10050 auto state = sr->getDSRecords(target, ds, false, 0, false);
10051 BOOST_CHECK_EQUAL(state, Secure);
10052 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10053 for (const auto& i : ds) {
10054 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
10055 }
10056 }
10057
10058 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) {
10059 std::unique_ptr<SyncRes> sr;
10060 initSR(sr, true);
10061
10062 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10063
10064 primeHints();
10065 const DNSName target("com.");
10066 testkeysset_t keys, keys2;
10067
10068 auto luaconfsCopy = g_luaconfs.getCopy();
10069 luaconfsCopy.dsAnchors.clear();
10070 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10071 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys);
10072 g_luaconfs.setState(luaconfsCopy);
10073
10074 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10075 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
10076 // But add the existing root key otherwise no RRSIG can be created
10077 auto rootkey = keys.find(g_rootdnsname);
10078 keys2.insert(*rootkey);
10079
10080 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
10081 DNSName auth = domain;
10082 auth.chopOff();
10083 if (type == QType::DS || type == QType::DNSKEY) {
10084 if (domain == target) {
10085 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10086 return 0;
10087 }
10088 }
10089 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10090 }
10091 return 0;
10092 });
10093
10094 dsmap_t ds;
10095 auto state = sr->getDSRecords(target, ds, false, 0, false);
10096 BOOST_CHECK_EQUAL(state, Secure);
10097 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10098 for (const auto& i : ds) {
10099 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST);
10100 }
10101 }
10102 #endif // HAVE_BOTAN110
10103
10104 /*
10105 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
10106
10107 - check out of band support
10108
10109 - check preoutquery
10110
10111 */
10112
10113 BOOST_AUTO_TEST_SUITE_END()