]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc.cc
Merge pull request #5570 from rgacogne/rec-neg-validation
[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 "dnssecinfra.hh"
7 #include "dnsseckeeper.hh"
8 #include "lua-recursor4.hh"
9 #include "namespaces.hh"
10 #include "rec-lua-conf.hh"
11 #include "root-dnssec.hh"
12 #include "syncres.hh"
13 #include "test-common.hh"
14 #include "utility.hh"
15 #include "validate-recursor.hh"
16
17 RecursorStats g_stats;
18 GlobalStateHolder<LuaConfigItems> g_luaconfs;
19 thread_local std::unique_ptr<MemRecursorCache> t_RC{nullptr};
20 unsigned int g_numThreads = 1;
21
22 /* Fake some required functions we didn't want the trouble to
23 link with */
24 ArgvMap &arg()
25 {
26 static ArgvMap theArg;
27 return theArg;
28 }
29
30 int getMTaskerTID()
31 {
32 return 0;
33 }
34
35 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret)
36 {
37 return false;
38 }
39
40 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)
41 {
42 return 0;
43 }
44
45 /* primeHints() is only here for now because it
46 was way too much trouble to link with the real one.
47 We should fix this, empty functions are one thing, but this is
48 bad.
49 */
50
51 #include "root-addresses.hh"
52
53 void primeHints(void)
54 {
55 vector<DNSRecord> nsset;
56 if(!t_RC)
57 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
58
59 DNSRecord arr, aaaarr, nsrr;
60 nsrr.d_name=g_rootdnsname;
61 arr.d_type=QType::A;
62 aaaarr.d_type=QType::AAAA;
63 nsrr.d_type=QType::NS;
64 arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(nullptr)+3600000;
65
66 for(char c='a';c<='m';++c) {
67 static char templ[40];
68 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
69 templ[sizeof(templ)-1] = '\0';
70 *templ=c;
71 aaaarr.d_name=arr.d_name=DNSName(templ);
72 nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
73 arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
74 vector<DNSRecord> aset;
75 aset.push_back(arr);
76 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
77 if (rootIps6[c-'a'] != NULL) {
78 aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
79
80 vector<DNSRecord> aaaaset;
81 aaaaset.push_back(aaaarr);
82 t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
83 }
84
85 nsset.push_back(nsrr);
86 }
87 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
88 }
89
90 LuaConfigItems::LuaConfigItems()
91 {
92 for (const auto &dsRecord : rootDSs) {
93 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
94 dsAnchors[g_rootdnsname].insert(*ds);
95 }
96 }
97
98 /* Some helpers functions */
99
100 static void init(bool debug=false)
101 {
102 if (debug) {
103 L.setName("test");
104 L.setLoglevel((Logger::Urgency)(6)); // info and up
105 L.disableSyslog(true);
106 L.toConsole(Logger::Info);
107 }
108
109 seedRandom("/dev/urandom");
110 reportAllTypes();
111
112 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
113
114 SyncRes::s_maxqperq = 50;
115 SyncRes::s_maxtotusec = 1000*7000;
116 SyncRes::s_maxdepth = 40;
117 SyncRes::s_maxnegttl = 3600;
118 SyncRes::s_maxcachettl = 86400;
119 SyncRes::s_packetcachettl = 3600;
120 SyncRes::s_packetcacheservfailttl = 60;
121 SyncRes::s_serverdownmaxfails = 64;
122 SyncRes::s_serverdownthrottletime = 60;
123 SyncRes::s_doIPv6 = true;
124 SyncRes::s_ecsipv4limit = 24;
125 SyncRes::s_ecsipv6limit = 56;
126 SyncRes::s_rootNXTrust = true;
127 SyncRes::s_minimumTTL = 0;
128 SyncRes::s_serverID = "PowerDNS Unit Tests Server ID";
129 SyncRes::clearEDNSSubnets();
130 SyncRes::clearEDNSDomains();
131 SyncRes::clearDelegationOnly();
132 SyncRes::clearDontQuery();
133
134 SyncRes::clearNSSpeeds();
135 BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0);
136 SyncRes::clearEDNSStatuses();
137 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0);
138 SyncRes::clearThrottle();
139 BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0);
140 SyncRes::clearFailedServers();
141 BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0);
142
143 auto luaconfsCopy = g_luaconfs.getCopy();
144 luaconfsCopy.dfe.clear();
145 luaconfsCopy.dsAnchors.clear();
146 for (const auto &dsRecord : rootDSs) {
147 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
148 luaconfsCopy.dsAnchors[g_rootdnsname].insert(*ds);
149 }
150 luaconfsCopy.negAnchors.clear();
151 g_luaconfs.setState(luaconfsCopy);
152
153 g_dnssecmode = DNSSECMode::Off;
154 g_dnssecLOG = debug;
155
156 ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Unit Tests";
157 }
158
159 static void initSR(std::unique_ptr<SyncRes>& sr, bool dnssec=false, bool debug=false, time_t fakeNow=0)
160 {
161 struct timeval now;
162 if (fakeNow > 0) {
163 now.tv_sec = fakeNow;
164 now.tv_usec = 0;
165 }
166 else {
167 Utility::gettimeofday(&now, 0);
168 }
169
170 init(debug);
171
172 sr = std::unique_ptr<SyncRes>(new SyncRes(now));
173 sr->setDoEDNS0(true);
174 if (dnssec) {
175 sr->setDoDNSSEC(dnssec);
176 }
177
178 sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
179
180 SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
181 SyncRes::clearNegCache();
182 }
183
184 static void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
185 {
186 sr->setDNSSECValidationRequested(true);
187 g_dnssecmode = mode;
188 }
189
190 static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
191 {
192 res->d_rcode = rcode;
193 res->d_aabit = aa;
194 res->d_tcbit = tc;
195 res->d_haveEDNS = edns;
196 }
197
198 static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
199 {
200 addRecordToList(res->d_records, name, type, content, place, ttl);
201 }
202
203 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)
204 {
205 addRecordToLW(res, DNSName(name), type, content, place, ttl);
206 }
207
208 static bool isRootServer(const ComboAddress& ip)
209 {
210 if (ip.isIPv4()) {
211 for (size_t idx = 0; idx < rootIps4Count; idx++) {
212 if (ip.toString() == rootIps4[idx]) {
213 return true;
214 }
215 }
216 }
217 else {
218 for (size_t idx = 0; idx < rootIps6Count; idx++) {
219 if (ip.toString() == rootIps6[idx]) {
220 return true;
221 }
222 }
223 }
224
225 return false;
226 }
227
228 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)
229 {
230 time_t now = time(nullptr);
231 DNSKEYRecordContent drc = dpk.getDNSKEY();
232 const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
233
234 rrc.d_type = signQType;
235 rrc.d_labels = signQName.countLabels() - signQName.isWildcard();
236 rrc.d_originalttl = signTTL;
237 rrc.d_siginception = inception ? *inception : (now - 10);
238 rrc.d_sigexpire = now + sigValidity;
239 rrc.d_signer = signer;
240 rrc.d_tag = 0;
241 rrc.d_tag = drc.getTag();
242 rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
243
244 std::string msg = getMessageForRRSET(signQName, rrc, toSign);
245
246 rrc.d_signature = rc->sign(msg);
247 }
248
249 typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t;
250
251 static void 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)
252 {
253 if (records.empty()) {
254 return;
255 }
256
257 const auto it = keys.find(signer);
258 if (it == keys.cend()) {
259 throw std::runtime_error("No DNSKEY found for " + signer.toString() + ", unable to compute the requested RRSIG");
260 }
261
262 size_t recordsCount = records.size();
263 const DNSName& name = records[recordsCount-1].d_name;
264 const uint16_t type = records[recordsCount-1].d_type;
265
266 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
267 for (const auto record : records) {
268 if (record.d_name == name && record.d_type == type) {
269 recordcontents.push_back(record.d_content);
270 }
271 }
272
273 RRSIGRecordContent rrc;
274 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);
275 if (broken) {
276 rrc.d_signature[0] ^= 42;
277 }
278
279 DNSRecord rec;
280 rec.d_place = records[recordsCount-1].d_place;
281 rec.d_name = records[recordsCount-1].d_name;
282 rec.d_type = QType::RRSIG;
283 rec.d_ttl = sigValidity;
284
285 rec.d_content = std::make_shared<RRSIGRecordContent>(rrc);
286 records.push_back(rec);
287 }
288
289 static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records)
290 {
291 const auto it = keys.find(signer);
292 if (it == keys.cend()) {
293 throw std::runtime_error("No DNSKEY found for " + signer.toString());
294 }
295
296 DNSRecord rec;
297 rec.d_place = DNSResourceRecord::ANSWER;
298 rec.d_name = signer;
299 rec.d_type = QType::DNSKEY;
300 rec.d_ttl = ttl;
301
302 rec.d_content = std::make_shared<DNSKEYRecordContent>(it->second.first.getDNSKEY());
303 records.push_back(rec);
304 }
305
306 static void addDS(const DNSName& domain, uint32_t ttl, std::vector<DNSRecord>& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY)
307 {
308 const auto it = keys.find(domain);
309 if (it == keys.cend()) {
310 return;
311 }
312
313 DNSRecord rec;
314 rec.d_name = domain;
315 rec.d_type = QType::DS;
316 rec.d_place = place;
317 rec.d_ttl = ttl;
318 rec.d_content = std::make_shared<DSRecordContent>(it->second.second);
319
320 records.push_back(rec);
321 }
322
323 static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
324 {
325 NSECRecordContent nrc;
326 nrc.d_next = next;
327 nrc.d_set = types;
328
329 DNSRecord rec;
330 rec.d_name = domain;
331 rec.d_ttl = ttl;
332 rec.d_type = QType::NSEC;
333 rec.d_content = std::make_shared<NSECRecordContent>(nrc);
334 rec.d_place = DNSResourceRecord::AUTHORITY;
335
336 records.push_back(rec);
337 }
338
339 static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys)
340 {
341 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(algo));
342 dcke->create((algo <= 10) ? 2048 : dcke->getBits());
343 DNSSECPrivateKey dpk;
344 dpk.d_flags = 256;
345 dpk.setKey(dcke);
346 DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest);
347 keys[name] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk,ds);
348 }
349
350 static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map<DNSName,dsmap_t>& dsAnchors)
351 {
352 generateKeyMaterial(name, algo, digest, keys);
353 dsAnchors[name].insert(keys[name].second);
354 }
355
356 /* Real tests */
357
358 BOOST_AUTO_TEST_SUITE(syncres_cc)
359
360 BOOST_AUTO_TEST_CASE(test_root_primed) {
361 std::unique_ptr<SyncRes> sr;
362 initSR(sr);
363
364 primeHints();
365
366 const DNSName target("a.root-servers.net.");
367
368 /* we are primed, we should be able to resolve A a.root-servers.net. without any query */
369 vector<DNSRecord> ret;
370 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
371 BOOST_CHECK_EQUAL(res, RCode::NoError);
372 BOOST_REQUIRE_EQUAL(ret.size(), 1);
373 BOOST_CHECK(ret[0].d_type == QType::A);
374 BOOST_CHECK_EQUAL(ret[0].d_name, target);
375
376 ret.clear();
377 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
378 BOOST_CHECK_EQUAL(res, RCode::NoError);
379 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
380 BOOST_REQUIRE_EQUAL(ret.size(), 1);
381 BOOST_CHECK(ret[0].d_type == QType::AAAA);
382 BOOST_CHECK_EQUAL(ret[0].d_name, target);
383 }
384
385 BOOST_AUTO_TEST_CASE(test_root_primed_ns) {
386 std::unique_ptr<SyncRes> sr;
387 initSR(sr);
388
389 primeHints();
390 const DNSName target(".");
391
392 /* we are primed, but we should not be able to NS . without any query
393 because the . NS entry is not stored as authoritative */
394
395 size_t queriesCount = 0;
396
397 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) {
398 queriesCount++;
399
400 if (domain == target && type == QType::NS) {
401
402 setLWResult(res, 0, true, false, true);
403 char addr[] = "a.root-servers.net.";
404 for (char idx = 'a'; idx <= 'm'; idx++) {
405 addr[0] = idx;
406 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
407 }
408
409 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
410 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
411
412 return 1;
413 }
414
415 return 0;
416 });
417
418 vector<DNSRecord> ret;
419 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
420 BOOST_CHECK_EQUAL(res, RCode::NoError);
421 BOOST_REQUIRE_EQUAL(ret.size(), 13);
422 BOOST_CHECK_EQUAL(queriesCount, 1);
423 }
424
425 BOOST_AUTO_TEST_CASE(test_root_not_primed) {
426 std::unique_ptr<SyncRes> sr;
427 initSR(sr);
428
429 size_t queriesCount = 0;
430
431 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) {
432 queriesCount++;
433
434 if (domain == g_rootdnsname && type == QType::NS) {
435 setLWResult(res, 0, true, false, true);
436 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
437 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
438 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
439
440 return 1;
441 }
442
443 return 0;
444 });
445
446 /* we are not primed yet, so SyncRes will have to call primeHints()
447 then call getRootNS(), for which at least one of the root servers needs to answer */
448 vector<DNSRecord> ret;
449 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
450 BOOST_CHECK_EQUAL(res, RCode::NoError);
451 BOOST_CHECK_EQUAL(ret.size(), 1);
452 BOOST_CHECK_EQUAL(queriesCount, 2);
453 }
454
455 BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
456 std::unique_ptr<SyncRes> sr;
457 initSR(sr);
458 std::set<ComboAddress> downServers;
459
460 /* we are not primed yet, so SyncRes will have to call primeHints()
461 then call getRootNS(), for which at least one of the root servers needs to answer.
462 None will, so it should ServFail.
463 */
464 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) {
465
466 downServers.insert(ip);
467 return 0;
468 });
469
470 vector<DNSRecord> ret;
471 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
472 BOOST_CHECK_EQUAL(res, RCode::ServFail);
473 BOOST_CHECK_EQUAL(ret.size(), 0);
474 BOOST_CHECK(downServers.size() > 0);
475 /* we explicitly refuse to mark the root servers down */
476 for (const auto& server : downServers) {
477 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
478 }
479 }
480
481 BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
482 std::unique_ptr<SyncRes> sr;
483 initSR(sr);
484
485 ComboAddress noEDNSServer;
486 size_t queriesWithEDNS = 0;
487 size_t queriesWithoutEDNS = 0;
488
489 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) {
490 if (EDNS0Level != 0) {
491 queriesWithEDNS++;
492 noEDNSServer = ip;
493
494 setLWResult(res, RCode::FormErr);
495 return 1;
496 }
497
498 queriesWithoutEDNS++;
499
500 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
501 setLWResult(res, 0, true, false, false);
502 addRecordToLW(res, domain, QType::A, "192.0.2.1");
503 return 1;
504 }
505
506 return 0;
507 });
508
509 primeHints();
510
511 /* fake that the root NS doesn't handle EDNS, check that we fallback */
512 vector<DNSRecord> ret;
513 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
514 BOOST_CHECK_EQUAL(res, RCode::NoError);
515 BOOST_CHECK_EQUAL(ret.size(), 1);
516 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
517 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
518 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
519 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
520 }
521
522 BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) {
523 std::unique_ptr<SyncRes> sr;
524 initSR(sr);
525
526 size_t queriesWithEDNS = 0;
527 size_t queriesWithoutEDNS = 0;
528
529 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) {
530 if (EDNS0Level != 0) {
531 queriesWithEDNS++;
532 setLWResult(res, RCode::NotImp);
533 return 1;
534 }
535
536 queriesWithoutEDNS++;
537
538 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
539 setLWResult(res, 0, true, false, false);
540 addRecordToLW(res, domain, QType::A, "192.0.2.1");
541 return 1;
542 }
543
544 return 0;
545 });
546
547 primeHints();
548
549 /* fake that the NS doesn't handle EDNS, check that we fallback */
550 vector<DNSRecord> ret;
551 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
552 BOOST_CHECK_EQUAL(res, RCode::NoError);
553 BOOST_CHECK_EQUAL(ret.size(), 1);
554 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
555 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
556 }
557
558 BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
559 std::unique_ptr<SyncRes> sr;
560 initSR(sr);
561
562 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) {
563 if (!doTCP) {
564 setLWResult(res, 0, false, true, false);
565 return 1;
566 }
567 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
568 setLWResult(res, 0, true, false, false);
569 addRecordToLW(res, domain, QType::A, "192.0.2.1");
570 return 1;
571 }
572
573 return 0;
574 });
575
576 primeHints();
577
578 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
579 vector<DNSRecord> ret;
580 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
581 BOOST_CHECK_EQUAL(res, RCode::NoError);
582 }
583
584 BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
585 std::unique_ptr<SyncRes> sr;
586 initSR(sr);
587
588 size_t tcpQueriesCount = 0;
589
590 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) {
591 if (!doTCP) {
592 setLWResult(res, 0, true, true, false);
593 return 1;
594 }
595
596 /* first TCP query is answered with a TC response */
597 tcpQueriesCount++;
598 if (tcpQueriesCount == 1) {
599 setLWResult(res, 0, true, true, false);
600 }
601 else {
602 setLWResult(res, 0, true, false, false);
603 }
604
605 addRecordToLW(res, domain, QType::A, "192.0.2.1");
606 return 1;
607 });
608
609 primeHints();
610
611 vector<DNSRecord> ret;
612 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
613 BOOST_CHECK_EQUAL(res, RCode::NoError);
614 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
615 }
616
617 BOOST_AUTO_TEST_CASE(test_all_nss_down) {
618 std::unique_ptr<SyncRes> sr;
619 initSR(sr);
620 std::set<ComboAddress> downServers;
621
622 primeHints();
623
624 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) {
625
626 if (isRootServer(ip)) {
627 setLWResult(res, 0, false, false, true);
628 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
629 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
630 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
631 return 1;
632 }
633 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
634 setLWResult(res, 0, false, false, true);
635 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
636 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
637 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
638 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
639 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
640 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
641 return 1;
642 }
643 else {
644 downServers.insert(ip);
645 return 0;
646 }
647 });
648
649 DNSName target("powerdns.com.");
650
651 vector<DNSRecord> ret;
652 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
653 BOOST_CHECK_EQUAL(res, RCode::ServFail);
654 BOOST_CHECK_EQUAL(ret.size(), 0);
655 BOOST_CHECK_EQUAL(downServers.size(), 4);
656
657 for (const auto& server : downServers) {
658 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
659 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
660 }
661 }
662
663 BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
664 std::unique_ptr<SyncRes> sr;
665 initSR(sr);
666 std::set<ComboAddress> downServers;
667
668 primeHints();
669
670 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) {
671
672 if (isRootServer(ip)) {
673 setLWResult(res, 0, false, false, true);
674 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
675 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
676 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
677 return 1;
678 }
679 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
680 setLWResult(res, 0, false, false, true);
681 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
682 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
683 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
684 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
685 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
686 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
687 return 1;
688 }
689 else {
690 downServers.insert(ip);
691 return -1;
692 }
693 });
694
695 /* exact same test than the previous one, except instead of a time out we fake a network error */
696 DNSName target("powerdns.com.");
697
698 vector<DNSRecord> ret;
699 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
700 BOOST_CHECK_EQUAL(res, RCode::ServFail);
701 BOOST_CHECK_EQUAL(ret.size(), 0);
702 BOOST_CHECK_EQUAL(downServers.size(), 4);
703
704 for (const auto& server : downServers) {
705 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
706 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
707 ;
708 }
709 }
710
711 BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
712 std::unique_ptr<SyncRes> sr;
713 initSR(sr);
714 std::set<ComboAddress> downServers;
715
716 primeHints();
717
718 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) {
719
720 if (isRootServer(ip)) {
721 setLWResult(res, 0, false, false, true);
722 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
723 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
724 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
725 return 1;
726 }
727 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
728 setLWResult(res, 0, false, false, true);
729 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
730 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
731 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
732 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
733 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
734 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
735 return 1;
736 }
737 else {
738 if (downServers.size() < 3) {
739 /* only the last one will answer */
740 downServers.insert(ip);
741 return -2;
742 }
743 else {
744 setLWResult(res, 0, true, false, true);
745 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
746 return 1;
747 }
748 }
749 });
750
751 DNSName target("powerdns.com.");
752
753 vector<DNSRecord> ret;
754 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
755 BOOST_CHECK_EQUAL(res, RCode::NoError);
756 BOOST_CHECK_EQUAL(ret.size(), 1);
757 BOOST_CHECK_EQUAL(downServers.size(), 3);
758
759 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
760 for (const auto& server : downServers) {
761 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
762 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
763 }
764 }
765
766 BOOST_AUTO_TEST_CASE(test_glued_referral) {
767 std::unique_ptr<SyncRes> sr;
768 initSR(sr);
769
770 primeHints();
771
772 const DNSName target("powerdns.com.");
773
774 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) {
775 /* this will cause issue with qname minimization if we ever implement it */
776 if (domain != target) {
777 return 0;
778 }
779
780 if (isRootServer(ip)) {
781 setLWResult(res, 0, false, false, true);
782 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
783 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
784 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
785 return 1;
786 }
787 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
788 setLWResult(res, 0, false, false, true);
789 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
790 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
791 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
792 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
793 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
794 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
795 return 1;
796 }
797 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")) {
798 setLWResult(res, 0, true, false, true);
799 addRecordToLW(res, target, QType::A, "192.0.2.4");
800 return 1;
801 }
802 else {
803 return 0;
804 }
805 });
806
807 vector<DNSRecord> ret;
808 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
809 BOOST_CHECK_EQUAL(res, RCode::NoError);
810 BOOST_REQUIRE_EQUAL(ret.size(), 1);
811 BOOST_CHECK(ret[0].d_type == QType::A);
812 BOOST_CHECK_EQUAL(ret[0].d_name, target);
813 }
814
815 BOOST_AUTO_TEST_CASE(test_glueless_referral) {
816 std::unique_ptr<SyncRes> sr;
817 initSR(sr);
818
819 primeHints();
820
821 const DNSName target("powerdns.com.");
822
823 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) {
824
825 if (isRootServer(ip)) {
826 setLWResult(res, 0, false, false, true);
827
828 if (domain.isPartOf(DNSName("com."))) {
829 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
830 } else if (domain.isPartOf(DNSName("org."))) {
831 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
832 }
833 else {
834 setLWResult(res, RCode::NXDomain, false, false, true);
835 return 1;
836 }
837
838 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
839 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
840 return 1;
841 }
842 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
843 if (domain == target) {
844 setLWResult(res, 0, false, false, true);
845 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
846 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
847 return 1;
848 }
849 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
850 setLWResult(res, 0, true, false, true);
851 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
852 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
853 return 1;
854 }
855 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
856 setLWResult(res, 0, true, false, true);
857 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
858 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
859 return 1;
860 }
861
862 setLWResult(res, RCode::NXDomain, false, false, true);
863 return 1;
864 }
865 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")) {
866 setLWResult(res, 0, true, false, true);
867 addRecordToLW(res, target, QType::A, "192.0.2.4");
868 return 1;
869 }
870 else {
871 return 0;
872 }
873 });
874
875 vector<DNSRecord> ret;
876 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
877 BOOST_CHECK_EQUAL(res, RCode::NoError);
878 BOOST_REQUIRE_EQUAL(ret.size(), 1);
879 BOOST_CHECK(ret[0].d_type == QType::A);
880 BOOST_CHECK_EQUAL(ret[0].d_name, target);
881 }
882
883 BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
884 std::unique_ptr<SyncRes> sr;
885 initSR(sr);
886
887 primeHints();
888
889 const DNSName target("powerdns.com.");
890 SyncRes::addEDNSDomain(target);
891
892 EDNSSubnetOpts incomingECS;
893 incomingECS.source = Netmask("192.0.2.128/32");
894 sr->setIncomingECSFound(true);
895 sr->setIncomingECS(incomingECS);
896
897 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) {
898
899 BOOST_REQUIRE(srcmask);
900 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
901 return 0;
902 });
903
904 vector<DNSRecord> ret;
905 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
906 BOOST_CHECK_EQUAL(res, RCode::ServFail);
907 }
908
909 BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
910 std::unique_ptr<SyncRes> sr;
911 initSR(sr);
912
913 primeHints();
914
915 const DNSName target("powerdns.com.");
916 SyncRes::addEDNSSubnet(Netmask("192.0.2.1/32"));
917
918 EDNSSubnetOpts incomingECS;
919 incomingECS.source = Netmask("2001:DB8::FF/128");
920 sr->setIncomingECSFound(true);
921 sr->setIncomingECS(incomingECS);
922
923 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) {
924
925 if (isRootServer(ip)) {
926 BOOST_REQUIRE(!srcmask);
927
928 setLWResult(res, 0, false, false, true);
929 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
930 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
931 return 1;
932 } else if (ip == ComboAddress("192.0.2.1:53")) {
933
934 BOOST_REQUIRE(srcmask);
935 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
936
937 setLWResult(res, 0, true, false, false);
938 addRecordToLW(res, domain, QType::A, "192.0.2.2");
939 return 1;
940 }
941
942 return 0;
943 });
944
945 vector<DNSRecord> ret;
946 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
947 BOOST_CHECK_EQUAL(res, RCode::NoError);
948 BOOST_REQUIRE_EQUAL(ret.size(), 1);
949 BOOST_CHECK(ret[0].d_type == QType::A);
950 BOOST_CHECK_EQUAL(ret[0].d_name, target);
951 }
952
953 BOOST_AUTO_TEST_CASE(test_following_cname) {
954 std::unique_ptr<SyncRes> sr;
955 initSR(sr);
956
957 primeHints();
958
959 const DNSName target("cname.powerdns.com.");
960 const DNSName cnameTarget("cname-target.powerdns.com");
961
962 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) {
963
964 if (isRootServer(ip)) {
965 setLWResult(res, 0, false, false, true);
966 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
967 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
968 return 1;
969 } else if (ip == ComboAddress("192.0.2.1:53")) {
970
971 if (domain == target) {
972 setLWResult(res, 0, true, false, false);
973 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
974 return 1;
975 }
976 else if (domain == cnameTarget) {
977 setLWResult(res, 0, true, false, false);
978 addRecordToLW(res, domain, QType::A, "192.0.2.2");
979 }
980
981 return 1;
982 }
983
984 return 0;
985 });
986
987 vector<DNSRecord> ret;
988 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
989 BOOST_CHECK_EQUAL(res, RCode::NoError);
990 BOOST_REQUIRE_EQUAL(ret.size(), 2);
991 BOOST_CHECK(ret[0].d_type == QType::CNAME);
992 BOOST_CHECK_EQUAL(ret[0].d_name, target);
993 BOOST_CHECK(ret[1].d_type == QType::A);
994 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
995 }
996
997 BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
998 std::unique_ptr<SyncRes> sr;
999 initSR(sr);
1000
1001 primeHints();
1002
1003 /* In this test we directly get the NS server for cname.powerdns.com.,
1004 and we don't know whether it's also authoritative for
1005 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1006 the additional A record for cname-target.powerdns.com. */
1007 const DNSName target("cname.powerdns.com.");
1008 const DNSName cnameTarget("cname-target.powerdns.com");
1009
1010 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) {
1011
1012 if (isRootServer(ip)) {
1013
1014 setLWResult(res, 0, false, false, true);
1015
1016 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1017 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1018 return 1;
1019 } else if (ip == ComboAddress("192.0.2.1:53")) {
1020
1021 if (domain == target) {
1022 setLWResult(res, 0, true, false, false);
1023 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1024 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1025 return 1;
1026 } else if (domain == cnameTarget) {
1027 setLWResult(res, 0, true, false, false);
1028 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1029 return 1;
1030 }
1031
1032 return 1;
1033 }
1034
1035 return 0;
1036 });
1037
1038 vector<DNSRecord> ret;
1039 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1040 BOOST_CHECK_EQUAL(res, RCode::NoError);
1041 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1042 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1043 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1044 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1045 BOOST_REQUIRE(ret[1].d_type == QType::A);
1046 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1047 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1048 }
1049
1050 BOOST_AUTO_TEST_CASE(test_cname_loop) {
1051 std::unique_ptr<SyncRes> sr;
1052 initSR(sr);
1053
1054 primeHints();
1055
1056 size_t count = 0;
1057 const DNSName target("cname.powerdns.com.");
1058
1059 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) {
1060
1061 count++;
1062
1063 if (isRootServer(ip)) {
1064
1065 setLWResult(res, 0, false, false, true);
1066 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1067 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1068 return 1;
1069 } else if (ip == ComboAddress("192.0.2.1:53")) {
1070
1071 if (domain == target) {
1072 setLWResult(res, 0, true, false, false);
1073 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1074 return 1;
1075 }
1076
1077 return 1;
1078 }
1079
1080 return 0;
1081 });
1082
1083 vector<DNSRecord> ret;
1084 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1085 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1086 BOOST_CHECK_GT(ret.size(), 0);
1087 BOOST_CHECK_EQUAL(count, 2);
1088 }
1089
1090 BOOST_AUTO_TEST_CASE(test_cname_depth) {
1091 std::unique_ptr<SyncRes> sr;
1092 initSR(sr);
1093
1094 primeHints();
1095
1096 size_t depth = 0;
1097 const DNSName target("cname.powerdns.com.");
1098
1099 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) {
1100
1101 if (isRootServer(ip)) {
1102
1103 setLWResult(res, 0, false, false, true);
1104 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1105 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1106 return 1;
1107 } else if (ip == ComboAddress("192.0.2.1:53")) {
1108
1109 setLWResult(res, 0, true, false, false);
1110 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1111 depth++;
1112 return 1;
1113 }
1114
1115 return 0;
1116 });
1117
1118 vector<DNSRecord> ret;
1119 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1120 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1121 BOOST_CHECK_EQUAL(ret.size(), depth);
1122 /* we have an arbitrary limit at 10 when following a CNAME chain */
1123 BOOST_CHECK_EQUAL(depth, 10 + 2);
1124 }
1125
1126 BOOST_AUTO_TEST_CASE(test_time_limit) {
1127 std::unique_ptr<SyncRes> sr;
1128 initSR(sr);
1129
1130 primeHints();
1131
1132 size_t queries = 0;
1133 const DNSName target("cname.powerdns.com.");
1134
1135 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) {
1136
1137 queries++;
1138
1139 if (isRootServer(ip)) {
1140 setLWResult(res, 0, false, false, true);
1141 /* Pretend that this query took 2000 ms */
1142 res->d_usec = 2000;
1143
1144 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1145 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1146 return 1;
1147 } else if (ip == ComboAddress("192.0.2.1:53")) {
1148
1149 setLWResult(res, 0, true, false, false);
1150 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1151 return 1;
1152 }
1153
1154 return 0;
1155 });
1156
1157 /* Set the maximum time to 1 ms */
1158 SyncRes::s_maxtotusec = 1000;
1159
1160 try {
1161 vector<DNSRecord> ret;
1162 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1163 BOOST_CHECK(false);
1164 }
1165 catch(const ImmediateServFailException& e) {
1166 }
1167 BOOST_CHECK_EQUAL(queries, 1);
1168 }
1169
1170 BOOST_AUTO_TEST_CASE(test_referral_depth) {
1171 std::unique_ptr<SyncRes> sr;
1172 initSR(sr);
1173
1174 primeHints();
1175
1176 size_t queries = 0;
1177 const DNSName target("www.powerdns.com.");
1178
1179 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) {
1180
1181 queries++;
1182
1183 if (isRootServer(ip)) {
1184 setLWResult(res, 0, false, false, true);
1185
1186 if (domain == DNSName("www.powerdns.com.")) {
1187 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1188 }
1189 else if (domain == DNSName("ns.powerdns.com.")) {
1190 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1191 }
1192 else if (domain == DNSName("ns1.powerdns.org.")) {
1193 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1194 }
1195 else if (domain == DNSName("ns2.powerdns.org.")) {
1196 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1197 }
1198 else if (domain == DNSName("ns3.powerdns.org.")) {
1199 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1200 }
1201 else if (domain == DNSName("ns4.powerdns.org.")) {
1202 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1203 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1204 }
1205
1206 return 1;
1207 } else if (ip == ComboAddress("192.0.2.1:53")) {
1208
1209 setLWResult(res, 0, true, false, false);
1210 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1211 return 1;
1212 }
1213
1214 return 0;
1215 });
1216
1217 /* Set the maximum depth low */
1218 SyncRes::s_maxdepth = 10;
1219
1220 try {
1221 vector<DNSRecord> ret;
1222 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1223 BOOST_CHECK(false);
1224 }
1225 catch(const ImmediateServFailException& e) {
1226 }
1227 }
1228
1229 BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1230 std::unique_ptr<SyncRes> sr;
1231 initSR(sr);
1232
1233 primeHints();
1234
1235 size_t queries = 0;
1236 const DNSName target("cname.powerdns.com.");
1237
1238 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) {
1239
1240 queries++;
1241
1242 if (isRootServer(ip)) {
1243
1244 setLWResult(res, 0, false, false, true);
1245 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1246 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1247 return 1;
1248 } else if (ip == ComboAddress("192.0.2.1:53")) {
1249
1250 setLWResult(res, 0, true, false, false);
1251 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1252 return 1;
1253 }
1254
1255 return 0;
1256 });
1257
1258 /* Set the maximum number of questions very low */
1259 SyncRes::s_maxqperq = 5;
1260
1261 try {
1262 vector<DNSRecord> ret;
1263 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1264 BOOST_CHECK(false);
1265 }
1266 catch(const ImmediateServFailException& e) {
1267 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1268 }
1269 }
1270
1271 BOOST_AUTO_TEST_CASE(test_throttled_server) {
1272 std::unique_ptr<SyncRes> sr;
1273 initSR(sr);
1274
1275 primeHints();
1276
1277 const DNSName target("throttled.powerdns.com.");
1278 const ComboAddress ns("192.0.2.1:53");
1279 size_t queriesToNS = 0;
1280
1281 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) {
1282
1283 if (isRootServer(ip)) {
1284
1285 setLWResult(res, 0, false, false, true);
1286 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1287 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1288 return 1;
1289 } else if (ip == ns) {
1290
1291 queriesToNS++;
1292
1293 setLWResult(res, 0, true, false, false);
1294 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1295
1296 return 1;
1297 }
1298
1299 return 0;
1300 });
1301
1302 /* mark ns as down */
1303 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, 10000);
1304
1305 vector<DNSRecord> ret;
1306 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1307 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1308 BOOST_CHECK_EQUAL(ret.size(), 0);
1309 /* we should not have sent any queries to ns */
1310 BOOST_CHECK_EQUAL(queriesToNS, 0);
1311 }
1312
1313 BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1314 std::unique_ptr<SyncRes> sr;
1315 initSR(sr);
1316
1317 primeHints();
1318
1319 const ComboAddress ns("192.0.2.1:53");
1320
1321 const size_t blocks = 10;
1322 /* mark ns as down for 'blocks' queries */
1323 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, blocks);
1324
1325 for (size_t idx = 0; idx < blocks; idx++) {
1326 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1327 }
1328
1329 /* we have been throttled 'blocks' times, we should not be throttled anymore */
1330 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1331 }
1332
1333 BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1334 std::unique_ptr<SyncRes> sr;
1335 initSR(sr);
1336
1337 primeHints();
1338
1339 const ComboAddress ns("192.0.2.1:53");
1340
1341 const size_t seconds = 1;
1342 /* mark ns as down for 'seconds' seconds */
1343 SyncRes::doThrottle(time(nullptr), ns, seconds, 10000);
1344
1345 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
1346
1347 sleep(seconds + 1);
1348
1349 /* we should not be throttled anymore */
1350 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
1351 }
1352
1353 BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1354 std::unique_ptr<SyncRes> sr;
1355 initSR(sr);
1356
1357 primeHints();
1358
1359 const DNSName target("throttled.powerdns.com.");
1360 const ComboAddress ns("192.0.2.1:53");
1361 size_t queriesToNS = 0;
1362
1363 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) {
1364
1365 if (isRootServer(ip)) {
1366
1367 setLWResult(res, 0, false, false, true);
1368 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1369 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1370 return 1;
1371 } else if (ip == ns) {
1372
1373 queriesToNS++;
1374
1375 setLWResult(res, 0, true, false, false);
1376 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1377
1378 return 1;
1379 }
1380
1381 return 0;
1382 });
1383
1384 /* prevent querying this NS */
1385 SyncRes::addDontQuery(Netmask(ns));
1386
1387 vector<DNSRecord> ret;
1388 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1389 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1390 BOOST_CHECK_EQUAL(ret.size(), 0);
1391 /* we should not have sent any queries to ns */
1392 BOOST_CHECK_EQUAL(queriesToNS, 0);
1393 }
1394
1395 BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1396 std::unique_ptr<SyncRes> sr;
1397 initSR(sr);
1398
1399 primeHints();
1400
1401 const DNSName target1("powerdns.com.");
1402 const DNSName target2("notpowerdns.com.");
1403 const ComboAddress ns("192.0.2.1:53");
1404 size_t queriesCount = 0;
1405
1406 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) {
1407
1408 queriesCount++;
1409
1410 if (isRootServer(ip)) {
1411
1412 if (domain == target1) {
1413 setLWResult(res, RCode::NXDomain, true, false, true);
1414 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1415 }
1416 else {
1417 setLWResult(res, 0, true, false, true);
1418 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1419 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1420 }
1421
1422 return 1;
1423 } else if (ip == ns) {
1424
1425 setLWResult(res, 0, true, false, false);
1426 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1427
1428 return 1;
1429 }
1430
1431 return 0;
1432 });
1433
1434 vector<DNSRecord> ret;
1435 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1436 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1437 BOOST_CHECK_EQUAL(ret.size(), 1);
1438 /* one for target1 and one for the entire TLD */
1439 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1440
1441 ret.clear();
1442 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1443 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1444 BOOST_CHECK_EQUAL(ret.size(), 1);
1445 /* one for target1 and one for the entire TLD */
1446 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
1447
1448 /* we should have sent only one query */
1449 BOOST_CHECK_EQUAL(queriesCount, 1);
1450 }
1451
1452 BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1453 std::unique_ptr<SyncRes> sr;
1454 init();
1455 initSR(sr, true, false);
1456
1457 primeHints();
1458
1459 const DNSName target1("powerdns.com.");
1460 const DNSName target2("notpowerdns.com.");
1461 const ComboAddress ns("192.0.2.1:53");
1462 size_t queriesCount = 0;
1463
1464 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1465 We should add target1 to the negcache, but not "com.". */
1466
1467 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) {
1468
1469 queriesCount++;
1470
1471 if (isRootServer(ip)) {
1472
1473 if (domain == target1) {
1474 setLWResult(res, RCode::NXDomain, true, false, true);
1475 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1476 }
1477 else {
1478 setLWResult(res, 0, true, false, true);
1479 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1480 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1481 }
1482
1483 return 1;
1484 } else if (ip == ns) {
1485
1486 setLWResult(res, 0, true, false, false);
1487 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1488
1489 return 1;
1490 }
1491
1492 return 0;
1493 });
1494
1495 vector<DNSRecord> ret;
1496 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1497 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1498 BOOST_CHECK_EQUAL(ret.size(), 1);
1499
1500 /* even with root-nx-trust on and a NX answer from the root,
1501 we should not have cached the entire TLD this time. */
1502 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1503
1504 ret.clear();
1505 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1506 BOOST_CHECK_EQUAL(res, RCode::NoError);
1507 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1508 BOOST_REQUIRE(ret[0].d_type == QType::A);
1509 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1510 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1511
1512 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
1513
1514 BOOST_CHECK_EQUAL(queriesCount, 3);
1515 }
1516
1517 BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1518 std::unique_ptr<SyncRes> sr;
1519 initSR(sr);
1520
1521 primeHints();
1522
1523 const DNSName target1("powerdns.com.");
1524 const DNSName target2("notpowerdns.com.");
1525 const ComboAddress ns("192.0.2.1:53");
1526 size_t queriesCount = 0;
1527
1528 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) {
1529
1530 queriesCount++;
1531
1532 if (isRootServer(ip)) {
1533
1534 if (domain == target1) {
1535 setLWResult(res, RCode::NXDomain, true, false, true);
1536 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1537 }
1538 else {
1539 setLWResult(res, 0, true, false, true);
1540 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1541 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1542 }
1543
1544 return 1;
1545 } else if (ip == ns) {
1546
1547 setLWResult(res, 0, true, false, false);
1548 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1549
1550 return 1;
1551 }
1552
1553 return 0;
1554 });
1555
1556 SyncRes::s_rootNXTrust = false;
1557
1558 vector<DNSRecord> ret;
1559 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1560 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1561 BOOST_CHECK_EQUAL(ret.size(), 1);
1562 /* one for target1 */
1563 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1564
1565 ret.clear();
1566 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1567 BOOST_CHECK_EQUAL(res, RCode::NoError);
1568 BOOST_CHECK_EQUAL(ret.size(), 1);
1569 /* one for target1 */
1570 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
1571
1572 /* we should have sent three queries */
1573 BOOST_CHECK_EQUAL(queriesCount, 3);
1574 }
1575
1576 BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1577 std::unique_ptr<SyncRes> sr;
1578 initSR(sr);
1579
1580 primeHints();
1581
1582 const DNSName target("www.powerdns.com.");
1583 const DNSName cnameTarget("cname.powerdns.com.");
1584
1585 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
1586
1587 EDNSSubnetOpts incomingECS;
1588 incomingECS.source = Netmask("192.0.2.128/32");
1589 sr->setIncomingECSFound(true);
1590 sr->setIncomingECS(incomingECS);
1591
1592 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) {
1593
1594 BOOST_REQUIRE(srcmask);
1595 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1596
1597 if (isRootServer(ip)) {
1598 setLWResult(res, 0, false, false, true);
1599 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1600 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1601
1602 return 1;
1603 } else if (ip == ComboAddress("192.0.2.1:53")) {
1604 if (domain == target) {
1605 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
1606 setLWResult(res, RCode::NXDomain, true, false, true);
1607 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1608 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1609 }
1610 else if (domain == cnameTarget) {
1611 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
1612 but we might if we still chase the CNAME. */
1613 setLWResult(res, RCode::NXDomain, true, false, true);
1614 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1615 }
1616
1617 return 1;
1618 }
1619
1620 return 0;
1621 });
1622
1623 vector<DNSRecord> ret;
1624 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1625 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1626 BOOST_CHECK_EQUAL(ret.size(), 2);
1627 /* no negative cache entry because the response was variable */
1628 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
1629 }
1630
1631 BOOST_AUTO_TEST_CASE(test_ns_speed) {
1632 std::unique_ptr<SyncRes> sr;
1633 initSR(sr);
1634
1635 primeHints();
1636
1637 const DNSName target("powerdns.com.");
1638
1639 std::map<ComboAddress, uint64_t> nsCounts;
1640
1641 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) {
1642
1643 if (isRootServer(ip)) {
1644 setLWResult(res, 0, false, false, true);
1645 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1646 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1647 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1648
1649 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1650 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1651 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1652 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
1653 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
1654 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
1655
1656 return 1;
1657 } else {
1658 nsCounts[ip]++;
1659
1660 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
1661 BOOST_CHECK_LT(nsCounts.size(), 3);
1662
1663 /* let's time out on pdns-public-ns2.powerdns.com. */
1664 return 0;
1665 }
1666 else if (ip == ComboAddress("192.0.2.1:53")) {
1667 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1668
1669 setLWResult(res, 0, true, false, true);
1670 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1671 return 1;
1672 }
1673
1674 return 0;
1675 }
1676
1677 return 0;
1678 });
1679
1680 struct timeval now;
1681 gettimeofday(&now, 0);
1682
1683 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
1684 then pdns-public-ns1.powerdns.com. on IPv4 */
1685 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
1686 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
1687 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
1688 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
1689 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
1690 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
1691
1692 vector<DNSRecord> ret;
1693 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1694 BOOST_CHECK_EQUAL(res, RCode::NoError);
1695 BOOST_CHECK_EQUAL(ret.size(), 1);
1696 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1697 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
1698 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
1699 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
1700 }
1701
1702 BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
1703 std::unique_ptr<SyncRes> sr;
1704 initSR(sr);
1705
1706 primeHints();
1707
1708 const DNSName target("powerdns.com.");
1709
1710 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) {
1711
1712 if (isRootServer(ip)) {
1713 setLWResult(res, 0, false, false, true);
1714 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1715
1716 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1717
1718 return 1;
1719 } else if (ip == ComboAddress("192.0.2.1:53")) {
1720 setLWResult(res, 0, true, false, true);
1721 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1722 return 1;
1723 }
1724
1725 return 0;
1726 });
1727
1728 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
1729 time_t now = time(nullptr);
1730 std::vector<DNSRecord> records;
1731 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1732 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
1733
1734 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1735
1736 vector<DNSRecord> ret;
1737 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1738 BOOST_CHECK_EQUAL(res, RCode::NoError);
1739 BOOST_CHECK_EQUAL(ret.size(), 1);
1740 }
1741
1742 BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
1743 std::unique_ptr<SyncRes> sr;
1744 initSR(sr);
1745
1746 primeHints();
1747
1748 const DNSName target("powerdns.com.");
1749 size_t queriesCount = 0;
1750
1751 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) {
1752
1753 queriesCount++;
1754
1755 if (isRootServer(ip) && domain == target) {
1756 setLWResult(res, 0, false, false, true);
1757 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1758 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1759 return 1;
1760 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
1761 setLWResult(res, 0, true, false, true);
1762 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1763 return 1;
1764 }
1765
1766 return 0;
1767 });
1768
1769 vector<DNSRecord> ret;
1770 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1771 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1772 BOOST_CHECK_EQUAL(ret.size(), 0);
1773 /* one query to get NSs, then A and AAAA for each NS */
1774 BOOST_CHECK_EQUAL(queriesCount, 5);
1775 }
1776
1777 BOOST_AUTO_TEST_CASE(test_cache_hit) {
1778 std::unique_ptr<SyncRes> sr;
1779 initSR(sr);
1780
1781 primeHints();
1782
1783 const DNSName target("powerdns.com.");
1784
1785 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) {
1786
1787 return 0;
1788 });
1789
1790 /* we populate the cache with eveything we need */
1791 time_t now = time(nullptr);
1792 std::vector<DNSRecord> records;
1793 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1794
1795 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
1796 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1797
1798 vector<DNSRecord> ret;
1799 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1800 BOOST_CHECK_EQUAL(res, RCode::NoError);
1801 BOOST_CHECK_EQUAL(ret.size(), 1);
1802 }
1803
1804 BOOST_AUTO_TEST_CASE(test_no_rd) {
1805 std::unique_ptr<SyncRes> sr;
1806 initSR(sr);
1807
1808 primeHints();
1809
1810 const DNSName target("powerdns.com.");
1811 size_t queriesCount = 0;
1812
1813 sr->setCacheOnly();
1814
1815 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) {
1816
1817 queriesCount++;
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::NoError);
1824 BOOST_CHECK_EQUAL(ret.size(), 0);
1825 BOOST_CHECK_EQUAL(queriesCount, 0);
1826 }
1827
1828 BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
1829 std::unique_ptr<SyncRes> sr;
1830 const time_t now = time(nullptr);
1831 initSR(sr);
1832
1833 primeHints();
1834
1835 const DNSName target("cachettl.powerdns.com.");
1836 const ComboAddress ns("192.0.2.1:53");
1837
1838 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) {
1839
1840 if (isRootServer(ip)) {
1841
1842 setLWResult(res, 0, false, false, true);
1843 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1844 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
1845 return 1;
1846 } else if (ip == ns) {
1847
1848 setLWResult(res, 0, true, false, false);
1849 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
1850
1851 return 1;
1852 }
1853
1854 return 0;
1855 });
1856
1857 SyncRes::s_minimumTTL = 60;
1858 SyncRes::s_maxcachettl = 3600;
1859
1860 vector<DNSRecord> ret;
1861 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1862 BOOST_CHECK_EQUAL(res, RCode::NoError);
1863 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1864 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
1865
1866 const ComboAddress who;
1867 vector<DNSRecord> cached;
1868 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
1869 BOOST_REQUIRE_EQUAL(cached.size(), 1);
1870 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
1871 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
1872
1873 cached.clear();
1874 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
1875 BOOST_REQUIRE_EQUAL(cached.size(), 1);
1876 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
1877 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
1878 }
1879
1880 BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
1881 std::unique_ptr<SyncRes> sr;
1882 initSR(sr);
1883
1884 primeHints();
1885
1886 const DNSName target("powerdns.com.");
1887
1888 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) {
1889
1890 if (isRootServer(ip)) {
1891 setLWResult(res, 0, false, false, true);
1892 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1893
1894 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1895
1896 return 1;
1897 } else if (ip == ComboAddress("192.0.2.1:53")) {
1898 setLWResult(res, 0, true, false, true);
1899 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1900 return 1;
1901 }
1902
1903 return 0;
1904 });
1905
1906 /* we populate the cache with entries that expired 60s ago*/
1907 time_t now = time(nullptr);
1908 std::vector<DNSRecord> records;
1909 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1910 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
1911
1912 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
1913
1914 vector<DNSRecord> ret;
1915 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1916 BOOST_CHECK_EQUAL(res, RCode::NoError);
1917 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1918 BOOST_REQUIRE(ret[0].d_type == QType::A);
1919 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
1920 }
1921
1922 BOOST_AUTO_TEST_CASE(test_delegation_only) {
1923 std::unique_ptr<SyncRes> sr;
1924 initSR(sr);
1925
1926 primeHints();
1927
1928 /* Thanks, Verisign */
1929 SyncRes::addDelegationOnly(DNSName("com."));
1930 SyncRes::addDelegationOnly(DNSName("net."));
1931
1932 const DNSName target("nx-powerdns.com.");
1933
1934 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) {
1935
1936 if (isRootServer(ip)) {
1937 setLWResult(res, 0, false, false, true);
1938 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1939 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1940 return 1;
1941 } else if (ip == ComboAddress("192.0.2.1:53")) {
1942
1943 setLWResult(res, 0, true, false, true);
1944 addRecordToLW(res, domain, QType::A, "192.0.2.42");
1945 return 1;
1946 }
1947
1948 return 0;
1949 });
1950
1951 vector<DNSRecord> ret;
1952 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1953 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1954 BOOST_CHECK_EQUAL(ret.size(), 0);
1955 }
1956
1957 BOOST_AUTO_TEST_CASE(test_unauth_any) {
1958 std::unique_ptr<SyncRes> sr;
1959 initSR(sr);
1960
1961 primeHints();
1962
1963 const DNSName target("powerdns.com.");
1964
1965 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) {
1966
1967 if (isRootServer(ip)) {
1968 setLWResult(res, 0, false, false, true);
1969 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1970 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1971 return 1;
1972 } else if (ip == ComboAddress("192.0.2.1:53")) {
1973
1974 setLWResult(res, 0, false, false, true);
1975 addRecordToLW(res, domain, QType::A, "192.0.2.42");
1976 return 1;
1977 }
1978
1979 return 0;
1980 });
1981
1982 vector<DNSRecord> ret;
1983 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
1984 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1985 BOOST_CHECK_EQUAL(ret.size(), 0);
1986 }
1987
1988 BOOST_AUTO_TEST_CASE(test_no_data) {
1989 std::unique_ptr<SyncRes> sr;
1990 initSR(sr);
1991
1992 primeHints();
1993
1994 const DNSName target("powerdns.com.");
1995
1996 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) {
1997
1998 setLWResult(res, 0, true, false, true);
1999 return 1;
2000 });
2001
2002 vector<DNSRecord> ret;
2003 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2004 BOOST_CHECK_EQUAL(res, RCode::NoError);
2005 BOOST_CHECK_EQUAL(ret.size(), 0);
2006 }
2007
2008 BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2009 std::unique_ptr<SyncRes> sr;
2010 initSR(sr);
2011
2012 primeHints();
2013
2014 const DNSName target("powerdns.com.");
2015
2016 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) {
2017
2018 setLWResult(res, 0, true, false, true);
2019 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2020 addRecordToLW(res, domain, QType::ANY, "0 0");
2021 addRecordToLW(res, domain, QType::OPT, "");
2022 return 1;
2023 });
2024
2025 vector<DNSRecord> ret;
2026 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2027 BOOST_CHECK_EQUAL(res, RCode::NoError);
2028 BOOST_CHECK_EQUAL(ret.size(), 1);
2029 }
2030
2031 BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2032 std::unique_ptr<SyncRes> sr;
2033 initSR(sr);
2034
2035 primeHints();
2036
2037 const DNSName target("powerdns.com.");
2038
2039 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) {
2040
2041 setLWResult(res, 0, true, false, true);
2042 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2043 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2044 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2045 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2046 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2047 return 1;
2048 });
2049
2050 vector<DNSRecord> ret;
2051 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2052 BOOST_CHECK_EQUAL(res, RCode::NoError);
2053 BOOST_CHECK_EQUAL(ret.size(), 1);
2054 }
2055
2056 BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2057 std::unique_ptr<SyncRes> sr;
2058 initSR(sr, true);
2059
2060 primeHints();
2061
2062 const DNSName target("powerdns.com.");
2063
2064 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) {
2065
2066 setLWResult(res, 0, true, false, true);
2067 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2068 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2069 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2070 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2071 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2072 return 1;
2073 });
2074
2075 vector<DNSRecord> ret;
2076 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2077 BOOST_CHECK_EQUAL(res, RCode::NoError);
2078 BOOST_CHECK_EQUAL(ret.size(), 4);
2079 }
2080
2081 BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2082 std::unique_ptr<SyncRes> sr;
2083 initSR(sr);
2084
2085 primeHints();
2086
2087 const DNSName target("powerdns.com.");
2088
2089 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) {
2090
2091 setLWResult(res, RCode::NXDomain, true, false, true);
2092 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2093 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2094 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2095 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2096 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2097 return 1;
2098 });
2099
2100 vector<DNSRecord> ret;
2101 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2102 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2103 BOOST_CHECK_EQUAL(ret.size(), 1);
2104 }
2105
2106 BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2107 std::unique_ptr<SyncRes> sr;
2108 initSR(sr, true);
2109
2110 primeHints();
2111
2112 const DNSName target("powerdns.com.");
2113
2114 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) {
2115
2116 setLWResult(res, RCode::NXDomain, true, false, true);
2117 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2118 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2119 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2120 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2121 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2122 return 1;
2123 });
2124
2125 vector<DNSRecord> ret;
2126 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2127 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2128 BOOST_CHECK_EQUAL(ret.size(), 4);
2129 }
2130
2131 BOOST_AUTO_TEST_CASE(test_qclass_none) {
2132 std::unique_ptr<SyncRes> sr;
2133 initSR(sr);
2134
2135 primeHints();
2136
2137 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2138 size_t queriesCount = 0;
2139
2140 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) {
2141
2142 queriesCount++;
2143 return 0;
2144 });
2145
2146 const DNSName target("powerdns.com.");
2147 vector<DNSRecord> ret;
2148 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2149 BOOST_CHECK_EQUAL(res, -1);
2150 BOOST_CHECK_EQUAL(ret.size(), 0);
2151 BOOST_CHECK_EQUAL(queriesCount, 0);
2152 }
2153
2154 BOOST_AUTO_TEST_CASE(test_xfr) {
2155 std::unique_ptr<SyncRes> sr;
2156 initSR(sr);
2157
2158 primeHints();
2159
2160 /* {A,I}XFR should be rejected right away */
2161 size_t queriesCount = 0;
2162
2163 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) {
2164
2165 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2166 queriesCount++;
2167 return 0;
2168 });
2169
2170 const DNSName target("powerdns.com.");
2171 vector<DNSRecord> ret;
2172 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2173 BOOST_CHECK_EQUAL(res, -1);
2174 BOOST_CHECK_EQUAL(ret.size(), 0);
2175 BOOST_CHECK_EQUAL(queriesCount, 0);
2176
2177 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2178 BOOST_CHECK_EQUAL(res, -1);
2179 BOOST_CHECK_EQUAL(ret.size(), 0);
2180 BOOST_CHECK_EQUAL(queriesCount, 0);
2181 }
2182
2183 BOOST_AUTO_TEST_CASE(test_special_names) {
2184 std::unique_ptr<SyncRes> sr;
2185 initSR(sr);
2186
2187 primeHints();
2188
2189 /* special names should be handled internally */
2190
2191 size_t queriesCount = 0;
2192
2193 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) {
2194
2195 queriesCount++;
2196 return 0;
2197 });
2198
2199 vector<DNSRecord> ret;
2200 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
2201 BOOST_CHECK_EQUAL(res, RCode::NoError);
2202 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2203 BOOST_CHECK(ret[0].d_type == QType::PTR);
2204 BOOST_CHECK_EQUAL(queriesCount, 0);
2205
2206 ret.clear();
2207 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
2208 BOOST_CHECK_EQUAL(res, RCode::NoError);
2209 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2210 BOOST_CHECK(ret[0].d_type == QType::PTR);
2211 BOOST_CHECK_EQUAL(queriesCount, 0);
2212
2213 ret.clear();
2214 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);
2215 BOOST_CHECK_EQUAL(res, RCode::NoError);
2216 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2217 BOOST_CHECK(ret[0].d_type == QType::PTR);
2218 BOOST_CHECK_EQUAL(queriesCount, 0);
2219
2220 ret.clear();
2221 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);
2222 BOOST_CHECK_EQUAL(res, RCode::NoError);
2223 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2224 BOOST_CHECK(ret[0].d_type == QType::PTR);
2225 BOOST_CHECK_EQUAL(queriesCount, 0);
2226
2227 ret.clear();
2228 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
2229 BOOST_CHECK_EQUAL(res, RCode::NoError);
2230 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2231 BOOST_CHECK(ret[0].d_type == QType::A);
2232 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2233 BOOST_CHECK_EQUAL(queriesCount, 0);
2234
2235 ret.clear();
2236 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
2237 BOOST_CHECK_EQUAL(res, RCode::NoError);
2238 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2239 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2240 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2241 BOOST_CHECK_EQUAL(queriesCount, 0);
2242
2243 ret.clear();
2244 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
2245 BOOST_CHECK_EQUAL(res, RCode::NoError);
2246 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2247 for (const auto& rec : ret) {
2248 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2249 if (rec.d_type == QType::A) {
2250 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2251 }
2252 else {
2253 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2254 }
2255 }
2256 BOOST_CHECK_EQUAL(queriesCount, 0);
2257
2258 ret.clear();
2259 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
2260 BOOST_CHECK_EQUAL(res, RCode::NoError);
2261 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2262 BOOST_CHECK(ret[0].d_type == QType::TXT);
2263 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2264 BOOST_CHECK_EQUAL(queriesCount, 0);
2265
2266 ret.clear();
2267 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
2268 BOOST_CHECK_EQUAL(res, RCode::NoError);
2269 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2270 BOOST_CHECK(ret[0].d_type == QType::TXT);
2271 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2272 BOOST_CHECK_EQUAL(queriesCount, 0);
2273
2274 ret.clear();
2275 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
2276 BOOST_CHECK_EQUAL(res, RCode::NoError);
2277 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2278 BOOST_CHECK(ret[0].d_type == QType::TXT);
2279 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2280 BOOST_CHECK_EQUAL(queriesCount, 0);
2281
2282 ret.clear();
2283 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
2284 BOOST_CHECK_EQUAL(res, RCode::NoError);
2285 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2286 BOOST_CHECK(ret[0].d_type == QType::TXT);
2287 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2288 BOOST_CHECK_EQUAL(queriesCount, 0);
2289
2290 ret.clear();
2291 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
2292 BOOST_CHECK_EQUAL(res, RCode::NoError);
2293 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2294 BOOST_CHECK(ret[0].d_type == QType::TXT);
2295 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2296 BOOST_CHECK_EQUAL(queriesCount, 0);
2297
2298 ret.clear();
2299 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
2300 BOOST_CHECK_EQUAL(res, RCode::NoError);
2301 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2302 BOOST_CHECK(ret[0].d_type == QType::TXT);
2303 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2304 BOOST_CHECK_EQUAL(queriesCount, 0);
2305 }
2306
2307 BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2308 std::unique_ptr<SyncRes> sr;
2309 initSR(sr);
2310
2311 primeHints();
2312
2313 const DNSName target("rpz.powerdns.com.");
2314 const ComboAddress ns("192.0.2.1:53");
2315
2316 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) {
2317
2318 if (isRootServer(ip)) {
2319 setLWResult(res, false, true, false, true);
2320 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2321 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2322 return 1;
2323 } else if (ip == ns) {
2324
2325 setLWResult(res, 0, true, false, true);
2326 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2327 return 1;
2328 }
2329
2330 return 0;
2331 });
2332
2333 DNSFilterEngine::Policy pol;
2334 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2335 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2336 zone->setName("Unit test policy 0");
2337 zone->addNSIPTrigger(Netmask(ns, 32), pol);
2338 auto luaconfsCopy = g_luaconfs.getCopy();
2339 luaconfsCopy.dfe.addZone(zone);
2340 g_luaconfs.setState(luaconfsCopy);
2341
2342 vector<DNSRecord> ret;
2343 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2344 BOOST_CHECK_EQUAL(res, -2);
2345 BOOST_CHECK_EQUAL(ret.size(), 0);
2346 }
2347
2348 BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2349 std::unique_ptr<SyncRes> sr;
2350 initSR(sr);
2351
2352 primeHints();
2353
2354 const DNSName target("rpz.powerdns.com.");
2355 const ComboAddress ns("[2001:DB8::42]:53");
2356
2357 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) {
2358
2359 if (isRootServer(ip)) {
2360 setLWResult(res, 0, false, false, true);
2361 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2362 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2363 return 1;
2364 } else if (ip == ns) {
2365
2366 setLWResult(res, 0, true, false, true);
2367 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2368 return 1;
2369 }
2370
2371 return 0;
2372 });
2373
2374 DNSFilterEngine::Policy pol;
2375 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2376 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2377 zone->setName("Unit test policy 0");
2378 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2379 auto luaconfsCopy = g_luaconfs.getCopy();
2380 luaconfsCopy.dfe.addZone(zone);
2381 g_luaconfs.setState(luaconfsCopy);
2382
2383 vector<DNSRecord> ret;
2384 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2385 BOOST_CHECK_EQUAL(res, -2);
2386 BOOST_CHECK_EQUAL(ret.size(), 0);
2387 }
2388
2389 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2390 std::unique_ptr<SyncRes> sr;
2391 initSR(sr);
2392
2393 primeHints();
2394
2395 const DNSName target("rpz.powerdns.com.");
2396 const ComboAddress ns("192.0.2.1:53");
2397 const DNSName nsName("ns1.powerdns.com.");
2398
2399 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) {
2400
2401 if (isRootServer(ip)) {
2402 setLWResult(res, 0, false, false, true);
2403 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2404 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2405 return 1;
2406 } else if (ip == ns) {
2407
2408 setLWResult(res, 0, true, false, true);
2409 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2410 return 1;
2411 }
2412
2413 return 0;
2414 });
2415
2416 DNSFilterEngine::Policy pol;
2417 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2418 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2419 zone->setName("Unit test policy 0");
2420 zone->addNSTrigger(nsName, pol);
2421 auto luaconfsCopy = g_luaconfs.getCopy();
2422 luaconfsCopy.dfe.addZone(zone);
2423 g_luaconfs.setState(luaconfsCopy);
2424
2425 vector<DNSRecord> ret;
2426 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2427 BOOST_CHECK_EQUAL(res, -2);
2428 BOOST_CHECK_EQUAL(ret.size(), 0);
2429 }
2430
2431 BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2432 std::unique_ptr<SyncRes> sr;
2433 initSR(sr);
2434
2435 primeHints();
2436
2437 const DNSName target("rpz.powerdns.com.");
2438 const ComboAddress ns("192.0.2.1:53");
2439 const DNSName nsName("ns1.powerdns.com.");
2440
2441 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) {
2442
2443 if (isRootServer(ip)) {
2444 setLWResult(res, 0, false, false, true);
2445 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2446 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2447 return 1;
2448 } else if (ip == ns) {
2449
2450 setLWResult(res, 0, true, false, true);
2451 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2452 return 1;
2453 }
2454
2455 return 0;
2456 });
2457
2458 DNSFilterEngine::Policy pol;
2459 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
2460 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2461 zone->setName("Unit test policy 0");
2462 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2463 zone->addNSTrigger(nsName, pol);
2464 auto luaconfsCopy = g_luaconfs.getCopy();
2465 luaconfsCopy.dfe.addZone(zone);
2466 g_luaconfs.setState(luaconfsCopy);
2467
2468 /* RPZ is disabled for this query, we should not be blocked */
2469 sr->setWantsRPZ(false);
2470
2471 vector<DNSRecord> ret;
2472 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2473 BOOST_CHECK_EQUAL(res, RCode::NoError);
2474 BOOST_CHECK_EQUAL(ret.size(), 1);
2475 }
2476
2477 BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2478 std::unique_ptr<SyncRes> sr;
2479 initSR(sr);
2480
2481 primeHints();
2482
2483 const DNSName target("powerdns.com.");
2484 const ComboAddress ns("192.0.2.1:53");
2485 const ComboAddress forwardedNS("192.0.2.42:53");
2486
2487 SyncRes::AuthDomain ad;
2488 ad.d_rdForward = false;
2489 ad.d_servers.push_back(forwardedNS);
2490 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2491
2492 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) {
2493
2494 if (ip == forwardedNS) {
2495 BOOST_CHECK_EQUAL(sendRDQuery, false);
2496
2497 setLWResult(res, 0, true, false, true);
2498 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2499 return 1;
2500 }
2501
2502 return 0;
2503 });
2504
2505 /* simulate a no-RD query */
2506 sr->setCacheOnly();
2507
2508 vector<DNSRecord> ret;
2509 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2510 BOOST_CHECK_EQUAL(res, RCode::NoError);
2511 BOOST_CHECK_EQUAL(ret.size(), 1);
2512 }
2513
2514 BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
2515 std::unique_ptr<SyncRes> sr;
2516 initSR(sr);
2517
2518 primeHints();
2519
2520 const DNSName target("powerdns.com.");
2521 const ComboAddress ns("192.0.2.1:53");
2522 const ComboAddress forwardedNS("192.0.2.42:53");
2523
2524 SyncRes::AuthDomain ad;
2525 ad.d_rdForward = false;
2526 ad.d_servers.push_back(forwardedNS);
2527 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2528
2529 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) {
2530
2531 if (ip == forwardedNS) {
2532 BOOST_CHECK_EQUAL(sendRDQuery, false);
2533
2534 setLWResult(res, 0, true, false, true);
2535 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2536 return 1;
2537 }
2538
2539 return 0;
2540 });
2541
2542 vector<DNSRecord> ret;
2543 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2544 BOOST_CHECK_EQUAL(res, RCode::NoError);
2545 BOOST_CHECK_EQUAL(ret.size(), 1);
2546 }
2547
2548 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
2549 std::unique_ptr<SyncRes> sr;
2550 initSR(sr);
2551
2552 primeHints();
2553
2554 const DNSName target("powerdns.com.");
2555 const ComboAddress ns("192.0.2.1:53");
2556 const ComboAddress forwardedNS("192.0.2.42:53");
2557
2558 SyncRes::AuthDomain ad;
2559 ad.d_rdForward = true;
2560 ad.d_servers.push_back(forwardedNS);
2561 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2562
2563 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) {
2564
2565 if (ip == forwardedNS) {
2566 BOOST_CHECK_EQUAL(sendRDQuery, false);
2567
2568 setLWResult(res, 0, true, false, true);
2569 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2570 return 1;
2571 }
2572
2573 return 0;
2574 });
2575
2576 /* simulate a no-RD query */
2577 sr->setCacheOnly();
2578
2579 vector<DNSRecord> ret;
2580 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2581 BOOST_CHECK_EQUAL(res, RCode::NoError);
2582 BOOST_CHECK_EQUAL(ret.size(), 1);
2583 }
2584
2585 BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
2586 std::unique_ptr<SyncRes> sr;
2587 initSR(sr);
2588
2589 primeHints();
2590
2591 const DNSName target("powerdns.com.");
2592 const ComboAddress ns("192.0.2.1:53");
2593 const ComboAddress forwardedNS("192.0.2.42:53");
2594
2595 SyncRes::AuthDomain ad;
2596 ad.d_rdForward = true;
2597 ad.d_servers.push_back(forwardedNS);
2598 (*SyncRes::t_sstorage.domainmap)[target] = ad;
2599
2600 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) {
2601
2602 if (ip == forwardedNS) {
2603 BOOST_CHECK_EQUAL(sendRDQuery, true);
2604
2605 setLWResult(res, 0, true, false, true);
2606 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2607 return 1;
2608 }
2609
2610 return 0;
2611 });
2612
2613 vector<DNSRecord> ret;
2614 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2615 BOOST_CHECK_EQUAL(res, RCode::NoError);
2616 BOOST_CHECK_EQUAL(ret.size(), 1);
2617 }
2618
2619 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_oob) {
2620 std::unique_ptr<SyncRes> sr;
2621 init();
2622 initSR(sr, true, false);
2623
2624 primeHints();
2625
2626 size_t queriesCount = 0;
2627 const DNSName target("test.xx.");
2628 const ComboAddress targetAddr("127.0.0.1");
2629 const DNSName ns("localhost.");
2630 const ComboAddress nsAddr("127.0.0.1");
2631 const DNSName authZone("test.xx");
2632
2633 SyncRes::AuthDomain ad;
2634 DNSRecord dr;
2635 dr.d_place = DNSResourceRecord::ANSWER;
2636 dr.d_name = authZone;
2637 dr.d_type = QType::NS;
2638 dr.d_ttl = 1800;
2639 dr.d_content = std::make_shared<NSRecordContent>("localhost.");
2640 ad.d_records.insert(dr);
2641
2642 dr.d_place = DNSResourceRecord::ANSWER;
2643 dr.d_name = authZone;
2644 dr.d_type = QType::A;
2645 dr.d_ttl = 1800;
2646 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
2647 ad.d_records.insert(dr);
2648
2649 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2650
2651 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) {
2652 queriesCount++;
2653 return 0;
2654 });
2655
2656 vector<DNSRecord> ret;
2657 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2658 BOOST_CHECK_EQUAL(res, 0);
2659 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2660 BOOST_CHECK(ret[0].d_type == QType::A);
2661 BOOST_CHECK_EQUAL(queriesCount, 0);
2662 BOOST_CHECK(sr->wasOutOfBand());
2663
2664 /* a second time, to check that the OOB flag is set when the query cache is used */
2665 ret.clear();
2666 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2667 BOOST_CHECK_EQUAL(res, 0);
2668 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2669 BOOST_CHECK(ret[0].d_type == QType::A);
2670 BOOST_CHECK_EQUAL(queriesCount, 0);
2671 BOOST_CHECK(sr->wasOutOfBand());
2672 }
2673
2674 BOOST_AUTO_TEST_CASE(test_auth_zone) {
2675 std::unique_ptr<SyncRes> sr;
2676 initSR(sr);
2677
2678 primeHints();
2679
2680 size_t queriesCount = 0;
2681 const DNSName target("powerdns.com.");
2682 const ComboAddress addr("192.0.2.5");
2683
2684 SyncRes::AuthDomain ad;
2685 ad.d_name = target;
2686 DNSRecord dr;
2687 dr.d_place = DNSResourceRecord::ANSWER;
2688 dr.d_name = target;
2689 dr.d_type = QType::SOA;
2690 dr.d_ttl = 3600;
2691 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2692 ad.d_records.insert(dr);
2693
2694 dr.d_place = DNSResourceRecord::ANSWER;
2695 dr.d_name = target;
2696 dr.d_type = QType::A;
2697 dr.d_ttl = 3600;
2698 dr.d_content = std::make_shared<ARecordContent>(addr);
2699 ad.d_records.insert(dr);
2700
2701 auto map = std::make_shared<SyncRes::domainmap_t>();
2702 (*map)[target] = ad;
2703 SyncRes::setDomainMap(map);
2704
2705 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) {
2706
2707 queriesCount++;
2708 setLWResult(res, 0, true, false, true);
2709 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2710 return 1;
2711 });
2712
2713 vector<DNSRecord> ret;
2714 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2715 BOOST_CHECK_EQUAL(res, RCode::NoError);
2716 BOOST_CHECK_EQUAL(ret.size(), 1);
2717 BOOST_CHECK(ret[0].d_type == QType::A);
2718 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
2719 BOOST_CHECK_EQUAL(queriesCount, 0);
2720 }
2721
2722 BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
2723 std::unique_ptr<SyncRes> sr;
2724 initSR(sr);
2725
2726 primeHints();
2727
2728 size_t queriesCount = 0;
2729 const DNSName target("powerdns.com.");
2730 const DNSName authZone("internal.powerdns.com.");
2731 const ComboAddress addr("192.0.2.5");
2732
2733 SyncRes::AuthDomain ad;
2734 ad.d_name = authZone;
2735 DNSRecord dr;
2736 dr.d_place = DNSResourceRecord::ANSWER;
2737 dr.d_name = authZone;
2738 dr.d_type = QType::SOA;
2739 dr.d_ttl = 3600;
2740 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2741 ad.d_records.insert(dr);
2742
2743 dr.d_place = DNSResourceRecord::ANSWER;
2744 dr.d_name = authZone;
2745 dr.d_type = QType::A;
2746 dr.d_ttl = 3600;
2747 dr.d_content = std::make_shared<ARecordContent>(addr);
2748 ad.d_records.insert(dr);
2749
2750 auto map = std::make_shared<SyncRes::domainmap_t>();
2751 (*map)[authZone] = ad;
2752 SyncRes::setDomainMap(map);
2753
2754 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) {
2755
2756 queriesCount++;
2757
2758 if (domain == target) {
2759 setLWResult(res, 0, true, false, true);
2760 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
2761 return 1;
2762 }
2763
2764 return 0;
2765 });
2766
2767 vector<DNSRecord> ret;
2768 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2769 BOOST_CHECK_EQUAL(res, RCode::NoError);
2770 BOOST_CHECK_EQUAL(ret.size(), 2);
2771 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2772 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
2773 BOOST_CHECK(ret[1].d_type == QType::A);
2774 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
2775 BOOST_CHECK_EQUAL(queriesCount, 1);
2776 }
2777
2778 BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
2779 std::unique_ptr<SyncRes> sr;
2780 initSR(sr);
2781
2782 primeHints();
2783
2784 size_t queriesCount = 0;
2785 const DNSName target("powerdns.com.");
2786 const DNSName externalCNAME("www.open-xchange.com.");
2787 const ComboAddress addr("192.0.2.5");
2788
2789 SyncRes::AuthDomain ad;
2790 ad.d_name = target;
2791 DNSRecord dr;
2792 dr.d_place = DNSResourceRecord::ANSWER;
2793 dr.d_name = target;
2794 dr.d_type = QType::SOA;
2795 dr.d_ttl = 3600;
2796 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2797 ad.d_records.insert(dr);
2798
2799 dr.d_place = DNSResourceRecord::ANSWER;
2800 dr.d_name = target;
2801 dr.d_type = QType::CNAME;
2802 dr.d_ttl = 3600;
2803 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
2804 ad.d_records.insert(dr);
2805
2806 auto map = std::make_shared<SyncRes::domainmap_t>();
2807 (*map)[target] = ad;
2808 SyncRes::setDomainMap(map);
2809
2810 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) {
2811
2812 queriesCount++;
2813
2814 if (domain == externalCNAME) {
2815 setLWResult(res, 0, true, false, true);
2816 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
2817 return 1;
2818 }
2819
2820 return 0;
2821 });
2822
2823 vector<DNSRecord> ret;
2824 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2825 BOOST_CHECK_EQUAL(res, RCode::NoError);
2826 BOOST_CHECK_EQUAL(ret.size(), 2);
2827 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2828 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
2829 BOOST_CHECK(ret[1].d_type == QType::A);
2830 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
2831 BOOST_CHECK_EQUAL(queriesCount, 1);
2832 }
2833
2834 BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
2835 std::unique_ptr<SyncRes> sr;
2836 initSR(sr);
2837
2838 primeHints();
2839
2840 size_t queriesCount = 0;
2841 const DNSName target("nodata.powerdns.com.");
2842 const DNSName authZone("powerdns.com");
2843
2844 SyncRes::AuthDomain ad;
2845 ad.d_name = authZone;
2846 DNSRecord dr;
2847 dr.d_place = DNSResourceRecord::ANSWER;
2848 dr.d_name = target;
2849 dr.d_type = QType::A;
2850 dr.d_ttl = 3600;
2851 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
2852 ad.d_records.insert(dr);
2853
2854 dr.d_place = DNSResourceRecord::ANSWER;
2855 dr.d_name = authZone;
2856 dr.d_type = QType::SOA;
2857 dr.d_ttl = 3600;
2858 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2859 ad.d_records.insert(dr);
2860
2861 auto map = std::make_shared<SyncRes::domainmap_t>();
2862 (*map)[authZone] = ad;
2863 SyncRes::setDomainMap(map);
2864
2865 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) {
2866
2867 queriesCount++;
2868
2869 return 0;
2870 });
2871
2872 vector<DNSRecord> ret;
2873 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
2874 BOOST_CHECK_EQUAL(res, RCode::NoError);
2875 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2876 BOOST_CHECK(ret[0].d_type == QType::SOA);
2877 BOOST_CHECK_EQUAL(queriesCount, 0);
2878 }
2879
2880 BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
2881 std::unique_ptr<SyncRes> sr;
2882 initSR(sr);
2883
2884 primeHints();
2885
2886 size_t queriesCount = 0;
2887 const DNSName target("nx.powerdns.com.");
2888 const DNSName authZone("powerdns.com");
2889
2890 SyncRes::AuthDomain ad;
2891 ad.d_name = authZone;
2892 DNSRecord dr;
2893 dr.d_place = DNSResourceRecord::ANSWER;
2894 dr.d_name = DNSName("powerdns.com.");
2895 dr.d_type = QType::SOA;
2896 dr.d_ttl = 3600;
2897 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2898 ad.d_records.insert(dr);
2899
2900 auto map = std::make_shared<SyncRes::domainmap_t>();
2901 (*map)[authZone] = ad;
2902 SyncRes::setDomainMap(map);
2903
2904 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) {
2905
2906 queriesCount++;
2907
2908 return 0;
2909 });
2910
2911 vector<DNSRecord> ret;
2912 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2913 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2914 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2915 BOOST_CHECK(ret[0].d_type == QType::SOA);
2916 BOOST_CHECK_EQUAL(queriesCount, 0);
2917 }
2918
2919 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
2920 std::unique_ptr<SyncRes> sr;
2921 initSR(sr);
2922
2923 primeHints();
2924
2925 size_t queriesCount = 0;
2926 const DNSName target("www.test.powerdns.com.");
2927 const ComboAddress targetAddr("192.0.2.2");
2928 const DNSName ns("ns1.test.powerdns.com.");
2929 const ComboAddress nsAddr("192.0.2.1");
2930 const DNSName authZone("powerdns.com");
2931
2932 SyncRes::AuthDomain ad;
2933 ad.d_name = authZone;
2934 DNSRecord dr;
2935 dr.d_place = DNSResourceRecord::ANSWER;
2936 dr.d_name = authZone;
2937 dr.d_type = QType::SOA;
2938 dr.d_ttl = 3600;
2939 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2940 ad.d_records.insert(dr);
2941
2942 dr.d_place = DNSResourceRecord::ANSWER;
2943 dr.d_name = DNSName("test.powerdns.com.");
2944 dr.d_type = QType::NS;
2945 dr.d_ttl = 3600;
2946 dr.d_content = std::make_shared<NSRecordContent>(ns);
2947 ad.d_records.insert(dr);
2948
2949 dr.d_place = DNSResourceRecord::ANSWER;
2950 dr.d_name = ns;
2951 dr.d_type = QType::A;
2952 dr.d_ttl = 3600;
2953 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
2954 ad.d_records.insert(dr);
2955
2956 auto map = std::make_shared<SyncRes::domainmap_t>();
2957 (*map)[authZone] = ad;
2958 SyncRes::setDomainMap(map);
2959
2960 sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2961
2962 queriesCount++;
2963 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
2964 setLWResult(res, 0, true, false, true);
2965 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
2966 return 1;
2967 }
2968
2969 return 0;
2970 });
2971
2972 vector<DNSRecord> ret;
2973 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2974 BOOST_CHECK_EQUAL(res, RCode::NoError);
2975 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2976 BOOST_CHECK(ret[0].d_type == QType::A);
2977 BOOST_CHECK_EQUAL(queriesCount, 1);
2978 }
2979
2980 BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
2981 std::unique_ptr<SyncRes> sr;
2982 initSR(sr);
2983
2984 primeHints();
2985
2986 size_t queriesCount = 0;
2987 const DNSName target("test.powerdns.com.");
2988 const ComboAddress targetAddr("192.0.2.2");
2989 const DNSName ns("ns1.test.powerdns.com.");
2990 const ComboAddress nsAddr("192.0.2.1");
2991 const DNSName authZone("powerdns.com");
2992
2993 SyncRes::AuthDomain ad;
2994 ad.d_name = authZone;
2995 DNSRecord dr;
2996 dr.d_place = DNSResourceRecord::ANSWER;
2997 dr.d_name = authZone;
2998 dr.d_type = QType::SOA;
2999 dr.d_ttl = 3600;
3000 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3001 ad.d_records.insert(dr);
3002
3003 dr.d_place = DNSResourceRecord::ANSWER;
3004 dr.d_name = DNSName("test.powerdns.com.");
3005 dr.d_type = QType::NS;
3006 dr.d_ttl = 3600;
3007 dr.d_content = std::make_shared<NSRecordContent>(ns);
3008 ad.d_records.insert(dr);
3009
3010 dr.d_place = DNSResourceRecord::ANSWER;
3011 dr.d_name = ns;
3012 dr.d_type = QType::A;
3013 dr.d_ttl = 3600;
3014 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3015 ad.d_records.insert(dr);
3016
3017 auto map = std::make_shared<SyncRes::domainmap_t>();
3018 (*map)[authZone] = ad;
3019 SyncRes::setDomainMap(map);
3020
3021 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) {
3022
3023 queriesCount++;
3024
3025 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3026 setLWResult(res, 0, true, false, true);
3027 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3028 return 1;
3029 }
3030
3031 return 0;
3032 });
3033
3034 vector<DNSRecord> ret;
3035 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3036 BOOST_CHECK_EQUAL(res, RCode::NoError);
3037 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3038 BOOST_CHECK(ret[0].d_type == QType::A);
3039 BOOST_CHECK_EQUAL(queriesCount, 1);
3040 }
3041
3042 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3043 std::unique_ptr<SyncRes> sr;
3044 initSR(sr);
3045
3046 primeHints();
3047
3048 size_t queriesCount = 0;
3049 const DNSName target("test.powerdns.com.");
3050 const ComboAddress targetAddr("192.0.2.2");
3051 const DNSName authZone("powerdns.com");
3052
3053 SyncRes::AuthDomain ad;
3054 ad.d_name = authZone;
3055 DNSRecord dr;
3056 dr.d_place = DNSResourceRecord::ANSWER;
3057 dr.d_name = authZone;
3058 dr.d_type = QType::SOA;
3059 dr.d_ttl = 3600;
3060 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3061 ad.d_records.insert(dr);
3062
3063 dr.d_place = DNSResourceRecord::ANSWER;
3064 dr.d_name = DNSName("*.powerdns.com.");
3065 dr.d_type = QType::A;
3066 dr.d_ttl = 3600;
3067 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3068 ad.d_records.insert(dr);
3069
3070 auto map = std::make_shared<SyncRes::domainmap_t>();
3071 (*map)[authZone] = ad;
3072 SyncRes::setDomainMap(map);
3073
3074 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) {
3075
3076 queriesCount++;
3077
3078 return 0;
3079 });
3080
3081 vector<DNSRecord> ret;
3082 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3083 BOOST_CHECK_EQUAL(res, RCode::NoError);
3084 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3085 BOOST_CHECK(ret[0].d_type == QType::A);
3086 BOOST_CHECK_EQUAL(queriesCount, 0);
3087 }
3088
3089 BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3090 std::unique_ptr<SyncRes> sr;
3091 initSR(sr);
3092
3093 primeHints();
3094
3095 size_t queriesCount = 0;
3096 const DNSName target("test.powerdns.com.");
3097 const ComboAddress targetAddr("192.0.2.2");
3098 const DNSName authZone("powerdns.com");
3099
3100 SyncRes::AuthDomain ad;
3101 ad.d_name = authZone;
3102 DNSRecord dr;
3103 dr.d_place = DNSResourceRecord::ANSWER;
3104 dr.d_name = authZone;
3105 dr.d_type = QType::SOA;
3106 dr.d_ttl = 3600;
3107 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3108 ad.d_records.insert(dr);
3109
3110 dr.d_place = DNSResourceRecord::ANSWER;
3111 dr.d_name = DNSName("*.powerdns.com.");
3112 dr.d_type = QType::A;
3113 dr.d_ttl = 3600;
3114 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3115 ad.d_records.insert(dr);
3116
3117 auto map = std::make_shared<SyncRes::domainmap_t>();
3118 (*map)[authZone] = ad;
3119 SyncRes::setDomainMap(map);
3120
3121 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) {
3122
3123 queriesCount++;
3124
3125 return 0;
3126 });
3127
3128 vector<DNSRecord> ret;
3129 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
3130 BOOST_CHECK_EQUAL(res, RCode::NoError);
3131 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3132 BOOST_CHECK(ret[0].d_type == QType::SOA);
3133 BOOST_CHECK_EQUAL(queriesCount, 0);
3134 }
3135
3136 BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3137 std::unique_ptr<SyncRes> sr;
3138 initSR(sr);
3139
3140 primeHints();
3141
3142 size_t queriesCount = 0;
3143 const DNSName target("powerdns.com.");
3144 const ComboAddress addr("192.0.2.5");
3145
3146 SyncRes::AuthDomain ad;
3147 ad.d_name = target;
3148 DNSRecord dr;
3149 dr.d_place = DNSResourceRecord::ANSWER;
3150 dr.d_name = target;
3151 dr.d_type = QType::SOA;
3152 dr.d_ttl = 3600;
3153 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3154 ad.d_records.insert(dr);
3155
3156 dr.d_place = DNSResourceRecord::ANSWER;
3157 dr.d_name = target;
3158 dr.d_type = QType::A;
3159 dr.d_ttl = 3600;
3160 dr.d_content = std::make_shared<ARecordContent>(addr);
3161 ad.d_records.insert(dr);
3162
3163 auto map = std::make_shared<SyncRes::domainmap_t>();
3164 (*map)[target] = ad;
3165 SyncRes::setDomainMap(map);
3166
3167 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) {
3168
3169 queriesCount++;
3170 setLWResult(res, 0, true, false, true);
3171 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3172 return 1;
3173 });
3174
3175 /* simulate a no-RD query */
3176 sr->setCacheOnly();
3177
3178 vector<DNSRecord> ret;
3179 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3180 BOOST_CHECK_EQUAL(res, RCode::NoError);
3181 BOOST_CHECK_EQUAL(ret.size(), 1);
3182 BOOST_CHECK(ret[0].d_type == QType::A);
3183 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3184 BOOST_CHECK_EQUAL(queriesCount, 0);
3185 }
3186
3187 BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
3188 init();
3189
3190 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3191 dcke->create(dcke->getBits());
3192 // cerr<<dcke->convertToISC()<<endl;
3193 DNSSECPrivateKey dpk;
3194 dpk.d_flags = 256;
3195 dpk.setKey(dcke);
3196
3197 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3198 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3199
3200 DNSName qname("powerdns.com.");
3201
3202 time_t now = time(nullptr);
3203 RRSIGRecordContent rrc;
3204 /* this RRSIG is valid for the current second only */
3205 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
3206
3207 skeyset_t keyset;
3208 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3209
3210 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3211 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3212
3213 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
3214 }
3215
3216 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3217 std::unique_ptr<SyncRes> sr;
3218 initSR(sr, true);
3219
3220 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3221
3222 primeHints();
3223 const DNSName target(".");
3224 testkeysset_t keys;
3225
3226 auto luaconfsCopy = g_luaconfs.getCopy();
3227 luaconfsCopy.dsAnchors.clear();
3228 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3229 g_luaconfs.setState(luaconfsCopy);
3230
3231 size_t queriesCount = 0;
3232
3233 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) {
3234 queriesCount++;
3235
3236 if (domain == target && type == QType::NS) {
3237
3238 setLWResult(res, 0, true, false, true);
3239 char addr[] = "a.root-servers.net.";
3240 for (char idx = 'a'; idx <= 'm'; idx++) {
3241 addr[0] = idx;
3242 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3243 }
3244
3245 addRRSIG(keys, res->d_records, domain, 300);
3246
3247 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3248 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3249
3250 return 1;
3251 } else if (domain == target && type == QType::DNSKEY) {
3252
3253 setLWResult(res, 0, true, false, true);
3254
3255 addDNSKEY(keys, domain, 300, res->d_records);
3256 addRRSIG(keys, res->d_records, domain, 300);
3257
3258 return 1;
3259 }
3260
3261 return 0;
3262 });
3263
3264 vector<DNSRecord> ret;
3265 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3266 BOOST_CHECK_EQUAL(res, RCode::NoError);
3267 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3268 /* 13 NS + 1 RRSIG */
3269 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3270 BOOST_CHECK_EQUAL(queriesCount, 2);
3271
3272 /* again, to test the cache */
3273 ret.clear();
3274 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3275 BOOST_CHECK_EQUAL(res, RCode::NoError);
3276 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3277 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3278 BOOST_CHECK_EQUAL(queriesCount, 2);
3279 }
3280
3281 BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3282 std::unique_ptr<SyncRes> sr;
3283 initSR(sr, true);
3284
3285 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3286
3287 primeHints();
3288 const DNSName target(".");
3289 testkeysset_t zskeys;
3290 testkeysset_t kskeys;
3291
3292 /* Generate key material for "." */
3293 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3294 dckeZ->create(dckeZ->getBits());
3295 DNSSECPrivateKey ksk;
3296 ksk.d_flags = 257;
3297 ksk.setKey(dckeZ);
3298 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3299
3300 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3301 dckeK->create(dckeK->getBits());
3302 DNSSECPrivateKey zsk;
3303 zsk.d_flags = 256;
3304 zsk.setKey(dckeK);
3305 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
3306
3307 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3308 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
3309
3310 /* Set the root DS */
3311 auto luaconfsCopy = g_luaconfs.getCopy();
3312 luaconfsCopy.dsAnchors.clear();
3313 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
3314 g_luaconfs.setState(luaconfsCopy);
3315
3316 size_t queriesCount = 0;
3317
3318 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) {
3319 queriesCount++;
3320
3321 if (domain == target && type == QType::NS) {
3322
3323 setLWResult(res, 0, true, false, true);
3324 char addr[] = "a.root-servers.net.";
3325 for (char idx = 'a'; idx <= 'm'; idx++) {
3326 addr[0] = idx;
3327 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3328 }
3329
3330 addRRSIG(zskeys, res->d_records, domain, 300);
3331
3332 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3333 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3334
3335 return 1;
3336 } else if (domain == target && type == QType::DNSKEY) {
3337
3338 setLWResult(res, 0, true, false, true);
3339
3340 addDNSKEY(kskeys, domain, 300, res->d_records);
3341 addDNSKEY(zskeys, domain, 300, res->d_records);
3342 addRRSIG(kskeys, res->d_records, domain, 300);
3343
3344 return 1;
3345 }
3346
3347 return 0;
3348 });
3349
3350 vector<DNSRecord> ret;
3351 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3352 BOOST_CHECK_EQUAL(res, RCode::NoError);
3353 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3354 /* 13 NS + 1 RRSIG */
3355 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3356 BOOST_CHECK_EQUAL(queriesCount, 2);
3357
3358 /* again, to test the cache */
3359 ret.clear();
3360 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3361 BOOST_CHECK_EQUAL(res, RCode::NoError);
3362 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
3363 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3364 BOOST_CHECK_EQUAL(queriesCount, 2);
3365 }
3366
3367 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
3368 std::unique_ptr<SyncRes> sr;
3369 initSR(sr, true);
3370
3371 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3372
3373 primeHints();
3374 const DNSName target(".");
3375 testkeysset_t keys;
3376
3377 auto luaconfsCopy = g_luaconfs.getCopy();
3378 luaconfsCopy.dsAnchors.clear();
3379 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3380 g_luaconfs.setState(luaconfsCopy);
3381
3382 size_t queriesCount = 0;
3383
3384 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) {
3385 queriesCount++;
3386
3387 if (domain == target && type == QType::NS) {
3388
3389 setLWResult(res, 0, true, false, true);
3390 char addr[] = "a.root-servers.net.";
3391 for (char idx = 'a'; idx <= 'm'; idx++) {
3392 addr[0] = idx;
3393 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3394 }
3395
3396 addRRSIG(keys, res->d_records, domain, 300);
3397
3398 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3399 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3400
3401 return 1;
3402 } else if (domain == target && type == QType::DNSKEY) {
3403
3404 setLWResult(res, 0, true, false, true);
3405
3406 /* No DNSKEY */
3407
3408 return 1;
3409 }
3410
3411 return 0;
3412 });
3413
3414 vector<DNSRecord> ret;
3415 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3416 BOOST_CHECK_EQUAL(res, RCode::NoError);
3417 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3418 /* 13 NS + 1 RRSIG */
3419 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3420 BOOST_CHECK_EQUAL(queriesCount, 2);
3421
3422 /* again, to test the cache */
3423 ret.clear();
3424 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3425 BOOST_CHECK_EQUAL(res, RCode::NoError);
3426 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3427 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3428 BOOST_CHECK_EQUAL(queriesCount, 2);
3429 }
3430
3431 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3432 std::unique_ptr<SyncRes> sr;
3433 initSR(sr, true);
3434
3435 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3436
3437 primeHints();
3438 const DNSName target(".");
3439 testkeysset_t dskeys;
3440 testkeysset_t keys;
3441
3442 /* Generate key material for "." */
3443 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3444 dckeDS->create(dckeDS->getBits());
3445 DNSSECPrivateKey dskey;
3446 dskey.d_flags = 257;
3447 dskey.setKey(dckeDS);
3448 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3449
3450 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3451 dcke->create(dcke->getBits());
3452 DNSSECPrivateKey dpk;
3453 dpk.d_flags = 256;
3454 dpk.setKey(dcke);
3455 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3456
3457 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3458 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
3459
3460 /* Set the root DS */
3461 auto luaconfsCopy = g_luaconfs.getCopy();
3462 luaconfsCopy.dsAnchors.clear();
3463 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3464 g_luaconfs.setState(luaconfsCopy);
3465
3466 size_t queriesCount = 0;
3467
3468 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) {
3469 queriesCount++;
3470
3471 if (domain == target && type == QType::NS) {
3472
3473 setLWResult(res, 0, true, false, true);
3474 char addr[] = "a.root-servers.net.";
3475 for (char idx = 'a'; idx <= 'm'; idx++) {
3476 addr[0] = idx;
3477 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3478 }
3479
3480 addRRSIG(keys, res->d_records, domain, 300);
3481
3482 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3483 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3484
3485 return 1;
3486 } else if (domain == target && type == QType::DNSKEY) {
3487
3488 setLWResult(res, 0, true, false, true);
3489
3490 addDNSKEY(keys, domain, 300, res->d_records);
3491 addRRSIG(keys, res->d_records, domain, 300);
3492
3493 return 1;
3494 }
3495
3496 return 0;
3497 });
3498
3499 vector<DNSRecord> ret;
3500 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3501 BOOST_CHECK_EQUAL(res, RCode::NoError);
3502 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3503 /* 13 NS + 1 RRSIG */
3504 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3505 BOOST_CHECK_EQUAL(queriesCount, 2);
3506
3507 /* again, to test the cache */
3508 ret.clear();
3509 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3510 BOOST_CHECK_EQUAL(res, RCode::NoError);
3511 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3512 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3513 BOOST_CHECK_EQUAL(queriesCount, 2);
3514 }
3515
3516 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
3517 std::unique_ptr<SyncRes> sr;
3518 initSR(sr, true);
3519
3520 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3521
3522 primeHints();
3523 const DNSName target(".");
3524 testkeysset_t keys;
3525 testkeysset_t rrsigkeys;
3526
3527 auto luaconfsCopy = g_luaconfs.getCopy();
3528 luaconfsCopy.dsAnchors.clear();
3529 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3530 g_luaconfs.setState(luaconfsCopy);
3531
3532 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3533 dckeRRSIG->create(dckeRRSIG->getBits());
3534 DNSSECPrivateKey rrsigkey;
3535 rrsigkey.d_flags = 257;
3536 rrsigkey.setKey(dckeRRSIG);
3537 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
3538
3539 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
3540
3541 size_t queriesCount = 0;
3542
3543 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) {
3544 queriesCount++;
3545
3546 if (domain == target && type == QType::NS) {
3547
3548 setLWResult(res, 0, true, false, true);
3549 char addr[] = "a.root-servers.net.";
3550 for (char idx = 'a'; idx <= 'm'; idx++) {
3551 addr[0] = idx;
3552 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3553 }
3554
3555 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3556
3557 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3558 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3559
3560 return 1;
3561 } else if (domain == target && type == QType::DNSKEY) {
3562
3563 setLWResult(res, 0, true, false, true);
3564
3565 addDNSKEY(keys, domain, 300, res->d_records);
3566 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3567
3568 return 1;
3569 }
3570
3571 return 0;
3572 });
3573
3574 vector<DNSRecord> ret;
3575 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3576 BOOST_CHECK_EQUAL(res, RCode::NoError);
3577 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3578 /* 13 NS + 1 RRSIG */
3579 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3580 BOOST_CHECK_EQUAL(queriesCount, 2);
3581
3582 /* again, to test the cache */
3583 ret.clear();
3584 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3585 BOOST_CHECK_EQUAL(res, RCode::NoError);
3586 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3587 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3588 BOOST_CHECK_EQUAL(queriesCount, 2);
3589 }
3590
3591 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
3592 std::unique_ptr<SyncRes> sr;
3593 initSR(sr, true);
3594
3595 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3596
3597 primeHints();
3598 const DNSName target(".");
3599 testkeysset_t keys;
3600
3601 auto luaconfsCopy = g_luaconfs.getCopy();
3602 luaconfsCopy.dsAnchors.clear();
3603 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3604 g_luaconfs.setState(luaconfsCopy);
3605
3606 size_t queriesCount = 0;
3607
3608 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) {
3609 queriesCount++;
3610
3611 if (domain == target && type == QType::NS) {
3612
3613 setLWResult(res, 0, true, false, true);
3614 char addr[] = "a.root-servers.net.";
3615 for (char idx = 'a'; idx <= 'm'; idx++) {
3616 addr[0] = idx;
3617 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3618 }
3619
3620 /* No RRSIG */
3621
3622 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3623 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3624
3625 return 1;
3626 } else if (domain == target && type == QType::DNSKEY) {
3627
3628 setLWResult(res, 0, true, false, true);
3629
3630 addDNSKEY(keys, domain, 300, res->d_records);
3631 addRRSIG(keys, res->d_records, domain, 300);
3632
3633 return 1;
3634 }
3635
3636 return 0;
3637 });
3638
3639 vector<DNSRecord> ret;
3640 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3641 BOOST_CHECK_EQUAL(res, RCode::NoError);
3642 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3643 /* 13 NS + 0 RRSIG */
3644 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3645 /* no RRSIG so no query for DNSKEYs */
3646 BOOST_CHECK_EQUAL(queriesCount, 1);
3647
3648 /* again, to test the cache */
3649 ret.clear();
3650 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3651 BOOST_CHECK_EQUAL(res, RCode::NoError);
3652 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3653 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3654 BOOST_CHECK_EQUAL(queriesCount, 1);
3655 }
3656
3657 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
3658 std::unique_ptr<SyncRes> sr;
3659 initSR(sr, true);
3660
3661 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3662
3663 primeHints();
3664 const DNSName target(".");
3665 testkeysset_t keys;
3666
3667 /* Generate key material for "." */
3668 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3669 dcke->create(dcke->getBits());
3670 DNSSECPrivateKey dpk;
3671 dpk.d_flags = 256;
3672 dpk.setKey(dcke);
3673 /* Fake algorithm number (private) */
3674 dpk.d_algorithm = 253;
3675
3676 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3677 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
3678 /* Fake algorithm number (private) */
3679 drc.d_algorithm = 253;
3680
3681 /* Set the root DS */
3682 auto luaconfsCopy = g_luaconfs.getCopy();
3683 luaconfsCopy.dsAnchors.clear();
3684 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3685 g_luaconfs.setState(luaconfsCopy);
3686
3687 size_t queriesCount = 0;
3688
3689 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) {
3690 queriesCount++;
3691
3692 if (domain == target && type == QType::NS) {
3693
3694 setLWResult(res, 0, true, false, true);
3695 char addr[] = "a.root-servers.net.";
3696 for (char idx = 'a'; idx <= 'm'; idx++) {
3697 addr[0] = idx;
3698 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3699 }
3700
3701 addRRSIG(keys, res->d_records, domain, 300);
3702
3703 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3704 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3705
3706 return 1;
3707 } else if (domain == target && type == QType::DNSKEY) {
3708
3709 setLWResult(res, 0, true, false, true);
3710
3711 addDNSKEY(keys, domain, 300, res->d_records);
3712 addRRSIG(keys, res->d_records, domain, 300);
3713
3714 return 1;
3715 }
3716
3717 return 0;
3718 });
3719
3720 vector<DNSRecord> ret;
3721 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3722 BOOST_CHECK_EQUAL(res, RCode::NoError);
3723 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3724 /* 13 NS + 1 RRSIG */
3725 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3726 /* no supported DS so no query for DNSKEYs */
3727 BOOST_CHECK_EQUAL(queriesCount, 1);
3728
3729 /* again, to test the cache */
3730 ret.clear();
3731 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3732 BOOST_CHECK_EQUAL(res, RCode::NoError);
3733 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3734 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3735 BOOST_CHECK_EQUAL(queriesCount, 1);
3736 }
3737
3738 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
3739 std::unique_ptr<SyncRes> sr;
3740 initSR(sr, true);
3741
3742 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3743
3744 primeHints();
3745 const DNSName target(".");
3746 testkeysset_t keys;
3747
3748 /* Generate key material for "." */
3749 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3750 dcke->create(dcke->getBits());
3751 DNSSECPrivateKey dpk;
3752 dpk.d_flags = 256;
3753 dpk.setKey(dcke);
3754 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3755 /* Fake digest number (reserved) */
3756 drc.d_digesttype = 0;
3757
3758 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
3759
3760 /* Set the root DS */
3761 auto luaconfsCopy = g_luaconfs.getCopy();
3762 luaconfsCopy.dsAnchors.clear();
3763 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3764 g_luaconfs.setState(luaconfsCopy);
3765
3766 size_t queriesCount = 0;
3767
3768 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) {
3769 queriesCount++;
3770
3771 if (domain == target && type == QType::NS) {
3772
3773 setLWResult(res, 0, true, false, true);
3774 char addr[] = "a.root-servers.net.";
3775 for (char idx = 'a'; idx <= 'm'; idx++) {
3776 addr[0] = idx;
3777 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3778 }
3779
3780 addRRSIG(keys, res->d_records, domain, 300);
3781
3782 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3783 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3784
3785 return 1;
3786 } else if (domain == target && type == QType::DNSKEY) {
3787
3788 setLWResult(res, 0, true, false, true);
3789
3790 addDNSKEY(keys, domain, 300, res->d_records);
3791 addRRSIG(keys, res->d_records, domain, 300);
3792
3793 return 1;
3794 }
3795
3796 return 0;
3797 });
3798
3799 vector<DNSRecord> ret;
3800 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3801 BOOST_CHECK_EQUAL(res, RCode::NoError);
3802 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3803 /* 13 NS + 1 RRSIG */
3804 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3805 /* no supported DS so no query for DNSKEYs */
3806 BOOST_CHECK_EQUAL(queriesCount, 1);
3807
3808 /* again, to test the cache */
3809 ret.clear();
3810 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3811 BOOST_CHECK_EQUAL(res, RCode::NoError);
3812 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3813 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3814 BOOST_CHECK_EQUAL(queriesCount, 1);
3815 }
3816
3817 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
3818 std::unique_ptr<SyncRes> sr;
3819 initSR(sr, true);
3820
3821 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3822
3823 primeHints();
3824 const DNSName target(".");
3825 testkeysset_t keys;
3826
3827 auto luaconfsCopy = g_luaconfs.getCopy();
3828 luaconfsCopy.dsAnchors.clear();
3829 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3830
3831 g_luaconfs.setState(luaconfsCopy);
3832
3833 size_t queriesCount = 0;
3834
3835 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) {
3836 queriesCount++;
3837
3838 if (domain == target && type == QType::NS) {
3839
3840 setLWResult(res, 0, true, false, true);
3841 char addr[] = "a.root-servers.net.";
3842 for (char idx = 'a'; idx <= 'm'; idx++) {
3843 addr[0] = idx;
3844 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3845 }
3846
3847 addRRSIG(keys, res->d_records, domain, 300, true);
3848
3849 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3850 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3851
3852 return 1;
3853 } else if (domain == target && type == QType::DNSKEY) {
3854
3855 setLWResult(res, 0, true, false, true);
3856
3857 addDNSKEY(keys, domain, 300, res->d_records);
3858 addRRSIG(keys, res->d_records, domain, 300);
3859
3860 return 1;
3861 }
3862
3863 return 0;
3864 });
3865
3866 vector<DNSRecord> ret;
3867 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3868 BOOST_CHECK_EQUAL(res, RCode::NoError);
3869 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3870 /* 13 NS + 1 RRSIG */
3871 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3872 BOOST_CHECK_EQUAL(queriesCount, 2);
3873
3874 /* again, to test the cache */
3875 ret.clear();
3876 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3877 BOOST_CHECK_EQUAL(res, RCode::NoError);
3878 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3879 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3880 BOOST_CHECK_EQUAL(queriesCount, 2);
3881 }
3882
3883 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
3884 std::unique_ptr<SyncRes> sr;
3885 initSR(sr, true);
3886
3887 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3888
3889 primeHints();
3890 const DNSName target(".");
3891 testkeysset_t keys;
3892
3893 auto luaconfsCopy = g_luaconfs.getCopy();
3894 luaconfsCopy.dsAnchors.clear();
3895 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3896
3897 g_luaconfs.setState(luaconfsCopy);
3898
3899 size_t queriesCount = 0;
3900
3901 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) {
3902 queriesCount++;
3903
3904 if (domain == target && type == QType::NS) {
3905
3906 setLWResult(res, 0, true, false, true);
3907 char addr[] = "a.root-servers.net.";
3908 for (char idx = 'a'; idx <= 'm'; idx++) {
3909 addr[0] = idx;
3910 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3911 }
3912
3913 /* FORCE WRONG ALGO */
3914 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
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 + 1 RRSIG */
3938 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3939 BOOST_CHECK_EQUAL(queriesCount, 2);
3940
3941 /* again, to test the cache */
3942 ret.clear();
3943 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3944 BOOST_CHECK_EQUAL(res, RCode::NoError);
3945 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3946 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3947 BOOST_CHECK_EQUAL(queriesCount, 2);
3948 }
3949
3950 BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
3951 std::unique_ptr<SyncRes> sr;
3952 initSR(sr, true);
3953
3954 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3955
3956 primeHints();
3957 const DNSName target("powerdns.com.");
3958 const ComboAddress targetAddr("192.0.2.42");
3959 testkeysset_t keys;
3960
3961 auto luaconfsCopy = g_luaconfs.getCopy();
3962 luaconfsCopy.dsAnchors.clear();
3963 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3964 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3965 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
3966
3967 g_luaconfs.setState(luaconfsCopy);
3968
3969 size_t queriesCount = 0;
3970
3971 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) {
3972 queriesCount++;
3973
3974 DNSName auth = domain;
3975 if (domain == target) {
3976 auth = DNSName("powerdns.com.");
3977 }
3978 if (type == QType::DS) {
3979 return 0;
3980 }
3981 else if (type == QType::DNSKEY) {
3982 setLWResult(res, 0, true, false, true);
3983 addDNSKEY(keys, auth, 300, res->d_records);
3984 addRRSIG(keys, res->d_records, auth, 300);
3985 return 1;
3986 }
3987 else {
3988 if (isRootServer(ip)) {
3989 setLWResult(res, 0, false, false, true);
3990 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
3991 addDS(DNSName("com."), 300, res->d_records, keys);
3992 addRRSIG(keys, res->d_records, DNSName("."), 300);
3993 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
3994 return 1;
3995 }
3996 else if (ip == ComboAddress("192.0.2.1:53")) {
3997 if (domain == DNSName("com.")) {
3998 setLWResult(res, 0, true, false, true);
3999 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4000 addRRSIG(keys, res->d_records, domain, 300);
4001 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4002 addRRSIG(keys, res->d_records, domain, 300);
4003 }
4004 else {
4005 setLWResult(res, 0, false, false, true);
4006 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4007 addDS(auth, 300, res->d_records, keys);
4008 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4009 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4010 }
4011 return 1;
4012 }
4013 else if (ip == ComboAddress("192.0.2.2:53")) {
4014 if (type == QType::NS) {
4015 setLWResult(res, 0, true, false, true);
4016 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4017 addRRSIG(keys, res->d_records, auth, 300);
4018 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4019 addRRSIG(keys, res->d_records, auth, 300);
4020 }
4021 else {
4022 setLWResult(res, RCode::NoError, true, false, true);
4023 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4024 addRRSIG(keys, res->d_records, auth, 300);
4025 }
4026 return 1;
4027 }
4028 }
4029
4030 return 0;
4031 });
4032
4033 vector<DNSRecord> ret;
4034 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4035 BOOST_CHECK_EQUAL(res, RCode::NoError);
4036 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4037 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4038 BOOST_CHECK_EQUAL(queriesCount, 8);
4039
4040 /* again, to test the cache */
4041 ret.clear();
4042 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4043 BOOST_CHECK_EQUAL(res, RCode::NoError);
4044 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4045 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4046 BOOST_CHECK_EQUAL(queriesCount, 8);
4047 }
4048
4049 BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4050 std::unique_ptr<SyncRes> sr;
4051 initSR(sr, true);
4052
4053 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4054
4055 primeHints();
4056 const DNSName target("powerdns.com.");
4057 const ComboAddress targetAddr("192.0.2.42");
4058 testkeysset_t keys;
4059
4060 auto luaconfsCopy = g_luaconfs.getCopy();
4061 luaconfsCopy.dsAnchors.clear();
4062 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4063 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4064 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4065 g_luaconfs.setState(luaconfsCopy);
4066
4067 size_t queriesCount = 0;
4068
4069 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) {
4070 queriesCount++;
4071
4072 DNSName auth = domain;
4073 if (domain == target) {
4074 auth = DNSName("powerdns.com.");
4075 }
4076 if (type == QType::DS) {
4077 return 0;
4078 }
4079 else if (type == QType::DNSKEY) {
4080 setLWResult(res, 0, true, false, true);
4081 addDNSKEY(keys, auth, 300, res->d_records);
4082 addRRSIG(keys, res->d_records, auth, 300);
4083 return 1;
4084 }
4085 else {
4086 if (isRootServer(ip)) {
4087 setLWResult(res, 0, false, false, true);
4088 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4089 addDS(DNSName("com."), 300, res->d_records, keys);
4090 addRRSIG(keys, res->d_records, DNSName("."), 300);
4091 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4092 return 1;
4093 }
4094 else if (ip == ComboAddress("192.0.2.1:53")) {
4095 if (domain == DNSName("com.")) {
4096 setLWResult(res, 0, true, false, true);
4097 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4098 addRRSIG(keys, res->d_records, domain, 300);
4099 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4100 addRRSIG(keys, res->d_records, domain, 300);
4101 }
4102 else {
4103 setLWResult(res, 0, false, false, true);
4104 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4105 addDS(auth, 300, res->d_records, keys);
4106 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4107 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4108 }
4109 return 1;
4110 }
4111 else if (ip == ComboAddress("192.0.2.2:53")) {
4112 if (type == QType::NS) {
4113 setLWResult(res, 0, true, false, true);
4114 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4115 addRRSIG(keys, res->d_records, auth, 300);
4116 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4117 addRRSIG(keys, res->d_records, auth, 300);
4118 }
4119 else {
4120 setLWResult(res, RCode::NoError, true, false, true);
4121 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4122 addRRSIG(keys, res->d_records, auth, 300);
4123 }
4124 return 1;
4125 }
4126 }
4127
4128 return 0;
4129 });
4130
4131 vector<DNSRecord> ret;
4132 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4133 BOOST_CHECK_EQUAL(res, RCode::NoError);
4134 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4135 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4136 BOOST_CHECK_EQUAL(queriesCount, 8);
4137
4138 /* again, to test the cache */
4139 ret.clear();
4140 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4141 BOOST_CHECK_EQUAL(res, RCode::NoError);
4142 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4143 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4144 BOOST_CHECK_EQUAL(queriesCount, 8);
4145
4146 /* this time we ask for the NS that should be in the cache, to check
4147 the validation status */
4148 ret.clear();
4149 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4150 BOOST_CHECK_EQUAL(res, RCode::NoError);
4151 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4152 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4153 BOOST_CHECK_EQUAL(queriesCount, 8);
4154
4155 }
4156
4157 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4158 std::unique_ptr<SyncRes> sr;
4159 initSR(sr, true);
4160
4161 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4162
4163 primeHints();
4164 const DNSName target("powerdns.com.");
4165 const ComboAddress targetAddr("192.0.2.42");
4166 testkeysset_t keys;
4167
4168 auto luaconfsCopy = g_luaconfs.getCopy();
4169 luaconfsCopy.dsAnchors.clear();
4170 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4171 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4172 g_luaconfs.setState(luaconfsCopy);
4173
4174 size_t queriesCount = 0;
4175
4176 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) {
4177 queriesCount++;
4178
4179 DNSName auth = domain;
4180 if (domain == target) {
4181 auth = DNSName("powerdns.com.");
4182 }
4183 if (type == QType::DS) {
4184 return 0;
4185 }
4186 else if (type == QType::DNSKEY) {
4187 setLWResult(res, 0, true, false, true);
4188 addDNSKEY(keys, auth, 300, res->d_records);
4189 addRRSIG(keys, res->d_records, auth, 300);
4190 return 1;
4191 }
4192 else {
4193 if (isRootServer(ip)) {
4194 setLWResult(res, 0, false, false, true);
4195 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4196 addDS(DNSName("com."), 300, res->d_records, keys);
4197 addRRSIG(keys, res->d_records, DNSName("."), 300);
4198 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4199 return 1;
4200 }
4201 else if (ip == ComboAddress("192.0.2.1:53")) {
4202 if (domain == DNSName("com.")) {
4203 setLWResult(res, 0, true, false, true);
4204 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4205 addRRSIG(keys, res->d_records, domain, 300);
4206 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4207 addRRSIG(keys, res->d_records, domain, 300);
4208 }
4209 else {
4210 setLWResult(res, 0, false, false, true);
4211 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4212 /* no DS */
4213 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4214 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4215 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4216 }
4217 return 1;
4218 }
4219 else if (ip == ComboAddress("192.0.2.2:53")) {
4220 if (type == QType::NS) {
4221 setLWResult(res, 0, true, false, true);
4222 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4223 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4224 }
4225 else {
4226 setLWResult(res, RCode::NoError, true, false, true);
4227 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4228 }
4229 return 1;
4230 }
4231 }
4232
4233 return 0;
4234 });
4235
4236 vector<DNSRecord> ret;
4237 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4238 BOOST_CHECK_EQUAL(res, RCode::NoError);
4239 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4240 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4241 BOOST_CHECK_EQUAL(queriesCount, 7);
4242
4243 /* again, to test the cache */
4244 ret.clear();
4245 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4246 BOOST_CHECK_EQUAL(res, RCode::NoError);
4247 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4248 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4249 BOOST_CHECK_EQUAL(queriesCount, 7);
4250
4251 /* this time we ask for the NS that should be in the cache, to check
4252 the validation status */
4253 ret.clear();
4254 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4255 BOOST_CHECK_EQUAL(res, RCode::NoError);
4256 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4257 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4258 BOOST_CHECK_EQUAL(queriesCount, 7);
4259 }
4260
4261 BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
4262 std::unique_ptr<SyncRes> sr;
4263 initSR(sr, true);
4264
4265 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4266
4267 primeHints();
4268 const DNSName target("powerdns.com.");
4269 const ComboAddress targetAddr("192.0.2.42");
4270 testkeysset_t keys;
4271
4272 auto luaconfsCopy = g_luaconfs.getCopy();
4273 luaconfsCopy.dsAnchors.clear();
4274 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4275 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4276 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4277
4278 /* Add a NTA for "powerdns.com" */
4279 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4280
4281 g_luaconfs.setState(luaconfsCopy);
4282
4283 size_t queriesCount = 0;
4284
4285 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) {
4286 queriesCount++;
4287
4288 DNSName auth = domain;
4289 if (domain == target) {
4290 auth = DNSName("powerdns.com.");
4291 }
4292 if (type == QType::DS) {
4293 return 0;
4294 }
4295 else if (type == QType::DNSKEY) {
4296 setLWResult(res, 0, true, false, true);
4297 addDNSKEY(keys, auth, 300, res->d_records);
4298 addRRSIG(keys, res->d_records, auth, 300);
4299 return 1;
4300 }
4301 else {
4302 if (isRootServer(ip)) {
4303 setLWResult(res, 0, false, false, true);
4304 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4305 addDS(DNSName("com."), 300, res->d_records, keys);
4306 addRRSIG(keys, res->d_records, DNSName("."), 300);
4307 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4308 return 1;
4309 }
4310 else if (ip == ComboAddress("192.0.2.1:53")) {
4311 if (domain == DNSName("com.")) {
4312 setLWResult(res, 0, true, false, true);
4313 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4314 addRRSIG(keys, res->d_records, domain, 300);
4315 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4316 addRRSIG(keys, res->d_records, domain, 300);
4317 }
4318 else {
4319 setLWResult(res, 0, false, false, true);
4320 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4321 addDS(auth, 300, res->d_records, keys);
4322 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4323 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4324 }
4325 return 1;
4326 }
4327 else if (ip == ComboAddress("192.0.2.2:53")) {
4328 if (type == QType::NS) {
4329 setLWResult(res, 0, true, false, true);
4330 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4331 addRRSIG(keys, res->d_records, auth, 300);
4332 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4333 addRRSIG(keys, res->d_records, auth, 300);
4334 }
4335 else {
4336 setLWResult(res, RCode::NoError, true, false, true);
4337 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4338 addRRSIG(keys, res->d_records, auth, 300);
4339 }
4340 return 1;
4341 }
4342 }
4343
4344 return 0;
4345 });
4346
4347 vector<DNSRecord> ret;
4348 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4349 BOOST_CHECK_EQUAL(res, RCode::NoError);
4350 /* Should be insecure because of the NTA */
4351 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4352 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4353 BOOST_CHECK_EQUAL(queriesCount, 7);
4354
4355 /* again, to test the cache */
4356 ret.clear();
4357 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4358 BOOST_CHECK_EQUAL(res, RCode::NoError);
4359 /* Should be insecure because of the NTA */
4360 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4361 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4362 BOOST_CHECK_EQUAL(queriesCount, 7);
4363 }
4364
4365 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4366 std::unique_ptr<SyncRes> sr;
4367 initSR(sr, true);
4368
4369 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4370
4371 primeHints();
4372 const DNSName target("powerdns.com.");
4373 const ComboAddress targetAddr("192.0.2.42");
4374 testkeysset_t keys;
4375
4376 auto luaconfsCopy = g_luaconfs.getCopy();
4377 luaconfsCopy.dsAnchors.clear();
4378 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4379 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4380 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4381
4382 /* Add a NTA for "powerdns.com" */
4383 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4384
4385 g_luaconfs.setState(luaconfsCopy);
4386
4387 size_t queriesCount = 0;
4388
4389 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) {
4390 queriesCount++;
4391
4392 if (type == QType::DS || type == QType::DNSKEY) {
4393 setLWResult(res, 0, false, false, true);
4394 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4395 return 1;
4396 }
4397 else {
4398 if (isRootServer(ip)) {
4399 setLWResult(res, 0, false, false, true);
4400 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4401 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4402 return 1;
4403 }
4404 else if (ip == ComboAddress("192.0.2.1:53")) {
4405 if (domain == DNSName("com.")) {
4406 setLWResult(res, 0, true, false, true);
4407 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4408 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4409 }
4410 else {
4411 setLWResult(res, 0, false, false, true);
4412 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4413 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4414 }
4415 return 1;
4416 }
4417 else if (ip == ComboAddress("192.0.2.2:53")) {
4418 if (type == QType::NS) {
4419 setLWResult(res, 0, true, false, true);
4420 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4421 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4422 }
4423 else {
4424 setLWResult(res, RCode::NoError, true, false, true);
4425 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4426 }
4427 return 1;
4428 }
4429 }
4430
4431 return 0;
4432 });
4433
4434 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
4435 vector<DNSRecord> ret;
4436 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4437 BOOST_CHECK_EQUAL(res, RCode::NoError);
4438 /* Should be insecure because of the NTA */
4439 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4440 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4441 /* and a such, no query for the DNSKEYs */
4442 BOOST_CHECK_EQUAL(queriesCount, 6);
4443
4444 /* again, to test the cache */
4445 ret.clear();
4446 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4447 BOOST_CHECK_EQUAL(res, RCode::NoError);
4448 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4449 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4450 BOOST_CHECK_EQUAL(queriesCount, 6);
4451 }
4452
4453 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
4454 std::unique_ptr<SyncRes> sr;
4455 initSR(sr, true);
4456
4457 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4458
4459 primeHints();
4460 const DNSName target("powerdns.com.");
4461 testkeysset_t keys;
4462
4463 auto luaconfsCopy = g_luaconfs.getCopy();
4464 luaconfsCopy.dsAnchors.clear();
4465 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4466 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4467 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4468
4469 g_luaconfs.setState(luaconfsCopy);
4470
4471 size_t queriesCount = 0;
4472
4473 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) {
4474 queriesCount++;
4475
4476 if (type == QType::DS) {
4477 return 0;
4478 }
4479 else if (type == QType::DNSKEY) {
4480 setLWResult(res, 0, true, false, true);
4481 addDNSKEY(keys, domain, 300, res->d_records);
4482 addRRSIG(keys, res->d_records, domain, 300);
4483 return 1;
4484 }
4485 else {
4486 if (isRootServer(ip)) {
4487 setLWResult(res, 0, false, false, true);
4488 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4489 addDS(DNSName("com."), 300, res->d_records, keys);
4490 addRRSIG(keys, res->d_records, DNSName("."), 300);
4491 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4492 return 1;
4493 }
4494 else if (ip == ComboAddress("192.0.2.1:53")) {
4495 if (domain == DNSName("com.")) {
4496 setLWResult(res, 0, true, false, true);
4497 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4498 addRRSIG(keys, res->d_records, domain, 300);
4499 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4500 addRRSIG(keys, res->d_records, domain, 300);
4501 }
4502 else {
4503 setLWResult(res, 0, false, false, true);
4504 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4505 addDS(domain, 300, res->d_records, keys);
4506 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4507 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4508 }
4509 return 1;
4510 }
4511 else if (ip == ComboAddress("192.0.2.2:53")) {
4512 if (type == QType::NS) {
4513 setLWResult(res, 0, true, false, true);
4514 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4515 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4516 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4517 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4518 }
4519 else {
4520 setLWResult(res, 0, true, false, true);
4521 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4522 addRRSIG(keys, res->d_records, domain, 300);
4523 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
4524 addRRSIG(keys, res->d_records, domain, 300);
4525 }
4526 return 1;
4527 }
4528 }
4529
4530 return 0;
4531 });
4532
4533 vector<DNSRecord> ret;
4534 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4535 BOOST_CHECK_EQUAL(res, RCode::NoError);
4536 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4537 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4538 BOOST_CHECK_EQUAL(queriesCount, 8);
4539
4540 /* again, to test the cache */
4541 ret.clear();
4542 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4543 BOOST_CHECK_EQUAL(res, RCode::NoError);
4544 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4545 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4546 BOOST_CHECK_EQUAL(queriesCount, 8);
4547 }
4548
4549 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
4550 std::unique_ptr<SyncRes> sr;
4551 initSR(sr, true);
4552
4553 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4554
4555 primeHints();
4556 const DNSName target("nx.powerdns.com.");
4557 testkeysset_t keys;
4558
4559 auto luaconfsCopy = g_luaconfs.getCopy();
4560 luaconfsCopy.dsAnchors.clear();
4561 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4562 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4563 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4564
4565 g_luaconfs.setState(luaconfsCopy);
4566
4567 size_t queriesCount = 0;
4568
4569 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) {
4570 queriesCount++;
4571
4572 DNSName auth = domain;
4573 if (domain == target) {
4574 auth = DNSName("powerdns.com.");
4575 }
4576 if (type == QType::DS) {
4577 return 0;
4578 }
4579 else if (type == QType::DNSKEY) {
4580 setLWResult(res, 0, true, false, true);
4581 addDNSKEY(keys, auth, 300, res->d_records);
4582 addRRSIG(keys, res->d_records, auth, 300);
4583 return 1;
4584 }
4585 else {
4586 if (isRootServer(ip)) {
4587 setLWResult(res, 0, false, false, true);
4588 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4589 addDS(DNSName("com."), 300, res->d_records, keys);
4590 addRRSIG(keys, res->d_records, DNSName("."), 300);
4591 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4592 return 1;
4593 }
4594 else if (ip == ComboAddress("192.0.2.1:53")) {
4595 if (domain == DNSName("com.")) {
4596 setLWResult(res, 0, true, false, true);
4597 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4598 addRRSIG(keys, res->d_records, domain, 300);
4599 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4600 addRRSIG(keys, res->d_records, domain, 300);
4601 }
4602 else {
4603 setLWResult(res, 0, false, false, true);
4604 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4605 addDS(auth, 300, res->d_records, keys);
4606 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4607 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4608 }
4609 return 1;
4610 }
4611 else if (ip == ComboAddress("192.0.2.2:53")) {
4612 if (type == QType::NS) {
4613 setLWResult(res, 0, true, false, true);
4614 if (domain == DNSName("powerdns.com.")) {
4615 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4616 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4617 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4618 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4619 }
4620 else {
4621 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4622 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4623 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4624 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4625 }
4626 }
4627 else {
4628 setLWResult(res, RCode::NXDomain, true, false, true);
4629 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4630 addRRSIG(keys, res->d_records, auth, 300);
4631 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4632 addRRSIG(keys, res->d_records, auth, 300);
4633 }
4634 return 1;
4635 }
4636 }
4637
4638 return 0;
4639 });
4640
4641 vector<DNSRecord> ret;
4642 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4643 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
4644 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4645 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4646 BOOST_CHECK_EQUAL(queriesCount, 9);
4647
4648 /* again, to test the cache */
4649 ret.clear();
4650 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4651 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
4652 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4653 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4654 BOOST_CHECK_EQUAL(queriesCount, 9);
4655 }
4656
4657 BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
4658 std::unique_ptr<SyncRes> sr;
4659 initSR(sr, true);
4660
4661 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4662
4663 primeHints();
4664 const DNSName target("www.powerdns.com.");
4665 testkeysset_t keys;
4666
4667 auto luaconfsCopy = g_luaconfs.getCopy();
4668 luaconfsCopy.dsAnchors.clear();
4669 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4670 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4671 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4672
4673 g_luaconfs.setState(luaconfsCopy);
4674
4675 size_t queriesCount = 0;
4676
4677 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) {
4678 queriesCount++;
4679
4680 if (type == QType::DS) {
4681 return 0;
4682 }
4683 else if (type == QType::DNSKEY) {
4684 setLWResult(res, 0, true, false, true);
4685 addDNSKEY(keys, domain, 300, res->d_records);
4686 addRRSIG(keys, res->d_records, domain, 300);
4687 return 1;
4688 }
4689 else {
4690 if (isRootServer(ip)) {
4691 setLWResult(res, 0, false, false, true);
4692 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4693 addDS(DNSName("com."), 300, res->d_records, keys);
4694 addRRSIG(keys, res->d_records, DNSName("."), 300);
4695 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4696 return 1;
4697 }
4698 else if (ip == ComboAddress("192.0.2.1:53")) {
4699 if (domain == DNSName("com.")) {
4700 setLWResult(res, 0, true, false, true);
4701 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4702 addRRSIG(keys, res->d_records, domain, 300);
4703 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4704 addRRSIG(keys, res->d_records, domain, 300);
4705 }
4706 else {
4707 setLWResult(res, 0, false, false, true);
4708 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4709 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
4710 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4711 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4712 }
4713 return 1;
4714 }
4715 else if (ip == ComboAddress("192.0.2.2:53")) {
4716 setLWResult(res, 0, true, false, true);
4717 if (type == QType::NS) {
4718 if (domain == DNSName("powerdns.com.")) {
4719 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4720 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4721 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4722 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4723 }
4724 else {
4725 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4726 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4727 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4728 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4729 }
4730 }
4731 else {
4732 addRecordToLW(res, domain, QType::A, "192.0.2.42");
4733 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
4734 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4735 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4736 }
4737 return 1;
4738 }
4739 }
4740
4741 return 0;
4742 });
4743
4744 vector<DNSRecord> ret;
4745 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4746 BOOST_CHECK_EQUAL(res, RCode::NoError);
4747 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4748 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4749 BOOST_CHECK_EQUAL(queriesCount, 9);
4750
4751 /* again, to test the cache */
4752 ret.clear();
4753 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4754 BOOST_CHECK_EQUAL(res, RCode::NoError);
4755 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4756 BOOST_REQUIRE_EQUAL(ret.size(), 4);
4757 BOOST_CHECK_EQUAL(queriesCount, 9);
4758 }
4759
4760 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
4761 std::unique_ptr<SyncRes> sr;
4762 initSR(sr, true);
4763
4764 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4765
4766 primeHints();
4767 const DNSName target("www.powerdns.com.");
4768 testkeysset_t keys;
4769
4770 auto luaconfsCopy = g_luaconfs.getCopy();
4771 luaconfsCopy.dsAnchors.clear();
4772 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4773 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4774 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4775
4776 g_luaconfs.setState(luaconfsCopy);
4777
4778 size_t queriesCount = 0;
4779 size_t dsQueriesCount = 0;
4780
4781 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) {
4782 queriesCount++;
4783
4784 if (type == QType::DS) {
4785 DNSName auth(domain);
4786 auth.chopOff();
4787 dsQueriesCount++;
4788
4789 setLWResult(res, 0, true, false, true);
4790 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
4791 addRRSIG(keys, res->d_records, auth, 300);
4792 return 1;
4793 }
4794 else if (type == QType::DNSKEY) {
4795 setLWResult(res, 0, true, false, true);
4796 addDNSKEY(keys, domain, 300, res->d_records);
4797 addRRSIG(keys, res->d_records, domain, 300);
4798 return 1;
4799 }
4800 else {
4801 if (isRootServer(ip)) {
4802 setLWResult(res, 0, false, false, true);
4803 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4804 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4805 /* No DS on referral, and no denial of the DS either */
4806 return 1;
4807 }
4808 else if (ip == ComboAddress("192.0.2.1:53")) {
4809 if (domain == DNSName("com.")) {
4810 setLWResult(res, 0, true, false, true);
4811 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4812 addRRSIG(keys, res->d_records, domain, 300);
4813 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4814 addRRSIG(keys, res->d_records, domain, 300);
4815 }
4816 else {
4817 setLWResult(res, 0, false, false, true);
4818 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4819 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4820 /* No DS on referral, and no denial of the DS either */
4821 }
4822 return 1;
4823 }
4824 else if (ip == ComboAddress("192.0.2.2:53")) {
4825 setLWResult(res, 0, true, false, true);
4826 if (type == QType::NS) {
4827 if (domain == DNSName("powerdns.com.")) {
4828 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4829 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4830 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4831 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4832 }
4833 else {
4834 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4835 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4836 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4837 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4838 }
4839 }
4840 else {
4841 addRecordToLW(res, domain, QType::A, "192.0.2.42");
4842 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4843 }
4844
4845 return 1;
4846 }
4847 }
4848
4849 return 0;
4850 });
4851
4852 vector<DNSRecord> ret;
4853 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4854 BOOST_CHECK_EQUAL(res, RCode::NoError);
4855 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4856 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4857 BOOST_CHECK_EQUAL(queriesCount, 11);
4858 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
4859
4860 /* again, to test the cache */
4861 ret.clear();
4862 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4863 BOOST_CHECK_EQUAL(res, RCode::NoError);
4864 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4865 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4866 BOOST_CHECK_EQUAL(queriesCount, 11);
4867 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
4868 }
4869
4870 BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
4871 std::unique_ptr<SyncRes> sr;
4872 initSR(sr, true);
4873
4874 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4875
4876 primeHints();
4877 const DNSName target("www.powerdns.com.");
4878 testkeysset_t keys;
4879
4880 auto luaconfsCopy = g_luaconfs.getCopy();
4881 luaconfsCopy.dsAnchors.clear();
4882 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4883 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4884
4885 g_luaconfs.setState(luaconfsCopy);
4886
4887 size_t queriesCount = 0;
4888 size_t dsQueriesCount = 0;
4889
4890 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) {
4891 queriesCount++;
4892
4893 if (type == QType::DS) {
4894 DNSName auth(domain);
4895 auth.chopOff();
4896 dsQueriesCount++;
4897
4898 setLWResult(res, 0, true, false, true);
4899 if (domain == DNSName("com.")) {
4900 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
4901 }
4902 else {
4903 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4904 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4905 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
4906 }
4907 addRRSIG(keys, res->d_records, auth, 300);
4908 return 1;
4909 }
4910 else if (type == QType::DNSKEY) {
4911 setLWResult(res, 0, true, false, true);
4912 addDNSKEY(keys, domain, 300, res->d_records);
4913 addRRSIG(keys, res->d_records, domain, 300);
4914 return 1;
4915 }
4916 else {
4917 if (isRootServer(ip)) {
4918 setLWResult(res, 0, false, false, true);
4919 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4920 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4921 /* No DS on referral, and no denial of the DS either */
4922 return 1;
4923 }
4924 else if (ip == ComboAddress("192.0.2.1:53")) {
4925 if (domain == DNSName("com.")) {
4926 setLWResult(res, 0, true, false, true);
4927 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4928 addRRSIG(keys, res->d_records, domain, 300);
4929 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4930 addRRSIG(keys, res->d_records, domain, 300);
4931 }
4932 else {
4933 setLWResult(res, 0, false, false, true);
4934 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4935 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4936 /* No DS on referral, and no denial of the DS either */
4937 }
4938 return 1;
4939 }
4940 else if (ip == ComboAddress("192.0.2.2:53")) {
4941 setLWResult(res, 0, true, false, true);
4942 if (type == QType::NS) {
4943 if (domain == DNSName("powerdns.com.")) {
4944 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4945 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4946 }
4947 else {
4948 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4949 }
4950 }
4951 else {
4952 addRecordToLW(res, domain, QType::A, "192.0.2.42");
4953 }
4954 return 1;
4955 }
4956 }
4957
4958 return 0;
4959 });
4960
4961 vector<DNSRecord> ret;
4962 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4963 BOOST_CHECK_EQUAL(res, RCode::NoError);
4964 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4965 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4966 BOOST_CHECK_EQUAL(queriesCount, 10);
4967 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
4968
4969 /* again, to test the cache */
4970 ret.clear();
4971 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4972 BOOST_CHECK_EQUAL(res, RCode::NoError);
4973 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4974 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4975 BOOST_CHECK_EQUAL(queriesCount, 10);
4976 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
4977 }
4978
4979 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
4980 std::unique_ptr<SyncRes> sr;
4981 initSR(sr, true);
4982
4983 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4984
4985 primeHints();
4986 const DNSName target("powerdns.com.");
4987 testkeysset_t keys;
4988
4989 auto luaconfsCopy = g_luaconfs.getCopy();
4990 luaconfsCopy.dsAnchors.clear();
4991 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4992 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4993 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4994
4995 g_luaconfs.setState(luaconfsCopy);
4996
4997 size_t queriesCount = 0;
4998
4999 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) {
5000 queriesCount++;
5001
5002 if (type == QType::DS) {
5003 return 0;
5004 }
5005 else if (type == QType::DNSKEY) {
5006 setLWResult(res, 0, true, false, true);
5007 addDNSKEY(keys, domain, 300, res->d_records);
5008 addRRSIG(keys, res->d_records, domain, 300);
5009 return 1;
5010 }
5011 else {
5012 if (isRootServer(ip)) {
5013 setLWResult(res, 0, false, false, true);
5014 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5015 addDS(DNSName("com."), 300, res->d_records, keys);
5016 addRRSIG(keys, res->d_records, DNSName("."), 300);
5017 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5018 return 1;
5019 }
5020 else if (ip == ComboAddress("192.0.2.1:53")) {
5021 if (domain == DNSName("com.")) {
5022 setLWResult(res, 0, true, false, true);
5023 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
5024 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5025 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5026 }
5027 else {
5028 setLWResult(res, 0, false, false, true);
5029 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5030 addDS(domain, 300, res->d_records, keys);
5031 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5032 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5033 }
5034 return 1;
5035 }
5036 else if (ip == ComboAddress("192.0.2.2:53")) {
5037 setLWResult(res, 0, true, false, true);
5038 if (type == QType::NS) {
5039 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5040 addRRSIG(keys, res->d_records, domain, 300);
5041 }
5042 else {
5043 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5044 addRRSIG(keys, res->d_records, domain, 300);
5045 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
5046 /* NO RRSIG for the NSEC record! */
5047 }
5048 return 1;
5049 }
5050 }
5051
5052 return 0;
5053 });
5054
5055 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
5056 vector<DNSRecord> ret;
5057 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5058 BOOST_CHECK_EQUAL(res, RCode::NoError);
5059 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5060 BOOST_CHECK_EQUAL(ret.size(), 3);
5061 BOOST_CHECK_EQUAL(queriesCount, 8);
5062
5063 /* again, to test the cache */
5064 ret.clear();
5065 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5066 BOOST_CHECK_EQUAL(res, RCode::NoError);
5067 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5068 BOOST_REQUIRE_EQUAL(ret.size(), 3);
5069 BOOST_CHECK_EQUAL(queriesCount, 8);
5070 }
5071
5072 BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
5073 std::unique_ptr<SyncRes> sr;
5074 initSR(sr, true);
5075
5076 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5077
5078 primeHints();
5079 const DNSName target("powerdns.com.");
5080 testkeysset_t keys;
5081
5082 auto luaconfsCopy = g_luaconfs.getCopy();
5083 luaconfsCopy.dsAnchors.clear();
5084 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5085 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5086 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5087
5088 g_luaconfs.setState(luaconfsCopy);
5089
5090 size_t queriesCount = 0;
5091
5092 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) {
5093 queriesCount++;
5094
5095 if (type == QType::DS) {
5096 return 0;
5097 }
5098 else if (type == QType::DNSKEY) {
5099 setLWResult(res, 0, true, false, true);
5100 addDNSKEY(keys, domain, 300, res->d_records);
5101 addRRSIG(keys, res->d_records, domain, 300);
5102 return 1;
5103 }
5104 else {
5105 if (isRootServer(ip)) {
5106 setLWResult(res, 0, false, false, true);
5107 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5108 addDS(DNSName("com."), 300, res->d_records, keys);
5109 addRRSIG(keys, res->d_records, DNSName("."), 300);
5110 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5111 return 1;
5112 }
5113 else if (ip == ComboAddress("192.0.2.1:53")) {
5114 if (domain == DNSName("com.")) {
5115 setLWResult(res, 0, true, false, true);
5116 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
5117 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5118 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5119 }
5120 else {
5121 setLWResult(res, 0, false, false, true);
5122 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5123 addDS(domain, 300, res->d_records, keys);
5124 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5125 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5126 }
5127 return 1;
5128 }
5129 else if (ip == ComboAddress("192.0.2.2:53")) {
5130 setLWResult(res, 0, true, false, true);
5131 if (type == QType::NS) {
5132 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5133 addRRSIG(keys, res->d_records, domain, 300);
5134 }
5135 else {
5136 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5137 addRRSIG(keys, res->d_records, domain, 300);
5138
5139 /* NO NSEC record! */
5140 }
5141 return 1;
5142 }
5143 }
5144
5145 return 0;
5146 });
5147
5148 /* no NSEC record in a secure zone, should be Bogus! */
5149 vector<DNSRecord> ret;
5150 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5151 BOOST_CHECK_EQUAL(res, RCode::NoError);
5152 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5153 BOOST_CHECK_EQUAL(ret.size(), 2);
5154 BOOST_CHECK_EQUAL(queriesCount, 8);
5155
5156 /* again, to test the cache */
5157 ret.clear();
5158 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5159 BOOST_CHECK_EQUAL(res, RCode::NoError);
5160 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5161 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5162 BOOST_CHECK_EQUAL(queriesCount, 8);
5163 }
5164
5165 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
5166 std::unique_ptr<SyncRes> sr;
5167 initSR(sr, true);
5168
5169 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5170
5171 primeHints();
5172 const DNSName target("powerdns.com.");
5173 const ComboAddress targetAddr("192.0.2.42");
5174 testkeysset_t keys;
5175
5176 auto luaconfsCopy = g_luaconfs.getCopy();
5177 luaconfsCopy.dsAnchors.clear();
5178 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5179 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5180
5181 g_luaconfs.setState(luaconfsCopy);
5182
5183 size_t queriesCount = 0;
5184
5185 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) {
5186 queriesCount++;
5187
5188 if (type == QType::DS) {
5189 if (domain == target) {
5190 setLWResult(res, 0, false, false, true);
5191 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5192 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5193 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5194 return 1;
5195 }
5196 }
5197 else if (type == QType::DNSKEY) {
5198 if (domain == g_rootdnsname || domain == DNSName("com.")) {
5199 setLWResult(res, 0, true, false, true);
5200 addDNSKEY(keys, domain, 300, res->d_records);
5201 addRRSIG(keys, res->d_records, domain, 300);
5202 return 1;
5203 }
5204 else {
5205 setLWResult(res, 0, false, false, true);
5206 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5207 return 1;
5208 }
5209 }
5210 else {
5211 if (isRootServer(ip)) {
5212 setLWResult(res, 0, false, false, true);
5213 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5214 addDS(DNSName("com."), 300, res->d_records, keys);
5215 addRRSIG(keys, res->d_records, DNSName("."), 300);
5216 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5217 return 1;
5218 }
5219 else if (ip == ComboAddress("192.0.2.1:53")) {
5220 if (domain == DNSName("com.")) {
5221 setLWResult(res, 0, true, false, true);
5222 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
5223 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5224 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5225 }
5226 else {
5227 setLWResult(res, 0, false, false, true);
5228 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5229 /* no DS */
5230 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5231 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5232 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5233 }
5234 return 1;
5235 }
5236 else if (ip == ComboAddress("192.0.2.2:53")) {
5237 setLWResult(res, 0, true, false, true);
5238 if (type == QType::NS) {
5239 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5240 }
5241 else {
5242 addRecordToLW(res, domain, QType::A, targetAddr.toString());
5243 }
5244 return 1;
5245 }
5246 }
5247
5248 return 0;
5249 });
5250
5251 vector<DNSRecord> ret;
5252 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5253 BOOST_CHECK_EQUAL(res, RCode::NoError);
5254 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5255 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5256 BOOST_CHECK(ret[0].d_type == QType::A);
5257 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
5258 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
5259 1 query for A */
5260 BOOST_CHECK_EQUAL(queriesCount, 7);
5261
5262 /* again, to test the cache */
5263 ret.clear();
5264 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5265 BOOST_CHECK_EQUAL(res, RCode::NoError);
5266 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5267 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5268 BOOST_CHECK(ret[0].d_type == QType::A);
5269 BOOST_CHECK_EQUAL(queriesCount, 7);
5270 }
5271
5272 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
5273 std::unique_ptr<SyncRes> sr;
5274 initSR(sr, true);
5275
5276 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5277
5278 primeHints();
5279 const DNSName target("www.sub.powerdns.com.");
5280 const ComboAddress targetAddr("192.0.2.42");
5281 testkeysset_t keys;
5282
5283 auto luaconfsCopy = g_luaconfs.getCopy();
5284 luaconfsCopy.dsAnchors.clear();
5285 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5286 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5287 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5288
5289 g_luaconfs.setState(luaconfsCopy);
5290
5291 size_t queriesCount = 0;
5292
5293 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) {
5294 queriesCount++;
5295
5296 if (type == QType::DS) {
5297 if (domain == DNSName("sub.powerdns.com.")) {
5298 setLWResult(res, 0, false, false, true);
5299 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5300 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5301 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5302 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5303 return 1;
5304 }
5305 else if (domain == DNSName("www.sub.powerdns.com.")) {
5306 setLWResult(res, 0, false, false, true);
5307 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);
5308 return 1;
5309 }
5310 }
5311 else if (type == QType::DNSKEY) {
5312 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
5313 setLWResult(res, 0, true, false, true);
5314 addDNSKEY(keys, domain, 300, res->d_records);
5315 addRRSIG(keys, res->d_records, domain, 300);
5316 return 1;
5317 }
5318 else {
5319 setLWResult(res, 0, false, false, true);
5320 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5321 return 1;
5322 }
5323 }
5324 else {
5325 if (isRootServer(ip)) {
5326 setLWResult(res, 0, false, false, true);
5327 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5328 addDS(DNSName("com."), 300, res->d_records, keys);
5329 addRRSIG(keys, res->d_records, DNSName("."), 300);
5330 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5331 return 1;
5332 }
5333 else if (ip == ComboAddress("192.0.2.1:53")) {
5334 if (domain == DNSName("com.")) {
5335 setLWResult(res, 0, true, false, true);
5336 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
5337 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5338 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5339 }
5340 else {
5341 setLWResult(res, 0, false, false, true);
5342 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5343 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5344 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5345 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5346 }
5347 return 1;
5348 }
5349 else if (ip == ComboAddress("192.0.2.2:53")) {
5350 setLWResult(res, 0, true, false, true);
5351 if (type == QType::NS) {
5352 if (domain == DNSName("www.sub.powerdns.com.")) {
5353 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);
5354 }
5355 else if (domain == DNSName("sub.powerdns.com.")) {
5356 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5357 }
5358 else if (domain == DNSName("powerdns.com.")) {
5359 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5360 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5361 }
5362 } else {
5363 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
5364 }
5365 return 1;
5366 }
5367 }
5368
5369 return 0;
5370 });
5371
5372 vector<DNSRecord> ret;
5373 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5374 BOOST_CHECK_EQUAL(res, RCode::NoError);
5375 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5376 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5377 BOOST_CHECK(ret[0].d_type == QType::A);
5378 BOOST_CHECK_EQUAL(queriesCount, 11);
5379
5380 /* again, to test the cache */
5381 ret.clear();
5382 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5383 BOOST_CHECK_EQUAL(res, RCode::NoError);
5384 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5385 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5386 BOOST_CHECK(ret[0].d_type == QType::A);
5387 BOOST_CHECK_EQUAL(queriesCount, 11);
5388 }
5389
5390 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
5391 std::unique_ptr<SyncRes> sr;
5392 initSR(sr, true);
5393
5394 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5395
5396 primeHints();
5397 const DNSName target("www.sub.powerdns.com.");
5398 const ComboAddress targetAddr("192.0.2.42");
5399 testkeysset_t keys;
5400
5401 auto luaconfsCopy = g_luaconfs.getCopy();
5402 luaconfsCopy.dsAnchors.clear();
5403 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5404 /* No key material for .com */
5405 /* But TA for sub.powerdns.com. */
5406 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5407 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
5408 g_luaconfs.setState(luaconfsCopy);
5409
5410 size_t queriesCount = 0;
5411
5412 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) {
5413 queriesCount++;
5414
5415 if (type == QType::DS) {
5416 if (domain == DNSName("www.sub.powerdns.com")) {
5417 setLWResult(res, 0, false, false, true);
5418 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);
5419 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
5420 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
5421 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
5422 }
5423 else {
5424 setLWResult(res, 0, false, false, true);
5425 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5426 }
5427 return 1;
5428 }
5429 else if (type == QType::DNSKEY) {
5430 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
5431 setLWResult(res, 0, true, false, true);
5432 addDNSKEY(keys, domain, 300, res->d_records);
5433 addRRSIG(keys, res->d_records, domain, 300);
5434 return 1;
5435 }
5436 }
5437 else {
5438 if (isRootServer(ip)) {
5439 setLWResult(res, 0, false, false, true);
5440 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5441 /* no DS */
5442 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
5443 addRRSIG(keys, res->d_records, DNSName("."), 300);
5444 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5445 return 1;
5446 }
5447 else if (ip == ComboAddress("192.0.2.1:53")) {
5448 if (domain == DNSName("com.")) {
5449 setLWResult(res, 0, true, false, true);
5450 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
5451 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5452 }
5453 else if (domain == DNSName("powerdns.com.")) {
5454 setLWResult(res, 0, false, false, true);
5455 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5456 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5457 }
5458 return 1;
5459 }
5460 else if (ip == ComboAddress("192.0.2.2:53")) {
5461 setLWResult(res, 0, true, false, true);
5462 if (type == QType::NS) {
5463 if (domain == DNSName("www.sub.powerdns.com.")) {
5464 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);
5465 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
5466 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
5467 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
5468 }
5469 else if (domain == DNSName("sub.powerdns.com.")) {
5470 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5471 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
5472 }
5473 else if (domain == DNSName("powerdns.com.")) {
5474 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5475 }
5476 }
5477 else if (domain == DNSName("www.sub.powerdns.com.")) {
5478 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
5479 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
5480 }
5481 return 1;
5482 }
5483 }
5484
5485 return 0;
5486 });
5487
5488 vector<DNSRecord> ret;
5489 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5490 BOOST_CHECK_EQUAL(res, RCode::NoError);
5491 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5492 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5493 BOOST_CHECK(ret[0].d_type == QType::A);
5494 BOOST_CHECK_EQUAL(queriesCount, 9);
5495
5496 /* again, to test the cache */
5497 ret.clear();
5498 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5499 BOOST_CHECK_EQUAL(res, RCode::NoError);
5500 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5501 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5502 BOOST_CHECK(ret[0].d_type == QType::A);
5503 BOOST_CHECK_EQUAL(queriesCount, 9);
5504 }
5505
5506 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
5507 std::unique_ptr<SyncRes> sr;
5508 initSR(sr, true);
5509
5510 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5511
5512 primeHints();
5513 const DNSName target("powerdns.com.");
5514 testkeysset_t keys;
5515
5516 auto luaconfsCopy = g_luaconfs.getCopy();
5517 luaconfsCopy.dsAnchors.clear();
5518 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5519 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5520
5521 g_luaconfs.setState(luaconfsCopy);
5522
5523 size_t queriesCount = 0;
5524
5525 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) {
5526 queriesCount++;
5527
5528 if (type == QType::DS) {
5529 if (domain == target) {
5530 setLWResult(res, 0, false, false, true);
5531 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5532 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5533 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5534 return 1;
5535 }
5536 }
5537 else if (type == QType::DNSKEY) {
5538 if (domain == g_rootdnsname || domain == DNSName("com.")) {
5539 setLWResult(res, 0, true, false, true);
5540 addDNSKEY(keys, domain, 300, res->d_records);
5541 addRRSIG(keys, res->d_records, domain, 300);
5542 return 1;
5543 }
5544 else {
5545 setLWResult(res, 0, false, false, true);
5546 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5547 return 1;
5548 }
5549 }
5550 else {
5551 if (isRootServer(ip)) {
5552 setLWResult(res, 0, false, false, true);
5553 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5554 addDS(DNSName("com."), 300, res->d_records, keys);
5555 addRRSIG(keys, res->d_records, DNSName("."), 300);
5556 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5557 return 1;
5558 }
5559 else if (ip == ComboAddress("192.0.2.1:53")) {
5560 if (domain == DNSName("com.")) {
5561 setLWResult(res, 0, true, false, true);
5562 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5563 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5564 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5565 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5566 }
5567 else {
5568 setLWResult(res, 0, false, false, true);
5569 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5570 /* no DS */
5571 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5572 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5573 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5574 }
5575 return 1;
5576 }
5577 else if (ip == ComboAddress("192.0.2.2:53")) {
5578 if (type == QType::NS) {
5579 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5580 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5581 }
5582 else {
5583 setLWResult(res, 0, true, false, true);
5584 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5585 }
5586 return 1;
5587 }
5588 }
5589
5590 return 0;
5591 });
5592
5593 vector<DNSRecord> ret;
5594 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5595 BOOST_CHECK_EQUAL(res, RCode::NoError);
5596 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5597 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5598 /* 4 NS (com from root, com from com, powerdns.com from com,
5599 powerdns.com from powerdns.com)
5600 2 DNSKEY (. and com., none for powerdns.com because no DS)
5601 1 query for A
5602 */
5603 BOOST_CHECK_EQUAL(queriesCount, 7);
5604
5605 /* again, to test the cache */
5606 ret.clear();
5607 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5608 BOOST_CHECK_EQUAL(res, RCode::NoError);
5609 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5610 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5611 BOOST_CHECK_EQUAL(queriesCount, 7);
5612 }
5613
5614 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
5615 std::unique_ptr<SyncRes> sr;
5616 initSR(sr, true);
5617
5618 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5619
5620 primeHints();
5621 const DNSName target("powerdns.com.");
5622 const DNSName targetCName("power-dns.com.");
5623 const ComboAddress targetCNameAddr("192.0.2.42");
5624 testkeysset_t keys;
5625
5626 auto luaconfsCopy = g_luaconfs.getCopy();
5627 luaconfsCopy.dsAnchors.clear();
5628 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5629 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5630 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5631 g_luaconfs.setState(luaconfsCopy);
5632
5633 size_t queriesCount = 0;
5634
5635 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) {
5636 queriesCount++;
5637
5638 if (type == QType::DS) {
5639 if (domain == target) {
5640 setLWResult(res, 0, false, false, true);
5641 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5642 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
5643 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5644 return 1;
5645 }
5646 }
5647 else if (type == QType::DNSKEY) {
5648 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
5649 setLWResult(res, 0, true, false, true);
5650 addDNSKEY(keys, domain, 300, res->d_records);
5651 addRRSIG(keys, res->d_records, domain, 300);
5652 return 1;
5653 }
5654 else {
5655 setLWResult(res, 0, false, false, true);
5656 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5657 return 1;
5658 }
5659 }
5660 else {
5661 if (isRootServer(ip)) {
5662 setLWResult(res, 0, false, false, true);
5663 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5664 addDS(DNSName("com."), 300, res->d_records, keys);
5665 addRRSIG(keys, res->d_records, DNSName("."), 300);
5666 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5667 return 1;
5668 }
5669 else if (ip == ComboAddress("192.0.2.1:53")) {
5670 setLWResult(res, 0, false, false, true);
5671 if (domain == DNSName("com.")) {
5672 setLWResult(res, 0, true, false, true);
5673 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5674 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5675 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5676 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5677 }
5678 else {
5679 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5680 if (domain == DNSName("powerdns.com.")) {
5681 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5682 }
5683 else if (domain == targetCName) {
5684 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
5685 }
5686 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5687 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5688 }
5689
5690 return 1;
5691 }
5692 else if (ip == ComboAddress("192.0.2.2:53")) {
5693 setLWResult(res, 0, true, false, true);
5694
5695 if (type == QType::NS) {
5696 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5697 if (domain == DNSName("powerdns.com.")) {
5698 addRRSIG(keys, res->d_records, domain, 300);
5699 }
5700 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5701 if (domain == DNSName("powerdns.com.")) {
5702 addRRSIG(keys, res->d_records, domain, 300);
5703 }
5704 }
5705 else {
5706 if (domain == DNSName("powerdns.com.")) {
5707 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
5708 addRRSIG(keys, res->d_records, domain, 300);
5709 }
5710 else if (domain == targetCName) {
5711 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
5712 }
5713 }
5714
5715 return 1;
5716 }
5717 }
5718
5719 return 0;
5720 });
5721
5722 vector<DNSRecord> ret;
5723 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5724 BOOST_CHECK_EQUAL(res, RCode::NoError);
5725 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5726 BOOST_REQUIRE_EQUAL(ret.size(), 3);
5727 BOOST_CHECK_EQUAL(queriesCount, 11);
5728
5729 /* again, to test the cache */
5730 ret.clear();
5731 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5732 BOOST_CHECK_EQUAL(res, RCode::NoError);
5733 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5734 BOOST_REQUIRE_EQUAL(ret.size(), 3);
5735 BOOST_CHECK_EQUAL(queriesCount, 11);
5736 }
5737
5738 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
5739 std::unique_ptr<SyncRes> sr;
5740 initSR(sr, true);
5741
5742 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5743
5744 primeHints();
5745 const DNSName target("power-dns.com.");
5746 const DNSName targetCName("powerdns.com.");
5747 const ComboAddress targetCNameAddr("192.0.2.42");
5748 testkeysset_t keys;
5749
5750 auto luaconfsCopy = g_luaconfs.getCopy();
5751 luaconfsCopy.dsAnchors.clear();
5752 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5753 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5754 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5755 g_luaconfs.setState(luaconfsCopy);
5756
5757 size_t queriesCount = 0;
5758
5759 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) {
5760 queriesCount++;
5761
5762 if (type == QType::DS) {
5763 if (domain == DNSName("power-dns.com.")) {
5764 setLWResult(res, 0, false, false, true);
5765 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5766 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
5767 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5768 return 1;
5769 }
5770 }
5771 else if (type == QType::DNSKEY) {
5772 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
5773 setLWResult(res, 0, true, false, true);
5774 addDNSKEY(keys, domain, 300, res->d_records);
5775 addRRSIG(keys, res->d_records, domain, 300);
5776 return 1;
5777 }
5778 else {
5779 setLWResult(res, 0, false, false, true);
5780 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5781 return 1;
5782 }
5783 }
5784 else {
5785 if (isRootServer(ip)) {
5786 setLWResult(res, 0, false, false, true);
5787 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5788 addDS(DNSName("com."), 300, res->d_records, keys);
5789 addRRSIG(keys, res->d_records, DNSName("."), 300);
5790 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5791 return 1;
5792 }
5793 else if (ip == ComboAddress("192.0.2.1:53")) {
5794 if (domain == DNSName("com.")) {
5795 setLWResult(res, 0, true, false, true);
5796 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5797 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5798 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5799 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5800 }
5801 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
5802 setLWResult(res, 0, false, false, true);
5803 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5804 if (domain == targetCName) {
5805 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5806 }
5807 else if (domain == target) {
5808 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
5809 }
5810 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5811 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5812 }
5813 return 1;
5814 }
5815 else if (ip == ComboAddress("192.0.2.2:53")) {
5816 setLWResult(res, 0, true, false, true);
5817 if (type == QType::NS) {
5818 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5819 if (domain == DNSName("powerdns.com.")) {
5820 addRRSIG(keys, res->d_records, domain, 300);
5821 }
5822 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5823 if (domain == DNSName("powerdns.com.")) {
5824 addRRSIG(keys, res->d_records, domain, 300);
5825 }
5826 }
5827 else {
5828 if (domain == target) {
5829 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
5830 }
5831 else if (domain == targetCName) {
5832 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
5833 addRRSIG(keys, res->d_records, domain, 300);
5834 }
5835 }
5836 return 1;
5837 }
5838 }
5839
5840 return 0;
5841 });
5842
5843 vector<DNSRecord> ret;
5844 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5845 BOOST_CHECK_EQUAL(res, RCode::NoError);
5846 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5847 BOOST_REQUIRE_EQUAL(ret.size(), 3);
5848 BOOST_CHECK_EQUAL(queriesCount, 11);
5849
5850 /* again, to test the cache */
5851 ret.clear();
5852 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5853 BOOST_CHECK_EQUAL(res, RCode::NoError);
5854 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5855 BOOST_REQUIRE_EQUAL(ret.size(), 3);
5856 BOOST_CHECK_EQUAL(queriesCount, 11);
5857 }
5858
5859 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
5860 std::unique_ptr<SyncRes> sr;
5861 initSR(sr, true);
5862
5863 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5864
5865 primeHints();
5866 const DNSName target("power-dns.com.");
5867 const DNSName targetCName("powerdns.com.");
5868 const ComboAddress targetCNameAddr("192.0.2.42");
5869 testkeysset_t keys;
5870
5871 auto luaconfsCopy = g_luaconfs.getCopy();
5872 luaconfsCopy.dsAnchors.clear();
5873 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5874 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5875 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5876 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5877 g_luaconfs.setState(luaconfsCopy);
5878
5879 size_t queriesCount = 0;
5880
5881 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) {
5882 queriesCount++;
5883
5884 if (type == QType::DS) {
5885 return 0;
5886 }
5887 else if (type == QType::DNSKEY) {
5888 setLWResult(res, 0, true, false, true);
5889 addDNSKEY(keys, domain, 300, res->d_records);
5890 addRRSIG(keys, res->d_records, domain, 300);
5891 return 1;
5892 }
5893 else {
5894 if (isRootServer(ip)) {
5895 setLWResult(res, 0, false, false, true);
5896 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5897 addDS(DNSName("com."), 300, res->d_records, keys);
5898 addRRSIG(keys, res->d_records, DNSName("."), 300);
5899 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5900 return 1;
5901 }
5902 else if (ip == ComboAddress("192.0.2.1:53")) {
5903 if (domain == DNSName("com.")) {
5904 setLWResult(res, 0, true, false, true);
5905 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5906 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5907 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5908 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5909 }
5910 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
5911 setLWResult(res, 0, false, false, true);
5912 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5913 addDS(DNSName(domain), 300, res->d_records, keys);
5914 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5915 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5916 }
5917 return 1;
5918 }
5919 else if (ip == ComboAddress("192.0.2.2:53")) {
5920 setLWResult(res, 0, true, false, true);
5921 if (type == QType::NS) {
5922 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5923 addRRSIG(keys, res->d_records, domain, 300);
5924 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5925 addRRSIG(keys, res->d_records, domain, 300);
5926 }
5927 else {
5928 if (domain == target) {
5929 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
5930 /* No RRSIG, leading to bogus */
5931 }
5932 else if (domain == targetCName) {
5933 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
5934 addRRSIG(keys, res->d_records, domain, 300);
5935 }
5936 }
5937 return 1;
5938 }
5939 }
5940
5941 return 0;
5942 });
5943
5944 vector<DNSRecord> ret;
5945 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5946 BOOST_CHECK_EQUAL(res, RCode::NoError);
5947 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5948 BOOST_REQUIRE_EQUAL(ret.size(), 3);
5949 BOOST_CHECK_EQUAL(queriesCount, 11);
5950
5951 /* again, to test the cache */
5952 ret.clear();
5953 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5954 BOOST_CHECK_EQUAL(res, RCode::NoError);
5955 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5956 BOOST_REQUIRE_EQUAL(ret.size(), 3);
5957 BOOST_CHECK_EQUAL(queriesCount, 11);
5958 }
5959
5960 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
5961 std::unique_ptr<SyncRes> sr;
5962 initSR(sr, true);
5963
5964 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5965
5966 primeHints();
5967 const DNSName target("power-dns.com.");
5968 const DNSName targetCName("powerdns.com.");
5969 const ComboAddress targetCNameAddr("192.0.2.42");
5970 testkeysset_t keys;
5971
5972 auto luaconfsCopy = g_luaconfs.getCopy();
5973 luaconfsCopy.dsAnchors.clear();
5974 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5975 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5976 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5977 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5978 g_luaconfs.setState(luaconfsCopy);
5979
5980 size_t queriesCount = 0;
5981
5982 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) {
5983 queriesCount++;
5984
5985 if (type == QType::DS) {
5986 return 0;
5987 }
5988 else if (type == QType::DNSKEY) {
5989 setLWResult(res, 0, true, false, true);
5990 addDNSKEY(keys, domain, 300, res->d_records);
5991 addRRSIG(keys, res->d_records, domain, 300);
5992 return 1;
5993 }
5994 else {
5995 if (isRootServer(ip)) {
5996 setLWResult(res, 0, false, false, true);
5997 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5998 addDS(DNSName("com."), 300, res->d_records, keys);
5999 addRRSIG(keys, res->d_records, DNSName("."), 300);
6000 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6001 return 1;
6002 }
6003 else if (ip == ComboAddress("192.0.2.1:53")) {
6004 if (domain == DNSName("com.")) {
6005 setLWResult(res, 0, true, false, true);
6006 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6007 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6008 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6009 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6010 }
6011 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
6012 setLWResult(res, 0, false, false, true);
6013 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6014 addDS(DNSName(domain), 300, res->d_records, keys);
6015 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6016 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6017 }
6018 return 1;
6019 }
6020 else if (ip == ComboAddress("192.0.2.2:53")) {
6021 setLWResult(res, 0, true, false, true);
6022 if (type == QType::NS) {
6023 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6024 addRRSIG(keys, res->d_records, domain, 300);
6025 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6026 addRRSIG(keys, res->d_records, domain, 300);
6027 }
6028 else {
6029 if (domain == target) {
6030 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6031 addRRSIG(keys, res->d_records, domain, 300);
6032 }
6033 else if (domain == targetCName) {
6034 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6035 /* No RRSIG, leading to bogus */
6036 }
6037 }
6038 return 1;
6039 }
6040 }
6041
6042 return 0;
6043 });
6044
6045 vector<DNSRecord> ret;
6046 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6047 BOOST_CHECK_EQUAL(res, RCode::NoError);
6048 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6049 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6050 BOOST_CHECK_EQUAL(queriesCount, 11);
6051
6052 /* again, to test the cache */
6053 ret.clear();
6054 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6055 BOOST_CHECK_EQUAL(res, RCode::NoError);
6056 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6057 BOOST_REQUIRE_EQUAL(ret.size(), 3);
6058 BOOST_CHECK_EQUAL(queriesCount, 11);
6059 }
6060
6061 BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
6062 std::unique_ptr<SyncRes> sr;
6063 initSR(sr, true);
6064
6065 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6066
6067 primeHints();
6068 const DNSName target("power-dns.com.");
6069 const DNSName targetCName("powerdns.com.");
6070 const ComboAddress targetCNameAddr("192.0.2.42");
6071 testkeysset_t keys;
6072
6073 auto luaconfsCopy = g_luaconfs.getCopy();
6074 luaconfsCopy.dsAnchors.clear();
6075 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6076 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6077 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6078 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6079 g_luaconfs.setState(luaconfsCopy);
6080
6081 size_t queriesCount = 0;
6082
6083 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) {
6084 queriesCount++;
6085
6086 if (type == QType::DS) {
6087 return 0;
6088 }
6089 else if (type == QType::DNSKEY) {
6090 setLWResult(res, 0, true, false, true);
6091 addDNSKEY(keys, domain, 300, res->d_records);
6092 addRRSIG(keys, res->d_records, domain, 300);
6093 return 1;
6094 }
6095 else {
6096 if (isRootServer(ip)) {
6097 setLWResult(res, 0, false, false, true);
6098 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6099 addDS(DNSName("com."), 300, res->d_records, keys);
6100 addRRSIG(keys, res->d_records, DNSName("."), 300);
6101 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6102 return 1;
6103 }
6104 else if (ip == ComboAddress("192.0.2.1:53")) {
6105 if (domain == DNSName("com.")) {
6106 setLWResult(res, 0, true, false, true);
6107 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6108 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6109 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6110 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6111 }
6112 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
6113 setLWResult(res, 0, false, false, true);
6114 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6115 addDS(DNSName(domain), 300, res->d_records, keys);
6116 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6117 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6118 }
6119 return 1;
6120 }
6121 else if (ip == ComboAddress("192.0.2.2:53")) {
6122 setLWResult(res, 0, true, false, true);
6123 if (type == QType::NS) {
6124 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6125 addRRSIG(keys, res->d_records, domain, 300);
6126 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6127 addRRSIG(keys, res->d_records, domain, 300);
6128 }
6129 else {
6130 if (domain == target) {
6131 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6132 addRRSIG(keys, res->d_records, domain, 300);
6133 }
6134 else if (domain == targetCName) {
6135 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6136 addRRSIG(keys, res->d_records, domain, 300);
6137 }
6138 }
6139 return 1;
6140 }
6141 }
6142
6143 return 0;
6144 });
6145
6146 vector<DNSRecord> ret;
6147 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6148 BOOST_CHECK_EQUAL(res, RCode::NoError);
6149 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6150 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6151 BOOST_CHECK_EQUAL(queriesCount, 12);
6152
6153 /* again, to test the cache */
6154 ret.clear();
6155 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6156 BOOST_CHECK_EQUAL(res, RCode::NoError);
6157 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6158 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6159 BOOST_CHECK_EQUAL(queriesCount, 12);
6160 }
6161
6162 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
6163 std::unique_ptr<SyncRes> sr;
6164 initSR(sr, true);
6165
6166 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6167
6168 primeHints();
6169 const DNSName target("powerdns.com.");
6170 const DNSName targetCName("power-dns.com.");
6171 const ComboAddress targetCNameAddr("192.0.2.42");
6172 testkeysset_t keys;
6173
6174 auto luaconfsCopy = g_luaconfs.getCopy();
6175 luaconfsCopy.dsAnchors.clear();
6176 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6177 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6178 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6179 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6180 g_luaconfs.setState(luaconfsCopy);
6181
6182 size_t queriesCount = 0;
6183
6184 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) {
6185 queriesCount++;
6186
6187 if (type == QType::DS) {
6188 if (domain == DNSName("power-dns.com.")) {
6189 setLWResult(res, 0, false, false, true);
6190 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6191 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6192 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6193 return 1;
6194 }
6195 }
6196 else if (type == QType::DNSKEY) {
6197 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6198 setLWResult(res, 0, true, false, true);
6199 addDNSKEY(keys, domain, 300, res->d_records);
6200 addRRSIG(keys, res->d_records, domain, 300);
6201 return 1;
6202 }
6203 else {
6204 setLWResult(res, 0, false, false, true);
6205 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6206 return 1;
6207 }
6208 }
6209 else {
6210 if (isRootServer(ip)) {
6211 setLWResult(res, 0, false, false, true);
6212 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6213 addDS(DNSName("com."), 300, res->d_records, keys);
6214 addRRSIG(keys, res->d_records, DNSName("."), 300);
6215 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6216 return 1;
6217 }
6218 else if (ip == ComboAddress("192.0.2.1:53")) {
6219 if (domain == DNSName("com.")) {
6220 setLWResult(res, 0, true, false, true);
6221 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6222 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6223 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6224 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6225 }
6226 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
6227 setLWResult(res, 0, false, false, true);
6228 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6229 if (domain == DNSName("powerdns.com.")) {
6230 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6231 }
6232 else if (domain == targetCName) {
6233 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6234 }
6235 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6236 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6237 }
6238 return 1;
6239 }
6240 else if (ip == ComboAddress("192.0.2.2:53")) {
6241 setLWResult(res, 0, true, false, true);
6242 if (type == QType::NS) {
6243 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6244 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6245 }
6246 else {
6247 if (domain == DNSName("powerdns.com.")) {
6248 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6249 /* No RRSIG -> Bogus */
6250 }
6251 else if (domain == targetCName) {
6252 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6253 }
6254 }
6255 return 1;
6256 }
6257 }
6258
6259 return 0;
6260 });
6261
6262 vector<DNSRecord> ret;
6263 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6264 BOOST_CHECK_EQUAL(res, RCode::NoError);
6265 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6266 /* no RRSIG to show */
6267 BOOST_CHECK_EQUAL(ret.size(), 2);
6268 BOOST_CHECK_EQUAL(queriesCount, 10);
6269
6270 /* again, to test the cache */
6271 ret.clear();
6272 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6273 BOOST_CHECK_EQUAL(res, RCode::NoError);
6274 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6275 BOOST_CHECK_EQUAL(ret.size(), 2);
6276 BOOST_CHECK_EQUAL(queriesCount, 10);
6277 }
6278
6279 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
6280 std::unique_ptr<SyncRes> sr;
6281 initSR(sr, true);
6282
6283 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6284
6285 primeHints();
6286 const DNSName target("powerdns.com.");
6287 const ComboAddress targetAddr("192.0.2.42");
6288 testkeysset_t keys;
6289
6290 auto luaconfsCopy = g_luaconfs.getCopy();
6291 luaconfsCopy.dsAnchors.clear();
6292 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6293 /* No key material for .com */
6294 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6295 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
6296 g_luaconfs.setState(luaconfsCopy);
6297
6298 size_t queriesCount = 0;
6299
6300 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) {
6301 queriesCount++;
6302
6303 if (type == QType::DNSKEY) {
6304 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
6305 setLWResult(res, 0, true, false, true);
6306 addDNSKEY(keys, domain, 300, res->d_records);
6307 addRRSIG(keys, res->d_records, domain, 300);
6308 return 1;
6309 }
6310 else if (domain == DNSName("com.")) {
6311 setLWResult(res, 0, false, false, true);
6312 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6313 return 1;
6314 }
6315 }
6316 else {
6317 if (isRootServer(ip)) {
6318 setLWResult(res, 0, false, false, true);
6319 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6320 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
6321 addRRSIG(keys, res->d_records, DNSName("."), 300);
6322 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6323 return 1;
6324 }
6325 else if (ip == ComboAddress("192.0.2.1:53")) {
6326 if (target == domain) {
6327 setLWResult(res, 0, false, false, true);
6328 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6329 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6330 }
6331 else if (domain == DNSName("com.")) {
6332 setLWResult(res, 0, true, false, true);
6333 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6334 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6335 }
6336 return 1;
6337 }
6338 else if (ip == ComboAddress("192.0.2.2:53")) {
6339 setLWResult(res, 0, true, false, true);
6340 if (type == QType::NS) {
6341 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6342 }
6343 else {
6344 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6345 }
6346 addRRSIG(keys, res->d_records, domain, 300);
6347 return 1;
6348 }
6349 }
6350
6351 return 0;
6352 });
6353
6354 vector<DNSRecord> ret;
6355 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6356 BOOST_CHECK_EQUAL(res, RCode::NoError);
6357 /* should be insecure but we have a TA for powerdns.com. */
6358 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6359 /* We got a RRSIG */
6360 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6361 BOOST_CHECK(ret[0].d_type == QType::A);
6362 /* - NS com. (at . and com.)
6363 - NS powerdns.com (com. and powerdns.com.)
6364 - DNSKEY (. and powerdns.com.)
6365 - A powerdns.com
6366 */
6367 BOOST_CHECK_EQUAL(queriesCount, 7);
6368
6369 /* again, to test the cache */
6370 ret.clear();
6371 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6372 BOOST_CHECK_EQUAL(res, RCode::NoError);
6373 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6374 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6375 BOOST_CHECK(ret[0].d_type == QType::A);
6376 BOOST_CHECK_EQUAL(queriesCount, 7);
6377 }
6378
6379 BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
6380 std::unique_ptr<SyncRes> sr;
6381 initSR(sr, true);
6382
6383 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6384
6385 primeHints();
6386 const DNSName target("powerdns.com.");
6387 const ComboAddress targetAddr("192.0.2.42");
6388 testkeysset_t keys;
6389
6390 auto luaconfsCopy = g_luaconfs.getCopy();
6391 luaconfsCopy.dsAnchors.clear();
6392 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6393 /* No key material for .com */
6394 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6395 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
6396 g_luaconfs.setState(luaconfsCopy);
6397
6398 size_t queriesCount = 0;
6399
6400 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) {
6401 queriesCount++;
6402
6403 if (type == QType::DNSKEY) {
6404 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
6405 setLWResult(res, 0, true, false, true);
6406 addDNSKEY(keys, domain, 300, res->d_records);
6407 addRRSIG(keys, res->d_records, domain, 300);
6408 return 1;
6409 }
6410 else if (domain == DNSName("com.")) {
6411 setLWResult(res, 0, false, false, true);
6412 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6413 return 1;
6414 }
6415 }
6416 else {
6417 if (target.isPartOf(domain) && isRootServer(ip)) {
6418 setLWResult(res, 0, false, false, true);
6419 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6420 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
6421 addRRSIG(keys, res->d_records, DNSName("."), 300);
6422 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6423 return 1;
6424 }
6425 else if (ip == ComboAddress("192.0.2.1:53")) {
6426 if (target == domain) {
6427 setLWResult(res, 0, false, false, true);
6428 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6429 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6430 }
6431 else if (domain == DNSName("com.")) {
6432 setLWResult(res, 0, true, false, true);
6433 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6434 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6435 }
6436 return 1;
6437 }
6438 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
6439 setLWResult(res, 0, true, false, true);
6440 if (type == QType::NS) {
6441 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6442 }
6443 else {
6444 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6445 }
6446 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
6447 return 1;
6448 }
6449 }
6450
6451 return 0;
6452 });
6453
6454 vector<DNSRecord> ret;
6455 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6456 BOOST_CHECK_EQUAL(res, RCode::NoError);
6457 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
6458 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6459 /* No RRSIG */
6460 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6461 BOOST_CHECK(ret[0].d_type == QType::A);
6462 /* - NS com. (at . and com.)
6463 - NS powerdns.com (com. and powerdns.com.)
6464 - DNSKEY (.)
6465 - A powerdns.com (no DNSKEY because no RRSIG)
6466 */
6467 BOOST_CHECK_EQUAL(queriesCount, 6);
6468
6469 /* again, to test the cache */
6470 ret.clear();
6471 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6472 BOOST_CHECK_EQUAL(res, RCode::NoError);
6473 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6474 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6475 BOOST_CHECK(ret[0].d_type == QType::A);
6476 BOOST_CHECK_EQUAL(queriesCount, 6);
6477 }
6478
6479 BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
6480 std::unique_ptr<SyncRes> sr;
6481 initSR(sr, true);
6482
6483 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6484
6485 primeHints();
6486 const DNSName target(".");
6487 testkeysset_t keys;
6488
6489 auto luaconfsCopy = g_luaconfs.getCopy();
6490 luaconfsCopy.dsAnchors.clear();
6491 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6492 /* Add a NTA for "." */
6493 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
6494 g_luaconfs.setState(luaconfsCopy);
6495
6496 size_t queriesCount = 0;
6497
6498 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) {
6499 queriesCount++;
6500
6501 if (domain == target && type == QType::NS) {
6502
6503 setLWResult(res, 0, true, false, true);
6504 char addr[] = "a.root-servers.net.";
6505 for (char idx = 'a'; idx <= 'm'; idx++) {
6506 addr[0] = idx;
6507 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
6508 }
6509
6510 addRRSIG(keys, res->d_records, domain, 300);
6511
6512 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
6513 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
6514
6515 return 1;
6516 } else if (domain == target && type == QType::DNSKEY) {
6517
6518 setLWResult(res, 0, true, false, true);
6519
6520 /* No DNSKEY */
6521
6522 return 1;
6523 }
6524
6525 return 0;
6526 });
6527
6528 vector<DNSRecord> ret;
6529 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
6530 BOOST_CHECK_EQUAL(res, RCode::NoError);
6531 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6532 /* 13 NS + 1 RRSIG */
6533 BOOST_REQUIRE_EQUAL(ret.size(), 14);
6534 BOOST_CHECK_EQUAL(queriesCount, 1);
6535
6536 /* again, to test the cache */
6537 ret.clear();
6538 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
6539 BOOST_CHECK_EQUAL(res, RCode::NoError);
6540 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6541 BOOST_REQUIRE_EQUAL(ret.size(), 14);
6542 BOOST_CHECK_EQUAL(queriesCount, 1);
6543 }
6544
6545 BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
6546 std::unique_ptr<SyncRes> sr;
6547 initSR(sr, true);
6548
6549 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6550
6551 primeHints();
6552 const DNSName target(".");
6553 testkeysset_t keys;
6554
6555 /* Remove the root DS */
6556 auto luaconfsCopy = g_luaconfs.getCopy();
6557 luaconfsCopy.dsAnchors.clear();
6558 g_luaconfs.setState(luaconfsCopy);
6559
6560 size_t queriesCount = 0;
6561
6562 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) {
6563 queriesCount++;
6564
6565 if (domain == target && type == QType::NS) {
6566
6567 setLWResult(res, 0, true, false, true);
6568 char addr[] = "a.root-servers.net.";
6569 for (char idx = 'a'; idx <= 'm'; idx++) {
6570 addr[0] = idx;
6571 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
6572 }
6573
6574 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
6575 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
6576
6577 return 1;
6578 }
6579
6580 return 0;
6581 });
6582
6583 vector<DNSRecord> ret;
6584 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
6585 BOOST_CHECK_EQUAL(res, RCode::NoError);
6586 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6587 /* 13 NS + 0 RRSIG */
6588 BOOST_REQUIRE_EQUAL(ret.size(), 13);
6589 BOOST_CHECK_EQUAL(queriesCount, 1);
6590
6591 /* again, to test the cache */
6592 ret.clear();
6593 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
6594 BOOST_CHECK_EQUAL(res, RCode::NoError);
6595 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6596 BOOST_REQUIRE_EQUAL(ret.size(), 13);
6597 BOOST_CHECK_EQUAL(queriesCount, 1);
6598 }
6599
6600 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
6601 std::unique_ptr<SyncRes> sr;
6602 initSR(sr, true);
6603
6604 g_dnssecmode = DNSSECMode::ValidateAll;
6605
6606 primeHints();
6607 const DNSName target("powerdns.com.");
6608 testkeysset_t keys;
6609
6610 auto luaconfsCopy = g_luaconfs.getCopy();
6611 luaconfsCopy.dsAnchors.clear();
6612 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6613 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6614 g_luaconfs.setState(luaconfsCopy);
6615
6616 size_t queriesCount = 0;
6617
6618 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) {
6619 queriesCount++;
6620
6621 if (type == QType::DS) {
6622 return 0;
6623 }
6624 else if (type == QType::DNSKEY) {
6625 setLWResult(res, 0, true, false, true);
6626 addDNSKEY(keys, domain, 300, res->d_records);
6627 addRRSIG(keys, res->d_records, domain, 300);
6628 return 1;
6629 }
6630 else {
6631
6632 setLWResult(res, 0, true, false, true);
6633 return 1;
6634 }
6635
6636 return 0;
6637 });
6638
6639 vector<DNSRecord> ret;
6640 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6641 BOOST_CHECK_EQUAL(res, RCode::NoError);
6642 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6643 BOOST_REQUIRE_EQUAL(ret.size(), 0);
6644 /* com|NS, powerdns.com|NS, powerdns.com|A */
6645 BOOST_CHECK_EQUAL(queriesCount, 3);
6646
6647 /* again, to test the cache */
6648 ret.clear();
6649 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6650 BOOST_CHECK_EQUAL(res, RCode::NoError);
6651 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6652 BOOST_REQUIRE_EQUAL(ret.size(), 0);
6653 /* we don't store empty results */
6654 BOOST_CHECK_EQUAL(queriesCount, 6);
6655 }
6656
6657 /*
6658 // cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
6659
6660 - check out of band support
6661
6662 - check preoutquery
6663
6664 */
6665
6666 BOOST_AUTO_TEST_SUITE_END()