]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc.cc
Merge pull request #6026 from pieterlexis/update-EOL
[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.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 == target) {
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 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5332 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5333 return 1;
5334 }
5335 else {
5336 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5337 }
5338 }
5339 else {
5340 if (isRootServer(ip)) {
5341 setLWResult(res, 0, false, false, true);
5342 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5343 addDS(DNSName("com."), 300, res->d_records, keys);
5344 addRRSIG(keys, res->d_records, DNSName("."), 300);
5345 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5346 return 1;
5347 }
5348 else if (ip == ComboAddress("192.0.2.1:53")) {
5349 if (domain == DNSName("com.")) {
5350 setLWResult(res, 0, true, false, true);
5351 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5352 addRRSIG(keys, res->d_records, domain, 300);
5353 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5354 addRRSIG(keys, res->d_records, domain, 300);
5355 }
5356 else {
5357 setLWResult(res, 0, false, false, true);
5358 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5359 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5360 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5361 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5362 }
5363 return 1;
5364 }
5365 else if (ip == ComboAddress("192.0.2.2:53")) {
5366 setLWResult(res, 0, true, false, true);
5367 if (type == QType::NS) {
5368 if (domain == DNSName("powerdns.com.")) {
5369 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5370 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5371 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5372 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5373 }
5374 else {
5375 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5376 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5377 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5378 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5379 }
5380 }
5381 else {
5382 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5383 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5384 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5385 /* first the closest encloser */
5386 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5387 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5388 /* then the next closer */
5389 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5390 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5391 }
5392 return 1;
5393 }
5394 }
5395
5396 return 0;
5397 });
5398
5399 vector<DNSRecord> ret;
5400 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5401 BOOST_CHECK_EQUAL(res, RCode::NoError);
5402 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5403 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5404 BOOST_CHECK_EQUAL(queriesCount, 9);
5405
5406 /* again, to test the cache */
5407 ret.clear();
5408 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5409 BOOST_CHECK_EQUAL(res, RCode::NoError);
5410 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5411 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5412 BOOST_CHECK_EQUAL(queriesCount, 9);
5413 }
5414
5415 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5416 std::unique_ptr<SyncRes> sr;
5417 initSR(sr, true);
5418
5419 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5420
5421 primeHints();
5422 const DNSName target("www.powerdns.com.");
5423 testkeysset_t keys;
5424
5425 auto luaconfsCopy = g_luaconfs.getCopy();
5426 luaconfsCopy.dsAnchors.clear();
5427 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5428 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5429 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5430
5431 g_luaconfs.setState(luaconfsCopy);
5432
5433 size_t queriesCount = 0;
5434
5435 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) {
5436 queriesCount++;
5437
5438 if (type == QType::DS || type == QType::DNSKEY) {
5439 if (type == QType::DS && domain == target) {
5440 setLWResult(res, RCode::NoError, true, false, true);
5441 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5442 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5443 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5444 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5445 return 1;
5446 }
5447 else {
5448 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5449 }
5450 }
5451 else {
5452 if (isRootServer(ip)) {
5453 setLWResult(res, 0, false, false, true);
5454 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5455 addDS(DNSName("com."), 300, res->d_records, keys);
5456 addRRSIG(keys, res->d_records, DNSName("."), 300);
5457 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5458 return 1;
5459 }
5460 else if (ip == ComboAddress("192.0.2.1:53")) {
5461 if (domain == DNSName("com.")) {
5462 setLWResult(res, 0, true, false, true);
5463 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5464 addRRSIG(keys, res->d_records, domain, 300);
5465 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5466 addRRSIG(keys, res->d_records, domain, 300);
5467 }
5468 else {
5469 setLWResult(res, 0, false, false, true);
5470 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5471 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5472 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5473 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5474 }
5475 return 1;
5476 }
5477 else if (ip == ComboAddress("192.0.2.2:53")) {
5478 setLWResult(res, 0, true, false, true);
5479 if (type == QType::NS) {
5480 if (domain == DNSName("powerdns.com.")) {
5481 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5482 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5483 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5484 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5485 }
5486 else {
5487 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5488 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5489 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5490 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5491 }
5492 }
5493 else {
5494 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5495 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5496 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5497 /* first the closest encloser */
5498 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5499 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5500 /* then the next closer */
5501 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5502 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5503 }
5504 return 1;
5505 }
5506 }
5507
5508 return 0;
5509 });
5510
5511 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5512 we should end up Insecure */
5513 vector<DNSRecord> ret;
5514 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5515 BOOST_CHECK_EQUAL(res, RCode::NoError);
5516 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5517 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5518 BOOST_CHECK_EQUAL(queriesCount, 9);
5519
5520 /* again, to test the cache */
5521 ret.clear();
5522 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5523 BOOST_CHECK_EQUAL(res, RCode::NoError);
5524 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5525 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5526 BOOST_CHECK_EQUAL(queriesCount, 9);
5527 }
5528
5529 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5530 std::unique_ptr<SyncRes> sr;
5531 initSR(sr, true);
5532
5533 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5534
5535 primeHints();
5536 const DNSName target("www.powerdns.com.");
5537 testkeysset_t keys;
5538
5539 auto luaconfsCopy = g_luaconfs.getCopy();
5540 luaconfsCopy.dsAnchors.clear();
5541 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5542 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5543 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5544
5545 g_luaconfs.setState(luaconfsCopy);
5546
5547 size_t queriesCount = 0;
5548
5549 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) {
5550 queriesCount++;
5551
5552 if (type == QType::DS || type == QType::DNSKEY) {
5553 if (type == QType::DS && domain == target) {
5554 setLWResult(res, RCode::NoError, true, false, true);
5555 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5556 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5557 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5558 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5559 return 1;
5560 }
5561 else {
5562 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5563 }
5564 }
5565 else {
5566 if (isRootServer(ip)) {
5567 setLWResult(res, 0, false, false, true);
5568 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5569 addDS(DNSName("com."), 300, res->d_records, keys);
5570 addRRSIG(keys, res->d_records, DNSName("."), 300);
5571 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5572 return 1;
5573 }
5574 else if (ip == ComboAddress("192.0.2.1:53")) {
5575 if (domain == DNSName("com.")) {
5576 setLWResult(res, 0, true, false, true);
5577 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5578 addRRSIG(keys, res->d_records, domain, 300);
5579 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5580 addRRSIG(keys, res->d_records, domain, 300);
5581 }
5582 else {
5583 setLWResult(res, 0, false, false, true);
5584 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5585 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5586 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5587 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5588 }
5589 return 1;
5590 }
5591 else if (ip == ComboAddress("192.0.2.2:53")) {
5592 setLWResult(res, 0, true, false, true);
5593 if (type == QType::NS) {
5594 if (domain == DNSName("powerdns.com.")) {
5595 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5596 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5597 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5598 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5599 }
5600 else {
5601 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5602 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5603 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5604 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5605 }
5606 }
5607 else {
5608 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5609 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5610 }
5611 return 1;
5612 }
5613 }
5614
5615 return 0;
5616 });
5617
5618 vector<DNSRecord> ret;
5619 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5620 BOOST_CHECK_EQUAL(res, RCode::NoError);
5621 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5622 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5623 BOOST_CHECK_EQUAL(queriesCount, 9);
5624
5625 /* again, to test the cache */
5626 ret.clear();
5627 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5628 BOOST_CHECK_EQUAL(res, RCode::NoError);
5629 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5630 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5631 BOOST_CHECK_EQUAL(queriesCount, 9);
5632 }
5633
5634 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5635 std::unique_ptr<SyncRes> sr;
5636 initSR(sr, true);
5637
5638 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5639
5640 primeHints();
5641 const DNSName target("www.powerdns.com.");
5642 testkeysset_t keys;
5643
5644 auto luaconfsCopy = g_luaconfs.getCopy();
5645 luaconfsCopy.dsAnchors.clear();
5646 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5647 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5648 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5649
5650 g_luaconfs.setState(luaconfsCopy);
5651
5652 size_t queriesCount = 0;
5653 size_t dsQueriesCount = 0;
5654
5655 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) {
5656 queriesCount++;
5657
5658 if (type == QType::DS) {
5659 DNSName auth(domain);
5660 auth.chopOff();
5661 dsQueriesCount++;
5662
5663 setLWResult(res, 0, true, false, true);
5664 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5665 addRRSIG(keys, res->d_records, auth, 300);
5666 return 1;
5667 }
5668 else if (type == QType::DNSKEY) {
5669 setLWResult(res, 0, true, false, true);
5670 addDNSKEY(keys, domain, 300, res->d_records);
5671 addRRSIG(keys, res->d_records, domain, 300);
5672 return 1;
5673 }
5674 else {
5675 if (isRootServer(ip)) {
5676 setLWResult(res, 0, false, false, true);
5677 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5678 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5679 /* No DS on referral, and no denial of the DS either */
5680 return 1;
5681 }
5682 else if (ip == ComboAddress("192.0.2.1:53")) {
5683 if (domain == DNSName("com.")) {
5684 setLWResult(res, 0, true, false, true);
5685 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5686 addRRSIG(keys, res->d_records, domain, 300);
5687 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5688 addRRSIG(keys, res->d_records, domain, 300);
5689 }
5690 else {
5691 setLWResult(res, 0, false, false, true);
5692 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5693 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5694 /* No DS on referral, and no denial of the DS either */
5695 }
5696 return 1;
5697 }
5698 else if (ip == ComboAddress("192.0.2.2:53")) {
5699 setLWResult(res, 0, true, false, true);
5700 if (type == QType::NS) {
5701 if (domain == DNSName("powerdns.com.")) {
5702 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5703 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5704 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5705 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5706 }
5707 else {
5708 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5709 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5710 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5711 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5712 }
5713 }
5714 else {
5715 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5716 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5717 }
5718
5719 return 1;
5720 }
5721 }
5722
5723 return 0;
5724 });
5725
5726 vector<DNSRecord> ret;
5727 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5728 BOOST_CHECK_EQUAL(res, RCode::NoError);
5729 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5730 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5731 BOOST_CHECK_EQUAL(queriesCount, 9);
5732 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5733
5734 /* again, to test the cache */
5735 ret.clear();
5736 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5737 BOOST_CHECK_EQUAL(res, RCode::NoError);
5738 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5739 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5740 BOOST_CHECK_EQUAL(queriesCount, 9);
5741 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
5742 }
5743
5744 BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
5745 std::unique_ptr<SyncRes> sr;
5746 initSR(sr, true);
5747
5748 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5749
5750 primeHints();
5751 const DNSName target("www.powerdns.com.");
5752 testkeysset_t keys;
5753
5754 auto luaconfsCopy = g_luaconfs.getCopy();
5755 luaconfsCopy.dsAnchors.clear();
5756 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5757 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5758 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5759 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5760
5761 g_luaconfs.setState(luaconfsCopy);
5762
5763 size_t queriesCount = 0;
5764
5765 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) {
5766 queriesCount++;
5767
5768 if (type == QType::DS) {
5769 DNSName auth(domain);
5770 auth.chopOff();
5771
5772 setLWResult(res, 0, true, false, true);
5773 if (domain == target) {
5774 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5775 addRRSIG(keys, res->d_records, target, 300);
5776 }
5777 else {
5778 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5779 addRRSIG(keys, res->d_records, auth, 300);
5780 }
5781 return 1;
5782 }
5783 else if (type == QType::DNSKEY) {
5784 setLWResult(res, 0, true, false, true);
5785 addDNSKEY(keys, domain, 300, res->d_records);
5786 addRRSIG(keys, res->d_records, domain, 300);
5787 return 1;
5788 }
5789 else {
5790 if (isRootServer(ip)) {
5791 setLWResult(res, 0, false, false, true);
5792 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5793 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5794 addDS(DNSName("com."), 300, res->d_records, keys);
5795 addRRSIG(keys, res->d_records, DNSName("."), 300);
5796 return 1;
5797 }
5798 else if (ip == ComboAddress("192.0.2.1:53")) {
5799 if (domain == DNSName("com.")) {
5800 setLWResult(res, 0, true, false, true);
5801 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5802 addRRSIG(keys, res->d_records, domain, 300);
5803 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5804 addRRSIG(keys, res->d_records, domain, 300);
5805 }
5806 else {
5807 setLWResult(res, 0, false, false, true);
5808 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5809 /* no DS */
5810 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5811 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5812 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5813 }
5814 return 1;
5815 }
5816 else if (ip == ComboAddress("192.0.2.2:53")) {
5817 if (type == QType::NS) {
5818 if (domain == DNSName("powerdns.com.")) {
5819 setLWResult(res, RCode::Refused, false, false, true);
5820 }
5821 else {
5822 setLWResult(res, 0, true, false, true);
5823 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5824 addRRSIG(keys, res->d_records, domain, 300);
5825 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5826 addRRSIG(keys, res->d_records, domain, 300);
5827 }
5828 }
5829 else {
5830 setLWResult(res, 0, true, false, true);
5831 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5832 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
5833 }
5834
5835 return 1;
5836 }
5837 }
5838
5839 return 0;
5840 });
5841
5842 vector<DNSRecord> ret;
5843 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5844 BOOST_CHECK_EQUAL(res, RCode::NoError);
5845 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5846 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5847 BOOST_CHECK_EQUAL(queriesCount, 9);
5848
5849 /* again, to test the cache */
5850 ret.clear();
5851 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5852 BOOST_CHECK_EQUAL(res, RCode::NoError);
5853 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5854 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5855 BOOST_CHECK_EQUAL(queriesCount, 9);
5856 }
5857
5858 BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) {
5859 /* check that we don't accept a signer below us */
5860 std::unique_ptr<SyncRes> sr;
5861 initSR(sr, true);
5862
5863 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5864
5865 primeHints();
5866 const DNSName target("www.powerdns.com.");
5867 testkeysset_t keys;
5868
5869 auto luaconfsCopy = g_luaconfs.getCopy();
5870 luaconfsCopy.dsAnchors.clear();
5871 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5872 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5873 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5874 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5875 generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5876
5877 g_luaconfs.setState(luaconfsCopy);
5878
5879 size_t queriesCount = 0;
5880
5881 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) {
5882 queriesCount++;
5883
5884 if (type == QType::DS) {
5885 DNSName auth(domain);
5886 auth.chopOff();
5887
5888 setLWResult(res, 0, true, false, true);
5889 if (domain == target) {
5890 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5891 addRRSIG(keys, res->d_records, target, 300);
5892 }
5893 else {
5894 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5895 addRRSIG(keys, res->d_records, auth, 300);
5896 }
5897 return 1;
5898 }
5899 else if (type == QType::DNSKEY) {
5900 setLWResult(res, 0, true, false, true);
5901 addDNSKEY(keys, domain, 300, res->d_records);
5902 if (domain == DNSName("www.powerdns.com.")) {
5903 addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
5904 }
5905 else {
5906 addRRSIG(keys, res->d_records, domain, 300);
5907 }
5908 return 1;
5909 }
5910 else {
5911 if (isRootServer(ip)) {
5912 setLWResult(res, 0, false, false, true);
5913 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5914 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5915 addDS(DNSName("com."), 300, res->d_records, keys);
5916 addRRSIG(keys, res->d_records, DNSName("."), 300);
5917 return 1;
5918 }
5919 else if (ip == ComboAddress("192.0.2.1:53")) {
5920 if (domain == DNSName("com.")) {
5921 setLWResult(res, 0, true, false, true);
5922 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5923 addRRSIG(keys, res->d_records, domain, 300);
5924 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5925 addRRSIG(keys, res->d_records, domain, 300);
5926 }
5927 else {
5928 setLWResult(res, 0, false, false, true);
5929 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5930 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5931 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5932 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5933 }
5934 return 1;
5935 }
5936 else if (ip == ComboAddress("192.0.2.2:53")) {
5937 if (type == QType::NS) {
5938 setLWResult(res, 0, true, false, true);
5939 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5940 addRRSIG(keys, res->d_records, domain, 300);
5941 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5942 addRRSIG(keys, res->d_records, domain, 300);
5943 }
5944 else {
5945 setLWResult(res, 0, true, false, true);
5946 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5947 addRRSIG(keys, res->d_records, domain, 300);
5948 }
5949
5950 return 1;
5951 }
5952 }
5953
5954 return 0;
5955 });
5956
5957 vector<DNSRecord> ret;
5958 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5959 BOOST_CHECK_EQUAL(res, RCode::NoError);
5960 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5961 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5962 BOOST_CHECK_EQUAL(queriesCount, 9);
5963
5964 /* again, to test the cache */
5965 ret.clear();
5966 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5967 BOOST_CHECK_EQUAL(res, RCode::NoError);
5968 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5969 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5970 BOOST_CHECK_EQUAL(queriesCount, 9);
5971 }
5972
5973 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
5974 std::unique_ptr<SyncRes> sr;
5975 initSR(sr, true);
5976
5977 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5978
5979 primeHints();
5980 const DNSName target("www.powerdns.com.");
5981 testkeysset_t keys;
5982
5983 auto luaconfsCopy = g_luaconfs.getCopy();
5984 luaconfsCopy.dsAnchors.clear();
5985 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5986 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5987
5988 g_luaconfs.setState(luaconfsCopy);
5989
5990 size_t queriesCount = 0;
5991 size_t dsQueriesCount = 0;
5992
5993 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) {
5994 queriesCount++;
5995
5996 if (type == QType::DS) {
5997 DNSName auth(domain);
5998 auth.chopOff();
5999 dsQueriesCount++;
6000
6001 setLWResult(res, 0, true, false, true);
6002 if (domain == DNSName("com.")) {
6003 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6004 }
6005 else {
6006 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6007 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6008 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
6009 }
6010 addRRSIG(keys, res->d_records, auth, 300);
6011 return 1;
6012 }
6013 else if (type == QType::DNSKEY) {
6014 setLWResult(res, 0, true, false, true);
6015 addDNSKEY(keys, domain, 300, res->d_records);
6016 addRRSIG(keys, res->d_records, domain, 300);
6017 return 1;
6018 }
6019 else {
6020 if (isRootServer(ip)) {
6021 setLWResult(res, 0, false, false, true);
6022 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6023 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6024 /* No DS on referral, and no denial of the DS either */
6025 return 1;
6026 }
6027 else if (ip == ComboAddress("192.0.2.1:53")) {
6028 if (domain == DNSName("com.")) {
6029 setLWResult(res, 0, true, false, true);
6030 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6031 addRRSIG(keys, res->d_records, domain, 300);
6032 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6033 addRRSIG(keys, res->d_records, domain, 300);
6034 }
6035 else {
6036 setLWResult(res, 0, false, false, true);
6037 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6038 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6039 /* No DS on referral, and no denial of the DS either */
6040 }
6041 return 1;
6042 }
6043 else if (ip == ComboAddress("192.0.2.2:53")) {
6044 setLWResult(res, 0, true, false, true);
6045 if (type == QType::NS) {
6046 if (domain == DNSName("powerdns.com.")) {
6047 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6048 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6049 }
6050 else {
6051 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6052 }
6053 }
6054 else {
6055 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6056 }
6057 return 1;
6058 }
6059 }
6060
6061 return 0;
6062 });
6063
6064 vector<DNSRecord> ret;
6065 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6066 BOOST_CHECK_EQUAL(res, RCode::NoError);
6067 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6068 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6069 BOOST_CHECK_EQUAL(queriesCount, 7);
6070 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6071
6072 /* again, to test the cache */
6073 ret.clear();
6074 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6075 BOOST_CHECK_EQUAL(res, RCode::NoError);
6076 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6077 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6078 BOOST_CHECK_EQUAL(queriesCount, 7);
6079 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6080 }
6081
6082 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
6083 std::unique_ptr<SyncRes> sr;
6084 initSR(sr, true);
6085
6086 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6087
6088 primeHints();
6089 const DNSName target("powerdns.com.");
6090 testkeysset_t keys;
6091
6092 auto luaconfsCopy = g_luaconfs.getCopy();
6093 luaconfsCopy.dsAnchors.clear();
6094 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6095 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6096 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6097
6098 g_luaconfs.setState(luaconfsCopy);
6099
6100 size_t queriesCount = 0;
6101
6102 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) {
6103 queriesCount++;
6104
6105 if (type == QType::DS || type == QType::DNSKEY) {
6106 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6107 }
6108 else {
6109 if (isRootServer(ip)) {
6110 setLWResult(res, 0, false, false, true);
6111 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6112 addDS(DNSName("com."), 300, res->d_records, keys);
6113 addRRSIG(keys, res->d_records, DNSName("."), 300);
6114 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6115 return 1;
6116 }
6117 else if (ip == ComboAddress("192.0.2.1:53")) {
6118 if (domain == DNSName("com.")) {
6119 setLWResult(res, 0, true, false, true);
6120 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6121 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6122 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6123 }
6124 else {
6125 setLWResult(res, 0, false, false, true);
6126 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6127 addDS(domain, 300, res->d_records, keys);
6128 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6129 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6130 }
6131 return 1;
6132 }
6133 else if (ip == ComboAddress("192.0.2.2:53")) {
6134 setLWResult(res, 0, true, false, true);
6135 if (type == QType::NS) {
6136 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6137 addRRSIG(keys, res->d_records, domain, 300);
6138 }
6139 else {
6140 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6141 addRRSIG(keys, res->d_records, domain, 300);
6142 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
6143 /* NO RRSIG for the NSEC record! */
6144 }
6145 return 1;
6146 }
6147 }
6148
6149 return 0;
6150 });
6151
6152 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
6153 vector<DNSRecord> ret;
6154 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6155 BOOST_CHECK_EQUAL(res, RCode::NoError);
6156 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6157 BOOST_CHECK_EQUAL(ret.size(), 3);
6158 BOOST_CHECK_EQUAL(queriesCount, 8);
6159
6160 /* again, to test the cache */
6161 ret.clear();
6162 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6163 BOOST_CHECK_EQUAL(res, RCode::NoError);
6164 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6165 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6166 BOOST_CHECK_EQUAL(queriesCount, 8);
6167 }
6168
6169 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
6170 std::unique_ptr<SyncRes> sr;
6171 initSR(sr, true);
6172
6173 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6174
6175 primeHints();
6176 const DNSName target("powerdns.com.");
6177 testkeysset_t keys;
6178
6179 auto luaconfsCopy = g_luaconfs.getCopy();
6180 luaconfsCopy.dsAnchors.clear();
6181 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6182 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6183 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6184
6185 g_luaconfs.setState(luaconfsCopy);
6186
6187 size_t queriesCount = 0;
6188
6189 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) {
6190 queriesCount++;
6191
6192 if (type == QType::DS || type == QType::DNSKEY) {
6193 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6194 }
6195 else {
6196 if (isRootServer(ip)) {
6197 setLWResult(res, 0, false, false, true);
6198 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6199 addDS(DNSName("com."), 300, res->d_records, keys);
6200 addRRSIG(keys, res->d_records, DNSName("."), 300);
6201 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6202 return 1;
6203 }
6204 else if (ip == ComboAddress("192.0.2.1:53")) {
6205 if (domain == DNSName("com.")) {
6206 setLWResult(res, 0, true, false, true);
6207 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6208 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6209 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6210 }
6211 else {
6212 setLWResult(res, 0, false, false, true);
6213 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6214 addDS(domain, 300, res->d_records, keys);
6215 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6216 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6217 }
6218 return 1;
6219 }
6220 else if (ip == ComboAddress("192.0.2.2:53")) {
6221 setLWResult(res, 0, true, false, true);
6222 if (type == QType::NS) {
6223 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6224 addRRSIG(keys, res->d_records, domain, 300);
6225 }
6226 else {
6227 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6228 addRRSIG(keys, res->d_records, domain, 300);
6229
6230 /* NO NSEC record! */
6231 }
6232 return 1;
6233 }
6234 }
6235
6236 return 0;
6237 });
6238
6239 /* no NSEC record in a secure zone, should be Bogus! */
6240 vector<DNSRecord> ret;
6241 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6242 BOOST_CHECK_EQUAL(res, RCode::NoError);
6243 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6244 BOOST_CHECK_EQUAL(ret.size(), 2);
6245 BOOST_CHECK_EQUAL(queriesCount, 8);
6246
6247 /* again, to test the cache */
6248 ret.clear();
6249 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6250 BOOST_CHECK_EQUAL(res, RCode::NoError);
6251 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6252 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6253 BOOST_CHECK_EQUAL(queriesCount, 8);
6254 }
6255
6256 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6257 std::unique_ptr<SyncRes> sr;
6258 initSR(sr, true);
6259
6260 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6261
6262 primeHints();
6263 const DNSName target("powerdns.com.");
6264 const ComboAddress targetAddr("192.0.2.42");
6265 testkeysset_t keys;
6266
6267 auto luaconfsCopy = g_luaconfs.getCopy();
6268 luaconfsCopy.dsAnchors.clear();
6269 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6270 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6271
6272 g_luaconfs.setState(luaconfsCopy);
6273
6274 size_t queriesCount = 0;
6275
6276 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) {
6277 queriesCount++;
6278
6279 if (type == QType::DS) {
6280 if (domain == target) {
6281 setLWResult(res, 0, false, false, true);
6282 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6283 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6284 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6285 return 1;
6286 } else {
6287 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6288 }
6289 }
6290 else if (type == QType::DNSKEY) {
6291 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6292 setLWResult(res, 0, true, false, true);
6293 addDNSKEY(keys, domain, 300, res->d_records);
6294 addRRSIG(keys, res->d_records, domain, 300);
6295 return 1;
6296 }
6297 else {
6298 setLWResult(res, 0, false, false, true);
6299 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6300 return 1;
6301 }
6302 }
6303 else {
6304 if (isRootServer(ip)) {
6305 setLWResult(res, 0, false, false, true);
6306 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6307 addDS(DNSName("com."), 300, res->d_records, keys);
6308 addRRSIG(keys, res->d_records, DNSName("."), 300);
6309 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6310 return 1;
6311 }
6312 else if (ip == ComboAddress("192.0.2.1:53")) {
6313 if (domain == DNSName("com.")) {
6314 setLWResult(res, 0, true, false, true);
6315 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6316 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6317 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6318 }
6319 else {
6320 setLWResult(res, 0, false, false, true);
6321 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6322 /* no DS */
6323 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6324 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6325 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6326 }
6327 return 1;
6328 }
6329 else if (ip == ComboAddress("192.0.2.2:53")) {
6330 setLWResult(res, 0, true, false, true);
6331 if (type == QType::NS) {
6332 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6333 }
6334 else {
6335 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6336 }
6337 return 1;
6338 }
6339 }
6340
6341 return 0;
6342 });
6343
6344 vector<DNSRecord> ret;
6345 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6346 BOOST_CHECK_EQUAL(res, RCode::NoError);
6347 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6348 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6349 BOOST_CHECK(ret[0].d_type == QType::A);
6350 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6351 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6352 1 query for A */
6353 BOOST_CHECK_EQUAL(queriesCount, 7);
6354
6355 /* again, to test the cache */
6356 ret.clear();
6357 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6358 BOOST_CHECK_EQUAL(res, RCode::NoError);
6359 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6360 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6361 BOOST_CHECK(ret[0].d_type == QType::A);
6362 BOOST_CHECK_EQUAL(queriesCount, 7);
6363 }
6364
6365
6366 BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6367 /*
6368 Direct DS query:
6369 - parent is secure, zone is secure: DS should be secure
6370 */
6371 std::unique_ptr<SyncRes> sr;
6372 initSR(sr, true);
6373
6374 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6375
6376 primeHints();
6377 const DNSName target("powerdns.com.");
6378 testkeysset_t keys;
6379
6380 auto luaconfsCopy = g_luaconfs.getCopy();
6381 luaconfsCopy.dsAnchors.clear();
6382 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6383 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6384 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6385
6386 g_luaconfs.setState(luaconfsCopy);
6387
6388 size_t queriesCount = 0;
6389
6390 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) {
6391 queriesCount++;
6392
6393 if (type == QType::DS || type == QType::DNSKEY) {
6394 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6395 }
6396 else {
6397 if (isRootServer(ip)) {
6398 setLWResult(res, 0, false, false, true);
6399 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6400 addDS(DNSName("com."), 300, res->d_records, keys);
6401 addRRSIG(keys, res->d_records, DNSName("."), 300);
6402 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6403 return 1;
6404 }
6405 }
6406
6407 return 0;
6408 });
6409
6410 vector<DNSRecord> ret;
6411 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6412 BOOST_CHECK_EQUAL(res, RCode::NoError);
6413 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6414 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6415 for (const auto& record : ret) {
6416 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6417 }
6418 BOOST_CHECK_EQUAL(queriesCount, 4);
6419
6420 /* again, to test the cache */
6421 ret.clear();
6422 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6423 BOOST_CHECK_EQUAL(res, RCode::NoError);
6424 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6425 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6426 for (const auto& record : ret) {
6427 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6428 }
6429 BOOST_CHECK_EQUAL(queriesCount, 4);
6430 }
6431
6432 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6433 /*
6434 Direct DS query:
6435 - parent is secure, zone is insecure: DS denial should be secure
6436 */
6437 std::unique_ptr<SyncRes> sr;
6438 initSR(sr, true);
6439
6440 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6441
6442 primeHints();
6443 const DNSName target("powerdns.com.");
6444 testkeysset_t keys;
6445
6446 auto luaconfsCopy = g_luaconfs.getCopy();
6447 luaconfsCopy.dsAnchors.clear();
6448 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6449 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6450
6451 g_luaconfs.setState(luaconfsCopy);
6452
6453 size_t queriesCount = 0;
6454
6455 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) {
6456 queriesCount++;
6457
6458 if (type == QType::DS || type == QType::DNSKEY) {
6459 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6460 }
6461 else {
6462 if (isRootServer(ip)) {
6463 setLWResult(res, 0, false, false, true);
6464 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6465 addDS(DNSName("com."), 300, res->d_records, keys);
6466 addRRSIG(keys, res->d_records, DNSName("."), 300);
6467 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6468 return 1;
6469 }
6470 }
6471
6472 return 0;
6473 });
6474
6475 vector<DNSRecord> ret;
6476 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6477 BOOST_CHECK_EQUAL(res, RCode::NoError);
6478 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6479 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6480 for (const auto& record : ret) {
6481 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6482 }
6483 BOOST_CHECK_EQUAL(queriesCount, 4);
6484
6485 /* again, to test the cache */
6486 ret.clear();
6487 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6488 BOOST_CHECK_EQUAL(res, RCode::NoError);
6489 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6490 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6491 for (const auto& record : ret) {
6492 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6493 }
6494 BOOST_CHECK_EQUAL(queriesCount, 4);
6495 }
6496
6497 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6498 std::unique_ptr<SyncRes> sr;
6499 initSR(sr, true);
6500
6501 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6502
6503 primeHints();
6504 const DNSName target("www.sub.powerdns.com.");
6505 const ComboAddress targetAddr("192.0.2.42");
6506 testkeysset_t keys;
6507
6508 auto luaconfsCopy = g_luaconfs.getCopy();
6509 luaconfsCopy.dsAnchors.clear();
6510 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6511 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6512 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6513
6514 g_luaconfs.setState(luaconfsCopy);
6515
6516 size_t queriesCount = 0;
6517
6518 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) {
6519 queriesCount++;
6520
6521 if (type == QType::DS) {
6522 if (domain == DNSName("sub.powerdns.com.")) {
6523 setLWResult(res, 0, false, false, true);
6524 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6525 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6526 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6527 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6528 return 1;
6529 }
6530 else if (domain == DNSName("www.sub.powerdns.com.")) {
6531 setLWResult(res, 0, false, false, true);
6532 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);
6533 return 1;
6534 }
6535 else {
6536 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6537 }
6538 }
6539 else if (type == QType::DNSKEY) {
6540 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6541 setLWResult(res, 0, true, false, true);
6542 addDNSKEY(keys, domain, 300, res->d_records);
6543 addRRSIG(keys, res->d_records, domain, 300);
6544 return 1;
6545 }
6546 else {
6547 setLWResult(res, 0, false, false, true);
6548 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6549 return 1;
6550 }
6551 }
6552 else {
6553 if (isRootServer(ip)) {
6554 setLWResult(res, 0, false, false, true);
6555 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6556 addDS(DNSName("com."), 300, res->d_records, keys);
6557 addRRSIG(keys, res->d_records, DNSName("."), 300);
6558 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6559 return 1;
6560 }
6561 else if (ip == ComboAddress("192.0.2.1:53")) {
6562 if (domain == DNSName("com.")) {
6563 setLWResult(res, 0, true, false, true);
6564 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6565 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6566 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6567 }
6568 else {
6569 setLWResult(res, 0, false, false, true);
6570 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6571 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6572 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6573 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6574 }
6575 return 1;
6576 }
6577 else if (ip == ComboAddress("192.0.2.2:53")) {
6578 setLWResult(res, 0, true, false, true);
6579 if (type == QType::NS) {
6580 if (domain == DNSName("www.sub.powerdns.com.")) {
6581 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);
6582 }
6583 else if (domain == DNSName("sub.powerdns.com.")) {
6584 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6585 }
6586 else if (domain == DNSName("powerdns.com.")) {
6587 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6588 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6589 }
6590 } else {
6591 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6592 }
6593 return 1;
6594 }
6595 }
6596
6597 return 0;
6598 });
6599
6600 vector<DNSRecord> ret;
6601 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6602 BOOST_CHECK_EQUAL(res, RCode::NoError);
6603 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6604 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6605 BOOST_CHECK(ret[0].d_type == QType::A);
6606 BOOST_CHECK_EQUAL(queriesCount, 9);
6607
6608 /* again, to test the cache */
6609 ret.clear();
6610 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6611 BOOST_CHECK_EQUAL(res, RCode::NoError);
6612 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6613 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6614 BOOST_CHECK(ret[0].d_type == QType::A);
6615 BOOST_CHECK_EQUAL(queriesCount, 9);
6616 }
6617
6618 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6619 std::unique_ptr<SyncRes> sr;
6620 initSR(sr, true);
6621
6622 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6623
6624 primeHints();
6625 const DNSName target("www.sub.powerdns.com.");
6626 const ComboAddress targetAddr("192.0.2.42");
6627 testkeysset_t keys;
6628
6629 auto luaconfsCopy = g_luaconfs.getCopy();
6630 luaconfsCopy.dsAnchors.clear();
6631 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6632 /* No key material for .com */
6633 /* But TA for sub.powerdns.com. */
6634 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6635 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6636 g_luaconfs.setState(luaconfsCopy);
6637
6638 size_t queriesCount = 0;
6639
6640 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) {
6641 queriesCount++;
6642
6643 if (type == QType::DS) {
6644 if (domain == DNSName("www.sub.powerdns.com")) {
6645 setLWResult(res, 0, false, false, true);
6646 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);
6647 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6648 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6649 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6650 }
6651 else {
6652 setLWResult(res, 0, false, false, true);
6653
6654 if (domain == DNSName("com.")) {
6655 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6656 /* no DS */
6657 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6658 addRRSIG(keys, res->d_records, DNSName("."), 300);
6659 }
6660 else {
6661 setLWResult(res, 0, false, false, true);
6662 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6663 }
6664 }
6665 return 1;
6666 }
6667 else if (type == QType::DNSKEY) {
6668 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
6669 setLWResult(res, 0, true, false, true);
6670 addDNSKEY(keys, domain, 300, res->d_records);
6671 addRRSIG(keys, res->d_records, domain, 300);
6672 return 1;
6673 }
6674 }
6675 else {
6676 if (isRootServer(ip)) {
6677 setLWResult(res, 0, false, false, true);
6678 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6679 /* no DS */
6680 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6681 addRRSIG(keys, res->d_records, DNSName("."), 300);
6682 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6683 return 1;
6684 }
6685 else if (ip == ComboAddress("192.0.2.1:53")) {
6686 if (domain == DNSName("com.")) {
6687 setLWResult(res, 0, true, false, true);
6688 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6689 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6690 }
6691 else if (domain.isPartOf(DNSName("powerdns.com."))) {
6692 setLWResult(res, 0, false, false, true);
6693 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6694 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6695 }
6696 return 1;
6697 }
6698 else if (ip == ComboAddress("192.0.2.2:53")) {
6699 setLWResult(res, 0, true, false, true);
6700 if (type == QType::NS) {
6701 if (domain == DNSName("www.sub.powerdns.com.")) {
6702 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);
6703 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6704 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6705 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6706 }
6707 else if (domain == DNSName("sub.powerdns.com.")) {
6708 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6709 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6710 }
6711 else if (domain == DNSName("powerdns.com.")) {
6712 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6713 }
6714 }
6715 else if (domain == DNSName("www.sub.powerdns.com.")) {
6716 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6717 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6718 }
6719 return 1;
6720 }
6721 }
6722
6723 return 0;
6724 });
6725
6726 vector<DNSRecord> ret;
6727 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6728 BOOST_CHECK_EQUAL(res, RCode::NoError);
6729 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6730 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6731 BOOST_CHECK(ret[0].d_type == QType::A);
6732 BOOST_CHECK_EQUAL(queriesCount, 7);
6733
6734 /* again, to test the cache */
6735 ret.clear();
6736 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6737 BOOST_CHECK_EQUAL(res, RCode::NoError);
6738 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6739 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6740 BOOST_CHECK(ret[0].d_type == QType::A);
6741 BOOST_CHECK_EQUAL(queriesCount, 7);
6742 }
6743
6744 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
6745 std::unique_ptr<SyncRes> sr;
6746 initSR(sr, true);
6747
6748 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6749
6750 primeHints();
6751 const DNSName target("powerdns.com.");
6752 testkeysset_t keys;
6753
6754 auto luaconfsCopy = g_luaconfs.getCopy();
6755 luaconfsCopy.dsAnchors.clear();
6756 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6757 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6758
6759 g_luaconfs.setState(luaconfsCopy);
6760
6761 size_t queriesCount = 0;
6762
6763 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) {
6764 queriesCount++;
6765
6766 if (type == QType::DS) {
6767 if (domain == target) {
6768 setLWResult(res, 0, false, false, true);
6769 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6770 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6771 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6772 return 1;
6773 }
6774 else {
6775 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6776 }
6777 }
6778 else if (type == QType::DNSKEY) {
6779 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6780 setLWResult(res, 0, true, false, true);
6781 addDNSKEY(keys, domain, 300, res->d_records);
6782 addRRSIG(keys, res->d_records, domain, 300);
6783 return 1;
6784 }
6785 else {
6786 setLWResult(res, 0, false, false, true);
6787 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6788 return 1;
6789 }
6790 }
6791 else {
6792 if (isRootServer(ip)) {
6793 setLWResult(res, 0, false, false, true);
6794 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6795 addDS(DNSName("com."), 300, res->d_records, keys);
6796 addRRSIG(keys, res->d_records, DNSName("."), 300);
6797 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6798 return 1;
6799 }
6800 else if (ip == ComboAddress("192.0.2.1:53")) {
6801 if (domain == DNSName("com.")) {
6802 setLWResult(res, 0, true, false, true);
6803 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6804 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6805 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6806 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6807 }
6808 else {
6809 setLWResult(res, 0, false, false, true);
6810 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6811 /* no DS */
6812 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6813 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6814 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6815 }
6816 return 1;
6817 }
6818 else if (ip == ComboAddress("192.0.2.2:53")) {
6819 if (type == QType::NS) {
6820 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6821 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6822 }
6823 else {
6824 setLWResult(res, 0, true, false, true);
6825 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6826 }
6827 return 1;
6828 }
6829 }
6830
6831 return 0;
6832 });
6833
6834 vector<DNSRecord> ret;
6835 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6836 BOOST_CHECK_EQUAL(res, RCode::NoError);
6837 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6838 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6839 /* 4 NS (com from root, com from com, powerdns.com from com,
6840 powerdns.com from powerdns.com)
6841 2 DNSKEY (. and com., none for powerdns.com because no DS)
6842 1 query for A
6843 */
6844 BOOST_CHECK_EQUAL(queriesCount, 7);
6845
6846 /* again, to test the cache */
6847 ret.clear();
6848 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6849 BOOST_CHECK_EQUAL(res, RCode::NoError);
6850 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6851 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6852 BOOST_CHECK_EQUAL(queriesCount, 7);
6853 }
6854
6855 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
6856 std::unique_ptr<SyncRes> sr;
6857 initSR(sr, true);
6858
6859 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6860
6861 primeHints();
6862 const DNSName target("powerdns.com.");
6863 const DNSName targetCName("power-dns.com.");
6864 const ComboAddress targetCNameAddr("192.0.2.42");
6865 testkeysset_t keys;
6866
6867 auto luaconfsCopy = g_luaconfs.getCopy();
6868 luaconfsCopy.dsAnchors.clear();
6869 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6870 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6871 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6872 g_luaconfs.setState(luaconfsCopy);
6873
6874 size_t queriesCount = 0;
6875
6876 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) {
6877 queriesCount++;
6878
6879 if (type == QType::DS) {
6880 if (domain == targetCName) {
6881 setLWResult(res, 0, false, false, true);
6882 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6883 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6884 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6885 return 1;
6886 }
6887 else {
6888 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6889 }
6890 }
6891 else if (type == QType::DNSKEY) {
6892 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6893 setLWResult(res, 0, true, false, true);
6894 addDNSKEY(keys, domain, 300, res->d_records);
6895 addRRSIG(keys, res->d_records, domain, 300);
6896 return 1;
6897 }
6898 else {
6899 setLWResult(res, 0, false, false, true);
6900 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6901 return 1;
6902 }
6903 }
6904 else {
6905 if (isRootServer(ip)) {
6906 setLWResult(res, 0, false, false, true);
6907 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6908 addDS(DNSName("com."), 300, res->d_records, keys);
6909 addRRSIG(keys, res->d_records, DNSName("."), 300);
6910 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6911 return 1;
6912 }
6913 else if (ip == ComboAddress("192.0.2.1:53")) {
6914 setLWResult(res, 0, false, false, true);
6915 if (domain == DNSName("com.")) {
6916 setLWResult(res, 0, true, false, true);
6917 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6918 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6919 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6920 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6921 }
6922 else {
6923 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6924 if (domain == DNSName("powerdns.com.")) {
6925 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6926 }
6927 else if (domain == targetCName) {
6928 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6929 }
6930 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6931 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6932 }
6933
6934 return 1;
6935 }
6936 else if (ip == ComboAddress("192.0.2.2:53")) {
6937 setLWResult(res, 0, true, false, true);
6938
6939 if (type == QType::NS) {
6940 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6941 if (domain == DNSName("powerdns.com.")) {
6942 addRRSIG(keys, res->d_records, domain, 300);
6943 }
6944 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6945 if (domain == DNSName("powerdns.com.")) {
6946 addRRSIG(keys, res->d_records, domain, 300);
6947 }
6948 }
6949 else {
6950 if (domain == DNSName("powerdns.com.")) {
6951 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6952 addRRSIG(keys, res->d_records, domain, 300);
6953 }
6954 else if (domain == targetCName) {
6955 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6956 }
6957 }
6958
6959 return 1;
6960 }
6961 }
6962
6963 return 0;
6964 });
6965
6966 vector<DNSRecord> ret;
6967 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6968 BOOST_CHECK_EQUAL(res, RCode::NoError);
6969 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6970 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6971 BOOST_CHECK_EQUAL(queriesCount, 11);
6972
6973 /* again, to test the cache */
6974 ret.clear();
6975 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6976 BOOST_CHECK_EQUAL(res, RCode::NoError);
6977 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6978 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6979 BOOST_CHECK_EQUAL(queriesCount, 11);
6980 }
6981
6982 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
6983 std::unique_ptr<SyncRes> sr;
6984 initSR(sr, true);
6985
6986 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6987
6988 primeHints();
6989 const DNSName target("power-dns.com.");
6990 const DNSName targetCName("powerdns.com.");
6991 const ComboAddress targetCNameAddr("192.0.2.42");
6992 testkeysset_t keys;
6993
6994 auto luaconfsCopy = g_luaconfs.getCopy();
6995 luaconfsCopy.dsAnchors.clear();
6996 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6997 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6998 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6999 g_luaconfs.setState(luaconfsCopy);
7000
7001 size_t queriesCount = 0;
7002
7003 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) {
7004 queriesCount++;
7005
7006 if (type == QType::DS) {
7007 if (domain == DNSName("power-dns.com.")) {
7008 setLWResult(res, 0, false, false, true);
7009 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7010 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7011 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7012 return 1;
7013 }
7014 else {
7015 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7016 }
7017 }
7018 else if (type == QType::DNSKEY) {
7019 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7020 setLWResult(res, 0, true, false, true);
7021 addDNSKEY(keys, domain, 300, res->d_records);
7022 addRRSIG(keys, res->d_records, domain, 300);
7023 return 1;
7024 }
7025 else {
7026 setLWResult(res, 0, false, false, true);
7027 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7028 return 1;
7029 }
7030 }
7031 else {
7032 if (isRootServer(ip)) {
7033 setLWResult(res, 0, false, false, true);
7034 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7035 addDS(DNSName("com."), 300, res->d_records, keys);
7036 addRRSIG(keys, res->d_records, DNSName("."), 300);
7037 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7038 return 1;
7039 }
7040 else if (ip == ComboAddress("192.0.2.1:53")) {
7041 if (domain == DNSName("com.")) {
7042 setLWResult(res, 0, true, false, true);
7043 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7044 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7045 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7046 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7047 }
7048 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7049 setLWResult(res, 0, false, false, true);
7050 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7051 if (domain == targetCName) {
7052 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7053 }
7054 else if (domain == target) {
7055 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7056 }
7057 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7058 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7059 }
7060 return 1;
7061 }
7062 else if (ip == ComboAddress("192.0.2.2:53")) {
7063 setLWResult(res, 0, true, false, true);
7064 if (type == QType::NS) {
7065 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7066 if (domain == DNSName("powerdns.com.")) {
7067 addRRSIG(keys, res->d_records, domain, 300);
7068 }
7069 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7070 if (domain == DNSName("powerdns.com.")) {
7071 addRRSIG(keys, res->d_records, domain, 300);
7072 }
7073 }
7074 else {
7075 if (domain == target) {
7076 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7077 }
7078 else if (domain == targetCName) {
7079 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7080 addRRSIG(keys, res->d_records, domain, 300);
7081 }
7082 }
7083 return 1;
7084 }
7085 }
7086
7087 return 0;
7088 });
7089
7090 vector<DNSRecord> ret;
7091 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7092 BOOST_CHECK_EQUAL(res, RCode::NoError);
7093 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7094 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7095 BOOST_CHECK_EQUAL(queriesCount, 11);
7096
7097 /* again, to test the cache */
7098 ret.clear();
7099 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7100 BOOST_CHECK_EQUAL(res, RCode::NoError);
7101 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7102 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7103 BOOST_CHECK_EQUAL(queriesCount, 11);
7104 }
7105
7106 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
7107 std::unique_ptr<SyncRes> sr;
7108 initSR(sr, true);
7109
7110 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7111
7112 primeHints();
7113 const DNSName target("power-dns.com.");
7114 const DNSName targetCName("powerdns.com.");
7115 const ComboAddress targetCNameAddr("192.0.2.42");
7116 testkeysset_t keys;
7117
7118 auto luaconfsCopy = g_luaconfs.getCopy();
7119 luaconfsCopy.dsAnchors.clear();
7120 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7121 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7122 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7123 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7124 g_luaconfs.setState(luaconfsCopy);
7125
7126 size_t queriesCount = 0;
7127
7128 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) {
7129 queriesCount++;
7130
7131 if (type == QType::DS || type == QType::DNSKEY) {
7132 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7133 }
7134 else {
7135 if (isRootServer(ip)) {
7136 setLWResult(res, 0, false, false, true);
7137 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7138 addDS(DNSName("com."), 300, res->d_records, keys);
7139 addRRSIG(keys, res->d_records, DNSName("."), 300);
7140 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7141 return 1;
7142 }
7143 else if (ip == ComboAddress("192.0.2.1:53")) {
7144 if (domain == DNSName("com.")) {
7145 setLWResult(res, 0, true, false, true);
7146 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7147 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7148 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7149 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7150 }
7151 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7152 setLWResult(res, 0, false, false, true);
7153 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7154 addDS(DNSName(domain), 300, res->d_records, keys);
7155 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7156 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7157 }
7158 return 1;
7159 }
7160 else if (ip == ComboAddress("192.0.2.2:53")) {
7161 setLWResult(res, 0, true, false, true);
7162 if (type == QType::NS) {
7163 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7164 addRRSIG(keys, res->d_records, domain, 300);
7165 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7166 addRRSIG(keys, res->d_records, domain, 300);
7167 }
7168 else {
7169 if (domain == target) {
7170 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7171 /* No RRSIG, leading to bogus */
7172 }
7173 else if (domain == targetCName) {
7174 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7175 addRRSIG(keys, res->d_records, domain, 300);
7176 }
7177 }
7178 return 1;
7179 }
7180 }
7181
7182 return 0;
7183 });
7184
7185 vector<DNSRecord> ret;
7186 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7187 BOOST_CHECK_EQUAL(res, RCode::NoError);
7188 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7189 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7190 BOOST_CHECK_EQUAL(queriesCount, 11);
7191
7192 /* again, to test the cache */
7193 ret.clear();
7194 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7195 BOOST_CHECK_EQUAL(res, RCode::NoError);
7196 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7197 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7198 BOOST_CHECK_EQUAL(queriesCount, 11);
7199 }
7200
7201 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7202 std::unique_ptr<SyncRes> sr;
7203 initSR(sr, true);
7204
7205 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7206
7207 primeHints();
7208 const DNSName target("power-dns.com.");
7209 const DNSName targetCName("powerdns.com.");
7210 const ComboAddress targetCNameAddr("192.0.2.42");
7211 testkeysset_t keys;
7212
7213 auto luaconfsCopy = g_luaconfs.getCopy();
7214 luaconfsCopy.dsAnchors.clear();
7215 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7216 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7217 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7218 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7219 g_luaconfs.setState(luaconfsCopy);
7220
7221 size_t queriesCount = 0;
7222
7223 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) {
7224 queriesCount++;
7225
7226 if (type == QType::DS || type == QType::DNSKEY) {
7227 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7228 }
7229 else {
7230 if (isRootServer(ip)) {
7231 setLWResult(res, 0, false, false, true);
7232 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7233 addDS(DNSName("com."), 300, res->d_records, keys);
7234 addRRSIG(keys, res->d_records, DNSName("."), 300);
7235 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7236 return 1;
7237 }
7238 else if (ip == ComboAddress("192.0.2.1:53")) {
7239 if (domain == DNSName("com.")) {
7240 setLWResult(res, 0, true, false, true);
7241 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7242 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7243 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7244 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7245 }
7246 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7247 setLWResult(res, 0, false, false, true);
7248 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7249 addDS(DNSName(domain), 300, res->d_records, keys);
7250 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7251 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7252 }
7253 return 1;
7254 }
7255 else if (ip == ComboAddress("192.0.2.2:53")) {
7256 setLWResult(res, 0, true, false, true);
7257 if (type == QType::NS) {
7258 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7259 addRRSIG(keys, res->d_records, domain, 300);
7260 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7261 addRRSIG(keys, res->d_records, domain, 300);
7262 }
7263 else {
7264 if (domain == target) {
7265 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7266 addRRSIG(keys, res->d_records, domain, 300);
7267 }
7268 else if (domain == targetCName) {
7269 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7270 /* No RRSIG, leading to bogus */
7271 }
7272 }
7273 return 1;
7274 }
7275 }
7276
7277 return 0;
7278 });
7279
7280 vector<DNSRecord> ret;
7281 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7282 BOOST_CHECK_EQUAL(res, RCode::NoError);
7283 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7284 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7285 BOOST_CHECK_EQUAL(queriesCount, 11);
7286
7287 /* again, to test the cache */
7288 ret.clear();
7289 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7290 BOOST_CHECK_EQUAL(res, RCode::NoError);
7291 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7292 BOOST_REQUIRE_EQUAL(ret.size(), 3);
7293 BOOST_CHECK_EQUAL(queriesCount, 11);
7294 }
7295
7296 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
7297 std::unique_ptr<SyncRes> sr;
7298 initSR(sr, true);
7299
7300 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7301
7302 primeHints();
7303 const DNSName target("power-dns.com.");
7304 const DNSName targetCName("powerdns.com.");
7305 const ComboAddress targetCNameAddr("192.0.2.42");
7306 testkeysset_t keys;
7307
7308 auto luaconfsCopy = g_luaconfs.getCopy();
7309 luaconfsCopy.dsAnchors.clear();
7310 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7311 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7312 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7313 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7314 g_luaconfs.setState(luaconfsCopy);
7315
7316 size_t queriesCount = 0;
7317
7318 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) {
7319 queriesCount++;
7320
7321 if (type == QType::DS || type == QType::DNSKEY) {
7322 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7323 }
7324 else {
7325 if (isRootServer(ip)) {
7326 setLWResult(res, 0, false, false, true);
7327 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7328 addDS(DNSName("com."), 300, res->d_records, keys);
7329 addRRSIG(keys, res->d_records, DNSName("."), 300);
7330 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7331 return 1;
7332 }
7333 else if (ip == ComboAddress("192.0.2.1:53")) {
7334 if (domain == DNSName("com.")) {
7335 setLWResult(res, 0, true, false, true);
7336 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7337 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7338 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7339 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7340 }
7341 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7342 setLWResult(res, 0, false, false, true);
7343 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7344 addDS(DNSName(domain), 300, res->d_records, keys);
7345 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7346 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7347 }
7348 return 1;
7349 }
7350 else if (ip == ComboAddress("192.0.2.2:53")) {
7351 setLWResult(res, 0, true, false, true);
7352 if (type == QType::NS) {
7353 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7354 addRRSIG(keys, res->d_records, domain, 300);
7355 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7356 addRRSIG(keys, res->d_records, domain, 300);
7357 }
7358 else {
7359 if (domain == target) {
7360 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7361 addRRSIG(keys, res->d_records, domain, 300);
7362 }
7363 else if (domain == targetCName) {
7364 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7365 addRRSIG(keys, res->d_records, domain, 300);
7366 }
7367 }
7368 return 1;
7369 }
7370 }
7371
7372 return 0;
7373 });
7374
7375 vector<DNSRecord> ret;
7376 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7377 BOOST_CHECK_EQUAL(res, RCode::NoError);
7378 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7379 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7380 BOOST_CHECK_EQUAL(queriesCount, 12);
7381
7382 /* again, to test the cache */
7383 ret.clear();
7384 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7385 BOOST_CHECK_EQUAL(res, RCode::NoError);
7386 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7387 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7388 BOOST_CHECK_EQUAL(queriesCount, 12);
7389 }
7390
7391 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7392 std::unique_ptr<SyncRes> sr;
7393 initSR(sr, true);
7394
7395 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7396
7397 primeHints();
7398 const DNSName target("powerdns.com.");
7399 const DNSName targetCName("power-dns.com.");
7400 const ComboAddress targetCNameAddr("192.0.2.42");
7401 testkeysset_t keys;
7402
7403 auto luaconfsCopy = g_luaconfs.getCopy();
7404 luaconfsCopy.dsAnchors.clear();
7405 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7406 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7407 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7408 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7409 g_luaconfs.setState(luaconfsCopy);
7410
7411 size_t queriesCount = 0;
7412
7413 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) {
7414 queriesCount++;
7415
7416 if (type == QType::DS) {
7417 if (domain == DNSName("power-dns.com.")) {
7418 setLWResult(res, 0, false, false, true);
7419 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7420 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7421 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7422 return 1;
7423 }
7424 else {
7425 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7426 }
7427 }
7428 else if (type == QType::DNSKEY) {
7429 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7430 setLWResult(res, 0, true, false, true);
7431 addDNSKEY(keys, domain, 300, res->d_records);
7432 addRRSIG(keys, res->d_records, domain, 300);
7433 return 1;
7434 }
7435 else {
7436 setLWResult(res, 0, false, false, true);
7437 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7438 return 1;
7439 }
7440 }
7441 else {
7442 if (isRootServer(ip)) {
7443 setLWResult(res, 0, false, false, true);
7444 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7445 addDS(DNSName("com."), 300, res->d_records, keys);
7446 addRRSIG(keys, res->d_records, DNSName("."), 300);
7447 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7448 return 1;
7449 }
7450 else if (ip == ComboAddress("192.0.2.1:53")) {
7451 if (domain == DNSName("com.")) {
7452 setLWResult(res, 0, true, false, true);
7453 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7454 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7455 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7456 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7457 }
7458 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7459 setLWResult(res, 0, false, false, true);
7460 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7461 if (domain == DNSName("powerdns.com.")) {
7462 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7463 }
7464 else if (domain == targetCName) {
7465 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7466 }
7467 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7468 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7469 }
7470 return 1;
7471 }
7472 else if (ip == ComboAddress("192.0.2.2:53")) {
7473 setLWResult(res, 0, true, false, true);
7474 if (type == QType::NS) {
7475 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7476 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7477 }
7478 else {
7479 if (domain == DNSName("powerdns.com.")) {
7480 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7481 /* No RRSIG -> Bogus */
7482 }
7483 else if (domain == targetCName) {
7484 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7485 }
7486 }
7487 return 1;
7488 }
7489 }
7490
7491 return 0;
7492 });
7493
7494 vector<DNSRecord> ret;
7495 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7496 BOOST_CHECK_EQUAL(res, RCode::NoError);
7497 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7498 /* no RRSIG to show */
7499 BOOST_CHECK_EQUAL(ret.size(), 2);
7500 BOOST_CHECK_EQUAL(queriesCount, 10);
7501
7502 /* again, to test the cache */
7503 ret.clear();
7504 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7505 BOOST_CHECK_EQUAL(res, RCode::NoError);
7506 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7507 BOOST_CHECK_EQUAL(ret.size(), 2);
7508 BOOST_CHECK_EQUAL(queriesCount, 10);
7509 }
7510
7511 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7512 std::unique_ptr<SyncRes> sr;
7513 initSR(sr, true);
7514
7515 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7516
7517 primeHints();
7518 const DNSName target("powerdns.com.");
7519 const ComboAddress targetAddr("192.0.2.42");
7520 testkeysset_t keys;
7521
7522 auto luaconfsCopy = g_luaconfs.getCopy();
7523 luaconfsCopy.dsAnchors.clear();
7524 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7525 /* No key material for .com */
7526 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7527 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7528 g_luaconfs.setState(luaconfsCopy);
7529
7530 size_t queriesCount = 0;
7531
7532 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) {
7533 queriesCount++;
7534
7535 if (type == QType::DNSKEY) {
7536 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7537 setLWResult(res, 0, true, false, true);
7538 addDNSKEY(keys, domain, 300, res->d_records);
7539 addRRSIG(keys, res->d_records, domain, 300);
7540 return 1;
7541 }
7542 else if (domain == DNSName("com.")) {
7543 setLWResult(res, 0, false, false, true);
7544 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7545 return 1;
7546 }
7547 }
7548 else {
7549 if (isRootServer(ip)) {
7550 setLWResult(res, 0, false, false, true);
7551 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7552 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7553 addRRSIG(keys, res->d_records, DNSName("."), 300);
7554 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7555 return 1;
7556 }
7557 else if (ip == ComboAddress("192.0.2.1:53")) {
7558 if (target == domain) {
7559 setLWResult(res, 0, false, false, true);
7560 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7561 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7562 }
7563 else if (domain == DNSName("com.")) {
7564 setLWResult(res, 0, true, false, true);
7565 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7566 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7567 }
7568 return 1;
7569 }
7570 else if (ip == ComboAddress("192.0.2.2:53")) {
7571 setLWResult(res, 0, true, false, true);
7572 if (type == QType::NS) {
7573 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7574 }
7575 else {
7576 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7577 }
7578 addRRSIG(keys, res->d_records, domain, 300);
7579 return 1;
7580 }
7581 }
7582
7583 return 0;
7584 });
7585
7586 vector<DNSRecord> ret;
7587 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7588 BOOST_CHECK_EQUAL(res, RCode::NoError);
7589 /* should be insecure but we have a TA for powerdns.com. */
7590 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7591 /* We got a RRSIG */
7592 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7593 BOOST_CHECK(ret[0].d_type == QType::A);
7594 BOOST_CHECK_EQUAL(queriesCount, 5);
7595
7596 /* again, to test the cache */
7597 ret.clear();
7598 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7599 BOOST_CHECK_EQUAL(res, RCode::NoError);
7600 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7601 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7602 BOOST_CHECK(ret[0].d_type == QType::A);
7603 BOOST_CHECK_EQUAL(queriesCount, 5);
7604 }
7605
7606 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
7607 std::unique_ptr<SyncRes> sr;
7608 initSR(sr, true);
7609
7610 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7611
7612 primeHints();
7613 const DNSName target("powerdns.com.");
7614 const ComboAddress targetAddr("192.0.2.42");
7615 testkeysset_t keys;
7616
7617 auto luaconfsCopy = g_luaconfs.getCopy();
7618 luaconfsCopy.dsAnchors.clear();
7619 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7620 /* No key material for .com */
7621 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7622 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7623 g_luaconfs.setState(luaconfsCopy);
7624
7625 size_t queriesCount = 0;
7626
7627 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) {
7628 queriesCount++;
7629
7630 if (type == QType::DNSKEY) {
7631 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7632 setLWResult(res, 0, true, false, true);
7633 addDNSKEY(keys, domain, 300, res->d_records);
7634 addRRSIG(keys, res->d_records, domain, 300);
7635 return 1;
7636 }
7637 else if (domain == DNSName("com.")) {
7638 setLWResult(res, 0, false, false, true);
7639 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7640 return 1;
7641 }
7642 }
7643 else {
7644 if (target.isPartOf(domain) && isRootServer(ip)) {
7645 setLWResult(res, 0, false, false, true);
7646 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7647 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7648 addRRSIG(keys, res->d_records, DNSName("."), 300);
7649 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7650 return 1;
7651 }
7652 else if (ip == ComboAddress("192.0.2.1:53")) {
7653 if (target == domain) {
7654 setLWResult(res, 0, false, false, true);
7655 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7656 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7657 }
7658 else if (domain == DNSName("com.")) {
7659 setLWResult(res, 0, true, false, true);
7660 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7661 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7662 }
7663 return 1;
7664 }
7665 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
7666 setLWResult(res, 0, true, false, true);
7667 if (type == QType::NS) {
7668 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7669 }
7670 else {
7671 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7672 }
7673 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
7674 return 1;
7675 }
7676 }
7677
7678 return 0;
7679 });
7680
7681 vector<DNSRecord> ret;
7682 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7683 BOOST_CHECK_EQUAL(res, RCode::NoError);
7684 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
7685 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7686 /* No RRSIG */
7687 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7688 BOOST_CHECK(ret[0].d_type == QType::A);
7689 BOOST_CHECK_EQUAL(queriesCount, 4);
7690
7691 /* again, to test the cache */
7692 ret.clear();
7693 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7694 BOOST_CHECK_EQUAL(res, RCode::NoError);
7695 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7696 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7697 BOOST_CHECK(ret[0].d_type == QType::A);
7698 BOOST_CHECK_EQUAL(queriesCount, 4);
7699 }
7700
7701 BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
7702 std::unique_ptr<SyncRes> sr;
7703 initSR(sr, true);
7704
7705 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7706
7707 primeHints();
7708 const DNSName target(".");
7709 testkeysset_t keys;
7710
7711 auto luaconfsCopy = g_luaconfs.getCopy();
7712 luaconfsCopy.dsAnchors.clear();
7713 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7714 /* Add a NTA for "." */
7715 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
7716 g_luaconfs.setState(luaconfsCopy);
7717
7718 size_t queriesCount = 0;
7719
7720 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) {
7721 queriesCount++;
7722
7723 if (domain == target && type == QType::NS) {
7724
7725 setLWResult(res, 0, true, false, true);
7726 char addr[] = "a.root-servers.net.";
7727 for (char idx = 'a'; idx <= 'm'; idx++) {
7728 addr[0] = idx;
7729 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7730 }
7731
7732 addRRSIG(keys, res->d_records, domain, 300);
7733
7734 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7735 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
7736
7737 return 1;
7738 } else if (domain == target && type == QType::DNSKEY) {
7739
7740 setLWResult(res, 0, true, false, true);
7741
7742 /* No DNSKEY */
7743
7744 return 1;
7745 }
7746
7747 return 0;
7748 });
7749
7750 vector<DNSRecord> ret;
7751 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7752 BOOST_CHECK_EQUAL(res, RCode::NoError);
7753 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7754 /* 13 NS + 1 RRSIG */
7755 BOOST_REQUIRE_EQUAL(ret.size(), 14);
7756 BOOST_CHECK_EQUAL(queriesCount, 1);
7757
7758 /* again, to test the cache */
7759 ret.clear();
7760 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7761 BOOST_CHECK_EQUAL(res, RCode::NoError);
7762 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7763 BOOST_REQUIRE_EQUAL(ret.size(), 14);
7764 BOOST_CHECK_EQUAL(queriesCount, 1);
7765 }
7766
7767 BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
7768 std::unique_ptr<SyncRes> sr;
7769 initSR(sr, true);
7770
7771 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7772
7773 primeHints();
7774 const DNSName target(".");
7775 testkeysset_t keys;
7776
7777 /* Remove the root DS */
7778 auto luaconfsCopy = g_luaconfs.getCopy();
7779 luaconfsCopy.dsAnchors.clear();
7780 g_luaconfs.setState(luaconfsCopy);
7781
7782 size_t queriesCount = 0;
7783
7784 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) {
7785 queriesCount++;
7786
7787 if (domain == target && type == QType::NS) {
7788
7789 setLWResult(res, 0, true, false, true);
7790 char addr[] = "a.root-servers.net.";
7791 for (char idx = 'a'; idx <= 'm'; idx++) {
7792 addr[0] = idx;
7793 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7794 }
7795
7796 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7797 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
7798
7799 return 1;
7800 }
7801
7802 return 0;
7803 });
7804
7805 vector<DNSRecord> ret;
7806 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7807 BOOST_CHECK_EQUAL(res, RCode::NoError);
7808 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7809 /* 13 NS + 0 RRSIG */
7810 BOOST_REQUIRE_EQUAL(ret.size(), 13);
7811 BOOST_CHECK_EQUAL(queriesCount, 1);
7812
7813 /* again, to test the cache */
7814 ret.clear();
7815 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7816 BOOST_CHECK_EQUAL(res, RCode::NoError);
7817 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7818 BOOST_REQUIRE_EQUAL(ret.size(), 13);
7819 BOOST_CHECK_EQUAL(queriesCount, 1);
7820 }
7821
7822 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
7823 std::unique_ptr<SyncRes> sr;
7824 initSR(sr, true);
7825
7826 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7827
7828 primeHints();
7829 const DNSName target("powerdns.com.");
7830 testkeysset_t keys;
7831
7832 auto luaconfsCopy = g_luaconfs.getCopy();
7833 luaconfsCopy.dsAnchors.clear();
7834 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7835 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7836 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7837 g_luaconfs.setState(luaconfsCopy);
7838
7839 size_t queriesCount = 0;
7840
7841 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) {
7842 queriesCount++;
7843
7844 if (type == QType::DS || type == QType::DNSKEY) {
7845 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7846 }
7847 else {
7848
7849 setLWResult(res, 0, true, false, true);
7850 return 1;
7851 }
7852
7853 return 0;
7854 });
7855
7856 vector<DNSRecord> ret;
7857 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7858 BOOST_CHECK_EQUAL(res, RCode::NoError);
7859 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7860 BOOST_REQUIRE_EQUAL(ret.size(), 0);
7861 /* com|NS, powerdns.com|NS, powerdns.com|A */
7862 BOOST_CHECK_EQUAL(queriesCount, 3);
7863
7864 /* again, to test the cache */
7865 ret.clear();
7866 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7867 BOOST_CHECK_EQUAL(res, RCode::NoError);
7868 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7869 BOOST_REQUIRE_EQUAL(ret.size(), 0);
7870 /* we don't store empty results */
7871 BOOST_CHECK_EQUAL(queriesCount, 4);
7872 }
7873
7874 BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
7875 init();
7876
7877 testkeysset_t keys;
7878 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7879
7880 vector<DNSRecord> records;
7881
7882 vector<shared_ptr<DNSRecordContent>> recordContents;
7883 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7884
7885 /*
7886 No wrap test case:
7887 a.example.org. -> d.example.org. denies the existence of b.example.org.
7888 */
7889 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7890 recordContents.push_back(records.at(0).d_content);
7891 addRRSIG(keys, records, DNSName("example.org."), 300);
7892 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7893 records.clear();
7894
7895 ContentSigPair pair;
7896 pair.records = recordContents;
7897 pair.signatures = signatureContents;
7898 cspmap_t denialMap;
7899 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
7900
7901 /* add wildcard denial */
7902 recordContents.clear();
7903 signatureContents.clear();
7904 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7905 recordContents.push_back(records.at(0).d_content);
7906 addRRSIG(keys, records, DNSName("example.org."), 300);
7907 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7908 records.clear();
7909
7910 pair.records = recordContents;
7911 pair.signatures = signatureContents;
7912 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
7913
7914 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
7915 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7916
7917 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
7918 /* let's check that d.example.org. is not denied by this proof */
7919 BOOST_CHECK_EQUAL(denialState, NODATA);
7920 }
7921
7922 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
7923 init();
7924
7925 testkeysset_t keys;
7926 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7927
7928 vector<DNSRecord> records;
7929
7930 vector<shared_ptr<DNSRecordContent>> recordContents;
7931 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7932
7933 /*
7934 Wrap case 1 test case:
7935 z.example.org. -> b.example.org. denies the existence of a.example.org.
7936 */
7937 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7938 recordContents.push_back(records.at(0).d_content);
7939 addRRSIG(keys, records, DNSName("example.org."), 300);
7940 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7941 records.clear();
7942
7943 ContentSigPair pair;
7944 pair.records = recordContents;
7945 pair.signatures = signatureContents;
7946 cspmap_t denialMap;
7947 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
7948
7949 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
7950 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7951
7952 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
7953 /* let's check that d.example.org. is not denied by this proof */
7954 BOOST_CHECK_EQUAL(denialState, NODATA);
7955 }
7956
7957 BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
7958 init();
7959
7960 testkeysset_t keys;
7961 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7962
7963 vector<DNSRecord> records;
7964
7965 vector<shared_ptr<DNSRecordContent>> recordContents;
7966 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7967
7968 /*
7969 Wrap case 2 test case:
7970 y.example.org. -> a.example.org. denies the existence of z.example.org.
7971 */
7972 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7973 recordContents.push_back(records.at(0).d_content);
7974 addRRSIG(keys, records, DNSName("example.org."), 300);
7975 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7976 records.clear();
7977
7978 ContentSigPair pair;
7979 pair.records = recordContents;
7980 pair.signatures = signatureContents;
7981 cspmap_t denialMap;
7982 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
7983
7984 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
7985 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7986
7987 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
7988 /* let's check that d.example.org. is not denied by this proof */
7989 BOOST_CHECK_EQUAL(denialState, NODATA);
7990 }
7991
7992 BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
7993 init();
7994
7995 testkeysset_t keys;
7996 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7997
7998 vector<DNSRecord> records;
7999
8000 vector<shared_ptr<DNSRecordContent>> recordContents;
8001 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8002
8003 /*
8004 Only one NSEC in the whole zone test case:
8005 a.example.org. -> a.example.org. denies the existence of b.example.org.
8006 */
8007 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8008 recordContents.push_back(records.at(0).d_content);
8009 addRRSIG(keys, records, DNSName("example.org."), 300);
8010 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8011 records.clear();
8012
8013 ContentSigPair pair;
8014 pair.records = recordContents;
8015 pair.signatures = signatureContents;
8016 cspmap_t denialMap;
8017 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8018
8019 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
8020 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8021
8022 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
8023 /* let's check that d.example.org. is not denied by this proof */
8024 BOOST_CHECK_EQUAL(denialState, NODATA);
8025 }
8026
8027 BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
8028 init();
8029
8030 testkeysset_t keys;
8031 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8032
8033 vector<DNSRecord> records;
8034
8035 vector<shared_ptr<DNSRecordContent>> recordContents;
8036 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8037
8038 /*
8039 The RRSIG from "." denies the existence of anything between a. and c.,
8040 including b.
8041 */
8042 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
8043 recordContents.push_back(records.at(0).d_content);
8044 addRRSIG(keys, records, DNSName("."), 300);
8045 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8046 records.clear();
8047
8048 ContentSigPair pair;
8049 pair.records = recordContents;
8050 pair.signatures = signatureContents;
8051 cspmap_t denialMap;
8052 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8053
8054 /* add wildcard denial */
8055 recordContents.clear();
8056 signatureContents.clear();
8057 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8058 recordContents.push_back(records.at(0).d_content);
8059 addRRSIG(keys, records, DNSName("."), 300);
8060 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8061 records.clear();
8062
8063 pair.records = recordContents;
8064 pair.signatures = signatureContents;
8065 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
8066
8067 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
8068 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8069 }
8070
8071 BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
8072 init();
8073
8074 testkeysset_t keys;
8075 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8076
8077 vector<DNSRecord> records;
8078
8079 vector<shared_ptr<DNSRecordContent>> recordContents;
8080 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8081
8082 /*
8083 The RRSIG from "." denies the existence of any type except NS at a.
8084 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8085 signer field that is shorter than the owner name of the NSEC RR) it can't
8086 be used to deny anything except the whole name or a DS.
8087 */
8088 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
8089 recordContents.push_back(records.at(0).d_content);
8090 addRRSIG(keys, records, DNSName("."), 300);
8091 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8092 records.clear();
8093
8094 ContentSigPair pair;
8095 pair.records = recordContents;
8096 pair.signatures = signatureContents;
8097 cspmap_t denialMap;
8098 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8099
8100 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8101 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8102 nonexistence of any RRs below that zone cut, which include all RRs at
8103 that (original) owner name other than DS RRs, and all RRs below that
8104 owner name regardless of type.
8105 */
8106
8107 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
8108 /* no data means the qname/qtype is not denied, because an ancestor
8109 delegation NSEC can only deny the DS */
8110 BOOST_CHECK_EQUAL(denialState, NODATA);
8111
8112 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8113 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8114 }
8115
8116 BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
8117 init();
8118
8119 testkeysset_t keys;
8120 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8121
8122 vector<DNSRecord> records;
8123
8124 vector<shared_ptr<DNSRecordContent>> recordContents;
8125 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8126
8127 /*
8128 * RFC 5155 section 8.9:
8129 * If there is an NSEC3 RR present in the response that matches the
8130 * delegation name, then the validator MUST ensure that the NS bit is
8131 * set and that the DS bit is not set in the Type Bit Maps field of the
8132 * NSEC3 RR.
8133 */
8134 /*
8135 The RRSIG from "." denies the existence of any type at a.
8136 NS should be set if it was proving an insecure delegation, let's check that
8137 we correctly detect that it's not.
8138 */
8139 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
8140 recordContents.push_back(records.at(0).d_content);
8141 addRRSIG(keys, records, DNSName("."), 300);
8142 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8143 records.clear();
8144
8145 ContentSigPair pair;
8146 pair.records = recordContents;
8147 pair.signatures = signatureContents;
8148 cspmap_t denialMap;
8149 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8150
8151 /* Insecure because the NS is not set, so while it does
8152 denies the DS, it can't prove an insecure delegation */
8153 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8154 BOOST_CHECK_EQUAL(denialState, NODATA);
8155 }
8156
8157 BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
8158 init();
8159
8160 testkeysset_t keys;
8161 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8162
8163 vector<DNSRecord> records;
8164
8165 vector<shared_ptr<DNSRecordContent>> recordContents;
8166 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8167
8168 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
8169 recordContents.push_back(records.at(0).d_content);
8170 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8171 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8172 records.clear();
8173
8174 ContentSigPair pair;
8175 pair.records = recordContents;
8176 pair.signatures = signatureContents;
8177 cspmap_t denialMap;
8178 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8179
8180 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8181 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
8182 BOOST_CHECK_EQUAL(denialState, NODATA);
8183 }
8184
8185 BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
8186 init();
8187
8188 testkeysset_t keys;
8189 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8190
8191 vector<DNSRecord> records;
8192
8193 vector<shared_ptr<DNSRecordContent>> recordContents;
8194 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8195
8196 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
8197 recordContents.push_back(records.at(0).d_content);
8198 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8199 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8200
8201 ContentSigPair pair;
8202 pair.records = recordContents;
8203 pair.signatures = signatureContents;
8204 cspmap_t denialMap;
8205 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8206 records.clear();
8207
8208 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8209 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8210 BOOST_CHECK_EQUAL(denialState, NODATA);
8211 }
8212
8213 BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8214 init();
8215
8216 testkeysset_t keys;
8217 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8218
8219 vector<DNSRecord> records;
8220
8221 vector<shared_ptr<DNSRecordContent>> recordContents;
8222 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8223
8224 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8225 recordContents.push_back(records.at(0).d_content);
8226 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8227 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8228 records.clear();
8229
8230 ContentSigPair pair;
8231 pair.records = recordContents;
8232 pair.signatures = signatureContents;
8233 cspmap_t denialMap;
8234 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8235
8236 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8237 BOOST_CHECK_EQUAL(denialState, NODATA);
8238 }
8239
8240 BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
8241 init();
8242
8243 testkeysset_t keys;
8244 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8245
8246 vector<DNSRecord> records;
8247
8248 vector<shared_ptr<DNSRecordContent>> recordContents;
8249 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8250
8251 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8252 recordContents.push_back(records.at(0).d_content);
8253 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8254 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8255
8256 ContentSigPair pair;
8257 pair.records = recordContents;
8258 pair.signatures = signatureContents;
8259 cspmap_t denialMap;
8260 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8261
8262 /* Add NSEC3 for the closest encloser */
8263 recordContents.clear();
8264 signatureContents.clear();
8265 records.clear();
8266 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8267 recordContents.push_back(records.at(0).d_content);
8268 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8269 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8270
8271 pair.records = recordContents;
8272 pair.signatures = signatureContents;
8273 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8274
8275 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8276 BOOST_CHECK_EQUAL(denialState, NODATA);
8277 }
8278
8279 BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8280 init();
8281
8282 testkeysset_t keys;
8283 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8284
8285 vector<DNSRecord> records;
8286
8287 vector<shared_ptr<DNSRecordContent>> recordContents;
8288 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8289
8290 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8291 recordContents.push_back(records.at(0).d_content);
8292 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8293 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8294 records.clear();
8295
8296 ContentSigPair pair;
8297 pair.records = recordContents;
8298 pair.signatures = signatureContents;
8299 cspmap_t denialMap;
8300 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8301
8302 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
8303 it is an ENT */
8304 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
8305 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8306
8307 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8308 it could prove a NXDOMAIN if it had an additional wildcard denial */
8309 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8310 BOOST_CHECK_EQUAL(denialState, NODATA);
8311
8312 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8313 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8314 BOOST_CHECK_EQUAL(denialState, NODATA);
8315
8316 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8317 recordContents.clear();
8318 signatureContents.clear();
8319 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8320 recordContents.push_back(records.at(0).d_content);
8321 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8322 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8323 records.clear();
8324 pair.records = recordContents;
8325 pair.signatures = signatureContents;
8326 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8327
8328 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
8329 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8330 }
8331
8332 BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8333 init();
8334
8335 testkeysset_t keys;
8336 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8337
8338 vector<DNSRecord> records;
8339
8340 vector<shared_ptr<DNSRecordContent>> recordContents;
8341 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8342
8343 /*
8344 The RRSIG from "." denies the existence of any type except NS at a.
8345 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8346 signer field that is shorter than the owner name of the NSEC RR) it can't
8347 be used to deny anything except the whole name or a DS.
8348 */
8349 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
8350 recordContents.push_back(records.at(0).d_content);
8351 addRRSIG(keys, records, DNSName("."), 300);
8352 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8353
8354 ContentSigPair pair;
8355 pair.records = recordContents;
8356 pair.signatures = signatureContents;
8357 cspmap_t denialMap;
8358 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8359 records.clear();
8360
8361 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8362 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8363 nonexistence of any RRs below that zone cut, which include all RRs at
8364 that (original) owner name other than DS RRs, and all RRs below that
8365 owner name regardless of type.
8366 */
8367
8368 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8369 /* no data means the qname/qtype is not denied, because an ancestor
8370 delegation NSEC3 can only deny the DS */
8371 BOOST_CHECK_EQUAL(denialState, NODATA);
8372
8373 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8374 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8375 }
8376
8377 BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8378 init();
8379
8380 testkeysset_t keys;
8381 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8382
8383 vector<DNSRecord> records;
8384
8385 vector<shared_ptr<DNSRecordContent>> recordContents;
8386 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8387
8388 /* adding a NSEC3 with more iterations that we support */
8389 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8390 recordContents.push_back(records.at(0).d_content);
8391 addRRSIG(keys, records, DNSName("."), 300);
8392 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8393
8394 ContentSigPair pair;
8395 pair.records = recordContents;
8396 pair.signatures = signatureContents;
8397 cspmap_t denialMap;
8398 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8399 records.clear();
8400
8401 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8402 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8403 BOOST_CHECK_EQUAL(denialState, INSECURE);
8404 }
8405
8406 BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8407 init();
8408
8409 testkeysset_t keys;
8410 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8411
8412 vector<DNSRecord> records;
8413
8414 vector<shared_ptr<DNSRecordContent>> recordContents;
8415 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8416
8417 /*
8418 * RFC 5155 section 8.9:
8419 * If there is an NSEC3 RR present in the response that matches the
8420 * delegation name, then the validator MUST ensure that the NS bit is
8421 * set and that the DS bit is not set in the Type Bit Maps field of the
8422 * NSEC3 RR.
8423 */
8424 /*
8425 The RRSIG from "." denies the existence of any type at a.
8426 NS should be set if it was proving an insecure delegation, let's check that
8427 we correctly detect that it's not.
8428 */
8429 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
8430 recordContents.push_back(records.at(0).d_content);
8431 addRRSIG(keys, records, DNSName("."), 300);
8432 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8433
8434 ContentSigPair pair;
8435 pair.records = recordContents;
8436 pair.signatures = signatureContents;
8437 cspmap_t denialMap;
8438 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8439 records.clear();
8440
8441 /* Insecure because the NS is not set, so while it does
8442 denies the DS, it can't prove an insecure delegation */
8443 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
8444 BOOST_CHECK_EQUAL(denialState, NODATA);
8445 }
8446
8447 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8448 std::unique_ptr<SyncRes> sr;
8449 initSR(sr, true);
8450
8451 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8452
8453 primeHints();
8454 const DNSName target("com.");
8455 testkeysset_t keys;
8456
8457 auto luaconfsCopy = g_luaconfs.getCopy();
8458 luaconfsCopy.dsAnchors.clear();
8459 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8460 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8461 g_luaconfs.setState(luaconfsCopy);
8462
8463 size_t queriesCount = 0;
8464
8465 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) {
8466 queriesCount++;
8467
8468 DNSName auth = domain;
8469 auth.chopOff();
8470
8471 if (type == QType::DS || type == QType::DNSKEY) {
8472 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8473 }
8474 else {
8475 setLWResult(res, RCode::NoError, true, false, true);
8476 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8477 addRRSIG(keys, res->d_records, domain, 300);
8478 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8479 addRRSIG(keys, res->d_records, domain, 1);
8480 return 1;
8481 }
8482
8483 return 0;
8484 });
8485
8486 const time_t now = time(nullptr);
8487 vector<DNSRecord> ret;
8488 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8489 BOOST_CHECK_EQUAL(res, RCode::NoError);
8490 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8491 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8492 BOOST_CHECK_EQUAL(queriesCount, 4);
8493
8494 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
8495 NegCache::NegCacheEntry ne;
8496 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8497 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8498 BOOST_CHECK_EQUAL(ne.d_ttd, now + 1);
8499 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
8500 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8501 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8502 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8503 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
8504
8505 /* again, to test the cache */
8506 ret.clear();
8507 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8508 BOOST_CHECK_EQUAL(res, RCode::NoError);
8509 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8510 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8511 BOOST_CHECK_EQUAL(queriesCount, 4);
8512 }
8513
8514 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
8515 std::unique_ptr<SyncRes> sr;
8516 initSR(sr, true);
8517
8518 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8519
8520 primeHints();
8521 const DNSName target("com.");
8522 const ComboAddress targetAddr("192.0.2.42");
8523 testkeysset_t keys;
8524
8525 auto luaconfsCopy = g_luaconfs.getCopy();
8526 luaconfsCopy.dsAnchors.clear();
8527 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8528 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8529 g_luaconfs.setState(luaconfsCopy);
8530
8531 size_t queriesCount = 0;
8532
8533 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) {
8534 queriesCount++;
8535
8536 DNSName auth = domain;
8537 auth.chopOff();
8538
8539 if (type == QType::DS || type == QType::DNSKEY) {
8540 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8541 }
8542 else {
8543 setLWResult(res, RCode::NoError, true, false, true);
8544 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8545 addRRSIG(keys, res->d_records, domain, 1);
8546 return 1;
8547 }
8548
8549 return 0;
8550 });
8551
8552 const time_t now = time(nullptr);
8553 vector<DNSRecord> ret;
8554 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8555 BOOST_CHECK_EQUAL(res, RCode::NoError);
8556 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8557 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8558 BOOST_CHECK_EQUAL(queriesCount, 4);
8559
8560 /* check that the entry has not been cached for longer than the RRSIG validity */
8561 const ComboAddress who;
8562 vector<DNSRecord> cached;
8563 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
8564 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
8565 BOOST_REQUIRE_EQUAL(cached.size(), 1);
8566 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
8567 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
8568
8569 /* again, to test the cache */
8570 ret.clear();
8571 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8572 BOOST_CHECK_EQUAL(res, RCode::NoError);
8573 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8574 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8575 BOOST_CHECK_EQUAL(queriesCount, 4);
8576 }
8577
8578 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
8579 /*
8580 Validation is optional, and the first query does not ask for it,
8581 so the answer is cached as Indeterminate.
8582 The second query asks for validation, answer should be marked as
8583 Secure.
8584 */
8585 std::unique_ptr<SyncRes> sr;
8586 initSR(sr, true);
8587
8588 setDNSSECValidation(sr, DNSSECMode::Process);
8589
8590 primeHints();
8591 const DNSName target("com.");
8592 testkeysset_t keys;
8593
8594 auto luaconfsCopy = g_luaconfs.getCopy();
8595 luaconfsCopy.dsAnchors.clear();
8596 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8597 g_luaconfs.setState(luaconfsCopy);
8598
8599 size_t queriesCount = 0;
8600
8601 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) {
8602 queriesCount++;
8603
8604 if (type == QType::DS || type == QType::DNSKEY) {
8605 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8606 }
8607 else {
8608 if (domain == target && type == QType::A) {
8609 setLWResult(res, 0, true, false, true);
8610 addRecordToLW(res, target, QType::A, "192.0.2.1");
8611 addRRSIG(keys, res->d_records, DNSName("."), 300);
8612 return 1;
8613 }
8614 }
8615
8616 return 0;
8617 });
8618
8619 vector<DNSRecord> ret;
8620 /* first query does not require validation */
8621 sr->setDNSSECValidationRequested(false);
8622 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8623 BOOST_CHECK_EQUAL(res, RCode::NoError);
8624 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8625 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8626 for (const auto& record : ret) {
8627 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8628 }
8629 BOOST_CHECK_EQUAL(queriesCount, 1);
8630
8631
8632 ret.clear();
8633 /* second one _does_ require validation */
8634 sr->setDNSSECValidationRequested(true);
8635 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8636 BOOST_CHECK_EQUAL(res, RCode::NoError);
8637 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8638 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8639 for (const auto& record : ret) {
8640 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8641 }
8642 BOOST_CHECK_EQUAL(queriesCount, 3);
8643 }
8644
8645 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
8646 /*
8647 Validation is optional, and the first query does not ask for it,
8648 so the answer is cached as Indeterminate.
8649 The second query asks for validation, answer should be marked as
8650 Insecure.
8651 */
8652 std::unique_ptr<SyncRes> sr;
8653 initSR(sr, true);
8654
8655 setDNSSECValidation(sr, DNSSECMode::Process);
8656
8657 primeHints();
8658 const DNSName target("com.");
8659 testkeysset_t keys;
8660
8661 auto luaconfsCopy = g_luaconfs.getCopy();
8662 luaconfsCopy.dsAnchors.clear();
8663 g_luaconfs.setState(luaconfsCopy);
8664
8665 size_t queriesCount = 0;
8666
8667 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) {
8668 queriesCount++;
8669
8670 if (type == QType::DS || type == QType::DNSKEY) {
8671 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8672 }
8673 else {
8674 if (domain == target && type == QType::A) {
8675 setLWResult(res, 0, true, false, true);
8676 addRecordToLW(res, target, QType::A, "192.0.2.1");
8677 return 1;
8678 }
8679 }
8680
8681 return 0;
8682 });
8683
8684 vector<DNSRecord> ret;
8685 /* first query does not require validation */
8686 sr->setDNSSECValidationRequested(false);
8687 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8688 BOOST_CHECK_EQUAL(res, RCode::NoError);
8689 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8690 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8691 for (const auto& record : ret) {
8692 BOOST_CHECK(record.d_type == QType::A);
8693 }
8694 BOOST_CHECK_EQUAL(queriesCount, 1);
8695
8696
8697 ret.clear();
8698 /* second one _does_ require validation */
8699 sr->setDNSSECValidationRequested(true);
8700 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8701 BOOST_CHECK_EQUAL(res, RCode::NoError);
8702 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8703 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8704 for (const auto& record : ret) {
8705 BOOST_CHECK(record.d_type == QType::A);
8706 }
8707 BOOST_CHECK_EQUAL(queriesCount, 1);
8708 }
8709
8710 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
8711 /*
8712 Validation is optional, and the first query does not ask for it,
8713 so the answer is cached as Indeterminate.
8714 The second query asks for validation, answer should be marked as
8715 Bogus.
8716 */
8717 std::unique_ptr<SyncRes> sr;
8718 initSR(sr, true);
8719
8720 setDNSSECValidation(sr, DNSSECMode::Process);
8721
8722 primeHints();
8723 const DNSName target("com.");
8724 testkeysset_t keys;
8725
8726 auto luaconfsCopy = g_luaconfs.getCopy();
8727 luaconfsCopy.dsAnchors.clear();
8728 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8729 g_luaconfs.setState(luaconfsCopy);
8730
8731 size_t queriesCount = 0;
8732
8733 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) {
8734 queriesCount++;
8735
8736 if (type == QType::DS || type == QType::DNSKEY) {
8737 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8738 }
8739 else {
8740 if (domain == target && type == QType::A) {
8741 setLWResult(res, 0, true, false, true);
8742 addRecordToLW(res, target, QType::A, "192.0.2.1");
8743 /* no RRSIG */
8744 return 1;
8745 }
8746 }
8747
8748 return 0;
8749 });
8750
8751 vector<DNSRecord> ret;
8752 /* first query does not require validation */
8753 sr->setDNSSECValidationRequested(false);
8754 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8755 BOOST_CHECK_EQUAL(res, RCode::NoError);
8756 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8757 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8758 for (const auto& record : ret) {
8759 BOOST_CHECK(record.d_type == QType::A);
8760 }
8761 BOOST_CHECK_EQUAL(queriesCount, 1);
8762
8763
8764 ret.clear();
8765 /* second one _does_ require validation */
8766 sr->setDNSSECValidationRequested(true);
8767 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8768 BOOST_CHECK_EQUAL(res, RCode::NoError);
8769 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8770 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8771 for (const auto& record : ret) {
8772 BOOST_CHECK(record.d_type == QType::A);
8773 }
8774 BOOST_CHECK_EQUAL(queriesCount, 3);
8775 }
8776
8777 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
8778 /*
8779 Validation is optional, and the first query does not ask for it,
8780 so the answer is cached as Indeterminate.
8781 The second query asks for validation, answer should be marked as
8782 Secure.
8783 */
8784 std::unique_ptr<SyncRes> sr;
8785 initSR(sr, true);
8786
8787 setDNSSECValidation(sr, DNSSECMode::Process);
8788
8789 primeHints();
8790 const DNSName target("com.");
8791 const DNSName cnameTarget("cname-com.");
8792 testkeysset_t keys;
8793
8794 auto luaconfsCopy = g_luaconfs.getCopy();
8795 luaconfsCopy.dsAnchors.clear();
8796 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8797 g_luaconfs.setState(luaconfsCopy);
8798
8799 size_t queriesCount = 0;
8800
8801 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) {
8802 queriesCount++;
8803
8804 if (type == QType::DS || type == QType::DNSKEY) {
8805 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8806 }
8807 else {
8808 if (domain == target && type == QType::A) {
8809 setLWResult(res, 0, true, false, true);
8810 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
8811 addRRSIG(keys, res->d_records, DNSName("."), 300);
8812 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8813 addRRSIG(keys, res->d_records, DNSName("."), 300);
8814 return 1;
8815 } else if (domain == cnameTarget && type == QType::A) {
8816 setLWResult(res, 0, true, false, true);
8817 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8818 addRRSIG(keys, res->d_records, DNSName("."), 300);
8819 return 1;
8820 }
8821 }
8822
8823 return 0;
8824 });
8825
8826 vector<DNSRecord> ret;
8827 /* first query does not require validation */
8828 sr->setDNSSECValidationRequested(false);
8829 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8830 BOOST_CHECK_EQUAL(res, RCode::NoError);
8831 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8832 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8833 for (const auto& record : ret) {
8834 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
8835 }
8836 BOOST_CHECK_EQUAL(queriesCount, 2);
8837
8838
8839 ret.clear();
8840 /* second one _does_ require validation */
8841 sr->setDNSSECValidationRequested(true);
8842 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8843 BOOST_CHECK_EQUAL(res, RCode::NoError);
8844 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8845 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8846 for (const auto& record : ret) {
8847 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
8848 }
8849 BOOST_CHECK_EQUAL(queriesCount, 5);
8850 }
8851
8852 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
8853 /*
8854 Validation is optional, and the first query does not ask for it,
8855 so the answer is cached as Indeterminate.
8856 The second query asks for validation, answer should be marked as
8857 Insecure.
8858 */
8859 std::unique_ptr<SyncRes> sr;
8860 initSR(sr, true);
8861
8862 setDNSSECValidation(sr, DNSSECMode::Process);
8863
8864 primeHints();
8865 const DNSName target("com.");
8866 const DNSName cnameTarget("cname-com.");
8867 testkeysset_t keys;
8868
8869 auto luaconfsCopy = g_luaconfs.getCopy();
8870 luaconfsCopy.dsAnchors.clear();
8871 g_luaconfs.setState(luaconfsCopy);
8872
8873 size_t queriesCount = 0;
8874
8875 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) {
8876 queriesCount++;
8877
8878 if (type == QType::DS || type == QType::DNSKEY) {
8879 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8880 }
8881 else {
8882 if (domain == target && type == QType::A) {
8883 setLWResult(res, 0, true, false, true);
8884 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
8885 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8886 return 1;
8887 } else if (domain == cnameTarget && type == QType::A) {
8888 setLWResult(res, 0, true, false, true);
8889 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8890 return 1;
8891 }
8892 }
8893
8894 return 0;
8895 });
8896
8897 vector<DNSRecord> ret;
8898 /* first query does not require validation */
8899 sr->setDNSSECValidationRequested(false);
8900 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8901 BOOST_CHECK_EQUAL(res, RCode::NoError);
8902 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8903 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8904 for (const auto& record : ret) {
8905 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8906 }
8907 BOOST_CHECK_EQUAL(queriesCount, 2);
8908
8909
8910 ret.clear();
8911 /* second one _does_ require validation */
8912 sr->setDNSSECValidationRequested(true);
8913 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8914 BOOST_CHECK_EQUAL(res, RCode::NoError);
8915 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8916 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8917 for (const auto& record : ret) {
8918 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8919 }
8920 BOOST_CHECK_EQUAL(queriesCount, 2);
8921 }
8922
8923 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
8924 /*
8925 Validation is optional, and the first query does not ask for it,
8926 so the answer is cached as Indeterminate.
8927 The second query asks for validation, answer should be marked as
8928 Bogus.
8929 */
8930 std::unique_ptr<SyncRes> sr;
8931 initSR(sr, true);
8932
8933 setDNSSECValidation(sr, DNSSECMode::Process);
8934
8935 primeHints();
8936 const DNSName target("com.");
8937 const DNSName cnameTarget("cname-com.");
8938 testkeysset_t keys;
8939
8940 auto luaconfsCopy = g_luaconfs.getCopy();
8941 luaconfsCopy.dsAnchors.clear();
8942 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8943 g_luaconfs.setState(luaconfsCopy);
8944
8945 size_t queriesCount = 0;
8946
8947 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) {
8948 queriesCount++;
8949
8950 if (type == QType::DS || type == QType::DNSKEY) {
8951 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8952 }
8953 else {
8954 if (domain == target && type == QType::A) {
8955 setLWResult(res, 0, true, false, true);
8956 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
8957 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8958 /* no RRSIG */
8959 return 1;
8960 } else if (domain == cnameTarget && type == QType::A) {
8961 setLWResult(res, 0, true, false, true);
8962 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8963 /* no RRSIG */
8964 return 1;
8965 }
8966 }
8967
8968 return 0;
8969 });
8970
8971 vector<DNSRecord> ret;
8972 /* first query does not require validation */
8973 sr->setDNSSECValidationRequested(false);
8974 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8975 BOOST_CHECK_EQUAL(res, RCode::NoError);
8976 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8977 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8978 for (const auto& record : ret) {
8979 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8980 }
8981 BOOST_CHECK_EQUAL(queriesCount, 2);
8982
8983
8984 ret.clear();
8985 /* second one _does_ require validation */
8986 sr->setDNSSECValidationRequested(true);
8987 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8988 BOOST_CHECK_EQUAL(res, RCode::NoError);
8989 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8990 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8991 for (const auto& record : ret) {
8992 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8993 }
8994 BOOST_CHECK_EQUAL(queriesCount, 5);
8995 }
8996
8997 BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) {
8998 /*
8999 We get a record from a secure zone in the additional section, without
9000 the corresponding RRSIG. The record should not be marked as authoritative
9001 and should be correctly validated.
9002 */
9003 std::unique_ptr<SyncRes> sr;
9004 initSR(sr, true);
9005
9006 setDNSSECValidation(sr, DNSSECMode::Process);
9007
9008 primeHints();
9009 const DNSName target("com.");
9010 const DNSName addTarget("nsX.com.");
9011 testkeysset_t keys;
9012
9013 auto luaconfsCopy = g_luaconfs.getCopy();
9014 luaconfsCopy.dsAnchors.clear();
9015 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9016 g_luaconfs.setState(luaconfsCopy);
9017
9018 size_t queriesCount = 0;
9019
9020 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) {
9021 queriesCount++;
9022
9023 if (type == QType::DS || type == QType::DNSKEY) {
9024 if (domain == addTarget) {
9025 DNSName auth(domain);
9026 /* no DS for com, auth will be . */
9027 auth.chopOff();
9028 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false);
9029 }
9030 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9031 }
9032 else {
9033 if (domain == target && type == QType::A) {
9034 setLWResult(res, 0, true, false, true);
9035 addRecordToLW(res, target, QType::A, "192.0.2.1");
9036 addRRSIG(keys, res->d_records, DNSName("."), 300);
9037 addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL);
9038 /* no RRSIG for the additional record */
9039 return 1;
9040 } else if (domain == addTarget && type == QType::A) {
9041 setLWResult(res, 0, true, false, true);
9042 addRecordToLW(res, addTarget, QType::A, "192.0.2.42");
9043 addRRSIG(keys, res->d_records, DNSName("."), 300);
9044 return 1;
9045 }
9046 }
9047
9048 return 0;
9049 });
9050
9051 vector<DNSRecord> ret;
9052 /* first query for target/A, will pick up the additional record as non-auth / unvalidated */
9053 sr->setDNSSECValidationRequested(false);
9054 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9055 BOOST_CHECK_EQUAL(res, RCode::NoError);
9056 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9057 BOOST_CHECK_EQUAL(ret.size(), 2);
9058 for (const auto& record : ret) {
9059 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9060 }
9061 BOOST_CHECK_EQUAL(queriesCount, 1);
9062
9063 ret.clear();
9064 /* ask for the additional record directly, we should not use
9065 the non-auth one and issue a new query, properly validated */
9066 sr->setDNSSECValidationRequested(true);
9067 res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret);
9068 BOOST_CHECK_EQUAL(res, RCode::NoError);
9069 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9070 BOOST_CHECK_EQUAL(ret.size(), 2);
9071 for (const auto& record : ret) {
9072 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9073 }
9074 BOOST_CHECK_EQUAL(queriesCount, 5);
9075 }
9076
9077 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
9078 /*
9079 Validation is optional, and the first query does not ask for it,
9080 so the answer is negatively cached as Indeterminate.
9081 The second query asks for validation, answer should be marked as
9082 Secure.
9083 */
9084 std::unique_ptr<SyncRes> sr;
9085 initSR(sr, true);
9086
9087 setDNSSECValidation(sr, DNSSECMode::Process);
9088
9089 primeHints();
9090 const DNSName target("com.");
9091 testkeysset_t keys;
9092
9093 auto luaconfsCopy = g_luaconfs.getCopy();
9094 luaconfsCopy.dsAnchors.clear();
9095 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9096 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9097 g_luaconfs.setState(luaconfsCopy);
9098
9099 size_t queriesCount = 0;
9100
9101 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) {
9102 queriesCount++;
9103
9104 DNSName auth = domain;
9105 auth.chopOff();
9106
9107 if (type == QType::DS || type == QType::DNSKEY) {
9108 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9109 }
9110 else {
9111 setLWResult(res, RCode::NoError, true, false, true);
9112 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9113 addRRSIG(keys, res->d_records, domain, 300);
9114 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
9115 addRRSIG(keys, res->d_records, domain, 1);
9116 return 1;
9117 }
9118
9119 return 0;
9120 });
9121
9122 vector<DNSRecord> ret;
9123 /* first query does not require validation */
9124 sr->setDNSSECValidationRequested(false);
9125 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9126 BOOST_CHECK_EQUAL(res, RCode::NoError);
9127 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9128 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9129 BOOST_CHECK_EQUAL(queriesCount, 1);
9130 /* check that the entry has not been negatively cached */
9131 NegCache::NegCacheEntry ne;
9132 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9133 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9134 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9135 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9136 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9137 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9138 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
9139
9140 ret.clear();
9141 /* second one _does_ require validation */
9142 sr->setDNSSECValidationRequested(true);
9143 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9144 BOOST_CHECK_EQUAL(res, RCode::NoError);
9145 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9146 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9147 BOOST_CHECK_EQUAL(queriesCount, 4);
9148 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9149 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9150 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
9151 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9152 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9153 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9154 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
9155 }
9156
9157 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
9158 /*
9159 Validation is optional, and the first query does not ask for it,
9160 so the answer is negatively cached as Indeterminate.
9161 The second query asks for validation, answer should be marked as
9162 Secure.
9163 The difference with test_dnssec_validation_from_negcache_secure is
9164 that have one more level here, so we are going to look for the proof
9165 that the DS does not exist for the last level. Since there is no cut,
9166 we should accept the fact that the NSEC denies DS and NS both.
9167 */
9168 std::unique_ptr<SyncRes> sr;
9169 initSR(sr, true);
9170
9171 setDNSSECValidation(sr, DNSSECMode::Process);
9172
9173 primeHints();
9174 const DNSName target("www.com.");
9175 testkeysset_t keys;
9176
9177 auto luaconfsCopy = g_luaconfs.getCopy();
9178 luaconfsCopy.dsAnchors.clear();
9179 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9180 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9181 g_luaconfs.setState(luaconfsCopy);
9182
9183 size_t queriesCount = 0;
9184
9185 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) {
9186 queriesCount++;
9187
9188 if (type == QType::DS || type == QType::DNSKEY) {
9189 if (domain == target) {
9190 /* there is no cut */
9191 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9192 }
9193 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
9194 }
9195
9196 return 0;
9197 });
9198
9199 vector<DNSRecord> ret;
9200 /* first query does not require validation */
9201 sr->setDNSSECValidationRequested(false);
9202 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9203 BOOST_CHECK_EQUAL(res, RCode::NoError);
9204 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9205 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9206 BOOST_CHECK_EQUAL(queriesCount, 1);
9207
9208 ret.clear();
9209 /* second one _does_ require validation */
9210 sr->setDNSSECValidationRequested(true);
9211 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9212 BOOST_CHECK_EQUAL(res, RCode::NoError);
9213 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9214 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9215 BOOST_CHECK_EQUAL(queriesCount, 4);
9216 }
9217
9218 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
9219 /*
9220 Validation is optional, and the first query does not ask for it,
9221 so the answer is negatively cached as Indeterminate.
9222 The second query asks for validation, answer should be marked as
9223 Insecure.
9224 */
9225 std::unique_ptr<SyncRes> sr;
9226 initSR(sr, true);
9227
9228 setDNSSECValidation(sr, DNSSECMode::Process);
9229
9230 primeHints();
9231 const DNSName target("com.");
9232 testkeysset_t keys;
9233
9234 auto luaconfsCopy = g_luaconfs.getCopy();
9235 luaconfsCopy.dsAnchors.clear();
9236 g_luaconfs.setState(luaconfsCopy);
9237
9238 size_t queriesCount = 0;
9239
9240 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) {
9241 queriesCount++;
9242
9243 DNSName auth = domain;
9244 auth.chopOff();
9245
9246 if (type == QType::DS || type == QType::DNSKEY) {
9247 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9248 }
9249 else {
9250 setLWResult(res, RCode::NoError, true, false, true);
9251 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9252 return 1;
9253 }
9254
9255 return 0;
9256 });
9257
9258 vector<DNSRecord> ret;
9259 /* first query does not require validation */
9260 sr->setDNSSECValidationRequested(false);
9261 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9262 BOOST_CHECK_EQUAL(res, RCode::NoError);
9263 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9264 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9265 BOOST_CHECK_EQUAL(queriesCount, 1);
9266 /* check that the entry has not been negatively cached */
9267 NegCache::NegCacheEntry ne;
9268 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9269 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9270 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9271 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9272 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9273 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9274 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9275
9276 ret.clear();
9277 /* second one _does_ require validation */
9278 sr->setDNSSECValidationRequested(true);
9279 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9280 BOOST_CHECK_EQUAL(res, RCode::NoError);
9281 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9282 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9283 BOOST_CHECK_EQUAL(queriesCount, 1);
9284 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9285 BOOST_CHECK_EQUAL(ne.d_validationState, Insecure);
9286 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9287 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9288 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9289 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9290 }
9291
9292 BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
9293 /*
9294 Validation is optional, and the first query does not ask for it,
9295 so the answer is negatively cached as Indeterminate.
9296 The second query asks for validation, answer should be marked as
9297 Bogus.
9298 */
9299 std::unique_ptr<SyncRes> sr;
9300 initSR(sr, true);
9301
9302 setDNSSECValidation(sr, DNSSECMode::Process);
9303
9304 primeHints();
9305 const DNSName target("com.");
9306 testkeysset_t keys;
9307
9308 auto luaconfsCopy = g_luaconfs.getCopy();
9309 luaconfsCopy.dsAnchors.clear();
9310 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9311 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9312 g_luaconfs.setState(luaconfsCopy);
9313
9314 size_t queriesCount = 0;
9315
9316 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) {
9317 queriesCount++;
9318
9319 DNSName auth = domain;
9320 auth.chopOff();
9321
9322 if (type == QType::DS || type == QType::DNSKEY) {
9323 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9324 }
9325 else {
9326 setLWResult(res, RCode::NoError, true, false, true);
9327 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9328 addRRSIG(keys, res->d_records, domain, 300);
9329 /* no denial */
9330 return 1;
9331 }
9332
9333 return 0;
9334 });
9335
9336 vector<DNSRecord> ret;
9337 /* first query does not require validation */
9338 sr->setDNSSECValidationRequested(false);
9339 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9340 BOOST_CHECK_EQUAL(res, RCode::NoError);
9341 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9342 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9343 BOOST_CHECK_EQUAL(queriesCount, 1);
9344 NegCache::NegCacheEntry ne;
9345 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9346 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9347 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9348 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9349 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9350 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9351 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9352
9353 ret.clear();
9354 /* second one _does_ require validation */
9355 sr->setDNSSECValidationRequested(true);
9356 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9357 BOOST_CHECK_EQUAL(res, RCode::NoError);
9358 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9359 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9360 BOOST_CHECK_EQUAL(queriesCount, 4);
9361 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9362 BOOST_CHECK_EQUAL(ne.d_validationState, Bogus);
9363 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9364 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9365 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9366 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
9367 }
9368
9369 BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
9370 g_lowercaseOutgoing = true;
9371 std::unique_ptr<SyncRes> sr;
9372 initSR(sr);
9373
9374 primeHints();
9375
9376 vector<DNSName> sentOutQnames;
9377
9378 const DNSName target("WWW.POWERDNS.COM");
9379 const DNSName cname("WWW.PowerDNS.org");
9380
9381 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) {
9382
9383 sentOutQnames.push_back(domain);
9384
9385 if (isRootServer(ip)) {
9386 if (domain == target) {
9387 setLWResult(res, 0, false, false, true);
9388 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
9389 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
9390 return 1;
9391 }
9392 if (domain == cname) {
9393 setLWResult(res, 0, false, false, true);
9394 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
9395 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
9396 return 1;
9397 }
9398 } else if (ip == ComboAddress("192.0.2.1:53")) {
9399 if (domain == target) {
9400 setLWResult(res, 0, true, false, false);
9401 addRecordToLW(res, domain, QType::CNAME, cname.toString());
9402 return 1;
9403 }
9404 } else if (ip == ComboAddress("192.0.2.2:53")) {
9405 if (domain == cname) {
9406 setLWResult(res, 0, true, false, false);
9407 addRecordToLW(res, domain, QType::A, "127.0.0.1");
9408 return 1;
9409 }
9410 }
9411 return 0;
9412 });
9413
9414 vector<DNSRecord> ret;
9415 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9416
9417 BOOST_CHECK_EQUAL(res, RCode::NoError);
9418
9419 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9420 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
9421
9422 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
9423 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
9424 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
9425 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
9426 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
9427
9428 g_lowercaseOutgoing = false;
9429 }
9430
9431 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
9432 std::unique_ptr<SyncRes> sr;
9433 initSR(sr, true);
9434
9435 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9436
9437 primeHints();
9438 const DNSName target("com.");
9439 testkeysset_t keys, keys2;
9440
9441 auto luaconfsCopy = g_luaconfs.getCopy();
9442 luaconfsCopy.dsAnchors.clear();
9443 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9444 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9445 g_luaconfs.setState(luaconfsCopy);
9446
9447 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9448 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9449 // But add the existing root key otherwise no RRSIG can be created
9450 auto rootkey = keys.find(g_rootdnsname);
9451 keys2.insert(*rootkey);
9452
9453 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) {
9454 DNSName auth = domain;
9455 auth.chopOff();
9456 if (type == QType::DS || type == QType::DNSKEY) {
9457 if (domain == target) {
9458 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9459 return 0;
9460 }
9461 }
9462 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9463 }
9464 return 0;
9465 });
9466
9467 dsmap_t ds;
9468 auto state = sr->getDSRecords(target, ds, false, 0, false);
9469 BOOST_CHECK_EQUAL(state, Secure);
9470 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9471 for (const auto& i : ds) {
9472 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9473 }
9474 }
9475
9476 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
9477 std::unique_ptr<SyncRes> sr;
9478 initSR(sr, true);
9479
9480 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9481
9482 primeHints();
9483 const DNSName target("com.");
9484 testkeysset_t keys, keys2, keys3;
9485
9486 auto luaconfsCopy = g_luaconfs.getCopy();
9487 luaconfsCopy.dsAnchors.clear();
9488 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9489 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9490 g_luaconfs.setState(luaconfsCopy);
9491
9492 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9493 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9494 // But add the existing root key otherwise no RRSIG can be created
9495 auto rootkey = keys.find(g_rootdnsname);
9496 keys2.insert(*rootkey);
9497
9498 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
9499 // But add the existing root key otherwise no RRSIG can be created
9500 keys3.insert(*rootkey);
9501
9502 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) {
9503 DNSName auth = domain;
9504 auth.chopOff();
9505 if (type == QType::DS || type == QType::DNSKEY) {
9506 if (domain == target) {
9507 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9508 return 0;
9509 }
9510 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9511 return 0;
9512 }
9513 }
9514 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9515 }
9516 return 0;
9517 });
9518
9519 dsmap_t ds;
9520 auto state = sr->getDSRecords(target, ds, false, 0, false);
9521 BOOST_CHECK_EQUAL(state, Secure);
9522 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9523 for (const auto& i : ds) {
9524 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9525 }
9526 }
9527
9528 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
9529 std::unique_ptr<SyncRes> sr;
9530 initSR(sr, true);
9531
9532 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9533
9534 primeHints();
9535 const DNSName target("com.");
9536 testkeysset_t keys, keys2, keys3;
9537
9538 auto luaconfsCopy = g_luaconfs.getCopy();
9539 luaconfsCopy.dsAnchors.clear();
9540 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9541 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9542 g_luaconfs.setState(luaconfsCopy);
9543
9544 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9545 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
9546 // But add the existing root key otherwise no RRSIG can be created
9547 auto rootkey = keys.find(g_rootdnsname);
9548 keys2.insert(*rootkey);
9549
9550 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
9551 // But add the existing root key otherwise no RRSIG can be created
9552 keys3.insert(*rootkey);
9553
9554 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) {
9555 DNSName auth = domain;
9556 auth.chopOff();
9557 if (type == QType::DS || type == QType::DNSKEY) {
9558 if (domain == target) {
9559 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9560 return 0;
9561 }
9562 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9563 return 0;
9564 }
9565 }
9566 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9567 }
9568 return 0;
9569 });
9570
9571 dsmap_t ds;
9572 auto state = sr->getDSRecords(target, ds, false, 0, false);
9573 BOOST_CHECK_EQUAL(state, Secure);
9574 BOOST_REQUIRE_EQUAL(ds.size(), 2);
9575 for (const auto& i : ds) {
9576 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9577 }
9578 }
9579
9580 #ifdef HAVE_BOTAN
9581 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) {
9582 std::unique_ptr<SyncRes> sr;
9583 initSR(sr, true);
9584
9585 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9586
9587 primeHints();
9588 const DNSName target("com.");
9589 testkeysset_t keys, keys2;
9590
9591 auto luaconfsCopy = g_luaconfs.getCopy();
9592 luaconfsCopy.dsAnchors.clear();
9593 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9594 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys);
9595 g_luaconfs.setState(luaconfsCopy);
9596
9597 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9598 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9599 // But add the existing root key otherwise no RRSIG can be created
9600 auto rootkey = keys.find(g_rootdnsname);
9601 keys2.insert(*rootkey);
9602
9603 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) {
9604 DNSName auth = domain;
9605 auth.chopOff();
9606 if (type == QType::DS || type == QType::DNSKEY) {
9607 if (domain == target) {
9608 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9609 return 0;
9610 }
9611 }
9612 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9613 }
9614 return 0;
9615 });
9616
9617 dsmap_t ds;
9618 auto state = sr->getDSRecords(target, ds, false, 0, false);
9619 BOOST_CHECK_EQUAL(state, Secure);
9620 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9621 for (const auto& i : ds) {
9622 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9623 }
9624 }
9625
9626 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) {
9627 std::unique_ptr<SyncRes> sr;
9628 initSR(sr, true);
9629
9630 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9631
9632 primeHints();
9633 const DNSName target("com.");
9634 testkeysset_t keys, keys2;
9635
9636 auto luaconfsCopy = g_luaconfs.getCopy();
9637 luaconfsCopy.dsAnchors.clear();
9638 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9639 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9640 g_luaconfs.setState(luaconfsCopy);
9641
9642 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9643 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9644 // But add the existing root key otherwise no RRSIG can be created
9645 auto rootkey = keys.find(g_rootdnsname);
9646 keys2.insert(*rootkey);
9647
9648 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) {
9649 DNSName auth = domain;
9650 auth.chopOff();
9651 if (type == QType::DS || type == QType::DNSKEY) {
9652 if (domain == target) {
9653 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9654 return 0;
9655 }
9656 }
9657 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9658 }
9659 return 0;
9660 });
9661
9662 dsmap_t ds;
9663 auto state = sr->getDSRecords(target, ds, false, 0, false);
9664 BOOST_CHECK_EQUAL(state, Secure);
9665 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9666 for (const auto& i : ds) {
9667 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9668 }
9669 }
9670
9671 BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) {
9672 std::unique_ptr<SyncRes> sr;
9673 initSR(sr, true);
9674
9675 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9676
9677 primeHints();
9678 const DNSName target("com.");
9679 testkeysset_t keys, keys2;
9680
9681 auto luaconfsCopy = g_luaconfs.getCopy();
9682 luaconfsCopy.dsAnchors.clear();
9683 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9684 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys);
9685 g_luaconfs.setState(luaconfsCopy);
9686
9687 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9688 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9689 // But add the existing root key otherwise no RRSIG can be created
9690 auto rootkey = keys.find(g_rootdnsname);
9691 keys2.insert(*rootkey);
9692
9693 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) {
9694 DNSName auth = domain;
9695 auth.chopOff();
9696 if (type == QType::DS || type == QType::DNSKEY) {
9697 if (domain == target) {
9698 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9699 return 0;
9700 }
9701 }
9702 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9703 }
9704 return 0;
9705 });
9706
9707 dsmap_t ds;
9708 auto state = sr->getDSRecords(target, ds, false, 0, false);
9709 BOOST_CHECK_EQUAL(state, Secure);
9710 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9711 for (const auto& i : ds) {
9712 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST);
9713 }
9714 }
9715 #endif // HAVE_BOTAN110
9716
9717 /*
9718 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
9719
9720 - check out of band support
9721
9722 - check preoutquery
9723
9724 */
9725
9726 BOOST_AUTO_TEST_SUITE_END()