]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/test-syncres_cc.cc
Merge pull request #6620 from Habbie/nit
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc.cc
CommitLineData
30ee601a
RG
1#define BOOST_TEST_DYN_LINK
2#define BOOST_TEST_NO_MAIN
3#include <boost/test/unit_test.hpp>
4
5#include "arguments.hh"
95823c07 6#include "base32.hh"
8455425c
RG
7#include "dnssecinfra.hh"
8#include "dnsseckeeper.hh"
30ee601a
RG
9#include "lua-recursor4.hh"
10#include "namespaces.hh"
11#include "rec-lua-conf.hh"
12#include "root-dnssec.hh"
13#include "syncres.hh"
e503653f 14#include "test-common.hh"
6dfff36f 15#include "utility.hh"
30ee601a
RG
16#include "validate-recursor.hh"
17
30ee601a
RG
18RecursorStats g_stats;
19GlobalStateHolder<LuaConfigItems> g_luaconfs;
f26bf547 20thread_local std::unique_ptr<MemRecursorCache> t_RC{nullptr};
30ee601a 21unsigned int g_numThreads = 1;
c1c29961 22bool g_lowercaseOutgoing = false;
30ee601a
RG
23
24/* Fake some required functions we didn't want the trouble to
25 link with */
26ArgvMap &arg()
27{
28 static ArgvMap theArg;
29 return theArg;
30}
31
32int getMTaskerTID()
33{
34 return 0;
35}
36
5899ee54 37bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
30ee601a
RG
38{
39 return false;
40}
41
deca7d8f 42int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained)
30ee601a
RG
43{
44 return 0;
45}
46
47/* primeHints() is only here for now because it
48 was way too much trouble to link with the real one.
49 We should fix this, empty functions are one thing, but this is
50 bad.
51*/
52
53#include "root-addresses.hh"
54
55void primeHints(void)
56{
57 vector<DNSRecord> nsset;
58 if(!t_RC)
f26bf547 59 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
30ee601a
RG
60
61 DNSRecord arr, aaaarr, nsrr;
62 nsrr.d_name=g_rootdnsname;
63 arr.d_type=QType::A;
64 aaaarr.d_type=QType::AAAA;
65 nsrr.d_type=QType::NS;
66 arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(nullptr)+3600000;
67
68 for(char c='a';c<='m';++c) {
e4f772ce 69 char templ[40];
30ee601a
RG
70 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
71 templ[sizeof(templ)-1] = '\0';
72 *templ=c;
73 aaaarr.d_name=arr.d_name=DNSName(templ);
74 nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
75 arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
76 vector<DNSRecord> aset;
77 aset.push_back(arr);
606accb0 78 t_RC->replace(time(nullptr), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
30ee601a
RG
79 if (rootIps6[c-'a'] != NULL) {
80 aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
81
82 vector<DNSRecord> aaaaset;
83 aaaaset.push_back(aaaarr);
606accb0 84 t_RC->replace(time(nullptr), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
30ee601a
RG
85 }
86
87 nsset.push_back(nsrr);
88 }
606accb0 89 t_RC->replace(time(nullptr), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
30ee601a
RG
90}
91
92LuaConfigItems::LuaConfigItems()
93{
94 for (const auto &dsRecord : rootDSs) {
95 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
96 dsAnchors[g_rootdnsname].insert(*ds);
97 }
98}
99
100/* Some helpers functions */
101
102static void init(bool debug=false)
103{
e6a9dde5
PL
104 g_log.setName("test");
105 g_log.disableSyslog(true);
b4c8789a 106
30ee601a 107 if (debug) {
e6a9dde5
PL
108 g_log.setLoglevel((Logger::Urgency)(6)); // info and up
109 g_log.toConsole(Logger::Info);
30ee601a 110 }
b4c8789a 111 else {
e6a9dde5
PL
112 g_log.setLoglevel(Logger::None);
113 g_log.toConsole(Logger::Error);
b4c8789a 114 }
30ee601a 115
d6e797b8 116 reportAllTypes();
30ee601a 117
f26bf547 118 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
30ee601a 119
30ee601a
RG
120 SyncRes::s_maxqperq = 50;
121 SyncRes::s_maxtotusec = 1000*7000;
122 SyncRes::s_maxdepth = 40;
123 SyncRes::s_maxnegttl = 3600;
124 SyncRes::s_maxcachettl = 86400;
125 SyncRes::s_packetcachettl = 3600;
126 SyncRes::s_packetcacheservfailttl = 60;
127 SyncRes::s_serverdownmaxfails = 64;
128 SyncRes::s_serverdownthrottletime = 60;
129 SyncRes::s_doIPv6 = true;
e9f9b8ec
RG
130 SyncRes::s_ecsipv4limit = 24;
131 SyncRes::s_ecsipv6limit = 56;
f58c8379 132 SyncRes::s_rootNXTrust = true;
d6e797b8 133 SyncRes::s_minimumTTL = 0;
648bcbd1 134 SyncRes::s_serverID = "PowerDNS Unit Tests Server ID";
2fe3354d
CH
135 SyncRes::clearEDNSLocalSubnets();
136 SyncRes::addEDNSLocalSubnet("0.0.0.0/0");
137 SyncRes::addEDNSLocalSubnet("::/0");
138 SyncRes::clearEDNSRemoteSubnets();
9065eb05
RG
139 SyncRes::clearEDNSDomains();
140 SyncRes::clearDelegationOnly();
141 SyncRes::clearDontQuery();
2fe3354d 142 SyncRes::setECSScopeZeroAddress(Netmask("127.0.0.1/32"));
648bcbd1 143
a712cb56 144 SyncRes::clearNSSpeeds();
6dfff36f 145 BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0);
a712cb56 146 SyncRes::clearEDNSStatuses();
6dfff36f 147 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0);
a712cb56 148 SyncRes::clearThrottle();
6dfff36f 149 BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0);
a712cb56 150 SyncRes::clearFailedServers();
6dfff36f 151 BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0);
a712cb56 152
648bcbd1
RG
153 auto luaconfsCopy = g_luaconfs.getCopy();
154 luaconfsCopy.dfe.clear();
8455425c
RG
155 luaconfsCopy.dsAnchors.clear();
156 for (const auto &dsRecord : rootDSs) {
157 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
158 luaconfsCopy.dsAnchors[g_rootdnsname].insert(*ds);
159 }
160 luaconfsCopy.negAnchors.clear();
648bcbd1
RG
161 g_luaconfs.setState(luaconfsCopy);
162
8455425c 163 g_dnssecmode = DNSSECMode::Off;
895449a5 164 g_dnssecLOG = debug;
b7c40613 165 g_maxNSEC3Iterations = 2500;
8455425c 166
648bcbd1 167 ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Unit Tests";
964ee532
RG
168 ::arg().set("rng")="auto";
169 ::arg().set("entropy-source")="/dev/urandom";
30ee601a
RG
170}
171
895449a5 172static void initSR(std::unique_ptr<SyncRes>& sr, bool dnssec=false, bool debug=false, time_t fakeNow=0)
30ee601a
RG
173{
174 struct timeval now;
d6e797b8
RG
175 if (fakeNow > 0) {
176 now.tv_sec = fakeNow;
177 now.tv_usec = 0;
178 }
179 else {
180 Utility::gettimeofday(&now, 0);
181 }
182
895449a5
RG
183 init(debug);
184
30ee601a 185 sr = std::unique_ptr<SyncRes>(new SyncRes(now));
895449a5 186 sr->setDoEDNS0(true);
0c43f455
RG
187 if (dnssec) {
188 sr->setDoDNSSEC(dnssec);
189 }
190
895449a5
RG
191 sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
192
a712cb56
RG
193 SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
194 SyncRes::clearNegCache();
30ee601a
RG
195}
196
0c43f455
RG
197static void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
198{
199 sr->setDNSSECValidationRequested(true);
200 g_dnssecmode = mode;
201}
202
30ee601a
RG
203static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
204{
205 res->d_rcode = rcode;
206 res->d_aabit = aa;
207 res->d_tcbit = tc;
208 res->d_haveEDNS = edns;
209}
210
d6e797b8
RG
211static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
212{
213 addRecordToList(res->d_records, name, type, content, place, ttl);
30ee601a
RG
214}
215
216static void addRecordToLW(LWResult* res, const std::string& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
217{
218 addRecordToLW(res, DNSName(name), type, content, place, ttl);
219}
220
221static bool isRootServer(const ComboAddress& ip)
222{
8455425c
RG
223 if (ip.isIPv4()) {
224 for (size_t idx = 0; idx < rootIps4Count; idx++) {
225 if (ip.toString() == rootIps4[idx]) {
226 return true;
227 }
30ee601a
RG
228 }
229 }
8455425c
RG
230 else {
231 for (size_t idx = 0; idx < rootIps6Count; idx++) {
232 if (ip.toString() == rootIps6[idx]) {
233 return true;
234 }
30ee601a
RG
235 }
236 }
8455425c 237
30ee601a
RG
238 return false;
239}
240
179b340d 241static 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)
8455425c
RG
242{
243 time_t now = time(nullptr);
244 DNSKEYRecordContent drc = dpk.getDNSKEY();
245 const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
246
247 rrc.d_type = signQType;
248 rrc.d_labels = signQName.countLabels() - signQName.isWildcard();
249 rrc.d_originalttl = signTTL;
179b340d 250 rrc.d_siginception = inception ? *inception : (now - 10);
8455425c
RG
251 rrc.d_sigexpire = now + sigValidity;
252 rrc.d_signer = signer;
253 rrc.d_tag = 0;
254 rrc.d_tag = drc.getTag();
3d5ebf10 255 rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
8455425c
RG
256
257 std::string msg = getMessageForRRSET(signQName, rrc, toSign);
258
259 rrc.d_signature = rc->sign(msg);
260}
261
b7f378d1
RG
262typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t;
263
5374b03b 264static bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional<uint8_t> algo=boost::none, boost::optional<DNSName> wildcard=boost::none)
8455425c
RG
265{
266 if (records.empty()) {
5374b03b 267 return false;
8455425c
RG
268 }
269
270 const auto it = keys.find(signer);
271 if (it == keys.cend()) {
86f1af1c 272 throw std::runtime_error("No DNSKEY found for " + signer.toLogString() + ", unable to compute the requested RRSIG");
8455425c
RG
273 }
274
275 size_t recordsCount = records.size();
276 const DNSName& name = records[recordsCount-1].d_name;
277 const uint16_t type = records[recordsCount-1].d_type;
278
279 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
280 for (const auto record : records) {
281 if (record.d_name == name && record.d_type == type) {
282 recordcontents.push_back(record.d_content);
283 }
284 }
285
286 RRSIGRecordContent rrc;
82fbd934 287 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);
3d5ebf10
RG
288 if (broken) {
289 rrc.d_signature[0] ^= 42;
290 }
8455425c
RG
291
292 DNSRecord rec;
dbbef467 293 rec.d_type = QType::RRSIG;
8455425c
RG
294 rec.d_place = records[recordsCount-1].d_place;
295 rec.d_name = records[recordsCount-1].d_name;
dbbef467 296 rec.d_ttl = records[recordsCount-1].d_ttl;
8455425c
RG
297
298 rec.d_content = std::make_shared<RRSIGRecordContent>(rrc);
299 records.push_back(rec);
5374b03b
RG
300
301 return true;
8455425c
RG
302}
303
b7f378d1 304static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records)
8455425c
RG
305{
306 const auto it = keys.find(signer);
307 if (it == keys.cend()) {
86f1af1c 308 throw std::runtime_error("No DNSKEY found for " + signer.toLogString());
8455425c
RG
309 }
310
311 DNSRecord rec;
312 rec.d_place = DNSResourceRecord::ANSWER;
313 rec.d_name = signer;
314 rec.d_type = QType::DNSKEY;
315 rec.d_ttl = ttl;
316
b7f378d1 317 rec.d_content = std::make_shared<DNSKEYRecordContent>(it->second.first.getDNSKEY());
8455425c
RG
318 records.push_back(rec);
319}
320
5374b03b 321static bool addDS(const DNSName& domain, uint32_t ttl, std::vector<DNSRecord>& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY)
8455425c 322{
b7f378d1
RG
323 const auto it = keys.find(domain);
324 if (it == keys.cend()) {
5374b03b 325 return false;
8455425c
RG
326 }
327
b7f378d1
RG
328 DNSRecord rec;
329 rec.d_name = domain;
330 rec.d_type = QType::DS;
a53e8fe3 331 rec.d_place = place;
b7f378d1
RG
332 rec.d_ttl = ttl;
333 rec.d_content = std::make_shared<DSRecordContent>(it->second.second);
8455425c 334
b7f378d1 335 records.push_back(rec);
5374b03b 336 return true;
8455425c
RG
337}
338
339static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
340{
341 NSECRecordContent nrc;
342 nrc.d_next = next;
343 nrc.d_set = types;
344
345 DNSRecord rec;
346 rec.d_name = domain;
347 rec.d_ttl = ttl;
348 rec.d_type = QType::NSEC;
349 rec.d_content = std::make_shared<NSECRecordContent>(nrc);
350 rec.d_place = DNSResourceRecord::AUTHORITY;
351
352 records.push_back(rec);
353}
354
95823c07
RG
355static void addNSEC3RecordToLW(const DNSName& hashedName, const std::string& hashedNext, const std::string& salt, unsigned int iterations, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
356{
357 NSEC3RecordContent nrc;
358 nrc.d_algorithm = 1;
359 nrc.d_flags = 0;
360 nrc.d_iterations = iterations;
361 nrc.d_salt = salt;
362 nrc.d_nexthash = hashedNext;
363 nrc.d_set = types;
364
365 DNSRecord rec;
366 rec.d_name = hashedName;
367 rec.d_ttl = ttl;
368 rec.d_type = QType::NSEC3;
369 rec.d_content = std::make_shared<NSEC3RecordContent>(nrc);
370 rec.d_place = DNSResourceRecord::AUTHORITY;
371
372 records.push_back(rec);
373}
374
b7c40613 375static void addNSEC3UnhashedRecordToLW(const DNSName& domain, const DNSName& zone, const std::string& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records, unsigned int iterations=10)
95823c07
RG
376{
377 static const std::string salt = "deadbeef";
95823c07
RG
378 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
379
9b061cf5 380 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, next, salt, iterations, types, ttl, records);
95823c07
RG
381}
382
b7c40613 383static void addNSEC3NarrowRecordToLW(const DNSName& domain, const DNSName& zone, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records, unsigned int iterations=10)
95823c07
RG
384{
385 static const std::string salt = "deadbeef";
95823c07 386 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
95823c07
RG
387 std::string hashedNext(hashed);
388 incrementHash(hashedNext);
389 decrementHash(hashed);
390
9b061cf5 391 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, hashedNext, salt, iterations, types, ttl, records);
95823c07
RG
392}
393
b7f378d1 394static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys)
8455425c
RG
395{
396 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(algo));
b7f378d1 397 dcke->create((algo <= 10) ? 2048 : dcke->getBits());
8455425c
RG
398 DNSSECPrivateKey dpk;
399 dpk.d_flags = 256;
400 dpk.setKey(dcke);
8455425c 401 DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest);
b7f378d1
RG
402 keys[name] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk,ds);
403}
404
405static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map<DNSName,dsmap_t>& dsAnchors)
406{
407 generateKeyMaterial(name, algo, digest, keys);
408 dsAnchors[name].insert(keys[name].second);
8455425c
RG
409}
410
f4de85a3 411static int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut=true)
5374b03b
RG
412{
413 if (type == QType::DS) {
414 auth.chopOff();
415
416 setLWResult(res, 0, true, false, true);
417
418 if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) {
419 addRRSIG(keys, res->d_records, auth, 300);
420 }
421 else {
422 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
423
424 /* if the auth zone is signed, we need to provide a secure denial */
425 const auto it = keys.find(auth);
426 if (it != keys.cend()) {
427 /* sign the SOA */
428 addRRSIG(keys, res->d_records, auth, 300);
429 /* add a NSEC denying the DS */
f4de85a3
RG
430 std::set<uint16_t> types = { QType::NSEC };
431 if (proveCut) {
432 types.insert(QType::NS);
433 }
434
435 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
5374b03b
RG
436 addRRSIG(keys, res->d_records, auth, 300);
437 }
438 }
439
440 return 1;
441 }
442
443 if (type == QType::DNSKEY) {
444 setLWResult(res, 0, true, false, true);
dbbef467
RG
445 addDNSKEY(keys, domain, 300, res->d_records);
446 addRRSIG(keys, res->d_records, domain, 300);
5374b03b
RG
447 return 1;
448 }
449
450 return 0;
451}
452
30ee601a
RG
453/* Real tests */
454
455BOOST_AUTO_TEST_SUITE(syncres_cc)
456
457BOOST_AUTO_TEST_CASE(test_root_primed) {
458 std::unique_ptr<SyncRes> sr;
895449a5 459 initSR(sr);
30ee601a
RG
460
461 primeHints();
895449a5 462
4d2be65d 463 const DNSName target("a.root-servers.net.");
30ee601a 464
4d2be65d 465 /* we are primed, we should be able to resolve A a.root-servers.net. without any query */
30ee601a 466 vector<DNSRecord> ret;
4d2be65d 467 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 468 BOOST_CHECK_EQUAL(res, RCode::NoError);
4d2be65d
RG
469 BOOST_REQUIRE_EQUAL(ret.size(), 1);
470 BOOST_CHECK(ret[0].d_type == QType::A);
471 BOOST_CHECK_EQUAL(ret[0].d_name, target);
472
473 ret.clear();
474 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1
RG
475 BOOST_CHECK_EQUAL(res, RCode::NoError);
476 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
4d2be65d
RG
477 BOOST_REQUIRE_EQUAL(ret.size(), 1);
478 BOOST_CHECK(ret[0].d_type == QType::AAAA);
479 BOOST_CHECK_EQUAL(ret[0].d_name, target);
4d2be65d
RG
480}
481
482BOOST_AUTO_TEST_CASE(test_root_primed_ns) {
483 std::unique_ptr<SyncRes> sr;
895449a5 484 initSR(sr);
4d2be65d
RG
485
486 primeHints();
487 const DNSName target(".");
488
489 /* we are primed, but we should not be able to NS . without any query
490 because the . NS entry is not stored as authoritative */
491
492 size_t queriesCount = 0;
493
deca7d8f 494 sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4d2be65d
RG
495 queriesCount++;
496
497 if (domain == target && type == QType::NS) {
498
499 setLWResult(res, 0, true, false, true);
8455425c 500 char addr[] = "a.root-servers.net.";
4d2be65d 501 for (char idx = 'a'; idx <= 'm'; idx++) {
8455425c
RG
502 addr[0] = idx;
503 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4d2be65d
RG
504 }
505
506 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
507 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
508
509 return 1;
510 }
511
512 return 0;
513 });
514
515 vector<DNSRecord> ret;
516 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1 517 BOOST_CHECK_EQUAL(res, RCode::NoError);
4d2be65d
RG
518 BOOST_REQUIRE_EQUAL(ret.size(), 13);
519 BOOST_CHECK_EQUAL(queriesCount, 1);
30ee601a
RG
520}
521
522BOOST_AUTO_TEST_CASE(test_root_not_primed) {
523 std::unique_ptr<SyncRes> sr;
895449a5 524 initSR(sr);
30ee601a
RG
525
526 size_t queriesCount = 0;
527
deca7d8f 528 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
30ee601a
RG
529 queriesCount++;
530
531 if (domain == g_rootdnsname && type == QType::NS) {
532 setLWResult(res, 0, true, false, true);
533 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
534 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
535 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
536
537 return 1;
538 }
539
540 return 0;
541 });
542
543 /* we are not primed yet, so SyncRes will have to call primeHints()
544 then call getRootNS(), for which at least one of the root servers needs to answer */
545 vector<DNSRecord> ret;
546 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
b7f378d1 547 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
548 BOOST_CHECK_EQUAL(ret.size(), 1);
549 BOOST_CHECK_EQUAL(queriesCount, 2);
550}
551
552BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
553 std::unique_ptr<SyncRes> sr;
895449a5 554 initSR(sr);
30ee601a
RG
555 std::set<ComboAddress> downServers;
556
557 /* we are not primed yet, so SyncRes will have to call primeHints()
558 then call getRootNS(), for which at least one of the root servers needs to answer.
559 None will, so it should ServFail.
560 */
deca7d8f 561 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
30ee601a
RG
562
563 downServers.insert(ip);
564 return 0;
565 });
566
567 vector<DNSRecord> ret;
568 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
f58c8379 569 BOOST_CHECK_EQUAL(res, RCode::ServFail);
30ee601a
RG
570 BOOST_CHECK_EQUAL(ret.size(), 0);
571 BOOST_CHECK(downServers.size() > 0);
572 /* we explicitly refuse to mark the root servers down */
573 for (const auto& server : downServers) {
a712cb56 574 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
30ee601a
RG
575 }
576}
577
578BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
579 std::unique_ptr<SyncRes> sr;
895449a5 580 initSR(sr);
30ee601a
RG
581
582 ComboAddress noEDNSServer;
583 size_t queriesWithEDNS = 0;
584 size_t queriesWithoutEDNS = 0;
585
deca7d8f 586 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &noEDNSServer](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
30ee601a
RG
587 if (EDNS0Level != 0) {
588 queriesWithEDNS++;
589 noEDNSServer = ip;
590
591 setLWResult(res, RCode::FormErr);
592 return 1;
593 }
594
595 queriesWithoutEDNS++;
596
597 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
598 setLWResult(res, 0, true, false, false);
599 addRecordToLW(res, domain, QType::A, "192.0.2.1");
600 return 1;
601 }
602
603 return 0;
604 });
605
606 primeHints();
607
608 /* fake that the root NS doesn't handle EDNS, check that we fallback */
609 vector<DNSRecord> ret;
610 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 611 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
612 BOOST_CHECK_EQUAL(ret.size(), 1);
613 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
614 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
a712cb56
RG
615 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
616 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
30ee601a
RG
617}
618
619BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) {
620 std::unique_ptr<SyncRes> sr;
895449a5 621 initSR(sr);
30ee601a
RG
622
623 size_t queriesWithEDNS = 0;
624 size_t queriesWithoutEDNS = 0;
625
deca7d8f 626 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
30ee601a
RG
627 if (EDNS0Level != 0) {
628 queriesWithEDNS++;
629 setLWResult(res, RCode::NotImp);
630 return 1;
631 }
632
633 queriesWithoutEDNS++;
634
635 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
636 setLWResult(res, 0, true, false, false);
637 addRecordToLW(res, domain, QType::A, "192.0.2.1");
638 return 1;
639 }
640
641 return 0;
642 });
643
644 primeHints();
645
646 /* fake that the NS doesn't handle EDNS, check that we fallback */
647 vector<DNSRecord> ret;
648 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 649 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
650 BOOST_CHECK_EQUAL(ret.size(), 1);
651 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
652 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
653}
654
655BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
656 std::unique_ptr<SyncRes> sr;
895449a5 657 initSR(sr);
30ee601a 658
deca7d8f 659 sr->setAsyncCallback([](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
30ee601a
RG
660 if (!doTCP) {
661 setLWResult(res, 0, false, true, false);
662 return 1;
663 }
664 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
665 setLWResult(res, 0, true, false, false);
666 addRecordToLW(res, domain, QType::A, "192.0.2.1");
667 return 1;
668 }
669
670 return 0;
671 });
672
673 primeHints();
674
675 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
676 vector<DNSRecord> ret;
677 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 678 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
679}
680
3337c2f7
RG
681BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
682 std::unique_ptr<SyncRes> sr;
895449a5 683 initSR(sr);
3337c2f7
RG
684
685 size_t tcpQueriesCount = 0;
686
deca7d8f 687 sr->setAsyncCallback([&tcpQueriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
688 if (!doTCP) {
689 setLWResult(res, 0, true, true, false);
690 return 1;
691 }
692
693 /* first TCP query is answered with a TC response */
694 tcpQueriesCount++;
695 if (tcpQueriesCount == 1) {
696 setLWResult(res, 0, true, true, false);
697 }
698 else {
699 setLWResult(res, 0, true, false, false);
700 }
701
702 addRecordToLW(res, domain, QType::A, "192.0.2.1");
703 return 1;
704 });
705
706 primeHints();
707
708 vector<DNSRecord> ret;
709 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 710 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
711 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
712}
713
30ee601a
RG
714BOOST_AUTO_TEST_CASE(test_all_nss_down) {
715 std::unique_ptr<SyncRes> sr;
895449a5 716 initSR(sr);
30ee601a
RG
717 std::set<ComboAddress> downServers;
718
719 primeHints();
720
deca7d8f 721 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
30ee601a
RG
722
723 if (isRootServer(ip)) {
8455425c 724 setLWResult(res, 0, false, false, true);
30ee601a
RG
725 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
726 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
727 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
728 return 1;
729 }
730 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 731 setLWResult(res, 0, false, false, true);
30ee601a
RG
732 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
733 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
734 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
735 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
736 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
737 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
738 return 1;
739 }
740 else {
741 downServers.insert(ip);
742 return 0;
743 }
744 });
745
ccb07d93
RG
746 DNSName target("powerdns.com.");
747
30ee601a 748 vector<DNSRecord> ret;
ccb07d93 749 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 750 BOOST_CHECK_EQUAL(res, RCode::ServFail);
30ee601a
RG
751 BOOST_CHECK_EQUAL(ret.size(), 0);
752 BOOST_CHECK_EQUAL(downServers.size(), 4);
753
606accb0 754 time_t now = sr->getNow().tv_sec;
30ee601a 755 for (const auto& server : downServers) {
a712cb56 756 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
606accb0 757 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
30ee601a
RG
758 }
759}
760
648bcbd1
RG
761BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
762 std::unique_ptr<SyncRes> sr;
895449a5 763 initSR(sr);
648bcbd1
RG
764 std::set<ComboAddress> downServers;
765
766 primeHints();
767
deca7d8f 768 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
769
770 if (isRootServer(ip)) {
8455425c 771 setLWResult(res, 0, false, false, true);
648bcbd1
RG
772 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
773 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
774 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
775 return 1;
776 }
777 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 778 setLWResult(res, 0, false, false, true);
648bcbd1
RG
779 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
780 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
781 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
782 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
783 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
784 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
785 return 1;
786 }
787 else {
788 downServers.insert(ip);
b4c8789a 789 return 0;
648bcbd1
RG
790 }
791 });
792
793 /* exact same test than the previous one, except instead of a time out we fake a network error */
794 DNSName target("powerdns.com.");
795
796 vector<DNSRecord> ret;
797 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
798 BOOST_CHECK_EQUAL(res, RCode::ServFail);
799 BOOST_CHECK_EQUAL(ret.size(), 0);
800 BOOST_CHECK_EQUAL(downServers.size(), 4);
801
606accb0 802 time_t now = sr->getNow().tv_sec;
648bcbd1 803 for (const auto& server : downServers) {
a712cb56 804 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
606accb0 805 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
648bcbd1
RG
806 }
807}
808
b4c8789a
RG
809BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) {
810 std::unique_ptr<SyncRes> sr;
811 initSR(sr);
812
813 primeHints();
814
815 DNSName target("www.powerdns.com.");
816
deca7d8f 817 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b4c8789a
RG
818
819 if (isRootServer(ip)) {
820 setLWResult(res, 0, false, false, true);
821 if (domain == target) {
822 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
823 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
824 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
825 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
826 }
827 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
828 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
829 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
830 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
831 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
832 }
833 return 1;
834 }
835 else if (ip == ComboAddress("192.0.2.3:53")) {
836 setLWResult(res, 0, true, false, true);
837 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
838 if (type == QType::A) {
839 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
840 }
841 else if (type == QType::AAAA) {
842 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
843 }
844 }
845 else if (domain == target) {
846 if (type == QType::A) {
847 addRecordToLW(res, domain, QType::A, "192.0.2.1");
848 }
849 else if (type == QType::AAAA) {
850 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
851 }
852 }
853 return 1;
854 }
855 return 0;
856 });
857
858 vector<DNSRecord> ret;
859 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
860 BOOST_CHECK_EQUAL(res, RCode::NoError);
861 BOOST_CHECK_EQUAL(ret.size(), 1);
862}
863
648bcbd1
RG
864BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
865 std::unique_ptr<SyncRes> sr;
895449a5 866 initSR(sr);
648bcbd1
RG
867 std::set<ComboAddress> downServers;
868
869 primeHints();
870
deca7d8f 871 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
872
873 if (isRootServer(ip)) {
8455425c 874 setLWResult(res, 0, false, false, true);
648bcbd1
RG
875 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
876 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
877 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
878 return 1;
879 }
880 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 881 setLWResult(res, 0, false, false, true);
648bcbd1
RG
882 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
883 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
884 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
885 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
886 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
887 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
888 return 1;
889 }
890 else {
891 if (downServers.size() < 3) {
892 /* only the last one will answer */
893 downServers.insert(ip);
894 return -2;
895 }
896 else {
897 setLWResult(res, 0, true, false, true);
898 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
899 return 1;
900 }
901 }
902 });
903
904 DNSName target("powerdns.com.");
905
906 vector<DNSRecord> ret;
907 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 908 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
909 BOOST_CHECK_EQUAL(ret.size(), 1);
910 BOOST_CHECK_EQUAL(downServers.size(), 3);
911
912 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
606accb0 913 time_t now = sr->getNow().tv_sec;
648bcbd1 914 for (const auto& server : downServers) {
a712cb56 915 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
606accb0 916 BOOST_CHECK(!SyncRes::isThrottled(now, server, target, QType::A));
648bcbd1
RG
917 }
918}
919
30ee601a
RG
920BOOST_AUTO_TEST_CASE(test_glued_referral) {
921 std::unique_ptr<SyncRes> sr;
895449a5 922 initSR(sr);
30ee601a
RG
923
924 primeHints();
925
926 const DNSName target("powerdns.com.");
927
deca7d8f 928 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
30ee601a
RG
929 /* this will cause issue with qname minimization if we ever implement it */
930 if (domain != target) {
931 return 0;
932 }
933
934 if (isRootServer(ip)) {
8455425c 935 setLWResult(res, 0, false, false, true);
30ee601a
RG
936 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
937 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
938 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
939 return 1;
940 }
941 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 942 setLWResult(res, 0, false, false, true);
30ee601a
RG
943 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
944 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
945 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
946 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
947 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
948 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
949 return 1;
950 }
951 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")) {
952 setLWResult(res, 0, true, false, true);
953 addRecordToLW(res, target, QType::A, "192.0.2.4");
954 return 1;
955 }
956 else {
957 return 0;
958 }
959 });
960
961 vector<DNSRecord> ret;
962 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 963 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 964 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 965 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
966 BOOST_CHECK_EQUAL(ret[0].d_name, target);
967}
968
969BOOST_AUTO_TEST_CASE(test_glueless_referral) {
970 std::unique_ptr<SyncRes> sr;
895449a5 971 initSR(sr);
30ee601a
RG
972
973 primeHints();
974
975 const DNSName target("powerdns.com.");
976
deca7d8f 977 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
30ee601a
RG
978
979 if (isRootServer(ip)) {
8455425c 980 setLWResult(res, 0, false, false, true);
30ee601a
RG
981
982 if (domain.isPartOf(DNSName("com."))) {
983 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
984 } else if (domain.isPartOf(DNSName("org."))) {
985 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
986 }
987 else {
988 setLWResult(res, RCode::NXDomain, false, false, true);
989 return 1;
990 }
991
992 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
993 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
994 return 1;
995 }
996 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
997 if (domain == target) {
8455425c 998 setLWResult(res, 0, false, false, true);
30ee601a
RG
999 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1000 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1001 return 1;
1002 }
1003 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
1004 setLWResult(res, 0, true, false, true);
1005 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
1006 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
1007 return 1;
1008 }
1009 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
1010 setLWResult(res, 0, true, false, true);
1011 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
1012 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
1013 return 1;
1014 }
1015
1016 setLWResult(res, RCode::NXDomain, false, false, true);
1017 return 1;
1018 }
1019 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")) {
1020 setLWResult(res, 0, true, false, true);
1021 addRecordToLW(res, target, QType::A, "192.0.2.4");
1022 return 1;
1023 }
1024 else {
1025 return 0;
1026 }
1027 });
1028
1029 vector<DNSRecord> ret;
1030 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1031 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 1032 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 1033 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
1034 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1035}
1036
e9f9b8ec
RG
1037BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
1038 std::unique_ptr<SyncRes> sr;
895449a5 1039 initSR(sr);
e9f9b8ec
RG
1040
1041 primeHints();
1042
1043 const DNSName target("powerdns.com.");
9065eb05 1044 SyncRes::addEDNSDomain(target);
e9f9b8ec
RG
1045
1046 EDNSSubnetOpts incomingECS;
1047 incomingECS.source = Netmask("192.0.2.128/32");
2fe3354d 1048 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
e9f9b8ec 1049
deca7d8f 1050 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
e9f9b8ec
RG
1051
1052 BOOST_REQUIRE(srcmask);
1053 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1054 return 0;
1055 });
1056
1057 vector<DNSRecord> ret;
1058 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 1059 BOOST_CHECK_EQUAL(res, RCode::ServFail);
e9f9b8ec
RG
1060}
1061
1062BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
1063 std::unique_ptr<SyncRes> sr;
895449a5 1064 initSR(sr);
e9f9b8ec
RG
1065
1066 primeHints();
1067
1068 const DNSName target("powerdns.com.");
2fe3354d 1069 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
e9f9b8ec
RG
1070
1071 EDNSSubnetOpts incomingECS;
1072 incomingECS.source = Netmask("2001:DB8::FF/128");
2fe3354d 1073 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
e9f9b8ec 1074
deca7d8f 1075 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
e9f9b8ec
RG
1076
1077 if (isRootServer(ip)) {
1078 BOOST_REQUIRE(!srcmask);
1079
8455425c 1080 setLWResult(res, 0, false, false, true);
e9f9b8ec
RG
1081 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1082 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1083 return 1;
1084 } else if (ip == ComboAddress("192.0.2.1:53")) {
1085
1086 BOOST_REQUIRE(srcmask);
1087 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1088
1089 setLWResult(res, 0, true, false, false);
1090 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1091 return 1;
1092 }
1093
1094 return 0;
1095 });
1096
1097 vector<DNSRecord> ret;
1098 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1099 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
1100 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1101 BOOST_CHECK(ret[0].d_type == QType::A);
1102 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1103}
1104
2fe3354d
CH
1105BOOST_AUTO_TEST_CASE(test_ecs_use_requestor) {
1106 std::unique_ptr<SyncRes> sr;
1107 initSR(sr);
1108
1109 primeHints();
1110
1111 const DNSName target("powerdns.com.");
1112 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1113 // No incoming ECS data
1114 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
1115
deca7d8f 1116 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2fe3354d
CH
1117
1118 if (isRootServer(ip)) {
1119 BOOST_REQUIRE(!srcmask);
1120
1121 setLWResult(res, 0, false, false, true);
1122 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1123 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1124 return 1;
1125 } else if (ip == ComboAddress("192.0.2.1:53")) {
1126
1127 BOOST_REQUIRE(srcmask);
1128 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1129
1130 setLWResult(res, 0, true, false, false);
1131 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1132 return 1;
1133 }
1134
1135 return 0;
1136 });
1137
1138 vector<DNSRecord> ret;
1139 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1140 BOOST_CHECK_EQUAL(res, RCode::NoError);
1141 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1142 BOOST_CHECK(ret[0].d_type == QType::A);
1143 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1144}
1145
1146BOOST_AUTO_TEST_CASE(test_ecs_use_scope_zero) {
1147 std::unique_ptr<SyncRes> sr;
1148 initSR(sr);
1149
1150 primeHints();
1151
1152 const DNSName target("powerdns.com.");
1153 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1154 SyncRes::clearEDNSLocalSubnets();
1155 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1156 // No incoming ECS data, Requestor IP not in ecs-add-for
1157 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
1158
deca7d8f 1159 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2fe3354d
CH
1160
1161 if (isRootServer(ip)) {
1162 BOOST_REQUIRE(!srcmask);
1163
1164 setLWResult(res, 0, false, false, true);
1165 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1166 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1167 return 1;
1168 } else if (ip == ComboAddress("192.0.2.1:53")) {
1169
1170 BOOST_REQUIRE(srcmask);
1171 BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
1172
1173 setLWResult(res, 0, true, false, false);
1174 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1175 return 1;
1176 }
1177
1178 return 0;
1179 });
1180
1181 vector<DNSRecord> ret;
1182 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1183 BOOST_CHECK_EQUAL(res, RCode::NoError);
1184 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1185 BOOST_CHECK(ret[0].d_type == QType::A);
1186 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1187}
1188
1189BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask) {
1190 std::unique_ptr<SyncRes> sr;
1191 initSR(sr);
1192
1193 primeHints();
1194
1195 const DNSName target("powerdns.com.");
1196 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1197 SyncRes::clearEDNSLocalSubnets();
1198 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1199 EDNSSubnetOpts incomingECS;
1200 incomingECS.source = Netmask("192.0.0.0/16");
1201 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1202
deca7d8f 1203 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2fe3354d
CH
1204
1205 if (isRootServer(ip)) {
1206 BOOST_REQUIRE(!srcmask);
1207
1208 setLWResult(res, 0, false, false, true);
1209 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1210 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1211 return 1;
1212 } else if (ip == ComboAddress("192.0.2.1:53")) {
1213
1214 BOOST_REQUIRE(srcmask);
1215 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.0.0/16");
1216
1217 setLWResult(res, 0, true, false, false);
1218 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1219 return 1;
1220 }
1221
1222 return 0;
1223 });
1224
1225 vector<DNSRecord> ret;
1226 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1227 BOOST_CHECK_EQUAL(res, RCode::NoError);
1228 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1229 BOOST_CHECK(ret[0].d_type == QType::A);
1230 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1231}
1232
1233BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask_zero) {
1234 std::unique_ptr<SyncRes> sr;
1235 initSR(sr);
1236
1237 primeHints();
1238
1239 const DNSName target("powerdns.com.");
1240 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1241 SyncRes::clearEDNSLocalSubnets();
1242 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1243 EDNSSubnetOpts incomingECS;
1244 incomingECS.source = Netmask("0.0.0.0/0");
1245 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1246
deca7d8f 1247 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2fe3354d
CH
1248
1249 if (isRootServer(ip)) {
1250 BOOST_REQUIRE(!srcmask);
1251
1252 setLWResult(res, 0, false, false, true);
1253 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1254 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1255 return 1;
1256 } else if (ip == ComboAddress("192.0.2.1:53")) {
1257
1258 BOOST_REQUIRE(srcmask);
1259 BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
1260
1261 setLWResult(res, 0, true, false, false);
1262 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1263 return 1;
1264 }
1265
1266 return 0;
1267 });
1268
1269 vector<DNSRecord> ret;
1270 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1271 BOOST_CHECK_EQUAL(res, RCode::NoError);
1272 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1273 BOOST_CHECK(ret[0].d_type == QType::A);
1274 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1275}
1276
778bcea6
RG
1277BOOST_AUTO_TEST_CASE(test_following_cname) {
1278 std::unique_ptr<SyncRes> sr;
895449a5 1279 initSR(sr);
778bcea6
RG
1280
1281 primeHints();
1282
1283 const DNSName target("cname.powerdns.com.");
1284 const DNSName cnameTarget("cname-target.powerdns.com");
1285
deca7d8f 1286 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
778bcea6
RG
1287
1288 if (isRootServer(ip)) {
8455425c 1289 setLWResult(res, 0, false, false, true);
778bcea6
RG
1290 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1291 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1292 return 1;
1293 } else if (ip == ComboAddress("192.0.2.1:53")) {
1294
1295 if (domain == target) {
1296 setLWResult(res, 0, true, false, false);
1297 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1298 return 1;
1299 }
1300 else if (domain == cnameTarget) {
1301 setLWResult(res, 0, true, false, false);
1302 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1303 }
1304
1305 return 1;
1306 }
1307
1308 return 0;
1309 });
1310
1311 vector<DNSRecord> ret;
1312 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1313 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
1314 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1315 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1316 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1317 BOOST_CHECK(ret[1].d_type == QType::A);
1318 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1319}
1320
9b061cf5
RG
1321BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
1322 std::unique_ptr<SyncRes> sr;
1323 initSR(sr);
1324
1325 primeHints();
1326
1327 const DNSName target("cname.powerdns.com.");
1328 const DNSName cnameTarget("cname-target.powerdns.com");
1329
deca7d8f 1330 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9b061cf5
RG
1331
1332 if (isRootServer(ip)) {
1333 setLWResult(res, 0, false, false, true);
1334 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1335 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1336 return 1;
1337 } else if (ip == ComboAddress("192.0.2.1:53")) {
1338
1339 if (domain == target) {
1340 setLWResult(res, RCode::NXDomain, true, false, false);
1341 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1342 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1343 } else if (domain == cnameTarget) {
1344 setLWResult(res, RCode::NXDomain, true, false, false);
1345 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1346 return 1;
1347 }
1348
1349 return 1;
1350 }
1351
1352 return 0;
1353 });
1354
1355 vector<DNSRecord> ret;
1356 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1357 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1358 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1359 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1360 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1361 BOOST_CHECK(ret[1].d_type == QType::SOA);
1362
1363 /* a second time, to check the cache */
1364 ret.clear();
1365 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1366 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1367 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1368 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1369 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1370 BOOST_CHECK(ret[1].d_type == QType::SOA);
1371}
1372
4fff116b
RG
1373BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1374 std::unique_ptr<SyncRes> sr;
895449a5 1375 initSR(sr);
4fff116b
RG
1376
1377 primeHints();
1378
1379 /* In this test we directly get the NS server for cname.powerdns.com.,
1380 and we don't know whether it's also authoritative for
1381 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1382 the additional A record for cname-target.powerdns.com. */
1383 const DNSName target("cname.powerdns.com.");
1384 const DNSName cnameTarget("cname-target.powerdns.com");
1385
deca7d8f 1386 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4fff116b
RG
1387
1388 if (isRootServer(ip)) {
1389
8455425c 1390 setLWResult(res, 0, false, false, true);
4fff116b
RG
1391
1392 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1393 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1394 return 1;
1395 } else if (ip == ComboAddress("192.0.2.1:53")) {
1396
1397 if (domain == target) {
1398 setLWResult(res, 0, true, false, false);
1399 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1400 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1401 return 1;
1402 } else if (domain == cnameTarget) {
1403 setLWResult(res, 0, true, false, false);
1404 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1405 return 1;
1406 }
1407
1408 return 1;
1409 }
1410
1411 return 0;
1412 });
1413
1414 vector<DNSRecord> ret;
1415 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1416 BOOST_CHECK_EQUAL(res, RCode::NoError);
4fff116b
RG
1417 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1418 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1419 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1420 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1421 BOOST_REQUIRE(ret[1].d_type == QType::A);
1422 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1423 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1424}
1425
778bcea6
RG
1426BOOST_AUTO_TEST_CASE(test_cname_loop) {
1427 std::unique_ptr<SyncRes> sr;
895449a5 1428 initSR(sr);
778bcea6
RG
1429
1430 primeHints();
1431
1432 size_t count = 0;
1433 const DNSName target("cname.powerdns.com.");
1434
deca7d8f 1435 sr->setAsyncCallback([target,&count](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
778bcea6
RG
1436
1437 count++;
1438
1439 if (isRootServer(ip)) {
778bcea6 1440
8455425c 1441 setLWResult(res, 0, false, false, true);
778bcea6
RG
1442 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1443 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1444 return 1;
1445 } else if (ip == ComboAddress("192.0.2.1:53")) {
1446
1447 if (domain == target) {
1448 setLWResult(res, 0, true, false, false);
1449 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1450 return 1;
1451 }
1452
1453 return 1;
1454 }
1455
1456 return 0;
1457 });
1458
1459 vector<DNSRecord> ret;
1460 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1461 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1462 BOOST_CHECK_GT(ret.size(), 0);
778bcea6 1463 BOOST_CHECK_EQUAL(count, 2);
e9f9b8ec
RG
1464}
1465
4fff116b
RG
1466BOOST_AUTO_TEST_CASE(test_cname_depth) {
1467 std::unique_ptr<SyncRes> sr;
895449a5 1468 initSR(sr);
4fff116b
RG
1469
1470 primeHints();
1471
1472 size_t depth = 0;
1473 const DNSName target("cname.powerdns.com.");
1474
deca7d8f 1475 sr->setAsyncCallback([target,&depth](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4fff116b
RG
1476
1477 if (isRootServer(ip)) {
4fff116b 1478
8455425c 1479 setLWResult(res, 0, false, false, true);
4fff116b
RG
1480 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1481 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1482 return 1;
1483 } else if (ip == ComboAddress("192.0.2.1:53")) {
1484
1485 setLWResult(res, 0, true, false, false);
1486 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1487 depth++;
1488 return 1;
1489 }
1490
1491 return 0;
1492 });
1493
1494 vector<DNSRecord> ret;
1495 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1496 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1497 BOOST_CHECK_EQUAL(ret.size(), depth);
4fff116b
RG
1498 /* we have an arbitrary limit at 10 when following a CNAME chain */
1499 BOOST_CHECK_EQUAL(depth, 10 + 2);
1500}
1501
d6e797b8
RG
1502BOOST_AUTO_TEST_CASE(test_time_limit) {
1503 std::unique_ptr<SyncRes> sr;
895449a5 1504 initSR(sr);
d6e797b8
RG
1505
1506 primeHints();
1507
1508 size_t queries = 0;
1509 const DNSName target("cname.powerdns.com.");
1510
deca7d8f 1511 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
1512
1513 queries++;
1514
1515 if (isRootServer(ip)) {
8455425c 1516 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1517 /* Pretend that this query took 2000 ms */
1518 res->d_usec = 2000;
1519
1520 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1521 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1522 return 1;
1523 } else if (ip == ComboAddress("192.0.2.1:53")) {
1524
1525 setLWResult(res, 0, true, false, false);
1526 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1527 return 1;
1528 }
1529
1530 return 0;
1531 });
1532
1533 /* Set the maximum time to 1 ms */
1534 SyncRes::s_maxtotusec = 1000;
1535
1536 try {
1537 vector<DNSRecord> ret;
1538 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1539 BOOST_CHECK(false);
1540 }
1541 catch(const ImmediateServFailException& e) {
1542 }
1543 BOOST_CHECK_EQUAL(queries, 1);
1544}
1545
1546BOOST_AUTO_TEST_CASE(test_referral_depth) {
1547 std::unique_ptr<SyncRes> sr;
895449a5 1548 initSR(sr);
d6e797b8
RG
1549
1550 primeHints();
1551
1552 size_t queries = 0;
1553 const DNSName target("www.powerdns.com.");
1554
deca7d8f 1555 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
1556
1557 queries++;
1558
1559 if (isRootServer(ip)) {
8455425c 1560 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1561
1562 if (domain == DNSName("www.powerdns.com.")) {
1563 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1564 }
1565 else if (domain == DNSName("ns.powerdns.com.")) {
1566 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1567 }
1568 else if (domain == DNSName("ns1.powerdns.org.")) {
1569 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1570 }
1571 else if (domain == DNSName("ns2.powerdns.org.")) {
1572 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1573 }
1574 else if (domain == DNSName("ns3.powerdns.org.")) {
1575 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1576 }
1577 else if (domain == DNSName("ns4.powerdns.org.")) {
1578 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1579 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1580 }
1581
1582 return 1;
1583 } else if (ip == ComboAddress("192.0.2.1:53")) {
1584
1585 setLWResult(res, 0, true, false, false);
1586 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1587 return 1;
1588 }
1589
1590 return 0;
1591 });
1592
1593 /* Set the maximum depth low */
1594 SyncRes::s_maxdepth = 10;
1595
1596 try {
1597 vector<DNSRecord> ret;
1598 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1599 BOOST_CHECK(false);
1600 }
1601 catch(const ImmediateServFailException& e) {
1602 }
1603}
1604
1605BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1606 std::unique_ptr<SyncRes> sr;
895449a5 1607 initSR(sr);
d6e797b8
RG
1608
1609 primeHints();
1610
1611 size_t queries = 0;
1612 const DNSName target("cname.powerdns.com.");
1613
deca7d8f 1614 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
1615
1616 queries++;
1617
1618 if (isRootServer(ip)) {
1619
8455425c 1620 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1621 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1622 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1623 return 1;
1624 } else if (ip == ComboAddress("192.0.2.1:53")) {
1625
1626 setLWResult(res, 0, true, false, false);
1627 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1628 return 1;
1629 }
1630
1631 return 0;
1632 });
1633
1634 /* Set the maximum number of questions very low */
1635 SyncRes::s_maxqperq = 5;
1636
1637 try {
1638 vector<DNSRecord> ret;
1639 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1640 BOOST_CHECK(false);
1641 }
1642 catch(const ImmediateServFailException& e) {
1643 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1644 }
1645}
1646
ccb07d93
RG
1647BOOST_AUTO_TEST_CASE(test_throttled_server) {
1648 std::unique_ptr<SyncRes> sr;
895449a5 1649 initSR(sr);
ccb07d93
RG
1650
1651 primeHints();
1652
1653 const DNSName target("throttled.powerdns.com.");
1654 const ComboAddress ns("192.0.2.1:53");
1655 size_t queriesToNS = 0;
1656
deca7d8f 1657 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
ccb07d93
RG
1658
1659 if (isRootServer(ip)) {
ccb07d93 1660
8455425c 1661 setLWResult(res, 0, false, false, true);
ccb07d93
RG
1662 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1663 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1664 return 1;
1665 } else if (ip == ns) {
1666
1667 queriesToNS++;
1668
1669 setLWResult(res, 0, true, false, false);
1670 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1671
1672 return 1;
1673 }
1674
1675 return 0;
1676 });
1677
1678 /* mark ns as down */
606accb0
RG
1679 time_t now = sr->getNow().tv_sec;
1680 SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, 10000);
ccb07d93
RG
1681
1682 vector<DNSRecord> ret;
1683 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1684 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1685 BOOST_CHECK_EQUAL(ret.size(), 0);
1686 /* we should not have sent any queries to ns */
ccb07d93
RG
1687 BOOST_CHECK_EQUAL(queriesToNS, 0);
1688}
1689
1690BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1691 std::unique_ptr<SyncRes> sr;
895449a5 1692 initSR(sr);
ccb07d93
RG
1693
1694 primeHints();
1695
1696 const ComboAddress ns("192.0.2.1:53");
1697
1698 const size_t blocks = 10;
1699 /* mark ns as down for 'blocks' queries */
606accb0
RG
1700 time_t now = sr->getNow().tv_sec;
1701 SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, blocks);
ccb07d93
RG
1702
1703 for (size_t idx = 0; idx < blocks; idx++) {
606accb0 1704 BOOST_CHECK(SyncRes::isThrottled(now, ns));
ccb07d93
RG
1705 }
1706
1707 /* we have been throttled 'blocks' times, we should not be throttled anymore */
606accb0 1708 BOOST_CHECK(!SyncRes::isThrottled(now, ns));
ccb07d93
RG
1709}
1710
1711BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1712 std::unique_ptr<SyncRes> sr;
895449a5 1713 initSR(sr);
ccb07d93
RG
1714
1715 primeHints();
1716
1717 const ComboAddress ns("192.0.2.1:53");
1718
1719 const size_t seconds = 1;
1720 /* mark ns as down for 'seconds' seconds */
606accb0
RG
1721 time_t now = sr->getNow().tv_sec;
1722 SyncRes::doThrottle(now, ns, seconds, 10000);
a712cb56 1723
606accb0 1724 BOOST_CHECK(SyncRes::isThrottled(now, ns));
ccb07d93
RG
1725
1726 /* we should not be throttled anymore */
606accb0 1727 BOOST_CHECK(!SyncRes::isThrottled(now + 2, ns));
ccb07d93
RG
1728}
1729
f58c8379
RG
1730BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1731 std::unique_ptr<SyncRes> sr;
895449a5 1732 initSR(sr);
f58c8379
RG
1733
1734 primeHints();
1735
1736 const DNSName target("throttled.powerdns.com.");
1737 const ComboAddress ns("192.0.2.1:53");
1738 size_t queriesToNS = 0;
1739
deca7d8f 1740 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f58c8379
RG
1741
1742 if (isRootServer(ip)) {
1743
8455425c 1744 setLWResult(res, 0, false, false, true);
f58c8379
RG
1745 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1746 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1747 return 1;
1748 } else if (ip == ns) {
1749
1750 queriesToNS++;
1751
1752 setLWResult(res, 0, true, false, false);
1753 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1754
1755 return 1;
1756 }
1757
1758 return 0;
1759 });
1760
1761 /* prevent querying this NS */
9065eb05 1762 SyncRes::addDontQuery(Netmask(ns));
f58c8379
RG
1763
1764 vector<DNSRecord> ret;
1765 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1766 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1767 BOOST_CHECK_EQUAL(ret.size(), 0);
1768 /* we should not have sent any queries to ns */
1769 BOOST_CHECK_EQUAL(queriesToNS, 0);
1770}
1771
1772BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1773 std::unique_ptr<SyncRes> sr;
895449a5 1774 initSR(sr);
f58c8379
RG
1775
1776 primeHints();
1777
1778 const DNSName target1("powerdns.com.");
1779 const DNSName target2("notpowerdns.com.");
1780 const ComboAddress ns("192.0.2.1:53");
1781 size_t queriesCount = 0;
1782
deca7d8f 1783 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f58c8379
RG
1784
1785 queriesCount++;
1786
1787 if (isRootServer(ip)) {
1788
1789 if (domain == target1) {
1790 setLWResult(res, RCode::NXDomain, true, false, true);
1791 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1792 }
1793 else {
1794 setLWResult(res, 0, true, false, true);
1795 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1796 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1797 }
1798
1799 return 1;
1800 } else if (ip == ns) {
1801
1802 setLWResult(res, 0, true, false, false);
1803 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1804
1805 return 1;
1806 }
1807
1808 return 0;
1809 });
1810
1811 vector<DNSRecord> ret;
1812 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1813 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1814 BOOST_CHECK_EQUAL(ret.size(), 1);
1815 /* one for target1 and one for the entire TLD */
a712cb56 1816 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1817
1818 ret.clear();
1819 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1820 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1821 BOOST_CHECK_EQUAL(ret.size(), 1);
1822 /* one for target1 and one for the entire TLD */
a712cb56 1823 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1824
1825 /* we should have sent only one query */
1826 BOOST_CHECK_EQUAL(queriesCount, 1);
1827}
1828
898856ca
RG
1829BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1830 std::unique_ptr<SyncRes> sr;
1831 init();
1832 initSR(sr, true, false);
1833
1834 primeHints();
1835
1836 const DNSName target1("powerdns.com.");
1837 const DNSName target2("notpowerdns.com.");
1838 const ComboAddress ns("192.0.2.1:53");
1839 size_t queriesCount = 0;
1840
1841 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1842 We should add target1 to the negcache, but not "com.". */
1843
deca7d8f 1844 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
898856ca
RG
1845
1846 queriesCount++;
1847
1848 if (isRootServer(ip)) {
1849
1850 if (domain == target1) {
1851 setLWResult(res, RCode::NXDomain, true, false, true);
1852 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1853 }
1854 else {
1855 setLWResult(res, 0, true, false, true);
1856 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1857 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1858 }
1859
1860 return 1;
1861 } else if (ip == ns) {
1862
1863 setLWResult(res, 0, true, false, false);
1864 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1865
1866 return 1;
1867 }
1868
1869 return 0;
1870 });
1871
1872 vector<DNSRecord> ret;
1873 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1874 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1875 BOOST_CHECK_EQUAL(ret.size(), 1);
1876
1877 /* even with root-nx-trust on and a NX answer from the root,
1878 we should not have cached the entire TLD this time. */
a712cb56 1879 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1880
1881 ret.clear();
1882 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1883 BOOST_CHECK_EQUAL(res, RCode::NoError);
1884 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1885 BOOST_REQUIRE(ret[0].d_type == QType::A);
1886 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1887 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1888
a712cb56 1889 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1890
1891 BOOST_CHECK_EQUAL(queriesCount, 3);
1892}
1893
f58c8379
RG
1894BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1895 std::unique_ptr<SyncRes> sr;
895449a5 1896 initSR(sr);
f58c8379
RG
1897
1898 primeHints();
1899
1900 const DNSName target1("powerdns.com.");
1901 const DNSName target2("notpowerdns.com.");
1902 const ComboAddress ns("192.0.2.1:53");
1903 size_t queriesCount = 0;
1904
deca7d8f 1905 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f58c8379
RG
1906
1907 queriesCount++;
1908
1909 if (isRootServer(ip)) {
1910
1911 if (domain == target1) {
1912 setLWResult(res, RCode::NXDomain, true, false, true);
1913 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1914 }
1915 else {
1916 setLWResult(res, 0, true, false, true);
1917 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1918 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1919 }
1920
1921 return 1;
1922 } else if (ip == ns) {
1923
1924 setLWResult(res, 0, true, false, false);
1925 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1926
1927 return 1;
1928 }
1929
1930 return 0;
1931 });
1932
1933 SyncRes::s_rootNXTrust = false;
1934
1935 vector<DNSRecord> ret;
1936 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1937 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1938 BOOST_CHECK_EQUAL(ret.size(), 1);
1939 /* one for target1 */
a712cb56 1940 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1941
1942 ret.clear();
1943 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
b7f378d1 1944 BOOST_CHECK_EQUAL(res, RCode::NoError);
f58c8379
RG
1945 BOOST_CHECK_EQUAL(ret.size(), 1);
1946 /* one for target1 */
a712cb56 1947 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1948
1949 /* we should have sent three queries */
1950 BOOST_CHECK_EQUAL(queriesCount, 3);
1951}
1952
1953BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1954 std::unique_ptr<SyncRes> sr;
895449a5 1955 initSR(sr);
f58c8379
RG
1956
1957 primeHints();
1958
1959 const DNSName target("www.powerdns.com.");
1960 const DNSName cnameTarget("cname.powerdns.com.");
1961
9065eb05 1962 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
f58c8379
RG
1963
1964 EDNSSubnetOpts incomingECS;
1965 incomingECS.source = Netmask("192.0.2.128/32");
2fe3354d 1966 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
f58c8379 1967
deca7d8f 1968 sr->setAsyncCallback([target,cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f58c8379
RG
1969
1970 BOOST_REQUIRE(srcmask);
1971 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1972
1973 if (isRootServer(ip)) {
8455425c 1974 setLWResult(res, 0, false, false, true);
f58c8379
RG
1975 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1976 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1977
1978 return 1;
1979 } else if (ip == ComboAddress("192.0.2.1:53")) {
1980 if (domain == target) {
1981 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
1982 setLWResult(res, RCode::NXDomain, true, false, true);
1983 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1984 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1985 }
1986 else if (domain == cnameTarget) {
1987 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
1988 but we might if we still chase the CNAME. */
1989 setLWResult(res, RCode::NXDomain, true, false, true);
1990 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1991 }
1992
1993 return 1;
1994 }
1995
1996 return 0;
1997 });
1998
1999 vector<DNSRecord> ret;
2000 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2001 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2002 BOOST_CHECK_EQUAL(ret.size(), 2);
2003 /* no negative cache entry because the response was variable */
a712cb56 2004 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
f58c8379
RG
2005}
2006
d6e797b8
RG
2007BOOST_AUTO_TEST_CASE(test_ns_speed) {
2008 std::unique_ptr<SyncRes> sr;
895449a5 2009 initSR(sr);
30ee601a 2010
d6e797b8 2011 primeHints();
30ee601a 2012
d6e797b8 2013 const DNSName target("powerdns.com.");
30ee601a 2014
d6e797b8 2015 std::map<ComboAddress, uint64_t> nsCounts;
30ee601a 2016
deca7d8f 2017 sr->setAsyncCallback([target,&nsCounts](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
30ee601a 2018
d6e797b8 2019 if (isRootServer(ip)) {
8455425c 2020 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2021 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2022 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2023 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
30ee601a 2024
d6e797b8
RG
2025 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2026 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2027 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2028 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
2029 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
2030 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
30ee601a 2031
d6e797b8
RG
2032 return 1;
2033 } else {
2034 nsCounts[ip]++;
30ee601a 2035
d6e797b8
RG
2036 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
2037 BOOST_CHECK_LT(nsCounts.size(), 3);
2038
2039 /* let's time out on pdns-public-ns2.powerdns.com. */
2040 return 0;
2041 }
2042 else if (ip == ComboAddress("192.0.2.1:53")) {
2043 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
2044
2045 setLWResult(res, 0, true, false, true);
2046 addRecordToLW(res, domain, QType::A, "192.0.2.254");
2047 return 1;
2048 }
2049
2050 return 0;
2051 }
30ee601a 2052
d6e797b8
RG
2053 return 0;
2054 });
30ee601a 2055
606accb0 2056 struct timeval now = sr->getNow();
30ee601a 2057
d6e797b8
RG
2058 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
2059 then pdns-public-ns1.powerdns.com. on IPv4 */
a712cb56
RG
2060 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
2061 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
2062 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
2063 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
2064 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
2065 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
30ee601a 2066
d6e797b8
RG
2067 vector<DNSRecord> ret;
2068 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2069 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2070 BOOST_CHECK_EQUAL(ret.size(), 1);
2071 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
2072 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
2073 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
2074 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
2075}
30ee601a 2076
d6e797b8
RG
2077BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
2078 std::unique_ptr<SyncRes> sr;
895449a5 2079 initSR(sr);
30ee601a 2080
d6e797b8 2081 primeHints();
30ee601a 2082
d6e797b8 2083 const DNSName target("powerdns.com.");
30ee601a 2084
deca7d8f 2085 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2086
2087 if (isRootServer(ip)) {
8455425c 2088 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2089 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2090
2091 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2092
2093 return 1;
2094 } else if (ip == ComboAddress("192.0.2.1:53")) {
2095 setLWResult(res, 0, true, false, true);
2096 addRecordToLW(res, domain, QType::A, "192.0.2.254");
2097 return 1;
2098 }
2099
2100 return 0;
2101 });
2102
2103 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
a66eacd6 2104 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2105 std::vector<DNSRecord> records;
2106 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2107 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
2108
2b984251 2109 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2110
2111 vector<DNSRecord> ret;
2112 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2113 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2114 BOOST_CHECK_EQUAL(ret.size(), 1);
2115}
2116
3337c2f7
RG
2117BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
2118 std::unique_ptr<SyncRes> sr;
895449a5 2119 initSR(sr);
3337c2f7
RG
2120
2121 primeHints();
2122
2123 const DNSName target("powerdns.com.");
2124 size_t queriesCount = 0;
2125
deca7d8f 2126 sr->setAsyncCallback([&queriesCount,target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
2127
2128 queriesCount++;
2129
2130 if (isRootServer(ip) && domain == target) {
8455425c 2131 setLWResult(res, 0, false, false, true);
3337c2f7
RG
2132 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2133 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2134 return 1;
2135 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
2136 setLWResult(res, 0, true, false, true);
2137 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2138 return 1;
2139 }
2140
2141 return 0;
2142 });
2143
2144 vector<DNSRecord> ret;
2145 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2146 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2147 BOOST_CHECK_EQUAL(ret.size(), 0);
2148 /* one query to get NSs, then A and AAAA for each NS */
2149 BOOST_CHECK_EQUAL(queriesCount, 5);
2150}
2151
d6e797b8
RG
2152BOOST_AUTO_TEST_CASE(test_cache_hit) {
2153 std::unique_ptr<SyncRes> sr;
895449a5 2154 initSR(sr);
d6e797b8
RG
2155
2156 primeHints();
2157
2158 const DNSName target("powerdns.com.");
2159
deca7d8f 2160 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2161
2162 return 0;
2163 });
2164
2165 /* we populate the cache with eveything we need */
a66eacd6 2166 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2167 std::vector<DNSRecord> records;
2168 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2169
2170 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
2b984251 2171 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2172
2173 vector<DNSRecord> ret;
2174 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2175 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2176 BOOST_CHECK_EQUAL(ret.size(), 1);
2177}
2178
648bcbd1
RG
2179BOOST_AUTO_TEST_CASE(test_no_rd) {
2180 std::unique_ptr<SyncRes> sr;
895449a5 2181 initSR(sr);
648bcbd1
RG
2182
2183 primeHints();
2184
2185 const DNSName target("powerdns.com.");
2186 size_t queriesCount = 0;
2187
2188 sr->setCacheOnly();
2189
deca7d8f 2190 sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
2191
2192 queriesCount++;
2193 return 0;
2194 });
2195
2196 vector<DNSRecord> ret;
2197 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2198 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2199 BOOST_CHECK_EQUAL(ret.size(), 0);
2200 BOOST_CHECK_EQUAL(queriesCount, 0);
2201}
2202
d6e797b8
RG
2203BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
2204 std::unique_ptr<SyncRes> sr;
895449a5 2205 initSR(sr);
d6e797b8
RG
2206
2207 primeHints();
2208
2209 const DNSName target("cachettl.powerdns.com.");
2210 const ComboAddress ns("192.0.2.1:53");
2211
deca7d8f 2212 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2213
2214 if (isRootServer(ip)) {
2215
8455425c 2216 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2217 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2218 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
2219 return 1;
2220 } else if (ip == ns) {
2221
2222 setLWResult(res, 0, true, false, false);
2223 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2224
2225 return 1;
2226 }
2227
2228 return 0;
2229 });
2230
a66eacd6 2231 const time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2232 SyncRes::s_minimumTTL = 60;
2233 SyncRes::s_maxcachettl = 3600;
2234
2235 vector<DNSRecord> ret;
2236 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2237 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2238 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2239 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
2240
2241 const ComboAddress who;
2242 vector<DNSRecord> cached;
24bb9b58 2243 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
d6e797b8
RG
2244 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2245 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2246 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
2247
2248 cached.clear();
24bb9b58 2249 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
d6e797b8
RG
2250 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2251 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2252 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
2253}
2254
2255BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
2256 std::unique_ptr<SyncRes> sr;
895449a5 2257 initSR(sr);
d6e797b8
RG
2258
2259 primeHints();
2260
2261 const DNSName target("powerdns.com.");
2262
deca7d8f 2263 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2264
2265 if (isRootServer(ip)) {
8455425c 2266 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2267 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2268
2269 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2270
2271 return 1;
2272 } else if (ip == ComboAddress("192.0.2.1:53")) {
2273 setLWResult(res, 0, true, false, true);
2274 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2275 return 1;
2276 }
2277
2278 return 0;
2279 });
2280
2281 /* we populate the cache with entries that expired 60s ago*/
129e658f
RG
2282 const time_t now = sr->getNow().tv_sec;
2283
d6e797b8
RG
2284 std::vector<DNSRecord> records;
2285 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2286 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
2287
2b984251 2288 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2289
2290 vector<DNSRecord> ret;
2291 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2292 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2293 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2294 BOOST_REQUIRE(ret[0].d_type == QType::A);
2295 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
2296}
2297
129e658f
RG
2298BOOST_AUTO_TEST_CASE(test_cache_auth) {
2299 std::unique_ptr<SyncRes> sr;
2300 initSR(sr);
2301
2302 primeHints();
2303
2304 /* the auth server is sending the same answer in answer and additional,
2305 check that we only return one result, and we only cache one too. */
2306 const DNSName target("cache-auth.powerdns.com.");
2307
deca7d8f 2308 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
129e658f
RG
2309
2310 setLWResult(res, 0, true, false, true);
2311 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2312 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 10);
2313
2314 return 1;
2315 });
2316
2317 const time_t now = sr->getNow().tv_sec;
2318
2319 vector<DNSRecord> ret;
2320 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2321 BOOST_CHECK_EQUAL(res, RCode::NoError);
2322 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2323 BOOST_REQUIRE_EQUAL(QType(ret.at(0).d_type).getName(), QType(QType::A).getName());
2324 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2325
2326 /* check that we correctly cached only the answer entry, not the additional one */
2327 const ComboAddress who;
2328 vector<DNSRecord> cached;
2329 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
2330 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2331 BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).getName(), QType(QType::A).getName());
2332 BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2333}
2334
d6e797b8
RG
2335BOOST_AUTO_TEST_CASE(test_delegation_only) {
2336 std::unique_ptr<SyncRes> sr;
895449a5 2337 initSR(sr);
d6e797b8
RG
2338
2339 primeHints();
2340
2341 /* Thanks, Verisign */
9065eb05
RG
2342 SyncRes::addDelegationOnly(DNSName("com."));
2343 SyncRes::addDelegationOnly(DNSName("net."));
d6e797b8
RG
2344
2345 const DNSName target("nx-powerdns.com.");
2346
deca7d8f 2347 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2348
2349 if (isRootServer(ip)) {
8455425c 2350 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2351 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2352 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2353 return 1;
2354 } else if (ip == ComboAddress("192.0.2.1:53")) {
2355
2356 setLWResult(res, 0, true, false, true);
2357 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2358 return 1;
2359 }
2360
2361 return 0;
2362 });
2363
2364 vector<DNSRecord> ret;
2365 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2366 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2367 BOOST_CHECK_EQUAL(ret.size(), 0);
2368}
2369
2370BOOST_AUTO_TEST_CASE(test_unauth_any) {
2371 std::unique_ptr<SyncRes> sr;
895449a5 2372 initSR(sr);
d6e797b8
RG
2373
2374 primeHints();
2375
2376 const DNSName target("powerdns.com.");
2377
deca7d8f 2378 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2379
2380 if (isRootServer(ip)) {
8455425c 2381 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2382 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2383 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2384 return 1;
2385 } else if (ip == ComboAddress("192.0.2.1:53")) {
2386
2387 setLWResult(res, 0, false, false, true);
2388 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2389 return 1;
2390 }
2391
2392 return 0;
2393 });
2394
2395 vector<DNSRecord> ret;
2396 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2397 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2398 BOOST_CHECK_EQUAL(ret.size(), 0);
2399}
2400
2401BOOST_AUTO_TEST_CASE(test_no_data) {
2402 std::unique_ptr<SyncRes> sr;
895449a5 2403 initSR(sr);
d6e797b8
RG
2404
2405 primeHints();
2406
2407 const DNSName target("powerdns.com.");
2408
deca7d8f 2409 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2410
2411 setLWResult(res, 0, true, false, true);
2412 return 1;
2413 });
2414
2415 vector<DNSRecord> ret;
2416 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2417 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2418 BOOST_CHECK_EQUAL(ret.size(), 0);
2419}
2420
2421BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2422 std::unique_ptr<SyncRes> sr;
895449a5 2423 initSR(sr);
d6e797b8
RG
2424
2425 primeHints();
2426
2427 const DNSName target("powerdns.com.");
2428
deca7d8f 2429 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2430
2431 setLWResult(res, 0, true, false, true);
2432 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2433 addRecordToLW(res, domain, QType::ANY, "0 0");
2434 addRecordToLW(res, domain, QType::OPT, "");
2435 return 1;
2436 });
2437
2438 vector<DNSRecord> ret;
2439 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2440 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2441 BOOST_CHECK_EQUAL(ret.size(), 1);
2442}
2443
2444BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2445 std::unique_ptr<SyncRes> sr;
895449a5 2446 initSR(sr);
d6e797b8
RG
2447
2448 primeHints();
2449
2450 const DNSName target("powerdns.com.");
2451
deca7d8f 2452 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2453
2454 setLWResult(res, 0, true, false, true);
2455 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2456 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2457 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2458 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2459 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2460 return 1;
2461 });
2462
2463 vector<DNSRecord> ret;
2464 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2465 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2466 BOOST_CHECK_EQUAL(ret.size(), 1);
2467}
2468
2469BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2470 std::unique_ptr<SyncRes> sr;
895449a5 2471 initSR(sr, true);
d6e797b8
RG
2472
2473 primeHints();
2474
2475 const DNSName target("powerdns.com.");
2476
deca7d8f 2477 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2478
2479 setLWResult(res, 0, true, false, true);
2480 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2481 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2482 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2483 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2484 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2485 return 1;
2486 });
2487
2488 vector<DNSRecord> ret;
2489 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2490 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2491 BOOST_CHECK_EQUAL(ret.size(), 4);
2492}
2493
2494BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2495 std::unique_ptr<SyncRes> sr;
895449a5 2496 initSR(sr);
d6e797b8
RG
2497
2498 primeHints();
2499
2500 const DNSName target("powerdns.com.");
2501
deca7d8f 2502 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2503
2504 setLWResult(res, RCode::NXDomain, true, false, true);
2505 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2506 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2507 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2508 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2509 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2510 return 1;
2511 });
2512
2513 vector<DNSRecord> ret;
2514 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2515 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2516 BOOST_CHECK_EQUAL(ret.size(), 1);
2517}
2518
2519BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2520 std::unique_ptr<SyncRes> sr;
895449a5 2521 initSR(sr, true);
d6e797b8
RG
2522
2523 primeHints();
2524
2525 const DNSName target("powerdns.com.");
2526
deca7d8f 2527 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
d6e797b8
RG
2528
2529 setLWResult(res, RCode::NXDomain, true, false, true);
2530 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2531 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2532 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2533 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2534 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2535 return 1;
2536 });
2537
2538 vector<DNSRecord> ret;
2539 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2540 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2541 BOOST_CHECK_EQUAL(ret.size(), 4);
2542}
2543
648bcbd1
RG
2544BOOST_AUTO_TEST_CASE(test_qclass_none) {
2545 std::unique_ptr<SyncRes> sr;
895449a5 2546 initSR(sr);
648bcbd1
RG
2547
2548 primeHints();
2549
2550 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2551 size_t queriesCount = 0;
2552
deca7d8f 2553 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
2554
2555 queriesCount++;
2556 return 0;
2557 });
2558
2559 const DNSName target("powerdns.com.");
2560 vector<DNSRecord> ret;
2561 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2562 BOOST_CHECK_EQUAL(res, -1);
2563 BOOST_CHECK_EQUAL(ret.size(), 0);
2564 BOOST_CHECK_EQUAL(queriesCount, 0);
2565}
2566
1f03b691 2567BOOST_AUTO_TEST_CASE(test_special_types) {
648bcbd1 2568 std::unique_ptr<SyncRes> sr;
895449a5 2569 initSR(sr);
648bcbd1
RG
2570
2571 primeHints();
2572
1f03b691 2573 /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
648bcbd1
RG
2574 size_t queriesCount = 0;
2575
deca7d8f 2576 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
2577
2578 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2579 queriesCount++;
2580 return 0;
2581 });
2582
2583 const DNSName target("powerdns.com.");
2584 vector<DNSRecord> ret;
2585 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2586 BOOST_CHECK_EQUAL(res, -1);
2587 BOOST_CHECK_EQUAL(ret.size(), 0);
2588 BOOST_CHECK_EQUAL(queriesCount, 0);
2589
2590 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2591 BOOST_CHECK_EQUAL(res, -1);
2592 BOOST_CHECK_EQUAL(ret.size(), 0);
2593 BOOST_CHECK_EQUAL(queriesCount, 0);
1f03b691
RG
2594
2595 res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2596 BOOST_CHECK_EQUAL(res, -1);
2597 BOOST_CHECK_EQUAL(ret.size(), 0);
2598 BOOST_CHECK_EQUAL(queriesCount, 0);
2599
2600 res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
648bcbd1
RG
2601 BOOST_CHECK_EQUAL(res, -1);
2602 BOOST_CHECK_EQUAL(ret.size(), 0);
2603 BOOST_CHECK_EQUAL(queriesCount, 0);
2604}
2605
2606BOOST_AUTO_TEST_CASE(test_special_names) {
2607 std::unique_ptr<SyncRes> sr;
895449a5 2608 initSR(sr);
648bcbd1
RG
2609
2610 primeHints();
2611
2612 /* special names should be handled internally */
2613
2614 size_t queriesCount = 0;
2615
deca7d8f 2616 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
2617
2618 queriesCount++;
2619 return 0;
2620 });
2621
2622 vector<DNSRecord> ret;
2623 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
b7f378d1 2624 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2625 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2626 BOOST_CHECK(ret[0].d_type == QType::PTR);
2627 BOOST_CHECK_EQUAL(queriesCount, 0);
2628
2629 ret.clear();
2630 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2631 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2632 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2633 BOOST_CHECK(ret[0].d_type == QType::PTR);
2634 BOOST_CHECK_EQUAL(queriesCount, 0);
2635
2636 ret.clear();
2637 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);
b7f378d1 2638 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2639 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2640 BOOST_CHECK(ret[0].d_type == QType::PTR);
2641 BOOST_CHECK_EQUAL(queriesCount, 0);
2642
2643 ret.clear();
2644 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);
b7f378d1 2645 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2646 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2647 BOOST_CHECK(ret[0].d_type == QType::PTR);
2648 BOOST_CHECK_EQUAL(queriesCount, 0);
2649
2650 ret.clear();
2651 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
b7f378d1 2652 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2653 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2654 BOOST_CHECK(ret[0].d_type == QType::A);
2655 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2656 BOOST_CHECK_EQUAL(queriesCount, 0);
2657
2658 ret.clear();
2659 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
b7f378d1 2660 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2661 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2662 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2663 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2664 BOOST_CHECK_EQUAL(queriesCount, 0);
2665
2666 ret.clear();
2667 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2668 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2669 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2670 for (const auto& rec : ret) {
2671 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2672 if (rec.d_type == QType::A) {
2673 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2674 }
2675 else {
2676 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2677 }
2678 }
2679 BOOST_CHECK_EQUAL(queriesCount, 0);
2680
2681 ret.clear();
2682 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2683 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2684 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2685 BOOST_CHECK(ret[0].d_type == QType::TXT);
2686 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2687 BOOST_CHECK_EQUAL(queriesCount, 0);
2688
2689 ret.clear();
2690 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2691 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2692 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2693 BOOST_CHECK(ret[0].d_type == QType::TXT);
2694 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2695 BOOST_CHECK_EQUAL(queriesCount, 0);
2696
2697 ret.clear();
2698 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2699 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2700 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2701 BOOST_CHECK(ret[0].d_type == QType::TXT);
2702 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2703 BOOST_CHECK_EQUAL(queriesCount, 0);
2704
2705 ret.clear();
2706 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2707 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2708 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2709 BOOST_CHECK(ret[0].d_type == QType::TXT);
2710 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2711 BOOST_CHECK_EQUAL(queriesCount, 0);
2712
2713 ret.clear();
2714 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2715 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2716 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2717 BOOST_CHECK(ret[0].d_type == QType::TXT);
2718 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2719 BOOST_CHECK_EQUAL(queriesCount, 0);
2720
2721 ret.clear();
2722 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2723 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2724 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2725 BOOST_CHECK(ret[0].d_type == QType::TXT);
2726 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2727 BOOST_CHECK_EQUAL(queriesCount, 0);
2728}
2729
2730BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2731 std::unique_ptr<SyncRes> sr;
895449a5 2732 initSR(sr);
648bcbd1
RG
2733
2734 primeHints();
2735
2736 const DNSName target("rpz.powerdns.com.");
2737 const ComboAddress ns("192.0.2.1:53");
2738
deca7d8f 2739 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
2740
2741 if (isRootServer(ip)) {
8455425c 2742 setLWResult(res, false, true, false, true);
648bcbd1
RG
2743 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2744 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2745 return 1;
2746 } else if (ip == ns) {
2747
2748 setLWResult(res, 0, true, false, true);
2749 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2750 return 1;
2751 }
2752
2753 return 0;
2754 });
2755
2756 DNSFilterEngine::Policy pol;
2757 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2758 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2759 zone->setName("Unit test policy 0");
2760 zone->addNSIPTrigger(Netmask(ns, 32), pol);
648bcbd1 2761 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2762 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2763 g_luaconfs.setState(luaconfsCopy);
2764
2765 vector<DNSRecord> ret;
2766 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2767 BOOST_CHECK_EQUAL(res, -2);
2768 BOOST_CHECK_EQUAL(ret.size(), 0);
2769}
2770
2771BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2772 std::unique_ptr<SyncRes> sr;
895449a5 2773 initSR(sr);
648bcbd1
RG
2774
2775 primeHints();
2776
2777 const DNSName target("rpz.powerdns.com.");
2778 const ComboAddress ns("[2001:DB8::42]:53");
2779
deca7d8f 2780 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
2781
2782 if (isRootServer(ip)) {
8455425c 2783 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2784 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2785 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2786 return 1;
2787 } else if (ip == ns) {
2788
2789 setLWResult(res, 0, true, false, true);
2790 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2791 return 1;
2792 }
2793
2794 return 0;
2795 });
2796
2797 DNSFilterEngine::Policy pol;
2798 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2799 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2800 zone->setName("Unit test policy 0");
2801 zone->addNSIPTrigger(Netmask(ns, 128), pol);
648bcbd1 2802 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2803 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2804 g_luaconfs.setState(luaconfsCopy);
2805
2806 vector<DNSRecord> ret;
2807 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2808 BOOST_CHECK_EQUAL(res, -2);
2809 BOOST_CHECK_EQUAL(ret.size(), 0);
2810}
2811
2812BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2813 std::unique_ptr<SyncRes> sr;
895449a5 2814 initSR(sr);
648bcbd1
RG
2815
2816 primeHints();
2817
2818 const DNSName target("rpz.powerdns.com.");
2819 const ComboAddress ns("192.0.2.1:53");
2820 const DNSName nsName("ns1.powerdns.com.");
2821
deca7d8f 2822 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
2823
2824 if (isRootServer(ip)) {
8455425c 2825 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2826 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2827 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2828 return 1;
2829 } else if (ip == ns) {
2830
2831 setLWResult(res, 0, true, false, true);
2832 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2833 return 1;
2834 }
2835
2836 return 0;
2837 });
2838
2839 DNSFilterEngine::Policy pol;
2840 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2841 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2842 zone->setName("Unit test policy 0");
2843 zone->addNSTrigger(nsName, pol);
648bcbd1 2844 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2845 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2846 g_luaconfs.setState(luaconfsCopy);
2847
2848 vector<DNSRecord> ret;
2849 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2850 BOOST_CHECK_EQUAL(res, -2);
2851 BOOST_CHECK_EQUAL(ret.size(), 0);
2852}
2853
2854BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2855 std::unique_ptr<SyncRes> sr;
895449a5 2856 initSR(sr);
648bcbd1
RG
2857
2858 primeHints();
2859
2860 const DNSName target("rpz.powerdns.com.");
2861 const ComboAddress ns("192.0.2.1:53");
2862 const DNSName nsName("ns1.powerdns.com.");
2863
deca7d8f 2864 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
648bcbd1
RG
2865
2866 if (isRootServer(ip)) {
8455425c 2867 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2868 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2869 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2870 return 1;
2871 } else if (ip == ns) {
2872
2873 setLWResult(res, 0, true, false, true);
2874 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2875 return 1;
2876 }
2877
2878 return 0;
2879 });
2880
2881 DNSFilterEngine::Policy pol;
2882 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2883 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2884 zone->setName("Unit test policy 0");
2885 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2886 zone->addNSTrigger(nsName, pol);
648bcbd1 2887 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2888 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2889 g_luaconfs.setState(luaconfsCopy);
2890
2891 /* RPZ is disabled for this query, we should not be blocked */
2892 sr->setWantsRPZ(false);
2893
2894 vector<DNSRecord> ret;
2895 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2896 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2897 BOOST_CHECK_EQUAL(ret.size(), 1);
2898}
2899
3e59ff53
RG
2900BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2901 std::unique_ptr<SyncRes> sr;
895449a5 2902 initSR(sr);
3e59ff53
RG
2903
2904 primeHints();
2905
2906 const DNSName target("powerdns.com.");
2907 const ComboAddress ns("192.0.2.1:53");
2908 const ComboAddress forwardedNS("192.0.2.42:53");
2909
2910 SyncRes::AuthDomain ad;
2911 ad.d_rdForward = false;
2912 ad.d_servers.push_back(forwardedNS);
a712cb56 2913 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2914
deca7d8f 2915 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3e59ff53
RG
2916
2917 if (ip == forwardedNS) {
6dfff36f
RG
2918 BOOST_CHECK_EQUAL(sendRDQuery, false);
2919
3e59ff53
RG
2920 setLWResult(res, 0, true, false, true);
2921 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2922 return 1;
2923 }
2924
2925 return 0;
2926 });
2927
2928 /* simulate a no-RD query */
2929 sr->setCacheOnly();
2930
2931 vector<DNSRecord> ret;
2932 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2933 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2934 BOOST_CHECK_EQUAL(ret.size(), 1);
2935}
2936
2937BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
2938 std::unique_ptr<SyncRes> sr;
895449a5 2939 initSR(sr);
3e59ff53
RG
2940
2941 primeHints();
2942
2943 const DNSName target("powerdns.com.");
2944 const ComboAddress ns("192.0.2.1:53");
2945 const ComboAddress forwardedNS("192.0.2.42:53");
2946
2947 SyncRes::AuthDomain ad;
2948 ad.d_rdForward = false;
2949 ad.d_servers.push_back(forwardedNS);
a712cb56 2950 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2951
deca7d8f 2952 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3e59ff53
RG
2953
2954 if (ip == forwardedNS) {
6dfff36f
RG
2955 BOOST_CHECK_EQUAL(sendRDQuery, false);
2956
3e59ff53
RG
2957 setLWResult(res, 0, true, false, true);
2958 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2959 return 1;
2960 }
2961
2962 return 0;
2963 });
2964
2965 vector<DNSRecord> ret;
2966 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2967 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2968 BOOST_CHECK_EQUAL(ret.size(), 1);
2969}
2970
2971BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
2972 std::unique_ptr<SyncRes> sr;
895449a5 2973 initSR(sr);
3e59ff53
RG
2974
2975 primeHints();
2976
2977 const DNSName target("powerdns.com.");
2978 const ComboAddress ns("192.0.2.1:53");
2979 const ComboAddress forwardedNS("192.0.2.42:53");
2980
2981 SyncRes::AuthDomain ad;
2982 ad.d_rdForward = true;
2983 ad.d_servers.push_back(forwardedNS);
a712cb56 2984 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2985
deca7d8f 2986 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3e59ff53
RG
2987
2988 if (ip == forwardedNS) {
6dfff36f
RG
2989 BOOST_CHECK_EQUAL(sendRDQuery, false);
2990
3e59ff53
RG
2991 setLWResult(res, 0, true, false, true);
2992 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2993 return 1;
2994 }
2995
2996 return 0;
2997 });
2998
2999 /* simulate a no-RD query */
3000 sr->setCacheOnly();
3001
3002 vector<DNSRecord> ret;
3003 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3004 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
3005 BOOST_CHECK_EQUAL(ret.size(), 1);
3006}
3007
3008BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
3009 std::unique_ptr<SyncRes> sr;
895449a5 3010 initSR(sr);
3e59ff53
RG
3011
3012 primeHints();
3013
3014 const DNSName target("powerdns.com.");
3015 const ComboAddress ns("192.0.2.1:53");
3016 const ComboAddress forwardedNS("192.0.2.42:53");
3017
3018 SyncRes::AuthDomain ad;
3019 ad.d_rdForward = true;
3020 ad.d_servers.push_back(forwardedNS);
a712cb56 3021 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 3022
deca7d8f 3023 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3e59ff53
RG
3024
3025 if (ip == forwardedNS) {
6dfff36f
RG
3026 BOOST_CHECK_EQUAL(sendRDQuery, true);
3027
3e59ff53
RG
3028 setLWResult(res, 0, true, false, true);
3029 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3030 return 1;
3031 }
3032
3033 return 0;
3034 });
3035
3036 vector<DNSRecord> ret;
3037 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3038 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
3039 BOOST_CHECK_EQUAL(ret.size(), 1);
3040}
3041
e1636f82 3042BOOST_AUTO_TEST_CASE(test_auth_zone_oob) {
f79a4e30 3043 std::unique_ptr<SyncRes> sr;
e1636f82 3044 initSR(sr, true);
f79a4e30
RG
3045
3046 primeHints();
3047
3048 size_t queriesCount = 0;
3049 const DNSName target("test.xx.");
3050 const ComboAddress targetAddr("127.0.0.1");
f79a4e30
RG
3051 const DNSName authZone("test.xx");
3052
3053 SyncRes::AuthDomain ad;
3054 DNSRecord dr;
f79a4e30
RG
3055
3056 dr.d_place = DNSResourceRecord::ANSWER;
e1636f82 3057 dr.d_name = target;
f79a4e30
RG
3058 dr.d_type = QType::A;
3059 dr.d_ttl = 1800;
e1636f82 3060 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
f79a4e30
RG
3061 ad.d_records.insert(dr);
3062
a712cb56 3063 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
f79a4e30 3064
deca7d8f 3065 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f79a4e30
RG
3066 queriesCount++;
3067 return 0;
3068 });
3069
3070 vector<DNSRecord> ret;
3071 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3072 BOOST_CHECK_EQUAL(res, 0);
3073 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3074 BOOST_CHECK(ret[0].d_type == QType::A);
3075 BOOST_CHECK_EQUAL(queriesCount, 0);
3076 BOOST_CHECK(sr->wasOutOfBand());
e1636f82 3077 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
3078
3079 /* a second time, to check that the OOB flag is set when the query cache is used */
3080 ret.clear();
3081 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3082 BOOST_CHECK_EQUAL(res, 0);
3083 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3084 BOOST_CHECK(ret[0].d_type == QType::A);
3085 BOOST_CHECK_EQUAL(queriesCount, 0);
3086 BOOST_CHECK(sr->wasOutOfBand());
e1636f82
RG
3087 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3088
3089 /* a third time, to check that the validation is disabled when the OOB flag is set */
3090 ret.clear();
3091 sr->setDNSSECValidationRequested(true);
3092 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3093 BOOST_CHECK_EQUAL(res, 0);
3094 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3095 BOOST_CHECK(ret[0].d_type == QType::A);
3096 BOOST_CHECK_EQUAL(queriesCount, 0);
3097 BOOST_CHECK(sr->wasOutOfBand());
3098 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3099}
3100
3101BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) {
3102 std::unique_ptr<SyncRes> sr;
3103 initSR(sr, true);
3104
3105 primeHints();
3106
3107 size_t queriesCount = 0;
3108 const DNSName target("cname.test.xx.");
3109 const DNSName targetCname("cname-target.test.xx.");
3110 const ComboAddress targetCnameAddr("127.0.0.1");
3111 const DNSName authZone("test.xx");
3112
3113 SyncRes::AuthDomain ad;
3114 DNSRecord dr;
3115
3116 dr.d_place = DNSResourceRecord::ANSWER;
3117 dr.d_name = target;
3118 dr.d_type = QType::CNAME;
3119 dr.d_ttl = 1800;
3120 dr.d_content = std::make_shared<CNAMERecordContent>(targetCname);
3121 ad.d_records.insert(dr);
3122
3123 dr.d_place = DNSResourceRecord::ANSWER;
3124 dr.d_name = targetCname;
3125 dr.d_type = QType::A;
3126 dr.d_ttl = 1800;
3127 dr.d_content = std::make_shared<ARecordContent>(targetCnameAddr);
3128 ad.d_records.insert(dr);
3129
3130 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
3131
deca7d8f 3132 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
e1636f82
RG
3133 queriesCount++;
3134 return 0;
3135 });
3136
3137 vector<DNSRecord> ret;
3138 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3139 BOOST_CHECK_EQUAL(res, 0);
3140 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3141 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3142 BOOST_CHECK(ret[1].d_type == QType::A);
3143 BOOST_CHECK_EQUAL(queriesCount, 0);
3144 BOOST_CHECK(sr->wasOutOfBand());
3145 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3146
3147 /* a second time, to check that the OOB flag is set when the query cache is used */
3148 ret.clear();
3149 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3150 BOOST_CHECK_EQUAL(res, 0);
3151 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3152 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3153 BOOST_CHECK(ret[1].d_type == QType::A);
3154 BOOST_CHECK_EQUAL(queriesCount, 0);
3155 BOOST_CHECK(sr->wasOutOfBand());
3156 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3157
3158 /* a third time, to check that the validation is disabled when the OOB flag is set */
3159 ret.clear();
3160 sr->setDNSSECValidationRequested(true);
3161 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3162 BOOST_CHECK_EQUAL(res, 0);
3163 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3164 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3165 BOOST_CHECK(ret[1].d_type == QType::A);
3166 BOOST_CHECK_EQUAL(queriesCount, 0);
3167 BOOST_CHECK(sr->wasOutOfBand());
3168 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
3169}
3170
3337c2f7
RG
3171BOOST_AUTO_TEST_CASE(test_auth_zone) {
3172 std::unique_ptr<SyncRes> sr;
895449a5 3173 initSR(sr);
3337c2f7
RG
3174
3175 primeHints();
3176
3177 size_t queriesCount = 0;
3178 const DNSName target("powerdns.com.");
3179 const ComboAddress addr("192.0.2.5");
3180
3181 SyncRes::AuthDomain ad;
3182 ad.d_name = target;
3183 DNSRecord dr;
3184 dr.d_place = DNSResourceRecord::ANSWER;
3185 dr.d_name = target;
3186 dr.d_type = QType::SOA;
3187 dr.d_ttl = 3600;
3188 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3189 ad.d_records.insert(dr);
3190
3191 dr.d_place = DNSResourceRecord::ANSWER;
3192 dr.d_name = target;
3193 dr.d_type = QType::A;
3194 dr.d_ttl = 3600;
3195 dr.d_content = std::make_shared<ARecordContent>(addr);
3196 ad.d_records.insert(dr);
3197
3198 auto map = std::make_shared<SyncRes::domainmap_t>();
3199 (*map)[target] = ad;
3200 SyncRes::setDomainMap(map);
3201
deca7d8f 3202 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3203
3204 queriesCount++;
3205 setLWResult(res, 0, true, false, true);
3206 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3207 return 1;
3208 });
3209
3210 vector<DNSRecord> ret;
3211 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3212 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3213 BOOST_CHECK_EQUAL(ret.size(), 1);
3214 BOOST_CHECK(ret[0].d_type == QType::A);
3215 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3216 BOOST_CHECK_EQUAL(queriesCount, 0);
3217}
3218
3219BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
3220 std::unique_ptr<SyncRes> sr;
895449a5 3221 initSR(sr);
3337c2f7
RG
3222
3223 primeHints();
3224
3225 size_t queriesCount = 0;
3226 const DNSName target("powerdns.com.");
3227 const DNSName authZone("internal.powerdns.com.");
3228 const ComboAddress addr("192.0.2.5");
3229
3230 SyncRes::AuthDomain ad;
3231 ad.d_name = authZone;
3232 DNSRecord dr;
3233 dr.d_place = DNSResourceRecord::ANSWER;
3234 dr.d_name = authZone;
3235 dr.d_type = QType::SOA;
3236 dr.d_ttl = 3600;
3237 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3238 ad.d_records.insert(dr);
3239
3240 dr.d_place = DNSResourceRecord::ANSWER;
3241 dr.d_name = authZone;
3242 dr.d_type = QType::A;
3243 dr.d_ttl = 3600;
3244 dr.d_content = std::make_shared<ARecordContent>(addr);
3245 ad.d_records.insert(dr);
3246
3247 auto map = std::make_shared<SyncRes::domainmap_t>();
3248 (*map)[authZone] = ad;
3249 SyncRes::setDomainMap(map);
3250
deca7d8f 3251 sr->setAsyncCallback([&queriesCount,target,authZone](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3252
3253 queriesCount++;
3254
3255 if (domain == target) {
3256 setLWResult(res, 0, true, false, true);
3257 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
3258 return 1;
3259 }
3260
3261 return 0;
3262 });
3263
3264 vector<DNSRecord> ret;
3265 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3266 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3267 BOOST_CHECK_EQUAL(ret.size(), 2);
3268 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3269 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
3270 BOOST_CHECK(ret[1].d_type == QType::A);
3271 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3272 BOOST_CHECK_EQUAL(queriesCount, 1);
3273}
3274
3275BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
3276 std::unique_ptr<SyncRes> sr;
895449a5 3277 initSR(sr);
3337c2f7
RG
3278
3279 primeHints();
3280
3281 size_t queriesCount = 0;
3282 const DNSName target("powerdns.com.");
3283 const DNSName externalCNAME("www.open-xchange.com.");
3284 const ComboAddress addr("192.0.2.5");
3285
3286 SyncRes::AuthDomain ad;
3287 ad.d_name = target;
3288 DNSRecord dr;
3289 dr.d_place = DNSResourceRecord::ANSWER;
3290 dr.d_name = target;
3291 dr.d_type = QType::SOA;
3292 dr.d_ttl = 3600;
3293 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3294 ad.d_records.insert(dr);
3295
3296 dr.d_place = DNSResourceRecord::ANSWER;
3297 dr.d_name = target;
3298 dr.d_type = QType::CNAME;
3299 dr.d_ttl = 3600;
3300 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
3301 ad.d_records.insert(dr);
3302
3303 auto map = std::make_shared<SyncRes::domainmap_t>();
3304 (*map)[target] = ad;
3305 SyncRes::setDomainMap(map);
3306
deca7d8f 3307 sr->setAsyncCallback([&queriesCount,externalCNAME,addr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3308
3309 queriesCount++;
3310
3311 if (domain == externalCNAME) {
3312 setLWResult(res, 0, true, false, true);
3313 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
3314 return 1;
3315 }
3316
3317 return 0;
3318 });
3319
3320 vector<DNSRecord> ret;
3321 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3322 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3323 BOOST_CHECK_EQUAL(ret.size(), 2);
3324 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3325 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
3326 BOOST_CHECK(ret[1].d_type == QType::A);
3327 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3328 BOOST_CHECK_EQUAL(queriesCount, 1);
3329}
3330
3331BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
3332 std::unique_ptr<SyncRes> sr;
895449a5 3333 initSR(sr);
3337c2f7
RG
3334
3335 primeHints();
3336
3337 size_t queriesCount = 0;
3338 const DNSName target("nodata.powerdns.com.");
3339 const DNSName authZone("powerdns.com");
3340
3341 SyncRes::AuthDomain ad;
3342 ad.d_name = authZone;
3343 DNSRecord dr;
3344 dr.d_place = DNSResourceRecord::ANSWER;
3345 dr.d_name = target;
3346 dr.d_type = QType::A;
3347 dr.d_ttl = 3600;
3348 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3349 ad.d_records.insert(dr);
3350
3351 dr.d_place = DNSResourceRecord::ANSWER;
3352 dr.d_name = authZone;
3353 dr.d_type = QType::SOA;
3354 dr.d_ttl = 3600;
3355 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3356 ad.d_records.insert(dr);
3357
3358 auto map = std::make_shared<SyncRes::domainmap_t>();
3359 (*map)[authZone] = ad;
3360 SyncRes::setDomainMap(map);
3361
deca7d8f 3362 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3363
3364 queriesCount++;
3365
3366 return 0;
3367 });
3368
3369 vector<DNSRecord> ret;
3370 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3371 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3372 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3373 BOOST_CHECK(ret[0].d_type == QType::SOA);
3374 BOOST_CHECK_EQUAL(queriesCount, 0);
3375}
3376
3377BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3378 std::unique_ptr<SyncRes> sr;
895449a5 3379 initSR(sr);
3337c2f7
RG
3380
3381 primeHints();
3382
3383 size_t queriesCount = 0;
3384 const DNSName target("nx.powerdns.com.");
3385 const DNSName authZone("powerdns.com");
3386
3387 SyncRes::AuthDomain ad;
3388 ad.d_name = authZone;
3389 DNSRecord dr;
3390 dr.d_place = DNSResourceRecord::ANSWER;
3391 dr.d_name = DNSName("powerdns.com.");
3392 dr.d_type = QType::SOA;
3393 dr.d_ttl = 3600;
3394 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3395 ad.d_records.insert(dr);
3396
3397 auto map = std::make_shared<SyncRes::domainmap_t>();
3398 (*map)[authZone] = ad;
3399 SyncRes::setDomainMap(map);
3400
deca7d8f 3401 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3402
3403 queriesCount++;
3404
3405 return 0;
3406 });
3407
3408 vector<DNSRecord> ret;
3409 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3410 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3411 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3412 BOOST_CHECK(ret[0].d_type == QType::SOA);
3413 BOOST_CHECK_EQUAL(queriesCount, 0);
3414}
3415
3416BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3417 std::unique_ptr<SyncRes> sr;
e1636f82 3418 initSR(sr, true, false);
3337c2f7
RG
3419
3420 primeHints();
3421
3422 size_t queriesCount = 0;
3423 const DNSName target("www.test.powerdns.com.");
3424 const ComboAddress targetAddr("192.0.2.2");
3425 const DNSName ns("ns1.test.powerdns.com.");
3426 const ComboAddress nsAddr("192.0.2.1");
3427 const DNSName authZone("powerdns.com");
3428
3429 SyncRes::AuthDomain ad;
3430 ad.d_name = authZone;
3431 DNSRecord dr;
3432 dr.d_place = DNSResourceRecord::ANSWER;
3433 dr.d_name = authZone;
3434 dr.d_type = QType::SOA;
3435 dr.d_ttl = 3600;
3436 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3437 ad.d_records.insert(dr);
3438
3439 dr.d_place = DNSResourceRecord::ANSWER;
3440 dr.d_name = DNSName("test.powerdns.com.");
3441 dr.d_type = QType::NS;
3442 dr.d_ttl = 3600;
3443 dr.d_content = std::make_shared<NSRecordContent>(ns);
3444 ad.d_records.insert(dr);
3445
3446 dr.d_place = DNSResourceRecord::ANSWER;
3447 dr.d_name = ns;
3448 dr.d_type = QType::A;
3449 dr.d_ttl = 3600;
3450 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3451 ad.d_records.insert(dr);
3452
3453 auto map = std::make_shared<SyncRes::domainmap_t>();
3454 (*map)[authZone] = ad;
3455 SyncRes::setDomainMap(map);
3456
e1636f82
RG
3457 testkeysset_t keys;
3458 auto luaconfsCopy = g_luaconfs.getCopy();
3459 luaconfsCopy.dsAnchors.clear();
3460 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3461 g_luaconfs.setState(luaconfsCopy);
3462
deca7d8f 3463 sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr,authZone,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3464
3465 queriesCount++;
e1636f82
RG
3466 if (type == QType::DS || type == QType::DNSKEY) {
3467 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone);
3468 }
3469
3337c2f7
RG
3470 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3471 setLWResult(res, 0, true, false, true);
3472 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3473 return 1;
3474 }
3475
3476 return 0;
3477 });
3478
e1636f82 3479 sr->setDNSSECValidationRequested(true);
3337c2f7
RG
3480 vector<DNSRecord> ret;
3481 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3482 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3483 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3484 BOOST_CHECK(ret[0].d_type == QType::A);
e1636f82
RG
3485 BOOST_CHECK_EQUAL(queriesCount, 4);
3486 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3337c2f7
RG
3487}
3488
3489BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3490 std::unique_ptr<SyncRes> sr;
895449a5 3491 initSR(sr);
3337c2f7
RG
3492
3493 primeHints();
3494
3495 size_t queriesCount = 0;
3496 const DNSName target("test.powerdns.com.");
3497 const ComboAddress targetAddr("192.0.2.2");
3498 const DNSName ns("ns1.test.powerdns.com.");
3499 const ComboAddress nsAddr("192.0.2.1");
3500 const DNSName authZone("powerdns.com");
3501
3502 SyncRes::AuthDomain ad;
3503 ad.d_name = authZone;
3504 DNSRecord dr;
3505 dr.d_place = DNSResourceRecord::ANSWER;
3506 dr.d_name = authZone;
3507 dr.d_type = QType::SOA;
3508 dr.d_ttl = 3600;
3509 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3510 ad.d_records.insert(dr);
3511
3512 dr.d_place = DNSResourceRecord::ANSWER;
3513 dr.d_name = DNSName("test.powerdns.com.");
3514 dr.d_type = QType::NS;
3515 dr.d_ttl = 3600;
3516 dr.d_content = std::make_shared<NSRecordContent>(ns);
3517 ad.d_records.insert(dr);
3518
3519 dr.d_place = DNSResourceRecord::ANSWER;
3520 dr.d_name = ns;
3521 dr.d_type = QType::A;
3522 dr.d_ttl = 3600;
3523 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3524 ad.d_records.insert(dr);
3525
3526 auto map = std::make_shared<SyncRes::domainmap_t>();
3527 (*map)[authZone] = ad;
3528 SyncRes::setDomainMap(map);
3529
deca7d8f 3530 sr->setAsyncCallback([&queriesCount,nsAddr,target,targetAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3531
3532 queriesCount++;
3533
3534 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3535 setLWResult(res, 0, true, false, true);
3536 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3537 return 1;
3538 }
3539
3540 return 0;
3541 });
3542
3543 vector<DNSRecord> ret;
3544 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3545 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3546 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3547 BOOST_CHECK(ret[0].d_type == QType::A);
3548 BOOST_CHECK_EQUAL(queriesCount, 1);
3549}
3550
3551BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3552 std::unique_ptr<SyncRes> sr;
895449a5 3553 initSR(sr);
3337c2f7
RG
3554
3555 primeHints();
3556
3557 size_t queriesCount = 0;
3558 const DNSName target("test.powerdns.com.");
3559 const ComboAddress targetAddr("192.0.2.2");
3560 const DNSName authZone("powerdns.com");
3561
3562 SyncRes::AuthDomain ad;
3563 ad.d_name = authZone;
3564 DNSRecord dr;
3565 dr.d_place = DNSResourceRecord::ANSWER;
3566 dr.d_name = authZone;
3567 dr.d_type = QType::SOA;
3568 dr.d_ttl = 3600;
3569 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3570 ad.d_records.insert(dr);
3571
3572 dr.d_place = DNSResourceRecord::ANSWER;
3573 dr.d_name = DNSName("*.powerdns.com.");
3574 dr.d_type = QType::A;
3575 dr.d_ttl = 3600;
3576 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3577 ad.d_records.insert(dr);
3578
3579 auto map = std::make_shared<SyncRes::domainmap_t>();
3580 (*map)[authZone] = ad;
3581 SyncRes::setDomainMap(map);
3582
deca7d8f 3583 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3584
3585 queriesCount++;
3586
3587 return 0;
3588 });
3589
3590 vector<DNSRecord> ret;
3591 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3592 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3593 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3594 BOOST_CHECK(ret[0].d_type == QType::A);
3595 BOOST_CHECK_EQUAL(queriesCount, 0);
3596}
3597
3598BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3599 std::unique_ptr<SyncRes> sr;
895449a5 3600 initSR(sr);
3337c2f7
RG
3601
3602 primeHints();
3603
3604 size_t queriesCount = 0;
3605 const DNSName target("test.powerdns.com.");
3606 const ComboAddress targetAddr("192.0.2.2");
3607 const DNSName authZone("powerdns.com");
3608
3609 SyncRes::AuthDomain ad;
3610 ad.d_name = authZone;
3611 DNSRecord dr;
3612 dr.d_place = DNSResourceRecord::ANSWER;
3613 dr.d_name = authZone;
3614 dr.d_type = QType::SOA;
3615 dr.d_ttl = 3600;
3616 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3617 ad.d_records.insert(dr);
3618
3619 dr.d_place = DNSResourceRecord::ANSWER;
3620 dr.d_name = DNSName("*.powerdns.com.");
3621 dr.d_type = QType::A;
3622 dr.d_ttl = 3600;
3623 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3624 ad.d_records.insert(dr);
3625
3626 auto map = std::make_shared<SyncRes::domainmap_t>();
3627 (*map)[authZone] = ad;
3628 SyncRes::setDomainMap(map);
3629
deca7d8f 3630 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3631
3632 queriesCount++;
3633
3634 return 0;
3635 });
3636
3637 vector<DNSRecord> ret;
3638 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3639 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3640 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3641 BOOST_CHECK(ret[0].d_type == QType::SOA);
3642 BOOST_CHECK_EQUAL(queriesCount, 0);
3643}
3644
3645BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3646 std::unique_ptr<SyncRes> sr;
895449a5 3647 initSR(sr);
3337c2f7
RG
3648
3649 primeHints();
3650
3651 size_t queriesCount = 0;
3652 const DNSName target("powerdns.com.");
3653 const ComboAddress addr("192.0.2.5");
3654
3655 SyncRes::AuthDomain ad;
3656 ad.d_name = target;
3657 DNSRecord dr;
3658 dr.d_place = DNSResourceRecord::ANSWER;
3659 dr.d_name = target;
3660 dr.d_type = QType::SOA;
3661 dr.d_ttl = 3600;
3662 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3663 ad.d_records.insert(dr);
3664
3665 dr.d_place = DNSResourceRecord::ANSWER;
3666 dr.d_name = target;
3667 dr.d_type = QType::A;
3668 dr.d_ttl = 3600;
3669 dr.d_content = std::make_shared<ARecordContent>(addr);
3670 ad.d_records.insert(dr);
3671
3672 auto map = std::make_shared<SyncRes::domainmap_t>();
3673 (*map)[target] = ad;
3674 SyncRes::setDomainMap(map);
3675
deca7d8f 3676 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3337c2f7
RG
3677
3678 queriesCount++;
3679 setLWResult(res, 0, true, false, true);
3680 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3681 return 1;
3682 });
3683
3684 /* simulate a no-RD query */
3685 sr->setCacheOnly();
3686
3687 vector<DNSRecord> ret;
3688 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3689 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3690 BOOST_CHECK_EQUAL(ret.size(), 1);
3691 BOOST_CHECK(ret[0].d_type == QType::A);
3692 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3693 BOOST_CHECK_EQUAL(queriesCount, 0);
3694}
3695
8455425c 3696BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
8455425c
RG
3697 init();
3698
3699 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3700 dcke->create(dcke->getBits());
3701 // cerr<<dcke->convertToISC()<<endl;
3702 DNSSECPrivateKey dpk;
3703 dpk.d_flags = 256;
3704 dpk.setKey(dcke);
3705
3706 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3707 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3708
3709 DNSName qname("powerdns.com.");
3710
179b340d 3711 time_t now = time(nullptr);
8455425c 3712 RRSIGRecordContent rrc;
179b340d
RG
3713 /* this RRSIG is valid for the current second only */
3714 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
8455425c
RG
3715
3716 skeyset_t keyset;
3717 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3718
3719 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3720 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3721
179b340d 3722 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
8455425c
RG
3723}
3724
3725BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3726 std::unique_ptr<SyncRes> sr;
895449a5 3727 initSR(sr, true);
8455425c 3728
0c43f455 3729 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3730
3731 primeHints();
3732 const DNSName target(".");
b7f378d1 3733 testkeysset_t keys;
8455425c
RG
3734
3735 auto luaconfsCopy = g_luaconfs.getCopy();
3736 luaconfsCopy.dsAnchors.clear();
3737 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3738 g_luaconfs.setState(luaconfsCopy);
3739
3740 size_t queriesCount = 0;
3741
deca7d8f 3742 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
3743 queriesCount++;
3744
3745 if (domain == target && type == QType::NS) {
3746
3747 setLWResult(res, 0, true, false, true);
3748 char addr[] = "a.root-servers.net.";
3749 for (char idx = 'a'; idx <= 'm'; idx++) {
3750 addr[0] = idx;
3751 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3752 }
3753
3754 addRRSIG(keys, res->d_records, domain, 300);
3755
3756 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3757 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3758
3759 return 1;
3760 } else if (domain == target && type == QType::DNSKEY) {
3761
3762 setLWResult(res, 0, true, false, true);
3763
3764 addDNSKEY(keys, domain, 300, res->d_records);
3765 addRRSIG(keys, res->d_records, domain, 300);
3766
3767 return 1;
3768 }
3769
3770 return 0;
3771 });
3772
3773 vector<DNSRecord> ret;
3774 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3775 BOOST_CHECK_EQUAL(res, RCode::NoError);
3776 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
3777 /* 13 NS + 1 RRSIG */
3778 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3779 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3780
3781 /* again, to test the cache */
3782 ret.clear();
3783 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3784 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3785 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
3786 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3787 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3788}
3789
3790BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3791 std::unique_ptr<SyncRes> sr;
895449a5 3792 initSR(sr, true);
8455425c 3793
0c43f455 3794 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3795
3796 primeHints();
3797 const DNSName target(".");
b7f378d1
RG
3798 testkeysset_t zskeys;
3799 testkeysset_t kskeys;
8455425c
RG
3800
3801 /* Generate key material for "." */
3802 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3803 dckeZ->create(dckeZ->getBits());
3804 DNSSECPrivateKey ksk;
3805 ksk.d_flags = 257;
3806 ksk.setKey(dckeZ);
b7f378d1
RG
3807 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3808
8455425c
RG
3809 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3810 dckeK->create(dckeK->getBits());
3811 DNSSECPrivateKey zsk;
3812 zsk.d_flags = 256;
3813 zsk.setKey(dckeK);
b7f378d1 3814 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3815
b7f378d1
RG
3816 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3817 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
8455425c
RG
3818
3819 /* Set the root DS */
8455425c
RG
3820 auto luaconfsCopy = g_luaconfs.getCopy();
3821 luaconfsCopy.dsAnchors.clear();
b7f378d1 3822 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
8455425c
RG
3823 g_luaconfs.setState(luaconfsCopy);
3824
3825 size_t queriesCount = 0;
3826
deca7d8f 3827 sr->setAsyncCallback([target,&queriesCount,zskeys,kskeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
3828 queriesCount++;
3829
3830 if (domain == target && type == QType::NS) {
3831
3832 setLWResult(res, 0, true, false, true);
3833 char addr[] = "a.root-servers.net.";
3834 for (char idx = 'a'; idx <= 'm'; idx++) {
3835 addr[0] = idx;
3836 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3837 }
3838
3839 addRRSIG(zskeys, res->d_records, domain, 300);
3840
3841 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3842 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3843
3844 return 1;
3845 } else if (domain == target && type == QType::DNSKEY) {
3846
3847 setLWResult(res, 0, true, false, true);
3848
3849 addDNSKEY(kskeys, domain, 300, res->d_records);
3850 addDNSKEY(zskeys, domain, 300, res->d_records);
3851 addRRSIG(kskeys, res->d_records, domain, 300);
3852
3853 return 1;
3854 }
3855
3856 return 0;
3857 });
3858
3859 vector<DNSRecord> ret;
3860 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3861 BOOST_CHECK_EQUAL(res, RCode::NoError);
3862 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
3863 /* 13 NS + 1 RRSIG */
3864 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3865 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3866
3867 /* again, to test the cache */
3868 ret.clear();
3869 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3870 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3871 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
3872 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3873 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3874}
3875
3876BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
3877 std::unique_ptr<SyncRes> sr;
895449a5 3878 initSR(sr, true);
8455425c 3879
0c43f455 3880 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3881
3882 primeHints();
3883 const DNSName target(".");
b7f378d1 3884 testkeysset_t keys;
8455425c
RG
3885
3886 auto luaconfsCopy = g_luaconfs.getCopy();
3887 luaconfsCopy.dsAnchors.clear();
3888 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3889 g_luaconfs.setState(luaconfsCopy);
3890
3891 size_t queriesCount = 0;
3892
deca7d8f 3893 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
3894 queriesCount++;
3895
3896 if (domain == target && type == QType::NS) {
3897
3898 setLWResult(res, 0, true, false, true);
3899 char addr[] = "a.root-servers.net.";
3900 for (char idx = 'a'; idx <= 'm'; idx++) {
3901 addr[0] = idx;
3902 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3903 }
3904
3905 addRRSIG(keys, res->d_records, domain, 300);
3906
3907 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3908 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3909
3910 return 1;
3911 } else if (domain == target && type == QType::DNSKEY) {
3912
3913 setLWResult(res, 0, true, false, true);
3914
3915 /* No DNSKEY */
3916
3917 return 1;
3918 }
3919
3920 return 0;
3921 });
3922
3923 vector<DNSRecord> ret;
3924 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3925 BOOST_CHECK_EQUAL(res, RCode::NoError);
3926 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3927 /* 13 NS + 1 RRSIG */
3928 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3929 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3930
3931 /* again, to test the cache */
3932 ret.clear();
3933 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3934 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3935 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3936 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3937 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3938}
3939
3940BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3941 std::unique_ptr<SyncRes> sr;
895449a5 3942 initSR(sr, true);
8455425c 3943
0c43f455 3944 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3945
3946 primeHints();
3947 const DNSName target(".");
b7f378d1
RG
3948 testkeysset_t dskeys;
3949 testkeysset_t keys;
8455425c
RG
3950
3951 /* Generate key material for "." */
3952 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3953 dckeDS->create(dckeDS->getBits());
3954 DNSSECPrivateKey dskey;
3955 dskey.d_flags = 257;
3956 dskey.setKey(dckeDS);
b7f378d1
RG
3957 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3958
8455425c
RG
3959 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3960 dcke->create(dcke->getBits());
3961 DNSSECPrivateKey dpk;
3962 dpk.d_flags = 256;
3963 dpk.setKey(dcke);
b7f378d1 3964 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3965
b7f378d1
RG
3966 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3967 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
8455425c
RG
3968
3969 /* Set the root DS */
8455425c
RG
3970 auto luaconfsCopy = g_luaconfs.getCopy();
3971 luaconfsCopy.dsAnchors.clear();
3972 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3973 g_luaconfs.setState(luaconfsCopy);
3974
3975 size_t queriesCount = 0;
3976
deca7d8f 3977 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
3978 queriesCount++;
3979
3980 if (domain == target && type == QType::NS) {
3981
3982 setLWResult(res, 0, true, false, true);
3983 char addr[] = "a.root-servers.net.";
3984 for (char idx = 'a'; idx <= 'm'; idx++) {
3985 addr[0] = idx;
3986 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3987 }
3988
3989 addRRSIG(keys, res->d_records, domain, 300);
3990
3991 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3992 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3993
3994 return 1;
3995 } else if (domain == target && type == QType::DNSKEY) {
3996
3997 setLWResult(res, 0, true, false, true);
3998
3999 addDNSKEY(keys, domain, 300, res->d_records);
4000 addRRSIG(keys, res->d_records, domain, 300);
4001
4002 return 1;
4003 }
4004
4005 return 0;
4006 });
4007
4008 vector<DNSRecord> ret;
4009 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4010 BOOST_CHECK_EQUAL(res, RCode::NoError);
4011 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
4012 /* 13 NS + 1 RRSIG */
4013 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4014 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
4015
4016 /* again, to test the cache */
4017 ret.clear();
4018 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4019 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4020 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4021 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4022 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
4023}
4024
4025BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
4026 std::unique_ptr<SyncRes> sr;
895449a5 4027 initSR(sr, true);
8455425c 4028
0c43f455 4029 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4030
4031 primeHints();
4032 const DNSName target(".");
b7f378d1
RG
4033 testkeysset_t keys;
4034 testkeysset_t rrsigkeys;
8455425c
RG
4035
4036 auto luaconfsCopy = g_luaconfs.getCopy();
4037 luaconfsCopy.dsAnchors.clear();
4038 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4039 g_luaconfs.setState(luaconfsCopy);
4040
4041 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4042 dckeRRSIG->create(dckeRRSIG->getBits());
4043 DNSSECPrivateKey rrsigkey;
4044 rrsigkey.d_flags = 257;
4045 rrsigkey.setKey(dckeRRSIG);
b7f378d1
RG
4046 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
4047
4048 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
8455425c
RG
4049
4050 size_t queriesCount = 0;
4051
deca7d8f 4052 sr->setAsyncCallback([target,&queriesCount,keys,rrsigkeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
4053 queriesCount++;
4054
4055 if (domain == target && type == QType::NS) {
4056
4057 setLWResult(res, 0, true, false, true);
4058 char addr[] = "a.root-servers.net.";
4059 for (char idx = 'a'; idx <= 'm'; idx++) {
4060 addr[0] = idx;
4061 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4062 }
4063
4064 addRRSIG(rrsigkeys, res->d_records, domain, 300);
4065
4066 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4067 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4068
4069 return 1;
4070 } else if (domain == target && type == QType::DNSKEY) {
4071
4072 setLWResult(res, 0, true, false, true);
4073
4074 addDNSKEY(keys, domain, 300, res->d_records);
4075 addRRSIG(rrsigkeys, res->d_records, domain, 300);
4076
4077 return 1;
4078 }
4079
4080 return 0;
4081 });
4082
4083 vector<DNSRecord> ret;
4084 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4085 BOOST_CHECK_EQUAL(res, RCode::NoError);
4086 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
4087 /* 13 NS + 1 RRSIG */
4088 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4089 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
4090
4091 /* again, to test the cache */
4092 ret.clear();
4093 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4094 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4095 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4096 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4097 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
4098}
4099
4100BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
4101 std::unique_ptr<SyncRes> sr;
895449a5 4102 initSR(sr, true);
8455425c 4103
0c43f455 4104 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4105
4106 primeHints();
4107 const DNSName target(".");
b7f378d1 4108 testkeysset_t keys;
8455425c
RG
4109
4110 auto luaconfsCopy = g_luaconfs.getCopy();
4111 luaconfsCopy.dsAnchors.clear();
4112 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4113 g_luaconfs.setState(luaconfsCopy);
4114
4115 size_t queriesCount = 0;
4116
deca7d8f 4117 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
4118 queriesCount++;
4119
4120 if (domain == target && type == QType::NS) {
4121
4122 setLWResult(res, 0, true, false, true);
4123 char addr[] = "a.root-servers.net.";
4124 for (char idx = 'a'; idx <= 'm'; idx++) {
4125 addr[0] = idx;
4126 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4127 }
4128
4129 /* No RRSIG */
4130
4131 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4132 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4133
4134 return 1;
4135 } else if (domain == target && type == QType::DNSKEY) {
4136
4137 setLWResult(res, 0, true, false, true);
4138
4139 addDNSKEY(keys, domain, 300, res->d_records);
4140 addRRSIG(keys, res->d_records, domain, 300);
4141
4142 return 1;
4143 }
4144
4145 return 0;
4146 });
4147
4148 vector<DNSRecord> ret;
4149 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4150 BOOST_CHECK_EQUAL(res, RCode::NoError);
4151 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
4152 /* 13 NS + 0 RRSIG */
4153 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4154 /* no RRSIG so no query for DNSKEYs */
4155 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4156
4157 /* again, to test the cache */
4158 ret.clear();
4159 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4160 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4161 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4162 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4163 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4164}
4165
4166BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
4167 std::unique_ptr<SyncRes> sr;
895449a5 4168 initSR(sr, true);
8455425c 4169
0c43f455 4170 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4171
4172 primeHints();
4173 const DNSName target(".");
b7f378d1 4174 testkeysset_t keys;
8455425c
RG
4175
4176 /* Generate key material for "." */
4177 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4178 dcke->create(dcke->getBits());
4179 DNSSECPrivateKey dpk;
4180 dpk.d_flags = 256;
4181 dpk.setKey(dcke);
4182 /* Fake algorithm number (private) */
4183 dpk.d_algorithm = 253;
4184
8455425c 4185 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
b7f378d1 4186 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
8455425c
RG
4187 /* Fake algorithm number (private) */
4188 drc.d_algorithm = 253;
4189
b7f378d1 4190 /* Set the root DS */
8455425c
RG
4191 auto luaconfsCopy = g_luaconfs.getCopy();
4192 luaconfsCopy.dsAnchors.clear();
4193 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4194 g_luaconfs.setState(luaconfsCopy);
4195
4196 size_t queriesCount = 0;
4197
deca7d8f 4198 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
4199 queriesCount++;
4200
4201 if (domain == target && type == QType::NS) {
4202
4203 setLWResult(res, 0, true, false, true);
4204 char addr[] = "a.root-servers.net.";
4205 for (char idx = 'a'; idx <= 'm'; idx++) {
4206 addr[0] = idx;
4207 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4208 }
4209
4210 addRRSIG(keys, res->d_records, domain, 300);
4211
4212 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4213 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4214
4215 return 1;
4216 } else if (domain == target && type == QType::DNSKEY) {
4217
4218 setLWResult(res, 0, true, false, true);
4219
4220 addDNSKEY(keys, domain, 300, res->d_records);
4221 addRRSIG(keys, res->d_records, domain, 300);
4222
4223 return 1;
4224 }
4225
4226 return 0;
4227 });
4228
4229 vector<DNSRecord> ret;
4230 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4231 BOOST_CHECK_EQUAL(res, RCode::NoError);
4232 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4233 /* 13 NS + 1 RRSIG */
4234 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4235 /* no supported DS so no query for DNSKEYs */
4236 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4237
4238 /* again, to test the cache */
4239 ret.clear();
4240 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4241 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4242 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4243 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4244 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4245}
4246
4247BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
4248 std::unique_ptr<SyncRes> sr;
895449a5 4249 initSR(sr, true);
8455425c 4250
0c43f455 4251 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4252
4253 primeHints();
4254 const DNSName target(".");
b7f378d1 4255 testkeysset_t keys;
8455425c
RG
4256
4257 /* Generate key material for "." */
4258 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4259 dcke->create(dcke->getBits());
4260 DNSSECPrivateKey dpk;
4261 dpk.d_flags = 256;
4262 dpk.setKey(dcke);
8455425c
RG
4263 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
4264 /* Fake digest number (reserved) */
4265 drc.d_digesttype = 0;
4266
b7f378d1
RG
4267 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
4268
4269 /* Set the root DS */
8455425c
RG
4270 auto luaconfsCopy = g_luaconfs.getCopy();
4271 luaconfsCopy.dsAnchors.clear();
4272 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4273 g_luaconfs.setState(luaconfsCopy);
4274
4275 size_t queriesCount = 0;
4276
deca7d8f 4277 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
4278 queriesCount++;
4279
4280 if (domain == target && type == QType::NS) {
4281
4282 setLWResult(res, 0, true, false, true);
4283 char addr[] = "a.root-servers.net.";
4284 for (char idx = 'a'; idx <= 'm'; idx++) {
4285 addr[0] = idx;
4286 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4287 }
4288
4289 addRRSIG(keys, res->d_records, domain, 300);
4290
4291 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4292 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4293
4294 return 1;
4295 } else if (domain == target && type == QType::DNSKEY) {
4296
4297 setLWResult(res, 0, true, false, true);
4298
4299 addDNSKEY(keys, domain, 300, res->d_records);
4300 addRRSIG(keys, res->d_records, domain, 300);
4301
4302 return 1;
4303 }
4304
4305 return 0;
4306 });
4307
4308 vector<DNSRecord> ret;
4309 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4310 BOOST_CHECK_EQUAL(res, RCode::NoError);
4311 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4312 /* 13 NS + 1 RRSIG */
4313 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4314 /* no supported DS so no query for DNSKEYs */
4315 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4316
4317 /* again, to test the cache */
4318 ret.clear();
4319 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4320 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4321 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4322 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4323 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4324}
4325
3d5ebf10
RG
4326BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
4327 std::unique_ptr<SyncRes> sr;
4328 initSR(sr, true);
4329
0c43f455 4330 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4331
4332 primeHints();
4333 const DNSName target(".");
4334 testkeysset_t keys;
4335
4336 auto luaconfsCopy = g_luaconfs.getCopy();
4337 luaconfsCopy.dsAnchors.clear();
4338 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4339
4340 g_luaconfs.setState(luaconfsCopy);
4341
4342 size_t queriesCount = 0;
4343
deca7d8f 4344 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3d5ebf10
RG
4345 queriesCount++;
4346
4347 if (domain == target && type == QType::NS) {
4348
4349 setLWResult(res, 0, true, false, true);
4350 char addr[] = "a.root-servers.net.";
4351 for (char idx = 'a'; idx <= 'm'; idx++) {
4352 addr[0] = idx;
4353 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4354 }
4355
4356 addRRSIG(keys, res->d_records, domain, 300, true);
4357
4358 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4359 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4360
4361 return 1;
4362 } else if (domain == target && type == QType::DNSKEY) {
4363
4364 setLWResult(res, 0, true, false, true);
4365
4366 addDNSKEY(keys, domain, 300, res->d_records);
4367 addRRSIG(keys, res->d_records, domain, 300);
4368
4369 return 1;
4370 }
4371
4372 return 0;
4373 });
4374
4375 vector<DNSRecord> ret;
4376 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4377 BOOST_CHECK_EQUAL(res, RCode::NoError);
4378 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4379 /* 13 NS + 1 RRSIG */
4380 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4381 BOOST_CHECK_EQUAL(queriesCount, 2);
4382
4383 /* again, to test the cache */
4384 ret.clear();
4385 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4386 BOOST_CHECK_EQUAL(res, RCode::NoError);
4387 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4388 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4389 BOOST_CHECK_EQUAL(queriesCount, 2);
4390}
4391
4392BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
4393 std::unique_ptr<SyncRes> sr;
4394 initSR(sr, true);
4395
0c43f455 4396 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4397
4398 primeHints();
4399 const DNSName target(".");
4400 testkeysset_t keys;
4401
4402 auto luaconfsCopy = g_luaconfs.getCopy();
4403 luaconfsCopy.dsAnchors.clear();
4404 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4405
4406 g_luaconfs.setState(luaconfsCopy);
4407
4408 size_t queriesCount = 0;
4409
deca7d8f 4410 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3d5ebf10
RG
4411 queriesCount++;
4412
4413 if (domain == target && type == QType::NS) {
4414
4415 setLWResult(res, 0, true, false, true);
4416 char addr[] = "a.root-servers.net.";
4417 for (char idx = 'a'; idx <= 'm'; idx++) {
4418 addr[0] = idx;
4419 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4420 }
4421
4422 /* FORCE WRONG ALGO */
4423 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4424
4425 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4426 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4427
4428 return 1;
4429 } else if (domain == target && type == QType::DNSKEY) {
4430
4431 setLWResult(res, 0, true, false, true);
4432
4433 addDNSKEY(keys, domain, 300, res->d_records);
4434 addRRSIG(keys, res->d_records, domain, 300);
4435
4436 return 1;
4437 }
4438
4439 return 0;
4440 });
4441
4442 vector<DNSRecord> ret;
4443 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4444 BOOST_CHECK_EQUAL(res, RCode::NoError);
4445 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4446 /* 13 NS + 1 RRSIG */
4447 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4448 BOOST_CHECK_EQUAL(queriesCount, 2);
4449
4450 /* again, to test the cache */
4451 ret.clear();
4452 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4453 BOOST_CHECK_EQUAL(res, RCode::NoError);
4454 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4455 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4456 BOOST_CHECK_EQUAL(queriesCount, 2);
4457}
4458
f100caac
RG
4459BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds) {
4460 std::unique_ptr<SyncRes> sr;
4461 initSR(sr, true);
4462
4463 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4464
4465 primeHints();
4466 const DNSName target("com.");
4467 const ComboAddress targetAddr("192.0.2.42");
4468 testkeysset_t keys;
4469
4470 auto luaconfsCopy = g_luaconfs.getCopy();
4471 luaconfsCopy.dsAnchors.clear();
4472 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4473 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4474
4475 g_luaconfs.setState(luaconfsCopy);
4476
4477 size_t queriesCount = 0;
4478
deca7d8f 4479 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f100caac
RG
4480 queriesCount++;
4481
4482 DNSName auth = domain;
4483
4484 if (type == QType::DS || type == QType::DNSKEY) {
4485 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4486 return 0;
4487 }
4488
4489 if (type == QType::DS && domain == target) {
4490 /* remove the last record, which is the DS's RRSIG */
4491 res->d_records.pop_back();
4492 }
4493
4494 return 1;
4495 }
4496
4497 if (isRootServer(ip)) {
4498 setLWResult(res, 0, false, false, true);
4499 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4500 /* Include the DS but omit the RRSIG*/
4501 addDS(DNSName("com."), 300, res->d_records, keys);
4502 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4503 return 1;
4504 }
4505
4506 if (ip == ComboAddress("192.0.2.1:53")) {
4507 setLWResult(res, RCode::NoError, true, false, true);
4508 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4509 addRRSIG(keys, res->d_records, auth, 300);
4510 return 1;
4511 }
4512
4513 return 0;
4514 });
4515
4516 vector<DNSRecord> ret;
4517 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4518 BOOST_CHECK_EQUAL(res, RCode::NoError);
4519 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4520 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4521 BOOST_CHECK_EQUAL(queriesCount, 4);
4522
4523 /* again, to test the cache */
4524 ret.clear();
4525 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4526 BOOST_CHECK_EQUAL(res, RCode::NoError);
4527 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4528 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4529 BOOST_CHECK_EQUAL(queriesCount, 4);
4530
4531 /* now we ask directly for the DS */
4532 ret.clear();
4533 res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4534 BOOST_CHECK_EQUAL(res, RCode::NoError);
4535 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4536 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4537 BOOST_CHECK_EQUAL(queriesCount, 4);
4538}
4539
4540BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds_direct) {
4541 std::unique_ptr<SyncRes> sr;
4542 initSR(sr, true);
4543
4544 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4545
4546 primeHints();
4547 const DNSName target("com.");
4548 testkeysset_t keys;
4549
4550 auto luaconfsCopy = g_luaconfs.getCopy();
4551 luaconfsCopy.dsAnchors.clear();
4552 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4553 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4554
4555 g_luaconfs.setState(luaconfsCopy);
4556
4557 size_t queriesCount = 0;
4558
deca7d8f 4559 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f100caac
RG
4560 queriesCount++;
4561
4562 DNSName auth = domain;
4563
4564 if (type == QType::DS || type == QType::DNSKEY) {
4565 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4566 return 0;
4567 }
4568
4569 if (type == QType::DS && domain == target) {
4570 /* remove the last record, which is the DS's RRSIG */
4571 res->d_records.pop_back();
4572 }
4573
4574 return 1;
4575 }
4576
4577 if (isRootServer(ip)) {
4578 setLWResult(res, 0, false, false, true);
4579 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4580 /* Include the DS but omit the RRSIG*/
4581 addDS(DNSName("com."), 300, res->d_records, keys);
4582 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4583 return 1;
4584 }
4585
4586 return 0;
4587 });
4588
4589 vector<DNSRecord> ret;
4590 int res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4591 BOOST_CHECK_EQUAL(res, RCode::NoError);
4592 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4593 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4594 BOOST_CHECK_EQUAL(queriesCount, 1);
4595}
4596
b7f378d1 4597BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
8455425c 4598 std::unique_ptr<SyncRes> sr;
895449a5 4599 initSR(sr, true);
8455425c 4600
0c43f455 4601 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4602
4603 primeHints();
4604 const DNSName target("powerdns.com.");
b7f378d1
RG
4605 const ComboAddress targetAddr("192.0.2.42");
4606 testkeysset_t keys;
8455425c
RG
4607
4608 auto luaconfsCopy = g_luaconfs.getCopy();
4609 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4610 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4611 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4612 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
8455425c
RG
4613
4614 g_luaconfs.setState(luaconfsCopy);
4615
4616 size_t queriesCount = 0;
4617
deca7d8f 4618 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
4619 queriesCount++;
4620
b7f378d1
RG
4621 DNSName auth = domain;
4622 if (domain == target) {
4623 auth = DNSName("powerdns.com.");
4624 }
5374b03b
RG
4625
4626 if (type == QType::DS || type == QType::DNSKEY) {
4627 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8455425c 4628 }
5374b03b
RG
4629
4630 if (isRootServer(ip)) {
4631 setLWResult(res, 0, false, false, true);
4632 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4633 addDS(DNSName("com."), 300, res->d_records, keys);
4634 addRRSIG(keys, res->d_records, DNSName("."), 300);
4635 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8455425c
RG
4636 return 1;
4637 }
5374b03b
RG
4638
4639 if (ip == ComboAddress("192.0.2.1:53")) {
4640 if (domain == DNSName("com.")) {
4641 setLWResult(res, 0, true, false, true);
4642 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4643 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4644 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4645 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4646 }
5374b03b
RG
4647 else {
4648 setLWResult(res, 0, false, false, true);
4649 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4650 addDS(auth, 300, res->d_records, keys);
4651 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4652 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8455425c 4653 }
5374b03b
RG
4654 return 1;
4655 }
4656
4657 if (ip == ComboAddress("192.0.2.2:53")) {
4658 if (type == QType::NS) {
4659 setLWResult(res, 0, true, false, true);
4660 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4661 addRRSIG(keys, res->d_records, auth, 300);
4662 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4663 addRRSIG(keys, res->d_records, auth, 300);
8455425c 4664 }
5374b03b
RG
4665 else {
4666 setLWResult(res, RCode::NoError, true, false, true);
4667 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4668 addRRSIG(keys, res->d_records, auth, 300);
4669 }
4670 return 1;
8455425c
RG
4671 }
4672
4673 return 0;
4674 });
4675
4676 vector<DNSRecord> ret;
4677 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1
RG
4678 BOOST_CHECK_EQUAL(res, RCode::NoError);
4679 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4680 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4681 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4682
4683 /* again, to test the cache */
4684 ret.clear();
4685 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4686 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4687 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1 4688 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4689 BOOST_CHECK_EQUAL(queriesCount, 8);
8455425c
RG
4690}
4691
428f41b7
RG
4692BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4693 std::unique_ptr<SyncRes> sr;
4694 initSR(sr, true);
4695
0c43f455 4696 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4697
4698 primeHints();
4699 const DNSName target("powerdns.com.");
4700 const ComboAddress targetAddr("192.0.2.42");
4701 testkeysset_t keys;
4702
4703 auto luaconfsCopy = g_luaconfs.getCopy();
4704 luaconfsCopy.dsAnchors.clear();
4705 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4706 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4707 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4708 g_luaconfs.setState(luaconfsCopy);
4709
4710 size_t queriesCount = 0;
4711
deca7d8f 4712 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
428f41b7
RG
4713 queriesCount++;
4714
4715 DNSName auth = domain;
4716 if (domain == target) {
4717 auth = DNSName("powerdns.com.");
4718 }
5374b03b
RG
4719
4720 if (type == QType::DS || type == QType::DNSKEY) {
4721 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4722 }
5374b03b
RG
4723
4724 if (isRootServer(ip)) {
4725 setLWResult(res, 0, false, false, true);
4726 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4727 addDS(DNSName("com."), 300, res->d_records, keys);
4728 addRRSIG(keys, res->d_records, DNSName("."), 300);
4729 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4730 return 1;
4731 }
5374b03b
RG
4732
4733 if (ip == ComboAddress("192.0.2.1:53")) {
4734 if (domain == DNSName("com.")) {
4735 setLWResult(res, 0, true, false, true);
4736 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4737 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4738 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4739 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4740 }
5374b03b
RG
4741 else {
4742 setLWResult(res, 0, false, false, true);
4743 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4744 addDS(auth, 300, res->d_records, keys);
4745 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4746 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4747 }
5374b03b
RG
4748 return 1;
4749 }
4750
4751 if (ip == ComboAddress("192.0.2.2:53")) {
4752 if (type == QType::NS) {
4753 setLWResult(res, 0, true, false, true);
4754 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4755 addRRSIG(keys, res->d_records, auth, 300);
4756 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4757 addRRSIG(keys, res->d_records, auth, 300);
4758 }
4759 else {
4760 setLWResult(res, RCode::NoError, true, false, true);
4761 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4762 addRRSIG(keys, res->d_records, auth, 300);
428f41b7 4763 }
5374b03b 4764 return 1;
428f41b7
RG
4765 }
4766
4767 return 0;
4768 });
4769
4770 vector<DNSRecord> ret;
4771 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4772 BOOST_CHECK_EQUAL(res, RCode::NoError);
4773 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4774 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4775 BOOST_CHECK_EQUAL(queriesCount, 8);
4776
4777 /* again, to test the cache */
4778 ret.clear();
4779 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4780 BOOST_CHECK_EQUAL(res, RCode::NoError);
4781 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4782 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4783 BOOST_CHECK_EQUAL(queriesCount, 8);
4784
4785 /* this time we ask for the NS that should be in the cache, to check
4786 the validation status */
4787 ret.clear();
4788 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4789 BOOST_CHECK_EQUAL(res, RCode::NoError);
4790 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4791 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4792 BOOST_CHECK_EQUAL(queriesCount, 9);
428f41b7
RG
4793
4794}
4795
4796BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4797 std::unique_ptr<SyncRes> sr;
4798 initSR(sr, true);
4799
0c43f455 4800 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4801
4802 primeHints();
4803 const DNSName target("powerdns.com.");
4804 const ComboAddress targetAddr("192.0.2.42");
4805 testkeysset_t keys;
4806
4807 auto luaconfsCopy = g_luaconfs.getCopy();
4808 luaconfsCopy.dsAnchors.clear();
4809 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4810 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4811 g_luaconfs.setState(luaconfsCopy);
4812
4813 size_t queriesCount = 0;
4814
deca7d8f 4815 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
428f41b7
RG
4816 queriesCount++;
4817
4818 DNSName auth = domain;
4819 if (domain == target) {
4820 auth = DNSName("powerdns.com.");
4821 }
5374b03b
RG
4822
4823 if (type == QType::DS || type == QType::DNSKEY) {
4824 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4825 }
5374b03b
RG
4826
4827 if (isRootServer(ip)) {
4828 setLWResult(res, 0, false, false, true);
4829 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4830 addDS(DNSName("com."), 300, res->d_records, keys);
4831 addRRSIG(keys, res->d_records, DNSName("."), 300);
4832 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4833 return 1;
4834 }
5374b03b
RG
4835
4836 if (ip == ComboAddress("192.0.2.1:53")) {
4837 if (domain == DNSName("com.")) {
4838 setLWResult(res, 0, true, false, true);
4839 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4840 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4841 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4842 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4843 }
5374b03b
RG
4844 else {
4845 setLWResult(res, 0, false, false, true);
4846 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4847 /* no DS */
4848 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4849 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4850 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4851 }
5374b03b
RG
4852 return 1;
4853 }
4854
4855 if (ip == ComboAddress("192.0.2.2:53")) {
4856 if (type == QType::NS) {
4857 setLWResult(res, 0, true, false, true);
4858 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4859 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4860 }
5374b03b
RG
4861 else {
4862 setLWResult(res, RCode::NoError, true, false, true);
4863 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4864 }
4865 return 1;
428f41b7
RG
4866 }
4867
4868 return 0;
4869 });
4870
4871 vector<DNSRecord> ret;
4872 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4873 BOOST_CHECK_EQUAL(res, RCode::NoError);
4874 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4875 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4876 BOOST_CHECK_EQUAL(queriesCount, 7);
4877
4878 /* again, to test the cache */
4879 ret.clear();
4880 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4881 BOOST_CHECK_EQUAL(res, RCode::NoError);
4882 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4883 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4884 BOOST_CHECK_EQUAL(queriesCount, 7);
4885
4886 /* this time we ask for the NS that should be in the cache, to check
4887 the validation status */
4888 ret.clear();
4889 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4890 BOOST_CHECK_EQUAL(res, RCode::NoError);
4891 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4892 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4893 BOOST_CHECK_EQUAL(queriesCount, 8);
428f41b7
RG
4894}
4895
b7f378d1 4896BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
8455425c 4897 std::unique_ptr<SyncRes> sr;
895449a5 4898 initSR(sr, true);
8455425c 4899
0c43f455 4900 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4901
4902 primeHints();
b7f378d1
RG
4903 const DNSName target("powerdns.com.");
4904 const ComboAddress targetAddr("192.0.2.42");
4905 testkeysset_t keys;
8455425c
RG
4906
4907 auto luaconfsCopy = g_luaconfs.getCopy();
4908 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4909 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4910 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4911 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4912
4913 /* Add a NTA for "powerdns.com" */
4914 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
8455425c 4915
8455425c
RG
4916 g_luaconfs.setState(luaconfsCopy);
4917
4918 size_t queriesCount = 0;
4919
deca7d8f 4920 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
4921 queriesCount++;
4922
b7f378d1
RG
4923 DNSName auth = domain;
4924 if (domain == target) {
4925 auth = DNSName("powerdns.com.");
4926 }
5374b03b
RG
4927
4928 if (type == QType::DS || type == QType::DNSKEY) {
4929 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
b7f378d1 4930 }
5374b03b
RG
4931
4932 if (isRootServer(ip)) {
4933 setLWResult(res, 0, false, false, true);
4934 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4935 addDS(DNSName("com."), 300, res->d_records, keys);
4936 addRRSIG(keys, res->d_records, DNSName("."), 300);
4937 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1
RG
4938 return 1;
4939 }
5374b03b
RG
4940
4941 if (ip == ComboAddress("192.0.2.1:53")) {
4942 if (domain == DNSName("com.")) {
4943 setLWResult(res, 0, true, false, true);
4944 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4945 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4946 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4947 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4948 }
5374b03b
RG
4949 else {
4950 setLWResult(res, 0, false, false, true);
4951 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4952 addDS(auth, 300, res->d_records, keys);
4953 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4954 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1 4955 }
5374b03b
RG
4956 return 1;
4957 }
4958
4959 if (ip == ComboAddress("192.0.2.2:53")) {
4960 if (type == QType::NS) {
4961 setLWResult(res, 0, true, false, true);
4962 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4963 addRRSIG(keys, res->d_records, auth, 300);
4964 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4965 addRRSIG(keys, res->d_records, auth, 300);
4966 }
4967 else {
4968 setLWResult(res, RCode::NoError, true, false, true);
4969 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4970 addRRSIG(keys, res->d_records, auth, 300);
b7f378d1 4971 }
5374b03b 4972 return 1;
b7f378d1
RG
4973 }
4974
4975 return 0;
4976 });
4977
4978 vector<DNSRecord> ret;
4979 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4980 BOOST_CHECK_EQUAL(res, RCode::NoError);
4981 /* Should be insecure because of the NTA */
4982 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4983 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4984 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4985
4986 /* again, to test the cache */
4987 ret.clear();
4988 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4989 BOOST_CHECK_EQUAL(res, RCode::NoError);
4990 /* Should be insecure because of the NTA */
4991 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4992 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4993 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4994}
4995
4996BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4997 std::unique_ptr<SyncRes> sr;
895449a5 4998 initSR(sr, true);
b7f378d1 4999
0c43f455 5000 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5001
5002 primeHints();
5003 const DNSName target("powerdns.com.");
5004 const ComboAddress targetAddr("192.0.2.42");
5005 testkeysset_t keys;
5006
5007 auto luaconfsCopy = g_luaconfs.getCopy();
5008 luaconfsCopy.dsAnchors.clear();
5009 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5010 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5011 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5012
5013 /* Add a NTA for "powerdns.com" */
5014 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
5015
5016 g_luaconfs.setState(luaconfsCopy);
5017
5018 size_t queriesCount = 0;
5019
deca7d8f 5020 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7f378d1
RG
5021 queriesCount++;
5022
5023 if (type == QType::DS || type == QType::DNSKEY) {
5024 setLWResult(res, 0, false, false, true);
5025 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5026 return 1;
5027 }
f24465e5 5028 else {
b7f378d1
RG
5029 if (isRootServer(ip)) {
5030 setLWResult(res, 0, false, false, true);
5031 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5032 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5033 return 1;
5034 }
5035 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5036 if (domain == DNSName("com.")) {
5037 setLWResult(res, 0, true, false, true);
5038 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5039 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5040 }
5041 else {
5042 setLWResult(res, 0, false, false, true);
5043 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5044 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5045 }
b7f378d1
RG
5046 return 1;
5047 }
5048 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5049 if (type == QType::NS) {
5050 setLWResult(res, 0, true, false, true);
5051 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5052 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5053 }
5054 else {
5055 setLWResult(res, RCode::NoError, true, false, true);
5056 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
5057 }
b7f378d1
RG
5058 return 1;
5059 }
5060 }
5061
5062 return 0;
5063 });
5064
5065 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
5066 vector<DNSRecord> ret;
5067 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5068 BOOST_CHECK_EQUAL(res, RCode::NoError);
5069 /* Should be insecure because of the NTA */
5070 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5071 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 5072 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
5073
5074 /* again, to test the cache */
5075 ret.clear();
5076 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5077 BOOST_CHECK_EQUAL(res, RCode::NoError);
5078 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5079 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 5080 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
5081}
5082
5083BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
5084 std::unique_ptr<SyncRes> sr;
895449a5 5085 initSR(sr, true);
b7f378d1 5086
0c43f455 5087 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5088
5089 primeHints();
5090 const DNSName target("powerdns.com.");
5091 testkeysset_t keys;
5092
5093 auto luaconfsCopy = g_luaconfs.getCopy();
5094 luaconfsCopy.dsAnchors.clear();
5095 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5096 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5097 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5098
5099 g_luaconfs.setState(luaconfsCopy);
5100
5101 size_t queriesCount = 0;
5102
deca7d8f 5103 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7f378d1
RG
5104 queriesCount++;
5105
5374b03b
RG
5106 if (type == QType::DS || type == QType::DNSKEY) {
5107 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 5108 }
f24465e5 5109 else {
b7f378d1
RG
5110 if (isRootServer(ip)) {
5111 setLWResult(res, 0, false, false, true);
5112 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5113 addDS(DNSName("com."), 300, res->d_records, keys);
5114 addRRSIG(keys, res->d_records, DNSName("."), 300);
5115 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5116 return 1;
5117 }
5118 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5119 if (domain == DNSName("com.")) {
5120 setLWResult(res, 0, true, false, true);
5121 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5122 addRRSIG(keys, res->d_records, domain, 300);
5123 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5124 addRRSIG(keys, res->d_records, domain, 300);
5125 }
5126 else {
5127 setLWResult(res, 0, false, false, true);
5128 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5129 addDS(domain, 300, res->d_records, keys);
5130 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5131 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5132 }
b7f378d1
RG
5133 return 1;
5134 }
5135 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5136 if (type == QType::NS) {
5137 setLWResult(res, 0, true, false, true);
5138 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5139 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5140 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5141 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5142 }
5143 else {
5144 setLWResult(res, 0, true, false, true);
5145 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5146 addRRSIG(keys, res->d_records, domain, 300);
5147 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
5148 addRRSIG(keys, res->d_records, domain, 300);
5149 }
b7f378d1
RG
5150 return 1;
5151 }
5152 }
5153
5154 return 0;
5155 });
5156
5157 vector<DNSRecord> ret;
5158 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5159 BOOST_CHECK_EQUAL(res, RCode::NoError);
5160 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5161 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5162 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5163
5164 /* again, to test the cache */
5165 ret.clear();
5166 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5167 BOOST_CHECK_EQUAL(res, RCode::NoError);
5168 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5169 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5170 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5171}
5172
5173BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
5174 std::unique_ptr<SyncRes> sr;
895449a5 5175 initSR(sr, true);
b7f378d1 5176
0c43f455 5177 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5178
5179 primeHints();
5180 const DNSName target("nx.powerdns.com.");
5181 testkeysset_t keys;
5182
5183 auto luaconfsCopy = g_luaconfs.getCopy();
5184 luaconfsCopy.dsAnchors.clear();
5185 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5186 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5187 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5188
5189 g_luaconfs.setState(luaconfsCopy);
5190
5191 size_t queriesCount = 0;
5192
deca7d8f 5193 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7f378d1
RG
5194 queriesCount++;
5195
5196 DNSName auth = domain;
5197 if (domain == target) {
5198 auth = DNSName("powerdns.com.");
5199 }
5374b03b
RG
5200 if (type == QType::DS || type == QType::DNSKEY) {
5201 if (type == QType::DS && domain == target) {
5202 setLWResult(res, RCode::NXDomain, true, false, true);
5203 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5204 addRRSIG(keys, res->d_records, auth, 300);
5205 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5206 addRRSIG(keys, res->d_records, auth, 300);
5207 return 1;
5208 }
5209 else {
5210 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
5211 }
b7f378d1 5212 }
f24465e5 5213 else {
b7f378d1
RG
5214 if (isRootServer(ip)) {
5215 setLWResult(res, 0, false, false, true);
5216 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5217 addDS(DNSName("com."), 300, res->d_records, keys);
5218 addRRSIG(keys, res->d_records, DNSName("."), 300);
5219 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5220 return 1;
5221 }
5222 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5223 if (domain == DNSName("com.")) {
5224 setLWResult(res, 0, true, false, true);
5225 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5226 addRRSIG(keys, res->d_records, domain, 300);
5227 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5228 addRRSIG(keys, res->d_records, domain, 300);
5229 }
5230 else {
5231 setLWResult(res, 0, false, false, true);
5232 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5233 addDS(auth, 300, res->d_records, keys);
5234 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5235 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5236 }
b7f378d1
RG
5237 return 1;
5238 }
5239 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5240 if (type == QType::NS) {
5241 setLWResult(res, 0, true, false, true);
5242 if (domain == DNSName("powerdns.com.")) {
5243 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5244 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5245 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5246 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5247 }
5248 else {
5249 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5250 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5251 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5252 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5253 }
5254 }
5255 else {
5256 setLWResult(res, RCode::NXDomain, true, false, true);
5257 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5258 addRRSIG(keys, res->d_records, auth, 300);
5259 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5260 addRRSIG(keys, res->d_records, auth, 300);
9b061cf5
RG
5261 /* add wildcard denial */
5262 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5263 addRRSIG(keys, res->d_records, auth, 300);
f24465e5 5264 }
b7f378d1
RG
5265 return 1;
5266 }
5267 }
5268
5269 return 0;
5270 });
5271
5272 vector<DNSRecord> ret;
5273 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5274 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5275 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5276 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5277 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5278
5279 /* again, to test the cache */
5280 ret.clear();
5281 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5282 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5283 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5284 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5285 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5286}
5287
2b984251
RG
5288BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
5289 std::unique_ptr<SyncRes> sr;
5290 initSR(sr, true);
5291
0c43f455 5292 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2b984251
RG
5293
5294 primeHints();
5295 const DNSName target("www.powerdns.com.");
5296 testkeysset_t keys;
5297
5298 auto luaconfsCopy = g_luaconfs.getCopy();
5299 luaconfsCopy.dsAnchors.clear();
5300 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5301 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5302 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5303
5304 g_luaconfs.setState(luaconfsCopy);
5305
5306 size_t queriesCount = 0;
5307
deca7d8f 5308 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2b984251
RG
5309 queriesCount++;
5310
5374b03b
RG
5311 if (type == QType::DS || type == QType::DNSKEY) {
5312 if (type == QType::DS && domain == target) {
5313 setLWResult(res, RCode::NoError, true, false, true);
5314 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5315 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5316 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5317 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5318 return 1;
5319 }
5320 else {
5321 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5322 }
2b984251 5323 }
f24465e5 5324 else {
2b984251
RG
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")) {
f24465e5
RG
5334 if (domain == DNSName("com.")) {
5335 setLWResult(res, 0, true, false, true);
5336 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5337 addRRSIG(keys, res->d_records, domain, 300);
5338 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5339 addRRSIG(keys, res->d_records, domain, 300);
5340 }
5341 else {
5342 setLWResult(res, 0, false, false, true);
5343 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5344 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5345 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5346 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5347 }
2b984251
RG
5348 return 1;
5349 }
5350 else if (ip == ComboAddress("192.0.2.2:53")) {
5351 setLWResult(res, 0, true, false, true);
f24465e5
RG
5352 if (type == QType::NS) {
5353 if (domain == DNSName("powerdns.com.")) {
5354 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5355 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5356 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5357 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5358 }
5359 else {
5360 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5361 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5362 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5363 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5364 }
5365 }
5366 else {
5367 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5368 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
9b061cf5 5369 /* we need to add the proof that this name does not exist, so the wildcard may apply */
f24465e5
RG
5370 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5371 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5372 }
2b984251
RG
5373 return 1;
5374 }
5375 }
5376
5377 return 0;
5378 });
5379
5380 vector<DNSRecord> ret;
5381 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5382 BOOST_CHECK_EQUAL(res, RCode::NoError);
5383 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5384 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5385 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5386
5387 /* again, to test the cache */
5388 ret.clear();
5389 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5390 BOOST_CHECK_EQUAL(res, RCode::NoError);
5391 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5392 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5393 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5394}
5395
9b061cf5
RG
5396BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
5397 std::unique_ptr<SyncRes> sr;
5398 initSR(sr, true);
5399
5400 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5401
5402 primeHints();
5403 const DNSName target("www.com.");
5404 testkeysset_t keys;
5405
5406 auto luaconfsCopy = g_luaconfs.getCopy();
5407 luaconfsCopy.dsAnchors.clear();
5408 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5409 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5410
5411 g_luaconfs.setState(luaconfsCopy);
5412
5413 size_t queriesCount = 0;
5414
deca7d8f 5415 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9b061cf5
RG
5416 queriesCount++;
5417
5418 if (type == QType::DS || type == QType::DNSKEY) {
5419 if (type == QType::DS && domain == target) {
5420 DNSName auth("com.");
5421 setLWResult(res, 0, true, false, true);
5422
5423 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5424 addRRSIG(keys, res->d_records, auth, 300);
5425 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
5426 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
5427 addRRSIG(keys, res->d_records, auth, 300);
5428 return 1;
5429 }
5430 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5431 }
5432 else {
5433 if (isRootServer(ip)) {
5434 setLWResult(res, 0, false, false, true);
5435 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5436 addDS(DNSName("com."), 300, res->d_records, keys);
5437 addRRSIG(keys, res->d_records, DNSName("."), 300);
5438 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5439 return 1;
5440 }
5441 else if (ip == ComboAddress("192.0.2.1:53")) {
5442 setLWResult(res, 0, true, false, true);
5443 /* no data */
5444 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5445 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5446 /* no record for this name */
5447 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
5448 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5449 /* a wildcard matches but has no record for this type */
5450 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5451 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5452 return 1;
5453 }
5454 }
5455
5456 return 0;
5457 });
5458
5459 vector<DNSRecord> ret;
5460 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5461 BOOST_CHECK_EQUAL(res, RCode::NoError);
5462 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5463 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5464 BOOST_CHECK_EQUAL(queriesCount, 6);
5465
5466 /* again, to test the cache */
5467 ret.clear();
5468 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5469 BOOST_CHECK_EQUAL(res, RCode::NoError);
5470 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5471 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5472 BOOST_CHECK_EQUAL(queriesCount, 6);
5473}
5474
5475BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
5476 std::unique_ptr<SyncRes> sr;
5477 initSR(sr, true);
5478
5479 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5480
5481 primeHints();
5482 const DNSName target("www.com.");
5483 testkeysset_t keys;
5484
5485 auto luaconfsCopy = g_luaconfs.getCopy();
5486 luaconfsCopy.dsAnchors.clear();
5487 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5488 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5489
5490 g_luaconfs.setState(luaconfsCopy);
5491
5492 size_t queriesCount = 0;
5493
deca7d8f 5494 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9b061cf5
RG
5495 queriesCount++;
5496
5497 if (type == QType::DS || type == QType::DNSKEY) {
5498 if (type == QType::DS && domain == target) {
5499 DNSName auth("com.");
5500 setLWResult(res, 0, true, false, true);
5501
5502 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5503 addRRSIG(keys, res->d_records, auth, 300);
5504 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5505 /* first the closest encloser */
5506 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5507 addRRSIG(keys, res->d_records, auth, 300);
5508 /* then the next closer */
5509 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5510 addRRSIG(keys, res->d_records, auth, 300);
5511 /* a wildcard matches but has no record for this type */
5512 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5513 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5514 return 1;
5515 }
5516 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5517 }
5518 else {
5519 if (isRootServer(ip)) {
5520 setLWResult(res, 0, false, false, true);
5521 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5522 addDS(DNSName("com."), 300, res->d_records, keys);
5523 addRRSIG(keys, res->d_records, DNSName("."), 300);
5524 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5525 return 1;
5526 }
5527 else if (ip == ComboAddress("192.0.2.1:53")) {
5528 setLWResult(res, 0, true, false, true);
5529 /* no data */
5530 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5531 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5532 /* no record for this name */
5533 /* first the closest encloser */
5534 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5535 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5536 /* then the next closer */
5537 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5538 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5539 /* a wildcard matches but has no record for this type */
5540 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5541 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5542 return 1;
5543 }
5544 }
5545
5546 return 0;
5547 });
5548
5549 vector<DNSRecord> ret;
5550 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5551 BOOST_CHECK_EQUAL(res, RCode::NoError);
5552 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5553 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5554 BOOST_CHECK_EQUAL(queriesCount, 6);
5555
5556 /* again, to test the cache */
5557 ret.clear();
5558 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5559 BOOST_CHECK_EQUAL(res, RCode::NoError);
5560 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5561 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5562 BOOST_CHECK_EQUAL(queriesCount, 6);
5563}
5564
b7c40613
RG
5565BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5566 std::unique_ptr<SyncRes> sr;
5567 initSR(sr, true);
5568
5569 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5570
5571 primeHints();
5572 const DNSName target("www.com.");
5573 testkeysset_t keys;
5574
5575 auto luaconfsCopy = g_luaconfs.getCopy();
5576 luaconfsCopy.dsAnchors.clear();
5577 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5578 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5579
5580 g_luaconfs.setState(luaconfsCopy);
5581
5582 size_t queriesCount = 0;
5583
deca7d8f 5584 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7c40613
RG
5585 queriesCount++;
5586
5587 if (type == QType::DS || type == QType::DNSKEY) {
5588 if (type == QType::DS && domain == target) {
5589 DNSName auth("com.");
5590 setLWResult(res, 0, true, false, true);
5591
5592 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5593 addRRSIG(keys, res->d_records, auth, 300);
5594 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5595 /* first the closest encloser */
5596 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5597 addRRSIG(keys, res->d_records, auth, 300);
5598 /* then the next closer */
5599 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5600 addRRSIG(keys, res->d_records, auth, 300);
5601 /* a wildcard matches but has no record for this type */
5602 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5603 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5604 return 1;
5605 }
5606 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5607 }
5608 else {
5609 if (isRootServer(ip)) {
5610 setLWResult(res, 0, false, false, true);
5611 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5612 addDS(DNSName("com."), 300, res->d_records, keys);
5613 addRRSIG(keys, res->d_records, DNSName("."), 300);
5614 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5615 return 1;
5616 }
5617 else if (ip == ComboAddress("192.0.2.1:53")) {
5618 setLWResult(res, 0, true, false, true);
5619 /* no data */
5620 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5621 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5622 /* no record for this name */
5623 /* first the closest encloser */
5624 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5625 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5626 /* then the next closer */
5627 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5628 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5629 /* a wildcard matches but has no record for this type */
5630 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5631 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5632 return 1;
5633 }
5634 }
5635
5636 return 0;
5637 });
5638
5639 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5640 vector<DNSRecord> ret;
5641 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5642 BOOST_CHECK_EQUAL(res, RCode::NoError);
5643 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5644 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5645 BOOST_CHECK_EQUAL(queriesCount, 6);
5646
5647 /* again, to test the cache */
5648 ret.clear();
5649 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5650 BOOST_CHECK_EQUAL(res, RCode::NoError);
5651 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5652 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5653 BOOST_CHECK_EQUAL(queriesCount, 6);
5654}
5655
9b061cf5
RG
5656BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5657 std::unique_ptr<SyncRes> sr;
5658 initSR(sr, true);
5659
5660 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5661
5662 primeHints();
e4894ce0 5663 const DNSName target("www.sub.powerdns.com.");
9b061cf5
RG
5664 testkeysset_t keys;
5665
5666 auto luaconfsCopy = g_luaconfs.getCopy();
5667 luaconfsCopy.dsAnchors.clear();
5668 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5669 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5670 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5671
5672 g_luaconfs.setState(luaconfsCopy);
5673
5674 size_t queriesCount = 0;
5675
deca7d8f 5676 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9b061cf5
RG
5677 queriesCount++;
5678
5679 if (type == QType::DS || type == QType::DNSKEY) {
e4894ce0 5680 if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) {
9b061cf5
RG
5681 setLWResult(res, RCode::NoError, true, false, true);
5682 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5683 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
e4894ce0
RG
5684 if (domain == DNSName("sub.powerdns.com")) {
5685 addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5686 }
5687 else if (domain == target) {
5688 addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5689 }
9b061cf5
RG
5690 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5691 return 1;
5692 }
5693 else {
5694 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5695 }
5696 }
5697 else {
5698 if (isRootServer(ip)) {
5699 setLWResult(res, 0, false, false, true);
5700 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5701 addDS(DNSName("com."), 300, res->d_records, keys);
5702 addRRSIG(keys, res->d_records, DNSName("."), 300);
5703 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5704 return 1;
5705 }
5706 else if (ip == ComboAddress("192.0.2.1:53")) {
5707 if (domain == DNSName("com.")) {
5708 setLWResult(res, 0, true, false, true);
5709 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5710 addRRSIG(keys, res->d_records, domain, 300);
5711 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5712 addRRSIG(keys, res->d_records, domain, 300);
5713 }
5714 else {
5715 setLWResult(res, 0, false, false, true);
5716 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5717 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5718 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5719 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5720 }
5721 return 1;
5722 }
5723 else if (ip == ComboAddress("192.0.2.2:53")) {
5724 setLWResult(res, 0, true, false, true);
5725 if (type == QType::NS) {
5726 if (domain == DNSName("powerdns.com.")) {
5727 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5728 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5729 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5730 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5731 }
5732 else {
5733 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5734 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5735 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5736 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5737 }
5738 }
5739 else {
5740 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5741 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5742 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5743 /* first the closest encloser */
5744 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5745 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5746 /* then the next closer */
e4894ce0 5747 addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
9b061cf5
RG
5748 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5749 }
5750 return 1;
5751 }
5752 }
5753
5754 return 0;
5755 });
5756
5757 vector<DNSRecord> ret;
5758 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5759 BOOST_CHECK_EQUAL(res, RCode::NoError);
5760 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5761 BOOST_REQUIRE_EQUAL(ret.size(), 6);
e4894ce0 5762 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
5763
5764 /* again, to test the cache */
5765 ret.clear();
5766 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5767 BOOST_CHECK_EQUAL(res, RCode::NoError);
5768 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5769 BOOST_REQUIRE_EQUAL(ret.size(), 6);
e4894ce0 5770 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
5771}
5772
b7c40613
RG
5773BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5774 std::unique_ptr<SyncRes> sr;
5775 initSR(sr, true);
5776
5777 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5778
5779 primeHints();
5780 const DNSName target("www.powerdns.com.");
5781 testkeysset_t keys;
5782
5783 auto luaconfsCopy = g_luaconfs.getCopy();
5784 luaconfsCopy.dsAnchors.clear();
5785 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5786 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5787 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5788
5789 g_luaconfs.setState(luaconfsCopy);
5790
5791 size_t queriesCount = 0;
5792
deca7d8f 5793 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7c40613
RG
5794 queriesCount++;
5795
5796 if (type == QType::DS || type == QType::DNSKEY) {
5797 if (type == QType::DS && domain == target) {
5798 setLWResult(res, RCode::NoError, true, false, true);
5799 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5800 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5801 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5802 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5803 return 1;
5804 }
5805 else {
5806 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5807 }
5808 }
5809 else {
5810 if (isRootServer(ip)) {
5811 setLWResult(res, 0, false, false, true);
5812 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5813 addDS(DNSName("com."), 300, res->d_records, keys);
5814 addRRSIG(keys, res->d_records, DNSName("."), 300);
5815 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5816 return 1;
5817 }
5818 else if (ip == ComboAddress("192.0.2.1:53")) {
5819 if (domain == DNSName("com.")) {
5820 setLWResult(res, 0, true, false, true);
5821 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5822 addRRSIG(keys, res->d_records, domain, 300);
5823 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5824 addRRSIG(keys, res->d_records, domain, 300);
5825 }
5826 else {
5827 setLWResult(res, 0, false, false, true);
5828 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5829 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5830 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5831 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5832 }
5833 return 1;
5834 }
5835 else if (ip == ComboAddress("192.0.2.2:53")) {
5836 setLWResult(res, 0, true, false, true);
5837 if (type == QType::NS) {
5838 if (domain == DNSName("powerdns.com.")) {
5839 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5840 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5841 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5842 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5843 }
5844 else {
5845 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5846 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5847 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5848 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5849 }
5850 }
5851 else {
5852 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5853 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5854 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5855 /* first the closest encloser */
5856 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5857 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5858 /* then the next closer */
5859 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5860 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5861 }
5862 return 1;
5863 }
5864 }
5865
5866 return 0;
5867 });
5868
5869 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5870 we should end up Insecure */
5871 vector<DNSRecord> ret;
5872 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5873 BOOST_CHECK_EQUAL(res, RCode::NoError);
5874 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5875 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5876 BOOST_CHECK_EQUAL(queriesCount, 9);
5877
5878 /* again, to test the cache */
5879 ret.clear();
5880 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5881 BOOST_CHECK_EQUAL(res, RCode::NoError);
5882 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5883 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5884 BOOST_CHECK_EQUAL(queriesCount, 9);
5885}
5886
9b061cf5
RG
5887BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5888 std::unique_ptr<SyncRes> sr;
5889 initSR(sr, true);
5890
5891 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5892
5893 primeHints();
5894 const DNSName target("www.powerdns.com.");
5895 testkeysset_t keys;
5896
5897 auto luaconfsCopy = g_luaconfs.getCopy();
5898 luaconfsCopy.dsAnchors.clear();
5899 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5900 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5901 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5902
5903 g_luaconfs.setState(luaconfsCopy);
5904
5905 size_t queriesCount = 0;
5906
deca7d8f 5907 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
9b061cf5
RG
5908 queriesCount++;
5909
5910 if (type == QType::DS || type == QType::DNSKEY) {
5911 if (type == QType::DS && domain == target) {
5912 setLWResult(res, RCode::NoError, true, false, true);
5913 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5914 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5915 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5916 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5917 return 1;
5918 }
5919 else {
5920 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5921 }
5922 }
5923 else {
5924 if (isRootServer(ip)) {
5925 setLWResult(res, 0, false, false, true);
5926 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5927 addDS(DNSName("com."), 300, res->d_records, keys);
5928 addRRSIG(keys, res->d_records, DNSName("."), 300);
5929 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5930 return 1;
5931 }
5932 else if (ip == ComboAddress("192.0.2.1:53")) {
5933 if (domain == DNSName("com.")) {
5934 setLWResult(res, 0, true, false, true);
5935 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5936 addRRSIG(keys, res->d_records, domain, 300);
5937 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5938 addRRSIG(keys, res->d_records, domain, 300);
5939 }
5940 else {
5941 setLWResult(res, 0, false, false, true);
5942 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5943 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5944 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5945 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5946 }
5947 return 1;
5948 }
5949 else if (ip == ComboAddress("192.0.2.2:53")) {
5950 setLWResult(res, 0, true, false, true);
5951 if (type == QType::NS) {
5952 if (domain == DNSName("powerdns.com.")) {
5953 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5954 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5955 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5956 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5957 }
5958 else {
5959 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5960 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5961 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5962 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5963 }
5964 }
5965 else {
5966 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5967 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5968 }
5969 return 1;
5970 }
5971 }
5972
5973 return 0;
5974 });
5975
5976 vector<DNSRecord> ret;
5977 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5978 BOOST_CHECK_EQUAL(res, RCode::NoError);
5979 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5980 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5981 BOOST_CHECK_EQUAL(queriesCount, 9);
5982
5983 /* again, to test the cache */
5984 ret.clear();
5985 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5986 BOOST_CHECK_EQUAL(res, RCode::NoError);
5987 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5988 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5989 BOOST_CHECK_EQUAL(queriesCount, 9);
5990}
5991
a53e8fe3
RG
5992BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5993 std::unique_ptr<SyncRes> sr;
5994 initSR(sr, true);
5995
0c43f455 5996 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
5997
5998 primeHints();
5999 const DNSName target("www.powerdns.com.");
6000 testkeysset_t keys;
6001
6002 auto luaconfsCopy = g_luaconfs.getCopy();
6003 luaconfsCopy.dsAnchors.clear();
6004 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6005 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6006 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6007
6008 g_luaconfs.setState(luaconfsCopy);
6009
6010 size_t queriesCount = 0;
6011 size_t dsQueriesCount = 0;
6012
deca7d8f 6013 sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
a53e8fe3
RG
6014 queriesCount++;
6015
6016 if (type == QType::DS) {
6017 DNSName auth(domain);
6018 auth.chopOff();
6019 dsQueriesCount++;
6020
6021 setLWResult(res, 0, true, false, true);
6022 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6023 addRRSIG(keys, res->d_records, auth, 300);
6024 return 1;
6025 }
6026 else if (type == QType::DNSKEY) {
6027 setLWResult(res, 0, true, false, true);
6028 addDNSKEY(keys, domain, 300, res->d_records);
6029 addRRSIG(keys, res->d_records, domain, 300);
6030 return 1;
6031 }
f24465e5 6032 else {
a53e8fe3
RG
6033 if (isRootServer(ip)) {
6034 setLWResult(res, 0, false, false, true);
6035 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6036 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6037 /* No DS on referral, and no denial of the DS either */
6038 return 1;
6039 }
6040 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
6041 if (domain == DNSName("com.")) {
6042 setLWResult(res, 0, true, false, true);
6043 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6044 addRRSIG(keys, res->d_records, domain, 300);
6045 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6046 addRRSIG(keys, res->d_records, domain, 300);
6047 }
6048 else {
6049 setLWResult(res, 0, false, false, true);
6050 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6051 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6052 /* No DS on referral, and no denial of the DS either */
6053 }
a53e8fe3
RG
6054 return 1;
6055 }
6056 else if (ip == ComboAddress("192.0.2.2:53")) {
6057 setLWResult(res, 0, true, false, true);
f24465e5
RG
6058 if (type == QType::NS) {
6059 if (domain == DNSName("powerdns.com.")) {
6060 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6061 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6062 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6063 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6064 }
6065 else {
6066 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6067 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6068 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
6069 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6070 }
6071 }
6072 else {
6073 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6074 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6075 }
6076
a53e8fe3
RG
6077 return 1;
6078 }
6079 }
6080
6081 return 0;
6082 });
6083
6084 vector<DNSRecord> ret;
6085 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6086 BOOST_CHECK_EQUAL(res, RCode::NoError);
6087 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 6088 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
6089 BOOST_CHECK_EQUAL(queriesCount, 9);
6090 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
6091
6092 /* again, to test the cache */
6093 ret.clear();
6094 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6095 BOOST_CHECK_EQUAL(res, RCode::NoError);
6096 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 6097 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
6098 BOOST_CHECK_EQUAL(queriesCount, 9);
6099 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
6100}
6101
f715542c
RG
6102BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
6103 std::unique_ptr<SyncRes> sr;
6104 initSR(sr, true);
6105
5d7b19c5 6106 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
f715542c
RG
6107
6108 primeHints();
6109 const DNSName target("www.powerdns.com.");
6110 testkeysset_t keys;
6111
6112 auto luaconfsCopy = g_luaconfs.getCopy();
6113 luaconfsCopy.dsAnchors.clear();
6114 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6115 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3cef03e9 6116 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
f715542c
RG
6117 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6118
6119 g_luaconfs.setState(luaconfsCopy);
6120
6121 size_t queriesCount = 0;
6122
deca7d8f 6123 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f715542c
RG
6124 queriesCount++;
6125
6126 if (type == QType::DS) {
6127 DNSName auth(domain);
6128 auth.chopOff();
6129
6130 setLWResult(res, 0, true, false, true);
6131 if (domain == target) {
6132 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6133 addRRSIG(keys, res->d_records, target, 300);
6134 }
6135 else {
6136 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6137 addRRSIG(keys, res->d_records, auth, 300);
6138 }
6139 return 1;
6140 }
6141 else if (type == QType::DNSKEY) {
6142 setLWResult(res, 0, true, false, true);
6143 addDNSKEY(keys, domain, 300, res->d_records);
6144 addRRSIG(keys, res->d_records, domain, 300);
6145 return 1;
6146 }
6147 else {
6148 if (isRootServer(ip)) {
6149 setLWResult(res, 0, false, false, true);
6150 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6151 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6152 addDS(DNSName("com."), 300, res->d_records, keys);
6153 addRRSIG(keys, res->d_records, DNSName("."), 300);
6154 return 1;
6155 }
6156 else if (ip == ComboAddress("192.0.2.1:53")) {
6157 if (domain == DNSName("com.")) {
6158 setLWResult(res, 0, true, false, true);
6159 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6160 addRRSIG(keys, res->d_records, domain, 300);
6161 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6162 addRRSIG(keys, res->d_records, domain, 300);
6163 }
6164 else {
6165 setLWResult(res, 0, false, false, true);
6166 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6167 /* no DS */
6168 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6169 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6170 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6171 }
6172 return 1;
6173 }
6174 else if (ip == ComboAddress("192.0.2.2:53")) {
6175 if (type == QType::NS) {
6176 if (domain == DNSName("powerdns.com.")) {
6177 setLWResult(res, RCode::Refused, false, false, true);
6178 }
6179 else {
6180 setLWResult(res, 0, true, false, true);
6181 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6182 addRRSIG(keys, res->d_records, domain, 300);
6183 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6184 addRRSIG(keys, res->d_records, domain, 300);
6185 }
6186 }
6187 else {
6188 setLWResult(res, 0, true, false, true);
6189 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6190 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
6191 }
6192
6193 return 1;
6194 }
6195 }
6196
6197 return 0;
6198 });
6199
6200 vector<DNSRecord> ret;
6201 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6202 BOOST_CHECK_EQUAL(res, RCode::NoError);
6203 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6204 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6205 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6206
6207 /* again, to test the cache */
6208 ret.clear();
6209 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6210 BOOST_CHECK_EQUAL(res, RCode::NoError);
6211 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6212 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6213 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6214}
6215
8d2e7fa1
RG
6216BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) {
6217 /* check that we don't accept a signer below us */
6218 std::unique_ptr<SyncRes> sr;
6219 initSR(sr, true);
6220
6221 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6222
6223 primeHints();
6224 const DNSName target("www.powerdns.com.");
6225 testkeysset_t keys;
6226
6227 auto luaconfsCopy = g_luaconfs.getCopy();
6228 luaconfsCopy.dsAnchors.clear();
6229 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6230 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6231 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6232 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6233 generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6234
6235 g_luaconfs.setState(luaconfsCopy);
6236
6237 size_t queriesCount = 0;
6238
deca7d8f 6239 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8d2e7fa1
RG
6240 queriesCount++;
6241
6242 if (type == QType::DS) {
6243 DNSName auth(domain);
6244 auth.chopOff();
6245
6246 setLWResult(res, 0, true, false, true);
6247 if (domain == target) {
6248 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6249 addRRSIG(keys, res->d_records, target, 300);
6250 }
6251 else {
6252 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6253 addRRSIG(keys, res->d_records, auth, 300);
6254 }
6255 return 1;
6256 }
6257 else if (type == QType::DNSKEY) {
6258 setLWResult(res, 0, true, false, true);
6259 addDNSKEY(keys, domain, 300, res->d_records);
6260 if (domain == DNSName("www.powerdns.com.")) {
6261 addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
6262 }
6263 else {
6264 addRRSIG(keys, res->d_records, domain, 300);
6265 }
6266 return 1;
6267 }
6268 else {
6269 if (isRootServer(ip)) {
6270 setLWResult(res, 0, false, false, true);
6271 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6272 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6273 addDS(DNSName("com."), 300, res->d_records, keys);
6274 addRRSIG(keys, res->d_records, DNSName("."), 300);
6275 return 1;
6276 }
6277 else if (ip == ComboAddress("192.0.2.1:53")) {
6278 if (domain == DNSName("com.")) {
6279 setLWResult(res, 0, true, false, true);
6280 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6281 addRRSIG(keys, res->d_records, domain, 300);
6282 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6283 addRRSIG(keys, res->d_records, domain, 300);
6284 }
6285 else {
6286 setLWResult(res, 0, false, false, true);
6287 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6288 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6289 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6290 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6291 }
6292 return 1;
6293 }
6294 else if (ip == ComboAddress("192.0.2.2:53")) {
6295 if (type == QType::NS) {
6296 setLWResult(res, 0, true, false, true);
6297 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6298 addRRSIG(keys, res->d_records, domain, 300);
6299 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6300 addRRSIG(keys, res->d_records, domain, 300);
6301 }
6302 else {
6303 setLWResult(res, 0, true, false, true);
6304 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6305 addRRSIG(keys, res->d_records, domain, 300);
6306 }
6307
6308 return 1;
6309 }
6310 }
6311
f715542c
RG
6312 return 0;
6313 });
6314
6315 vector<DNSRecord> ret;
6316 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6317 BOOST_CHECK_EQUAL(res, RCode::NoError);
6318 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6319 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6320 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6321
6322 /* again, to test the cache */
6323 ret.clear();
6324 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6325 BOOST_CHECK_EQUAL(res, RCode::NoError);
6326 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6327 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6328 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6329}
6330
a53e8fe3
RG
6331BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
6332 std::unique_ptr<SyncRes> sr;
f24465e5 6333 initSR(sr, true);
a53e8fe3 6334
0c43f455 6335 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
6336
6337 primeHints();
6338 const DNSName target("www.powerdns.com.");
6339 testkeysset_t keys;
6340
6341 auto luaconfsCopy = g_luaconfs.getCopy();
6342 luaconfsCopy.dsAnchors.clear();
6343 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6344 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6345
6346 g_luaconfs.setState(luaconfsCopy);
6347
6348 size_t queriesCount = 0;
6349 size_t dsQueriesCount = 0;
6350
deca7d8f 6351 sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
a53e8fe3
RG
6352 queriesCount++;
6353
6354 if (type == QType::DS) {
6355 DNSName auth(domain);
6356 auth.chopOff();
6357 dsQueriesCount++;
6358
6359 setLWResult(res, 0, true, false, true);
6360 if (domain == DNSName("com.")) {
6361 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6362 }
6363 else {
f24465e5
RG
6364 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6365 addRRSIG(keys, res->d_records, DNSName("com."), 300);
a53e8fe3
RG
6366 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
6367 }
6368 addRRSIG(keys, res->d_records, auth, 300);
6369 return 1;
6370 }
6371 else if (type == QType::DNSKEY) {
6372 setLWResult(res, 0, true, false, true);
6373 addDNSKEY(keys, domain, 300, res->d_records);
6374 addRRSIG(keys, res->d_records, domain, 300);
6375 return 1;
6376 }
a69867f2 6377 else {
a53e8fe3
RG
6378 if (isRootServer(ip)) {
6379 setLWResult(res, 0, false, false, true);
6380 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6381 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6382 /* No DS on referral, and no denial of the DS either */
6383 return 1;
6384 }
6385 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6386 if (domain == DNSName("com.")) {
6387 setLWResult(res, 0, true, false, true);
6388 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
f24465e5 6389 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 6390 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
f24465e5 6391 addRRSIG(keys, res->d_records, domain, 300);
a69867f2
RG
6392 }
6393 else {
6394 setLWResult(res, 0, false, false, true);
6395 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6396 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6397 /* No DS on referral, and no denial of the DS either */
6398 }
a53e8fe3
RG
6399 return 1;
6400 }
6401 else if (ip == ComboAddress("192.0.2.2:53")) {
6402 setLWResult(res, 0, true, false, true);
f24465e5
RG
6403 if (type == QType::NS) {
6404 if (domain == DNSName("powerdns.com.")) {
6405 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6406 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6407 }
6408 else {
6409 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6410 }
6411 }
6412 else {
6413 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6414 }
a53e8fe3
RG
6415 return 1;
6416 }
6417 }
6418
6419 return 0;
6420 });
6421
6422 vector<DNSRecord> ret;
6423 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6424 BOOST_CHECK_EQUAL(res, RCode::NoError);
6425 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6426 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6427 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6428 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6429
6430 /* again, to test the cache */
6431 ret.clear();
6432 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6433 BOOST_CHECK_EQUAL(res, RCode::NoError);
6434 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6435 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6436 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6437 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6438}
6439
e59c8907 6440BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
b7f378d1 6441 std::unique_ptr<SyncRes> sr;
895449a5 6442 initSR(sr, true);
b7f378d1 6443
0c43f455 6444 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6445
6446 primeHints();
6447 const DNSName target("powerdns.com.");
6448 testkeysset_t keys;
6449
6450 auto luaconfsCopy = g_luaconfs.getCopy();
6451 luaconfsCopy.dsAnchors.clear();
6452 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6453 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6454 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6455
6456 g_luaconfs.setState(luaconfsCopy);
6457
6458 size_t queriesCount = 0;
6459
deca7d8f 6460 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7f378d1
RG
6461 queriesCount++;
6462
5374b03b
RG
6463 if (type == QType::DS || type == QType::DNSKEY) {
6464 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6465 }
a69867f2 6466 else {
b7f378d1
RG
6467 if (isRootServer(ip)) {
6468 setLWResult(res, 0, false, false, true);
6469 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6470 addDS(DNSName("com."), 300, res->d_records, keys);
6471 addRRSIG(keys, res->d_records, DNSName("."), 300);
6472 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6473 return 1;
6474 }
6475 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6476 if (domain == DNSName("com.")) {
6477 setLWResult(res, 0, true, false, true);
6478 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6479 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6480 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6481 }
6482 else {
6483 setLWResult(res, 0, false, false, true);
6484 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6485 addDS(domain, 300, res->d_records, keys);
6486 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6487 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6488 }
b7f378d1
RG
6489 return 1;
6490 }
6491 else if (ip == ComboAddress("192.0.2.2:53")) {
6492 setLWResult(res, 0, true, false, true);
a69867f2
RG
6493 if (type == QType::NS) {
6494 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6495 addRRSIG(keys, res->d_records, domain, 300);
6496 }
6497 else {
6498 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6499 addRRSIG(keys, res->d_records, domain, 300);
6500 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
6501 /* NO RRSIG for the NSEC record! */
6502 }
b7f378d1
RG
6503 return 1;
6504 }
6505 }
6506
6507 return 0;
6508 });
6509
6510 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
6511 vector<DNSRecord> ret;
6512 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6513 BOOST_CHECK_EQUAL(res, RCode::NoError);
6514 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6515 BOOST_CHECK_EQUAL(ret.size(), 3);
a69867f2 6516 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6517
6518 /* again, to test the cache */
6519 ret.clear();
6520 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6521 BOOST_CHECK_EQUAL(res, RCode::NoError);
6522 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6523 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 6524 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6525}
6526
e59c8907 6527BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
b7f378d1 6528 std::unique_ptr<SyncRes> sr;
895449a5 6529 initSR(sr, true);
b7f378d1 6530
0c43f455 6531 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6532
6533 primeHints();
6534 const DNSName target("powerdns.com.");
6535 testkeysset_t keys;
6536
6537 auto luaconfsCopy = g_luaconfs.getCopy();
6538 luaconfsCopy.dsAnchors.clear();
6539 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6540 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6541 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6542
6543 g_luaconfs.setState(luaconfsCopy);
6544
6545 size_t queriesCount = 0;
6546
deca7d8f 6547 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7f378d1
RG
6548 queriesCount++;
6549
5374b03b
RG
6550 if (type == QType::DS || type == QType::DNSKEY) {
6551 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6552 }
a69867f2 6553 else {
b7f378d1
RG
6554 if (isRootServer(ip)) {
6555 setLWResult(res, 0, false, false, true);
6556 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6557 addDS(DNSName("com."), 300, res->d_records, keys);
6558 addRRSIG(keys, res->d_records, DNSName("."), 300);
6559 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6560 return 1;
6561 }
6562 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6563 if (domain == DNSName("com.")) {
6564 setLWResult(res, 0, true, false, true);
6565 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6566 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6567 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6568 }
6569 else {
6570 setLWResult(res, 0, false, false, true);
6571 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6572 addDS(domain, 300, res->d_records, keys);
6573 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6574 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6575 }
b7f378d1
RG
6576 return 1;
6577 }
6578 else if (ip == ComboAddress("192.0.2.2:53")) {
6579 setLWResult(res, 0, true, false, true);
a69867f2
RG
6580 if (type == QType::NS) {
6581 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6582 addRRSIG(keys, res->d_records, domain, 300);
6583 }
6584 else {
6585 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6586 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 6587
a69867f2
RG
6588 /* NO NSEC record! */
6589 }
b7f378d1
RG
6590 return 1;
6591 }
6592 }
6593
6594 return 0;
6595 });
6596
6597 /* no NSEC record in a secure zone, should be Bogus! */
6598 vector<DNSRecord> ret;
6599 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6600 BOOST_CHECK_EQUAL(res, RCode::NoError);
6601 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6602 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 6603 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6604
6605 /* again, to test the cache */
6606 ret.clear();
6607 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6608 BOOST_CHECK_EQUAL(res, RCode::NoError);
6609 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6610 BOOST_REQUIRE_EQUAL(ret.size(), 2);
a69867f2 6611 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6612}
6613
6614BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6615 std::unique_ptr<SyncRes> sr;
895449a5 6616 initSR(sr, true);
b7f378d1 6617
0c43f455 6618 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6619
6620 primeHints();
6621 const DNSName target("powerdns.com.");
6622 const ComboAddress targetAddr("192.0.2.42");
6623 testkeysset_t keys;
6624
6625 auto luaconfsCopy = g_luaconfs.getCopy();
6626 luaconfsCopy.dsAnchors.clear();
6627 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6628 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6629
6630 g_luaconfs.setState(luaconfsCopy);
6631
6632 size_t queriesCount = 0;
6633
deca7d8f 6634 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7f378d1
RG
6635 queriesCount++;
6636
6637 if (type == QType::DS) {
a53e8fe3 6638 if (domain == target) {
b7f378d1 6639 setLWResult(res, 0, false, false, true);
895449a5 6640 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6641 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6642 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6643 return 1;
5374b03b
RG
6644 } else {
6645 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1
RG
6646 }
6647 }
6648 else if (type == QType::DNSKEY) {
6649 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6650 setLWResult(res, 0, true, false, true);
6651 addDNSKEY(keys, domain, 300, res->d_records);
6652 addRRSIG(keys, res->d_records, domain, 300);
6653 return 1;
6654 }
6655 else {
6656 setLWResult(res, 0, false, false, true);
895449a5 6657 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6658 return 1;
6659 }
6660 }
a69867f2 6661 else {
b7f378d1
RG
6662 if (isRootServer(ip)) {
6663 setLWResult(res, 0, false, false, true);
6664 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6665 addDS(DNSName("com."), 300, res->d_records, keys);
6666 addRRSIG(keys, res->d_records, DNSName("."), 300);
6667 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6668 return 1;
6669 }
6670 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6671 if (domain == DNSName("com.")) {
6672 setLWResult(res, 0, true, false, true);
6673 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6674 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6675 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6676 }
6677 else {
6678 setLWResult(res, 0, false, false, true);
6679 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6680 /* no DS */
6681 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6682 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6683 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6684 }
b7f378d1
RG
6685 return 1;
6686 }
6687 else if (ip == ComboAddress("192.0.2.2:53")) {
6688 setLWResult(res, 0, true, false, true);
a69867f2
RG
6689 if (type == QType::NS) {
6690 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6691 }
6692 else {
6693 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6694 }
b7f378d1
RG
6695 return 1;
6696 }
6697 }
6698
6699 return 0;
6700 });
6701
6702 vector<DNSRecord> ret;
6703 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6704 BOOST_CHECK_EQUAL(res, RCode::NoError);
6705 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6706 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6707 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2
RG
6708 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6709 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6710 1 query for A */
6711 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6712
6713 /* again, to test the cache */
6714 ret.clear();
6715 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6716 BOOST_CHECK_EQUAL(res, RCode::NoError);
6717 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6718 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6719 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2 6720 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6721}
6722
3cef03e9
RG
6723
6724BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6725 /*
6726 Direct DS query:
6727 - parent is secure, zone is secure: DS should be secure
6728 */
6729 std::unique_ptr<SyncRes> sr;
6730 initSR(sr, true);
6731
6732 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6733
6734 primeHints();
6735 const DNSName target("powerdns.com.");
6736 testkeysset_t keys;
6737
6738 auto luaconfsCopy = g_luaconfs.getCopy();
6739 luaconfsCopy.dsAnchors.clear();
6740 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6741 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6742 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6743
6744 g_luaconfs.setState(luaconfsCopy);
6745
6746 size_t queriesCount = 0;
6747
deca7d8f 6748 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3cef03e9
RG
6749 queriesCount++;
6750
6751 if (type == QType::DS || type == QType::DNSKEY) {
6752 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6753 }
6754 else {
6755 if (isRootServer(ip)) {
6756 setLWResult(res, 0, false, false, true);
6757 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6758 addDS(DNSName("com."), 300, res->d_records, keys);
6759 addRRSIG(keys, res->d_records, DNSName("."), 300);
6760 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6761 return 1;
6762 }
6763 }
6764
6765 return 0;
6766 });
6767
6768 vector<DNSRecord> ret;
6769 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6770 BOOST_CHECK_EQUAL(res, RCode::NoError);
6771 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6772 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6773 for (const auto& record : ret) {
6774 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6775 }
6776 BOOST_CHECK_EQUAL(queriesCount, 4);
6777
6778 /* again, to test the cache */
6779 ret.clear();
6780 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6781 BOOST_CHECK_EQUAL(res, RCode::NoError);
6782 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6783 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6784 for (const auto& record : ret) {
6785 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6786 }
6787 BOOST_CHECK_EQUAL(queriesCount, 4);
6788}
6789
6790BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6791 /*
6792 Direct DS query:
6793 - parent is secure, zone is insecure: DS denial should be secure
6794 */
6795 std::unique_ptr<SyncRes> sr;
6796 initSR(sr, true);
6797
6798 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6799
6800 primeHints();
6801 const DNSName target("powerdns.com.");
6802 testkeysset_t keys;
6803
6804 auto luaconfsCopy = g_luaconfs.getCopy();
6805 luaconfsCopy.dsAnchors.clear();
6806 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6807 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6808
6809 g_luaconfs.setState(luaconfsCopy);
6810
6811 size_t queriesCount = 0;
6812
deca7d8f 6813 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3cef03e9
RG
6814 queriesCount++;
6815
6816 if (type == QType::DS || type == QType::DNSKEY) {
6817 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6818 }
6819 else {
6820 if (isRootServer(ip)) {
6821 setLWResult(res, 0, false, false, true);
6822 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6823 addDS(DNSName("com."), 300, res->d_records, keys);
6824 addRRSIG(keys, res->d_records, DNSName("."), 300);
6825 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6826 return 1;
6827 }
6828 }
6829
6830 return 0;
6831 });
6832
6833 vector<DNSRecord> ret;
6834 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6835 BOOST_CHECK_EQUAL(res, RCode::NoError);
6836 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6837 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6838 for (const auto& record : ret) {
6839 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6840 }
6841 BOOST_CHECK_EQUAL(queriesCount, 4);
6842
6843 /* again, to test the cache */
6844 ret.clear();
6845 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6846 BOOST_CHECK_EQUAL(res, RCode::NoError);
6847 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6848 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6849 for (const auto& record : ret) {
6850 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6851 }
6852 BOOST_CHECK_EQUAL(queriesCount, 4);
6853}
6854
70b3fe7a
RG
6855BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6856 std::unique_ptr<SyncRes> sr;
a69867f2 6857 initSR(sr, true);
70b3fe7a 6858
0c43f455 6859 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6860
6861 primeHints();
6862 const DNSName target("www.sub.powerdns.com.");
6863 const ComboAddress targetAddr("192.0.2.42");
6864 testkeysset_t keys;
6865
6866 auto luaconfsCopy = g_luaconfs.getCopy();
6867 luaconfsCopy.dsAnchors.clear();
6868 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6869 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6870 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6871
6872 g_luaconfs.setState(luaconfsCopy);
6873
6874 size_t queriesCount = 0;
6875
deca7d8f 6876 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
70b3fe7a
RG
6877 queriesCount++;
6878
6879 if (type == QType::DS) {
6880 if (domain == DNSName("sub.powerdns.com.")) {
6881 setLWResult(res, 0, false, false, true);
6882 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6883 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6884 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6885 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6886 return 1;
6887 }
6888 else if (domain == DNSName("www.sub.powerdns.com.")) {
6889 setLWResult(res, 0, false, false, true);
6890 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);
6891 return 1;
6892 }
5374b03b
RG
6893 else {
6894 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6895 }
70b3fe7a
RG
6896 }
6897 else if (type == QType::DNSKEY) {
a69867f2 6898 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
70b3fe7a
RG
6899 setLWResult(res, 0, true, false, true);
6900 addDNSKEY(keys, domain, 300, res->d_records);
6901 addRRSIG(keys, res->d_records, domain, 300);
6902 return 1;
6903 }
6904 else {
6905 setLWResult(res, 0, false, false, true);
6906 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6907 return 1;
6908 }
6909 }
88cb0fe0 6910 else {
70b3fe7a
RG
6911 if (isRootServer(ip)) {
6912 setLWResult(res, 0, false, false, true);
6913 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6914 addDS(DNSName("com."), 300, res->d_records, keys);
6915 addRRSIG(keys, res->d_records, DNSName("."), 300);
6916 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6917 return 1;
6918 }
6919 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6920 if (domain == DNSName("com.")) {
6921 setLWResult(res, 0, true, false, true);
6922 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6923 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6924 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6925 }
6926 else {
6927 setLWResult(res, 0, false, false, true);
6928 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6929 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6930 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6931 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6932 }
70b3fe7a
RG
6933 return 1;
6934 }
6935 else if (ip == ComboAddress("192.0.2.2:53")) {
6936 setLWResult(res, 0, true, false, true);
a69867f2
RG
6937 if (type == QType::NS) {
6938 if (domain == DNSName("www.sub.powerdns.com.")) {
6939 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);
6940 }
6941 else if (domain == DNSName("sub.powerdns.com.")) {
6942 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
a69867f2
RG
6943 }
6944 else if (domain == DNSName("powerdns.com.")) {
6945 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6946 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6947 }
6948 } else {
6949 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6950 }
70b3fe7a
RG
6951 return 1;
6952 }
6953 }
6954
6955 return 0;
6956 });
6957
6958 vector<DNSRecord> ret;
6959 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6960 BOOST_CHECK_EQUAL(res, RCode::NoError);
6961 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6962 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6963 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6964 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6965
6966 /* again, to test the cache */
6967 ret.clear();
6968 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6969 BOOST_CHECK_EQUAL(res, RCode::NoError);
6970 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6971 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6972 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6973 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6974}
6975
6976BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6977 std::unique_ptr<SyncRes> sr;
a69867f2 6978 initSR(sr, true);
70b3fe7a 6979
0c43f455 6980 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6981
6982 primeHints();
6983 const DNSName target("www.sub.powerdns.com.");
6984 const ComboAddress targetAddr("192.0.2.42");
6985 testkeysset_t keys;
6986
6987 auto luaconfsCopy = g_luaconfs.getCopy();
6988 luaconfsCopy.dsAnchors.clear();
6989 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6990 /* No key material for .com */
6991 /* But TA for sub.powerdns.com. */
6992 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6993 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6994 g_luaconfs.setState(luaconfsCopy);
6995
6996 size_t queriesCount = 0;
6997
deca7d8f 6998 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
70b3fe7a
RG
6999 queriesCount++;
7000
7001 if (type == QType::DS) {
88cb0fe0
RG
7002 if (domain == DNSName("www.sub.powerdns.com")) {
7003 setLWResult(res, 0, false, false, true);
7004 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);
7005 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7006 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
7007 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7008 }
7009 else {
7010 setLWResult(res, 0, false, false, true);
5374b03b
RG
7011
7012 if (domain == DNSName("com.")) {
7013 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7014 /* no DS */
7015 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
7016 addRRSIG(keys, res->d_records, DNSName("."), 300);
7017 }
7018 else {
7019 setLWResult(res, 0, false, false, true);
7020 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7021 }
88cb0fe0 7022 }
70b3fe7a
RG
7023 return 1;
7024 }
7025 else if (type == QType::DNSKEY) {
7026 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
7027 setLWResult(res, 0, true, false, true);
7028 addDNSKEY(keys, domain, 300, res->d_records);
7029 addRRSIG(keys, res->d_records, domain, 300);
7030 return 1;
7031 }
7032 }
88cb0fe0 7033 else {
70b3fe7a
RG
7034 if (isRootServer(ip)) {
7035 setLWResult(res, 0, false, false, true);
7036 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7037 /* no DS */
7038 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
7039 addRRSIG(keys, res->d_records, DNSName("."), 300);
7040 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7041 return 1;
7042 }
7043 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7044 if (domain == DNSName("com.")) {
7045 setLWResult(res, 0, true, false, true);
7046 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
7047 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7048 }
5374b03b 7049 else if (domain.isPartOf(DNSName("powerdns.com."))) {
88cb0fe0
RG
7050 setLWResult(res, 0, false, false, true);
7051 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7052 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7053 }
70b3fe7a
RG
7054 return 1;
7055 }
7056 else if (ip == ComboAddress("192.0.2.2:53")) {
7057 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7058 if (type == QType::NS) {
7059 if (domain == DNSName("www.sub.powerdns.com.")) {
7060 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);
7061 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7062 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
7063 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7064 }
7065 else if (domain == DNSName("sub.powerdns.com.")) {
7066 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7067 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
7068 }
7069 else if (domain == DNSName("powerdns.com.")) {
7070 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7071 }
7072 }
7073 else if (domain == DNSName("www.sub.powerdns.com.")) {
7074 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7075 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
7076 }
70b3fe7a
RG
7077 return 1;
7078 }
7079 }
7080
7081 return 0;
7082 });
7083
7084 vector<DNSRecord> ret;
7085 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7086 BOOST_CHECK_EQUAL(res, RCode::NoError);
7087 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 7088 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 7089 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7090 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
7091
7092 /* again, to test the cache */
7093 ret.clear();
7094 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7095 BOOST_CHECK_EQUAL(res, RCode::NoError);
7096 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 7097 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 7098 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7099 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
7100}
7101
b7f378d1
RG
7102BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
7103 std::unique_ptr<SyncRes> sr;
895449a5 7104 initSR(sr, true);
b7f378d1 7105
0c43f455 7106 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
7107
7108 primeHints();
7109 const DNSName target("powerdns.com.");
7110 testkeysset_t keys;
7111
7112 auto luaconfsCopy = g_luaconfs.getCopy();
7113 luaconfsCopy.dsAnchors.clear();
7114 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7115 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7116
7117 g_luaconfs.setState(luaconfsCopy);
7118
7119 size_t queriesCount = 0;
7120
deca7d8f 7121 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7f378d1
RG
7122 queriesCount++;
7123
7124 if (type == QType::DS) {
a53e8fe3 7125 if (domain == target) {
b7f378d1 7126 setLWResult(res, 0, false, false, true);
895449a5 7127 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
7128 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7129 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7130 return 1;
7131 }
5374b03b
RG
7132 else {
7133 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7134 }
b7f378d1
RG
7135 }
7136 else if (type == QType::DNSKEY) {
7137 if (domain == g_rootdnsname || domain == DNSName("com.")) {
7138 setLWResult(res, 0, true, false, true);
7139 addDNSKEY(keys, domain, 300, res->d_records);
7140 addRRSIG(keys, res->d_records, domain, 300);
7141 return 1;
7142 }
7143 else {
7144 setLWResult(res, 0, false, false, true);
895449a5 7145 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
7146 return 1;
7147 }
7148 }
a69867f2 7149 else {
b7f378d1
RG
7150 if (isRootServer(ip)) {
7151 setLWResult(res, 0, false, false, true);
7152 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7153 addDS(DNSName("com."), 300, res->d_records, keys);
7154 addRRSIG(keys, res->d_records, DNSName("."), 300);
7155 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7156 return 1;
7157 }
7158 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7159 if (domain == DNSName("com.")) {
7160 setLWResult(res, 0, true, false, true);
7161 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7162 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7163 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7164 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7165 }
7166 else {
7167 setLWResult(res, 0, false, false, true);
7168 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7169 /* no DS */
7170 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7171 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7172 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7173 }
b7f378d1
RG
7174 return 1;
7175 }
7176 else if (ip == ComboAddress("192.0.2.2:53")) {
a69867f2
RG
7177 if (type == QType::NS) {
7178 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7179 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7180 }
7181 else {
7182 setLWResult(res, 0, true, false, true);
7183 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7184 }
b7f378d1
RG
7185 return 1;
7186 }
7187 }
7188
7189 return 0;
7190 });
7191
7192 vector<DNSRecord> ret;
7193 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7194 BOOST_CHECK_EQUAL(res, RCode::NoError);
7195 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7196 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2
RG
7197 /* 4 NS (com from root, com from com, powerdns.com from com,
7198 powerdns.com from powerdns.com)
7199 2 DNSKEY (. and com., none for powerdns.com because no DS)
7200 1 query for A
7201 */
7202 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7203
7204 /* again, to test the cache */
7205 ret.clear();
7206 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7207 BOOST_CHECK_EQUAL(res, RCode::NoError);
7208 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7209 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2 7210 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7211}
7212
895449a5 7213BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
b7f378d1 7214 std::unique_ptr<SyncRes> sr;
860d5e8e 7215 initSR(sr, true);
b7f378d1 7216
0c43f455 7217 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1 7218
895449a5
RG
7219 primeHints();
7220 const DNSName target("powerdns.com.");
7221 const DNSName targetCName("power-dns.com.");
7222 const ComboAddress targetCNameAddr("192.0.2.42");
7223 testkeysset_t keys;
7224
7225 auto luaconfsCopy = g_luaconfs.getCopy();
7226 luaconfsCopy.dsAnchors.clear();
7227 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7228 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7229 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7230 g_luaconfs.setState(luaconfsCopy);
7231
7232 size_t queriesCount = 0;
7233
deca7d8f 7234 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
895449a5
RG
7235 queriesCount++;
7236
7237 if (type == QType::DS) {
5374b03b 7238 if (domain == targetCName) {
895449a5
RG
7239 setLWResult(res, 0, false, false, true);
7240 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7241 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7242 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7243 return 1;
7244 }
5374b03b
RG
7245 else {
7246 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7247 }
895449a5
RG
7248 }
7249 else if (type == QType::DNSKEY) {
7250 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7251 setLWResult(res, 0, true, false, true);
7252 addDNSKEY(keys, domain, 300, res->d_records);
7253 addRRSIG(keys, res->d_records, domain, 300);
7254 return 1;
7255 }
7256 else {
7257 setLWResult(res, 0, false, false, true);
7258 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7259 return 1;
7260 }
7261 }
7262 else {
7263 if (isRootServer(ip)) {
7264 setLWResult(res, 0, false, false, true);
7265 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7266 addDS(DNSName("com."), 300, res->d_records, keys);
7267 addRRSIG(keys, res->d_records, DNSName("."), 300);
7268 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7269 return 1;
7270 }
7271 else if (ip == ComboAddress("192.0.2.1:53")) {
7272 setLWResult(res, 0, false, false, true);
a69867f2
RG
7273 if (domain == DNSName("com.")) {
7274 setLWResult(res, 0, true, false, true);
7275 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7276 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7277 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7278 addRRSIG(keys, res->d_records, DNSName("com."), 300);
895449a5 7279 }
a69867f2
RG
7280 else {
7281 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7282 if (domain == DNSName("powerdns.com.")) {
7283 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7284 }
7285 else if (domain == targetCName) {
7286 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7287 }
7288 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7289 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
895449a5 7290 }
a69867f2 7291
895449a5
RG
7292 return 1;
7293 }
7294 else if (ip == ComboAddress("192.0.2.2:53")) {
7295 setLWResult(res, 0, true, false, true);
a69867f2
RG
7296
7297 if (type == QType::NS) {
7298 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7299 if (domain == DNSName("powerdns.com.")) {
7300 addRRSIG(keys, res->d_records, domain, 300);
7301 }
7302 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7303 if (domain == DNSName("powerdns.com.")) {
7304 addRRSIG(keys, res->d_records, domain, 300);
7305 }
895449a5 7306 }
a69867f2
RG
7307 else {
7308 if (domain == DNSName("powerdns.com.")) {
7309 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7310 addRRSIG(keys, res->d_records, domain, 300);
7311 }
7312 else if (domain == targetCName) {
7313 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7314 }
895449a5 7315 }
a69867f2 7316
895449a5
RG
7317 return 1;
7318 }
7319 }
7320
7321 return 0;
7322 });
7323
7324 vector<DNSRecord> ret;
7325 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7326 BOOST_CHECK_EQUAL(res, RCode::NoError);
7327 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7328 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7329 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7330
7331 /* again, to test the cache */
7332 ret.clear();
7333 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7334 BOOST_CHECK_EQUAL(res, RCode::NoError);
7335 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7336 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7337 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7338}
7339
933299e8
RG
7340BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname_glue) {
7341 std::unique_ptr<SyncRes> sr;
f100caac 7342 initSR(sr, true);
933299e8
RG
7343
7344 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7345
7346 primeHints();
7347 const DNSName target("powerdns.com.");
7348 const DNSName targetCName1("cname.sub.powerdns.com.");
7349 const DNSName targetCName2("cname2.sub.powerdns.com.");
7350 const ComboAddress targetCName2Addr("192.0.2.42");
7351 testkeysset_t keys;
7352
7353 auto luaconfsCopy = g_luaconfs.getCopy();
7354 luaconfsCopy.dsAnchors.clear();
7355 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7356 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7357 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7358 g_luaconfs.setState(luaconfsCopy);
7359
7360 size_t queriesCount = 0;
7361
deca7d8f 7362 sr->setAsyncCallback([target,targetCName1,targetCName2,targetCName2Addr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
933299e8
RG
7363 queriesCount++;
7364
7365 if (type == QType::DS || type == QType::DNSKEY) {
7366 if (domain == DNSName("sub.powerdns.com")) {
7367 setLWResult(res, 0, false, false, true);
7368 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7369 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7370 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7371 return 1;
7372 }
7373 else {
7374 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7375 }
7376 }
7377 else {
7378 if (isRootServer(ip)) {
7379 setLWResult(res, 0, false, false, true);
7380 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7381 addDS(DNSName("com."), 300, res->d_records, keys);
7382 addRRSIG(keys, res->d_records, DNSName("."), 300);
7383 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7384 return 1;
7385 }
7386 else if (ip == ComboAddress("192.0.2.1:53")) {
7387 setLWResult(res, 0, false, false, true);
7388 if (domain == DNSName("com.")) {
7389 setLWResult(res, 0, true, false, true);
7390 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7391 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7392 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7393 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7394 }
7395 else {
7396 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7397 if (domain == DNSName("powerdns.com.")) {
7398 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7399 }
7400 else if (domain == DNSName("sub.powerdns.com")) {
7401 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7402 }
7403 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7404 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7405 }
7406
7407 return 1;
7408 }
7409 else if (ip == ComboAddress("192.0.2.2:53")) {
7410 setLWResult(res, 0, true, false, true);
7411
7412 if (type == QType::NS) {
7413 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7414 if (domain == DNSName("powerdns.com.")) {
7415 addRRSIG(keys, res->d_records, domain, 300);
7416 }
7417 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7418 if (domain == DNSName("powerdns.com.")) {
7419 addRRSIG(keys, res->d_records, domain, 300);
7420 }
7421 }
7422 else {
7423 if (domain == DNSName("powerdns.com.")) {
7424 addRecordToLW(res, domain, QType::CNAME, targetCName1.toString());
7425 addRRSIG(keys, res->d_records, domain, 300);
7426 /* add the CNAME target as a glue, with no RRSIG since the sub zone is insecure */
7427 addRecordToLW(res, targetCName1, QType::CNAME, targetCName2.toString());
7428 addRecordToLW(res, targetCName2, QType::A, targetCName2Addr.toString());
7429 }
7430 else if (domain == targetCName1) {
7431 addRecordToLW(res, domain, QType::CNAME, targetCName2.toString());
7432 }
7433 else if (domain == targetCName2) {
7434 addRecordToLW(res, domain, QType::A, targetCName2Addr.toString());
7435 }
7436 }
7437
7438 return 1;
7439 }
7440 }
7441
7442 return 0;
7443 });
7444
7445 vector<DNSRecord> ret;
7446 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7447 BOOST_CHECK_EQUAL(res, RCode::NoError);
7448 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7449 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7450 BOOST_CHECK_EQUAL(queriesCount, 11);
7451
7452 /* again, to test the cache */
7453 ret.clear();
7454 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7455 BOOST_CHECK_EQUAL(res, RCode::NoError);
7456 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7457 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7458 BOOST_CHECK_EQUAL(queriesCount, 11);
7459}
7460
3d5ebf10
RG
7461BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
7462 std::unique_ptr<SyncRes> sr;
7463 initSR(sr, true);
7464
0c43f455 7465 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7466
7467 primeHints();
7468 const DNSName target("power-dns.com.");
7469 const DNSName targetCName("powerdns.com.");
7470 const ComboAddress targetCNameAddr("192.0.2.42");
7471 testkeysset_t keys;
7472
7473 auto luaconfsCopy = g_luaconfs.getCopy();
7474 luaconfsCopy.dsAnchors.clear();
7475 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7476 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7477 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7478 g_luaconfs.setState(luaconfsCopy);
7479
7480 size_t queriesCount = 0;
7481
deca7d8f 7482 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3d5ebf10
RG
7483 queriesCount++;
7484
7485 if (type == QType::DS) {
a53e8fe3 7486 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
7487 setLWResult(res, 0, false, false, true);
7488 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7489 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7490 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7491 return 1;
7492 }
5374b03b
RG
7493 else {
7494 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7495 }
3d5ebf10
RG
7496 }
7497 else if (type == QType::DNSKEY) {
7498 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7499 setLWResult(res, 0, true, false, true);
7500 addDNSKEY(keys, domain, 300, res->d_records);
7501 addRRSIG(keys, res->d_records, domain, 300);
7502 return 1;
7503 }
7504 else {
7505 setLWResult(res, 0, false, false, true);
7506 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7507 return 1;
7508 }
7509 }
7510 else {
7511 if (isRootServer(ip)) {
7512 setLWResult(res, 0, false, false, true);
7513 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7514 addDS(DNSName("com."), 300, res->d_records, keys);
7515 addRRSIG(keys, res->d_records, DNSName("."), 300);
7516 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7517 return 1;
7518 }
7519 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7520 if (domain == DNSName("com.")) {
7521 setLWResult(res, 0, true, false, true);
7522 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7523 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7524 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7525 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7526 }
a69867f2
RG
7527 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7528 setLWResult(res, 0, false, false, true);
7529 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7530 if (domain == targetCName) {
7531 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7532 }
7533 else if (domain == target) {
7534 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7535 }
7536 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7537 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7538 }
3d5ebf10
RG
7539 return 1;
7540 }
7541 else if (ip == ComboAddress("192.0.2.2:53")) {
7542 setLWResult(res, 0, true, false, true);
a69867f2
RG
7543 if (type == QType::NS) {
7544 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7545 if (domain == DNSName("powerdns.com.")) {
7546 addRRSIG(keys, res->d_records, domain, 300);
7547 }
7548 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7549 if (domain == DNSName("powerdns.com.")) {
7550 addRRSIG(keys, res->d_records, domain, 300);
7551 }
3d5ebf10 7552 }
a69867f2
RG
7553 else {
7554 if (domain == target) {
7555 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7556 }
7557 else if (domain == targetCName) {
7558 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7559 addRRSIG(keys, res->d_records, domain, 300);
7560 }
3d5ebf10
RG
7561 }
7562 return 1;
7563 }
7564 }
7565
7566 return 0;
7567 });
7568
7569 vector<DNSRecord> ret;
7570 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7571 BOOST_CHECK_EQUAL(res, RCode::NoError);
7572 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7573 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7574 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7575
7576 /* again, to test the cache */
7577 ret.clear();
7578 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7579 BOOST_CHECK_EQUAL(res, RCode::NoError);
7580 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7581 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7582 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7583}
7584
7585BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
7586 std::unique_ptr<SyncRes> sr;
7587 initSR(sr, true);
7588
0c43f455 7589 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7590
7591 primeHints();
7592 const DNSName target("power-dns.com.");
7593 const DNSName targetCName("powerdns.com.");
7594 const ComboAddress targetCNameAddr("192.0.2.42");
7595 testkeysset_t keys;
7596
7597 auto luaconfsCopy = g_luaconfs.getCopy();
7598 luaconfsCopy.dsAnchors.clear();
7599 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7600 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7601 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7602 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7603 g_luaconfs.setState(luaconfsCopy);
7604
7605 size_t queriesCount = 0;
7606
deca7d8f 7607 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3d5ebf10
RG
7608 queriesCount++;
7609
5374b03b
RG
7610 if (type == QType::DS || type == QType::DNSKEY) {
7611 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7612 }
7613 else {
7614 if (isRootServer(ip)) {
7615 setLWResult(res, 0, false, false, true);
7616 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7617 addDS(DNSName("com."), 300, res->d_records, keys);
7618 addRRSIG(keys, res->d_records, DNSName("."), 300);
7619 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7620 return 1;
7621 }
7622 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7623 if (domain == DNSName("com.")) {
7624 setLWResult(res, 0, true, false, true);
7625 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7626 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7627 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7628 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7629 }
7630 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7631 setLWResult(res, 0, false, false, true);
7632 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7633 addDS(DNSName(domain), 300, res->d_records, keys);
7634 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7635 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7636 }
3d5ebf10
RG
7637 return 1;
7638 }
7639 else if (ip == ComboAddress("192.0.2.2:53")) {
7640 setLWResult(res, 0, true, false, true);
a69867f2
RG
7641 if (type == QType::NS) {
7642 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7643 addRRSIG(keys, res->d_records, domain, 300);
7644 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7645 addRRSIG(keys, res->d_records, domain, 300);
7646 }
a69867f2
RG
7647 else {
7648 if (domain == target) {
7649 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7650 /* No RRSIG, leading to bogus */
7651 }
7652 else if (domain == targetCName) {
7653 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7654 addRRSIG(keys, res->d_records, domain, 300);
7655 }
7656 }
3d5ebf10
RG
7657 return 1;
7658 }
7659 }
7660
7661 return 0;
7662 });
7663
7664 vector<DNSRecord> ret;
7665 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7666 BOOST_CHECK_EQUAL(res, RCode::NoError);
7667 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7668 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7669 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7670
7671 /* again, to test the cache */
7672 ret.clear();
7673 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7674 BOOST_CHECK_EQUAL(res, RCode::NoError);
7675 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7676 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7677 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7678}
7679
7680BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7681 std::unique_ptr<SyncRes> sr;
7682 initSR(sr, true);
7683
0c43f455 7684 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7685
7686 primeHints();
7687 const DNSName target("power-dns.com.");
7688 const DNSName targetCName("powerdns.com.");
7689 const ComboAddress targetCNameAddr("192.0.2.42");
7690 testkeysset_t keys;
7691
7692 auto luaconfsCopy = g_luaconfs.getCopy();
7693 luaconfsCopy.dsAnchors.clear();
7694 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7695 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7696 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7697 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7698 g_luaconfs.setState(luaconfsCopy);
7699
7700 size_t queriesCount = 0;
7701
deca7d8f 7702 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3d5ebf10
RG
7703 queriesCount++;
7704
5374b03b
RG
7705 if (type == QType::DS || type == QType::DNSKEY) {
7706 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7707 }
7708 else {
7709 if (isRootServer(ip)) {
7710 setLWResult(res, 0, false, false, true);
7711 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7712 addDS(DNSName("com."), 300, res->d_records, keys);
7713 addRRSIG(keys, res->d_records, DNSName("."), 300);
7714 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7715 return 1;
7716 }
7717 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7718 if (domain == DNSName("com.")) {
7719 setLWResult(res, 0, true, false, true);
7720 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7721 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7722 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7723 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7724 }
7725 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7726 setLWResult(res, 0, false, false, true);
7727 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7728 addDS(DNSName(domain), 300, res->d_records, keys);
7729 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7730 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7731 }
3d5ebf10
RG
7732 return 1;
7733 }
7734 else if (ip == ComboAddress("192.0.2.2:53")) {
7735 setLWResult(res, 0, true, false, true);
a69867f2
RG
7736 if (type == QType::NS) {
7737 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7738 addRRSIG(keys, res->d_records, domain, 300);
7739 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7740 addRRSIG(keys, res->d_records, domain, 300);
7741 }
a69867f2
RG
7742 else {
7743 if (domain == target) {
7744 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7745 addRRSIG(keys, res->d_records, domain, 300);
7746 }
7747 else if (domain == targetCName) {
7748 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7749 /* No RRSIG, leading to bogus */
7750 }
3d5ebf10
RG
7751 }
7752 return 1;
7753 }
7754 }
7755
7756 return 0;
7757 });
7758
7759 vector<DNSRecord> ret;
7760 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7761 BOOST_CHECK_EQUAL(res, RCode::NoError);
7762 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7763 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7764 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7765
7766 /* again, to test the cache */
7767 ret.clear();
7768 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7769 BOOST_CHECK_EQUAL(res, RCode::NoError);
7770 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7771 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7772 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7773}
7774
7775BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
7776 std::unique_ptr<SyncRes> sr;
7777 initSR(sr, true);
7778
0c43f455 7779 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7780
7781 primeHints();
7782 const DNSName target("power-dns.com.");
7783 const DNSName targetCName("powerdns.com.");
7784 const ComboAddress targetCNameAddr("192.0.2.42");
7785 testkeysset_t keys;
7786
7787 auto luaconfsCopy = g_luaconfs.getCopy();
7788 luaconfsCopy.dsAnchors.clear();
7789 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7790 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7791 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7792 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7793 g_luaconfs.setState(luaconfsCopy);
7794
7795 size_t queriesCount = 0;
7796
deca7d8f 7797 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3d5ebf10
RG
7798 queriesCount++;
7799
5374b03b
RG
7800 if (type == QType::DS || type == QType::DNSKEY) {
7801 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7802 }
7803 else {
7804 if (isRootServer(ip)) {
7805 setLWResult(res, 0, false, false, true);
7806 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7807 addDS(DNSName("com."), 300, res->d_records, keys);
7808 addRRSIG(keys, res->d_records, DNSName("."), 300);
7809 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7810 return 1;
7811 }
7812 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7813 if (domain == DNSName("com.")) {
7814 setLWResult(res, 0, true, false, true);
7815 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7816 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7817 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7818 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7819 }
7820 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7821 setLWResult(res, 0, false, false, true);
7822 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7823 addDS(DNSName(domain), 300, res->d_records, keys);
7824 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7825 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7826 }
3d5ebf10
RG
7827 return 1;
7828 }
7829 else if (ip == ComboAddress("192.0.2.2:53")) {
7830 setLWResult(res, 0, true, false, true);
a69867f2
RG
7831 if (type == QType::NS) {
7832 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
3d5ebf10 7833 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 7834 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7835 addRRSIG(keys, res->d_records, domain, 300);
7836 }
a69867f2
RG
7837 else {
7838 if (domain == target) {
7839 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7840 addRRSIG(keys, res->d_records, domain, 300);
7841 }
7842 else if (domain == targetCName) {
7843 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7844 addRRSIG(keys, res->d_records, domain, 300);
7845 }
7846 }
3d5ebf10
RG
7847 return 1;
7848 }
7849 }
7850
7851 return 0;
7852 });
7853
7854 vector<DNSRecord> ret;
7855 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7856 BOOST_CHECK_EQUAL(res, RCode::NoError);
7857 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7858 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7859 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7860
7861 /* again, to test the cache */
7862 ret.clear();
7863 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7864 BOOST_CHECK_EQUAL(res, RCode::NoError);
7865 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7866 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7867 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7868}
7869
7870BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7871 std::unique_ptr<SyncRes> sr;
a69867f2 7872 initSR(sr, true);
3d5ebf10 7873
0c43f455 7874 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7875
7876 primeHints();
7877 const DNSName target("powerdns.com.");
7878 const DNSName targetCName("power-dns.com.");
7879 const ComboAddress targetCNameAddr("192.0.2.42");
7880 testkeysset_t keys;
7881
7882 auto luaconfsCopy = g_luaconfs.getCopy();
7883 luaconfsCopy.dsAnchors.clear();
7884 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7885 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7886 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7887 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7888 g_luaconfs.setState(luaconfsCopy);
7889
7890 size_t queriesCount = 0;
7891
deca7d8f 7892 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
3d5ebf10
RG
7893 queriesCount++;
7894
7895 if (type == QType::DS) {
a53e8fe3 7896 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
7897 setLWResult(res, 0, false, false, true);
7898 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7899 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7900 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7901 return 1;
7902 }
5374b03b
RG
7903 else {
7904 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7905 }
3d5ebf10
RG
7906 }
7907 else if (type == QType::DNSKEY) {
7908 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7909 setLWResult(res, 0, true, false, true);
7910 addDNSKEY(keys, domain, 300, res->d_records);
7911 addRRSIG(keys, res->d_records, domain, 300);
7912 return 1;
7913 }
7914 else {
7915 setLWResult(res, 0, false, false, true);
7916 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7917 return 1;
7918 }
7919 }
7920 else {
7921 if (isRootServer(ip)) {
7922 setLWResult(res, 0, false, false, true);
7923 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7924 addDS(DNSName("com."), 300, res->d_records, keys);
7925 addRRSIG(keys, res->d_records, DNSName("."), 300);
7926 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7927 return 1;
7928 }
7929 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7930 if (domain == DNSName("com.")) {
7931 setLWResult(res, 0, true, false, true);
a69867f2 7932 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0
RG
7933 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7934 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7935 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7936 }
88cb0fe0
RG
7937 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7938 setLWResult(res, 0, false, false, true);
7939 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7940 if (domain == DNSName("powerdns.com.")) {
7941 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7942 }
7943 else if (domain == targetCName) {
7944 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7945 }
7946 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7947 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7948 }
3d5ebf10
RG
7949 return 1;
7950 }
7951 else if (ip == ComboAddress("192.0.2.2:53")) {
7952 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7953 if (type == QType::NS) {
7954 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7955 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7956 }
88cb0fe0
RG
7957 else {
7958 if (domain == DNSName("powerdns.com.")) {
7959 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7960 /* No RRSIG -> Bogus */
7961 }
7962 else if (domain == targetCName) {
7963 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7964 }
3d5ebf10
RG
7965 }
7966 return 1;
7967 }
7968 }
7969
7970 return 0;
7971 });
7972
7973 vector<DNSRecord> ret;
7974 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7975 BOOST_CHECK_EQUAL(res, RCode::NoError);
7976 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7977 /* no RRSIG to show */
7978 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7979 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7980
7981 /* again, to test the cache */
7982 ret.clear();
7983 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7984 BOOST_CHECK_EQUAL(res, RCode::NoError);
7985 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7986 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7987 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7988}
7989
895449a5
RG
7990BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7991 std::unique_ptr<SyncRes> sr;
7992 initSR(sr, true);
7993
0c43f455 7994 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
7995
7996 primeHints();
7997 const DNSName target("powerdns.com.");
7998 const ComboAddress targetAddr("192.0.2.42");
7999 testkeysset_t keys;
8000
8001 auto luaconfsCopy = g_luaconfs.getCopy();
8002 luaconfsCopy.dsAnchors.clear();
8003 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8004 /* No key material for .com */
8005 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8006 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
8007 g_luaconfs.setState(luaconfsCopy);
8008
8009 size_t queriesCount = 0;
8010
deca7d8f 8011 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
895449a5
RG
8012 queriesCount++;
8013
a53e8fe3 8014 if (type == QType::DNSKEY) {
895449a5
RG
8015 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
8016 setLWResult(res, 0, true, false, true);
8017 addDNSKEY(keys, domain, 300, res->d_records);
8018 addRRSIG(keys, res->d_records, domain, 300);
8019 return 1;
8020 }
8021 else if (domain == DNSName("com.")) {
8022 setLWResult(res, 0, false, false, true);
8023 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8024 return 1;
8025 }
8026 }
88cb0fe0 8027 else {
895449a5
RG
8028 if (isRootServer(ip)) {
8029 setLWResult(res, 0, false, false, true);
8030 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8031 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
8032 addRRSIG(keys, res->d_records, DNSName("."), 300);
8033 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8034 return 1;
8035 }
8036 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
8037 if (target == domain) {
8038 setLWResult(res, 0, false, false, true);
8039 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8040 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8041 }
8042 else if (domain == DNSName("com.")) {
8043 setLWResult(res, 0, true, false, true);
8044 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
8045 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8046 }
895449a5
RG
8047 return 1;
8048 }
8049 else if (ip == ComboAddress("192.0.2.2:53")) {
8050 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
8051 if (type == QType::NS) {
8052 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8053 }
8054 else {
8055 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8056 }
895449a5
RG
8057 addRRSIG(keys, res->d_records, domain, 300);
8058 return 1;
8059 }
8060 }
8061
8062 return 0;
8063 });
8064
8065 vector<DNSRecord> ret;
8066 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8067 BOOST_CHECK_EQUAL(res, RCode::NoError);
8068 /* should be insecure but we have a TA for powerdns.com. */
8069 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8070 /* We got a RRSIG */
8071 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8072 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8073 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
8074
8075 /* again, to test the cache */
8076 ret.clear();
8077 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8078 BOOST_CHECK_EQUAL(res, RCode::NoError);
8079 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8080 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8081 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8082 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
8083}
8084
8085BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
8086 std::unique_ptr<SyncRes> sr;
8087 initSR(sr, true);
8088
0c43f455 8089 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
8090
8091 primeHints();
8092 const DNSName target("powerdns.com.");
8093 const ComboAddress targetAddr("192.0.2.42");
8094 testkeysset_t keys;
8095
8096 auto luaconfsCopy = g_luaconfs.getCopy();
8097 luaconfsCopy.dsAnchors.clear();
8098 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8099 /* No key material for .com */
8100 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8101 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
8102 g_luaconfs.setState(luaconfsCopy);
8103
8104 size_t queriesCount = 0;
8105
deca7d8f 8106 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
895449a5
RG
8107 queriesCount++;
8108
a53e8fe3 8109 if (type == QType::DNSKEY) {
895449a5
RG
8110 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
8111 setLWResult(res, 0, true, false, true);
8112 addDNSKEY(keys, domain, 300, res->d_records);
8113 addRRSIG(keys, res->d_records, domain, 300);
8114 return 1;
8115 }
8116 else if (domain == DNSName("com.")) {
8117 setLWResult(res, 0, false, false, true);
8118 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8119 return 1;
8120 }
8121 }
70b3fe7a
RG
8122 else {
8123 if (target.isPartOf(domain) && isRootServer(ip)) {
895449a5
RG
8124 setLWResult(res, 0, false, false, true);
8125 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8126 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
8127 addRRSIG(keys, res->d_records, DNSName("."), 300);
8128 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8129 return 1;
8130 }
8131 else if (ip == ComboAddress("192.0.2.1:53")) {
70b3fe7a
RG
8132 if (target == domain) {
8133 setLWResult(res, 0, false, false, true);
8134 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8135 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8136 }
8137 else if (domain == DNSName("com.")) {
8138 setLWResult(res, 0, true, false, true);
8139 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0 8140 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
70b3fe7a 8141 }
895449a5
RG
8142 return 1;
8143 }
70b3fe7a 8144 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
895449a5 8145 setLWResult(res, 0, true, false, true);
70b3fe7a
RG
8146 if (type == QType::NS) {
8147 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8148 }
8149 else {
8150 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8151 }
895449a5
RG
8152 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
8153 return 1;
8154 }
8155 }
8156
8157 return 0;
8158 });
8159
8160 vector<DNSRecord> ret;
8161 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8162 BOOST_CHECK_EQUAL(res, RCode::NoError);
8163 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
8164 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8165 /* No RRSIG */
8166 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8167 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8168 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
8169
8170 /* again, to test the cache */
8171 ret.clear();
8172 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8173 BOOST_CHECK_EQUAL(res, RCode::NoError);
8174 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8175 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8176 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8177 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
8178}
8179
895449a5
RG
8180BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
8181 std::unique_ptr<SyncRes> sr;
8182 initSR(sr, true);
8183
0c43f455 8184 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5 8185
b7f378d1
RG
8186 primeHints();
8187 const DNSName target(".");
8188 testkeysset_t keys;
8189
8190 auto luaconfsCopy = g_luaconfs.getCopy();
8191 luaconfsCopy.dsAnchors.clear();
8192 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8193 /* Add a NTA for "." */
8194 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
8195 g_luaconfs.setState(luaconfsCopy);
8196
8197 size_t queriesCount = 0;
8198
deca7d8f 8199 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
b7f378d1
RG
8200 queriesCount++;
8201
8202 if (domain == target && type == QType::NS) {
8203
8204 setLWResult(res, 0, true, false, true);
8205 char addr[] = "a.root-servers.net.";
8206 for (char idx = 'a'; idx <= 'm'; idx++) {
8207 addr[0] = idx;
8455425c
RG
8208 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8209 }
8210
8211 addRRSIG(keys, res->d_records, domain, 300);
8212
8213 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8214 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8215
8216 return 1;
8217 } else if (domain == target && type == QType::DNSKEY) {
8218
8219 setLWResult(res, 0, true, false, true);
8220
8221 /* No DNSKEY */
8222
8223 return 1;
8224 }
8225
8226 return 0;
8227 });
8228
8229 vector<DNSRecord> ret;
8230 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8231 BOOST_CHECK_EQUAL(res, RCode::NoError);
8232 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8233 /* 13 NS + 1 RRSIG */
8234 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8235 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8236
8237 /* again, to test the cache */
8238 ret.clear();
8239 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8240 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8241 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8242 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8243 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8244}
8245
8246BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
8247 std::unique_ptr<SyncRes> sr;
895449a5 8248 initSR(sr, true);
8455425c 8249
0c43f455 8250 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
8251
8252 primeHints();
8253 const DNSName target(".");
b7f378d1 8254 testkeysset_t keys;
8455425c
RG
8255
8256 /* Remove the root DS */
8257 auto luaconfsCopy = g_luaconfs.getCopy();
8258 luaconfsCopy.dsAnchors.clear();
8259 g_luaconfs.setState(luaconfsCopy);
8260
8261 size_t queriesCount = 0;
8262
deca7d8f 8263 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8455425c
RG
8264 queriesCount++;
8265
8266 if (domain == target && type == QType::NS) {
8267
8268 setLWResult(res, 0, true, false, true);
8269 char addr[] = "a.root-servers.net.";
8270 for (char idx = 'a'; idx <= 'm'; idx++) {
8271 addr[0] = idx;
8272 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8273 }
8274
8275 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8276 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8277
8278 return 1;
8279 }
8280
8281 return 0;
8282 });
8283
8284 vector<DNSRecord> ret;
8285 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8286 BOOST_CHECK_EQUAL(res, RCode::NoError);
8287 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8288 /* 13 NS + 0 RRSIG */
8289 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8290 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8291
8292 /* again, to test the cache */
8293 ret.clear();
8294 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8295 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8296 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8297 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8298 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8299}
8300
114829cc
RG
8301BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
8302 std::unique_ptr<SyncRes> sr;
8303 initSR(sr, true);
8304
5d7b19c5 8305 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
114829cc
RG
8306
8307 primeHints();
8308 const DNSName target("powerdns.com.");
8309 testkeysset_t keys;
8310
8311 auto luaconfsCopy = g_luaconfs.getCopy();
8312 luaconfsCopy.dsAnchors.clear();
8313 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5374b03b 8314 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
114829cc
RG
8315 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8316 g_luaconfs.setState(luaconfsCopy);
8317
8318 size_t queriesCount = 0;
8319
deca7d8f 8320 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
114829cc
RG
8321 queriesCount++;
8322
5374b03b
RG
8323 if (type == QType::DS || type == QType::DNSKEY) {
8324 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
114829cc
RG
8325 }
8326 else {
8327
8328 setLWResult(res, 0, true, false, true);
8329 return 1;
8330 }
8331
8332 return 0;
8333 });
8334
8335 vector<DNSRecord> ret;
8336 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8337 BOOST_CHECK_EQUAL(res, RCode::NoError);
8338 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8339 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8340 /* com|NS, powerdns.com|NS, powerdns.com|A */
8341 BOOST_CHECK_EQUAL(queriesCount, 3);
8342
8343 /* again, to test the cache */
8344 ret.clear();
8345 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8346 BOOST_CHECK_EQUAL(res, RCode::NoError);
8347 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8348 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8349 /* we don't store empty results */
5374b03b 8350 BOOST_CHECK_EQUAL(queriesCount, 4);
114829cc
RG
8351}
8352
db04449e
RG
8353BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
8354 init();
8355
8356 testkeysset_t keys;
8357 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8358
8359 vector<DNSRecord> records;
8360
8361 vector<shared_ptr<DNSRecordContent>> recordContents;
8362 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8363
8364 /*
8365 No wrap test case:
8366 a.example.org. -> d.example.org. denies the existence of b.example.org.
8367 */
8368 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8369 recordContents.push_back(records.at(0).d_content);
8370 addRRSIG(keys, records, DNSName("example.org."), 300);
8371 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8372 records.clear();
8373
8374 ContentSigPair pair;
8375 pair.records = recordContents;
8376 pair.signatures = signatureContents;
8377 cspmap_t denialMap;
8378 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8379
9b061cf5
RG
8380 /* add wildcard denial */
8381 recordContents.clear();
8382 signatureContents.clear();
8383 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8384 recordContents.push_back(records.at(0).d_content);
8385 addRRSIG(keys, records, DNSName("example.org."), 300);
8386 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8387 records.clear();
8388
8389 pair.records = recordContents;
8390 pair.signatures = signatureContents;
8391 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
8392
00e3fef4 8393 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8394 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8395
00e3fef4 8396 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8397 /* let's check that d.example.org. is not denied by this proof */
8398 BOOST_CHECK_EQUAL(denialState, NODATA);
8399}
8400
8401BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
8402 init();
8403
8404 testkeysset_t keys;
8405 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8406
8407 vector<DNSRecord> records;
8408
8409 vector<shared_ptr<DNSRecordContent>> recordContents;
8410 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8411
8412 /*
8413 Wrap case 1 test case:
8414 z.example.org. -> b.example.org. denies the existence of a.example.org.
8415 */
8416 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8417 recordContents.push_back(records.at(0).d_content);
8418 addRRSIG(keys, records, DNSName("example.org."), 300);
8419 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8420 records.clear();
8421
8422 ContentSigPair pair;
8423 pair.records = recordContents;
8424 pair.signatures = signatureContents;
8425 cspmap_t denialMap;
8426 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
8427
00e3fef4 8428 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8429 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8430
00e3fef4 8431 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8432 /* let's check that d.example.org. is not denied by this proof */
8433 BOOST_CHECK_EQUAL(denialState, NODATA);
8434}
8435
8436BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
8437 init();
8438
8439 testkeysset_t keys;
8440 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8441
8442 vector<DNSRecord> records;
8443
8444 vector<shared_ptr<DNSRecordContent>> recordContents;
8445 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8446
8447 /*
8448 Wrap case 2 test case:
8449 y.example.org. -> a.example.org. denies the existence of z.example.org.
8450 */
8451 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8452 recordContents.push_back(records.at(0).d_content);
8453 addRRSIG(keys, records, DNSName("example.org."), 300);
8454 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8455 records.clear();
8456
8457 ContentSigPair pair;
8458 pair.records = recordContents;
8459 pair.signatures = signatureContents;
8460 cspmap_t denialMap;
8461 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
8462
00e3fef4 8463 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
db04449e
RG
8464 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8465
00e3fef4 8466 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8467 /* let's check that d.example.org. is not denied by this proof */
8468 BOOST_CHECK_EQUAL(denialState, NODATA);
8469}
8470
8471BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
8472 init();
8473
8474 testkeysset_t keys;
8475 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8476
8477 vector<DNSRecord> records;
8478
8479 vector<shared_ptr<DNSRecordContent>> recordContents;
8480 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8481
8482 /*
8483 Only one NSEC in the whole zone test case:
8484 a.example.org. -> a.example.org. denies the existence of b.example.org.
8485 */
8486 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8487 recordContents.push_back(records.at(0).d_content);
8488 addRRSIG(keys, records, DNSName("example.org."), 300);
8489 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8490 records.clear();
8491
8492 ContentSigPair pair;
8493 pair.records = recordContents;
8494 pair.signatures = signatureContents;
8495 cspmap_t denialMap;
8496 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8497
00e3fef4 8498 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8499 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8500
00e3fef4 8501 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8502 /* let's check that d.example.org. is not denied by this proof */
8503 BOOST_CHECK_EQUAL(denialState, NODATA);
8504}
8505
1efd998a
RG
8506BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
8507 init();
8508
8509 testkeysset_t keys;
8510 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8511
8512 vector<DNSRecord> records;
8513
8514 vector<shared_ptr<DNSRecordContent>> recordContents;
8515 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8516
8517 /*
8518 The RRSIG from "." denies the existence of anything between a. and c.,
8519 including b.
8520 */
8521 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
8522 recordContents.push_back(records.at(0).d_content);
8523 addRRSIG(keys, records, DNSName("."), 300);
8524 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8525 records.clear();
8526
8527 ContentSigPair pair;
8528 pair.records = recordContents;
8529 pair.signatures = signatureContents;
8530 cspmap_t denialMap;
8531 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8532
9b061cf5
RG
8533 /* add wildcard denial */
8534 recordContents.clear();
8535 signatureContents.clear();
8536 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8537 recordContents.push_back(records.at(0).d_content);
8538 addRRSIG(keys, records, DNSName("."), 300);
8539 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8540 records.clear();
8541
8542 pair.records = recordContents;
8543 pair.signatures = signatureContents;
8544 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
8545
00e3fef4 8546 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
1efd998a
RG
8547 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8548}
8549
8550BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
8551 init();
8552
8553 testkeysset_t keys;
8554 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8555
8556 vector<DNSRecord> records;
8557
8558 vector<shared_ptr<DNSRecordContent>> recordContents;
8559 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8560
8561 /*
8562 The RRSIG from "." denies the existence of any type except NS at a.
8563 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8564 signer field that is shorter than the owner name of the NSEC RR) it can't
8565 be used to deny anything except the whole name or a DS.
8566 */
8567 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
8568 recordContents.push_back(records.at(0).d_content);
8569 addRRSIG(keys, records, DNSName("."), 300);
8570 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8571 records.clear();
8572
8573 ContentSigPair pair;
8574 pair.records = recordContents;
8575 pair.signatures = signatureContents;
8576 cspmap_t denialMap;
8577 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8578
8579 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8580 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8581 nonexistence of any RRs below that zone cut, which include all RRs at
8582 that (original) owner name other than DS RRs, and all RRs below that
8583 owner name regardless of type.
8584 */
8585
00e3fef4 8586 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
1efd998a
RG
8587 /* no data means the qname/qtype is not denied, because an ancestor
8588 delegation NSEC can only deny the DS */
8589 BOOST_CHECK_EQUAL(denialState, NODATA);
8590
5b522864
RG
8591 /* it can not be used to deny any RRs below that owner name either */
8592 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false);
8593 BOOST_CHECK_EQUAL(denialState, NODATA);
8594
00e3fef4 8595 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
1efd998a
RG
8596 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8597}
8598
95823c07
RG
8599BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
8600 init();
8601
8602 testkeysset_t keys;
8603 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8604
8605 vector<DNSRecord> records;
8606
8607 vector<shared_ptr<DNSRecordContent>> recordContents;
8608 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8609
8610 /*
8611 * RFC 5155 section 8.9:
8612 * If there is an NSEC3 RR present in the response that matches the
8613 * delegation name, then the validator MUST ensure that the NS bit is
8614 * set and that the DS bit is not set in the Type Bit Maps field of the
8615 * NSEC3 RR.
8616 */
8617 /*
8618 The RRSIG from "." denies the existence of any type at a.
8619 NS should be set if it was proving an insecure delegation, let's check that
8620 we correctly detect that it's not.
8621 */
8622 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
8623 recordContents.push_back(records.at(0).d_content);
8624 addRRSIG(keys, records, DNSName("."), 300);
8625 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8626 records.clear();
8627
8628 ContentSigPair pair;
8629 pair.records = recordContents;
8630 pair.signatures = signatureContents;
8631 cspmap_t denialMap;
8632 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8633
8634 /* Insecure because the NS is not set, so while it does
8635 denies the DS, it can't prove an insecure delegation */
00e3fef4 8636 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8637 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8638}
8639
9b061cf5
RG
8640BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
8641 init();
8642
8643 testkeysset_t keys;
8644 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8645
8646 vector<DNSRecord> records;
8647
8648 vector<shared_ptr<DNSRecordContent>> recordContents;
8649 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8650
8651 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
8652 recordContents.push_back(records.at(0).d_content);
8653 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8654 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8655 records.clear();
8656
8657 ContentSigPair pair;
8658 pair.records = recordContents;
8659 pair.signatures = signatureContents;
8660 cspmap_t denialMap;
8661 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8662
8663 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8664 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
8665 BOOST_CHECK_EQUAL(denialState, NODATA);
8666}
8667
8668BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
8669 init();
8670
8671 testkeysset_t keys;
8672 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8673
8674 vector<DNSRecord> records;
8675
8676 vector<shared_ptr<DNSRecordContent>> recordContents;
8677 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8678
8679 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
8680 recordContents.push_back(records.at(0).d_content);
8681 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8682 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8683
8684 ContentSigPair pair;
8685 pair.records = recordContents;
8686 pair.signatures = signatureContents;
8687 cspmap_t denialMap;
8688 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8689 records.clear();
8690
8691 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8692 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8693 BOOST_CHECK_EQUAL(denialState, NODATA);
8694}
8695
8696BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8697 init();
8698
8699 testkeysset_t keys;
8700 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8701
8702 vector<DNSRecord> records;
8703
8704 vector<shared_ptr<DNSRecordContent>> recordContents;
8705 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8706
8707 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8708 recordContents.push_back(records.at(0).d_content);
8709 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8710 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8711 records.clear();
8712
8713 ContentSigPair pair;
8714 pair.records = recordContents;
8715 pair.signatures = signatureContents;
8716 cspmap_t denialMap;
8717 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8718
8719 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8720 BOOST_CHECK_EQUAL(denialState, NODATA);
8721}
8722
8723BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
8724 init();
8725
8726 testkeysset_t keys;
8727 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8728
8729 vector<DNSRecord> records;
8730
8731 vector<shared_ptr<DNSRecordContent>> recordContents;
8732 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8733
8734 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8735 recordContents.push_back(records.at(0).d_content);
8736 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8737 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8738
8739 ContentSigPair pair;
8740 pair.records = recordContents;
8741 pair.signatures = signatureContents;
8742 cspmap_t denialMap;
8743 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8744
8745 /* Add NSEC3 for the closest encloser */
8746 recordContents.clear();
8747 signatureContents.clear();
8748 records.clear();
8749 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8750 recordContents.push_back(records.at(0).d_content);
8751 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8752 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8753
8754 pair.records = recordContents;
8755 pair.signatures = signatureContents;
8756 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8757
8758 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8759 BOOST_CHECK_EQUAL(denialState, NODATA);
8760}
8761
00e3fef4
RG
8762BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8763 init();
8764
8765 testkeysset_t keys;
8766 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8767
8768 vector<DNSRecord> records;
8769
8770 vector<shared_ptr<DNSRecordContent>> recordContents;
8771 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8772
8773 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8774 recordContents.push_back(records.at(0).d_content);
8775 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8776 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8777 records.clear();
8778
8779 ContentSigPair pair;
8780 pair.records = recordContents;
8781 pair.signatures = signatureContents;
8782 cspmap_t denialMap;
8783 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8784
9b061cf5 8785 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
00e3fef4 8786 it is an ENT */
9b061cf5 8787 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
00e3fef4 8788 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
00be1ff6 8789
9b061cf5
RG
8790 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8791 it could prove a NXDOMAIN if it had an additional wildcard denial */
8792 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8793 BOOST_CHECK_EQUAL(denialState, NODATA);
8794
00be1ff6
RG
8795 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8796 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8797 BOOST_CHECK_EQUAL(denialState, NODATA);
9b061cf5
RG
8798
8799 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8800 recordContents.clear();
8801 signatureContents.clear();
8802 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8803 recordContents.push_back(records.at(0).d_content);
8804 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8805 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8806 records.clear();
8807 pair.records = recordContents;
8808 pair.signatures = signatureContents;
8809 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8810
82566a96 8811 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
9b061cf5 8812 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
00e3fef4
RG
8813}
8814
95823c07
RG
8815BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8816 init();
8817
8818 testkeysset_t keys;
8819 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8820
8821 vector<DNSRecord> records;
8822
8823 vector<shared_ptr<DNSRecordContent>> recordContents;
8824 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8825
8826 /*
8827 The RRSIG from "." denies the existence of any type except NS at a.
8828 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8829 signer field that is shorter than the owner name of the NSEC RR) it can't
8830 be used to deny anything except the whole name or a DS.
8831 */
9b061cf5 8832 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
95823c07
RG
8833 recordContents.push_back(records.at(0).d_content);
8834 addRRSIG(keys, records, DNSName("."), 300);
8835 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8836
8837 ContentSigPair pair;
8838 pair.records = recordContents;
8839 pair.signatures = signatureContents;
8840 cspmap_t denialMap;
8841 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8842 records.clear();
8843
8844 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8845 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8846 nonexistence of any RRs below that zone cut, which include all RRs at
8847 that (original) owner name other than DS RRs, and all RRs below that
8848 owner name regardless of type.
8849 */
8850
00e3fef4 8851 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
95823c07
RG
8852 /* no data means the qname/qtype is not denied, because an ancestor
8853 delegation NSEC3 can only deny the DS */
8854 BOOST_CHECK_EQUAL(denialState, NODATA);
8855
00e3fef4 8856 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
95823c07 8857 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
5b522864
RG
8858
8859 /* it can not be used to deny any RRs below that owner name either */
8860 /* Add NSEC3 for the next closer */
8861 recordContents.clear();
8862 signatureContents.clear();
8863 records.clear();
8864 addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8865 recordContents.push_back(records.at(0).d_content);
8866 addRRSIG(keys, records, DNSName("."), 300);
8867 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8868
8869 pair.records = recordContents;
8870 pair.signatures = signatureContents;
8871 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8872
8873 /* add wildcard denial */
8874 recordContents.clear();
8875 signatureContents.clear();
8876 records.clear();
8877 addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8878 recordContents.push_back(records.at(0).d_content);
8879 addRRSIG(keys, records, DNSName("."), 300);
8880 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8881
8882 pair.records = recordContents;
8883 pair.signatures = signatureContents;
8884 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8885
8886 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true);
8887 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8888}
8889
b7c40613
RG
8890BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8891 init();
8892
8893 testkeysset_t keys;
8894 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8895
8896 vector<DNSRecord> records;
8897
8898 vector<shared_ptr<DNSRecordContent>> recordContents;
8899 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8900
8901 /* adding a NSEC3 with more iterations that we support */
8902 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8903 recordContents.push_back(records.at(0).d_content);
8904 addRRSIG(keys, records, DNSName("."), 300);
8905 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8906
8907 ContentSigPair pair;
8908 pair.records = recordContents;
8909 pair.signatures = signatureContents;
8910 cspmap_t denialMap;
8911 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8912 records.clear();
8913
8914 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8915 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8916 BOOST_CHECK_EQUAL(denialState, INSECURE);
8917}
8918
95823c07
RG
8919BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8920 init();
8921
8922 testkeysset_t keys;
8923 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8924
8925 vector<DNSRecord> records;
8926
8927 vector<shared_ptr<DNSRecordContent>> recordContents;
8928 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8929
8930 /*
8931 * RFC 5155 section 8.9:
8932 * If there is an NSEC3 RR present in the response that matches the
8933 * delegation name, then the validator MUST ensure that the NS bit is
8934 * set and that the DS bit is not set in the Type Bit Maps field of the
8935 * NSEC3 RR.
8936 */
8937 /*
8938 The RRSIG from "." denies the existence of any type at a.
8939 NS should be set if it was proving an insecure delegation, let's check that
8940 we correctly detect that it's not.
8941 */
9b061cf5 8942 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
95823c07
RG
8943 recordContents.push_back(records.at(0).d_content);
8944 addRRSIG(keys, records, DNSName("."), 300);
8945 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8946
8947 ContentSigPair pair;
8948 pair.records = recordContents;
8949 pair.signatures = signatureContents;
8950 cspmap_t denialMap;
8951 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8952 records.clear();
8953
8954 /* Insecure because the NS is not set, so while it does
8955 denies the DS, it can't prove an insecure delegation */
00e3fef4 8956 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8957 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8958}
8959
dbbef467
RG
8960BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8961 std::unique_ptr<SyncRes> sr;
dbbef467
RG
8962 initSR(sr, true);
8963
8964 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8965
8966 primeHints();
8967 const DNSName target("com.");
8968 testkeysset_t keys;
8969
8970 auto luaconfsCopy = g_luaconfs.getCopy();
8971 luaconfsCopy.dsAnchors.clear();
8972 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8973 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8974 g_luaconfs.setState(luaconfsCopy);
8975
8976 size_t queriesCount = 0;
8977
deca7d8f 8978 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
dbbef467
RG
8979 queriesCount++;
8980
8981 DNSName auth = domain;
8982 auth.chopOff();
8983
8984 if (type == QType::DS || type == QType::DNSKEY) {
8985 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8986 }
8987 else {
8988 setLWResult(res, RCode::NoError, true, false, true);
8989 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8990 addRRSIG(keys, res->d_records, domain, 300);
8991 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8992 addRRSIG(keys, res->d_records, domain, 1);
8993 return 1;
8994 }
8995
8996 return 0;
8997 });
8998
a66eacd6 8999 const time_t now = sr->getNow().tv_sec;
dbbef467
RG
9000 vector<DNSRecord> ret;
9001 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9002 BOOST_CHECK_EQUAL(res, RCode::NoError);
9003 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9004 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9005 BOOST_CHECK_EQUAL(queriesCount, 4);
9006
9007 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
28364e4b 9008 const NegCache::NegCacheEntry* ne = nullptr;
dbbef467 9009 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9010 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9011 BOOST_CHECK_EQUAL(ne->d_ttd, now + 1);
9012 BOOST_CHECK_EQUAL(ne->d_validationState, Secure);
9013 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9014 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9015 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
9016 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 1);
dbbef467
RG
9017
9018 /* again, to test the cache */
9019 ret.clear();
9020 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9021 BOOST_CHECK_EQUAL(res, RCode::NoError);
9022 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9023 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9024 BOOST_CHECK_EQUAL(queriesCount, 4);
9025}
9026
9027BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
9028 std::unique_ptr<SyncRes> sr;
dbbef467
RG
9029 initSR(sr, true);
9030
9031 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9032
9033 primeHints();
9034 const DNSName target("com.");
9035 const ComboAddress targetAddr("192.0.2.42");
9036 testkeysset_t keys;
9037
9038 auto luaconfsCopy = g_luaconfs.getCopy();
9039 luaconfsCopy.dsAnchors.clear();
9040 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9041 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9042 g_luaconfs.setState(luaconfsCopy);
9043
9044 size_t queriesCount = 0;
9045
deca7d8f 9046 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
dbbef467
RG
9047 queriesCount++;
9048
9049 DNSName auth = domain;
9050 auth.chopOff();
9051
9052 if (type == QType::DS || type == QType::DNSKEY) {
9053 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9054 }
9055 else {
9056 setLWResult(res, RCode::NoError, true, false, true);
9057 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
9058 addRRSIG(keys, res->d_records, domain, 1);
9059 return 1;
9060 }
9061
9062 return 0;
9063 });
9064
a66eacd6 9065 const time_t now = sr->getNow().tv_sec;
dbbef467
RG
9066 vector<DNSRecord> ret;
9067 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9068 BOOST_CHECK_EQUAL(res, RCode::NoError);
9069 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9070 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9071 BOOST_CHECK_EQUAL(queriesCount, 4);
9072
9073 /* check that the entry has not been cached for longer than the RRSIG validity */
9074 const ComboAddress who;
9075 vector<DNSRecord> cached;
9076 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
9077 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
9078 BOOST_REQUIRE_EQUAL(cached.size(), 1);
9079 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
9080 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
9081
9082 /* again, to test the cache */
9083 ret.clear();
9084 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9085 BOOST_CHECK_EQUAL(res, RCode::NoError);
9086 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9087 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9088 BOOST_CHECK_EQUAL(queriesCount, 4);
9089}
9090
f4de85a3
RG
9091BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
9092 /*
9093 Validation is optional, and the first query does not ask for it,
9094 so the answer is cached as Indeterminate.
9095 The second query asks for validation, answer should be marked as
9096 Secure.
9097 */
9098 std::unique_ptr<SyncRes> sr;
9099 initSR(sr, true);
9100
9101 setDNSSECValidation(sr, DNSSECMode::Process);
9102
9103 primeHints();
9104 const DNSName target("com.");
9105 testkeysset_t keys;
9106
9107 auto luaconfsCopy = g_luaconfs.getCopy();
9108 luaconfsCopy.dsAnchors.clear();
9109 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9110 g_luaconfs.setState(luaconfsCopy);
9111
9112 size_t queriesCount = 0;
9113
deca7d8f 9114 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f4de85a3
RG
9115 queriesCount++;
9116
9117 if (type == QType::DS || type == QType::DNSKEY) {
9118 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9119 }
9120 else {
9121 if (domain == target && type == QType::A) {
9122 setLWResult(res, 0, true, false, true);
9123 addRecordToLW(res, target, QType::A, "192.0.2.1");
9124 addRRSIG(keys, res->d_records, DNSName("."), 300);
9125 return 1;
9126 }
9127 }
9128
9129 return 0;
9130 });
9131
9132 vector<DNSRecord> ret;
9133 /* first query does not require validation */
9134 sr->setDNSSECValidationRequested(false);
9135 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9136 BOOST_CHECK_EQUAL(res, RCode::NoError);
9137 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9138 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9139 for (const auto& record : ret) {
9140 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
9141 }
9142 BOOST_CHECK_EQUAL(queriesCount, 1);
9143
9144
9145 ret.clear();
9146 /* second one _does_ require validation */
9147 sr->setDNSSECValidationRequested(true);
9148 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9149 BOOST_CHECK_EQUAL(res, RCode::NoError);
9150 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9151 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9152 for (const auto& record : ret) {
9153 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
9154 }
9155 BOOST_CHECK_EQUAL(queriesCount, 3);
9156}
9157
9158BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
9159 /*
9160 Validation is optional, and the first query does not ask for it,
9161 so the answer is cached as Indeterminate.
9162 The second query asks for validation, answer should be marked as
9163 Insecure.
9164 */
9165 std::unique_ptr<SyncRes> sr;
9166 initSR(sr, true);
9167
9168 setDNSSECValidation(sr, DNSSECMode::Process);
9169
9170 primeHints();
9171 const DNSName target("com.");
9172 testkeysset_t keys;
9173
9174 auto luaconfsCopy = g_luaconfs.getCopy();
9175 luaconfsCopy.dsAnchors.clear();
9176 g_luaconfs.setState(luaconfsCopy);
9177
9178 size_t queriesCount = 0;
9179
deca7d8f 9180 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f4de85a3
RG
9181 queriesCount++;
9182
9183 if (type == QType::DS || type == QType::DNSKEY) {
9184 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9185 }
9186 else {
9187 if (domain == target && type == QType::A) {
9188 setLWResult(res, 0, true, false, true);
9189 addRecordToLW(res, target, QType::A, "192.0.2.1");
9190 return 1;
9191 }
9192 }
9193
9194 return 0;
9195 });
9196
9197 vector<DNSRecord> ret;
9198 /* first query does not require validation */
9199 sr->setDNSSECValidationRequested(false);
9200 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9201 BOOST_CHECK_EQUAL(res, RCode::NoError);
9202 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9203 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9204 for (const auto& record : ret) {
55acb073 9205 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9206 }
9207 BOOST_CHECK_EQUAL(queriesCount, 1);
9208
9209
9210 ret.clear();
9211 /* second one _does_ require validation */
9212 sr->setDNSSECValidationRequested(true);
9213 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9214 BOOST_CHECK_EQUAL(res, RCode::NoError);
9215 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9216 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9217 for (const auto& record : ret) {
55acb073 9218 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9219 }
9220 BOOST_CHECK_EQUAL(queriesCount, 1);
9221}
9222
9223BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
9224 /*
9225 Validation is optional, and the first query does not ask for it,
9226 so the answer is cached as Indeterminate.
9227 The second query asks for validation, answer should be marked as
9228 Bogus.
9229 */
9230 std::unique_ptr<SyncRes> sr;
9231 initSR(sr, true);
9232
9233 setDNSSECValidation(sr, DNSSECMode::Process);
9234
9235 primeHints();
9236 const DNSName target("com.");
9237 testkeysset_t keys;
9238
9239 auto luaconfsCopy = g_luaconfs.getCopy();
9240 luaconfsCopy.dsAnchors.clear();
9241 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9242 g_luaconfs.setState(luaconfsCopy);
9243
9244 size_t queriesCount = 0;
9245
deca7d8f 9246 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f4de85a3
RG
9247 queriesCount++;
9248
9249 if (type == QType::DS || type == QType::DNSKEY) {
9250 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9251 }
9252 else {
9253 if (domain == target && type == QType::A) {
9254 setLWResult(res, 0, true, false, true);
9255 addRecordToLW(res, target, QType::A, "192.0.2.1");
9256 /* no RRSIG */
9257 return 1;
9258 }
9259 }
9260
9261 return 0;
9262 });
9263
9264 vector<DNSRecord> ret;
9265 /* first query does not require validation */
9266 sr->setDNSSECValidationRequested(false);
9267 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9268 BOOST_CHECK_EQUAL(res, RCode::NoError);
9269 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9270 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9271 for (const auto& record : ret) {
55acb073 9272 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9273 }
9274 BOOST_CHECK_EQUAL(queriesCount, 1);
9275
9276
9277 ret.clear();
9278 /* second one _does_ require validation */
9279 sr->setDNSSECValidationRequested(true);
9280 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9281 BOOST_CHECK_EQUAL(res, RCode::NoError);
9282 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9283 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9284 for (const auto& record : ret) {
55acb073 9285 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9286 }
9287 BOOST_CHECK_EQUAL(queriesCount, 3);
9288}
9289
55acb073
RG
9290BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
9291 /*
9292 Validation is optional, and the first query does not ask for it,
9293 so the answer is cached as Indeterminate.
9294 The second query asks for validation, answer should be marked as
9295 Secure.
9296 */
9297 std::unique_ptr<SyncRes> sr;
9298 initSR(sr, true);
9299
9300 setDNSSECValidation(sr, DNSSECMode::Process);
9301
9302 primeHints();
9303 const DNSName target("com.");
9304 const DNSName cnameTarget("cname-com.");
9305 testkeysset_t keys;
9306
9307 auto luaconfsCopy = g_luaconfs.getCopy();
9308 luaconfsCopy.dsAnchors.clear();
9309 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9310 g_luaconfs.setState(luaconfsCopy);
9311
9312 size_t queriesCount = 0;
9313
deca7d8f 9314 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
55acb073
RG
9315 queriesCount++;
9316
9317 if (type == QType::DS || type == QType::DNSKEY) {
9318 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9319 }
9320 else {
9321 if (domain == target && type == QType::A) {
9322 setLWResult(res, 0, true, false, true);
9323 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9324 addRRSIG(keys, res->d_records, DNSName("."), 300);
9325 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9326 addRRSIG(keys, res->d_records, DNSName("."), 300);
9327 return 1;
9328 } else if (domain == cnameTarget && type == QType::A) {
9329 setLWResult(res, 0, true, false, true);
9330 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9331 addRRSIG(keys, res->d_records, DNSName("."), 300);
9332 return 1;
9333 }
9334 }
9335
9336 return 0;
9337 });
9338
9339 vector<DNSRecord> ret;
9340 /* first query does not require validation */
9341 sr->setDNSSECValidationRequested(false);
9342 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9343 BOOST_CHECK_EQUAL(res, RCode::NoError);
9344 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9345 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9346 for (const auto& record : ret) {
9347 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9348 }
9349 BOOST_CHECK_EQUAL(queriesCount, 2);
9350
9351
9352 ret.clear();
9353 /* second one _does_ require validation */
9354 sr->setDNSSECValidationRequested(true);
9355 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9356 BOOST_CHECK_EQUAL(res, RCode::NoError);
9357 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9358 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9359 for (const auto& record : ret) {
9360 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9361 }
9362 BOOST_CHECK_EQUAL(queriesCount, 5);
9363}
9364
9365BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
9366 /*
9367 Validation is optional, and the first query does not ask for it,
9368 so the answer is cached as Indeterminate.
9369 The second query asks for validation, answer should be marked as
9370 Insecure.
9371 */
9372 std::unique_ptr<SyncRes> sr;
9373 initSR(sr, true);
9374
9375 setDNSSECValidation(sr, DNSSECMode::Process);
9376
9377 primeHints();
9378 const DNSName target("com.");
9379 const DNSName cnameTarget("cname-com.");
9380 testkeysset_t keys;
9381
9382 auto luaconfsCopy = g_luaconfs.getCopy();
9383 luaconfsCopy.dsAnchors.clear();
9384 g_luaconfs.setState(luaconfsCopy);
9385
9386 size_t queriesCount = 0;
9387
deca7d8f 9388 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
55acb073
RG
9389 queriesCount++;
9390
9391 if (type == QType::DS || type == QType::DNSKEY) {
9392 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9393 }
9394 else {
9395 if (domain == target && type == QType::A) {
9396 setLWResult(res, 0, true, false, true);
9397 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9398 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9399 return 1;
9400 } else if (domain == cnameTarget && type == QType::A) {
9401 setLWResult(res, 0, true, false, true);
9402 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9403 return 1;
9404 }
9405 }
9406
9407 return 0;
9408 });
9409
9410 vector<DNSRecord> ret;
9411 /* first query does not require validation */
9412 sr->setDNSSECValidationRequested(false);
9413 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9414 BOOST_CHECK_EQUAL(res, RCode::NoError);
9415 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9416 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9417 for (const auto& record : ret) {
9418 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9419 }
9420 BOOST_CHECK_EQUAL(queriesCount, 2);
9421
9422
9423 ret.clear();
9424 /* second one _does_ require validation */
9425 sr->setDNSSECValidationRequested(true);
9426 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9427 BOOST_CHECK_EQUAL(res, RCode::NoError);
9428 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9429 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9430 for (const auto& record : ret) {
9431 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9432 }
9433 BOOST_CHECK_EQUAL(queriesCount, 2);
9434}
9435
9436BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
9437 /*
9438 Validation is optional, and the first query does not ask for it,
9439 so the answer is cached as Indeterminate.
9440 The second query asks for validation, answer should be marked as
9441 Bogus.
9442 */
9443 std::unique_ptr<SyncRes> sr;
9444 initSR(sr, true);
9445
9446 setDNSSECValidation(sr, DNSSECMode::Process);
9447
9448 primeHints();
9449 const DNSName target("com.");
9450 const DNSName cnameTarget("cname-com.");
9451 testkeysset_t keys;
9452
9453 auto luaconfsCopy = g_luaconfs.getCopy();
9454 luaconfsCopy.dsAnchors.clear();
9455 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9456 g_luaconfs.setState(luaconfsCopy);
9457
9458 size_t queriesCount = 0;
9459
deca7d8f 9460 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
55acb073
RG
9461 queriesCount++;
9462
9463 if (type == QType::DS || type == QType::DNSKEY) {
9464 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9465 }
9466 else {
9467 if (domain == target && type == QType::A) {
9468 setLWResult(res, 0, true, false, true);
9469 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9470 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9471 /* no RRSIG */
9472 return 1;
9473 } else if (domain == cnameTarget && type == QType::A) {
9474 setLWResult(res, 0, true, false, true);
9475 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9476 /* no RRSIG */
9477 return 1;
9478 }
9479 }
9480
9481 return 0;
9482 });
9483
9484 vector<DNSRecord> ret;
9485 /* first query does not require validation */
9486 sr->setDNSSECValidationRequested(false);
9487 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9488 BOOST_CHECK_EQUAL(res, RCode::NoError);
9489 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9490 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9491 for (const auto& record : ret) {
9492 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9493 }
9494 BOOST_CHECK_EQUAL(queriesCount, 2);
9495
9496
9497 ret.clear();
9498 /* second one _does_ require validation */
9499 sr->setDNSSECValidationRequested(true);
9500 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9501 BOOST_CHECK_EQUAL(res, RCode::NoError);
9502 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9503 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9504 for (const auto& record : ret) {
9505 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9506 }
9507 BOOST_CHECK_EQUAL(queriesCount, 5);
9508}
9509
405a26bd
RG
9510BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) {
9511 /*
9512 We get a record from a secure zone in the additional section, without
9513 the corresponding RRSIG. The record should not be marked as authoritative
9514 and should be correctly validated.
9515 */
9516 std::unique_ptr<SyncRes> sr;
9517 initSR(sr, true);
9518
9519 setDNSSECValidation(sr, DNSSECMode::Process);
9520
9521 primeHints();
9522 const DNSName target("com.");
9523 const DNSName addTarget("nsX.com.");
9524 testkeysset_t keys;
9525
9526 auto luaconfsCopy = g_luaconfs.getCopy();
9527 luaconfsCopy.dsAnchors.clear();
9528 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9529 g_luaconfs.setState(luaconfsCopy);
9530
9531 size_t queriesCount = 0;
9532
deca7d8f 9533 sr->setAsyncCallback([target,addTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
405a26bd
RG
9534 queriesCount++;
9535
9536 if (type == QType::DS || type == QType::DNSKEY) {
9537 if (domain == addTarget) {
9538 DNSName auth(domain);
9539 /* no DS for com, auth will be . */
9540 auth.chopOff();
9541 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false);
9542 }
9543 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9544 }
9545 else {
9546 if (domain == target && type == QType::A) {
9547 setLWResult(res, 0, true, false, true);
9548 addRecordToLW(res, target, QType::A, "192.0.2.1");
9549 addRRSIG(keys, res->d_records, DNSName("."), 300);
9550 addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL);
9551 /* no RRSIG for the additional record */
9552 return 1;
9553 } else if (domain == addTarget && type == QType::A) {
9554 setLWResult(res, 0, true, false, true);
9555 addRecordToLW(res, addTarget, QType::A, "192.0.2.42");
9556 addRRSIG(keys, res->d_records, DNSName("."), 300);
9557 return 1;
9558 }
9559 }
9560
9561 return 0;
9562 });
9563
9564 vector<DNSRecord> ret;
9565 /* first query for target/A, will pick up the additional record as non-auth / unvalidated */
9566 sr->setDNSSECValidationRequested(false);
9567 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9568 BOOST_CHECK_EQUAL(res, RCode::NoError);
9569 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9570 BOOST_CHECK_EQUAL(ret.size(), 2);
9571 for (const auto& record : ret) {
9572 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9573 }
9574 BOOST_CHECK_EQUAL(queriesCount, 1);
9575
9576 ret.clear();
9577 /* ask for the additional record directly, we should not use
9578 the non-auth one and issue a new query, properly validated */
9579 sr->setDNSSECValidationRequested(true);
9580 res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret);
9581 BOOST_CHECK_EQUAL(res, RCode::NoError);
9582 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9583 BOOST_CHECK_EQUAL(ret.size(), 2);
9584 for (const auto& record : ret) {
9585 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9586 }
9587 BOOST_CHECK_EQUAL(queriesCount, 5);
9588}
9589
f4de85a3
RG
9590BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
9591 /*
9592 Validation is optional, and the first query does not ask for it,
9593 so the answer is negatively cached as Indeterminate.
9594 The second query asks for validation, answer should be marked as
9595 Secure.
9596 */
9597 std::unique_ptr<SyncRes> sr;
9598 initSR(sr, true);
9599
9600 setDNSSECValidation(sr, DNSSECMode::Process);
9601
9602 primeHints();
9603 const DNSName target("com.");
9604 testkeysset_t keys;
9605
9606 auto luaconfsCopy = g_luaconfs.getCopy();
9607 luaconfsCopy.dsAnchors.clear();
9608 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9609 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9610 g_luaconfs.setState(luaconfsCopy);
9611
9612 size_t queriesCount = 0;
9613
deca7d8f 9614 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f4de85a3
RG
9615 queriesCount++;
9616
9617 DNSName auth = domain;
9618 auth.chopOff();
9619
9620 if (type == QType::DS || type == QType::DNSKEY) {
9621 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9622 }
9623 else {
9624 setLWResult(res, RCode::NoError, true, false, true);
9625 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9626 addRRSIG(keys, res->d_records, domain, 300);
9627 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
9628 addRRSIG(keys, res->d_records, domain, 1);
9629 return 1;
9630 }
9631
9632 return 0;
9633 });
9634
9635 vector<DNSRecord> ret;
9636 /* first query does not require validation */
9637 sr->setDNSSECValidationRequested(false);
9638 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9639 BOOST_CHECK_EQUAL(res, RCode::NoError);
9640 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9641 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9642 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd 9643 /* check that the entry has not been negatively cached */
28364e4b 9644 const NegCache::NegCacheEntry* ne = nullptr;
b25712fd 9645 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9646 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9647 BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
9648 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9649 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9650 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
9651 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9652
9653 ret.clear();
9654 /* second one _does_ require validation */
9655 sr->setDNSSECValidationRequested(true);
9656 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9657 BOOST_CHECK_EQUAL(res, RCode::NoError);
9658 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9659 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9660 BOOST_CHECK_EQUAL(queriesCount, 4);
b25712fd 9661 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9662 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9663 BOOST_CHECK_EQUAL(ne->d_validationState, Secure);
9664 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9665 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9666 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
9667 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9668}
9669
f5a747bb
RG
9670BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
9671 /*
9672 Validation is optional, and the first query does not ask for it,
9673 so the answer is negatively cached as Indeterminate.
9674 The second query asks for validation, answer should be marked as
9675 Secure.
9676 The difference with test_dnssec_validation_from_negcache_secure is
9677 that have one more level here, so we are going to look for the proof
9678 that the DS does not exist for the last level. Since there is no cut,
9679 we should accept the fact that the NSEC denies DS and NS both.
9680 */
9681 std::unique_ptr<SyncRes> sr;
9682 initSR(sr, true);
9683
9684 setDNSSECValidation(sr, DNSSECMode::Process);
9685
9686 primeHints();
9687 const DNSName target("www.com.");
9688 testkeysset_t keys;
9689
9690 auto luaconfsCopy = g_luaconfs.getCopy();
9691 luaconfsCopy.dsAnchors.clear();
9692 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9693 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9694 g_luaconfs.setState(luaconfsCopy);
9695
9696 size_t queriesCount = 0;
9697
deca7d8f 9698 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f5a747bb
RG
9699 queriesCount++;
9700
9701 if (type == QType::DS || type == QType::DNSKEY) {
9702 if (domain == target) {
9703 /* there is no cut */
9704 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9705 }
9706 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
9707 }
9708
9709 return 0;
9710 });
9711
9712 vector<DNSRecord> ret;
9713 /* first query does not require validation */
9714 sr->setDNSSECValidationRequested(false);
9715 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9716 BOOST_CHECK_EQUAL(res, RCode::NoError);
9717 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9718 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9719 BOOST_CHECK_EQUAL(queriesCount, 1);
9720
9721 ret.clear();
9722 /* second one _does_ require validation */
9723 sr->setDNSSECValidationRequested(true);
9724 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9725 BOOST_CHECK_EQUAL(res, RCode::NoError);
9726 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9727 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9728 BOOST_CHECK_EQUAL(queriesCount, 4);
9729}
9730
f4de85a3
RG
9731BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
9732 /*
9733 Validation is optional, and the first query does not ask for it,
9734 so the answer is negatively cached as Indeterminate.
9735 The second query asks for validation, answer should be marked as
9736 Insecure.
9737 */
9738 std::unique_ptr<SyncRes> sr;
9739 initSR(sr, true);
9740
9741 setDNSSECValidation(sr, DNSSECMode::Process);
9742
9743 primeHints();
9744 const DNSName target("com.");
9745 testkeysset_t keys;
9746
9747 auto luaconfsCopy = g_luaconfs.getCopy();
9748 luaconfsCopy.dsAnchors.clear();
9749 g_luaconfs.setState(luaconfsCopy);
9750
9751 size_t queriesCount = 0;
9752
deca7d8f 9753 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f4de85a3
RG
9754 queriesCount++;
9755
9756 DNSName auth = domain;
9757 auth.chopOff();
9758
9759 if (type == QType::DS || type == QType::DNSKEY) {
9760 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9761 }
9762 else {
9763 setLWResult(res, RCode::NoError, true, false, true);
9764 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9765 return 1;
9766 }
9767
9768 return 0;
9769 });
9770
9771 vector<DNSRecord> ret;
9772 /* first query does not require validation */
9773 sr->setDNSSECValidationRequested(false);
9774 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9775 BOOST_CHECK_EQUAL(res, RCode::NoError);
9776 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9777 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9778 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd 9779 /* check that the entry has not been negatively cached */
28364e4b 9780 const NegCache::NegCacheEntry* ne = nullptr;
b25712fd 9781 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9782 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9783 BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
9784 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9785 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 0);
9786 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
9787 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9788
9789 ret.clear();
9790 /* second one _does_ require validation */
9791 sr->setDNSSECValidationRequested(true);
9792 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9793 BOOST_CHECK_EQUAL(res, RCode::NoError);
9794 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9795 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9796 BOOST_CHECK_EQUAL(queriesCount, 1);
28364e4b
RG
9797 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9798 BOOST_CHECK_EQUAL(ne->d_validationState, Insecure);
9799 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9800 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 0);
9801 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
9802 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9803}
9804
9805BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
9806 /*
9807 Validation is optional, and the first query does not ask for it,
9808 so the answer is negatively cached as Indeterminate.
9809 The second query asks for validation, answer should be marked as
9810 Bogus.
9811 */
9812 std::unique_ptr<SyncRes> sr;
9813 initSR(sr, true);
9814
9815 setDNSSECValidation(sr, DNSSECMode::Process);
9816
9817 primeHints();
9818 const DNSName target("com.");
9819 testkeysset_t keys;
9820
9821 auto luaconfsCopy = g_luaconfs.getCopy();
9822 luaconfsCopy.dsAnchors.clear();
9823 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9824 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9825 g_luaconfs.setState(luaconfsCopy);
9826
9827 size_t queriesCount = 0;
9828
deca7d8f 9829 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
f4de85a3
RG
9830 queriesCount++;
9831
9832 DNSName auth = domain;
9833 auth.chopOff();
9834
9835 if (type == QType::DS || type == QType::DNSKEY) {
9836 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9837 }
9838 else {
9839 setLWResult(res, RCode::NoError, true, false, true);
9840 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9841 addRRSIG(keys, res->d_records, domain, 300);
9842 /* no denial */
9843 return 1;
9844 }
9845
9846 return 0;
9847 });
9848
9849 vector<DNSRecord> ret;
9850 /* first query does not require validation */
9851 sr->setDNSSECValidationRequested(false);
9852 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9853 BOOST_CHECK_EQUAL(res, RCode::NoError);
9854 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9855 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9856 BOOST_CHECK_EQUAL(queriesCount, 1);
28364e4b 9857 const NegCache::NegCacheEntry* ne = nullptr;
b25712fd 9858 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9859 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9860 BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
9861 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9862 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9863 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
9864 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9865
9866 ret.clear();
9867 /* second one _does_ require validation */
9868 sr->setDNSSECValidationRequested(true);
9869 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9870 BOOST_CHECK_EQUAL(res, RCode::NoError);
9871 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9872 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9873 BOOST_CHECK_EQUAL(queriesCount, 4);
28364e4b
RG
9874 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9875 BOOST_CHECK_EQUAL(ne->d_validationState, Bogus);
9876 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9877 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9878 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
9879 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9880}
9881
429ce1da
PL
9882BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
9883 g_lowercaseOutgoing = true;
9884 std::unique_ptr<SyncRes> sr;
9885 initSR(sr);
9886
9887 primeHints();
9888
9889 vector<DNSName> sentOutQnames;
9890
9891 const DNSName target("WWW.POWERDNS.COM");
9892 const DNSName cname("WWW.PowerDNS.org");
9893
deca7d8f 9894 sr->setAsyncCallback([target, cname, &sentOutQnames](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
429ce1da
PL
9895
9896 sentOutQnames.push_back(domain);
9897
9898 if (isRootServer(ip)) {
9899 if (domain == target) {
9900 setLWResult(res, 0, false, false, true);
9901 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
9902 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
9903 return 1;
9904 }
9905 if (domain == cname) {
9906 setLWResult(res, 0, false, false, true);
9907 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
9908 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
9909 return 1;
9910 }
9911 } else if (ip == ComboAddress("192.0.2.1:53")) {
9912 if (domain == target) {
9913 setLWResult(res, 0, true, false, false);
9914 addRecordToLW(res, domain, QType::CNAME, cname.toString());
9915 return 1;
9916 }
9917 } else if (ip == ComboAddress("192.0.2.2:53")) {
9918 if (domain == cname) {
9919 setLWResult(res, 0, true, false, false);
9920 addRecordToLW(res, domain, QType::A, "127.0.0.1");
9921 return 1;
9922 }
9923 }
9924 return 0;
9925 });
9926
9927 vector<DNSRecord> ret;
9928 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9929
9930 BOOST_CHECK_EQUAL(res, RCode::NoError);
9931
9932 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9933 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
9934
9935 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
9936 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
9937 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
9938 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
9939 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
9940
9941 g_lowercaseOutgoing = false;
9942}
9943
4d787d30
PL
9944BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
9945 std::unique_ptr<SyncRes> sr;
9946 initSR(sr, true);
9947
9948 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9949
9950 primeHints();
9951 const DNSName target("com.");
9952 testkeysset_t keys, keys2;
9953
9954 auto luaconfsCopy = g_luaconfs.getCopy();
9955 luaconfsCopy.dsAnchors.clear();
9956 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9957 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9958 g_luaconfs.setState(luaconfsCopy);
9959
9960 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9961 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9962 // But add the existing root key otherwise no RRSIG can be created
9963 auto rootkey = keys.find(g_rootdnsname);
9964 keys2.insert(*rootkey);
9965
deca7d8f 9966 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4d787d30
PL
9967 DNSName auth = domain;
9968 auth.chopOff();
9969 if (type == QType::DS || type == QType::DNSKEY) {
9970 if (domain == target) {
9971 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9972 return 0;
9973 }
9974 }
9975 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9976 }
9977 return 0;
9978 });
9979
9980 dsmap_t ds;
9981 auto state = sr->getDSRecords(target, ds, false, 0, false);
9982 BOOST_CHECK_EQUAL(state, Secure);
9983 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9984 for (const auto& i : ds) {
9985 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9986 }
9987}
9988
9989BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
9990 std::unique_ptr<SyncRes> sr;
9991 initSR(sr, true);
9992
9993 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9994
9995 primeHints();
9996 const DNSName target("com.");
9997 testkeysset_t keys, keys2, keys3;
9998
9999 auto luaconfsCopy = g_luaconfs.getCopy();
10000 luaconfsCopy.dsAnchors.clear();
10001 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10002 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10003 g_luaconfs.setState(luaconfsCopy);
10004
10005 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10006 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
10007 // But add the existing root key otherwise no RRSIG can be created
10008 auto rootkey = keys.find(g_rootdnsname);
10009 keys2.insert(*rootkey);
10010
10011 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
10012 // But add the existing root key otherwise no RRSIG can be created
10013 keys3.insert(*rootkey);
10014
deca7d8f 10015 sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4d787d30
PL
10016 DNSName auth = domain;
10017 auth.chopOff();
10018 if (type == QType::DS || type == QType::DNSKEY) {
10019 if (domain == target) {
10020 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10021 return 0;
10022 }
10023 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
10024 return 0;
10025 }
10026 }
10027 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10028 }
10029 return 0;
10030 });
10031
10032 dsmap_t ds;
10033 auto state = sr->getDSRecords(target, ds, false, 0, false);
10034 BOOST_CHECK_EQUAL(state, Secure);
10035 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10036 for (const auto& i : ds) {
10037 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
10038 }
10039}
10040
10041BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
10042 std::unique_ptr<SyncRes> sr;
10043 initSR(sr, true);
10044
10045 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10046
10047 primeHints();
10048 const DNSName target("com.");
10049 testkeysset_t keys, keys2, keys3;
10050
10051 auto luaconfsCopy = g_luaconfs.getCopy();
10052 luaconfsCopy.dsAnchors.clear();
10053 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10054 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10055 g_luaconfs.setState(luaconfsCopy);
10056
10057 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10058 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
10059 // But add the existing root key otherwise no RRSIG can be created
10060 auto rootkey = keys.find(g_rootdnsname);
10061 keys2.insert(*rootkey);
10062
10063 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
10064 // But add the existing root key otherwise no RRSIG can be created
10065 keys3.insert(*rootkey);
10066
deca7d8f 10067 sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4d787d30
PL
10068 DNSName auth = domain;
10069 auth.chopOff();
10070 if (type == QType::DS || type == QType::DNSKEY) {
10071 if (domain == target) {
10072 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10073 return 0;
10074 }
10075 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
10076 return 0;
10077 }
10078 }
10079 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10080 }
10081 return 0;
10082 });
10083
10084 dsmap_t ds;
10085 auto state = sr->getDSRecords(target, ds, false, 0, false);
10086 BOOST_CHECK_EQUAL(state, Secure);
10087 BOOST_REQUIRE_EQUAL(ds.size(), 2);
10088 for (const auto& i : ds) {
10089 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
10090 }
10091}
10092
77cb3d33 10093#ifdef HAVE_BOTAN
4d787d30
PL
10094BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) {
10095 std::unique_ptr<SyncRes> sr;
10096 initSR(sr, true);
10097
10098 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10099
10100 primeHints();
10101 const DNSName target("com.");
10102 testkeysset_t keys, keys2;
10103
10104 auto luaconfsCopy = g_luaconfs.getCopy();
10105 luaconfsCopy.dsAnchors.clear();
10106 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10107 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys);
10108 g_luaconfs.setState(luaconfsCopy);
10109
10110 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10111 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
10112 // But add the existing root key otherwise no RRSIG can be created
10113 auto rootkey = keys.find(g_rootdnsname);
10114 keys2.insert(*rootkey);
10115
deca7d8f 10116 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4d787d30
PL
10117 DNSName auth = domain;
10118 auth.chopOff();
10119 if (type == QType::DS || type == QType::DNSKEY) {
10120 if (domain == target) {
10121 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10122 return 0;
10123 }
10124 }
10125 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10126 }
10127 return 0;
10128 });
10129
10130 dsmap_t ds;
10131 auto state = sr->getDSRecords(target, ds, false, 0, false);
10132 BOOST_CHECK_EQUAL(state, Secure);
10133 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10134 for (const auto& i : ds) {
10135 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
10136 }
10137}
10138
10139BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) {
10140 std::unique_ptr<SyncRes> sr;
10141 initSR(sr, true);
10142
10143 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10144
10145 primeHints();
10146 const DNSName target("com.");
10147 testkeysset_t keys, keys2;
10148
10149 auto luaconfsCopy = g_luaconfs.getCopy();
10150 luaconfsCopy.dsAnchors.clear();
10151 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10152 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10153 g_luaconfs.setState(luaconfsCopy);
10154
10155 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10156 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
10157 // But add the existing root key otherwise no RRSIG can be created
10158 auto rootkey = keys.find(g_rootdnsname);
10159 keys2.insert(*rootkey);
10160
deca7d8f 10161 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4d787d30
PL
10162 DNSName auth = domain;
10163 auth.chopOff();
10164 if (type == QType::DS || type == QType::DNSKEY) {
10165 if (domain == target) {
10166 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10167 return 0;
10168 }
10169 }
10170 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10171 }
10172 return 0;
10173 });
10174
10175 dsmap_t ds;
10176 auto state = sr->getDSRecords(target, ds, false, 0, false);
10177 BOOST_CHECK_EQUAL(state, Secure);
10178 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10179 for (const auto& i : ds) {
10180 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
10181 }
10182}
10183
10184BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) {
10185 std::unique_ptr<SyncRes> sr;
10186 initSR(sr, true);
10187
10188 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10189
10190 primeHints();
10191 const DNSName target("com.");
10192 testkeysset_t keys, keys2;
10193
10194 auto luaconfsCopy = g_luaconfs.getCopy();
10195 luaconfsCopy.dsAnchors.clear();
10196 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10197 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys);
10198 g_luaconfs.setState(luaconfsCopy);
10199
10200 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10201 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
10202 // But add the existing root key otherwise no RRSIG can be created
10203 auto rootkey = keys.find(g_rootdnsname);
10204 keys2.insert(*rootkey);
10205
deca7d8f 10206 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
4d787d30
PL
10207 DNSName auth = domain;
10208 auth.chopOff();
10209 if (type == QType::DS || type == QType::DNSKEY) {
10210 if (domain == target) {
10211 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10212 return 0;
10213 }
10214 }
10215 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10216 }
10217 return 0;
10218 });
10219
10220 dsmap_t ds;
10221 auto state = sr->getDSRecords(target, ds, false, 0, false);
10222 BOOST_CHECK_EQUAL(state, Secure);
10223 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10224 for (const auto& i : ds) {
10225 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST);
10226 }
10227}
10228#endif // HAVE_BOTAN110
10229
d6e797b8
RG
10230/*
10231// cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
10232
648bcbd1 10233- check out of band support
d6e797b8 10234
648bcbd1 10235- check preoutquery
d6e797b8 10236
30ee601a
RG
10237*/
10238
10239BOOST_AUTO_TEST_SUITE_END()