]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc.cc
Merge pull request #6199 from aerique/bugfix/backport-6092
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc.cc
1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
3 #include <boost/test/unit_test.hpp>
4
5 #include "arguments.hh"
6 #include "base32.hh"
7 #include "dnssecinfra.hh"
8 #include "dnsseckeeper.hh"
9 #include "lua-recursor4.hh"
10 #include "namespaces.hh"
11 #include "rec-lua-conf.hh"
12 #include "root-dnssec.hh"
13 #include "syncres.hh"
14 #include "test-common.hh"
15 #include "utility.hh"
16 #include "validate-recursor.hh"
17
18 RecursorStats g_stats;
19 GlobalStateHolder<LuaConfigItems> g_luaconfs;
20 thread_local std::unique_ptr<MemRecursorCache> t_RC{nullptr};
21 unsigned int g_numThreads = 1;
22 bool g_lowercaseOutgoing = false;
23
24 /* Fake some required functions we didn't want the trouble to
25 link with */
26 ArgvMap &arg()
27 {
28 static ArgvMap theArg;
29 return theArg;
30 }
31
32 int getMTaskerTID()
33 {
34 return 0;
35 }
36
37 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret)
38 {
39 return false;
40 }
41
42 int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res)
43 {
44 return 0;
45 }
46
47 /* primeHints() is only here for now because it
48 was way too much trouble to link with the real one.
49 We should fix this, empty functions are one thing, but this is
50 bad.
51 */
52
53 #include "root-addresses.hh"
54
55 void primeHints(void)
56 {
57 vector<DNSRecord> nsset;
58 if(!t_RC)
59 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
60
61 DNSRecord arr, aaaarr, nsrr;
62 nsrr.d_name=g_rootdnsname;
63 arr.d_type=QType::A;
64 aaaarr.d_type=QType::AAAA;
65 nsrr.d_type=QType::NS;
66 arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(nullptr)+3600000;
67
68 for(char c='a';c<='m';++c) {
69 static char templ[40];
70 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
71 templ[sizeof(templ)-1] = '\0';
72 *templ=c;
73 aaaarr.d_name=arr.d_name=DNSName(templ);
74 nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
75 arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
76 vector<DNSRecord> aset;
77 aset.push_back(arr);
78 t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
79 if (rootIps6[c-'a'] != NULL) {
80 aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
81
82 vector<DNSRecord> aaaaset;
83 aaaaset.push_back(aaaarr);
84 t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
85 }
86
87 nsset.push_back(nsrr);
88 }
89 t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
90 }
91
92 LuaConfigItems::LuaConfigItems()
93 {
94 for (const auto &dsRecord : rootDSs) {
95 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
96 dsAnchors[g_rootdnsname].insert(*ds);
97 }
98 }
99
100 /* Some helpers functions */
101
102 static void init(bool debug=false)
103 {
104 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=unique_ptr<DSRecordContent>(dynamic_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) {
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) {
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) {
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) {
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) {
622 if (EDNS0Level != 0) {
623 queriesWithEDNS++;
624 setLWResult(res, RCode::NotImp);
625 return 1;
626 }
627
628 queriesWithoutEDNS++;
629
630 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
631 setLWResult(res, 0, true, false, false);
632 addRecordToLW(res, domain, QType::A, "192.0.2.1");
633 return 1;
634 }
635
636 return 0;
637 });
638
639 primeHints();
640
641 /* fake that the NS doesn't handle EDNS, check that we fallback */
642 vector<DNSRecord> ret;
643 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
644 BOOST_CHECK_EQUAL(res, RCode::NoError);
645 BOOST_CHECK_EQUAL(ret.size(), 1);
646 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
647 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
648 }
649
650 BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
651 std::unique_ptr<SyncRes> sr;
652 initSR(sr);
653
654 sr->setAsyncCallback([](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
655 if (!doTCP) {
656 setLWResult(res, 0, false, true, false);
657 return 1;
658 }
659 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
660 setLWResult(res, 0, true, false, false);
661 addRecordToLW(res, domain, QType::A, "192.0.2.1");
662 return 1;
663 }
664
665 return 0;
666 });
667
668 primeHints();
669
670 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
671 vector<DNSRecord> ret;
672 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
673 BOOST_CHECK_EQUAL(res, RCode::NoError);
674 }
675
676 BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
677 std::unique_ptr<SyncRes> sr;
678 initSR(sr);
679
680 size_t tcpQueriesCount = 0;
681
682 sr->setAsyncCallback([&tcpQueriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
683 if (!doTCP) {
684 setLWResult(res, 0, true, true, false);
685 return 1;
686 }
687
688 /* first TCP query is answered with a TC response */
689 tcpQueriesCount++;
690 if (tcpQueriesCount == 1) {
691 setLWResult(res, 0, true, true, false);
692 }
693 else {
694 setLWResult(res, 0, true, false, false);
695 }
696
697 addRecordToLW(res, domain, QType::A, "192.0.2.1");
698 return 1;
699 });
700
701 primeHints();
702
703 vector<DNSRecord> ret;
704 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
705 BOOST_CHECK_EQUAL(res, RCode::NoError);
706 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
707 }
708
709 BOOST_AUTO_TEST_CASE(test_all_nss_down) {
710 std::unique_ptr<SyncRes> sr;
711 initSR(sr);
712 std::set<ComboAddress> downServers;
713
714 primeHints();
715
716 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
717
718 if (isRootServer(ip)) {
719 setLWResult(res, 0, false, false, true);
720 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
721 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
722 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
723 return 1;
724 }
725 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
726 setLWResult(res, 0, false, false, true);
727 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
728 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
729 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
730 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
731 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
732 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
733 return 1;
734 }
735 else {
736 downServers.insert(ip);
737 return 0;
738 }
739 });
740
741 DNSName target("powerdns.com.");
742
743 vector<DNSRecord> ret;
744 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
745 BOOST_CHECK_EQUAL(res, RCode::ServFail);
746 BOOST_CHECK_EQUAL(ret.size(), 0);
747 BOOST_CHECK_EQUAL(downServers.size(), 4);
748
749 for (const auto& server : downServers) {
750 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
751 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
752 }
753 }
754
755 BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
756 std::unique_ptr<SyncRes> sr;
757 initSR(sr);
758 std::set<ComboAddress> downServers;
759
760 primeHints();
761
762 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
763
764 if (isRootServer(ip)) {
765 setLWResult(res, 0, false, false, true);
766 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
767 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
768 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
769 return 1;
770 }
771 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
772 setLWResult(res, 0, false, false, true);
773 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
774 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
775 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
776 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
777 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
778 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
779 return 1;
780 }
781 else {
782 downServers.insert(ip);
783 return 0;
784 }
785 });
786
787 /* exact same test than the previous one, except instead of a time out we fake a network error */
788 DNSName target("powerdns.com.");
789
790 vector<DNSRecord> ret;
791 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
792 BOOST_CHECK_EQUAL(res, RCode::ServFail);
793 BOOST_CHECK_EQUAL(ret.size(), 0);
794 BOOST_CHECK_EQUAL(downServers.size(), 4);
795
796 for (const auto& server : downServers) {
797 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
798 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
799 }
800 }
801
802 BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) {
803 std::unique_ptr<SyncRes> sr;
804 initSR(sr);
805
806 primeHints();
807
808 DNSName target("www.powerdns.com.");
809
810 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
811
812 if (isRootServer(ip)) {
813 setLWResult(res, 0, false, false, true);
814 if (domain == target) {
815 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
816 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
817 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
818 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
819 }
820 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
821 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
822 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
823 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
824 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
825 }
826 return 1;
827 }
828 else if (ip == ComboAddress("192.0.2.3:53")) {
829 setLWResult(res, 0, true, false, true);
830 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
831 if (type == QType::A) {
832 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
833 }
834 else if (type == QType::AAAA) {
835 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
836 }
837 }
838 else if (domain == target) {
839 if (type == QType::A) {
840 addRecordToLW(res, domain, QType::A, "192.0.2.1");
841 }
842 else if (type == QType::AAAA) {
843 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
844 }
845 }
846 return 1;
847 }
848 return 0;
849 });
850
851 vector<DNSRecord> ret;
852 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
853 BOOST_CHECK_EQUAL(res, RCode::NoError);
854 BOOST_CHECK_EQUAL(ret.size(), 1);
855 }
856
857 BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
858 std::unique_ptr<SyncRes> sr;
859 initSR(sr);
860 std::set<ComboAddress> downServers;
861
862 primeHints();
863
864 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
865
866 if (isRootServer(ip)) {
867 setLWResult(res, 0, false, false, true);
868 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
869 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
870 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
871 return 1;
872 }
873 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
874 setLWResult(res, 0, false, false, true);
875 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
876 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
877 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
878 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
879 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
880 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
881 return 1;
882 }
883 else {
884 if (downServers.size() < 3) {
885 /* only the last one will answer */
886 downServers.insert(ip);
887 return -2;
888 }
889 else {
890 setLWResult(res, 0, true, false, true);
891 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
892 return 1;
893 }
894 }
895 });
896
897 DNSName target("powerdns.com.");
898
899 vector<DNSRecord> ret;
900 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
901 BOOST_CHECK_EQUAL(res, RCode::NoError);
902 BOOST_CHECK_EQUAL(ret.size(), 1);
903 BOOST_CHECK_EQUAL(downServers.size(), 3);
904
905 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
906 for (const auto& server : downServers) {
907 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
908 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
909 }
910 }
911
912 BOOST_AUTO_TEST_CASE(test_glued_referral) {
913 std::unique_ptr<SyncRes> sr;
914 initSR(sr);
915
916 primeHints();
917
918 const DNSName target("powerdns.com.");
919
920 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
921 /* this will cause issue with qname minimization if we ever implement it */
922 if (domain != target) {
923 return 0;
924 }
925
926 if (isRootServer(ip)) {
927 setLWResult(res, 0, false, false, true);
928 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
929 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
930 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
931 return 1;
932 }
933 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
934 setLWResult(res, 0, false, false, true);
935 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
936 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
937 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
938 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
939 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
940 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
941 return 1;
942 }
943 else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) {
944 setLWResult(res, 0, true, false, true);
945 addRecordToLW(res, target, QType::A, "192.0.2.4");
946 return 1;
947 }
948 else {
949 return 0;
950 }
951 });
952
953 vector<DNSRecord> ret;
954 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
955 BOOST_CHECK_EQUAL(res, RCode::NoError);
956 BOOST_REQUIRE_EQUAL(ret.size(), 1);
957 BOOST_CHECK(ret[0].d_type == QType::A);
958 BOOST_CHECK_EQUAL(ret[0].d_name, target);
959 }
960
961 BOOST_AUTO_TEST_CASE(test_glueless_referral) {
962 std::unique_ptr<SyncRes> sr;
963 initSR(sr);
964
965 primeHints();
966
967 const DNSName target("powerdns.com.");
968
969 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
970
971 if (isRootServer(ip)) {
972 setLWResult(res, 0, false, false, true);
973
974 if (domain.isPartOf(DNSName("com."))) {
975 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
976 } else if (domain.isPartOf(DNSName("org."))) {
977 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
978 }
979 else {
980 setLWResult(res, RCode::NXDomain, false, false, true);
981 return 1;
982 }
983
984 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
985 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
986 return 1;
987 }
988 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
989 if (domain == target) {
990 setLWResult(res, 0, false, false, true);
991 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
992 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
993 return 1;
994 }
995 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
996 setLWResult(res, 0, true, false, true);
997 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
998 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
999 return 1;
1000 }
1001 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
1002 setLWResult(res, 0, true, false, true);
1003 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
1004 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
1005 return 1;
1006 }
1007
1008 setLWResult(res, RCode::NXDomain, false, false, true);
1009 return 1;
1010 }
1011 else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) {
1012 setLWResult(res, 0, true, false, true);
1013 addRecordToLW(res, target, QType::A, "192.0.2.4");
1014 return 1;
1015 }
1016 else {
1017 return 0;
1018 }
1019 });
1020
1021 vector<DNSRecord> ret;
1022 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1023 BOOST_CHECK_EQUAL(res, RCode::NoError);
1024 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1025 BOOST_CHECK(ret[0].d_type == QType::A);
1026 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1027 }
1028
1029 BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
1030 std::unique_ptr<SyncRes> sr;
1031 initSR(sr);
1032
1033 primeHints();
1034
1035 const DNSName target("powerdns.com.");
1036 SyncRes::addEDNSDomain(target);
1037
1038 EDNSSubnetOpts incomingECS;
1039 incomingECS.source = Netmask("192.0.2.128/32");
1040 sr->setIncomingECSFound(true);
1041 sr->setIncomingECS(incomingECS);
1042
1043 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1044
1045 BOOST_REQUIRE(srcmask);
1046 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1047 return 0;
1048 });
1049
1050 vector<DNSRecord> ret;
1051 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1052 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1053 }
1054
1055 BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
1056 std::unique_ptr<SyncRes> sr;
1057 initSR(sr);
1058
1059 primeHints();
1060
1061 const DNSName target("powerdns.com.");
1062 SyncRes::addEDNSSubnet(Netmask("192.0.2.1/32"));
1063
1064 EDNSSubnetOpts incomingECS;
1065 incomingECS.source = Netmask("2001:DB8::FF/128");
1066 sr->setIncomingECSFound(true);
1067 sr->setIncomingECS(incomingECS);
1068
1069 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1070
1071 if (isRootServer(ip)) {
1072 BOOST_REQUIRE(!srcmask);
1073
1074 setLWResult(res, 0, false, false, true);
1075 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1076 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1077 return 1;
1078 } else if (ip == ComboAddress("192.0.2.1:53")) {
1079
1080 BOOST_REQUIRE(srcmask);
1081 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1082
1083 setLWResult(res, 0, true, false, false);
1084 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1085 return 1;
1086 }
1087
1088 return 0;
1089 });
1090
1091 vector<DNSRecord> ret;
1092 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1093 BOOST_CHECK_EQUAL(res, RCode::NoError);
1094 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1095 BOOST_CHECK(ret[0].d_type == QType::A);
1096 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1097 }
1098
1099 BOOST_AUTO_TEST_CASE(test_following_cname) {
1100 std::unique_ptr<SyncRes> sr;
1101 initSR(sr);
1102
1103 primeHints();
1104
1105 const DNSName target("cname.powerdns.com.");
1106 const DNSName cnameTarget("cname-target.powerdns.com");
1107
1108 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1109
1110 if (isRootServer(ip)) {
1111 setLWResult(res, 0, false, false, true);
1112 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1113 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1114 return 1;
1115 } else if (ip == ComboAddress("192.0.2.1:53")) {
1116
1117 if (domain == target) {
1118 setLWResult(res, 0, true, false, false);
1119 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1120 return 1;
1121 }
1122 else if (domain == cnameTarget) {
1123 setLWResult(res, 0, true, false, false);
1124 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1125 }
1126
1127 return 1;
1128 }
1129
1130 return 0;
1131 });
1132
1133 vector<DNSRecord> ret;
1134 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1135 BOOST_CHECK_EQUAL(res, RCode::NoError);
1136 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1137 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1138 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1139 BOOST_CHECK(ret[1].d_type == QType::A);
1140 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1141 }
1142
1143 BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
1144 std::unique_ptr<SyncRes> sr;
1145 initSR(sr);
1146
1147 primeHints();
1148
1149 const DNSName target("cname.powerdns.com.");
1150 const DNSName cnameTarget("cname-target.powerdns.com");
1151
1152 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1153
1154 if (isRootServer(ip)) {
1155 setLWResult(res, 0, false, false, true);
1156 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1157 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1158 return 1;
1159 } else if (ip == ComboAddress("192.0.2.1:53")) {
1160
1161 if (domain == target) {
1162 setLWResult(res, RCode::NXDomain, true, false, false);
1163 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1164 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1165 } else if (domain == cnameTarget) {
1166 setLWResult(res, RCode::NXDomain, true, false, false);
1167 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1168 return 1;
1169 }
1170
1171 return 1;
1172 }
1173
1174 return 0;
1175 });
1176
1177 vector<DNSRecord> ret;
1178 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1179 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1180 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1181 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1182 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1183 BOOST_CHECK(ret[1].d_type == QType::SOA);
1184
1185 /* a second time, to check the cache */
1186 ret.clear();
1187 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1188 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1189 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1190 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1191 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1192 BOOST_CHECK(ret[1].d_type == QType::SOA);
1193 }
1194
1195 BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1196 std::unique_ptr<SyncRes> sr;
1197 initSR(sr);
1198
1199 primeHints();
1200
1201 /* In this test we directly get the NS server for cname.powerdns.com.,
1202 and we don't know whether it's also authoritative for
1203 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1204 the additional A record for cname-target.powerdns.com. */
1205 const DNSName target("cname.powerdns.com.");
1206 const DNSName cnameTarget("cname-target.powerdns.com");
1207
1208 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1209
1210 if (isRootServer(ip)) {
1211
1212 setLWResult(res, 0, false, false, true);
1213
1214 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1215 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1216 return 1;
1217 } else if (ip == ComboAddress("192.0.2.1:53")) {
1218
1219 if (domain == target) {
1220 setLWResult(res, 0, true, false, false);
1221 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1222 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1223 return 1;
1224 } else if (domain == cnameTarget) {
1225 setLWResult(res, 0, true, false, false);
1226 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1227 return 1;
1228 }
1229
1230 return 1;
1231 }
1232
1233 return 0;
1234 });
1235
1236 vector<DNSRecord> ret;
1237 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1238 BOOST_CHECK_EQUAL(res, RCode::NoError);
1239 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1240 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1241 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1242 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1243 BOOST_REQUIRE(ret[1].d_type == QType::A);
1244 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1245 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1246 }
1247
1248 BOOST_AUTO_TEST_CASE(test_cname_loop) {
1249 std::unique_ptr<SyncRes> sr;
1250 initSR(sr);
1251
1252 primeHints();
1253
1254 size_t count = 0;
1255 const DNSName target("cname.powerdns.com.");
1256
1257 sr->setAsyncCallback([target,&count](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1258
1259 count++;
1260
1261 if (isRootServer(ip)) {
1262
1263 setLWResult(res, 0, false, false, true);
1264 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1265 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1266 return 1;
1267 } else if (ip == ComboAddress("192.0.2.1:53")) {
1268
1269 if (domain == target) {
1270 setLWResult(res, 0, true, false, false);
1271 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1272 return 1;
1273 }
1274
1275 return 1;
1276 }
1277
1278 return 0;
1279 });
1280
1281 vector<DNSRecord> ret;
1282 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1283 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1284 BOOST_CHECK_GT(ret.size(), 0);
1285 BOOST_CHECK_EQUAL(count, 2);
1286 }
1287
1288 BOOST_AUTO_TEST_CASE(test_cname_depth) {
1289 std::unique_ptr<SyncRes> sr;
1290 initSR(sr);
1291
1292 primeHints();
1293
1294 size_t depth = 0;
1295 const DNSName target("cname.powerdns.com.");
1296
1297 sr->setAsyncCallback([target,&depth](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1298
1299 if (isRootServer(ip)) {
1300
1301 setLWResult(res, 0, false, false, true);
1302 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1303 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1304 return 1;
1305 } else if (ip == ComboAddress("192.0.2.1:53")) {
1306
1307 setLWResult(res, 0, true, false, false);
1308 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1309 depth++;
1310 return 1;
1311 }
1312
1313 return 0;
1314 });
1315
1316 vector<DNSRecord> ret;
1317 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1318 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1319 BOOST_CHECK_EQUAL(ret.size(), depth);
1320 /* we have an arbitrary limit at 10 when following a CNAME chain */
1321 BOOST_CHECK_EQUAL(depth, 10 + 2);
1322 }
1323
1324 BOOST_AUTO_TEST_CASE(test_time_limit) {
1325 std::unique_ptr<SyncRes> sr;
1326 initSR(sr);
1327
1328 primeHints();
1329
1330 size_t queries = 0;
1331 const DNSName target("cname.powerdns.com.");
1332
1333 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1334
1335 queries++;
1336
1337 if (isRootServer(ip)) {
1338 setLWResult(res, 0, false, false, true);
1339 /* Pretend that this query took 2000 ms */
1340 res->d_usec = 2000;
1341
1342 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1343 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1344 return 1;
1345 } else if (ip == ComboAddress("192.0.2.1:53")) {
1346
1347 setLWResult(res, 0, true, false, false);
1348 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1349 return 1;
1350 }
1351
1352 return 0;
1353 });
1354
1355 /* Set the maximum time to 1 ms */
1356 SyncRes::s_maxtotusec = 1000;
1357
1358 try {
1359 vector<DNSRecord> ret;
1360 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1361 BOOST_CHECK(false);
1362 }
1363 catch(const ImmediateServFailException& e) {
1364 }
1365 BOOST_CHECK_EQUAL(queries, 1);
1366 }
1367
1368 BOOST_AUTO_TEST_CASE(test_referral_depth) {
1369 std::unique_ptr<SyncRes> sr;
1370 initSR(sr);
1371
1372 primeHints();
1373
1374 size_t queries = 0;
1375 const DNSName target("www.powerdns.com.");
1376
1377 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1378
1379 queries++;
1380
1381 if (isRootServer(ip)) {
1382 setLWResult(res, 0, false, false, true);
1383
1384 if (domain == DNSName("www.powerdns.com.")) {
1385 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1386 }
1387 else if (domain == DNSName("ns.powerdns.com.")) {
1388 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1389 }
1390 else if (domain == DNSName("ns1.powerdns.org.")) {
1391 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1392 }
1393 else if (domain == DNSName("ns2.powerdns.org.")) {
1394 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1395 }
1396 else if (domain == DNSName("ns3.powerdns.org.")) {
1397 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1398 }
1399 else if (domain == DNSName("ns4.powerdns.org.")) {
1400 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1401 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1402 }
1403
1404 return 1;
1405 } else if (ip == ComboAddress("192.0.2.1:53")) {
1406
1407 setLWResult(res, 0, true, false, false);
1408 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1409 return 1;
1410 }
1411
1412 return 0;
1413 });
1414
1415 /* Set the maximum depth low */
1416 SyncRes::s_maxdepth = 10;
1417
1418 try {
1419 vector<DNSRecord> ret;
1420 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1421 BOOST_CHECK(false);
1422 }
1423 catch(const ImmediateServFailException& e) {
1424 }
1425 }
1426
1427 BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1428 std::unique_ptr<SyncRes> sr;
1429 initSR(sr);
1430
1431 primeHints();
1432
1433 size_t queries = 0;
1434 const DNSName target("cname.powerdns.com.");
1435
1436 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1437
1438 queries++;
1439
1440 if (isRootServer(ip)) {
1441
1442 setLWResult(res, 0, false, false, true);
1443 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1444 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1445 return 1;
1446 } else if (ip == ComboAddress("192.0.2.1:53")) {
1447
1448 setLWResult(res, 0, true, false, false);
1449 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1450 return 1;
1451 }
1452
1453 return 0;
1454 });
1455
1456 /* Set the maximum number of questions very low */
1457 SyncRes::s_maxqperq = 5;
1458
1459 try {
1460 vector<DNSRecord> ret;
1461 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1462 BOOST_CHECK(false);
1463 }
1464 catch(const ImmediateServFailException& e) {
1465 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1466 }
1467 }
1468
1469 BOOST_AUTO_TEST_CASE(test_throttled_server) {
1470 std::unique_ptr<SyncRes> sr;
1471 initSR(sr);
1472
1473 primeHints();
1474
1475 const DNSName target("throttled.powerdns.com.");
1476 const ComboAddress ns("192.0.2.1:53");
1477 size_t queriesToNS = 0;
1478
1479 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1480
1481 if (isRootServer(ip)) {
1482
1483 setLWResult(res, 0, false, false, true);
1484 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1485 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1486 return 1;
1487 } else if (ip == ns) {
1488
1489 queriesToNS++;
1490
1491 setLWResult(res, 0, true, false, false);
1492 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1493
1494 return 1;
1495 }
1496
1497 return 0;
1498 });
1499
1500 /* mark ns as down */
1501 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, 10000);
1502
1503 vector<DNSRecord> ret;
1504 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1505 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1506 BOOST_CHECK_EQUAL(ret.size(), 0);
1507 /* we should not have sent any queries to ns */
1508 BOOST_CHECK_EQUAL(queriesToNS, 0);
1509 }
1510
1511 BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1512 std::unique_ptr<SyncRes> sr;
1513 initSR(sr);
1514
1515 primeHints();
1516
1517 const ComboAddress ns("192.0.2.1:53");
1518
1519 const size_t blocks = 10;
1520 /* mark ns as down for 'blocks' queries */
1521 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, blocks);
1522
1523 for (size_t idx = 0; idx < blocks; idx++) {
1524 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1525 }
1526
1527 /* we have been throttled 'blocks' times, we should not be throttled anymore */
1528 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1529 }
1530
1531 BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1532 std::unique_ptr<SyncRes> sr;
1533 initSR(sr);
1534
1535 primeHints();
1536
1537 const ComboAddress ns("192.0.2.1:53");
1538
1539 const size_t seconds = 1;
1540 /* mark ns as down for 'seconds' seconds */
1541 SyncRes::doThrottle(time(nullptr), ns, seconds, 10000);
1542
1543 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1544
1545 sleep(seconds + 1);
1546
1547 /* we should not be throttled anymore */
1548 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1549 }
1550
1551 BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1552 std::unique_ptr<SyncRes> sr;
1553 initSR(sr);
1554
1555 primeHints();
1556
1557 const DNSName target("throttled.powerdns.com.");
1558 const ComboAddress ns("192.0.2.1:53");
1559 size_t queriesToNS = 0;
1560
1561 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1562
1563 if (isRootServer(ip)) {
1564
1565 setLWResult(res, 0, false, false, true);
1566 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1567 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1568 return 1;
1569 } else if (ip == ns) {
1570
1571 queriesToNS++;
1572
1573 setLWResult(res, 0, true, false, false);
1574 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1575
1576 return 1;
1577 }
1578
1579 return 0;
1580 });
1581
1582 /* prevent querying this NS */
1583 SyncRes::addDontQuery(Netmask(ns));
1584
1585 vector<DNSRecord> ret;
1586 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1587 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1588 BOOST_CHECK_EQUAL(ret.size(), 0);
1589 /* we should not have sent any queries to ns */
1590 BOOST_CHECK_EQUAL(queriesToNS, 0);
1591 }
1592
1593 BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1594 std::unique_ptr<SyncRes> sr;
1595 initSR(sr);
1596
1597 primeHints();
1598
1599 const DNSName target1("powerdns.com.");
1600 const DNSName target2("notpowerdns.com.");
1601 const ComboAddress ns("192.0.2.1:53");
1602 size_t queriesCount = 0;
1603
1604 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1605
1606 queriesCount++;
1607
1608 if (isRootServer(ip)) {
1609
1610 if (domain == target1) {
1611 setLWResult(res, RCode::NXDomain, true, false, true);
1612 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1613 }
1614 else {
1615 setLWResult(res, 0, true, false, true);
1616 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1617 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1618 }
1619
1620 return 1;
1621 } else if (ip == ns) {
1622
1623 setLWResult(res, 0, true, false, false);
1624 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1625
1626 return 1;
1627 }
1628
1629 return 0;
1630 });
1631
1632 vector<DNSRecord> ret;
1633 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1634 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1635 BOOST_CHECK_EQUAL(ret.size(), 1);
1636 /* one for target1 and one for the entire TLD */
1637 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1638
1639 ret.clear();
1640 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1641 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1642 BOOST_CHECK_EQUAL(ret.size(), 1);
1643 /* one for target1 and one for the entire TLD */
1644 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1645
1646 /* we should have sent only one query */
1647 BOOST_CHECK_EQUAL(queriesCount, 1);
1648 }
1649
1650 BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1651 std::unique_ptr<SyncRes> sr;
1652 init();
1653 initSR(sr, true, false);
1654
1655 primeHints();
1656
1657 const DNSName target1("powerdns.com.");
1658 const DNSName target2("notpowerdns.com.");
1659 const ComboAddress ns("192.0.2.1:53");
1660 size_t queriesCount = 0;
1661
1662 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1663 We should add target1 to the negcache, but not "com.". */
1664
1665 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1666
1667 queriesCount++;
1668
1669 if (isRootServer(ip)) {
1670
1671 if (domain == target1) {
1672 setLWResult(res, RCode::NXDomain, true, false, true);
1673 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1674 }
1675 else {
1676 setLWResult(res, 0, true, false, true);
1677 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1678 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1679 }
1680
1681 return 1;
1682 } else if (ip == ns) {
1683
1684 setLWResult(res, 0, true, false, false);
1685 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1686
1687 return 1;
1688 }
1689
1690 return 0;
1691 });
1692
1693 vector<DNSRecord> ret;
1694 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1695 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1696 BOOST_CHECK_EQUAL(ret.size(), 1);
1697
1698 /* even with root-nx-trust on and a NX answer from the root,
1699 we should not have cached the entire TLD this time. */
1700 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1701
1702 ret.clear();
1703 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1704 BOOST_CHECK_EQUAL(res, RCode::NoError);
1705 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1706 BOOST_REQUIRE(ret[0].d_type == QType::A);
1707 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1708 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1709
1710 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1711
1712 BOOST_CHECK_EQUAL(queriesCount, 3);
1713 }
1714
1715 BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1716 std::unique_ptr<SyncRes> sr;
1717 initSR(sr);
1718
1719 primeHints();
1720
1721 const DNSName target1("powerdns.com.");
1722 const DNSName target2("notpowerdns.com.");
1723 const ComboAddress ns("192.0.2.1:53");
1724 size_t queriesCount = 0;
1725
1726 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1727
1728 queriesCount++;
1729
1730 if (isRootServer(ip)) {
1731
1732 if (domain == target1) {
1733 setLWResult(res, RCode::NXDomain, true, false, true);
1734 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1735 }
1736 else {
1737 setLWResult(res, 0, true, false, true);
1738 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1739 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1740 }
1741
1742 return 1;
1743 } else if (ip == ns) {
1744
1745 setLWResult(res, 0, true, false, false);
1746 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1747
1748 return 1;
1749 }
1750
1751 return 0;
1752 });
1753
1754 SyncRes::s_rootNXTrust = false;
1755
1756 vector<DNSRecord> ret;
1757 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1758 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1759 BOOST_CHECK_EQUAL(ret.size(), 1);
1760 /* one for target1 */
1761 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1762
1763 ret.clear();
1764 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1765 BOOST_CHECK_EQUAL(res, RCode::NoError);
1766 BOOST_CHECK_EQUAL(ret.size(), 1);
1767 /* one for target1 */
1768 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1769
1770 /* we should have sent three queries */
1771 BOOST_CHECK_EQUAL(queriesCount, 3);
1772 }
1773
1774 BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1775 std::unique_ptr<SyncRes> sr;
1776 initSR(sr);
1777
1778 primeHints();
1779
1780 const DNSName target("www.powerdns.com.");
1781 const DNSName cnameTarget("cname.powerdns.com.");
1782
1783 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
1784
1785 EDNSSubnetOpts incomingECS;
1786 incomingECS.source = Netmask("192.0.2.128/32");
1787 sr->setIncomingECSFound(true);
1788 sr->setIncomingECS(incomingECS);
1789
1790 sr->setAsyncCallback([target,cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1791
1792 BOOST_REQUIRE(srcmask);
1793 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1794
1795 if (isRootServer(ip)) {
1796 setLWResult(res, 0, false, false, true);
1797 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1798 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1799
1800 return 1;
1801 } else if (ip == ComboAddress("192.0.2.1:53")) {
1802 if (domain == target) {
1803 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
1804 setLWResult(res, RCode::NXDomain, true, false, true);
1805 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1806 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1807 }
1808 else if (domain == cnameTarget) {
1809 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
1810 but we might if we still chase the CNAME. */
1811 setLWResult(res, RCode::NXDomain, true, false, true);
1812 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1813 }
1814
1815 return 1;
1816 }
1817
1818 return 0;
1819 });
1820
1821 vector<DNSRecord> ret;
1822 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1823 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1824 BOOST_CHECK_EQUAL(ret.size(), 2);
1825 /* no negative cache entry because the response was variable */
1826 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
1827 }
1828
1829 BOOST_AUTO_TEST_CASE(test_ns_speed) {
1830 std::unique_ptr<SyncRes> sr;
1831 initSR(sr);
1832
1833 primeHints();
1834
1835 const DNSName target("powerdns.com.");
1836
1837 std::map<ComboAddress, uint64_t> nsCounts;
1838
1839 sr->setAsyncCallback([target,&nsCounts](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1840
1841 if (isRootServer(ip)) {
1842 setLWResult(res, 0, false, false, true);
1843 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1844 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1845 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1846
1847 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1848 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1849 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1850 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
1851 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
1852 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
1853
1854 return 1;
1855 } else {
1856 nsCounts[ip]++;
1857
1858 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
1859 BOOST_CHECK_LT(nsCounts.size(), 3);
1860
1861 /* let's time out on pdns-public-ns2.powerdns.com. */
1862 return 0;
1863 }
1864 else if (ip == ComboAddress("192.0.2.1:53")) {
1865 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1866
1867 setLWResult(res, 0, true, false, true);
1868 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1869 return 1;
1870 }
1871
1872 return 0;
1873 }
1874
1875 return 0;
1876 });
1877
1878 struct timeval now;
1879 gettimeofday(&now, 0);
1880
1881 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
1882 then pdns-public-ns1.powerdns.com. on IPv4 */
1883 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
1884 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
1885 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
1886 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
1887 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
1888 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
1889
1890 vector<DNSRecord> ret;
1891 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1892 BOOST_CHECK_EQUAL(res, RCode::NoError);
1893 BOOST_CHECK_EQUAL(ret.size(), 1);
1894 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1895 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
1896 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
1897 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
1898 }
1899
1900 BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
1901 std::unique_ptr<SyncRes> sr;
1902 initSR(sr);
1903
1904 primeHints();
1905
1906 const DNSName target("powerdns.com.");
1907
1908 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1909
1910 if (isRootServer(ip)) {
1911 setLWResult(res, 0, false, false, true);
1912 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1913
1914 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1915
1916 return 1;
1917 } else if (ip == ComboAddress("192.0.2.1:53")) {
1918 setLWResult(res, 0, true, false, true);
1919 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1920 return 1;
1921 }
1922
1923 return 0;
1924 });
1925
1926 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
1927 time_t now = time(nullptr);
1928 std::vector<DNSRecord> records;
1929 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1930 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
1931
1932 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1933
1934 vector<DNSRecord> ret;
1935 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1936 BOOST_CHECK_EQUAL(res, RCode::NoError);
1937 BOOST_CHECK_EQUAL(ret.size(), 1);
1938 }
1939
1940 BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
1941 std::unique_ptr<SyncRes> sr;
1942 initSR(sr);
1943
1944 primeHints();
1945
1946 const DNSName target("powerdns.com.");
1947 size_t queriesCount = 0;
1948
1949 sr->setAsyncCallback([&queriesCount,target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1950
1951 queriesCount++;
1952
1953 if (isRootServer(ip) && domain == target) {
1954 setLWResult(res, 0, false, false, true);
1955 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1956 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1957 return 1;
1958 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
1959 setLWResult(res, 0, true, false, true);
1960 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1961 return 1;
1962 }
1963
1964 return 0;
1965 });
1966
1967 vector<DNSRecord> ret;
1968 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1969 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1970 BOOST_CHECK_EQUAL(ret.size(), 0);
1971 /* one query to get NSs, then A and AAAA for each NS */
1972 BOOST_CHECK_EQUAL(queriesCount, 5);
1973 }
1974
1975 BOOST_AUTO_TEST_CASE(test_cache_hit) {
1976 std::unique_ptr<SyncRes> sr;
1977 initSR(sr);
1978
1979 primeHints();
1980
1981 const DNSName target("powerdns.com.");
1982
1983 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1984
1985 return 0;
1986 });
1987
1988 /* we populate the cache with eveything we need */
1989 time_t now = time(nullptr);
1990 std::vector<DNSRecord> records;
1991 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1992
1993 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
1994 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1995
1996 vector<DNSRecord> ret;
1997 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1998 BOOST_CHECK_EQUAL(res, RCode::NoError);
1999 BOOST_CHECK_EQUAL(ret.size(), 1);
2000 }
2001
2002 BOOST_AUTO_TEST_CASE(test_no_rd) {
2003 std::unique_ptr<SyncRes> sr;
2004 initSR(sr);
2005
2006 primeHints();
2007
2008 const DNSName target("powerdns.com.");
2009 size_t queriesCount = 0;
2010
2011 sr->setCacheOnly();
2012
2013 sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2014
2015 queriesCount++;
2016 return 0;
2017 });
2018
2019 vector<DNSRecord> ret;
2020 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2021 BOOST_CHECK_EQUAL(res, RCode::NoError);
2022 BOOST_CHECK_EQUAL(ret.size(), 0);
2023 BOOST_CHECK_EQUAL(queriesCount, 0);
2024 }
2025
2026 BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
2027 std::unique_ptr<SyncRes> sr;
2028 initSR(sr);
2029
2030 primeHints();
2031
2032 const DNSName target("cachettl.powerdns.com.");
2033 const ComboAddress ns("192.0.2.1:53");
2034
2035 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2036
2037 if (isRootServer(ip)) {
2038
2039 setLWResult(res, 0, false, false, true);
2040 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2041 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
2042 return 1;
2043 } else if (ip == ns) {
2044
2045 setLWResult(res, 0, true, false, false);
2046 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2047
2048 return 1;
2049 }
2050
2051 return 0;
2052 });
2053
2054 const time_t now = time(nullptr);
2055 SyncRes::s_minimumTTL = 60;
2056 SyncRes::s_maxcachettl = 3600;
2057
2058 vector<DNSRecord> ret;
2059 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2060 BOOST_CHECK_EQUAL(res, RCode::NoError);
2061 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2062 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
2063
2064 const ComboAddress who;
2065 vector<DNSRecord> cached;
2066 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
2067 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2068 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2069 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
2070
2071 cached.clear();
2072 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
2073 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2074 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2075 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
2076 }
2077
2078 BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
2079 std::unique_ptr<SyncRes> sr;
2080 initSR(sr);
2081
2082 primeHints();
2083
2084 const DNSName target("powerdns.com.");
2085
2086 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2087
2088 if (isRootServer(ip)) {
2089 setLWResult(res, 0, false, false, true);
2090 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2091
2092 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2093
2094 return 1;
2095 } else if (ip == ComboAddress("192.0.2.1:53")) {
2096 setLWResult(res, 0, true, false, true);
2097 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2098 return 1;
2099 }
2100
2101 return 0;
2102 });
2103
2104 /* we populate the cache with entries that expired 60s ago*/
2105 time_t now = time(nullptr);
2106 std::vector<DNSRecord> records;
2107 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2108 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
2109
2110 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
2111
2112 vector<DNSRecord> ret;
2113 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2114 BOOST_CHECK_EQUAL(res, RCode::NoError);
2115 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2116 BOOST_REQUIRE(ret[0].d_type == QType::A);
2117 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
2118 }
2119
2120 BOOST_AUTO_TEST_CASE(test_delegation_only) {
2121 std::unique_ptr<SyncRes> sr;
2122 initSR(sr);
2123
2124 primeHints();
2125
2126 /* Thanks, Verisign */
2127 SyncRes::addDelegationOnly(DNSName("com."));
2128 SyncRes::addDelegationOnly(DNSName("net."));
2129
2130 const DNSName target("nx-powerdns.com.");
2131
2132 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2133
2134 if (isRootServer(ip)) {
2135 setLWResult(res, 0, false, false, true);
2136 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2137 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2138 return 1;
2139 } else if (ip == ComboAddress("192.0.2.1:53")) {
2140
2141 setLWResult(res, 0, true, false, true);
2142 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2143 return 1;
2144 }
2145
2146 return 0;
2147 });
2148
2149 vector<DNSRecord> ret;
2150 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2151 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2152 BOOST_CHECK_EQUAL(ret.size(), 0);
2153 }
2154
2155 BOOST_AUTO_TEST_CASE(test_unauth_any) {
2156 std::unique_ptr<SyncRes> sr;
2157 initSR(sr);
2158
2159 primeHints();
2160
2161 const DNSName target("powerdns.com.");
2162
2163 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2164
2165 if (isRootServer(ip)) {
2166 setLWResult(res, 0, false, false, true);
2167 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2168 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2169 return 1;
2170 } else if (ip == ComboAddress("192.0.2.1:53")) {
2171
2172 setLWResult(res, 0, false, false, true);
2173 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2174 return 1;
2175 }
2176
2177 return 0;
2178 });
2179
2180 vector<DNSRecord> ret;
2181 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2182 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2183 BOOST_CHECK_EQUAL(ret.size(), 0);
2184 }
2185
2186 BOOST_AUTO_TEST_CASE(test_no_data) {
2187 std::unique_ptr<SyncRes> sr;
2188 initSR(sr);
2189
2190 primeHints();
2191
2192 const DNSName target("powerdns.com.");
2193
2194 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2195
2196 setLWResult(res, 0, true, false, true);
2197 return 1;
2198 });
2199
2200 vector<DNSRecord> ret;
2201 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2202 BOOST_CHECK_EQUAL(res, RCode::NoError);
2203 BOOST_CHECK_EQUAL(ret.size(), 0);
2204 }
2205
2206 BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2207 std::unique_ptr<SyncRes> sr;
2208 initSR(sr);
2209
2210 primeHints();
2211
2212 const DNSName target("powerdns.com.");
2213
2214 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2215
2216 setLWResult(res, 0, true, false, true);
2217 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2218 addRecordToLW(res, domain, QType::ANY, "0 0");
2219 addRecordToLW(res, domain, QType::OPT, "");
2220 return 1;
2221 });
2222
2223 vector<DNSRecord> ret;
2224 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2225 BOOST_CHECK_EQUAL(res, RCode::NoError);
2226 BOOST_CHECK_EQUAL(ret.size(), 1);
2227 }
2228
2229 BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2230 std::unique_ptr<SyncRes> sr;
2231 initSR(sr);
2232
2233 primeHints();
2234
2235 const DNSName target("powerdns.com.");
2236
2237 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2238
2239 setLWResult(res, 0, true, false, true);
2240 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2241 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2242 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2243 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2244 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2245 return 1;
2246 });
2247
2248 vector<DNSRecord> ret;
2249 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2250 BOOST_CHECK_EQUAL(res, RCode::NoError);
2251 BOOST_CHECK_EQUAL(ret.size(), 1);
2252 }
2253
2254 BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2255 std::unique_ptr<SyncRes> sr;
2256 initSR(sr, true);
2257
2258 primeHints();
2259
2260 const DNSName target("powerdns.com.");
2261
2262 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2263
2264 setLWResult(res, 0, true, false, true);
2265 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2266 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2267 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2268 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2269 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2270 return 1;
2271 });
2272
2273 vector<DNSRecord> ret;
2274 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2275 BOOST_CHECK_EQUAL(res, RCode::NoError);
2276 BOOST_CHECK_EQUAL(ret.size(), 4);
2277 }
2278
2279 BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2280 std::unique_ptr<SyncRes> sr;
2281 initSR(sr);
2282
2283 primeHints();
2284
2285 const DNSName target("powerdns.com.");
2286
2287 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2288
2289 setLWResult(res, RCode::NXDomain, true, false, true);
2290 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2291 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2292 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2293 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2294 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2295 return 1;
2296 });
2297
2298 vector<DNSRecord> ret;
2299 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2300 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2301 BOOST_CHECK_EQUAL(ret.size(), 1);
2302 }
2303
2304 BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2305 std::unique_ptr<SyncRes> sr;
2306 initSR(sr, true);
2307
2308 primeHints();
2309
2310 const DNSName target("powerdns.com.");
2311
2312 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2313
2314 setLWResult(res, RCode::NXDomain, true, false, true);
2315 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2316 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2317 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2318 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2319 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2320 return 1;
2321 });
2322
2323 vector<DNSRecord> ret;
2324 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2325 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2326 BOOST_CHECK_EQUAL(ret.size(), 4);
2327 }
2328
2329 BOOST_AUTO_TEST_CASE(test_qclass_none) {
2330 std::unique_ptr<SyncRes> sr;
2331 initSR(sr);
2332
2333 primeHints();
2334
2335 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2336 size_t queriesCount = 0;
2337
2338 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2339
2340 queriesCount++;
2341 return 0;
2342 });
2343
2344 const DNSName target("powerdns.com.");
2345 vector<DNSRecord> ret;
2346 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2347 BOOST_CHECK_EQUAL(res, -1);
2348 BOOST_CHECK_EQUAL(ret.size(), 0);
2349 BOOST_CHECK_EQUAL(queriesCount, 0);
2350 }
2351
2352 BOOST_AUTO_TEST_CASE(test_special_types) {
2353 std::unique_ptr<SyncRes> sr;
2354 initSR(sr);
2355
2356 primeHints();
2357
2358 /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
2359 size_t queriesCount = 0;
2360
2361 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2362
2363 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2364 queriesCount++;
2365 return 0;
2366 });
2367
2368 const DNSName target("powerdns.com.");
2369 vector<DNSRecord> ret;
2370 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2371 BOOST_CHECK_EQUAL(res, -1);
2372 BOOST_CHECK_EQUAL(ret.size(), 0);
2373 BOOST_CHECK_EQUAL(queriesCount, 0);
2374
2375 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2376 BOOST_CHECK_EQUAL(res, -1);
2377 BOOST_CHECK_EQUAL(ret.size(), 0);
2378 BOOST_CHECK_EQUAL(queriesCount, 0);
2379
2380 res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2381 BOOST_CHECK_EQUAL(res, -1);
2382 BOOST_CHECK_EQUAL(ret.size(), 0);
2383 BOOST_CHECK_EQUAL(queriesCount, 0);
2384
2385 res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
2386 BOOST_CHECK_EQUAL(res, -1);
2387 BOOST_CHECK_EQUAL(ret.size(), 0);
2388 BOOST_CHECK_EQUAL(queriesCount, 0);
2389 }
2390
2391 BOOST_AUTO_TEST_CASE(test_special_names) {
2392 std::unique_ptr<SyncRes> sr;
2393 initSR(sr);
2394
2395 primeHints();
2396
2397 /* special names should be handled internally */
2398
2399 size_t queriesCount = 0;
2400
2401 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2402
2403 queriesCount++;
2404 return 0;
2405 });
2406
2407 vector<DNSRecord> ret;
2408 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
2409 BOOST_CHECK_EQUAL(res, RCode::NoError);
2410 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2411 BOOST_CHECK(ret[0].d_type == QType::PTR);
2412 BOOST_CHECK_EQUAL(queriesCount, 0);
2413
2414 ret.clear();
2415 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
2416 BOOST_CHECK_EQUAL(res, RCode::NoError);
2417 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2418 BOOST_CHECK(ret[0].d_type == QType::PTR);
2419 BOOST_CHECK_EQUAL(queriesCount, 0);
2420
2421 ret.clear();
2422 res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::PTR), QClass::IN, ret);
2423 BOOST_CHECK_EQUAL(res, RCode::NoError);
2424 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2425 BOOST_CHECK(ret[0].d_type == QType::PTR);
2426 BOOST_CHECK_EQUAL(queriesCount, 0);
2427
2428 ret.clear();
2429 res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::ANY), QClass::IN, ret);
2430 BOOST_CHECK_EQUAL(res, RCode::NoError);
2431 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2432 BOOST_CHECK(ret[0].d_type == QType::PTR);
2433 BOOST_CHECK_EQUAL(queriesCount, 0);
2434
2435 ret.clear();
2436 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
2437 BOOST_CHECK_EQUAL(res, RCode::NoError);
2438 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2439 BOOST_CHECK(ret[0].d_type == QType::A);
2440 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2441 BOOST_CHECK_EQUAL(queriesCount, 0);
2442
2443 ret.clear();
2444 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
2445 BOOST_CHECK_EQUAL(res, RCode::NoError);
2446 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2447 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2448 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2449 BOOST_CHECK_EQUAL(queriesCount, 0);
2450
2451 ret.clear();
2452 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
2453 BOOST_CHECK_EQUAL(res, RCode::NoError);
2454 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2455 for (const auto& rec : ret) {
2456 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2457 if (rec.d_type == QType::A) {
2458 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2459 }
2460 else {
2461 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2462 }
2463 }
2464 BOOST_CHECK_EQUAL(queriesCount, 0);
2465
2466 ret.clear();
2467 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
2468 BOOST_CHECK_EQUAL(res, RCode::NoError);
2469 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2470 BOOST_CHECK(ret[0].d_type == QType::TXT);
2471 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2472 BOOST_CHECK_EQUAL(queriesCount, 0);
2473
2474 ret.clear();
2475 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
2476 BOOST_CHECK_EQUAL(res, RCode::NoError);
2477 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2478 BOOST_CHECK(ret[0].d_type == QType::TXT);
2479 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2480 BOOST_CHECK_EQUAL(queriesCount, 0);
2481
2482 ret.clear();
2483 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
2484 BOOST_CHECK_EQUAL(res, RCode::NoError);
2485 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2486 BOOST_CHECK(ret[0].d_type == QType::TXT);
2487 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2488 BOOST_CHECK_EQUAL(queriesCount, 0);
2489
2490 ret.clear();
2491 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
2492 BOOST_CHECK_EQUAL(res, RCode::NoError);
2493 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2494 BOOST_CHECK(ret[0].d_type == QType::TXT);
2495 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2496 BOOST_CHECK_EQUAL(queriesCount, 0);
2497
2498 ret.clear();
2499 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
2500 BOOST_CHECK_EQUAL(res, RCode::NoError);
2501 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2502 BOOST_CHECK(ret[0].d_type == QType::TXT);
2503 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2504 BOOST_CHECK_EQUAL(queriesCount, 0);
2505
2506 ret.clear();
2507 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
2508 BOOST_CHECK_EQUAL(res, RCode::NoError);
2509 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2510 BOOST_CHECK(ret[0].d_type == QType::TXT);
2511 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2512 BOOST_CHECK_EQUAL(queriesCount, 0);
2513 }
2514
2515 BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2516 std::unique_ptr<SyncRes> sr;
2517 initSR(sr);
2518
2519 primeHints();
2520
2521 const DNSName target("rpz.powerdns.com.");
2522 const ComboAddress ns("192.0.2.1:53");
2523
2524 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2525
2526 if (isRootServer(ip)) {
2527 setLWResult(res, false, true, false, true);
2528 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2529 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2530 return 1;
2531 } else if (ip == ns) {
2532
2533 setLWResult(res, 0, true, false, true);
2534 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2535 return 1;
2536 }
2537
2538 return 0;
2539 });
2540
2541 DNSFilterEngine::Policy pol;
2542 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2543 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2544 zone->setName("Unit test policy 0");
2545 zone->addNSIPTrigger(Netmask(ns, 32), pol);
2546 auto luaconfsCopy = g_luaconfs.getCopy();
2547 luaconfsCopy.dfe.addZone(zone);
2548 g_luaconfs.setState(luaconfsCopy);
2549
2550 vector<DNSRecord> ret;
2551 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2552 BOOST_CHECK_EQUAL(res, -2);
2553 BOOST_CHECK_EQUAL(ret.size(), 0);
2554 }
2555
2556 BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2557 std::unique_ptr<SyncRes> sr;
2558 initSR(sr);
2559
2560 primeHints();
2561
2562 const DNSName target("rpz.powerdns.com.");
2563 const ComboAddress ns("[2001:DB8::42]:53");
2564
2565 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2566
2567 if (isRootServer(ip)) {
2568 setLWResult(res, 0, false, false, true);
2569 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2570 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2571 return 1;
2572 } else if (ip == ns) {
2573
2574 setLWResult(res, 0, true, false, true);
2575 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2576 return 1;
2577 }
2578
2579 return 0;
2580 });
2581
2582 DNSFilterEngine::Policy pol;
2583 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2584 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2585 zone->setName("Unit test policy 0");
2586 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2587 auto luaconfsCopy = g_luaconfs.getCopy();
2588 luaconfsCopy.dfe.addZone(zone);
2589 g_luaconfs.setState(luaconfsCopy);
2590
2591 vector<DNSRecord> ret;
2592 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2593 BOOST_CHECK_EQUAL(res, -2);
2594 BOOST_CHECK_EQUAL(ret.size(), 0);
2595 }
2596
2597 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2598 std::unique_ptr<SyncRes> sr;
2599 initSR(sr);
2600
2601 primeHints();
2602
2603 const DNSName target("rpz.powerdns.com.");
2604 const ComboAddress ns("192.0.2.1:53");
2605 const DNSName nsName("ns1.powerdns.com.");
2606
2607 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2608
2609 if (isRootServer(ip)) {
2610 setLWResult(res, 0, false, false, true);
2611 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2612 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2613 return 1;
2614 } else if (ip == ns) {
2615
2616 setLWResult(res, 0, true, false, true);
2617 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2618 return 1;
2619 }
2620
2621 return 0;
2622 });
2623
2624 DNSFilterEngine::Policy pol;
2625 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2626 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2627 zone->setName("Unit test policy 0");
2628 zone->addNSTrigger(nsName, pol);
2629 auto luaconfsCopy = g_luaconfs.getCopy();
2630 luaconfsCopy.dfe.addZone(zone);
2631 g_luaconfs.setState(luaconfsCopy);
2632
2633 vector<DNSRecord> ret;
2634 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2635 BOOST_CHECK_EQUAL(res, -2);
2636 BOOST_CHECK_EQUAL(ret.size(), 0);
2637 }
2638
2639 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2640 std::unique_ptr<SyncRes> sr;
2641 initSR(sr);
2642
2643 primeHints();
2644
2645 const DNSName target("rpz.powerdns.com.");
2646 const ComboAddress ns("192.0.2.1:53");
2647 const DNSName nsName("ns1.powerdns.com.");
2648
2649 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2650
2651 if (isRootServer(ip)) {
2652 setLWResult(res, 0, false, false, true);
2653 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2654 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2655 return 1;
2656 } else if (ip == ns) {
2657
2658 setLWResult(res, 0, true, false, true);
2659 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2660 return 1;
2661 }
2662
2663 return 0;
2664 });
2665
2666 DNSFilterEngine::Policy pol;
2667 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2668 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2669 zone->setName("Unit test policy 0");
2670 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2671 zone->addNSTrigger(nsName, pol);
2672 auto luaconfsCopy = g_luaconfs.getCopy();
2673 luaconfsCopy.dfe.addZone(zone);
2674 g_luaconfs.setState(luaconfsCopy);
2675
2676 /* RPZ is disabled for this query, we should not be blocked */
2677 sr->setWantsRPZ(false);
2678
2679 vector<DNSRecord> ret;
2680 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2681 BOOST_CHECK_EQUAL(res, RCode::NoError);
2682 BOOST_CHECK_EQUAL(ret.size(), 1);
2683 }
2684
2685 BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2686 std::unique_ptr<SyncRes> sr;
2687 initSR(sr);
2688
2689 primeHints();
2690
2691 const DNSName target("powerdns.com.");
2692 const ComboAddress ns("192.0.2.1:53");
2693 const ComboAddress forwardedNS("192.0.2.42:53");
2694
2695 SyncRes::AuthDomain ad;
2696 ad.d_rdForward = false;
2697 ad.d_servers.push_back(forwardedNS);
2698 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2699
2700 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2701
2702 if (ip == forwardedNS) {
2703 BOOST_CHECK_EQUAL(sendRDQuery, false);
2704
2705 setLWResult(res, 0, true, false, true);
2706 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2707 return 1;
2708 }
2709
2710 return 0;
2711 });
2712
2713 /* simulate a no-RD query */
2714 sr->setCacheOnly();
2715
2716 vector<DNSRecord> ret;
2717 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2718 BOOST_CHECK_EQUAL(res, RCode::NoError);
2719 BOOST_CHECK_EQUAL(ret.size(), 1);
2720 }
2721
2722 BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
2723 std::unique_ptr<SyncRes> sr;
2724 initSR(sr);
2725
2726 primeHints();
2727
2728 const DNSName target("powerdns.com.");
2729 const ComboAddress ns("192.0.2.1:53");
2730 const ComboAddress forwardedNS("192.0.2.42:53");
2731
2732 SyncRes::AuthDomain ad;
2733 ad.d_rdForward = false;
2734 ad.d_servers.push_back(forwardedNS);
2735 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2736
2737 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2738
2739 if (ip == forwardedNS) {
2740 BOOST_CHECK_EQUAL(sendRDQuery, false);
2741
2742 setLWResult(res, 0, true, false, true);
2743 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2744 return 1;
2745 }
2746
2747 return 0;
2748 });
2749
2750 vector<DNSRecord> ret;
2751 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2752 BOOST_CHECK_EQUAL(res, RCode::NoError);
2753 BOOST_CHECK_EQUAL(ret.size(), 1);
2754 }
2755
2756 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
2757 std::unique_ptr<SyncRes> sr;
2758 initSR(sr);
2759
2760 primeHints();
2761
2762 const DNSName target("powerdns.com.");
2763 const ComboAddress ns("192.0.2.1:53");
2764 const ComboAddress forwardedNS("192.0.2.42:53");
2765
2766 SyncRes::AuthDomain ad;
2767 ad.d_rdForward = true;
2768 ad.d_servers.push_back(forwardedNS);
2769 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2770
2771 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2772
2773 if (ip == forwardedNS) {
2774 BOOST_CHECK_EQUAL(sendRDQuery, false);
2775
2776 setLWResult(res, 0, true, false, true);
2777 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2778 return 1;
2779 }
2780
2781 return 0;
2782 });
2783
2784 /* simulate a no-RD query */
2785 sr->setCacheOnly();
2786
2787 vector<DNSRecord> ret;
2788 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2789 BOOST_CHECK_EQUAL(res, RCode::NoError);
2790 BOOST_CHECK_EQUAL(ret.size(), 1);
2791 }
2792
2793 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
2794 std::unique_ptr<SyncRes> sr;
2795 initSR(sr);
2796
2797 primeHints();
2798
2799 const DNSName target("powerdns.com.");
2800 const ComboAddress ns("192.0.2.1:53");
2801 const ComboAddress forwardedNS("192.0.2.42:53");
2802
2803 SyncRes::AuthDomain ad;
2804 ad.d_rdForward = true;
2805 ad.d_servers.push_back(forwardedNS);
2806 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2807
2808 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2809
2810 if (ip == forwardedNS) {
2811 BOOST_CHECK_EQUAL(sendRDQuery, true);
2812
2813 setLWResult(res, 0, true, false, true);
2814 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2815 return 1;
2816 }
2817
2818 return 0;
2819 });
2820
2821 vector<DNSRecord> ret;
2822 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2823 BOOST_CHECK_EQUAL(res, RCode::NoError);
2824 BOOST_CHECK_EQUAL(ret.size(), 1);
2825 }
2826
2827 BOOST_AUTO_TEST_CASE(test_auth_zone_oob) {
2828 std::unique_ptr<SyncRes> sr;
2829 initSR(sr, true);
2830
2831 primeHints();
2832
2833 size_t queriesCount = 0;
2834 const DNSName target("test.xx.");
2835 const ComboAddress targetAddr("127.0.0.1");
2836 const DNSName authZone("test.xx");
2837
2838 SyncRes::AuthDomain ad;
2839 DNSRecord dr;
2840
2841 dr.d_place = DNSResourceRecord::ANSWER;
2842 dr.d_name = target;
2843 dr.d_type = QType::A;
2844 dr.d_ttl = 1800;
2845 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
2846 ad.d_records.insert(dr);
2847
2848 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2849
2850 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2851 queriesCount++;
2852 return 0;
2853 });
2854
2855 vector<DNSRecord> ret;
2856 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2857 BOOST_CHECK_EQUAL(res, 0);
2858 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2859 BOOST_CHECK(ret[0].d_type == QType::A);
2860 BOOST_CHECK_EQUAL(queriesCount, 0);
2861 BOOST_CHECK(sr->wasOutOfBand());
2862 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2863
2864 /* a second time, to check that the OOB flag is set when the query cache is used */
2865 ret.clear();
2866 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2867 BOOST_CHECK_EQUAL(res, 0);
2868 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2869 BOOST_CHECK(ret[0].d_type == QType::A);
2870 BOOST_CHECK_EQUAL(queriesCount, 0);
2871 BOOST_CHECK(sr->wasOutOfBand());
2872 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2873
2874 /* a third time, to check that the validation is disabled when the OOB flag is set */
2875 ret.clear();
2876 sr->setDNSSECValidationRequested(true);
2877 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2878 BOOST_CHECK_EQUAL(res, 0);
2879 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2880 BOOST_CHECK(ret[0].d_type == QType::A);
2881 BOOST_CHECK_EQUAL(queriesCount, 0);
2882 BOOST_CHECK(sr->wasOutOfBand());
2883 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2884 }
2885
2886 BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) {
2887 std::unique_ptr<SyncRes> sr;
2888 initSR(sr, true);
2889
2890 primeHints();
2891
2892 size_t queriesCount = 0;
2893 const DNSName target("cname.test.xx.");
2894 const DNSName targetCname("cname-target.test.xx.");
2895 const ComboAddress targetCnameAddr("127.0.0.1");
2896 const DNSName authZone("test.xx");
2897
2898 SyncRes::AuthDomain ad;
2899 DNSRecord dr;
2900
2901 dr.d_place = DNSResourceRecord::ANSWER;
2902 dr.d_name = target;
2903 dr.d_type = QType::CNAME;
2904 dr.d_ttl = 1800;
2905 dr.d_content = std::make_shared<CNAMERecordContent>(targetCname);
2906 ad.d_records.insert(dr);
2907
2908 dr.d_place = DNSResourceRecord::ANSWER;
2909 dr.d_name = targetCname;
2910 dr.d_type = QType::A;
2911 dr.d_ttl = 1800;
2912 dr.d_content = std::make_shared<ARecordContent>(targetCnameAddr);
2913 ad.d_records.insert(dr);
2914
2915 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2916
2917 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2918 queriesCount++;
2919 return 0;
2920 });
2921
2922 vector<DNSRecord> ret;
2923 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2924 BOOST_CHECK_EQUAL(res, 0);
2925 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2926 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2927 BOOST_CHECK(ret[1].d_type == QType::A);
2928 BOOST_CHECK_EQUAL(queriesCount, 0);
2929 BOOST_CHECK(sr->wasOutOfBand());
2930 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2931
2932 /* a second time, to check that the OOB flag is set when the query cache is used */
2933 ret.clear();
2934 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2935 BOOST_CHECK_EQUAL(res, 0);
2936 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2937 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2938 BOOST_CHECK(ret[1].d_type == QType::A);
2939 BOOST_CHECK_EQUAL(queriesCount, 0);
2940 BOOST_CHECK(sr->wasOutOfBand());
2941 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2942
2943 /* a third time, to check that the validation is disabled when the OOB flag is set */
2944 ret.clear();
2945 sr->setDNSSECValidationRequested(true);
2946 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2947 BOOST_CHECK_EQUAL(res, 0);
2948 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2949 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2950 BOOST_CHECK(ret[1].d_type == QType::A);
2951 BOOST_CHECK_EQUAL(queriesCount, 0);
2952 BOOST_CHECK(sr->wasOutOfBand());
2953 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2954 }
2955
2956 BOOST_AUTO_TEST_CASE(test_auth_zone) {
2957 std::unique_ptr<SyncRes> sr;
2958 initSR(sr);
2959
2960 primeHints();
2961
2962 size_t queriesCount = 0;
2963 const DNSName target("powerdns.com.");
2964 const ComboAddress addr("192.0.2.5");
2965
2966 SyncRes::AuthDomain ad;
2967 ad.d_name = target;
2968 DNSRecord dr;
2969 dr.d_place = DNSResourceRecord::ANSWER;
2970 dr.d_name = target;
2971 dr.d_type = QType::SOA;
2972 dr.d_ttl = 3600;
2973 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2974 ad.d_records.insert(dr);
2975
2976 dr.d_place = DNSResourceRecord::ANSWER;
2977 dr.d_name = target;
2978 dr.d_type = QType::A;
2979 dr.d_ttl = 3600;
2980 dr.d_content = std::make_shared<ARecordContent>(addr);
2981 ad.d_records.insert(dr);
2982
2983 auto map = std::make_shared<SyncRes::domainmap_t>();
2984 (*map)[target] = ad;
2985 SyncRes::setDomainMap(map);
2986
2987 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2988
2989 queriesCount++;
2990 setLWResult(res, 0, true, false, true);
2991 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2992 return 1;
2993 });
2994
2995 vector<DNSRecord> ret;
2996 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2997 BOOST_CHECK_EQUAL(res, RCode::NoError);
2998 BOOST_CHECK_EQUAL(ret.size(), 1);
2999 BOOST_CHECK(ret[0].d_type == QType::A);
3000 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3001 BOOST_CHECK_EQUAL(queriesCount, 0);
3002 }
3003
3004 BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
3005 std::unique_ptr<SyncRes> sr;
3006 initSR(sr);
3007
3008 primeHints();
3009
3010 size_t queriesCount = 0;
3011 const DNSName target("powerdns.com.");
3012 const DNSName authZone("internal.powerdns.com.");
3013 const ComboAddress addr("192.0.2.5");
3014
3015 SyncRes::AuthDomain ad;
3016 ad.d_name = authZone;
3017 DNSRecord dr;
3018 dr.d_place = DNSResourceRecord::ANSWER;
3019 dr.d_name = authZone;
3020 dr.d_type = QType::SOA;
3021 dr.d_ttl = 3600;
3022 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3023 ad.d_records.insert(dr);
3024
3025 dr.d_place = DNSResourceRecord::ANSWER;
3026 dr.d_name = authZone;
3027 dr.d_type = QType::A;
3028 dr.d_ttl = 3600;
3029 dr.d_content = std::make_shared<ARecordContent>(addr);
3030 ad.d_records.insert(dr);
3031
3032 auto map = std::make_shared<SyncRes::domainmap_t>();
3033 (*map)[authZone] = ad;
3034 SyncRes::setDomainMap(map);
3035
3036 sr->setAsyncCallback([&queriesCount,target,authZone](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3037
3038 queriesCount++;
3039
3040 if (domain == target) {
3041 setLWResult(res, 0, true, false, true);
3042 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
3043 return 1;
3044 }
3045
3046 return 0;
3047 });
3048
3049 vector<DNSRecord> ret;
3050 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3051 BOOST_CHECK_EQUAL(res, RCode::NoError);
3052 BOOST_CHECK_EQUAL(ret.size(), 2);
3053 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3054 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
3055 BOOST_CHECK(ret[1].d_type == QType::A);
3056 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3057 BOOST_CHECK_EQUAL(queriesCount, 1);
3058 }
3059
3060 BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
3061 std::unique_ptr<SyncRes> sr;
3062 initSR(sr);
3063
3064 primeHints();
3065
3066 size_t queriesCount = 0;
3067 const DNSName target("powerdns.com.");
3068 const DNSName externalCNAME("www.open-xchange.com.");
3069 const ComboAddress addr("192.0.2.5");
3070
3071 SyncRes::AuthDomain ad;
3072 ad.d_name = target;
3073 DNSRecord dr;
3074 dr.d_place = DNSResourceRecord::ANSWER;
3075 dr.d_name = target;
3076 dr.d_type = QType::SOA;
3077 dr.d_ttl = 3600;
3078 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3079 ad.d_records.insert(dr);
3080
3081 dr.d_place = DNSResourceRecord::ANSWER;
3082 dr.d_name = target;
3083 dr.d_type = QType::CNAME;
3084 dr.d_ttl = 3600;
3085 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
3086 ad.d_records.insert(dr);
3087
3088 auto map = std::make_shared<SyncRes::domainmap_t>();
3089 (*map)[target] = ad;
3090 SyncRes::setDomainMap(map);
3091
3092 sr->setAsyncCallback([&queriesCount,externalCNAME,addr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3093
3094 queriesCount++;
3095
3096 if (domain == externalCNAME) {
3097 setLWResult(res, 0, true, false, true);
3098 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
3099 return 1;
3100 }
3101
3102 return 0;
3103 });
3104
3105 vector<DNSRecord> ret;
3106 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3107 BOOST_CHECK_EQUAL(res, RCode::NoError);
3108 BOOST_CHECK_EQUAL(ret.size(), 2);
3109 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3110 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
3111 BOOST_CHECK(ret[1].d_type == QType::A);
3112 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3113 BOOST_CHECK_EQUAL(queriesCount, 1);
3114 }
3115
3116 BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
3117 std::unique_ptr<SyncRes> sr;
3118 initSR(sr);
3119
3120 primeHints();
3121
3122 size_t queriesCount = 0;
3123 const DNSName target("nodata.powerdns.com.");
3124 const DNSName authZone("powerdns.com");
3125
3126 SyncRes::AuthDomain ad;
3127 ad.d_name = authZone;
3128 DNSRecord dr;
3129 dr.d_place = DNSResourceRecord::ANSWER;
3130 dr.d_name = target;
3131 dr.d_type = QType::A;
3132 dr.d_ttl = 3600;
3133 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3134 ad.d_records.insert(dr);
3135
3136 dr.d_place = DNSResourceRecord::ANSWER;
3137 dr.d_name = authZone;
3138 dr.d_type = QType::SOA;
3139 dr.d_ttl = 3600;
3140 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3141 ad.d_records.insert(dr);
3142
3143 auto map = std::make_shared<SyncRes::domainmap_t>();
3144 (*map)[authZone] = ad;
3145 SyncRes::setDomainMap(map);
3146
3147 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3148
3149 queriesCount++;
3150
3151 return 0;
3152 });
3153
3154 vector<DNSRecord> ret;
3155 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
3156 BOOST_CHECK_EQUAL(res, RCode::NoError);
3157 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3158 BOOST_CHECK(ret[0].d_type == QType::SOA);
3159 BOOST_CHECK_EQUAL(queriesCount, 0);
3160 }
3161
3162 BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3163 std::unique_ptr<SyncRes> sr;
3164 initSR(sr);
3165
3166 primeHints();
3167
3168 size_t queriesCount = 0;
3169 const DNSName target("nx.powerdns.com.");
3170 const DNSName authZone("powerdns.com");
3171
3172 SyncRes::AuthDomain ad;
3173 ad.d_name = authZone;
3174 DNSRecord dr;
3175 dr.d_place = DNSResourceRecord::ANSWER;
3176 dr.d_name = DNSName("powerdns.com.");
3177 dr.d_type = QType::SOA;
3178 dr.d_ttl = 3600;
3179 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3180 ad.d_records.insert(dr);
3181
3182 auto map = std::make_shared<SyncRes::domainmap_t>();
3183 (*map)[authZone] = ad;
3184 SyncRes::setDomainMap(map);
3185
3186 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3187
3188 queriesCount++;
3189
3190 return 0;
3191 });
3192
3193 vector<DNSRecord> ret;
3194 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3195 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3196 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3197 BOOST_CHECK(ret[0].d_type == QType::SOA);
3198 BOOST_CHECK_EQUAL(queriesCount, 0);
3199 }
3200
3201 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3202 std::unique_ptr<SyncRes> sr;
3203 initSR(sr, true, false);
3204
3205 primeHints();
3206
3207 size_t queriesCount = 0;
3208 const DNSName target("www.test.powerdns.com.");
3209 const ComboAddress targetAddr("192.0.2.2");
3210 const DNSName ns("ns1.test.powerdns.com.");
3211 const ComboAddress nsAddr("192.0.2.1");
3212 const DNSName authZone("powerdns.com");
3213
3214 SyncRes::AuthDomain ad;
3215 ad.d_name = authZone;
3216 DNSRecord dr;
3217 dr.d_place = DNSResourceRecord::ANSWER;
3218 dr.d_name = authZone;
3219 dr.d_type = QType::SOA;
3220 dr.d_ttl = 3600;
3221 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3222 ad.d_records.insert(dr);
3223
3224 dr.d_place = DNSResourceRecord::ANSWER;
3225 dr.d_name = DNSName("test.powerdns.com.");
3226 dr.d_type = QType::NS;
3227 dr.d_ttl = 3600;
3228 dr.d_content = std::make_shared<NSRecordContent>(ns);
3229 ad.d_records.insert(dr);
3230
3231 dr.d_place = DNSResourceRecord::ANSWER;
3232 dr.d_name = ns;
3233 dr.d_type = QType::A;
3234 dr.d_ttl = 3600;
3235 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3236 ad.d_records.insert(dr);
3237
3238 auto map = std::make_shared<SyncRes::domainmap_t>();
3239 (*map)[authZone] = ad;
3240 SyncRes::setDomainMap(map);
3241
3242 testkeysset_t keys;
3243 auto luaconfsCopy = g_luaconfs.getCopy();
3244 luaconfsCopy.dsAnchors.clear();
3245 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3246 g_luaconfs.setState(luaconfsCopy);
3247
3248 sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr,authZone,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3249
3250 queriesCount++;
3251 if (type == QType::DS || type == QType::DNSKEY) {
3252 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone);
3253 }
3254
3255 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3256 setLWResult(res, 0, true, false, true);
3257 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3258 return 1;
3259 }
3260
3261 return 0;
3262 });
3263
3264 sr->setDNSSECValidationRequested(true);
3265 vector<DNSRecord> ret;
3266 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3267 BOOST_CHECK_EQUAL(res, RCode::NoError);
3268 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3269 BOOST_CHECK(ret[0].d_type == QType::A);
3270 BOOST_CHECK_EQUAL(queriesCount, 4);
3271 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3272 }
3273
3274 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3275 std::unique_ptr<SyncRes> sr;
3276 initSR(sr);
3277
3278 primeHints();
3279
3280 size_t queriesCount = 0;
3281 const DNSName target("test.powerdns.com.");
3282 const ComboAddress targetAddr("192.0.2.2");
3283 const DNSName ns("ns1.test.powerdns.com.");
3284 const ComboAddress nsAddr("192.0.2.1");
3285 const DNSName authZone("powerdns.com");
3286
3287 SyncRes::AuthDomain ad;
3288 ad.d_name = authZone;
3289 DNSRecord dr;
3290 dr.d_place = DNSResourceRecord::ANSWER;
3291 dr.d_name = authZone;
3292 dr.d_type = QType::SOA;
3293 dr.d_ttl = 3600;
3294 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3295 ad.d_records.insert(dr);
3296
3297 dr.d_place = DNSResourceRecord::ANSWER;
3298 dr.d_name = DNSName("test.powerdns.com.");
3299 dr.d_type = QType::NS;
3300 dr.d_ttl = 3600;
3301 dr.d_content = std::make_shared<NSRecordContent>(ns);
3302 ad.d_records.insert(dr);
3303
3304 dr.d_place = DNSResourceRecord::ANSWER;
3305 dr.d_name = ns;
3306 dr.d_type = QType::A;
3307 dr.d_ttl = 3600;
3308 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3309 ad.d_records.insert(dr);
3310
3311 auto map = std::make_shared<SyncRes::domainmap_t>();
3312 (*map)[authZone] = ad;
3313 SyncRes::setDomainMap(map);
3314
3315 sr->setAsyncCallback([&queriesCount,nsAddr,target,targetAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3316
3317 queriesCount++;
3318
3319 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3320 setLWResult(res, 0, true, false, true);
3321 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3322 return 1;
3323 }
3324
3325 return 0;
3326 });
3327
3328 vector<DNSRecord> ret;
3329 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3330 BOOST_CHECK_EQUAL(res, RCode::NoError);
3331 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3332 BOOST_CHECK(ret[0].d_type == QType::A);
3333 BOOST_CHECK_EQUAL(queriesCount, 1);
3334 }
3335
3336 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3337 std::unique_ptr<SyncRes> sr;
3338 initSR(sr);
3339
3340 primeHints();
3341
3342 size_t queriesCount = 0;
3343 const DNSName target("test.powerdns.com.");
3344 const ComboAddress targetAddr("192.0.2.2");
3345 const DNSName authZone("powerdns.com");
3346
3347 SyncRes::AuthDomain ad;
3348 ad.d_name = authZone;
3349 DNSRecord dr;
3350 dr.d_place = DNSResourceRecord::ANSWER;
3351 dr.d_name = authZone;
3352 dr.d_type = QType::SOA;
3353 dr.d_ttl = 3600;
3354 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3355 ad.d_records.insert(dr);
3356
3357 dr.d_place = DNSResourceRecord::ANSWER;
3358 dr.d_name = DNSName("*.powerdns.com.");
3359 dr.d_type = QType::A;
3360 dr.d_ttl = 3600;
3361 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3362 ad.d_records.insert(dr);
3363
3364 auto map = std::make_shared<SyncRes::domainmap_t>();
3365 (*map)[authZone] = ad;
3366 SyncRes::setDomainMap(map);
3367
3368 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3369
3370 queriesCount++;
3371
3372 return 0;
3373 });
3374
3375 vector<DNSRecord> ret;
3376 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3377 BOOST_CHECK_EQUAL(res, RCode::NoError);
3378 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3379 BOOST_CHECK(ret[0].d_type == QType::A);
3380 BOOST_CHECK_EQUAL(queriesCount, 0);
3381 }
3382
3383 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3384 std::unique_ptr<SyncRes> sr;
3385 initSR(sr);
3386
3387 primeHints();
3388
3389 size_t queriesCount = 0;
3390 const DNSName target("test.powerdns.com.");
3391 const ComboAddress targetAddr("192.0.2.2");
3392 const DNSName authZone("powerdns.com");
3393
3394 SyncRes::AuthDomain ad;
3395 ad.d_name = authZone;
3396 DNSRecord dr;
3397 dr.d_place = DNSResourceRecord::ANSWER;
3398 dr.d_name = authZone;
3399 dr.d_type = QType::SOA;
3400 dr.d_ttl = 3600;
3401 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3402 ad.d_records.insert(dr);
3403
3404 dr.d_place = DNSResourceRecord::ANSWER;
3405 dr.d_name = DNSName("*.powerdns.com.");
3406 dr.d_type = QType::A;
3407 dr.d_ttl = 3600;
3408 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3409 ad.d_records.insert(dr);
3410
3411 auto map = std::make_shared<SyncRes::domainmap_t>();
3412 (*map)[authZone] = ad;
3413 SyncRes::setDomainMap(map);
3414
3415 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3416
3417 queriesCount++;
3418
3419 return 0;
3420 });
3421
3422 vector<DNSRecord> ret;
3423 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
3424 BOOST_CHECK_EQUAL(res, RCode::NoError);
3425 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3426 BOOST_CHECK(ret[0].d_type == QType::SOA);
3427 BOOST_CHECK_EQUAL(queriesCount, 0);
3428 }
3429
3430 BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3431 std::unique_ptr<SyncRes> sr;
3432 initSR(sr);
3433
3434 primeHints();
3435
3436 size_t queriesCount = 0;
3437 const DNSName target("powerdns.com.");
3438 const ComboAddress addr("192.0.2.5");
3439
3440 SyncRes::AuthDomain ad;
3441 ad.d_name = target;
3442 DNSRecord dr;
3443 dr.d_place = DNSResourceRecord::ANSWER;
3444 dr.d_name = target;
3445 dr.d_type = QType::SOA;
3446 dr.d_ttl = 3600;
3447 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3448 ad.d_records.insert(dr);
3449
3450 dr.d_place = DNSResourceRecord::ANSWER;
3451 dr.d_name = target;
3452 dr.d_type = QType::A;
3453 dr.d_ttl = 3600;
3454 dr.d_content = std::make_shared<ARecordContent>(addr);
3455 ad.d_records.insert(dr);
3456
3457 auto map = std::make_shared<SyncRes::domainmap_t>();
3458 (*map)[target] = ad;
3459 SyncRes::setDomainMap(map);
3460
3461 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3462
3463 queriesCount++;
3464 setLWResult(res, 0, true, false, true);
3465 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3466 return 1;
3467 });
3468
3469 /* simulate a no-RD query */
3470 sr->setCacheOnly();
3471
3472 vector<DNSRecord> ret;
3473 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3474 BOOST_CHECK_EQUAL(res, RCode::NoError);
3475 BOOST_CHECK_EQUAL(ret.size(), 1);
3476 BOOST_CHECK(ret[0].d_type == QType::A);
3477 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3478 BOOST_CHECK_EQUAL(queriesCount, 0);
3479 }
3480
3481 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
3482 init();
3483
3484 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3485 dcke->create(dcke->getBits());
3486 // cerr<<dcke->convertToISC()<<endl;
3487 DNSSECPrivateKey dpk;
3488 dpk.d_flags = 256;
3489 dpk.setKey(dcke);
3490
3491 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3492 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3493
3494 DNSName qname("powerdns.com.");
3495
3496 time_t now = time(nullptr);
3497 RRSIGRecordContent rrc;
3498 /* this RRSIG is valid for the current second only */
3499 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
3500
3501 skeyset_t keyset;
3502 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3503
3504 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3505 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3506
3507 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
3508 }
3509
3510 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3511 std::unique_ptr<SyncRes> sr;
3512 initSR(sr, true);
3513
3514 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3515
3516 primeHints();
3517 const DNSName target(".");
3518 testkeysset_t keys;
3519
3520 auto luaconfsCopy = g_luaconfs.getCopy();
3521 luaconfsCopy.dsAnchors.clear();
3522 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3523 g_luaconfs.setState(luaconfsCopy);
3524
3525 size_t queriesCount = 0;
3526
3527 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3528 queriesCount++;
3529
3530 if (domain == target && type == QType::NS) {
3531
3532 setLWResult(res, 0, true, false, true);
3533 char addr[] = "a.root-servers.net.";
3534 for (char idx = 'a'; idx <= 'm'; idx++) {
3535 addr[0] = idx;
3536 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3537 }
3538
3539 addRRSIG(keys, res->d_records, domain, 300);
3540
3541 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3542 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3543
3544 return 1;
3545 } else if (domain == target && type == QType::DNSKEY) {
3546
3547 setLWResult(res, 0, true, false, true);
3548
3549 addDNSKEY(keys, domain, 300, res->d_records);
3550 addRRSIG(keys, res->d_records, domain, 300);
3551
3552 return 1;
3553 }
3554
3555 return 0;
3556 });
3557
3558 vector<DNSRecord> ret;
3559 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3560 BOOST_CHECK_EQUAL(res, RCode::NoError);
3561 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3562 /* 13 NS + 1 RRSIG */
3563 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3564 BOOST_CHECK_EQUAL(queriesCount, 2);
3565
3566 /* again, to test the cache */
3567 ret.clear();
3568 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3569 BOOST_CHECK_EQUAL(res, RCode::NoError);
3570 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3571 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3572 BOOST_CHECK_EQUAL(queriesCount, 2);
3573 }
3574
3575 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3576 std::unique_ptr<SyncRes> sr;
3577 initSR(sr, true);
3578
3579 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3580
3581 primeHints();
3582 const DNSName target(".");
3583 testkeysset_t zskeys;
3584 testkeysset_t kskeys;
3585
3586 /* Generate key material for "." */
3587 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3588 dckeZ->create(dckeZ->getBits());
3589 DNSSECPrivateKey ksk;
3590 ksk.d_flags = 257;
3591 ksk.setKey(dckeZ);
3592 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3593
3594 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3595 dckeK->create(dckeK->getBits());
3596 DNSSECPrivateKey zsk;
3597 zsk.d_flags = 256;
3598 zsk.setKey(dckeK);
3599 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
3600
3601 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3602 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
3603
3604 /* Set the root DS */
3605 auto luaconfsCopy = g_luaconfs.getCopy();
3606 luaconfsCopy.dsAnchors.clear();
3607 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
3608 g_luaconfs.setState(luaconfsCopy);
3609
3610 size_t queriesCount = 0;
3611
3612 sr->setAsyncCallback([target,&queriesCount,zskeys,kskeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3613 queriesCount++;
3614
3615 if (domain == target && type == QType::NS) {
3616
3617 setLWResult(res, 0, true, false, true);
3618 char addr[] = "a.root-servers.net.";
3619 for (char idx = 'a'; idx <= 'm'; idx++) {
3620 addr[0] = idx;
3621 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3622 }
3623
3624 addRRSIG(zskeys, res->d_records, domain, 300);
3625
3626 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3627 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3628
3629 return 1;
3630 } else if (domain == target && type == QType::DNSKEY) {
3631
3632 setLWResult(res, 0, true, false, true);
3633
3634 addDNSKEY(kskeys, domain, 300, res->d_records);
3635 addDNSKEY(zskeys, domain, 300, res->d_records);
3636 addRRSIG(kskeys, res->d_records, domain, 300);
3637
3638 return 1;
3639 }
3640
3641 return 0;
3642 });
3643
3644 vector<DNSRecord> ret;
3645 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3646 BOOST_CHECK_EQUAL(res, RCode::NoError);
3647 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3648 /* 13 NS + 1 RRSIG */
3649 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3650 BOOST_CHECK_EQUAL(queriesCount, 2);
3651
3652 /* again, to test the cache */
3653 ret.clear();
3654 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3655 BOOST_CHECK_EQUAL(res, RCode::NoError);
3656 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3657 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3658 BOOST_CHECK_EQUAL(queriesCount, 2);
3659 }
3660
3661 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
3662 std::unique_ptr<SyncRes> sr;
3663 initSR(sr, true);
3664
3665 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3666
3667 primeHints();
3668 const DNSName target(".");
3669 testkeysset_t keys;
3670
3671 auto luaconfsCopy = g_luaconfs.getCopy();
3672 luaconfsCopy.dsAnchors.clear();
3673 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3674 g_luaconfs.setState(luaconfsCopy);
3675
3676 size_t queriesCount = 0;
3677
3678 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3679 queriesCount++;
3680
3681 if (domain == target && type == QType::NS) {
3682
3683 setLWResult(res, 0, true, false, true);
3684 char addr[] = "a.root-servers.net.";
3685 for (char idx = 'a'; idx <= 'm'; idx++) {
3686 addr[0] = idx;
3687 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3688 }
3689
3690 addRRSIG(keys, res->d_records, domain, 300);
3691
3692 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3693 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3694
3695 return 1;
3696 } else if (domain == target && type == QType::DNSKEY) {
3697
3698 setLWResult(res, 0, true, false, true);
3699
3700 /* No DNSKEY */
3701
3702 return 1;
3703 }
3704
3705 return 0;
3706 });
3707
3708 vector<DNSRecord> ret;
3709 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3710 BOOST_CHECK_EQUAL(res, RCode::NoError);
3711 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3712 /* 13 NS + 1 RRSIG */
3713 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3714 BOOST_CHECK_EQUAL(queriesCount, 2);
3715
3716 /* again, to test the cache */
3717 ret.clear();
3718 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3719 BOOST_CHECK_EQUAL(res, RCode::NoError);
3720 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3721 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3722 BOOST_CHECK_EQUAL(queriesCount, 2);
3723 }
3724
3725 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3726 std::unique_ptr<SyncRes> sr;
3727 initSR(sr, true);
3728
3729 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3730
3731 primeHints();
3732 const DNSName target(".");
3733 testkeysset_t dskeys;
3734 testkeysset_t keys;
3735
3736 /* Generate key material for "." */
3737 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3738 dckeDS->create(dckeDS->getBits());
3739 DNSSECPrivateKey dskey;
3740 dskey.d_flags = 257;
3741 dskey.setKey(dckeDS);
3742 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3743
3744 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3745 dcke->create(dcke->getBits());
3746 DNSSECPrivateKey dpk;
3747 dpk.d_flags = 256;
3748 dpk.setKey(dcke);
3749 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3750
3751 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3752 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
3753
3754 /* Set the root DS */
3755 auto luaconfsCopy = g_luaconfs.getCopy();
3756 luaconfsCopy.dsAnchors.clear();
3757 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3758 g_luaconfs.setState(luaconfsCopy);
3759
3760 size_t queriesCount = 0;
3761
3762 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3763 queriesCount++;
3764
3765 if (domain == target && type == QType::NS) {
3766
3767 setLWResult(res, 0, true, false, true);
3768 char addr[] = "a.root-servers.net.";
3769 for (char idx = 'a'; idx <= 'm'; idx++) {
3770 addr[0] = idx;
3771 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3772 }
3773
3774 addRRSIG(keys, res->d_records, domain, 300);
3775
3776 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3777 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3778
3779 return 1;
3780 } else if (domain == target && type == QType::DNSKEY) {
3781
3782 setLWResult(res, 0, true, false, true);
3783
3784 addDNSKEY(keys, domain, 300, res->d_records);
3785 addRRSIG(keys, res->d_records, domain, 300);
3786
3787 return 1;
3788 }
3789
3790 return 0;
3791 });
3792
3793 vector<DNSRecord> ret;
3794 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3795 BOOST_CHECK_EQUAL(res, RCode::NoError);
3796 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3797 /* 13 NS + 1 RRSIG */
3798 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3799 BOOST_CHECK_EQUAL(queriesCount, 2);
3800
3801 /* again, to test the cache */
3802 ret.clear();
3803 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3804 BOOST_CHECK_EQUAL(res, RCode::NoError);
3805 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3806 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3807 BOOST_CHECK_EQUAL(queriesCount, 2);
3808 }
3809
3810 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
3811 std::unique_ptr<SyncRes> sr;
3812 initSR(sr, true);
3813
3814 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3815
3816 primeHints();
3817 const DNSName target(".");
3818 testkeysset_t keys;
3819 testkeysset_t rrsigkeys;
3820
3821 auto luaconfsCopy = g_luaconfs.getCopy();
3822 luaconfsCopy.dsAnchors.clear();
3823 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3824 g_luaconfs.setState(luaconfsCopy);
3825
3826 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3827 dckeRRSIG->create(dckeRRSIG->getBits());
3828 DNSSECPrivateKey rrsigkey;
3829 rrsigkey.d_flags = 257;
3830 rrsigkey.setKey(dckeRRSIG);
3831 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
3832
3833 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
3834
3835 size_t queriesCount = 0;
3836
3837 sr->setAsyncCallback([target,&queriesCount,keys,rrsigkeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3838 queriesCount++;
3839
3840 if (domain == target && type == QType::NS) {
3841
3842 setLWResult(res, 0, true, false, true);
3843 char addr[] = "a.root-servers.net.";
3844 for (char idx = 'a'; idx <= 'm'; idx++) {
3845 addr[0] = idx;
3846 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3847 }
3848
3849 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3850
3851 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3852 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3853
3854 return 1;
3855 } else if (domain == target && type == QType::DNSKEY) {
3856
3857 setLWResult(res, 0, true, false, true);
3858
3859 addDNSKEY(keys, domain, 300, res->d_records);
3860 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3861
3862 return 1;
3863 }
3864
3865 return 0;
3866 });
3867
3868 vector<DNSRecord> ret;
3869 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3870 BOOST_CHECK_EQUAL(res, RCode::NoError);
3871 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3872 /* 13 NS + 1 RRSIG */
3873 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3874 BOOST_CHECK_EQUAL(queriesCount, 2);
3875
3876 /* again, to test the cache */
3877 ret.clear();
3878 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3879 BOOST_CHECK_EQUAL(res, RCode::NoError);
3880 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3881 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3882 BOOST_CHECK_EQUAL(queriesCount, 2);
3883 }
3884
3885 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
3886 std::unique_ptr<SyncRes> sr;
3887 initSR(sr, true);
3888
3889 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3890
3891 primeHints();
3892 const DNSName target(".");
3893 testkeysset_t keys;
3894
3895 auto luaconfsCopy = g_luaconfs.getCopy();
3896 luaconfsCopy.dsAnchors.clear();
3897 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3898 g_luaconfs.setState(luaconfsCopy);
3899
3900 size_t queriesCount = 0;
3901
3902 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3903 queriesCount++;
3904
3905 if (domain == target && type == QType::NS) {
3906
3907 setLWResult(res, 0, true, false, true);
3908 char addr[] = "a.root-servers.net.";
3909 for (char idx = 'a'; idx <= 'm'; idx++) {
3910 addr[0] = idx;
3911 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3912 }
3913
3914 /* No RRSIG */
3915
3916 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3917 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3918
3919 return 1;
3920 } else if (domain == target && type == QType::DNSKEY) {
3921
3922 setLWResult(res, 0, true, false, true);
3923
3924 addDNSKEY(keys, domain, 300, res->d_records);
3925 addRRSIG(keys, res->d_records, domain, 300);
3926
3927 return 1;
3928 }
3929
3930 return 0;
3931 });
3932
3933 vector<DNSRecord> ret;
3934 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3935 BOOST_CHECK_EQUAL(res, RCode::NoError);
3936 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3937 /* 13 NS + 0 RRSIG */
3938 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3939 /* no RRSIG so no query for DNSKEYs */
3940 BOOST_CHECK_EQUAL(queriesCount, 1);
3941
3942 /* again, to test the cache */
3943 ret.clear();
3944 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3945 BOOST_CHECK_EQUAL(res, RCode::NoError);
3946 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3947 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3948 BOOST_CHECK_EQUAL(queriesCount, 1);
3949 }
3950
3951 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
3952 std::unique_ptr<SyncRes> sr;
3953 initSR(sr, true);
3954
3955 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3956
3957 primeHints();
3958 const DNSName target(".");
3959 testkeysset_t keys;
3960
3961 /* Generate key material for "." */
3962 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3963 dcke->create(dcke->getBits());
3964 DNSSECPrivateKey dpk;
3965 dpk.d_flags = 256;
3966 dpk.setKey(dcke);
3967 /* Fake algorithm number (private) */
3968 dpk.d_algorithm = 253;
3969
3970 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3971 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
3972 /* Fake algorithm number (private) */
3973 drc.d_algorithm = 253;
3974
3975 /* Set the root DS */
3976 auto luaconfsCopy = g_luaconfs.getCopy();
3977 luaconfsCopy.dsAnchors.clear();
3978 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3979 g_luaconfs.setState(luaconfsCopy);
3980
3981 size_t queriesCount = 0;
3982
3983 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3984 queriesCount++;
3985
3986 if (domain == target && type == QType::NS) {
3987
3988 setLWResult(res, 0, true, false, true);
3989 char addr[] = "a.root-servers.net.";
3990 for (char idx = 'a'; idx <= 'm'; idx++) {
3991 addr[0] = idx;
3992 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3993 }
3994
3995 addRRSIG(keys, res->d_records, domain, 300);
3996
3997 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3998 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3999
4000 return 1;
4001 } else if (domain == target && type == QType::DNSKEY) {
4002
4003 setLWResult(res, 0, true, false, true);
4004
4005 addDNSKEY(keys, domain, 300, res->d_records);
4006 addRRSIG(keys, res->d_records, domain, 300);
4007
4008 return 1;
4009 }
4010
4011 return 0;
4012 });
4013
4014 vector<DNSRecord> ret;
4015 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4016 BOOST_CHECK_EQUAL(res, RCode::NoError);
4017 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4018 /* 13 NS + 1 RRSIG */
4019 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4020 /* no supported DS so no query for DNSKEYs */
4021 BOOST_CHECK_EQUAL(queriesCount, 1);
4022
4023 /* again, to test the cache */
4024 ret.clear();
4025 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4026 BOOST_CHECK_EQUAL(res, RCode::NoError);
4027 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4028 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4029 BOOST_CHECK_EQUAL(queriesCount, 1);
4030 }
4031
4032 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
4033 std::unique_ptr<SyncRes> sr;
4034 initSR(sr, true);
4035
4036 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4037
4038 primeHints();
4039 const DNSName target(".");
4040 testkeysset_t keys;
4041
4042 /* Generate key material for "." */
4043 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4044 dcke->create(dcke->getBits());
4045 DNSSECPrivateKey dpk;
4046 dpk.d_flags = 256;
4047 dpk.setKey(dcke);
4048 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
4049 /* Fake digest number (reserved) */
4050 drc.d_digesttype = 0;
4051
4052 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
4053
4054 /* Set the root DS */
4055 auto luaconfsCopy = g_luaconfs.getCopy();
4056 luaconfsCopy.dsAnchors.clear();
4057 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4058 g_luaconfs.setState(luaconfsCopy);
4059
4060 size_t queriesCount = 0;
4061
4062 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4063 queriesCount++;
4064
4065 if (domain == target && type == QType::NS) {
4066
4067 setLWResult(res, 0, true, false, true);
4068 char addr[] = "a.root-servers.net.";
4069 for (char idx = 'a'; idx <= 'm'; idx++) {
4070 addr[0] = idx;
4071 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4072 }
4073
4074 addRRSIG(keys, res->d_records, domain, 300);
4075
4076 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4077 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4078
4079 return 1;
4080 } else if (domain == target && type == QType::DNSKEY) {
4081
4082 setLWResult(res, 0, true, false, true);
4083
4084 addDNSKEY(keys, domain, 300, res->d_records);
4085 addRRSIG(keys, res->d_records, domain, 300);
4086
4087 return 1;
4088 }
4089
4090 return 0;
4091 });
4092
4093 vector<DNSRecord> ret;
4094 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4095 BOOST_CHECK_EQUAL(res, RCode::NoError);
4096 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4097 /* 13 NS + 1 RRSIG */
4098 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4099 /* no supported DS so no query for DNSKEYs */
4100 BOOST_CHECK_EQUAL(queriesCount, 1);
4101
4102 /* again, to test the cache */
4103 ret.clear();
4104 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4105 BOOST_CHECK_EQUAL(res, RCode::NoError);
4106 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4107 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4108 BOOST_CHECK_EQUAL(queriesCount, 1);
4109 }
4110
4111 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
4112 std::unique_ptr<SyncRes> sr;
4113 initSR(sr, true);
4114
4115 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4116
4117 primeHints();
4118 const DNSName target(".");
4119 testkeysset_t keys;
4120
4121 auto luaconfsCopy = g_luaconfs.getCopy();
4122 luaconfsCopy.dsAnchors.clear();
4123 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4124
4125 g_luaconfs.setState(luaconfsCopy);
4126
4127 size_t queriesCount = 0;
4128
4129 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4130 queriesCount++;
4131
4132 if (domain == target && type == QType::NS) {
4133
4134 setLWResult(res, 0, true, false, true);
4135 char addr[] = "a.root-servers.net.";
4136 for (char idx = 'a'; idx <= 'm'; idx++) {
4137 addr[0] = idx;
4138 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4139 }
4140
4141 addRRSIG(keys, res->d_records, domain, 300, true);
4142
4143 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4144 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4145
4146 return 1;
4147 } else if (domain == target && type == QType::DNSKEY) {
4148
4149 setLWResult(res, 0, true, false, true);
4150
4151 addDNSKEY(keys, domain, 300, res->d_records);
4152 addRRSIG(keys, res->d_records, domain, 300);
4153
4154 return 1;
4155 }
4156
4157 return 0;
4158 });
4159
4160 vector<DNSRecord> ret;
4161 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4162 BOOST_CHECK_EQUAL(res, RCode::NoError);
4163 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4164 /* 13 NS + 1 RRSIG */
4165 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4166 BOOST_CHECK_EQUAL(queriesCount, 2);
4167
4168 /* again, to test the cache */
4169 ret.clear();
4170 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4171 BOOST_CHECK_EQUAL(res, RCode::NoError);
4172 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4173 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4174 BOOST_CHECK_EQUAL(queriesCount, 2);
4175 }
4176
4177 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
4178 std::unique_ptr<SyncRes> sr;
4179 initSR(sr, true);
4180
4181 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4182
4183 primeHints();
4184 const DNSName target(".");
4185 testkeysset_t keys;
4186
4187 auto luaconfsCopy = g_luaconfs.getCopy();
4188 luaconfsCopy.dsAnchors.clear();
4189 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4190
4191 g_luaconfs.setState(luaconfsCopy);
4192
4193 size_t queriesCount = 0;
4194
4195 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4196 queriesCount++;
4197
4198 if (domain == target && type == QType::NS) {
4199
4200 setLWResult(res, 0, true, false, true);
4201 char addr[] = "a.root-servers.net.";
4202 for (char idx = 'a'; idx <= 'm'; idx++) {
4203 addr[0] = idx;
4204 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4205 }
4206
4207 /* FORCE WRONG ALGO */
4208 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4209
4210 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4211 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4212
4213 return 1;
4214 } else if (domain == target && type == QType::DNSKEY) {
4215
4216 setLWResult(res, 0, true, false, true);
4217
4218 addDNSKEY(keys, domain, 300, res->d_records);
4219 addRRSIG(keys, res->d_records, domain, 300);
4220
4221 return 1;
4222 }
4223
4224 return 0;
4225 });
4226
4227 vector<DNSRecord> ret;
4228 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4229 BOOST_CHECK_EQUAL(res, RCode::NoError);
4230 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4231 /* 13 NS + 1 RRSIG */
4232 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4233 BOOST_CHECK_EQUAL(queriesCount, 2);
4234
4235 /* again, to test the cache */
4236 ret.clear();
4237 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4238 BOOST_CHECK_EQUAL(res, RCode::NoError);
4239 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4240 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4241 BOOST_CHECK_EQUAL(queriesCount, 2);
4242 }
4243
4244 BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
4245 std::unique_ptr<SyncRes> sr;
4246 initSR(sr, true);
4247
4248 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4249
4250 primeHints();
4251 const DNSName target("powerdns.com.");
4252 const ComboAddress targetAddr("192.0.2.42");
4253 testkeysset_t keys;
4254
4255 auto luaconfsCopy = g_luaconfs.getCopy();
4256 luaconfsCopy.dsAnchors.clear();
4257 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4258 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4259 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
4260
4261 g_luaconfs.setState(luaconfsCopy);
4262
4263 size_t queriesCount = 0;
4264
4265 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) {
4266 queriesCount++;
4267
4268 DNSName auth = domain;
4269 if (domain == target) {
4270 auth = DNSName("powerdns.com.");
4271 }
4272
4273 if (type == QType::DS || type == QType::DNSKEY) {
4274 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4275 }
4276
4277 if (isRootServer(ip)) {
4278 setLWResult(res, 0, false, false, true);
4279 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4280 addDS(DNSName("com."), 300, res->d_records, keys);
4281 addRRSIG(keys, res->d_records, DNSName("."), 300);
4282 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4283 return 1;
4284 }
4285
4286 if (ip == ComboAddress("192.0.2.1:53")) {
4287 if (domain == DNSName("com.")) {
4288 setLWResult(res, 0, true, false, true);
4289 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4290 addRRSIG(keys, res->d_records, domain, 300);
4291 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4292 addRRSIG(keys, res->d_records, domain, 300);
4293 }
4294 else {
4295 setLWResult(res, 0, false, false, true);
4296 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4297 addDS(auth, 300, res->d_records, keys);
4298 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4299 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4300 }
4301 return 1;
4302 }
4303
4304 if (ip == ComboAddress("192.0.2.2:53")) {
4305 if (type == QType::NS) {
4306 setLWResult(res, 0, true, false, true);
4307 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4308 addRRSIG(keys, res->d_records, auth, 300);
4309 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4310 addRRSIG(keys, res->d_records, auth, 300);
4311 }
4312 else {
4313 setLWResult(res, RCode::NoError, true, false, true);
4314 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4315 addRRSIG(keys, res->d_records, auth, 300);
4316 }
4317 return 1;
4318 }
4319
4320 return 0;
4321 });
4322
4323 vector<DNSRecord> ret;
4324 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4325 BOOST_CHECK_EQUAL(res, RCode::NoError);
4326 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4327 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4328 BOOST_CHECK_EQUAL(queriesCount, 8);
4329
4330 /* again, to test the cache */
4331 ret.clear();
4332 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4333 BOOST_CHECK_EQUAL(res, RCode::NoError);
4334 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4335 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4336 BOOST_CHECK_EQUAL(queriesCount, 8);
4337 }
4338
4339 BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4340 std::unique_ptr<SyncRes> sr;
4341 initSR(sr, true);
4342
4343 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4344
4345 primeHints();
4346 const DNSName target("powerdns.com.");
4347 const ComboAddress targetAddr("192.0.2.42");
4348 testkeysset_t keys;
4349
4350 auto luaconfsCopy = g_luaconfs.getCopy();
4351 luaconfsCopy.dsAnchors.clear();
4352 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4353 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4354 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4355 g_luaconfs.setState(luaconfsCopy);
4356
4357 size_t queriesCount = 0;
4358
4359 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) {
4360 queriesCount++;
4361
4362 DNSName auth = domain;
4363 if (domain == target) {
4364 auth = DNSName("powerdns.com.");
4365 }
4366
4367 if (type == QType::DS || type == QType::DNSKEY) {
4368 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
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 addDS(DNSName("com."), 300, res->d_records, keys);
4375 addRRSIG(keys, res->d_records, DNSName("."), 300);
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 if (domain == DNSName("com.")) {
4382 setLWResult(res, 0, true, false, true);
4383 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4384 addRRSIG(keys, res->d_records, domain, 300);
4385 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4386 addRRSIG(keys, res->d_records, domain, 300);
4387 }
4388 else {
4389 setLWResult(res, 0, false, false, true);
4390 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4391 addDS(auth, 300, res->d_records, keys);
4392 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4393 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4394 }
4395 return 1;
4396 }
4397
4398 if (ip == ComboAddress("192.0.2.2:53")) {
4399 if (type == QType::NS) {
4400 setLWResult(res, 0, true, false, true);
4401 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4402 addRRSIG(keys, res->d_records, auth, 300);
4403 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4404 addRRSIG(keys, res->d_records, auth, 300);
4405 }
4406 else {
4407 setLWResult(res, RCode::NoError, true, false, true);
4408 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4409 addRRSIG(keys, res->d_records, auth, 300);
4410 }
4411 return 1;
4412 }
4413
4414 return 0;
4415 });
4416
4417 vector<DNSRecord> ret;
4418 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4419 BOOST_CHECK_EQUAL(res, RCode::NoError);
4420 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4421 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4422 BOOST_CHECK_EQUAL(queriesCount, 8);
4423
4424 /* again, to test the cache */
4425 ret.clear();
4426 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4427 BOOST_CHECK_EQUAL(res, RCode::NoError);
4428 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4429 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4430 BOOST_CHECK_EQUAL(queriesCount, 8);
4431
4432 /* this time we ask for the NS that should be in the cache, to check
4433 the validation status */
4434 ret.clear();
4435 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4436 BOOST_CHECK_EQUAL(res, RCode::NoError);
4437 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4438 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4439 BOOST_CHECK_EQUAL(queriesCount, 9);
4440
4441 }
4442
4443 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4444 std::unique_ptr<SyncRes> sr;
4445 initSR(sr, true);
4446
4447 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4448
4449 primeHints();
4450 const DNSName target("powerdns.com.");
4451 const ComboAddress targetAddr("192.0.2.42");
4452 testkeysset_t keys;
4453
4454 auto luaconfsCopy = g_luaconfs.getCopy();
4455 luaconfsCopy.dsAnchors.clear();
4456 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4457 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4458 g_luaconfs.setState(luaconfsCopy);
4459
4460 size_t queriesCount = 0;
4461
4462 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) {
4463 queriesCount++;
4464
4465 DNSName auth = domain;
4466 if (domain == target) {
4467 auth = DNSName("powerdns.com.");
4468 }
4469
4470 if (type == QType::DS || type == QType::DNSKEY) {
4471 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4472 }
4473
4474 if (isRootServer(ip)) {
4475 setLWResult(res, 0, false, false, true);
4476 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4477 addDS(DNSName("com."), 300, res->d_records, keys);
4478 addRRSIG(keys, res->d_records, DNSName("."), 300);
4479 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4480 return 1;
4481 }
4482
4483 if (ip == ComboAddress("192.0.2.1:53")) {
4484 if (domain == DNSName("com.")) {
4485 setLWResult(res, 0, true, false, true);
4486 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4487 addRRSIG(keys, res->d_records, domain, 300);
4488 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4489 addRRSIG(keys, res->d_records, domain, 300);
4490 }
4491 else {
4492 setLWResult(res, 0, false, false, true);
4493 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4494 /* no DS */
4495 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4496 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4497 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4498 }
4499 return 1;
4500 }
4501
4502 if (ip == ComboAddress("192.0.2.2:53")) {
4503 if (type == QType::NS) {
4504 setLWResult(res, 0, true, false, true);
4505 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4506 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4507 }
4508 else {
4509 setLWResult(res, RCode::NoError, true, false, true);
4510 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4511 }
4512 return 1;
4513 }
4514
4515 return 0;
4516 });
4517
4518 vector<DNSRecord> ret;
4519 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4520 BOOST_CHECK_EQUAL(res, RCode::NoError);
4521 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4522 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4523 BOOST_CHECK_EQUAL(queriesCount, 7);
4524
4525 /* again, to test the cache */
4526 ret.clear();
4527 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4528 BOOST_CHECK_EQUAL(res, RCode::NoError);
4529 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4530 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4531 BOOST_CHECK_EQUAL(queriesCount, 7);
4532
4533 /* this time we ask for the NS that should be in the cache, to check
4534 the validation status */
4535 ret.clear();
4536 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4537 BOOST_CHECK_EQUAL(res, RCode::NoError);
4538 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4539 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4540 BOOST_CHECK_EQUAL(queriesCount, 8);
4541 }
4542
4543 BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
4544 std::unique_ptr<SyncRes> sr;
4545 initSR(sr, true);
4546
4547 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4548
4549 primeHints();
4550 const DNSName target("powerdns.com.");
4551 const ComboAddress targetAddr("192.0.2.42");
4552 testkeysset_t keys;
4553
4554 auto luaconfsCopy = g_luaconfs.getCopy();
4555 luaconfsCopy.dsAnchors.clear();
4556 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4557 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4558 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4559
4560 /* Add a NTA for "powerdns.com" */
4561 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4562
4563 g_luaconfs.setState(luaconfsCopy);
4564
4565 size_t queriesCount = 0;
4566
4567 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) {
4568 queriesCount++;
4569
4570 DNSName auth = domain;
4571 if (domain == target) {
4572 auth = DNSName("powerdns.com.");
4573 }
4574
4575 if (type == QType::DS || type == QType::DNSKEY) {
4576 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4577 }
4578
4579 if (isRootServer(ip)) {
4580 setLWResult(res, 0, false, false, true);
4581 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4582 addDS(DNSName("com."), 300, res->d_records, keys);
4583 addRRSIG(keys, res->d_records, DNSName("."), 300);
4584 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4585 return 1;
4586 }
4587
4588 if (ip == ComboAddress("192.0.2.1:53")) {
4589 if (domain == DNSName("com.")) {
4590 setLWResult(res, 0, true, false, true);
4591 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4592 addRRSIG(keys, res->d_records, domain, 300);
4593 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4594 addRRSIG(keys, res->d_records, domain, 300);
4595 }
4596 else {
4597 setLWResult(res, 0, false, false, true);
4598 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4599 addDS(auth, 300, res->d_records, keys);
4600 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4601 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4602 }
4603 return 1;
4604 }
4605
4606 if (ip == ComboAddress("192.0.2.2:53")) {
4607 if (type == QType::NS) {
4608 setLWResult(res, 0, true, false, true);
4609 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4610 addRRSIG(keys, res->d_records, auth, 300);
4611 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4612 addRRSIG(keys, res->d_records, auth, 300);
4613 }
4614 else {
4615 setLWResult(res, RCode::NoError, true, false, true);
4616 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4617 addRRSIG(keys, res->d_records, auth, 300);
4618 }
4619 return 1;
4620 }
4621
4622 return 0;
4623 });
4624
4625 vector<DNSRecord> ret;
4626 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4627 BOOST_CHECK_EQUAL(res, RCode::NoError);
4628 /* Should be insecure because of the NTA */
4629 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4630 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4631 BOOST_CHECK_EQUAL(queriesCount, 5);
4632
4633 /* again, to test the cache */
4634 ret.clear();
4635 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4636 BOOST_CHECK_EQUAL(res, RCode::NoError);
4637 /* Should be insecure because of the NTA */
4638 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4639 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4640 BOOST_CHECK_EQUAL(queriesCount, 5);
4641 }
4642
4643 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4644 std::unique_ptr<SyncRes> sr;
4645 initSR(sr, true);
4646
4647 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4648
4649 primeHints();
4650 const DNSName target("powerdns.com.");
4651 const ComboAddress targetAddr("192.0.2.42");
4652 testkeysset_t keys;
4653
4654 auto luaconfsCopy = g_luaconfs.getCopy();
4655 luaconfsCopy.dsAnchors.clear();
4656 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4657 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4658 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4659
4660 /* Add a NTA for "powerdns.com" */
4661 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4662
4663 g_luaconfs.setState(luaconfsCopy);
4664
4665 size_t queriesCount = 0;
4666
4667 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) {
4668 queriesCount++;
4669
4670 if (type == QType::DS || type == QType::DNSKEY) {
4671 setLWResult(res, 0, false, false, true);
4672 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4673 return 1;
4674 }
4675 else {
4676 if (isRootServer(ip)) {
4677 setLWResult(res, 0, false, false, true);
4678 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4679 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4680 return 1;
4681 }
4682 else if (ip == ComboAddress("192.0.2.1:53")) {
4683 if (domain == DNSName("com.")) {
4684 setLWResult(res, 0, true, false, true);
4685 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4686 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4687 }
4688 else {
4689 setLWResult(res, 0, false, false, true);
4690 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4691 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4692 }
4693 return 1;
4694 }
4695 else if (ip == ComboAddress("192.0.2.2:53")) {
4696 if (type == QType::NS) {
4697 setLWResult(res, 0, true, false, true);
4698 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4699 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4700 }
4701 else {
4702 setLWResult(res, RCode::NoError, true, false, true);
4703 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4704 }
4705 return 1;
4706 }
4707 }
4708
4709 return 0;
4710 });
4711
4712 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
4713 vector<DNSRecord> ret;
4714 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4715 BOOST_CHECK_EQUAL(res, RCode::NoError);
4716 /* Should be insecure because of the NTA */
4717 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4718 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4719 BOOST_CHECK_EQUAL(queriesCount, 4);
4720
4721 /* again, to test the cache */
4722 ret.clear();
4723 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4724 BOOST_CHECK_EQUAL(res, RCode::NoError);
4725 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4726 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4727 BOOST_CHECK_EQUAL(queriesCount, 4);
4728 }
4729
4730 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
4731 std::unique_ptr<SyncRes> sr;
4732 initSR(sr, true);
4733
4734 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4735
4736 primeHints();
4737 const DNSName target("powerdns.com.");
4738 testkeysset_t keys;
4739
4740 auto luaconfsCopy = g_luaconfs.getCopy();
4741 luaconfsCopy.dsAnchors.clear();
4742 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4743 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4744 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4745
4746 g_luaconfs.setState(luaconfsCopy);
4747
4748 size_t queriesCount = 0;
4749
4750 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) {
4751 queriesCount++;
4752
4753 if (type == QType::DS || type == QType::DNSKEY) {
4754 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4755 }
4756 else {
4757 if (isRootServer(ip)) {
4758 setLWResult(res, 0, false, false, true);
4759 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4760 addDS(DNSName("com."), 300, res->d_records, keys);
4761 addRRSIG(keys, res->d_records, DNSName("."), 300);
4762 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4763 return 1;
4764 }
4765 else if (ip == ComboAddress("192.0.2.1:53")) {
4766 if (domain == DNSName("com.")) {
4767 setLWResult(res, 0, true, false, true);
4768 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4769 addRRSIG(keys, res->d_records, domain, 300);
4770 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4771 addRRSIG(keys, res->d_records, domain, 300);
4772 }
4773 else {
4774 setLWResult(res, 0, false, false, true);
4775 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4776 addDS(domain, 300, res->d_records, keys);
4777 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4778 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4779 }
4780 return 1;
4781 }
4782 else if (ip == ComboAddress("192.0.2.2:53")) {
4783 if (type == QType::NS) {
4784 setLWResult(res, 0, true, false, true);
4785 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4786 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4787 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4788 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4789 }
4790 else {
4791 setLWResult(res, 0, true, false, true);
4792 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4793 addRRSIG(keys, res->d_records, domain, 300);
4794 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
4795 addRRSIG(keys, res->d_records, domain, 300);
4796 }
4797 return 1;
4798 }
4799 }
4800
4801 return 0;
4802 });
4803
4804 vector<DNSRecord> ret;
4805 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4806 BOOST_CHECK_EQUAL(res, RCode::NoError);
4807 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4808 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4809 BOOST_CHECK_EQUAL(queriesCount, 8);
4810
4811 /* again, to test the cache */
4812 ret.clear();
4813 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4814 BOOST_CHECK_EQUAL(res, RCode::NoError);
4815 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4816 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4817 BOOST_CHECK_EQUAL(queriesCount, 8);
4818 }
4819
4820 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
4821 std::unique_ptr<SyncRes> sr;
4822 initSR(sr, true);
4823
4824 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4825
4826 primeHints();
4827 const DNSName target("nx.powerdns.com.");
4828 testkeysset_t keys;
4829
4830 auto luaconfsCopy = g_luaconfs.getCopy();
4831 luaconfsCopy.dsAnchors.clear();
4832 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4833 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4834 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4835
4836 g_luaconfs.setState(luaconfsCopy);
4837
4838 size_t queriesCount = 0;
4839
4840 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) {
4841 queriesCount++;
4842
4843 DNSName auth = domain;
4844 if (domain == target) {
4845 auth = DNSName("powerdns.com.");
4846 }
4847 if (type == QType::DS || type == QType::DNSKEY) {
4848 if (type == QType::DS && domain == target) {
4849 setLWResult(res, RCode::NXDomain, true, false, true);
4850 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4851 addRRSIG(keys, res->d_records, auth, 300);
4852 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4853 addRRSIG(keys, res->d_records, auth, 300);
4854 return 1;
4855 }
4856 else {
4857 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4858 }
4859 }
4860 else {
4861 if (isRootServer(ip)) {
4862 setLWResult(res, 0, false, false, true);
4863 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4864 addDS(DNSName("com."), 300, res->d_records, keys);
4865 addRRSIG(keys, res->d_records, DNSName("."), 300);
4866 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4867 return 1;
4868 }
4869 else if (ip == ComboAddress("192.0.2.1:53")) {
4870 if (domain == DNSName("com.")) {
4871 setLWResult(res, 0, true, false, true);
4872 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4873 addRRSIG(keys, res->d_records, domain, 300);
4874 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4875 addRRSIG(keys, res->d_records, domain, 300);
4876 }
4877 else {
4878 setLWResult(res, 0, false, false, true);
4879 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4880 addDS(auth, 300, res->d_records, keys);
4881 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4882 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4883 }
4884 return 1;
4885 }
4886 else if (ip == ComboAddress("192.0.2.2:53")) {
4887 if (type == QType::NS) {
4888 setLWResult(res, 0, true, false, true);
4889 if (domain == DNSName("powerdns.com.")) {
4890 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4891 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4892 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4893 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4894 }
4895 else {
4896 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4897 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4898 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4899 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4900 }
4901 }
4902 else {
4903 setLWResult(res, RCode::NXDomain, true, false, true);
4904 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4905 addRRSIG(keys, res->d_records, auth, 300);
4906 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4907 addRRSIG(keys, res->d_records, auth, 300);
4908 /* add wildcard denial */
4909 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4910 addRRSIG(keys, res->d_records, auth, 300);
4911 }
4912 return 1;
4913 }
4914 }
4915
4916 return 0;
4917 });
4918
4919 vector<DNSRecord> ret;
4920 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4921 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
4922 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4923 BOOST_REQUIRE_EQUAL(ret.size(), 6);
4924 BOOST_CHECK_EQUAL(queriesCount, 9);
4925
4926 /* again, to test the cache */
4927 ret.clear();
4928 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4929 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
4930 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4931 BOOST_REQUIRE_EQUAL(ret.size(), 6);
4932 BOOST_CHECK_EQUAL(queriesCount, 9);
4933 }
4934
4935 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
4936 std::unique_ptr<SyncRes> sr;
4937 initSR(sr, true);
4938
4939 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4940
4941 primeHints();
4942 const DNSName target("www.powerdns.com.");
4943 testkeysset_t keys;
4944
4945 auto luaconfsCopy = g_luaconfs.getCopy();
4946 luaconfsCopy.dsAnchors.clear();
4947 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4948 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4949 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4950
4951 g_luaconfs.setState(luaconfsCopy);
4952
4953 size_t queriesCount = 0;
4954
4955 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) {
4956 queriesCount++;
4957
4958 if (type == QType::DS || type == QType::DNSKEY) {
4959 if (type == QType::DS && domain == target) {
4960 setLWResult(res, RCode::NoError, true, false, true);
4961 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4962 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
4963 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4964 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4965 return 1;
4966 }
4967 else {
4968 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4969 }
4970 }
4971 else {
4972 if (isRootServer(ip)) {
4973 setLWResult(res, 0, false, false, true);
4974 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4975 addDS(DNSName("com."), 300, res->d_records, keys);
4976 addRRSIG(keys, res->d_records, DNSName("."), 300);
4977 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4978 return 1;
4979 }
4980 else if (ip == ComboAddress("192.0.2.1:53")) {
4981 if (domain == DNSName("com.")) {
4982 setLWResult(res, 0, true, false, true);
4983 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4984 addRRSIG(keys, res->d_records, domain, 300);
4985 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4986 addRRSIG(keys, res->d_records, domain, 300);
4987 }
4988 else {
4989 setLWResult(res, 0, false, false, true);
4990 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4991 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
4992 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4993 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4994 }
4995 return 1;
4996 }
4997 else if (ip == ComboAddress("192.0.2.2:53")) {
4998 setLWResult(res, 0, true, false, true);
4999 if (type == QType::NS) {
5000 if (domain == DNSName("powerdns.com.")) {
5001 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5002 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5003 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5004 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5005 }
5006 else {
5007 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5008 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5009 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5010 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5011 }
5012 }
5013 else {
5014 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5015 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5016 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5017 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5018 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5019 }
5020 return 1;
5021 }
5022 }
5023
5024 return 0;
5025 });
5026
5027 vector<DNSRecord> ret;
5028 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5029 BOOST_CHECK_EQUAL(res, RCode::NoError);
5030 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5031 BOOST_REQUIRE_EQUAL(ret.size(), 4);
5032 BOOST_CHECK_EQUAL(queriesCount, 9);
5033
5034 /* again, to test the cache */
5035 ret.clear();
5036 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5037 BOOST_CHECK_EQUAL(res, RCode::NoError);
5038 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5039 BOOST_REQUIRE_EQUAL(ret.size(), 4);
5040 BOOST_CHECK_EQUAL(queriesCount, 9);
5041 }
5042
5043 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
5044 std::unique_ptr<SyncRes> sr;
5045 initSR(sr, true);
5046
5047 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5048
5049 primeHints();
5050 const DNSName target("www.com.");
5051 testkeysset_t keys;
5052
5053 auto luaconfsCopy = g_luaconfs.getCopy();
5054 luaconfsCopy.dsAnchors.clear();
5055 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5056 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5057
5058 g_luaconfs.setState(luaconfsCopy);
5059
5060 size_t queriesCount = 0;
5061
5062 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) {
5063 queriesCount++;
5064
5065 if (type == QType::DS || type == QType::DNSKEY) {
5066 if (type == QType::DS && domain == target) {
5067 DNSName auth("com.");
5068 setLWResult(res, 0, true, false, true);
5069
5070 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5071 addRRSIG(keys, res->d_records, auth, 300);
5072 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
5073 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
5074 addRRSIG(keys, res->d_records, auth, 300);
5075 return 1;
5076 }
5077 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5078 }
5079 else {
5080 if (isRootServer(ip)) {
5081 setLWResult(res, 0, false, false, true);
5082 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5083 addDS(DNSName("com."), 300, res->d_records, keys);
5084 addRRSIG(keys, res->d_records, DNSName("."), 300);
5085 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5086 return 1;
5087 }
5088 else if (ip == ComboAddress("192.0.2.1:53")) {
5089 setLWResult(res, 0, true, false, true);
5090 /* no data */
5091 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5092 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5093 /* no record for this name */
5094 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
5095 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5096 /* a wildcard matches but has no record for this type */
5097 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5098 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5099 return 1;
5100 }
5101 }
5102
5103 return 0;
5104 });
5105
5106 vector<DNSRecord> ret;
5107 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5108 BOOST_CHECK_EQUAL(res, RCode::NoError);
5109 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5110 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5111 BOOST_CHECK_EQUAL(queriesCount, 6);
5112
5113 /* again, to test the cache */
5114 ret.clear();
5115 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5116 BOOST_CHECK_EQUAL(res, RCode::NoError);
5117 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5118 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5119 BOOST_CHECK_EQUAL(queriesCount, 6);
5120 }
5121
5122 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
5123 std::unique_ptr<SyncRes> sr;
5124 initSR(sr, true);
5125
5126 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5127
5128 primeHints();
5129 const DNSName target("www.com.");
5130 testkeysset_t keys;
5131
5132 auto luaconfsCopy = g_luaconfs.getCopy();
5133 luaconfsCopy.dsAnchors.clear();
5134 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5135 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5136
5137 g_luaconfs.setState(luaconfsCopy);
5138
5139 size_t queriesCount = 0;
5140
5141 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) {
5142 queriesCount++;
5143
5144 if (type == QType::DS || type == QType::DNSKEY) {
5145 if (type == QType::DS && domain == target) {
5146 DNSName auth("com.");
5147 setLWResult(res, 0, true, false, true);
5148
5149 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5150 addRRSIG(keys, res->d_records, auth, 300);
5151 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5152 /* first the closest encloser */
5153 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5154 addRRSIG(keys, res->d_records, auth, 300);
5155 /* then the next closer */
5156 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5157 addRRSIG(keys, res->d_records, auth, 300);
5158 /* a wildcard matches but has no record for this type */
5159 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5160 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5161 return 1;
5162 }
5163 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5164 }
5165 else {
5166 if (isRootServer(ip)) {
5167 setLWResult(res, 0, false, false, true);
5168 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5169 addDS(DNSName("com."), 300, res->d_records, keys);
5170 addRRSIG(keys, res->d_records, DNSName("."), 300);
5171 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5172 return 1;
5173 }
5174 else if (ip == ComboAddress("192.0.2.1:53")) {
5175 setLWResult(res, 0, true, false, true);
5176 /* no data */
5177 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5178 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5179 /* no record for this name */
5180 /* first the closest encloser */
5181 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5182 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5183 /* then the next closer */
5184 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5185 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5186 /* a wildcard matches but has no record for this type */
5187 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5188 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5189 return 1;
5190 }
5191 }
5192
5193 return 0;
5194 });
5195
5196 vector<DNSRecord> ret;
5197 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5198 BOOST_CHECK_EQUAL(res, RCode::NoError);
5199 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5200 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5201 BOOST_CHECK_EQUAL(queriesCount, 6);
5202
5203 /* again, to test the cache */
5204 ret.clear();
5205 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5206 BOOST_CHECK_EQUAL(res, RCode::NoError);
5207 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5208 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5209 BOOST_CHECK_EQUAL(queriesCount, 6);
5210 }
5211
5212 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5213 std::unique_ptr<SyncRes> sr;
5214 initSR(sr, true);
5215
5216 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5217
5218 primeHints();
5219 const DNSName target("www.com.");
5220 testkeysset_t keys;
5221
5222 auto luaconfsCopy = g_luaconfs.getCopy();
5223 luaconfsCopy.dsAnchors.clear();
5224 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5225 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5226
5227 g_luaconfs.setState(luaconfsCopy);
5228
5229 size_t queriesCount = 0;
5230
5231 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) {
5232 queriesCount++;
5233
5234 if (type == QType::DS || type == QType::DNSKEY) {
5235 if (type == QType::DS && domain == target) {
5236 DNSName auth("com.");
5237 setLWResult(res, 0, true, false, true);
5238
5239 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5240 addRRSIG(keys, res->d_records, auth, 300);
5241 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5242 /* first the closest encloser */
5243 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5244 addRRSIG(keys, res->d_records, auth, 300);
5245 /* then the next closer */
5246 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5247 addRRSIG(keys, res->d_records, auth, 300);
5248 /* a wildcard matches but has no record for this type */
5249 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5250 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5251 return 1;
5252 }
5253 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5254 }
5255 else {
5256 if (isRootServer(ip)) {
5257 setLWResult(res, 0, false, false, true);
5258 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5259 addDS(DNSName("com."), 300, res->d_records, keys);
5260 addRRSIG(keys, res->d_records, DNSName("."), 300);
5261 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5262 return 1;
5263 }
5264 else if (ip == ComboAddress("192.0.2.1:53")) {
5265 setLWResult(res, 0, true, false, true);
5266 /* no data */
5267 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5268 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5269 /* no record for this name */
5270 /* first the closest encloser */
5271 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5272 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5273 /* then the next closer */
5274 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5275 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5276 /* a wildcard matches but has no record for this type */
5277 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5278 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5279 return 1;
5280 }
5281 }
5282
5283 return 0;
5284 });
5285
5286 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5287 vector<DNSRecord> ret;
5288 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5289 BOOST_CHECK_EQUAL(res, RCode::NoError);
5290 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5291 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5292 BOOST_CHECK_EQUAL(queriesCount, 6);
5293
5294 /* again, to test the cache */
5295 ret.clear();
5296 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5297 BOOST_CHECK_EQUAL(res, RCode::NoError);
5298 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5299 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5300 BOOST_CHECK_EQUAL(queriesCount, 6);
5301 }
5302
5303 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5304 std::unique_ptr<SyncRes> sr;
5305 initSR(sr, true);
5306
5307 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5308
5309 primeHints();
5310 const DNSName target("www.sub.powerdns.com.");
5311 testkeysset_t keys;
5312
5313 auto luaconfsCopy = g_luaconfs.getCopy();
5314 luaconfsCopy.dsAnchors.clear();
5315 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5316 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5317 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5318
5319 g_luaconfs.setState(luaconfsCopy);
5320
5321 size_t queriesCount = 0;
5322
5323 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) {
5324 queriesCount++;
5325
5326 if (type == QType::DS || type == QType::DNSKEY) {
5327 if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) {
5328 setLWResult(res, RCode::NoError, true, false, true);
5329 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5330 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5331 if (domain == DNSName("sub.powerdns.com")) {
5332 addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5333 }
5334 else if (domain == target) {
5335 addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5336 }
5337 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5338 return 1;
5339 }
5340 else {
5341 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5342 }
5343 }
5344 else {
5345 if (isRootServer(ip)) {
5346 setLWResult(res, 0, false, false, true);
5347 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5348 addDS(DNSName("com."), 300, res->d_records, keys);
5349 addRRSIG(keys, res->d_records, DNSName("."), 300);
5350 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5351 return 1;
5352 }
5353 else if (ip == ComboAddress("192.0.2.1:53")) {
5354 if (domain == DNSName("com.")) {
5355 setLWResult(res, 0, true, false, true);
5356 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5357 addRRSIG(keys, res->d_records, domain, 300);
5358 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5359 addRRSIG(keys, res->d_records, domain, 300);
5360 }
5361 else {
5362 setLWResult(res, 0, false, false, true);
5363 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5364 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5365 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5366 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5367 }
5368 return 1;
5369 }
5370 else if (ip == ComboAddress("192.0.2.2:53")) {
5371 setLWResult(res, 0, true, false, true);
5372 if (type == QType::NS) {
5373 if (domain == DNSName("powerdns.com.")) {
5374 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5375 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5376 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5377 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5378 }
5379 else {
5380 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5381 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5382 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5383 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5384 }
5385 }
5386 else {
5387 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5388 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5389 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5390 /* first the closest encloser */
5391 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5392 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5393 /* then the next closer */
5394 addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5395 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5396 }
5397 return 1;
5398 }
5399 }
5400
5401 return 0;
5402 });
5403
5404 vector<DNSRecord> ret;
5405 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5406 BOOST_CHECK_EQUAL(res, RCode::NoError);
5407 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5408 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5409 BOOST_CHECK_EQUAL(queriesCount, 10);
5410
5411 /* again, to test the cache */
5412 ret.clear();
5413 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5414 BOOST_CHECK_EQUAL(res, RCode::NoError);
5415 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5416 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5417 BOOST_CHECK_EQUAL(queriesCount, 10);
5418 }
5419
5420 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5421 std::unique_ptr<SyncRes> sr;
5422 initSR(sr, true);
5423
5424 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5425
5426 primeHints();
5427 const DNSName target("www.powerdns.com.");
5428 testkeysset_t keys;
5429
5430 auto luaconfsCopy = g_luaconfs.getCopy();
5431 luaconfsCopy.dsAnchors.clear();
5432 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5433 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5434 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5435
5436 g_luaconfs.setState(luaconfsCopy);
5437
5438 size_t queriesCount = 0;
5439
5440 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) {
5441 queriesCount++;
5442
5443 if (type == QType::DS || type == QType::DNSKEY) {
5444 if (type == QType::DS && domain == target) {
5445 setLWResult(res, RCode::NoError, true, false, true);
5446 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5447 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5448 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5449 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5450 return 1;
5451 }
5452 else {
5453 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5454 }
5455 }
5456 else {
5457 if (isRootServer(ip)) {
5458 setLWResult(res, 0, false, false, true);
5459 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5460 addDS(DNSName("com."), 300, res->d_records, keys);
5461 addRRSIG(keys, res->d_records, DNSName("."), 300);
5462 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5463 return 1;
5464 }
5465 else if (ip == ComboAddress("192.0.2.1:53")) {
5466 if (domain == DNSName("com.")) {
5467 setLWResult(res, 0, true, false, true);
5468 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5469 addRRSIG(keys, res->d_records, domain, 300);
5470 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5471 addRRSIG(keys, res->d_records, domain, 300);
5472 }
5473 else {
5474 setLWResult(res, 0, false, false, true);
5475 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5476 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5477 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5478 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5479 }
5480 return 1;
5481 }
5482 else if (ip == ComboAddress("192.0.2.2:53")) {
5483 setLWResult(res, 0, true, false, true);
5484 if (type == QType::NS) {
5485 if (domain == DNSName("powerdns.com.")) {
5486 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5487 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5488 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5489 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5490 }
5491 else {
5492 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5493 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5494 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5495 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5496 }
5497 }
5498 else {
5499 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5500 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5501 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5502 /* first the closest encloser */
5503 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5504 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5505 /* then the next closer */
5506 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5507 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5508 }
5509 return 1;
5510 }
5511 }
5512
5513 return 0;
5514 });
5515
5516 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5517 we should end up Insecure */
5518 vector<DNSRecord> ret;
5519 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5520 BOOST_CHECK_EQUAL(res, RCode::NoError);
5521 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5522 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5523 BOOST_CHECK_EQUAL(queriesCount, 9);
5524
5525 /* again, to test the cache */
5526 ret.clear();
5527 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5528 BOOST_CHECK_EQUAL(res, RCode::NoError);
5529 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5530 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5531 BOOST_CHECK_EQUAL(queriesCount, 9);
5532 }
5533
5534 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5535 std::unique_ptr<SyncRes> sr;
5536 initSR(sr, true);
5537
5538 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5539
5540 primeHints();
5541 const DNSName target("www.powerdns.com.");
5542 testkeysset_t keys;
5543
5544 auto luaconfsCopy = g_luaconfs.getCopy();
5545 luaconfsCopy.dsAnchors.clear();
5546 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5547 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5548 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5549
5550 g_luaconfs.setState(luaconfsCopy);
5551
5552 size_t queriesCount = 0;
5553
5554 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) {
5555 queriesCount++;
5556
5557 if (type == QType::DS || type == QType::DNSKEY) {
5558 if (type == QType::DS && domain == target) {
5559 setLWResult(res, RCode::NoError, true, false, true);
5560 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5561 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5562 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5563 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5564 return 1;
5565 }
5566 else {
5567 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5568 }
5569 }
5570 else {
5571 if (isRootServer(ip)) {
5572 setLWResult(res, 0, false, false, true);
5573 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5574 addDS(DNSName("com."), 300, res->d_records, keys);
5575 addRRSIG(keys, res->d_records, DNSName("."), 300);
5576 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5577 return 1;
5578 }
5579 else if (ip == ComboAddress("192.0.2.1:53")) {
5580 if (domain == DNSName("com.")) {
5581 setLWResult(res, 0, true, false, true);
5582 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5583 addRRSIG(keys, res->d_records, domain, 300);
5584 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5585 addRRSIG(keys, res->d_records, domain, 300);
5586 }
5587 else {
5588 setLWResult(res, 0, false, false, true);
5589 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5590 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5591 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5592 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5593 }
5594 return 1;
5595 }
5596 else if (ip == ComboAddress("192.0.2.2:53")) {
5597 setLWResult(res, 0, true, false, true);
5598 if (type == QType::NS) {
5599 if (domain == DNSName("powerdns.com.")) {
5600 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5601 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5602 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5603 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5604 }
5605 else {
5606 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5607 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5608 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5609 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5610 }
5611 }
5612 else {
5613 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5614 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5615 }
5616 return 1;
5617 }
5618 }
5619
5620 return 0;
5621 });
5622
5623 vector<DNSRecord> ret;
5624 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5625 BOOST_CHECK_EQUAL(res, RCode::NoError);
5626 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5627 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5628 BOOST_CHECK_EQUAL(queriesCount, 9);
5629
5630 /* again, to test the cache */
5631 ret.clear();
5632 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5633 BOOST_CHECK_EQUAL(res, RCode::NoError);
5634 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5635 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5636 BOOST_CHECK_EQUAL(queriesCount, 9);
5637 }
5638
5639 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5640 std::unique_ptr<SyncRes> sr;
5641 initSR(sr, true);
5642
5643 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5644
5645 primeHints();
5646 const DNSName target("www.powerdns.com.");
5647 testkeysset_t keys;
5648
5649 auto luaconfsCopy = g_luaconfs.getCopy();
5650 luaconfsCopy.dsAnchors.clear();
5651 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5652 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5653 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5654
5655 g_luaconfs.setState(luaconfsCopy);
5656
5657 size_t queriesCount = 0;
5658 size_t dsQueriesCount = 0;
5659
5660 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) {
5661 queriesCount++;
5662
5663 if (type == QType::DS) {
5664 DNSName auth(domain);
5665 auth.chopOff();
5666 dsQueriesCount++;
5667
5668 setLWResult(res, 0, true, false, true);
5669 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5670 addRRSIG(keys, res->d_records, auth, 300);
5671 return 1;
5672 }
5673 else if (type == QType::DNSKEY) {
5674 setLWResult(res, 0, true, false, true);
5675 addDNSKEY(keys, domain, 300, res->d_records);
5676 addRRSIG(keys, res->d_records, domain, 300);
5677 return 1;
5678 }
5679 else {
5680 if (isRootServer(ip)) {
5681 setLWResult(res, 0, false, false, true);
5682 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5683 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5684 /* No DS on referral, and no denial of the DS either */
5685 return 1;
5686 }
5687 else if (ip == ComboAddress("192.0.2.1:53")) {
5688 if (domain == DNSName("com.")) {
5689 setLWResult(res, 0, true, false, true);
5690 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5691 addRRSIG(keys, res->d_records, domain, 300);
5692 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5693 addRRSIG(keys, res->d_records, domain, 300);
5694 }
5695 else {
5696 setLWResult(res, 0, false, false, true);
5697 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5698 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5699 /* No DS on referral, and no denial of the DS either */
5700 }
5701 return 1;
5702 }
5703 else if (ip == ComboAddress("192.0.2.2:53")) {
5704 setLWResult(res, 0, true, false, true);
5705 if (type == QType::NS) {
5706 if (domain == DNSName("powerdns.com.")) {
5707 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5708 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5709 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5710 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5711 }
5712 else {
5713 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5714 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5715 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5716 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5717 }
5718 }
5719 else {
5720 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5721 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5722 }
5723
5724 return 1;
5725 }
5726 }
5727
5728 return 0;
5729 });
5730
5731 vector<DNSRecord> ret;
5732 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5733 BOOST_CHECK_EQUAL(res, RCode::NoError);
5734 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5735 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5736 BOOST_CHECK_EQUAL(queriesCount, 9);
5737 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5738
5739 /* again, to test the cache */
5740 ret.clear();
5741 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5742 BOOST_CHECK_EQUAL(res, RCode::NoError);
5743 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5744 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5745 BOOST_CHECK_EQUAL(queriesCount, 9);
5746 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5747 }
5748
5749 BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
5750 std::unique_ptr<SyncRes> sr;
5751 initSR(sr, true);
5752
5753 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5754
5755 primeHints();
5756 const DNSName target("www.powerdns.com.");
5757 testkeysset_t keys;
5758
5759 auto luaconfsCopy = g_luaconfs.getCopy();
5760 luaconfsCopy.dsAnchors.clear();
5761 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5762 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5763 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5764 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5765
5766 g_luaconfs.setState(luaconfsCopy);
5767
5768 size_t queriesCount = 0;
5769
5770 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) {
5771 queriesCount++;
5772
5773 if (type == QType::DS) {
5774 DNSName auth(domain);
5775 auth.chopOff();
5776
5777 setLWResult(res, 0, true, false, true);
5778 if (domain == target) {
5779 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5780 addRRSIG(keys, res->d_records, target, 300);
5781 }
5782 else {
5783 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5784 addRRSIG(keys, res->d_records, auth, 300);
5785 }
5786 return 1;
5787 }
5788 else if (type == QType::DNSKEY) {
5789 setLWResult(res, 0, true, false, true);
5790 addDNSKEY(keys, domain, 300, res->d_records);
5791 addRRSIG(keys, res->d_records, domain, 300);
5792 return 1;
5793 }
5794 else {
5795 if (isRootServer(ip)) {
5796 setLWResult(res, 0, false, false, true);
5797 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5798 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5799 addDS(DNSName("com."), 300, res->d_records, keys);
5800 addRRSIG(keys, res->d_records, DNSName("."), 300);
5801 return 1;
5802 }
5803 else if (ip == ComboAddress("192.0.2.1:53")) {
5804 if (domain == DNSName("com.")) {
5805 setLWResult(res, 0, true, false, true);
5806 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5807 addRRSIG(keys, res->d_records, domain, 300);
5808 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5809 addRRSIG(keys, res->d_records, domain, 300);
5810 }
5811 else {
5812 setLWResult(res, 0, false, false, true);
5813 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5814 /* no DS */
5815 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5816 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5817 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5818 }
5819 return 1;
5820 }
5821 else if (ip == ComboAddress("192.0.2.2:53")) {
5822 if (type == QType::NS) {
5823 if (domain == DNSName("powerdns.com.")) {
5824 setLWResult(res, RCode::Refused, false, false, true);
5825 }
5826 else {
5827 setLWResult(res, 0, true, false, true);
5828 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5829 addRRSIG(keys, res->d_records, domain, 300);
5830 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5831 addRRSIG(keys, res->d_records, domain, 300);
5832 }
5833 }
5834 else {
5835 setLWResult(res, 0, true, false, true);
5836 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5837 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
5838 }
5839
5840 return 1;
5841 }
5842 }
5843
5844 return 0;
5845 });
5846
5847 vector<DNSRecord> ret;
5848 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5849 BOOST_CHECK_EQUAL(res, RCode::NoError);
5850 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5851 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5852 BOOST_CHECK_EQUAL(queriesCount, 9);
5853
5854 /* again, to test the cache */
5855 ret.clear();
5856 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5857 BOOST_CHECK_EQUAL(res, RCode::NoError);
5858 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5859 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5860 BOOST_CHECK_EQUAL(queriesCount, 9);
5861 }
5862
5863 BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) {
5864 /* check that we don't accept a signer below us */
5865 std::unique_ptr<SyncRes> sr;
5866 initSR(sr, true);
5867
5868 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5869
5870 primeHints();
5871 const DNSName target("www.powerdns.com.");
5872 testkeysset_t keys;
5873
5874 auto luaconfsCopy = g_luaconfs.getCopy();
5875 luaconfsCopy.dsAnchors.clear();
5876 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5877 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5878 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5879 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5880 generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5881
5882 g_luaconfs.setState(luaconfsCopy);
5883
5884 size_t queriesCount = 0;
5885
5886 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) {
5887 queriesCount++;
5888
5889 if (type == QType::DS) {
5890 DNSName auth(domain);
5891 auth.chopOff();
5892
5893 setLWResult(res, 0, true, false, true);
5894 if (domain == target) {
5895 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5896 addRRSIG(keys, res->d_records, target, 300);
5897 }
5898 else {
5899 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5900 addRRSIG(keys, res->d_records, auth, 300);
5901 }
5902 return 1;
5903 }
5904 else if (type == QType::DNSKEY) {
5905 setLWResult(res, 0, true, false, true);
5906 addDNSKEY(keys, domain, 300, res->d_records);
5907 if (domain == DNSName("www.powerdns.com.")) {
5908 addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
5909 }
5910 else {
5911 addRRSIG(keys, res->d_records, domain, 300);
5912 }
5913 return 1;
5914 }
5915 else {
5916 if (isRootServer(ip)) {
5917 setLWResult(res, 0, false, false, true);
5918 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5919 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5920 addDS(DNSName("com."), 300, res->d_records, keys);
5921 addRRSIG(keys, res->d_records, DNSName("."), 300);
5922 return 1;
5923 }
5924 else if (ip == ComboAddress("192.0.2.1:53")) {
5925 if (domain == DNSName("com.")) {
5926 setLWResult(res, 0, true, false, true);
5927 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5928 addRRSIG(keys, res->d_records, domain, 300);
5929 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5930 addRRSIG(keys, res->d_records, domain, 300);
5931 }
5932 else {
5933 setLWResult(res, 0, false, false, true);
5934 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5935 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5936 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5937 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5938 }
5939 return 1;
5940 }
5941 else if (ip == ComboAddress("192.0.2.2:53")) {
5942 if (type == QType::NS) {
5943 setLWResult(res, 0, true, false, true);
5944 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5945 addRRSIG(keys, res->d_records, domain, 300);
5946 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5947 addRRSIG(keys, res->d_records, domain, 300);
5948 }
5949 else {
5950 setLWResult(res, 0, true, false, true);
5951 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5952 addRRSIG(keys, res->d_records, domain, 300);
5953 }
5954
5955 return 1;
5956 }
5957 }
5958
5959 return 0;
5960 });
5961
5962 vector<DNSRecord> ret;
5963 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5964 BOOST_CHECK_EQUAL(res, RCode::NoError);
5965 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5966 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5967 BOOST_CHECK_EQUAL(queriesCount, 9);
5968
5969 /* again, to test the cache */
5970 ret.clear();
5971 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5972 BOOST_CHECK_EQUAL(res, RCode::NoError);
5973 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5974 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5975 BOOST_CHECK_EQUAL(queriesCount, 9);
5976 }
5977
5978 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
5979 std::unique_ptr<SyncRes> sr;
5980 initSR(sr, true);
5981
5982 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5983
5984 primeHints();
5985 const DNSName target("www.powerdns.com.");
5986 testkeysset_t keys;
5987
5988 auto luaconfsCopy = g_luaconfs.getCopy();
5989 luaconfsCopy.dsAnchors.clear();
5990 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5991 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5992
5993 g_luaconfs.setState(luaconfsCopy);
5994
5995 size_t queriesCount = 0;
5996 size_t dsQueriesCount = 0;
5997
5998 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) {
5999 queriesCount++;
6000
6001 if (type == QType::DS) {
6002 DNSName auth(domain);
6003 auth.chopOff();
6004 dsQueriesCount++;
6005
6006 setLWResult(res, 0, true, false, true);
6007 if (domain == DNSName("com.")) {
6008 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6009 }
6010 else {
6011 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6012 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6013 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
6014 }
6015 addRRSIG(keys, res->d_records, auth, 300);
6016 return 1;
6017 }
6018 else if (type == QType::DNSKEY) {
6019 setLWResult(res, 0, true, false, true);
6020 addDNSKEY(keys, domain, 300, res->d_records);
6021 addRRSIG(keys, res->d_records, domain, 300);
6022 return 1;
6023 }
6024 else {
6025 if (isRootServer(ip)) {
6026 setLWResult(res, 0, false, false, true);
6027 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6028 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6029 /* No DS on referral, and no denial of the DS either */
6030 return 1;
6031 }
6032 else if (ip == ComboAddress("192.0.2.1:53")) {
6033 if (domain == DNSName("com.")) {
6034 setLWResult(res, 0, true, false, true);
6035 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6036 addRRSIG(keys, res->d_records, domain, 300);
6037 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6038 addRRSIG(keys, res->d_records, domain, 300);
6039 }
6040 else {
6041 setLWResult(res, 0, false, false, true);
6042 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6043 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6044 /* No DS on referral, and no denial of the DS either */
6045 }
6046 return 1;
6047 }
6048 else if (ip == ComboAddress("192.0.2.2:53")) {
6049 setLWResult(res, 0, true, false, true);
6050 if (type == QType::NS) {
6051 if (domain == DNSName("powerdns.com.")) {
6052 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6053 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6054 }
6055 else {
6056 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6057 }
6058 }
6059 else {
6060 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6061 }
6062 return 1;
6063 }
6064 }
6065
6066 return 0;
6067 });
6068
6069 vector<DNSRecord> ret;
6070 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6071 BOOST_CHECK_EQUAL(res, RCode::NoError);
6072 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6073 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6074 BOOST_CHECK_EQUAL(queriesCount, 7);
6075 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6076
6077 /* again, to test the cache */
6078 ret.clear();
6079 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6080 BOOST_CHECK_EQUAL(res, RCode::NoError);
6081 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6082 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6083 BOOST_CHECK_EQUAL(queriesCount, 7);
6084 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6085 }
6086
6087 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
6088 std::unique_ptr<SyncRes> sr;
6089 initSR(sr, true);
6090
6091 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6092
6093 primeHints();
6094 const DNSName target("powerdns.com.");
6095 testkeysset_t keys;
6096
6097 auto luaconfsCopy = g_luaconfs.getCopy();
6098 luaconfsCopy.dsAnchors.clear();
6099 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6100 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6101 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6102
6103 g_luaconfs.setState(luaconfsCopy);
6104
6105 size_t queriesCount = 0;
6106
6107 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) {
6108 queriesCount++;
6109
6110 if (type == QType::DS || type == QType::DNSKEY) {
6111 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6112 }
6113 else {
6114 if (isRootServer(ip)) {
6115 setLWResult(res, 0, false, false, true);
6116 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6117 addDS(DNSName("com."), 300, res->d_records, keys);
6118 addRRSIG(keys, res->d_records, DNSName("."), 300);
6119 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6120 return 1;
6121 }
6122 else if (ip == ComboAddress("192.0.2.1:53")) {
6123 if (domain == DNSName("com.")) {
6124 setLWResult(res, 0, true, false, true);
6125 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6126 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6127 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6128 }
6129 else {
6130 setLWResult(res, 0, false, false, true);
6131 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6132 addDS(domain, 300, res->d_records, keys);
6133 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6134 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6135 }
6136 return 1;
6137 }
6138 else if (ip == ComboAddress("192.0.2.2:53")) {
6139 setLWResult(res, 0, true, false, true);
6140 if (type == QType::NS) {
6141 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6142 addRRSIG(keys, res->d_records, domain, 300);
6143 }
6144 else {
6145 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6146 addRRSIG(keys, res->d_records, domain, 300);
6147 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
6148 /* NO RRSIG for the NSEC record! */
6149 }
6150 return 1;
6151 }
6152 }
6153
6154 return 0;
6155 });
6156
6157 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
6158 vector<DNSRecord> ret;
6159 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6160 BOOST_CHECK_EQUAL(res, RCode::NoError);
6161 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6162 BOOST_CHECK_EQUAL(ret.size(), 3);
6163 BOOST_CHECK_EQUAL(queriesCount, 8);
6164
6165 /* again, to test the cache */
6166 ret.clear();
6167 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6168 BOOST_CHECK_EQUAL(res, RCode::NoError);
6169 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6170 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6171 BOOST_CHECK_EQUAL(queriesCount, 8);
6172 }
6173
6174 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
6175 std::unique_ptr<SyncRes> sr;
6176 initSR(sr, true);
6177
6178 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6179
6180 primeHints();
6181 const DNSName target("powerdns.com.");
6182 testkeysset_t keys;
6183
6184 auto luaconfsCopy = g_luaconfs.getCopy();
6185 luaconfsCopy.dsAnchors.clear();
6186 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6187 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6188 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6189
6190 g_luaconfs.setState(luaconfsCopy);
6191
6192 size_t queriesCount = 0;
6193
6194 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) {
6195 queriesCount++;
6196
6197 if (type == QType::DS || type == QType::DNSKEY) {
6198 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6199 }
6200 else {
6201 if (isRootServer(ip)) {
6202 setLWResult(res, 0, false, false, true);
6203 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6204 addDS(DNSName("com."), 300, res->d_records, keys);
6205 addRRSIG(keys, res->d_records, DNSName("."), 300);
6206 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6207 return 1;
6208 }
6209 else if (ip == ComboAddress("192.0.2.1:53")) {
6210 if (domain == DNSName("com.")) {
6211 setLWResult(res, 0, true, false, true);
6212 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6213 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6214 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6215 }
6216 else {
6217 setLWResult(res, 0, false, false, true);
6218 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6219 addDS(domain, 300, res->d_records, keys);
6220 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6221 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6222 }
6223 return 1;
6224 }
6225 else if (ip == ComboAddress("192.0.2.2:53")) {
6226 setLWResult(res, 0, true, false, true);
6227 if (type == QType::NS) {
6228 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6229 addRRSIG(keys, res->d_records, domain, 300);
6230 }
6231 else {
6232 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6233 addRRSIG(keys, res->d_records, domain, 300);
6234
6235 /* NO NSEC record! */
6236 }
6237 return 1;
6238 }
6239 }
6240
6241 return 0;
6242 });
6243
6244 /* no NSEC record in a secure zone, should be Bogus! */
6245 vector<DNSRecord> ret;
6246 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6247 BOOST_CHECK_EQUAL(res, RCode::NoError);
6248 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6249 BOOST_CHECK_EQUAL(ret.size(), 2);
6250 BOOST_CHECK_EQUAL(queriesCount, 8);
6251
6252 /* again, to test the cache */
6253 ret.clear();
6254 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6255 BOOST_CHECK_EQUAL(res, RCode::NoError);
6256 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6257 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6258 BOOST_CHECK_EQUAL(queriesCount, 8);
6259 }
6260
6261 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6262 std::unique_ptr<SyncRes> sr;
6263 initSR(sr, true);
6264
6265 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6266
6267 primeHints();
6268 const DNSName target("powerdns.com.");
6269 const ComboAddress targetAddr("192.0.2.42");
6270 testkeysset_t keys;
6271
6272 auto luaconfsCopy = g_luaconfs.getCopy();
6273 luaconfsCopy.dsAnchors.clear();
6274 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6275 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6276
6277 g_luaconfs.setState(luaconfsCopy);
6278
6279 size_t queriesCount = 0;
6280
6281 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) {
6282 queriesCount++;
6283
6284 if (type == QType::DS) {
6285 if (domain == target) {
6286 setLWResult(res, 0, false, false, true);
6287 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6288 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6289 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6290 return 1;
6291 } else {
6292 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6293 }
6294 }
6295 else if (type == QType::DNSKEY) {
6296 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6297 setLWResult(res, 0, true, false, true);
6298 addDNSKEY(keys, domain, 300, res->d_records);
6299 addRRSIG(keys, res->d_records, domain, 300);
6300 return 1;
6301 }
6302 else {
6303 setLWResult(res, 0, false, false, true);
6304 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6305 return 1;
6306 }
6307 }
6308 else {
6309 if (isRootServer(ip)) {
6310 setLWResult(res, 0, false, false, true);
6311 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6312 addDS(DNSName("com."), 300, res->d_records, keys);
6313 addRRSIG(keys, res->d_records, DNSName("."), 300);
6314 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6315 return 1;
6316 }
6317 else if (ip == ComboAddress("192.0.2.1:53")) {
6318 if (domain == DNSName("com.")) {
6319 setLWResult(res, 0, true, false, true);
6320 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6321 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6322 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6323 }
6324 else {
6325 setLWResult(res, 0, false, false, true);
6326 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6327 /* no DS */
6328 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6329 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6330 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6331 }
6332 return 1;
6333 }
6334 else if (ip == ComboAddress("192.0.2.2:53")) {
6335 setLWResult(res, 0, true, false, true);
6336 if (type == QType::NS) {
6337 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6338 }
6339 else {
6340 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6341 }
6342 return 1;
6343 }
6344 }
6345
6346 return 0;
6347 });
6348
6349 vector<DNSRecord> ret;
6350 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6351 BOOST_CHECK_EQUAL(res, RCode::NoError);
6352 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6353 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6354 BOOST_CHECK(ret[0].d_type == QType::A);
6355 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6356 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6357 1 query for A */
6358 BOOST_CHECK_EQUAL(queriesCount, 7);
6359
6360 /* again, to test the cache */
6361 ret.clear();
6362 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6363 BOOST_CHECK_EQUAL(res, RCode::NoError);
6364 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6365 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6366 BOOST_CHECK(ret[0].d_type == QType::A);
6367 BOOST_CHECK_EQUAL(queriesCount, 7);
6368 }
6369
6370
6371 BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6372 /*
6373 Direct DS query:
6374 - parent is secure, zone is secure: DS should be secure
6375 */
6376 std::unique_ptr<SyncRes> sr;
6377 initSR(sr, true);
6378
6379 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6380
6381 primeHints();
6382 const DNSName target("powerdns.com.");
6383 testkeysset_t keys;
6384
6385 auto luaconfsCopy = g_luaconfs.getCopy();
6386 luaconfsCopy.dsAnchors.clear();
6387 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6388 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6389 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6390
6391 g_luaconfs.setState(luaconfsCopy);
6392
6393 size_t queriesCount = 0;
6394
6395 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) {
6396 queriesCount++;
6397
6398 if (type == QType::DS || type == QType::DNSKEY) {
6399 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6400 }
6401 else {
6402 if (isRootServer(ip)) {
6403 setLWResult(res, 0, false, false, true);
6404 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6405 addDS(DNSName("com."), 300, res->d_records, keys);
6406 addRRSIG(keys, res->d_records, DNSName("."), 300);
6407 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6408 return 1;
6409 }
6410 }
6411
6412 return 0;
6413 });
6414
6415 vector<DNSRecord> ret;
6416 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6417 BOOST_CHECK_EQUAL(res, RCode::NoError);
6418 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6419 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6420 for (const auto& record : ret) {
6421 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6422 }
6423 BOOST_CHECK_EQUAL(queriesCount, 4);
6424
6425 /* again, to test the cache */
6426 ret.clear();
6427 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6428 BOOST_CHECK_EQUAL(res, RCode::NoError);
6429 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6430 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6431 for (const auto& record : ret) {
6432 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6433 }
6434 BOOST_CHECK_EQUAL(queriesCount, 4);
6435 }
6436
6437 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6438 /*
6439 Direct DS query:
6440 - parent is secure, zone is insecure: DS denial should be secure
6441 */
6442 std::unique_ptr<SyncRes> sr;
6443 initSR(sr, true);
6444
6445 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6446
6447 primeHints();
6448 const DNSName target("powerdns.com.");
6449 testkeysset_t keys;
6450
6451 auto luaconfsCopy = g_luaconfs.getCopy();
6452 luaconfsCopy.dsAnchors.clear();
6453 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6454 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6455
6456 g_luaconfs.setState(luaconfsCopy);
6457
6458 size_t queriesCount = 0;
6459
6460 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) {
6461 queriesCount++;
6462
6463 if (type == QType::DS || type == QType::DNSKEY) {
6464 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6465 }
6466 else {
6467 if (isRootServer(ip)) {
6468 setLWResult(res, 0, false, false, true);
6469 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6470 addDS(DNSName("com."), 300, res->d_records, keys);
6471 addRRSIG(keys, res->d_records, DNSName("."), 300);
6472 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6473 return 1;
6474 }
6475 }
6476
6477 return 0;
6478 });
6479
6480 vector<DNSRecord> ret;
6481 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6482 BOOST_CHECK_EQUAL(res, RCode::NoError);
6483 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6484 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6485 for (const auto& record : ret) {
6486 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6487 }
6488 BOOST_CHECK_EQUAL(queriesCount, 4);
6489
6490 /* again, to test the cache */
6491 ret.clear();
6492 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6493 BOOST_CHECK_EQUAL(res, RCode::NoError);
6494 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6495 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6496 for (const auto& record : ret) {
6497 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6498 }
6499 BOOST_CHECK_EQUAL(queriesCount, 4);
6500 }
6501
6502 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6503 std::unique_ptr<SyncRes> sr;
6504 initSR(sr, true);
6505
6506 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6507
6508 primeHints();
6509 const DNSName target("www.sub.powerdns.com.");
6510 const ComboAddress targetAddr("192.0.2.42");
6511 testkeysset_t keys;
6512
6513 auto luaconfsCopy = g_luaconfs.getCopy();
6514 luaconfsCopy.dsAnchors.clear();
6515 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6516 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6517 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6518
6519 g_luaconfs.setState(luaconfsCopy);
6520
6521 size_t queriesCount = 0;
6522
6523 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) {
6524 queriesCount++;
6525
6526 if (type == QType::DS) {
6527 if (domain == DNSName("sub.powerdns.com.")) {
6528 setLWResult(res, 0, false, false, true);
6529 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6530 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6531 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6532 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6533 return 1;
6534 }
6535 else if (domain == DNSName("www.sub.powerdns.com.")) {
6536 setLWResult(res, 0, false, false, true);
6537 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);
6538 return 1;
6539 }
6540 else {
6541 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6542 }
6543 }
6544 else if (type == QType::DNSKEY) {
6545 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6546 setLWResult(res, 0, true, false, true);
6547 addDNSKEY(keys, domain, 300, res->d_records);
6548 addRRSIG(keys, res->d_records, domain, 300);
6549 return 1;
6550 }
6551 else {
6552 setLWResult(res, 0, false, false, true);
6553 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6554 return 1;
6555 }
6556 }
6557 else {
6558 if (isRootServer(ip)) {
6559 setLWResult(res, 0, false, false, true);
6560 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6561 addDS(DNSName("com."), 300, res->d_records, keys);
6562 addRRSIG(keys, res->d_records, DNSName("."), 300);
6563 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6564 return 1;
6565 }
6566 else if (ip == ComboAddress("192.0.2.1:53")) {
6567 if (domain == DNSName("com.")) {
6568 setLWResult(res, 0, true, false, true);
6569 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6570 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6571 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6572 }
6573 else {
6574 setLWResult(res, 0, false, false, true);
6575 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6576 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6577 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6578 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6579 }
6580 return 1;
6581 }
6582 else if (ip == ComboAddress("192.0.2.2:53")) {
6583 setLWResult(res, 0, true, false, true);
6584 if (type == QType::NS) {
6585 if (domain == DNSName("www.sub.powerdns.com.")) {
6586 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);
6587 }
6588 else if (domain == DNSName("sub.powerdns.com.")) {
6589 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6590 }
6591 else if (domain == DNSName("powerdns.com.")) {
6592 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6593 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6594 }
6595 } else {
6596 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6597 }
6598 return 1;
6599 }
6600 }
6601
6602 return 0;
6603 });
6604
6605 vector<DNSRecord> ret;
6606 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6607 BOOST_CHECK_EQUAL(res, RCode::NoError);
6608 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6609 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6610 BOOST_CHECK(ret[0].d_type == QType::A);
6611 BOOST_CHECK_EQUAL(queriesCount, 9);
6612
6613 /* again, to test the cache */
6614 ret.clear();
6615 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6616 BOOST_CHECK_EQUAL(res, RCode::NoError);
6617 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6618 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6619 BOOST_CHECK(ret[0].d_type == QType::A);
6620 BOOST_CHECK_EQUAL(queriesCount, 9);
6621 }
6622
6623 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6624 std::unique_ptr<SyncRes> sr;
6625 initSR(sr, true);
6626
6627 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6628
6629 primeHints();
6630 const DNSName target("www.sub.powerdns.com.");
6631 const ComboAddress targetAddr("192.0.2.42");
6632 testkeysset_t keys;
6633
6634 auto luaconfsCopy = g_luaconfs.getCopy();
6635 luaconfsCopy.dsAnchors.clear();
6636 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6637 /* No key material for .com */
6638 /* But TA for sub.powerdns.com. */
6639 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6640 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6641 g_luaconfs.setState(luaconfsCopy);
6642
6643 size_t queriesCount = 0;
6644
6645 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) {
6646 queriesCount++;
6647
6648 if (type == QType::DS) {
6649 if (domain == DNSName("www.sub.powerdns.com")) {
6650 setLWResult(res, 0, false, false, true);
6651 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);
6652 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6653 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6654 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6655 }
6656 else {
6657 setLWResult(res, 0, false, false, true);
6658
6659 if (domain == DNSName("com.")) {
6660 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6661 /* no DS */
6662 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6663 addRRSIG(keys, res->d_records, DNSName("."), 300);
6664 }
6665 else {
6666 setLWResult(res, 0, false, false, true);
6667 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6668 }
6669 }
6670 return 1;
6671 }
6672 else if (type == QType::DNSKEY) {
6673 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
6674 setLWResult(res, 0, true, false, true);
6675 addDNSKEY(keys, domain, 300, res->d_records);
6676 addRRSIG(keys, res->d_records, domain, 300);
6677 return 1;
6678 }
6679 }
6680 else {
6681 if (isRootServer(ip)) {
6682 setLWResult(res, 0, false, false, true);
6683 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6684 /* no DS */
6685 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6686 addRRSIG(keys, res->d_records, DNSName("."), 300);
6687 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6688 return 1;
6689 }
6690 else if (ip == ComboAddress("192.0.2.1:53")) {
6691 if (domain == DNSName("com.")) {
6692 setLWResult(res, 0, true, false, true);
6693 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6694 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6695 }
6696 else if (domain.isPartOf(DNSName("powerdns.com."))) {
6697 setLWResult(res, 0, false, false, true);
6698 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6699 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6700 }
6701 return 1;
6702 }
6703 else if (ip == ComboAddress("192.0.2.2:53")) {
6704 setLWResult(res, 0, true, false, true);
6705 if (type == QType::NS) {
6706 if (domain == DNSName("www.sub.powerdns.com.")) {
6707 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);
6708 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6709 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6710 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6711 }
6712 else if (domain == DNSName("sub.powerdns.com.")) {
6713 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6714 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6715 }
6716 else if (domain == DNSName("powerdns.com.")) {
6717 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6718 }
6719 }
6720 else if (domain == DNSName("www.sub.powerdns.com.")) {
6721 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6722 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6723 }
6724 return 1;
6725 }
6726 }
6727
6728 return 0;
6729 });
6730
6731 vector<DNSRecord> ret;
6732 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6733 BOOST_CHECK_EQUAL(res, RCode::NoError);
6734 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6735 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6736 BOOST_CHECK(ret[0].d_type == QType::A);
6737 BOOST_CHECK_EQUAL(queriesCount, 7);
6738
6739 /* again, to test the cache */
6740 ret.clear();
6741 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6742 BOOST_CHECK_EQUAL(res, RCode::NoError);
6743 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6744 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6745 BOOST_CHECK(ret[0].d_type == QType::A);
6746 BOOST_CHECK_EQUAL(queriesCount, 7);
6747 }
6748
6749 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
6750 std::unique_ptr<SyncRes> sr;
6751 initSR(sr, true);
6752
6753 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6754
6755 primeHints();
6756 const DNSName target("powerdns.com.");
6757 testkeysset_t keys;
6758
6759 auto luaconfsCopy = g_luaconfs.getCopy();
6760 luaconfsCopy.dsAnchors.clear();
6761 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6762 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6763
6764 g_luaconfs.setState(luaconfsCopy);
6765
6766 size_t queriesCount = 0;
6767
6768 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) {
6769 queriesCount++;
6770
6771 if (type == QType::DS) {
6772 if (domain == target) {
6773 setLWResult(res, 0, false, false, true);
6774 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6775 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6776 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6777 return 1;
6778 }
6779 else {
6780 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6781 }
6782 }
6783 else if (type == QType::DNSKEY) {
6784 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6785 setLWResult(res, 0, true, false, true);
6786 addDNSKEY(keys, domain, 300, res->d_records);
6787 addRRSIG(keys, res->d_records, domain, 300);
6788 return 1;
6789 }
6790 else {
6791 setLWResult(res, 0, false, false, true);
6792 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6793 return 1;
6794 }
6795 }
6796 else {
6797 if (isRootServer(ip)) {
6798 setLWResult(res, 0, false, false, true);
6799 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6800 addDS(DNSName("com."), 300, res->d_records, keys);
6801 addRRSIG(keys, res->d_records, DNSName("."), 300);
6802 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6803 return 1;
6804 }
6805 else if (ip == ComboAddress("192.0.2.1:53")) {
6806 if (domain == DNSName("com.")) {
6807 setLWResult(res, 0, true, false, true);
6808 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6809 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6810 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6811 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6812 }
6813 else {
6814 setLWResult(res, 0, false, false, true);
6815 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6816 /* no DS */
6817 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6818 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6819 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6820 }
6821 return 1;
6822 }
6823 else if (ip == ComboAddress("192.0.2.2:53")) {
6824 if (type == QType::NS) {
6825 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6826 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6827 }
6828 else {
6829 setLWResult(res, 0, true, false, true);
6830 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6831 }
6832 return 1;
6833 }
6834 }
6835
6836 return 0;
6837 });
6838
6839 vector<DNSRecord> ret;
6840 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6841 BOOST_CHECK_EQUAL(res, RCode::NoError);
6842 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6843 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6844 /* 4 NS (com from root, com from com, powerdns.com from com,
6845 powerdns.com from powerdns.com)
6846 2 DNSKEY (. and com., none for powerdns.com because no DS)
6847 1 query for A
6848 */
6849 BOOST_CHECK_EQUAL(queriesCount, 7);
6850
6851 /* again, to test the cache */
6852 ret.clear();
6853 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6854 BOOST_CHECK_EQUAL(res, RCode::NoError);
6855 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6856 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6857 BOOST_CHECK_EQUAL(queriesCount, 7);
6858 }
6859
6860 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
6861 std::unique_ptr<SyncRes> sr;
6862 initSR(sr, true);
6863
6864 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6865
6866 primeHints();
6867 const DNSName target("powerdns.com.");
6868 const DNSName targetCName("power-dns.com.");
6869 const ComboAddress targetCNameAddr("192.0.2.42");
6870 testkeysset_t keys;
6871
6872 auto luaconfsCopy = g_luaconfs.getCopy();
6873 luaconfsCopy.dsAnchors.clear();
6874 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6875 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6876 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6877 g_luaconfs.setState(luaconfsCopy);
6878
6879 size_t queriesCount = 0;
6880
6881 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) {
6882 queriesCount++;
6883
6884 if (type == QType::DS) {
6885 if (domain == targetCName) {
6886 setLWResult(res, 0, false, false, true);
6887 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6888 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6889 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6890 return 1;
6891 }
6892 else {
6893 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6894 }
6895 }
6896 else if (type == QType::DNSKEY) {
6897 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6898 setLWResult(res, 0, true, false, true);
6899 addDNSKEY(keys, domain, 300, res->d_records);
6900 addRRSIG(keys, res->d_records, domain, 300);
6901 return 1;
6902 }
6903 else {
6904 setLWResult(res, 0, false, false, true);
6905 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6906 return 1;
6907 }
6908 }
6909 else {
6910 if (isRootServer(ip)) {
6911 setLWResult(res, 0, false, false, true);
6912 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6913 addDS(DNSName("com."), 300, res->d_records, keys);
6914 addRRSIG(keys, res->d_records, DNSName("."), 300);
6915 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6916 return 1;
6917 }
6918 else if (ip == ComboAddress("192.0.2.1:53")) {
6919 setLWResult(res, 0, false, false, true);
6920 if (domain == DNSName("com.")) {
6921 setLWResult(res, 0, true, false, true);
6922 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6923 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6924 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6925 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6926 }
6927 else {
6928 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6929 if (domain == DNSName("powerdns.com.")) {
6930 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6931 }
6932 else if (domain == targetCName) {
6933 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6934 }
6935 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6936 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6937 }
6938
6939 return 1;
6940 }
6941 else if (ip == ComboAddress("192.0.2.2:53")) {
6942 setLWResult(res, 0, true, false, true);
6943
6944 if (type == QType::NS) {
6945 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6946 if (domain == DNSName("powerdns.com.")) {
6947 addRRSIG(keys, res->d_records, domain, 300);
6948 }
6949 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6950 if (domain == DNSName("powerdns.com.")) {
6951 addRRSIG(keys, res->d_records, domain, 300);
6952 }
6953 }
6954 else {
6955 if (domain == DNSName("powerdns.com.")) {
6956 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6957 addRRSIG(keys, res->d_records, domain, 300);
6958 }
6959 else if (domain == targetCName) {
6960 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6961 }
6962 }
6963
6964 return 1;
6965 }
6966 }
6967
6968 return 0;
6969 });
6970
6971 vector<DNSRecord> ret;
6972 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6973 BOOST_CHECK_EQUAL(res, RCode::NoError);
6974 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6975 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6976 BOOST_CHECK_EQUAL(queriesCount, 11);
6977
6978 /* again, to test the cache */
6979 ret.clear();
6980 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6981 BOOST_CHECK_EQUAL(res, RCode::NoError);
6982 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6983 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6984 BOOST_CHECK_EQUAL(queriesCount, 11);
6985 }
6986
6987 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
6988 std::unique_ptr<SyncRes> sr;
6989 initSR(sr, true);
6990
6991 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6992
6993 primeHints();
6994 const DNSName target("power-dns.com.");
6995 const DNSName targetCName("powerdns.com.");
6996 const ComboAddress targetCNameAddr("192.0.2.42");
6997 testkeysset_t keys;
6998
6999 auto luaconfsCopy = g_luaconfs.getCopy();
7000 luaconfsCopy.dsAnchors.clear();
7001 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7002 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7003 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7004 g_luaconfs.setState(luaconfsCopy);
7005
7006 size_t queriesCount = 0;
7007
7008 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) {
7009 queriesCount++;
7010
7011 if (type == QType::DS) {
7012 if (domain == DNSName("power-dns.com.")) {
7013 setLWResult(res, 0, false, false, true);
7014 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7015 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7016 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7017 return 1;
7018 }
7019 else {
7020 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7021 }
7022 }
7023 else if (type == QType::DNSKEY) {
7024 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7025 setLWResult(res, 0, true, false, true);
7026 addDNSKEY(keys, domain, 300, res->d_records);
7027 addRRSIG(keys, res->d_records, domain, 300);
7028 return 1;
7029 }
7030 else {
7031 setLWResult(res, 0, false, false, true);
7032 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7033 return 1;
7034 }
7035 }
7036 else {
7037 if (isRootServer(ip)) {
7038 setLWResult(res, 0, false, false, true);
7039 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7040 addDS(DNSName("com."), 300, res->d_records, keys);
7041 addRRSIG(keys, res->d_records, DNSName("."), 300);
7042 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7043 return 1;
7044 }
7045 else if (ip == ComboAddress("192.0.2.1:53")) {
7046 if (domain == DNSName("com.")) {
7047 setLWResult(res, 0, true, false, true);
7048 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7049 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7050 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7051 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7052 }
7053 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7054 setLWResult(res, 0, false, false, true);
7055 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7056 if (domain == targetCName) {
7057 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7058 }
7059 else if (domain == target) {
7060 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7061 }
7062 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7063 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7064 }
7065 return 1;
7066 }
7067 else if (ip == ComboAddress("192.0.2.2:53")) {
7068 setLWResult(res, 0, true, false, true);
7069 if (type == QType::NS) {
7070 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7071 if (domain == DNSName("powerdns.com.")) {
7072 addRRSIG(keys, res->d_records, domain, 300);
7073 }
7074 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7075 if (domain == DNSName("powerdns.com.")) {
7076 addRRSIG(keys, res->d_records, domain, 300);
7077 }
7078 }
7079 else {
7080 if (domain == target) {
7081 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7082 }
7083 else if (domain == targetCName) {
7084 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7085 addRRSIG(keys, res->d_records, domain, 300);
7086 }
7087 }
7088 return 1;
7089 }
7090 }
7091
7092 return 0;
7093 });
7094
7095 vector<DNSRecord> ret;
7096 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7097 BOOST_CHECK_EQUAL(res, RCode::NoError);
7098 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7099 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7100 BOOST_CHECK_EQUAL(queriesCount, 11);
7101
7102 /* again, to test the cache */
7103 ret.clear();
7104 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7105 BOOST_CHECK_EQUAL(res, RCode::NoError);
7106 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7107 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7108 BOOST_CHECK_EQUAL(queriesCount, 11);
7109 }
7110
7111 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
7112 std::unique_ptr<SyncRes> sr;
7113 initSR(sr, true);
7114
7115 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7116
7117 primeHints();
7118 const DNSName target("power-dns.com.");
7119 const DNSName targetCName("powerdns.com.");
7120 const ComboAddress targetCNameAddr("192.0.2.42");
7121 testkeysset_t keys;
7122
7123 auto luaconfsCopy = g_luaconfs.getCopy();
7124 luaconfsCopy.dsAnchors.clear();
7125 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7126 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7127 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7128 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7129 g_luaconfs.setState(luaconfsCopy);
7130
7131 size_t queriesCount = 0;
7132
7133 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) {
7134 queriesCount++;
7135
7136 if (type == QType::DS || type == QType::DNSKEY) {
7137 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7138 }
7139 else {
7140 if (isRootServer(ip)) {
7141 setLWResult(res, 0, false, false, true);
7142 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7143 addDS(DNSName("com."), 300, res->d_records, keys);
7144 addRRSIG(keys, res->d_records, DNSName("."), 300);
7145 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7146 return 1;
7147 }
7148 else if (ip == ComboAddress("192.0.2.1:53")) {
7149 if (domain == DNSName("com.")) {
7150 setLWResult(res, 0, true, false, true);
7151 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7152 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7153 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7154 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7155 }
7156 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7157 setLWResult(res, 0, false, false, true);
7158 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7159 addDS(DNSName(domain), 300, res->d_records, keys);
7160 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7161 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7162 }
7163 return 1;
7164 }
7165 else if (ip == ComboAddress("192.0.2.2:53")) {
7166 setLWResult(res, 0, true, false, true);
7167 if (type == QType::NS) {
7168 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7169 addRRSIG(keys, res->d_records, domain, 300);
7170 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7171 addRRSIG(keys, res->d_records, domain, 300);
7172 }
7173 else {
7174 if (domain == target) {
7175 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7176 /* No RRSIG, leading to bogus */
7177 }
7178 else if (domain == targetCName) {
7179 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7180 addRRSIG(keys, res->d_records, domain, 300);
7181 }
7182 }
7183 return 1;
7184 }
7185 }
7186
7187 return 0;
7188 });
7189
7190 vector<DNSRecord> ret;
7191 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7192 BOOST_CHECK_EQUAL(res, RCode::NoError);
7193 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7194 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7195 BOOST_CHECK_EQUAL(queriesCount, 11);
7196
7197 /* again, to test the cache */
7198 ret.clear();
7199 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7200 BOOST_CHECK_EQUAL(res, RCode::NoError);
7201 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7202 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7203 BOOST_CHECK_EQUAL(queriesCount, 11);
7204 }
7205
7206 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7207 std::unique_ptr<SyncRes> sr;
7208 initSR(sr, true);
7209
7210 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7211
7212 primeHints();
7213 const DNSName target("power-dns.com.");
7214 const DNSName targetCName("powerdns.com.");
7215 const ComboAddress targetCNameAddr("192.0.2.42");
7216 testkeysset_t keys;
7217
7218 auto luaconfsCopy = g_luaconfs.getCopy();
7219 luaconfsCopy.dsAnchors.clear();
7220 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7221 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7222 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7223 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7224 g_luaconfs.setState(luaconfsCopy);
7225
7226 size_t queriesCount = 0;
7227
7228 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) {
7229 queriesCount++;
7230
7231 if (type == QType::DS || type == QType::DNSKEY) {
7232 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7233 }
7234 else {
7235 if (isRootServer(ip)) {
7236 setLWResult(res, 0, false, false, true);
7237 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7238 addDS(DNSName("com."), 300, res->d_records, keys);
7239 addRRSIG(keys, res->d_records, DNSName("."), 300);
7240 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7241 return 1;
7242 }
7243 else if (ip == ComboAddress("192.0.2.1:53")) {
7244 if (domain == DNSName("com.")) {
7245 setLWResult(res, 0, true, false, true);
7246 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7247 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7248 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7249 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7250 }
7251 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7252 setLWResult(res, 0, false, false, true);
7253 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7254 addDS(DNSName(domain), 300, res->d_records, keys);
7255 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7256 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7257 }
7258 return 1;
7259 }
7260 else if (ip == ComboAddress("192.0.2.2:53")) {
7261 setLWResult(res, 0, true, false, true);
7262 if (type == QType::NS) {
7263 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7264 addRRSIG(keys, res->d_records, domain, 300);
7265 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7266 addRRSIG(keys, res->d_records, domain, 300);
7267 }
7268 else {
7269 if (domain == target) {
7270 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7271 addRRSIG(keys, res->d_records, domain, 300);
7272 }
7273 else if (domain == targetCName) {
7274 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7275 /* No RRSIG, leading to bogus */
7276 }
7277 }
7278 return 1;
7279 }
7280 }
7281
7282 return 0;
7283 });
7284
7285 vector<DNSRecord> ret;
7286 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7287 BOOST_CHECK_EQUAL(res, RCode::NoError);
7288 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7289 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7290 BOOST_CHECK_EQUAL(queriesCount, 11);
7291
7292 /* again, to test the cache */
7293 ret.clear();
7294 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7295 BOOST_CHECK_EQUAL(res, RCode::NoError);
7296 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7297 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7298 BOOST_CHECK_EQUAL(queriesCount, 11);
7299 }
7300
7301 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
7302 std::unique_ptr<SyncRes> sr;
7303 initSR(sr, true);
7304
7305 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7306
7307 primeHints();
7308 const DNSName target("power-dns.com.");
7309 const DNSName targetCName("powerdns.com.");
7310 const ComboAddress targetCNameAddr("192.0.2.42");
7311 testkeysset_t keys;
7312
7313 auto luaconfsCopy = g_luaconfs.getCopy();
7314 luaconfsCopy.dsAnchors.clear();
7315 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7316 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7317 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7318 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7319 g_luaconfs.setState(luaconfsCopy);
7320
7321 size_t queriesCount = 0;
7322
7323 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) {
7324 queriesCount++;
7325
7326 if (type == QType::DS || type == QType::DNSKEY) {
7327 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7328 }
7329 else {
7330 if (isRootServer(ip)) {
7331 setLWResult(res, 0, false, false, true);
7332 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7333 addDS(DNSName("com."), 300, res->d_records, keys);
7334 addRRSIG(keys, res->d_records, DNSName("."), 300);
7335 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7336 return 1;
7337 }
7338 else if (ip == ComboAddress("192.0.2.1:53")) {
7339 if (domain == DNSName("com.")) {
7340 setLWResult(res, 0, true, false, true);
7341 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7342 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7343 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7344 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7345 }
7346 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7347 setLWResult(res, 0, false, false, true);
7348 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7349 addDS(DNSName(domain), 300, res->d_records, keys);
7350 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7351 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7352 }
7353 return 1;
7354 }
7355 else if (ip == ComboAddress("192.0.2.2:53")) {
7356 setLWResult(res, 0, true, false, true);
7357 if (type == QType::NS) {
7358 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7359 addRRSIG(keys, res->d_records, domain, 300);
7360 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7361 addRRSIG(keys, res->d_records, domain, 300);
7362 }
7363 else {
7364 if (domain == target) {
7365 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7366 addRRSIG(keys, res->d_records, domain, 300);
7367 }
7368 else if (domain == targetCName) {
7369 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7370 addRRSIG(keys, res->d_records, domain, 300);
7371 }
7372 }
7373 return 1;
7374 }
7375 }
7376
7377 return 0;
7378 });
7379
7380 vector<DNSRecord> ret;
7381 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7382 BOOST_CHECK_EQUAL(res, RCode::NoError);
7383 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7384 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7385 BOOST_CHECK_EQUAL(queriesCount, 12);
7386
7387 /* again, to test the cache */
7388 ret.clear();
7389 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7390 BOOST_CHECK_EQUAL(res, RCode::NoError);
7391 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7392 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7393 BOOST_CHECK_EQUAL(queriesCount, 12);
7394 }
7395
7396 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7397 std::unique_ptr<SyncRes> sr;
7398 initSR(sr, true);
7399
7400 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7401
7402 primeHints();
7403 const DNSName target("powerdns.com.");
7404 const DNSName targetCName("power-dns.com.");
7405 const ComboAddress targetCNameAddr("192.0.2.42");
7406 testkeysset_t keys;
7407
7408 auto luaconfsCopy = g_luaconfs.getCopy();
7409 luaconfsCopy.dsAnchors.clear();
7410 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7411 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7412 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7413 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7414 g_luaconfs.setState(luaconfsCopy);
7415
7416 size_t queriesCount = 0;
7417
7418 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) {
7419 queriesCount++;
7420
7421 if (type == QType::DS) {
7422 if (domain == DNSName("power-dns.com.")) {
7423 setLWResult(res, 0, false, false, true);
7424 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7425 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7426 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7427 return 1;
7428 }
7429 else {
7430 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7431 }
7432 }
7433 else if (type == QType::DNSKEY) {
7434 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7435 setLWResult(res, 0, true, false, true);
7436 addDNSKEY(keys, domain, 300, res->d_records);
7437 addRRSIG(keys, res->d_records, domain, 300);
7438 return 1;
7439 }
7440 else {
7441 setLWResult(res, 0, false, false, true);
7442 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7443 return 1;
7444 }
7445 }
7446 else {
7447 if (isRootServer(ip)) {
7448 setLWResult(res, 0, false, false, true);
7449 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7450 addDS(DNSName("com."), 300, res->d_records, keys);
7451 addRRSIG(keys, res->d_records, DNSName("."), 300);
7452 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7453 return 1;
7454 }
7455 else if (ip == ComboAddress("192.0.2.1:53")) {
7456 if (domain == DNSName("com.")) {
7457 setLWResult(res, 0, true, false, true);
7458 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7459 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7460 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7461 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7462 }
7463 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7464 setLWResult(res, 0, false, false, true);
7465 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7466 if (domain == DNSName("powerdns.com.")) {
7467 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7468 }
7469 else if (domain == targetCName) {
7470 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7471 }
7472 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7473 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7474 }
7475 return 1;
7476 }
7477 else if (ip == ComboAddress("192.0.2.2:53")) {
7478 setLWResult(res, 0, true, false, true);
7479 if (type == QType::NS) {
7480 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7481 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7482 }
7483 else {
7484 if (domain == DNSName("powerdns.com.")) {
7485 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7486 /* No RRSIG -> Bogus */
7487 }
7488 else if (domain == targetCName) {
7489 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7490 }
7491 }
7492 return 1;
7493 }
7494 }
7495
7496 return 0;
7497 });
7498
7499 vector<DNSRecord> ret;
7500 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7501 BOOST_CHECK_EQUAL(res, RCode::NoError);
7502 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7503 /* no RRSIG to show */
7504 BOOST_CHECK_EQUAL(ret.size(), 2);
7505 BOOST_CHECK_EQUAL(queriesCount, 10);
7506
7507 /* again, to test the cache */
7508 ret.clear();
7509 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7510 BOOST_CHECK_EQUAL(res, RCode::NoError);
7511 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7512 BOOST_CHECK_EQUAL(ret.size(), 2);
7513 BOOST_CHECK_EQUAL(queriesCount, 10);
7514 }
7515
7516 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7517 std::unique_ptr<SyncRes> sr;
7518 initSR(sr, true);
7519
7520 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7521
7522 primeHints();
7523 const DNSName target("powerdns.com.");
7524 const ComboAddress targetAddr("192.0.2.42");
7525 testkeysset_t keys;
7526
7527 auto luaconfsCopy = g_luaconfs.getCopy();
7528 luaconfsCopy.dsAnchors.clear();
7529 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7530 /* No key material for .com */
7531 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7532 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7533 g_luaconfs.setState(luaconfsCopy);
7534
7535 size_t queriesCount = 0;
7536
7537 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) {
7538 queriesCount++;
7539
7540 if (type == QType::DNSKEY) {
7541 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7542 setLWResult(res, 0, true, false, true);
7543 addDNSKEY(keys, domain, 300, res->d_records);
7544 addRRSIG(keys, res->d_records, domain, 300);
7545 return 1;
7546 }
7547 else if (domain == DNSName("com.")) {
7548 setLWResult(res, 0, false, false, true);
7549 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7550 return 1;
7551 }
7552 }
7553 else {
7554 if (isRootServer(ip)) {
7555 setLWResult(res, 0, false, false, true);
7556 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7557 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7558 addRRSIG(keys, res->d_records, DNSName("."), 300);
7559 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7560 return 1;
7561 }
7562 else if (ip == ComboAddress("192.0.2.1:53")) {
7563 if (target == domain) {
7564 setLWResult(res, 0, false, false, true);
7565 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7566 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7567 }
7568 else if (domain == DNSName("com.")) {
7569 setLWResult(res, 0, true, false, true);
7570 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7571 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7572 }
7573 return 1;
7574 }
7575 else if (ip == ComboAddress("192.0.2.2:53")) {
7576 setLWResult(res, 0, true, false, true);
7577 if (type == QType::NS) {
7578 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7579 }
7580 else {
7581 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7582 }
7583 addRRSIG(keys, res->d_records, domain, 300);
7584 return 1;
7585 }
7586 }
7587
7588 return 0;
7589 });
7590
7591 vector<DNSRecord> ret;
7592 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7593 BOOST_CHECK_EQUAL(res, RCode::NoError);
7594 /* should be insecure but we have a TA for powerdns.com. */
7595 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7596 /* We got a RRSIG */
7597 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7598 BOOST_CHECK(ret[0].d_type == QType::A);
7599 BOOST_CHECK_EQUAL(queriesCount, 5);
7600
7601 /* again, to test the cache */
7602 ret.clear();
7603 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7604 BOOST_CHECK_EQUAL(res, RCode::NoError);
7605 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7606 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7607 BOOST_CHECK(ret[0].d_type == QType::A);
7608 BOOST_CHECK_EQUAL(queriesCount, 5);
7609 }
7610
7611 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
7612 std::unique_ptr<SyncRes> sr;
7613 initSR(sr, true);
7614
7615 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7616
7617 primeHints();
7618 const DNSName target("powerdns.com.");
7619 const ComboAddress targetAddr("192.0.2.42");
7620 testkeysset_t keys;
7621
7622 auto luaconfsCopy = g_luaconfs.getCopy();
7623 luaconfsCopy.dsAnchors.clear();
7624 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7625 /* No key material for .com */
7626 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7627 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7628 g_luaconfs.setState(luaconfsCopy);
7629
7630 size_t queriesCount = 0;
7631
7632 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) {
7633 queriesCount++;
7634
7635 if (type == QType::DNSKEY) {
7636 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7637 setLWResult(res, 0, true, false, true);
7638 addDNSKEY(keys, domain, 300, res->d_records);
7639 addRRSIG(keys, res->d_records, domain, 300);
7640 return 1;
7641 }
7642 else if (domain == DNSName("com.")) {
7643 setLWResult(res, 0, false, false, true);
7644 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7645 return 1;
7646 }
7647 }
7648 else {
7649 if (target.isPartOf(domain) && isRootServer(ip)) {
7650 setLWResult(res, 0, false, false, true);
7651 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7652 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7653 addRRSIG(keys, res->d_records, DNSName("."), 300);
7654 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7655 return 1;
7656 }
7657 else if (ip == ComboAddress("192.0.2.1:53")) {
7658 if (target == domain) {
7659 setLWResult(res, 0, false, false, true);
7660 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7661 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7662 }
7663 else if (domain == DNSName("com.")) {
7664 setLWResult(res, 0, true, false, true);
7665 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7666 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7667 }
7668 return 1;
7669 }
7670 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
7671 setLWResult(res, 0, true, false, true);
7672 if (type == QType::NS) {
7673 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7674 }
7675 else {
7676 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7677 }
7678 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
7679 return 1;
7680 }
7681 }
7682
7683 return 0;
7684 });
7685
7686 vector<DNSRecord> ret;
7687 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7688 BOOST_CHECK_EQUAL(res, RCode::NoError);
7689 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
7690 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7691 /* No RRSIG */
7692 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7693 BOOST_CHECK(ret[0].d_type == QType::A);
7694 BOOST_CHECK_EQUAL(queriesCount, 4);
7695
7696 /* again, to test the cache */
7697 ret.clear();
7698 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7699 BOOST_CHECK_EQUAL(res, RCode::NoError);
7700 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7701 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7702 BOOST_CHECK(ret[0].d_type == QType::A);
7703 BOOST_CHECK_EQUAL(queriesCount, 4);
7704 }
7705
7706 BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
7707 std::unique_ptr<SyncRes> sr;
7708 initSR(sr, true);
7709
7710 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7711
7712 primeHints();
7713 const DNSName target(".");
7714 testkeysset_t keys;
7715
7716 auto luaconfsCopy = g_luaconfs.getCopy();
7717 luaconfsCopy.dsAnchors.clear();
7718 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7719 /* Add a NTA for "." */
7720 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
7721 g_luaconfs.setState(luaconfsCopy);
7722
7723 size_t queriesCount = 0;
7724
7725 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) {
7726 queriesCount++;
7727
7728 if (domain == target && type == QType::NS) {
7729
7730 setLWResult(res, 0, true, false, true);
7731 char addr[] = "a.root-servers.net.";
7732 for (char idx = 'a'; idx <= 'm'; idx++) {
7733 addr[0] = idx;
7734 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7735 }
7736
7737 addRRSIG(keys, res->d_records, domain, 300);
7738
7739 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7740 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
7741
7742 return 1;
7743 } else if (domain == target && type == QType::DNSKEY) {
7744
7745 setLWResult(res, 0, true, false, true);
7746
7747 /* No DNSKEY */
7748
7749 return 1;
7750 }
7751
7752 return 0;
7753 });
7754
7755 vector<DNSRecord> ret;
7756 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7757 BOOST_CHECK_EQUAL(res, RCode::NoError);
7758 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7759 /* 13 NS + 1 RRSIG */
7760 BOOST_REQUIRE_EQUAL(ret.size(), 14);
7761 BOOST_CHECK_EQUAL(queriesCount, 1);
7762
7763 /* again, to test the cache */
7764 ret.clear();
7765 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7766 BOOST_CHECK_EQUAL(res, RCode::NoError);
7767 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7768 BOOST_REQUIRE_EQUAL(ret.size(), 14);
7769 BOOST_CHECK_EQUAL(queriesCount, 1);
7770 }
7771
7772 BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
7773 std::unique_ptr<SyncRes> sr;
7774 initSR(sr, true);
7775
7776 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7777
7778 primeHints();
7779 const DNSName target(".");
7780 testkeysset_t keys;
7781
7782 /* Remove the root DS */
7783 auto luaconfsCopy = g_luaconfs.getCopy();
7784 luaconfsCopy.dsAnchors.clear();
7785 g_luaconfs.setState(luaconfsCopy);
7786
7787 size_t queriesCount = 0;
7788
7789 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) {
7790 queriesCount++;
7791
7792 if (domain == target && type == QType::NS) {
7793
7794 setLWResult(res, 0, true, false, true);
7795 char addr[] = "a.root-servers.net.";
7796 for (char idx = 'a'; idx <= 'm'; idx++) {
7797 addr[0] = idx;
7798 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7799 }
7800
7801 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7802 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
7803
7804 return 1;
7805 }
7806
7807 return 0;
7808 });
7809
7810 vector<DNSRecord> ret;
7811 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7812 BOOST_CHECK_EQUAL(res, RCode::NoError);
7813 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7814 /* 13 NS + 0 RRSIG */
7815 BOOST_REQUIRE_EQUAL(ret.size(), 13);
7816 BOOST_CHECK_EQUAL(queriesCount, 1);
7817
7818 /* again, to test the cache */
7819 ret.clear();
7820 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7821 BOOST_CHECK_EQUAL(res, RCode::NoError);
7822 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7823 BOOST_REQUIRE_EQUAL(ret.size(), 13);
7824 BOOST_CHECK_EQUAL(queriesCount, 1);
7825 }
7826
7827 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
7828 std::unique_ptr<SyncRes> sr;
7829 initSR(sr, true);
7830
7831 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7832
7833 primeHints();
7834 const DNSName target("powerdns.com.");
7835 testkeysset_t keys;
7836
7837 auto luaconfsCopy = g_luaconfs.getCopy();
7838 luaconfsCopy.dsAnchors.clear();
7839 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7840 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7841 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7842 g_luaconfs.setState(luaconfsCopy);
7843
7844 size_t queriesCount = 0;
7845
7846 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) {
7847 queriesCount++;
7848
7849 if (type == QType::DS || type == QType::DNSKEY) {
7850 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7851 }
7852 else {
7853
7854 setLWResult(res, 0, true, false, true);
7855 return 1;
7856 }
7857
7858 return 0;
7859 });
7860
7861 vector<DNSRecord> ret;
7862 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7863 BOOST_CHECK_EQUAL(res, RCode::NoError);
7864 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7865 BOOST_REQUIRE_EQUAL(ret.size(), 0);
7866 /* com|NS, powerdns.com|NS, powerdns.com|A */
7867 BOOST_CHECK_EQUAL(queriesCount, 3);
7868
7869 /* again, to test the cache */
7870 ret.clear();
7871 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7872 BOOST_CHECK_EQUAL(res, RCode::NoError);
7873 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7874 BOOST_REQUIRE_EQUAL(ret.size(), 0);
7875 /* we don't store empty results */
7876 BOOST_CHECK_EQUAL(queriesCount, 4);
7877 }
7878
7879 BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
7880 init();
7881
7882 testkeysset_t keys;
7883 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7884
7885 vector<DNSRecord> records;
7886
7887 vector<shared_ptr<DNSRecordContent>> recordContents;
7888 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7889
7890 /*
7891 No wrap test case:
7892 a.example.org. -> d.example.org. denies the existence of b.example.org.
7893 */
7894 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7895 recordContents.push_back(records.at(0).d_content);
7896 addRRSIG(keys, records, DNSName("example.org."), 300);
7897 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7898 records.clear();
7899
7900 ContentSigPair pair;
7901 pair.records = recordContents;
7902 pair.signatures = signatureContents;
7903 cspmap_t denialMap;
7904 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
7905
7906 /* add wildcard denial */
7907 recordContents.clear();
7908 signatureContents.clear();
7909 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7910 recordContents.push_back(records.at(0).d_content);
7911 addRRSIG(keys, records, DNSName("example.org."), 300);
7912 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7913 records.clear();
7914
7915 pair.records = recordContents;
7916 pair.signatures = signatureContents;
7917 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
7918
7919 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
7920 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7921
7922 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
7923 /* let's check that d.example.org. is not denied by this proof */
7924 BOOST_CHECK_EQUAL(denialState, NODATA);
7925 }
7926
7927 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
7928 init();
7929
7930 testkeysset_t keys;
7931 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7932
7933 vector<DNSRecord> records;
7934
7935 vector<shared_ptr<DNSRecordContent>> recordContents;
7936 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7937
7938 /*
7939 Wrap case 1 test case:
7940 z.example.org. -> b.example.org. denies the existence of a.example.org.
7941 */
7942 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7943 recordContents.push_back(records.at(0).d_content);
7944 addRRSIG(keys, records, DNSName("example.org."), 300);
7945 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7946 records.clear();
7947
7948 ContentSigPair pair;
7949 pair.records = recordContents;
7950 pair.signatures = signatureContents;
7951 cspmap_t denialMap;
7952 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
7953
7954 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
7955 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7956
7957 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
7958 /* let's check that d.example.org. is not denied by this proof */
7959 BOOST_CHECK_EQUAL(denialState, NODATA);
7960 }
7961
7962 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
7963 init();
7964
7965 testkeysset_t keys;
7966 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7967
7968 vector<DNSRecord> records;
7969
7970 vector<shared_ptr<DNSRecordContent>> recordContents;
7971 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7972
7973 /*
7974 Wrap case 2 test case:
7975 y.example.org. -> a.example.org. denies the existence of z.example.org.
7976 */
7977 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7978 recordContents.push_back(records.at(0).d_content);
7979 addRRSIG(keys, records, DNSName("example.org."), 300);
7980 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7981 records.clear();
7982
7983 ContentSigPair pair;
7984 pair.records = recordContents;
7985 pair.signatures = signatureContents;
7986 cspmap_t denialMap;
7987 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
7988
7989 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
7990 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7991
7992 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
7993 /* let's check that d.example.org. is not denied by this proof */
7994 BOOST_CHECK_EQUAL(denialState, NODATA);
7995 }
7996
7997 BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
7998 init();
7999
8000 testkeysset_t keys;
8001 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8002
8003 vector<DNSRecord> records;
8004
8005 vector<shared_ptr<DNSRecordContent>> recordContents;
8006 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8007
8008 /*
8009 Only one NSEC in the whole zone test case:
8010 a.example.org. -> a.example.org. denies the existence of b.example.org.
8011 */
8012 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8013 recordContents.push_back(records.at(0).d_content);
8014 addRRSIG(keys, records, DNSName("example.org."), 300);
8015 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8016 records.clear();
8017
8018 ContentSigPair pair;
8019 pair.records = recordContents;
8020 pair.signatures = signatureContents;
8021 cspmap_t denialMap;
8022 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8023
8024 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
8025 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8026
8027 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
8028 /* let's check that d.example.org. is not denied by this proof */
8029 BOOST_CHECK_EQUAL(denialState, NODATA);
8030 }
8031
8032 BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
8033 init();
8034
8035 testkeysset_t keys;
8036 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8037
8038 vector<DNSRecord> records;
8039
8040 vector<shared_ptr<DNSRecordContent>> recordContents;
8041 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8042
8043 /*
8044 The RRSIG from "." denies the existence of anything between a. and c.,
8045 including b.
8046 */
8047 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
8048 recordContents.push_back(records.at(0).d_content);
8049 addRRSIG(keys, records, DNSName("."), 300);
8050 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8051 records.clear();
8052
8053 ContentSigPair pair;
8054 pair.records = recordContents;
8055 pair.signatures = signatureContents;
8056 cspmap_t denialMap;
8057 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8058
8059 /* add wildcard denial */
8060 recordContents.clear();
8061 signatureContents.clear();
8062 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8063 recordContents.push_back(records.at(0).d_content);
8064 addRRSIG(keys, records, DNSName("."), 300);
8065 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8066 records.clear();
8067
8068 pair.records = recordContents;
8069 pair.signatures = signatureContents;
8070 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
8071
8072 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
8073 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8074 }
8075
8076 BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
8077 init();
8078
8079 testkeysset_t keys;
8080 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8081
8082 vector<DNSRecord> records;
8083
8084 vector<shared_ptr<DNSRecordContent>> recordContents;
8085 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8086
8087 /*
8088 The RRSIG from "." denies the existence of any type except NS at a.
8089 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8090 signer field that is shorter than the owner name of the NSEC RR) it can't
8091 be used to deny anything except the whole name or a DS.
8092 */
8093 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
8094 recordContents.push_back(records.at(0).d_content);
8095 addRRSIG(keys, records, DNSName("."), 300);
8096 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8097 records.clear();
8098
8099 ContentSigPair pair;
8100 pair.records = recordContents;
8101 pair.signatures = signatureContents;
8102 cspmap_t denialMap;
8103 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8104
8105 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8106 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8107 nonexistence of any RRs below that zone cut, which include all RRs at
8108 that (original) owner name other than DS RRs, and all RRs below that
8109 owner name regardless of type.
8110 */
8111
8112 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
8113 /* no data means the qname/qtype is not denied, because an ancestor
8114 delegation NSEC can only deny the DS */
8115 BOOST_CHECK_EQUAL(denialState, NODATA);
8116
8117 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8118 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8119 }
8120
8121 BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
8122 init();
8123
8124 testkeysset_t keys;
8125 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8126
8127 vector<DNSRecord> records;
8128
8129 vector<shared_ptr<DNSRecordContent>> recordContents;
8130 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8131
8132 /*
8133 * RFC 5155 section 8.9:
8134 * If there is an NSEC3 RR present in the response that matches the
8135 * delegation name, then the validator MUST ensure that the NS bit is
8136 * set and that the DS bit is not set in the Type Bit Maps field of the
8137 * NSEC3 RR.
8138 */
8139 /*
8140 The RRSIG from "." denies the existence of any type at a.
8141 NS should be set if it was proving an insecure delegation, let's check that
8142 we correctly detect that it's not.
8143 */
8144 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
8145 recordContents.push_back(records.at(0).d_content);
8146 addRRSIG(keys, records, DNSName("."), 300);
8147 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8148 records.clear();
8149
8150 ContentSigPair pair;
8151 pair.records = recordContents;
8152 pair.signatures = signatureContents;
8153 cspmap_t denialMap;
8154 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8155
8156 /* Insecure because the NS is not set, so while it does
8157 denies the DS, it can't prove an insecure delegation */
8158 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8159 BOOST_CHECK_EQUAL(denialState, NODATA);
8160 }
8161
8162 BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
8163 init();
8164
8165 testkeysset_t keys;
8166 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8167
8168 vector<DNSRecord> records;
8169
8170 vector<shared_ptr<DNSRecordContent>> recordContents;
8171 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8172
8173 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
8174 recordContents.push_back(records.at(0).d_content);
8175 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8176 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8177 records.clear();
8178
8179 ContentSigPair pair;
8180 pair.records = recordContents;
8181 pair.signatures = signatureContents;
8182 cspmap_t denialMap;
8183 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8184
8185 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8186 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
8187 BOOST_CHECK_EQUAL(denialState, NODATA);
8188 }
8189
8190 BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
8191 init();
8192
8193 testkeysset_t keys;
8194 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8195
8196 vector<DNSRecord> records;
8197
8198 vector<shared_ptr<DNSRecordContent>> recordContents;
8199 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8200
8201 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
8202 recordContents.push_back(records.at(0).d_content);
8203 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8204 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8205
8206 ContentSigPair pair;
8207 pair.records = recordContents;
8208 pair.signatures = signatureContents;
8209 cspmap_t denialMap;
8210 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8211 records.clear();
8212
8213 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8214 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8215 BOOST_CHECK_EQUAL(denialState, NODATA);
8216 }
8217
8218 BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8219 init();
8220
8221 testkeysset_t keys;
8222 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8223
8224 vector<DNSRecord> records;
8225
8226 vector<shared_ptr<DNSRecordContent>> recordContents;
8227 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8228
8229 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8230 recordContents.push_back(records.at(0).d_content);
8231 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8232 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8233 records.clear();
8234
8235 ContentSigPair pair;
8236 pair.records = recordContents;
8237 pair.signatures = signatureContents;
8238 cspmap_t denialMap;
8239 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8240
8241 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8242 BOOST_CHECK_EQUAL(denialState, NODATA);
8243 }
8244
8245 BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
8246 init();
8247
8248 testkeysset_t keys;
8249 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8250
8251 vector<DNSRecord> records;
8252
8253 vector<shared_ptr<DNSRecordContent>> recordContents;
8254 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8255
8256 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8257 recordContents.push_back(records.at(0).d_content);
8258 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8259 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8260
8261 ContentSigPair pair;
8262 pair.records = recordContents;
8263 pair.signatures = signatureContents;
8264 cspmap_t denialMap;
8265 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8266
8267 /* Add NSEC3 for the closest encloser */
8268 recordContents.clear();
8269 signatureContents.clear();
8270 records.clear();
8271 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8272 recordContents.push_back(records.at(0).d_content);
8273 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8274 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8275
8276 pair.records = recordContents;
8277 pair.signatures = signatureContents;
8278 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8279
8280 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8281 BOOST_CHECK_EQUAL(denialState, NODATA);
8282 }
8283
8284 BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8285 init();
8286
8287 testkeysset_t keys;
8288 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8289
8290 vector<DNSRecord> records;
8291
8292 vector<shared_ptr<DNSRecordContent>> recordContents;
8293 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8294
8295 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8296 recordContents.push_back(records.at(0).d_content);
8297 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8298 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8299 records.clear();
8300
8301 ContentSigPair pair;
8302 pair.records = recordContents;
8303 pair.signatures = signatureContents;
8304 cspmap_t denialMap;
8305 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8306
8307 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
8308 it is an ENT */
8309 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
8310 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8311
8312 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8313 it could prove a NXDOMAIN if it had an additional wildcard denial */
8314 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8315 BOOST_CHECK_EQUAL(denialState, NODATA);
8316
8317 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8318 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8319 BOOST_CHECK_EQUAL(denialState, NODATA);
8320
8321 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8322 recordContents.clear();
8323 signatureContents.clear();
8324 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8325 recordContents.push_back(records.at(0).d_content);
8326 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8327 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8328 records.clear();
8329 pair.records = recordContents;
8330 pair.signatures = signatureContents;
8331 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8332
8333 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
8334 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8335 }
8336
8337 BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8338 init();
8339
8340 testkeysset_t keys;
8341 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8342
8343 vector<DNSRecord> records;
8344
8345 vector<shared_ptr<DNSRecordContent>> recordContents;
8346 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8347
8348 /*
8349 The RRSIG from "." denies the existence of any type except NS at a.
8350 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8351 signer field that is shorter than the owner name of the NSEC RR) it can't
8352 be used to deny anything except the whole name or a DS.
8353 */
8354 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
8355 recordContents.push_back(records.at(0).d_content);
8356 addRRSIG(keys, records, DNSName("."), 300);
8357 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8358
8359 ContentSigPair pair;
8360 pair.records = recordContents;
8361 pair.signatures = signatureContents;
8362 cspmap_t denialMap;
8363 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8364 records.clear();
8365
8366 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8367 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8368 nonexistence of any RRs below that zone cut, which include all RRs at
8369 that (original) owner name other than DS RRs, and all RRs below that
8370 owner name regardless of type.
8371 */
8372
8373 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8374 /* no data means the qname/qtype is not denied, because an ancestor
8375 delegation NSEC3 can only deny the DS */
8376 BOOST_CHECK_EQUAL(denialState, NODATA);
8377
8378 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8379 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8380 }
8381
8382 BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8383 init();
8384
8385 testkeysset_t keys;
8386 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8387
8388 vector<DNSRecord> records;
8389
8390 vector<shared_ptr<DNSRecordContent>> recordContents;
8391 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8392
8393 /* adding a NSEC3 with more iterations that we support */
8394 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8395 recordContents.push_back(records.at(0).d_content);
8396 addRRSIG(keys, records, DNSName("."), 300);
8397 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8398
8399 ContentSigPair pair;
8400 pair.records = recordContents;
8401 pair.signatures = signatureContents;
8402 cspmap_t denialMap;
8403 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8404 records.clear();
8405
8406 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8407 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8408 BOOST_CHECK_EQUAL(denialState, INSECURE);
8409 }
8410
8411 BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8412 init();
8413
8414 testkeysset_t keys;
8415 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8416
8417 vector<DNSRecord> records;
8418
8419 vector<shared_ptr<DNSRecordContent>> recordContents;
8420 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8421
8422 /*
8423 * RFC 5155 section 8.9:
8424 * If there is an NSEC3 RR present in the response that matches the
8425 * delegation name, then the validator MUST ensure that the NS bit is
8426 * set and that the DS bit is not set in the Type Bit Maps field of the
8427 * NSEC3 RR.
8428 */
8429 /*
8430 The RRSIG from "." denies the existence of any type at a.
8431 NS should be set if it was proving an insecure delegation, let's check that
8432 we correctly detect that it's not.
8433 */
8434 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
8435 recordContents.push_back(records.at(0).d_content);
8436 addRRSIG(keys, records, DNSName("."), 300);
8437 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8438
8439 ContentSigPair pair;
8440 pair.records = recordContents;
8441 pair.signatures = signatureContents;
8442 cspmap_t denialMap;
8443 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8444 records.clear();
8445
8446 /* Insecure because the NS is not set, so while it does
8447 denies the DS, it can't prove an insecure delegation */
8448 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8449 BOOST_CHECK_EQUAL(denialState, NODATA);
8450 }
8451
8452 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8453 std::unique_ptr<SyncRes> sr;
8454 initSR(sr, true);
8455
8456 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8457
8458 primeHints();
8459 const DNSName target("com.");
8460 testkeysset_t keys;
8461
8462 auto luaconfsCopy = g_luaconfs.getCopy();
8463 luaconfsCopy.dsAnchors.clear();
8464 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8465 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8466 g_luaconfs.setState(luaconfsCopy);
8467
8468 size_t queriesCount = 0;
8469
8470 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) {
8471 queriesCount++;
8472
8473 DNSName auth = domain;
8474 auth.chopOff();
8475
8476 if (type == QType::DS || type == QType::DNSKEY) {
8477 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8478 }
8479 else {
8480 setLWResult(res, RCode::NoError, true, false, true);
8481 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8482 addRRSIG(keys, res->d_records, domain, 300);
8483 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8484 addRRSIG(keys, res->d_records, domain, 1);
8485 return 1;
8486 }
8487
8488 return 0;
8489 });
8490
8491 const time_t now = time(nullptr);
8492 vector<DNSRecord> ret;
8493 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8494 BOOST_CHECK_EQUAL(res, RCode::NoError);
8495 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8496 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8497 BOOST_CHECK_EQUAL(queriesCount, 4);
8498
8499 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
8500 NegCache::NegCacheEntry ne;
8501 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8502 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8503 BOOST_CHECK_EQUAL(ne.d_ttd, now + 1);
8504 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
8505 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8506 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8507 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8508 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
8509
8510 /* again, to test the cache */
8511 ret.clear();
8512 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8513 BOOST_CHECK_EQUAL(res, RCode::NoError);
8514 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8515 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8516 BOOST_CHECK_EQUAL(queriesCount, 4);
8517 }
8518
8519 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
8520 std::unique_ptr<SyncRes> sr;
8521 initSR(sr, true);
8522
8523 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8524
8525 primeHints();
8526 const DNSName target("com.");
8527 const ComboAddress targetAddr("192.0.2.42");
8528 testkeysset_t keys;
8529
8530 auto luaconfsCopy = g_luaconfs.getCopy();
8531 luaconfsCopy.dsAnchors.clear();
8532 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8533 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8534 g_luaconfs.setState(luaconfsCopy);
8535
8536 size_t queriesCount = 0;
8537
8538 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) {
8539 queriesCount++;
8540
8541 DNSName auth = domain;
8542 auth.chopOff();
8543
8544 if (type == QType::DS || type == QType::DNSKEY) {
8545 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8546 }
8547 else {
8548 setLWResult(res, RCode::NoError, true, false, true);
8549 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8550 addRRSIG(keys, res->d_records, domain, 1);
8551 return 1;
8552 }
8553
8554 return 0;
8555 });
8556
8557 const time_t now = time(nullptr);
8558 vector<DNSRecord> ret;
8559 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8560 BOOST_CHECK_EQUAL(res, RCode::NoError);
8561 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8562 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8563 BOOST_CHECK_EQUAL(queriesCount, 4);
8564
8565 /* check that the entry has not been cached for longer than the RRSIG validity */
8566 const ComboAddress who;
8567 vector<DNSRecord> cached;
8568 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
8569 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
8570 BOOST_REQUIRE_EQUAL(cached.size(), 1);
8571 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
8572 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
8573
8574 /* again, to test the cache */
8575 ret.clear();
8576 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8577 BOOST_CHECK_EQUAL(res, RCode::NoError);
8578 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8579 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8580 BOOST_CHECK_EQUAL(queriesCount, 4);
8581 }
8582
8583 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
8584 /*
8585 Validation is optional, and the first query does not ask for it,
8586 so the answer is cached as Indeterminate.
8587 The second query asks for validation, answer should be marked as
8588 Secure.
8589 */
8590 std::unique_ptr<SyncRes> sr;
8591 initSR(sr, true);
8592
8593 setDNSSECValidation(sr, DNSSECMode::Process);
8594
8595 primeHints();
8596 const DNSName target("com.");
8597 testkeysset_t keys;
8598
8599 auto luaconfsCopy = g_luaconfs.getCopy();
8600 luaconfsCopy.dsAnchors.clear();
8601 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8602 g_luaconfs.setState(luaconfsCopy);
8603
8604 size_t queriesCount = 0;
8605
8606 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) {
8607 queriesCount++;
8608
8609 if (type == QType::DS || type == QType::DNSKEY) {
8610 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8611 }
8612 else {
8613 if (domain == target && type == QType::A) {
8614 setLWResult(res, 0, true, false, true);
8615 addRecordToLW(res, target, QType::A, "192.0.2.1");
8616 addRRSIG(keys, res->d_records, DNSName("."), 300);
8617 return 1;
8618 }
8619 }
8620
8621 return 0;
8622 });
8623
8624 vector<DNSRecord> ret;
8625 /* first query does not require validation */
8626 sr->setDNSSECValidationRequested(false);
8627 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8628 BOOST_CHECK_EQUAL(res, RCode::NoError);
8629 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8630 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8631 for (const auto& record : ret) {
8632 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8633 }
8634 BOOST_CHECK_EQUAL(queriesCount, 1);
8635
8636
8637 ret.clear();
8638 /* second one _does_ require validation */
8639 sr->setDNSSECValidationRequested(true);
8640 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8641 BOOST_CHECK_EQUAL(res, RCode::NoError);
8642 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8643 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8644 for (const auto& record : ret) {
8645 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8646 }
8647 BOOST_CHECK_EQUAL(queriesCount, 3);
8648 }
8649
8650 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
8651 /*
8652 Validation is optional, and the first query does not ask for it,
8653 so the answer is cached as Indeterminate.
8654 The second query asks for validation, answer should be marked as
8655 Insecure.
8656 */
8657 std::unique_ptr<SyncRes> sr;
8658 initSR(sr, true);
8659
8660 setDNSSECValidation(sr, DNSSECMode::Process);
8661
8662 primeHints();
8663 const DNSName target("com.");
8664 testkeysset_t keys;
8665
8666 auto luaconfsCopy = g_luaconfs.getCopy();
8667 luaconfsCopy.dsAnchors.clear();
8668 g_luaconfs.setState(luaconfsCopy);
8669
8670 size_t queriesCount = 0;
8671
8672 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) {
8673 queriesCount++;
8674
8675 if (type == QType::DS || type == QType::DNSKEY) {
8676 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8677 }
8678 else {
8679 if (domain == target && type == QType::A) {
8680 setLWResult(res, 0, true, false, true);
8681 addRecordToLW(res, target, QType::A, "192.0.2.1");
8682 return 1;
8683 }
8684 }
8685
8686 return 0;
8687 });
8688
8689 vector<DNSRecord> ret;
8690 /* first query does not require validation */
8691 sr->setDNSSECValidationRequested(false);
8692 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8693 BOOST_CHECK_EQUAL(res, RCode::NoError);
8694 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8695 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8696 for (const auto& record : ret) {
8697 BOOST_CHECK(record.d_type == QType::A);
8698 }
8699 BOOST_CHECK_EQUAL(queriesCount, 1);
8700
8701
8702 ret.clear();
8703 /* second one _does_ require validation */
8704 sr->setDNSSECValidationRequested(true);
8705 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8706 BOOST_CHECK_EQUAL(res, RCode::NoError);
8707 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8708 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8709 for (const auto& record : ret) {
8710 BOOST_CHECK(record.d_type == QType::A);
8711 }
8712 BOOST_CHECK_EQUAL(queriesCount, 1);
8713 }
8714
8715 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
8716 /*
8717 Validation is optional, and the first query does not ask for it,
8718 so the answer is cached as Indeterminate.
8719 The second query asks for validation, answer should be marked as
8720 Bogus.
8721 */
8722 std::unique_ptr<SyncRes> sr;
8723 initSR(sr, true);
8724
8725 setDNSSECValidation(sr, DNSSECMode::Process);
8726
8727 primeHints();
8728 const DNSName target("com.");
8729 testkeysset_t keys;
8730
8731 auto luaconfsCopy = g_luaconfs.getCopy();
8732 luaconfsCopy.dsAnchors.clear();
8733 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8734 g_luaconfs.setState(luaconfsCopy);
8735
8736 size_t queriesCount = 0;
8737
8738 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) {
8739 queriesCount++;
8740
8741 if (type == QType::DS || type == QType::DNSKEY) {
8742 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8743 }
8744 else {
8745 if (domain == target && type == QType::A) {
8746 setLWResult(res, 0, true, false, true);
8747 addRecordToLW(res, target, QType::A, "192.0.2.1");
8748 /* no RRSIG */
8749 return 1;
8750 }
8751 }
8752
8753 return 0;
8754 });
8755
8756 vector<DNSRecord> ret;
8757 /* first query does not require validation */
8758 sr->setDNSSECValidationRequested(false);
8759 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8760 BOOST_CHECK_EQUAL(res, RCode::NoError);
8761 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8762 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8763 for (const auto& record : ret) {
8764 BOOST_CHECK(record.d_type == QType::A);
8765 }
8766 BOOST_CHECK_EQUAL(queriesCount, 1);
8767
8768
8769 ret.clear();
8770 /* second one _does_ require validation */
8771 sr->setDNSSECValidationRequested(true);
8772 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8773 BOOST_CHECK_EQUAL(res, RCode::NoError);
8774 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8775 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8776 for (const auto& record : ret) {
8777 BOOST_CHECK(record.d_type == QType::A);
8778 }
8779 BOOST_CHECK_EQUAL(queriesCount, 3);
8780 }
8781
8782 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
8783 /*
8784 Validation is optional, and the first query does not ask for it,
8785 so the answer is cached as Indeterminate.
8786 The second query asks for validation, answer should be marked as
8787 Secure.
8788 */
8789 std::unique_ptr<SyncRes> sr;
8790 initSR(sr, true);
8791
8792 setDNSSECValidation(sr, DNSSECMode::Process);
8793
8794 primeHints();
8795 const DNSName target("com.");
8796 const DNSName cnameTarget("cname-com.");
8797 testkeysset_t keys;
8798
8799 auto luaconfsCopy = g_luaconfs.getCopy();
8800 luaconfsCopy.dsAnchors.clear();
8801 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8802 g_luaconfs.setState(luaconfsCopy);
8803
8804 size_t queriesCount = 0;
8805
8806 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) {
8807 queriesCount++;
8808
8809 if (type == QType::DS || type == QType::DNSKEY) {
8810 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8811 }
8812 else {
8813 if (domain == target && type == QType::A) {
8814 setLWResult(res, 0, true, false, true);
8815 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
8816 addRRSIG(keys, res->d_records, DNSName("."), 300);
8817 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8818 addRRSIG(keys, res->d_records, DNSName("."), 300);
8819 return 1;
8820 } else if (domain == cnameTarget && type == QType::A) {
8821 setLWResult(res, 0, true, false, true);
8822 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8823 addRRSIG(keys, res->d_records, DNSName("."), 300);
8824 return 1;
8825 }
8826 }
8827
8828 return 0;
8829 });
8830
8831 vector<DNSRecord> ret;
8832 /* first query does not require validation */
8833 sr->setDNSSECValidationRequested(false);
8834 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8835 BOOST_CHECK_EQUAL(res, RCode::NoError);
8836 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8837 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8838 for (const auto& record : ret) {
8839 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
8840 }
8841 BOOST_CHECK_EQUAL(queriesCount, 2);
8842
8843
8844 ret.clear();
8845 /* second one _does_ require validation */
8846 sr->setDNSSECValidationRequested(true);
8847 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8848 BOOST_CHECK_EQUAL(res, RCode::NoError);
8849 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8850 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8851 for (const auto& record : ret) {
8852 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
8853 }
8854 BOOST_CHECK_EQUAL(queriesCount, 5);
8855 }
8856
8857 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
8858 /*
8859 Validation is optional, and the first query does not ask for it,
8860 so the answer is cached as Indeterminate.
8861 The second query asks for validation, answer should be marked as
8862 Insecure.
8863 */
8864 std::unique_ptr<SyncRes> sr;
8865 initSR(sr, true);
8866
8867 setDNSSECValidation(sr, DNSSECMode::Process);
8868
8869 primeHints();
8870 const DNSName target("com.");
8871 const DNSName cnameTarget("cname-com.");
8872 testkeysset_t keys;
8873
8874 auto luaconfsCopy = g_luaconfs.getCopy();
8875 luaconfsCopy.dsAnchors.clear();
8876 g_luaconfs.setState(luaconfsCopy);
8877
8878 size_t queriesCount = 0;
8879
8880 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) {
8881 queriesCount++;
8882
8883 if (type == QType::DS || type == QType::DNSKEY) {
8884 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8885 }
8886 else {
8887 if (domain == target && type == QType::A) {
8888 setLWResult(res, 0, true, false, true);
8889 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
8890 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8891 return 1;
8892 } else if (domain == cnameTarget && type == QType::A) {
8893 setLWResult(res, 0, true, false, true);
8894 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8895 return 1;
8896 }
8897 }
8898
8899 return 0;
8900 });
8901
8902 vector<DNSRecord> ret;
8903 /* first query does not require validation */
8904 sr->setDNSSECValidationRequested(false);
8905 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8906 BOOST_CHECK_EQUAL(res, RCode::NoError);
8907 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8908 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8909 for (const auto& record : ret) {
8910 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8911 }
8912 BOOST_CHECK_EQUAL(queriesCount, 2);
8913
8914
8915 ret.clear();
8916 /* second one _does_ require validation */
8917 sr->setDNSSECValidationRequested(true);
8918 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8919 BOOST_CHECK_EQUAL(res, RCode::NoError);
8920 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8921 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8922 for (const auto& record : ret) {
8923 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8924 }
8925 BOOST_CHECK_EQUAL(queriesCount, 2);
8926 }
8927
8928 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
8929 /*
8930 Validation is optional, and the first query does not ask for it,
8931 so the answer is cached as Indeterminate.
8932 The second query asks for validation, answer should be marked as
8933 Bogus.
8934 */
8935 std::unique_ptr<SyncRes> sr;
8936 initSR(sr, true);
8937
8938 setDNSSECValidation(sr, DNSSECMode::Process);
8939
8940 primeHints();
8941 const DNSName target("com.");
8942 const DNSName cnameTarget("cname-com.");
8943 testkeysset_t keys;
8944
8945 auto luaconfsCopy = g_luaconfs.getCopy();
8946 luaconfsCopy.dsAnchors.clear();
8947 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8948 g_luaconfs.setState(luaconfsCopy);
8949
8950 size_t queriesCount = 0;
8951
8952 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) {
8953 queriesCount++;
8954
8955 if (type == QType::DS || type == QType::DNSKEY) {
8956 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8957 }
8958 else {
8959 if (domain == target && type == QType::A) {
8960 setLWResult(res, 0, true, false, true);
8961 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
8962 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8963 /* no RRSIG */
8964 return 1;
8965 } else if (domain == cnameTarget && type == QType::A) {
8966 setLWResult(res, 0, true, false, true);
8967 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8968 /* no RRSIG */
8969 return 1;
8970 }
8971 }
8972
8973 return 0;
8974 });
8975
8976 vector<DNSRecord> ret;
8977 /* first query does not require validation */
8978 sr->setDNSSECValidationRequested(false);
8979 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8980 BOOST_CHECK_EQUAL(res, RCode::NoError);
8981 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8982 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8983 for (const auto& record : ret) {
8984 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8985 }
8986 BOOST_CHECK_EQUAL(queriesCount, 2);
8987
8988
8989 ret.clear();
8990 /* second one _does_ require validation */
8991 sr->setDNSSECValidationRequested(true);
8992 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8993 BOOST_CHECK_EQUAL(res, RCode::NoError);
8994 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8995 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8996 for (const auto& record : ret) {
8997 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8998 }
8999 BOOST_CHECK_EQUAL(queriesCount, 5);
9000 }
9001
9002 BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) {
9003 /*
9004 We get a record from a secure zone in the additional section, without
9005 the corresponding RRSIG. The record should not be marked as authoritative
9006 and should be correctly validated.
9007 */
9008 std::unique_ptr<SyncRes> sr;
9009 initSR(sr, true);
9010
9011 setDNSSECValidation(sr, DNSSECMode::Process);
9012
9013 primeHints();
9014 const DNSName target("com.");
9015 const DNSName addTarget("nsX.com.");
9016 testkeysset_t keys;
9017
9018 auto luaconfsCopy = g_luaconfs.getCopy();
9019 luaconfsCopy.dsAnchors.clear();
9020 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9021 g_luaconfs.setState(luaconfsCopy);
9022
9023 size_t queriesCount = 0;
9024
9025 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) {
9026 queriesCount++;
9027
9028 if (type == QType::DS || type == QType::DNSKEY) {
9029 if (domain == addTarget) {
9030 DNSName auth(domain);
9031 /* no DS for com, auth will be . */
9032 auth.chopOff();
9033 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false);
9034 }
9035 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9036 }
9037 else {
9038 if (domain == target && type == QType::A) {
9039 setLWResult(res, 0, true, false, true);
9040 addRecordToLW(res, target, QType::A, "192.0.2.1");
9041 addRRSIG(keys, res->d_records, DNSName("."), 300);
9042 addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL);
9043 /* no RRSIG for the additional record */
9044 return 1;
9045 } else if (domain == addTarget && type == QType::A) {
9046 setLWResult(res, 0, true, false, true);
9047 addRecordToLW(res, addTarget, QType::A, "192.0.2.42");
9048 addRRSIG(keys, res->d_records, DNSName("."), 300);
9049 return 1;
9050 }
9051 }
9052
9053 return 0;
9054 });
9055
9056 vector<DNSRecord> ret;
9057 /* first query for target/A, will pick up the additional record as non-auth / unvalidated */
9058 sr->setDNSSECValidationRequested(false);
9059 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9060 BOOST_CHECK_EQUAL(res, RCode::NoError);
9061 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9062 BOOST_CHECK_EQUAL(ret.size(), 2);
9063 for (const auto& record : ret) {
9064 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9065 }
9066 BOOST_CHECK_EQUAL(queriesCount, 1);
9067
9068 ret.clear();
9069 /* ask for the additional record directly, we should not use
9070 the non-auth one and issue a new query, properly validated */
9071 sr->setDNSSECValidationRequested(true);
9072 res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret);
9073 BOOST_CHECK_EQUAL(res, RCode::NoError);
9074 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9075 BOOST_CHECK_EQUAL(ret.size(), 2);
9076 for (const auto& record : ret) {
9077 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9078 }
9079 BOOST_CHECK_EQUAL(queriesCount, 5);
9080 }
9081
9082 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
9083 /*
9084 Validation is optional, and the first query does not ask for it,
9085 so the answer is negatively cached as Indeterminate.
9086 The second query asks for validation, answer should be marked as
9087 Secure.
9088 */
9089 std::unique_ptr<SyncRes> sr;
9090 initSR(sr, true);
9091
9092 setDNSSECValidation(sr, DNSSECMode::Process);
9093
9094 primeHints();
9095 const DNSName target("com.");
9096 testkeysset_t keys;
9097
9098 auto luaconfsCopy = g_luaconfs.getCopy();
9099 luaconfsCopy.dsAnchors.clear();
9100 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9101 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9102 g_luaconfs.setState(luaconfsCopy);
9103
9104 size_t queriesCount = 0;
9105
9106 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) {
9107 queriesCount++;
9108
9109 DNSName auth = domain;
9110 auth.chopOff();
9111
9112 if (type == QType::DS || type == QType::DNSKEY) {
9113 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9114 }
9115 else {
9116 setLWResult(res, RCode::NoError, true, false, true);
9117 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9118 addRRSIG(keys, res->d_records, domain, 300);
9119 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
9120 addRRSIG(keys, res->d_records, domain, 1);
9121 return 1;
9122 }
9123
9124 return 0;
9125 });
9126
9127 vector<DNSRecord> ret;
9128 /* first query does not require validation */
9129 sr->setDNSSECValidationRequested(false);
9130 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9131 BOOST_CHECK_EQUAL(res, RCode::NoError);
9132 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9133 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9134 BOOST_CHECK_EQUAL(queriesCount, 1);
9135 /* check that the entry has not been negatively cached */
9136 NegCache::NegCacheEntry ne;
9137 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9138 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9139 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9140 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9141 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9142 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9143 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
9144
9145 ret.clear();
9146 /* second one _does_ require validation */
9147 sr->setDNSSECValidationRequested(true);
9148 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9149 BOOST_CHECK_EQUAL(res, RCode::NoError);
9150 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9151 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9152 BOOST_CHECK_EQUAL(queriesCount, 4);
9153 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9154 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9155 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
9156 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9157 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9158 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9159 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
9160 }
9161
9162 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
9163 /*
9164 Validation is optional, and the first query does not ask for it,
9165 so the answer is negatively cached as Indeterminate.
9166 The second query asks for validation, answer should be marked as
9167 Secure.
9168 The difference with test_dnssec_validation_from_negcache_secure is
9169 that have one more level here, so we are going to look for the proof
9170 that the DS does not exist for the last level. Since there is no cut,
9171 we should accept the fact that the NSEC denies DS and NS both.
9172 */
9173 std::unique_ptr<SyncRes> sr;
9174 initSR(sr, true);
9175
9176 setDNSSECValidation(sr, DNSSECMode::Process);
9177
9178 primeHints();
9179 const DNSName target("www.com.");
9180 testkeysset_t keys;
9181
9182 auto luaconfsCopy = g_luaconfs.getCopy();
9183 luaconfsCopy.dsAnchors.clear();
9184 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9185 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9186 g_luaconfs.setState(luaconfsCopy);
9187
9188 size_t queriesCount = 0;
9189
9190 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) {
9191 queriesCount++;
9192
9193 if (type == QType::DS || type == QType::DNSKEY) {
9194 if (domain == target) {
9195 /* there is no cut */
9196 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9197 }
9198 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
9199 }
9200
9201 return 0;
9202 });
9203
9204 vector<DNSRecord> ret;
9205 /* first query does not require validation */
9206 sr->setDNSSECValidationRequested(false);
9207 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9208 BOOST_CHECK_EQUAL(res, RCode::NoError);
9209 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9210 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9211 BOOST_CHECK_EQUAL(queriesCount, 1);
9212
9213 ret.clear();
9214 /* second one _does_ require validation */
9215 sr->setDNSSECValidationRequested(true);
9216 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9217 BOOST_CHECK_EQUAL(res, RCode::NoError);
9218 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9219 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9220 BOOST_CHECK_EQUAL(queriesCount, 4);
9221 }
9222
9223 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
9224 /*
9225 Validation is optional, and the first query does not ask for it,
9226 so the answer is negatively cached as Indeterminate.
9227 The second query asks for validation, answer should be marked as
9228 Insecure.
9229 */
9230 std::unique_ptr<SyncRes> sr;
9231 initSR(sr, true);
9232
9233 setDNSSECValidation(sr, DNSSECMode::Process);
9234
9235 primeHints();
9236 const DNSName target("com.");
9237 testkeysset_t keys;
9238
9239 auto luaconfsCopy = g_luaconfs.getCopy();
9240 luaconfsCopy.dsAnchors.clear();
9241 g_luaconfs.setState(luaconfsCopy);
9242
9243 size_t queriesCount = 0;
9244
9245 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) {
9246 queriesCount++;
9247
9248 DNSName auth = domain;
9249 auth.chopOff();
9250
9251 if (type == QType::DS || type == QType::DNSKEY) {
9252 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9253 }
9254 else {
9255 setLWResult(res, RCode::NoError, true, false, true);
9256 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9257 return 1;
9258 }
9259
9260 return 0;
9261 });
9262
9263 vector<DNSRecord> ret;
9264 /* first query does not require validation */
9265 sr->setDNSSECValidationRequested(false);
9266 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9267 BOOST_CHECK_EQUAL(res, RCode::NoError);
9268 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9269 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9270 BOOST_CHECK_EQUAL(queriesCount, 1);
9271 /* check that the entry has not been negatively cached */
9272 NegCache::NegCacheEntry ne;
9273 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9274 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9275 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9276 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9277 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9278 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9279 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9280
9281 ret.clear();
9282 /* second one _does_ require validation */
9283 sr->setDNSSECValidationRequested(true);
9284 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9285 BOOST_CHECK_EQUAL(res, RCode::NoError);
9286 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9287 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9288 BOOST_CHECK_EQUAL(queriesCount, 1);
9289 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9290 BOOST_CHECK_EQUAL(ne.d_validationState, Insecure);
9291 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9292 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9293 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9294 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9295 }
9296
9297 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
9298 /*
9299 Validation is optional, and the first query does not ask for it,
9300 so the answer is negatively cached as Indeterminate.
9301 The second query asks for validation, answer should be marked as
9302 Bogus.
9303 */
9304 std::unique_ptr<SyncRes> sr;
9305 initSR(sr, true);
9306
9307 setDNSSECValidation(sr, DNSSECMode::Process);
9308
9309 primeHints();
9310 const DNSName target("com.");
9311 testkeysset_t keys;
9312
9313 auto luaconfsCopy = g_luaconfs.getCopy();
9314 luaconfsCopy.dsAnchors.clear();
9315 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9316 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9317 g_luaconfs.setState(luaconfsCopy);
9318
9319 size_t queriesCount = 0;
9320
9321 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) {
9322 queriesCount++;
9323
9324 DNSName auth = domain;
9325 auth.chopOff();
9326
9327 if (type == QType::DS || type == QType::DNSKEY) {
9328 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9329 }
9330 else {
9331 setLWResult(res, RCode::NoError, true, false, true);
9332 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9333 addRRSIG(keys, res->d_records, domain, 300);
9334 /* no denial */
9335 return 1;
9336 }
9337
9338 return 0;
9339 });
9340
9341 vector<DNSRecord> ret;
9342 /* first query does not require validation */
9343 sr->setDNSSECValidationRequested(false);
9344 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9345 BOOST_CHECK_EQUAL(res, RCode::NoError);
9346 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9347 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9348 BOOST_CHECK_EQUAL(queriesCount, 1);
9349 NegCache::NegCacheEntry ne;
9350 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9351 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9352 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9353 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9354 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9355 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9356 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9357
9358 ret.clear();
9359 /* second one _does_ require validation */
9360 sr->setDNSSECValidationRequested(true);
9361 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9362 BOOST_CHECK_EQUAL(res, RCode::NoError);
9363 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9364 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9365 BOOST_CHECK_EQUAL(queriesCount, 4);
9366 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9367 BOOST_CHECK_EQUAL(ne.d_validationState, Bogus);
9368 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9369 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9370 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9371 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9372 }
9373
9374 BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
9375 g_lowercaseOutgoing = true;
9376 std::unique_ptr<SyncRes> sr;
9377 initSR(sr);
9378
9379 primeHints();
9380
9381 vector<DNSName> sentOutQnames;
9382
9383 const DNSName target("WWW.POWERDNS.COM");
9384 const DNSName cname("WWW.PowerDNS.org");
9385
9386 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) {
9387
9388 sentOutQnames.push_back(domain);
9389
9390 if (isRootServer(ip)) {
9391 if (domain == target) {
9392 setLWResult(res, 0, false, false, true);
9393 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
9394 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
9395 return 1;
9396 }
9397 if (domain == cname) {
9398 setLWResult(res, 0, false, false, true);
9399 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
9400 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
9401 return 1;
9402 }
9403 } else if (ip == ComboAddress("192.0.2.1:53")) {
9404 if (domain == target) {
9405 setLWResult(res, 0, true, false, false);
9406 addRecordToLW(res, domain, QType::CNAME, cname.toString());
9407 return 1;
9408 }
9409 } else if (ip == ComboAddress("192.0.2.2:53")) {
9410 if (domain == cname) {
9411 setLWResult(res, 0, true, false, false);
9412 addRecordToLW(res, domain, QType::A, "127.0.0.1");
9413 return 1;
9414 }
9415 }
9416 return 0;
9417 });
9418
9419 vector<DNSRecord> ret;
9420 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9421
9422 BOOST_CHECK_EQUAL(res, RCode::NoError);
9423
9424 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9425 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
9426
9427 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
9428 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
9429 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
9430 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
9431 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
9432
9433 g_lowercaseOutgoing = false;
9434 }
9435
9436 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
9437 std::unique_ptr<SyncRes> sr;
9438 initSR(sr, true);
9439
9440 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9441
9442 primeHints();
9443 const DNSName target("com.");
9444 testkeysset_t keys, keys2;
9445
9446 auto luaconfsCopy = g_luaconfs.getCopy();
9447 luaconfsCopy.dsAnchors.clear();
9448 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9449 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9450 g_luaconfs.setState(luaconfsCopy);
9451
9452 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9453 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9454 // But add the existing root key otherwise no RRSIG can be created
9455 auto rootkey = keys.find(g_rootdnsname);
9456 keys2.insert(*rootkey);
9457
9458 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) {
9459 DNSName auth = domain;
9460 auth.chopOff();
9461 if (type == QType::DS || type == QType::DNSKEY) {
9462 if (domain == target) {
9463 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9464 return 0;
9465 }
9466 }
9467 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9468 }
9469 return 0;
9470 });
9471
9472 dsmap_t ds;
9473 auto state = sr->getDSRecords(target, ds, false, 0, false);
9474 BOOST_CHECK_EQUAL(state, Secure);
9475 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9476 for (const auto& i : ds) {
9477 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9478 }
9479 }
9480
9481 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
9482 std::unique_ptr<SyncRes> sr;
9483 initSR(sr, true);
9484
9485 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9486
9487 primeHints();
9488 const DNSName target("com.");
9489 testkeysset_t keys, keys2, keys3;
9490
9491 auto luaconfsCopy = g_luaconfs.getCopy();
9492 luaconfsCopy.dsAnchors.clear();
9493 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9494 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9495 g_luaconfs.setState(luaconfsCopy);
9496
9497 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9498 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9499 // But add the existing root key otherwise no RRSIG can be created
9500 auto rootkey = keys.find(g_rootdnsname);
9501 keys2.insert(*rootkey);
9502
9503 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
9504 // But add the existing root key otherwise no RRSIG can be created
9505 keys3.insert(*rootkey);
9506
9507 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) {
9508 DNSName auth = domain;
9509 auth.chopOff();
9510 if (type == QType::DS || type == QType::DNSKEY) {
9511 if (domain == target) {
9512 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9513 return 0;
9514 }
9515 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9516 return 0;
9517 }
9518 }
9519 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9520 }
9521 return 0;
9522 });
9523
9524 dsmap_t ds;
9525 auto state = sr->getDSRecords(target, ds, false, 0, false);
9526 BOOST_CHECK_EQUAL(state, Secure);
9527 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9528 for (const auto& i : ds) {
9529 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9530 }
9531 }
9532
9533 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
9534 std::unique_ptr<SyncRes> sr;
9535 initSR(sr, true);
9536
9537 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9538
9539 primeHints();
9540 const DNSName target("com.");
9541 testkeysset_t keys, keys2, keys3;
9542
9543 auto luaconfsCopy = g_luaconfs.getCopy();
9544 luaconfsCopy.dsAnchors.clear();
9545 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9546 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9547 g_luaconfs.setState(luaconfsCopy);
9548
9549 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9550 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
9551 // But add the existing root key otherwise no RRSIG can be created
9552 auto rootkey = keys.find(g_rootdnsname);
9553 keys2.insert(*rootkey);
9554
9555 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
9556 // But add the existing root key otherwise no RRSIG can be created
9557 keys3.insert(*rootkey);
9558
9559 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) {
9560 DNSName auth = domain;
9561 auth.chopOff();
9562 if (type == QType::DS || type == QType::DNSKEY) {
9563 if (domain == target) {
9564 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9565 return 0;
9566 }
9567 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9568 return 0;
9569 }
9570 }
9571 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9572 }
9573 return 0;
9574 });
9575
9576 dsmap_t ds;
9577 auto state = sr->getDSRecords(target, ds, false, 0, false);
9578 BOOST_CHECK_EQUAL(state, Secure);
9579 BOOST_REQUIRE_EQUAL(ds.size(), 2);
9580 for (const auto& i : ds) {
9581 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9582 }
9583 }
9584
9585 #ifdef HAVE_BOTAN
9586 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) {
9587 std::unique_ptr<SyncRes> sr;
9588 initSR(sr, true);
9589
9590 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9591
9592 primeHints();
9593 const DNSName target("com.");
9594 testkeysset_t keys, keys2;
9595
9596 auto luaconfsCopy = g_luaconfs.getCopy();
9597 luaconfsCopy.dsAnchors.clear();
9598 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9599 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys);
9600 g_luaconfs.setState(luaconfsCopy);
9601
9602 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9603 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9604 // But add the existing root key otherwise no RRSIG can be created
9605 auto rootkey = keys.find(g_rootdnsname);
9606 keys2.insert(*rootkey);
9607
9608 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) {
9609 DNSName auth = domain;
9610 auth.chopOff();
9611 if (type == QType::DS || type == QType::DNSKEY) {
9612 if (domain == target) {
9613 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9614 return 0;
9615 }
9616 }
9617 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9618 }
9619 return 0;
9620 });
9621
9622 dsmap_t ds;
9623 auto state = sr->getDSRecords(target, ds, false, 0, false);
9624 BOOST_CHECK_EQUAL(state, Secure);
9625 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9626 for (const auto& i : ds) {
9627 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9628 }
9629 }
9630
9631 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) {
9632 std::unique_ptr<SyncRes> sr;
9633 initSR(sr, true);
9634
9635 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9636
9637 primeHints();
9638 const DNSName target("com.");
9639 testkeysset_t keys, keys2;
9640
9641 auto luaconfsCopy = g_luaconfs.getCopy();
9642 luaconfsCopy.dsAnchors.clear();
9643 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9644 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9645 g_luaconfs.setState(luaconfsCopy);
9646
9647 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9648 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9649 // But add the existing root key otherwise no RRSIG can be created
9650 auto rootkey = keys.find(g_rootdnsname);
9651 keys2.insert(*rootkey);
9652
9653 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) {
9654 DNSName auth = domain;
9655 auth.chopOff();
9656 if (type == QType::DS || type == QType::DNSKEY) {
9657 if (domain == target) {
9658 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9659 return 0;
9660 }
9661 }
9662 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9663 }
9664 return 0;
9665 });
9666
9667 dsmap_t ds;
9668 auto state = sr->getDSRecords(target, ds, false, 0, false);
9669 BOOST_CHECK_EQUAL(state, Secure);
9670 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9671 for (const auto& i : ds) {
9672 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9673 }
9674 }
9675
9676 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) {
9677 std::unique_ptr<SyncRes> sr;
9678 initSR(sr, true);
9679
9680 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9681
9682 primeHints();
9683 const DNSName target("com.");
9684 testkeysset_t keys, keys2;
9685
9686 auto luaconfsCopy = g_luaconfs.getCopy();
9687 luaconfsCopy.dsAnchors.clear();
9688 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9689 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys);
9690 g_luaconfs.setState(luaconfsCopy);
9691
9692 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9693 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9694 // But add the existing root key otherwise no RRSIG can be created
9695 auto rootkey = keys.find(g_rootdnsname);
9696 keys2.insert(*rootkey);
9697
9698 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) {
9699 DNSName auth = domain;
9700 auth.chopOff();
9701 if (type == QType::DS || type == QType::DNSKEY) {
9702 if (domain == target) {
9703 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9704 return 0;
9705 }
9706 }
9707 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9708 }
9709 return 0;
9710 });
9711
9712 dsmap_t ds;
9713 auto state = sr->getDSRecords(target, ds, false, 0, false);
9714 BOOST_CHECK_EQUAL(state, Secure);
9715 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9716 for (const auto& i : ds) {
9717 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST);
9718 }
9719 }
9720 #endif // HAVE_BOTAN110
9721
9722 /*
9723 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
9724
9725 - check out of band support
9726
9727 - check preoutquery
9728
9729 */
9730
9731 BOOST_AUTO_TEST_SUITE_END()