]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/test-syncres_cc.cc
Merge pull request #7475 from omoerbeek/mydns-no-infinite-loop
[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
3fe06137 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, const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const std::set<uint16_t>& exportTypes, 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) {
32122aab 95 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
30ee601a
RG
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) {
32122aab 157 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
8455425c
RG
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
269ac73d 203static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false, bool validpacket=true)
30ee601a
RG
204{
205 res->d_rcode = rcode;
206 res->d_aabit = aa;
207 res->d_tcbit = tc;
208 res->d_haveEDNS = edns;
269ac73d 209 res->d_validpacket = validpacket;
30ee601a
RG
210}
211
d6e797b8
RG
212static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
213{
214 addRecordToList(res->d_records, name, type, content, place, ttl);
30ee601a
RG
215}
216
217static void addRecordToLW(LWResult* res, const std::string& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
218{
219 addRecordToLW(res, DNSName(name), type, content, place, ttl);
220}
221
222static bool isRootServer(const ComboAddress& ip)
223{
8455425c
RG
224 if (ip.isIPv4()) {
225 for (size_t idx = 0; idx < rootIps4Count; idx++) {
226 if (ip.toString() == rootIps4[idx]) {
227 return true;
228 }
30ee601a
RG
229 }
230 }
8455425c
RG
231 else {
232 for (size_t idx = 0; idx < rootIps6Count; idx++) {
233 if (ip.toString() == rootIps6[idx]) {
234 return true;
235 }
30ee601a
RG
236 }
237 }
8455425c 238
30ee601a
RG
239 return false;
240}
241
1e2e06f1 242static 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, boost::optional<time_t> now=boost::none)
8455425c 243{
1e2e06f1
RG
244 if (!now) {
245 now = time(nullptr);
246 }
8455425c
RG
247 DNSKEYRecordContent drc = dpk.getDNSKEY();
248 const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
249
250 rrc.d_type = signQType;
251 rrc.d_labels = signQName.countLabels() - signQName.isWildcard();
252 rrc.d_originalttl = signTTL;
1e2e06f1
RG
253 rrc.d_siginception = inception ? *inception : (*now - 10);
254 rrc.d_sigexpire = *now + sigValidity;
8455425c
RG
255 rrc.d_signer = signer;
256 rrc.d_tag = 0;
257 rrc.d_tag = drc.getTag();
3d5ebf10 258 rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
8455425c
RG
259
260 std::string msg = getMessageForRRSET(signQName, rrc, toSign);
261
262 rrc.d_signature = rc->sign(msg);
263}
264
b7f378d1
RG
265typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t;
266
1e2e06f1 267static 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, boost::optional<time_t> now=boost::none)
8455425c
RG
268{
269 if (records.empty()) {
5374b03b 270 return false;
8455425c
RG
271 }
272
273 const auto it = keys.find(signer);
274 if (it == keys.cend()) {
86f1af1c 275 throw std::runtime_error("No DNSKEY found for " + signer.toLogString() + ", unable to compute the requested RRSIG");
8455425c
RG
276 }
277
278 size_t recordsCount = records.size();
279 const DNSName& name = records[recordsCount-1].d_name;
280 const uint16_t type = records[recordsCount-1].d_type;
281
282 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
283 for (const auto record : records) {
284 if (record.d_name == name && record.d_type == type) {
285 recordcontents.push_back(record.d_content);
286 }
287 }
288
289 RRSIGRecordContent rrc;
1e2e06f1 290 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, boost::none, now);
3d5ebf10
RG
291 if (broken) {
292 rrc.d_signature[0] ^= 42;
293 }
8455425c
RG
294
295 DNSRecord rec;
dbbef467 296 rec.d_type = QType::RRSIG;
8455425c
RG
297 rec.d_place = records[recordsCount-1].d_place;
298 rec.d_name = records[recordsCount-1].d_name;
dbbef467 299 rec.d_ttl = records[recordsCount-1].d_ttl;
8455425c
RG
300
301 rec.d_content = std::make_shared<RRSIGRecordContent>(rrc);
302 records.push_back(rec);
5374b03b
RG
303
304 return true;
8455425c
RG
305}
306
b7f378d1 307static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records)
8455425c
RG
308{
309 const auto it = keys.find(signer);
310 if (it == keys.cend()) {
86f1af1c 311 throw std::runtime_error("No DNSKEY found for " + signer.toLogString());
8455425c
RG
312 }
313
314 DNSRecord rec;
315 rec.d_place = DNSResourceRecord::ANSWER;
316 rec.d_name = signer;
317 rec.d_type = QType::DNSKEY;
318 rec.d_ttl = ttl;
319
b7f378d1 320 rec.d_content = std::make_shared<DNSKEYRecordContent>(it->second.first.getDNSKEY());
8455425c
RG
321 records.push_back(rec);
322}
323
5374b03b 324static bool addDS(const DNSName& domain, uint32_t ttl, std::vector<DNSRecord>& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY)
8455425c 325{
b7f378d1
RG
326 const auto it = keys.find(domain);
327 if (it == keys.cend()) {
5374b03b 328 return false;
8455425c
RG
329 }
330
b7f378d1
RG
331 DNSRecord rec;
332 rec.d_name = domain;
333 rec.d_type = QType::DS;
a53e8fe3 334 rec.d_place = place;
b7f378d1
RG
335 rec.d_ttl = ttl;
336 rec.d_content = std::make_shared<DSRecordContent>(it->second.second);
8455425c 337
b7f378d1 338 records.push_back(rec);
5374b03b 339 return true;
8455425c
RG
340}
341
342static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
343{
344 NSECRecordContent nrc;
345 nrc.d_next = next;
27d4a65b
RG
346 for (const auto& type : types) {
347 nrc.set(type);
348 }
8455425c
RG
349
350 DNSRecord rec;
351 rec.d_name = domain;
352 rec.d_ttl = ttl;
353 rec.d_type = QType::NSEC;
27d4a65b 354 rec.d_content = std::make_shared<NSECRecordContent>(std::move(nrc));
8455425c
RG
355 rec.d_place = DNSResourceRecord::AUTHORITY;
356
357 records.push_back(rec);
358}
359
95823c07
RG
360static 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)
361{
362 NSEC3RecordContent nrc;
363 nrc.d_algorithm = 1;
364 nrc.d_flags = 0;
365 nrc.d_iterations = iterations;
366 nrc.d_salt = salt;
367 nrc.d_nexthash = hashedNext;
27d4a65b
RG
368 for (const auto& type : types) {
369 nrc.set(type);
370 }
95823c07
RG
371
372 DNSRecord rec;
373 rec.d_name = hashedName;
374 rec.d_ttl = ttl;
375 rec.d_type = QType::NSEC3;
27d4a65b 376 rec.d_content = std::make_shared<NSEC3RecordContent>(std::move(nrc));
95823c07
RG
377 rec.d_place = DNSResourceRecord::AUTHORITY;
378
379 records.push_back(rec);
380}
381
b7c40613 382static 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
383{
384 static const std::string salt = "deadbeef";
95823c07
RG
385 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
386
9b061cf5 387 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, next, salt, iterations, types, ttl, records);
95823c07
RG
388}
389
b7c40613 390static 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
391{
392 static const std::string salt = "deadbeef";
95823c07 393 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
95823c07
RG
394 std::string hashedNext(hashed);
395 incrementHash(hashedNext);
396 decrementHash(hashed);
397
9b061cf5 398 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, hashedNext, salt, iterations, types, ttl, records);
95823c07
RG
399}
400
b7f378d1 401static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys)
8455425c
RG
402{
403 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(algo));
b7f378d1 404 dcke->create((algo <= 10) ? 2048 : dcke->getBits());
8455425c
RG
405 DNSSECPrivateKey dpk;
406 dpk.d_flags = 256;
407 dpk.setKey(dcke);
8455425c 408 DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest);
b7f378d1
RG
409 keys[name] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk,ds);
410}
411
412static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map<DNSName,dsmap_t>& dsAnchors)
413{
414 generateKeyMaterial(name, algo, digest, keys);
415 dsAnchors[name].insert(keys[name].second);
8455425c
RG
416}
417
f4de85a3 418static int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut=true)
5374b03b
RG
419{
420 if (type == QType::DS) {
421 auth.chopOff();
422
423 setLWResult(res, 0, true, false, true);
424
425 if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) {
426 addRRSIG(keys, res->d_records, auth, 300);
427 }
428 else {
429 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
430
431 /* if the auth zone is signed, we need to provide a secure denial */
432 const auto it = keys.find(auth);
433 if (it != keys.cend()) {
434 /* sign the SOA */
435 addRRSIG(keys, res->d_records, auth, 300);
436 /* add a NSEC denying the DS */
f4de85a3
RG
437 std::set<uint16_t> types = { QType::NSEC };
438 if (proveCut) {
439 types.insert(QType::NS);
440 }
441
442 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
5374b03b
RG
443 addRRSIG(keys, res->d_records, auth, 300);
444 }
445 }
446
447 return 1;
448 }
449
450 if (type == QType::DNSKEY) {
451 setLWResult(res, 0, true, false, true);
dbbef467
RG
452 addDNSKEY(keys, domain, 300, res->d_records);
453 addRRSIG(keys, res->d_records, domain, 300);
5374b03b
RG
454 return 1;
455 }
456
457 return 0;
458}
459
30ee601a
RG
460/* Real tests */
461
462BOOST_AUTO_TEST_SUITE(syncres_cc)
463
464BOOST_AUTO_TEST_CASE(test_root_primed) {
465 std::unique_ptr<SyncRes> sr;
895449a5 466 initSR(sr);
30ee601a
RG
467
468 primeHints();
895449a5 469
4d2be65d 470 const DNSName target("a.root-servers.net.");
30ee601a 471
4d2be65d 472 /* we are primed, we should be able to resolve A a.root-servers.net. without any query */
30ee601a 473 vector<DNSRecord> ret;
4d2be65d 474 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 475 BOOST_CHECK_EQUAL(res, RCode::NoError);
4d2be65d
RG
476 BOOST_REQUIRE_EQUAL(ret.size(), 1);
477 BOOST_CHECK(ret[0].d_type == QType::A);
478 BOOST_CHECK_EQUAL(ret[0].d_name, target);
479
480 ret.clear();
481 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1
RG
482 BOOST_CHECK_EQUAL(res, RCode::NoError);
483 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
4d2be65d
RG
484 BOOST_REQUIRE_EQUAL(ret.size(), 1);
485 BOOST_CHECK(ret[0].d_type == QType::AAAA);
486 BOOST_CHECK_EQUAL(ret[0].d_name, target);
4d2be65d
RG
487}
488
489BOOST_AUTO_TEST_CASE(test_root_primed_ns) {
490 std::unique_ptr<SyncRes> sr;
895449a5 491 initSR(sr);
4d2be65d
RG
492
493 primeHints();
494 const DNSName target(".");
495
496 /* we are primed, but we should not be able to NS . without any query
497 because the . NS entry is not stored as authoritative */
498
499 size_t queriesCount = 0;
500
0bd2e252 501 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, LWResult* res, bool* chained) {
4d2be65d
RG
502 queriesCount++;
503
504 if (domain == target && type == QType::NS) {
505
506 setLWResult(res, 0, true, false, true);
8455425c 507 char addr[] = "a.root-servers.net.";
4d2be65d 508 for (char idx = 'a'; idx <= 'm'; idx++) {
8455425c
RG
509 addr[0] = idx;
510 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4d2be65d
RG
511 }
512
513 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
514 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
515
516 return 1;
517 }
518
519 return 0;
520 });
521
522 vector<DNSRecord> ret;
523 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1 524 BOOST_CHECK_EQUAL(res, RCode::NoError);
4d2be65d
RG
525 BOOST_REQUIRE_EQUAL(ret.size(), 13);
526 BOOST_CHECK_EQUAL(queriesCount, 1);
30ee601a
RG
527}
528
529BOOST_AUTO_TEST_CASE(test_root_not_primed) {
530 std::unique_ptr<SyncRes> sr;
895449a5 531 initSR(sr);
30ee601a
RG
532
533 size_t queriesCount = 0;
534
0bd2e252 535 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, LWResult* res, bool* chained) {
30ee601a
RG
536 queriesCount++;
537
538 if (domain == g_rootdnsname && type == QType::NS) {
539 setLWResult(res, 0, true, false, true);
540 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
541 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
542 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
543
544 return 1;
545 }
546
547 return 0;
548 });
549
550 /* we are not primed yet, so SyncRes will have to call primeHints()
551 then call getRootNS(), for which at least one of the root servers needs to answer */
552 vector<DNSRecord> ret;
553 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
b7f378d1 554 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
555 BOOST_CHECK_EQUAL(ret.size(), 1);
556 BOOST_CHECK_EQUAL(queriesCount, 2);
557}
558
559BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
560 std::unique_ptr<SyncRes> sr;
895449a5 561 initSR(sr);
30ee601a
RG
562 std::set<ComboAddress> downServers;
563
564 /* we are not primed yet, so SyncRes will have to call primeHints()
565 then call getRootNS(), for which at least one of the root servers needs to answer.
566 None will, so it should ServFail.
567 */
0bd2e252 568 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, LWResult* res, bool* chained) {
30ee601a
RG
569
570 downServers.insert(ip);
571 return 0;
572 });
573
574 vector<DNSRecord> ret;
575 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
f58c8379 576 BOOST_CHECK_EQUAL(res, RCode::ServFail);
30ee601a
RG
577 BOOST_CHECK_EQUAL(ret.size(), 0);
578 BOOST_CHECK(downServers.size() > 0);
579 /* we explicitly refuse to mark the root servers down */
580 for (const auto& server : downServers) {
a712cb56 581 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
30ee601a
RG
582 }
583}
584
585BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
586 std::unique_ptr<SyncRes> sr;
895449a5 587 initSR(sr);
30ee601a
RG
588
589 ComboAddress noEDNSServer;
590 size_t queriesWithEDNS = 0;
591 size_t queriesWithoutEDNS = 0;
592
0bd2e252 593 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, LWResult* res, bool* chained) {
30ee601a
RG
594 if (EDNS0Level != 0) {
595 queriesWithEDNS++;
596 noEDNSServer = ip;
597
598 setLWResult(res, RCode::FormErr);
599 return 1;
600 }
601
602 queriesWithoutEDNS++;
603
604 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
605 setLWResult(res, 0, true, false, false);
606 addRecordToLW(res, domain, QType::A, "192.0.2.1");
607 return 1;
608 }
609
610 return 0;
611 });
612
613 primeHints();
614
615 /* fake that the root NS doesn't handle EDNS, check that we fallback */
616 vector<DNSRecord> ret;
617 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 618 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
619 BOOST_CHECK_EQUAL(ret.size(), 1);
620 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
621 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
a712cb56
RG
622 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
623 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
30ee601a
RG
624}
625
27ae17df
RG
626BOOST_AUTO_TEST_CASE(test_edns_formerr_but_edns_enabled) {
627 std::unique_ptr<SyncRes> sr;
628 initSR(sr);
629
630 /* in this test, the auth answers with FormErr to an EDNS-enabled
631 query, but the response does contain EDNS so we should not mark
632 it as EDNS ignorant or intolerant.
633 */
634 size_t queriesWithEDNS = 0;
635 size_t queriesWithoutEDNS = 0;
636 std::set<ComboAddress> usedServers;
637
638 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &usedServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
639
640 if (EDNS0Level > 0) {
641 queriesWithEDNS++;
642 }
643 else {
644 queriesWithoutEDNS++;
645 }
646 usedServers.insert(ip);
647
648 if (type == QType::DNAME) {
649 setLWResult(res, RCode::FormErr);
650 if (EDNS0Level > 0) {
651 res->d_haveEDNS = true;
652 }
653 return 1;
654 }
655
656 return 0;
657 });
658
659 primeHints();
660
661 vector<DNSRecord> ret;
662 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::DNAME), QClass::IN, ret);
663 BOOST_CHECK_EQUAL(res, RCode::ServFail);
664 BOOST_CHECK_EQUAL(ret.size(), 0);
665 BOOST_CHECK_EQUAL(queriesWithEDNS, 26);
666 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 0);
667 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 26);
668 BOOST_CHECK_EQUAL(usedServers.size(), 26);
669 for (const auto& server : usedServers) {
670 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK);
671 }
672}
673
25e654f7
RG
674BOOST_AUTO_TEST_CASE(test_meta_types) {
675 std::unique_ptr<SyncRes> sr;
676 initSR(sr);
677
678 static const std::set<uint16_t> invalidTypes = { 128, QType::AXFR, QType::IXFR, QType::RRSIG, QType::NSEC3, QType::OPT, QType::TSIG, QType::TKEY, QType::MAILA, QType::MAILB, 65535 };
679
680 for (const auto qtype : invalidTypes) {
681 size_t queriesCount = 0;
682
683 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, LWResult* res, bool* chained) {
684
685 queriesCount++;
686 return 0;
687 });
688
689 primeHints();
690
691 vector<DNSRecord> ret;
692 int res = sr->beginResolve(DNSName("powerdns.com."), QType(qtype), QClass::IN, ret);
693 BOOST_CHECK_EQUAL(res, -1);
694 BOOST_CHECK_EQUAL(ret.size(), 0);
695 BOOST_CHECK_EQUAL(queriesCount, 0);
696 }
697}
698
30ee601a
RG
699BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
700 std::unique_ptr<SyncRes> sr;
895449a5 701 initSR(sr);
30ee601a 702
0bd2e252 703 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, LWResult* res, bool* chained) {
30ee601a
RG
704 if (!doTCP) {
705 setLWResult(res, 0, false, true, false);
706 return 1;
707 }
708 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
709 setLWResult(res, 0, true, false, false);
710 addRecordToLW(res, domain, QType::A, "192.0.2.1");
711 return 1;
712 }
713
714 return 0;
715 });
716
717 primeHints();
718
719 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
720 vector<DNSRecord> ret;
721 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 722 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
723}
724
3337c2f7
RG
725BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
726 std::unique_ptr<SyncRes> sr;
895449a5 727 initSR(sr);
3337c2f7
RG
728
729 size_t tcpQueriesCount = 0;
730
0bd2e252 731 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, LWResult* res, bool* chained) {
3337c2f7
RG
732 if (!doTCP) {
733 setLWResult(res, 0, true, true, false);
734 return 1;
735 }
736
737 /* first TCP query is answered with a TC response */
738 tcpQueriesCount++;
739 if (tcpQueriesCount == 1) {
740 setLWResult(res, 0, true, true, false);
741 }
742 else {
743 setLWResult(res, 0, true, false, false);
744 }
745
746 addRecordToLW(res, domain, QType::A, "192.0.2.1");
747 return 1;
748 });
749
750 primeHints();
751
752 vector<DNSRecord> ret;
753 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 754 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
755 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
756}
757
30ee601a
RG
758BOOST_AUTO_TEST_CASE(test_all_nss_down) {
759 std::unique_ptr<SyncRes> sr;
895449a5 760 initSR(sr);
30ee601a
RG
761 std::set<ComboAddress> downServers;
762
763 primeHints();
764
0bd2e252 765 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, LWResult* res, bool* chained) {
30ee601a
RG
766
767 if (isRootServer(ip)) {
8455425c 768 setLWResult(res, 0, false, false, true);
30ee601a
RG
769 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
770 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
771 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
772 return 1;
773 }
774 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 775 setLWResult(res, 0, false, false, true);
30ee601a
RG
776 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
777 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
778 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
779 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
780 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
781 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
782 return 1;
783 }
784 else {
785 downServers.insert(ip);
786 return 0;
787 }
788 });
789
ccb07d93
RG
790 DNSName target("powerdns.com.");
791
30ee601a 792 vector<DNSRecord> ret;
ccb07d93 793 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 794 BOOST_CHECK_EQUAL(res, RCode::ServFail);
30ee601a
RG
795 BOOST_CHECK_EQUAL(ret.size(), 0);
796 BOOST_CHECK_EQUAL(downServers.size(), 4);
797
606accb0 798 time_t now = sr->getNow().tv_sec;
30ee601a 799 for (const auto& server : downServers) {
a712cb56 800 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
606accb0 801 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
30ee601a
RG
802 }
803}
804
648bcbd1
RG
805BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
806 std::unique_ptr<SyncRes> sr;
895449a5 807 initSR(sr);
648bcbd1
RG
808 std::set<ComboAddress> downServers;
809
810 primeHints();
811
0bd2e252 812 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, LWResult* res, bool* chained) {
648bcbd1
RG
813
814 if (isRootServer(ip)) {
8455425c 815 setLWResult(res, 0, false, false, true);
648bcbd1
RG
816 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
817 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
818 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
819 return 1;
820 }
821 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 822 setLWResult(res, 0, false, false, true);
648bcbd1
RG
823 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
824 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
825 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
826 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
827 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
828 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
829 return 1;
830 }
831 else {
832 downServers.insert(ip);
b4c8789a 833 return 0;
648bcbd1
RG
834 }
835 });
836
837 /* exact same test than the previous one, except instead of a time out we fake a network error */
838 DNSName target("powerdns.com.");
839
840 vector<DNSRecord> ret;
841 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
842 BOOST_CHECK_EQUAL(res, RCode::ServFail);
843 BOOST_CHECK_EQUAL(ret.size(), 0);
844 BOOST_CHECK_EQUAL(downServers.size(), 4);
845
606accb0 846 time_t now = sr->getNow().tv_sec;
648bcbd1 847 for (const auto& server : downServers) {
a712cb56 848 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
606accb0 849 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
648bcbd1
RG
850 }
851}
852
b4c8789a
RG
853BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) {
854 std::unique_ptr<SyncRes> sr;
855 initSR(sr);
856
857 primeHints();
858
859 DNSName target("www.powerdns.com.");
860
0bd2e252 861 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, LWResult* res, bool* chained) {
b4c8789a
RG
862
863 if (isRootServer(ip)) {
864 setLWResult(res, 0, false, false, true);
865 if (domain == target) {
866 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
867 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
868 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
869 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
870 }
871 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
872 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
873 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
874 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
875 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
876 }
877 return 1;
878 }
879 else if (ip == ComboAddress("192.0.2.3:53")) {
880 setLWResult(res, 0, true, false, true);
881 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
882 if (type == QType::A) {
883 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
884 }
885 else if (type == QType::AAAA) {
886 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
887 }
888 }
889 else if (domain == target) {
890 if (type == QType::A) {
891 addRecordToLW(res, domain, QType::A, "192.0.2.1");
892 }
893 else if (type == QType::AAAA) {
894 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
895 }
896 }
897 return 1;
898 }
899 return 0;
900 });
901
902 vector<DNSRecord> ret;
903 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
904 BOOST_CHECK_EQUAL(res, RCode::NoError);
905 BOOST_CHECK_EQUAL(ret.size(), 1);
906}
907
648bcbd1
RG
908BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
909 std::unique_ptr<SyncRes> sr;
895449a5 910 initSR(sr);
648bcbd1
RG
911 std::set<ComboAddress> downServers;
912
913 primeHints();
914
0bd2e252 915 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, LWResult* res, bool* chained) {
648bcbd1
RG
916
917 if (isRootServer(ip)) {
8455425c 918 setLWResult(res, 0, false, false, true);
648bcbd1
RG
919 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
920 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
921 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
922 return 1;
923 }
924 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 925 setLWResult(res, 0, false, false, true);
648bcbd1
RG
926 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
927 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
928 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
929 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
930 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
931 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
932 return 1;
933 }
934 else {
935 if (downServers.size() < 3) {
936 /* only the last one will answer */
937 downServers.insert(ip);
938 return -2;
939 }
940 else {
941 setLWResult(res, 0, true, false, true);
942 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
943 return 1;
944 }
945 }
946 });
947
948 DNSName target("powerdns.com.");
949
950 vector<DNSRecord> ret;
951 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 952 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
953 BOOST_CHECK_EQUAL(ret.size(), 1);
954 BOOST_CHECK_EQUAL(downServers.size(), 3);
955
956 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
606accb0 957 time_t now = sr->getNow().tv_sec;
648bcbd1 958 for (const auto& server : downServers) {
a712cb56 959 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
606accb0 960 BOOST_CHECK(!SyncRes::isThrottled(now, server, target, QType::A));
648bcbd1
RG
961 }
962}
963
30ee601a
RG
964BOOST_AUTO_TEST_CASE(test_glued_referral) {
965 std::unique_ptr<SyncRes> sr;
895449a5 966 initSR(sr);
30ee601a
RG
967
968 primeHints();
969
970 const DNSName target("powerdns.com.");
971
0bd2e252 972 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, LWResult* res, bool* chained) {
30ee601a
RG
973 /* this will cause issue with qname minimization if we ever implement it */
974 if (domain != target) {
975 return 0;
976 }
977
978 if (isRootServer(ip)) {
8455425c 979 setLWResult(res, 0, false, false, true);
30ee601a
RG
980 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
981 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
982 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
983 return 1;
984 }
985 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 986 setLWResult(res, 0, false, false, true);
30ee601a
RG
987 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
988 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
989 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
990 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
991 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
992 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
993 return 1;
994 }
995 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")) {
996 setLWResult(res, 0, true, false, true);
997 addRecordToLW(res, target, QType::A, "192.0.2.4");
998 return 1;
999 }
1000 else {
1001 return 0;
1002 }
1003 });
1004
1005 vector<DNSRecord> ret;
1006 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1007 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 1008 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 1009 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
1010 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1011}
1012
1013BOOST_AUTO_TEST_CASE(test_glueless_referral) {
1014 std::unique_ptr<SyncRes> sr;
895449a5 1015 initSR(sr);
30ee601a
RG
1016
1017 primeHints();
1018
1019 const DNSName target("powerdns.com.");
1020
0bd2e252 1021 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, LWResult* res, bool* chained) {
30ee601a
RG
1022
1023 if (isRootServer(ip)) {
8455425c 1024 setLWResult(res, 0, false, false, true);
30ee601a
RG
1025
1026 if (domain.isPartOf(DNSName("com."))) {
1027 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1028 } else if (domain.isPartOf(DNSName("org."))) {
1029 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1030 }
1031 else {
1032 setLWResult(res, RCode::NXDomain, false, false, true);
1033 return 1;
1034 }
1035
1036 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1037 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1038 return 1;
1039 }
1040 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
1041 if (domain == target) {
8455425c 1042 setLWResult(res, 0, false, false, true);
30ee601a
RG
1043 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1044 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1045 return 1;
1046 }
1047 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
1048 setLWResult(res, 0, true, false, true);
1049 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
1050 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
1051 return 1;
1052 }
1053 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
1054 setLWResult(res, 0, true, false, true);
1055 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
1056 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
1057 return 1;
1058 }
1059
1060 setLWResult(res, RCode::NXDomain, false, false, true);
1061 return 1;
1062 }
1063 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")) {
1064 setLWResult(res, 0, true, false, true);
1065 addRecordToLW(res, target, QType::A, "192.0.2.4");
1066 return 1;
1067 }
1068 else {
1069 return 0;
1070 }
1071 });
1072
1073 vector<DNSRecord> ret;
1074 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1075 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 1076 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 1077 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
1078 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1079}
1080
e9f9b8ec
RG
1081BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
1082 std::unique_ptr<SyncRes> sr;
895449a5 1083 initSR(sr);
e9f9b8ec
RG
1084
1085 primeHints();
1086
1087 const DNSName target("powerdns.com.");
9065eb05 1088 SyncRes::addEDNSDomain(target);
e9f9b8ec
RG
1089
1090 EDNSSubnetOpts incomingECS;
1091 incomingECS.source = Netmask("192.0.2.128/32");
2fe3354d 1092 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
e9f9b8ec 1093
0bd2e252 1094 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, LWResult* res, bool* chained) {
e9f9b8ec
RG
1095
1096 BOOST_REQUIRE(srcmask);
1097 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1098 return 0;
1099 });
1100
1101 vector<DNSRecord> ret;
1102 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 1103 BOOST_CHECK_EQUAL(res, RCode::ServFail);
e9f9b8ec
RG
1104}
1105
1106BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
1107 std::unique_ptr<SyncRes> sr;
895449a5 1108 initSR(sr);
e9f9b8ec
RG
1109
1110 primeHints();
1111
1112 const DNSName target("powerdns.com.");
2fe3354d 1113 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
e9f9b8ec
RG
1114
1115 EDNSSubnetOpts incomingECS;
1116 incomingECS.source = Netmask("2001:DB8::FF/128");
2fe3354d 1117 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
e9f9b8ec 1118
0bd2e252 1119 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, LWResult* res, bool* chained) {
e9f9b8ec
RG
1120
1121 if (isRootServer(ip)) {
1122 BOOST_REQUIRE(!srcmask);
1123
8455425c 1124 setLWResult(res, 0, false, false, true);
e9f9b8ec
RG
1125 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1126 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1127 return 1;
1128 } else if (ip == ComboAddress("192.0.2.1:53")) {
1129
1130 BOOST_REQUIRE(srcmask);
1131 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1132
1133 setLWResult(res, 0, true, false, false);
1134 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1135 return 1;
1136 }
1137
1138 return 0;
1139 });
1140
1141 vector<DNSRecord> ret;
1142 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1143 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
1144 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1145 BOOST_CHECK(ret[0].d_type == QType::A);
1146 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1147}
1148
2fe3354d
CH
1149BOOST_AUTO_TEST_CASE(test_ecs_use_requestor) {
1150 std::unique_ptr<SyncRes> sr;
1151 initSR(sr);
1152
1153 primeHints();
1154
1155 const DNSName target("powerdns.com.");
1156 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1157 // No incoming ECS data
1158 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
1159
0bd2e252 1160 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, LWResult* res, bool* chained) {
2fe3354d
CH
1161
1162 if (isRootServer(ip)) {
1163 BOOST_REQUIRE(!srcmask);
1164
1165 setLWResult(res, 0, false, false, true);
1166 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1167 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1168 return 1;
1169 } else if (ip == ComboAddress("192.0.2.1:53")) {
1170
1171 BOOST_REQUIRE(srcmask);
1172 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1173
1174 setLWResult(res, 0, true, false, false);
1175 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1176 return 1;
1177 }
1178
1179 return 0;
1180 });
1181
1182 vector<DNSRecord> ret;
1183 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1184 BOOST_CHECK_EQUAL(res, RCode::NoError);
1185 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1186 BOOST_CHECK(ret[0].d_type == QType::A);
1187 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1188}
1189
1190BOOST_AUTO_TEST_CASE(test_ecs_use_scope_zero) {
1191 std::unique_ptr<SyncRes> sr;
1192 initSR(sr);
1193
1194 primeHints();
1195
1196 const DNSName target("powerdns.com.");
1197 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1198 SyncRes::clearEDNSLocalSubnets();
1199 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1200 // No incoming ECS data, Requestor IP not in ecs-add-for
1201 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
1202
0bd2e252 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, 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(), "127.0.0.1/32");
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) {
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("192.0.0.0/16");
1245 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1246
0bd2e252 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, 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(), "192.0.0.0/16");
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
1277BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask_zero) {
1278 std::unique_ptr<SyncRes> sr;
1279 initSR(sr);
1280
1281 primeHints();
1282
1283 const DNSName target("powerdns.com.");
1284 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1285 SyncRes::clearEDNSLocalSubnets();
1286 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1287 EDNSSubnetOpts incomingECS;
1288 incomingECS.source = Netmask("0.0.0.0/0");
1289 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1290
0bd2e252 1291 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, LWResult* res, bool* chained) {
2fe3354d
CH
1292
1293 if (isRootServer(ip)) {
1294 BOOST_REQUIRE(!srcmask);
1295
1296 setLWResult(res, 0, false, false, true);
1297 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1298 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1299 return 1;
1300 } else if (ip == ComboAddress("192.0.2.1:53")) {
1301
1302 BOOST_REQUIRE(srcmask);
1303 BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
1304
1305 setLWResult(res, 0, true, false, false);
1306 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1307 return 1;
1308 }
1309
1310 return 0;
1311 });
1312
1313 vector<DNSRecord> ret;
1314 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1315 BOOST_CHECK_EQUAL(res, RCode::NoError);
1316 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1317 BOOST_CHECK(ret[0].d_type == QType::A);
1318 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1319}
1320
778bcea6
RG
1321BOOST_AUTO_TEST_CASE(test_following_cname) {
1322 std::unique_ptr<SyncRes> sr;
895449a5 1323 initSR(sr);
778bcea6
RG
1324
1325 primeHints();
1326
1327 const DNSName target("cname.powerdns.com.");
1328 const DNSName cnameTarget("cname-target.powerdns.com");
1329
0bd2e252 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, LWResult* res, bool* chained) {
778bcea6
RG
1331
1332 if (isRootServer(ip)) {
8455425c 1333 setLWResult(res, 0, false, false, true);
778bcea6
RG
1334 addRecordToLW(res, domain, 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, 0, true, false, false);
1341 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1342 return 1;
1343 }
1344 else if (domain == cnameTarget) {
1345 setLWResult(res, 0, true, false, false);
1346 addRecordToLW(res, domain, QType::A, "192.0.2.2");
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);
b7f378d1 1357 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
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::A);
1362 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1363}
1364
9b061cf5
RG
1365BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
1366 std::unique_ptr<SyncRes> sr;
1367 initSR(sr);
1368
1369 primeHints();
1370
1371 const DNSName target("cname.powerdns.com.");
1372 const DNSName cnameTarget("cname-target.powerdns.com");
1373
0bd2e252 1374 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, LWResult* res, bool* chained) {
9b061cf5
RG
1375
1376 if (isRootServer(ip)) {
1377 setLWResult(res, 0, false, false, true);
1378 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1379 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1380 return 1;
1381 } else if (ip == ComboAddress("192.0.2.1:53")) {
1382
1383 if (domain == target) {
1384 setLWResult(res, RCode::NXDomain, true, false, false);
1385 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1386 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1387 } else if (domain == cnameTarget) {
1388 setLWResult(res, RCode::NXDomain, true, false, false);
1389 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1390 return 1;
1391 }
1392
1393 return 1;
1394 }
1395
1396 return 0;
1397 });
1398
1399 vector<DNSRecord> ret;
1400 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1401 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1402 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1403 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1404 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1405 BOOST_CHECK(ret[1].d_type == QType::SOA);
1406
1407 /* a second time, to check the cache */
1408 ret.clear();
1409 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1410 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1411 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1412 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1413 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1414 BOOST_CHECK(ret[1].d_type == QType::SOA);
1415}
1416
4fff116b
RG
1417BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1418 std::unique_ptr<SyncRes> sr;
895449a5 1419 initSR(sr);
4fff116b
RG
1420
1421 primeHints();
1422
1423 /* In this test we directly get the NS server for cname.powerdns.com.,
1424 and we don't know whether it's also authoritative for
1425 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1426 the additional A record for cname-target.powerdns.com. */
1427 const DNSName target("cname.powerdns.com.");
1428 const DNSName cnameTarget("cname-target.powerdns.com");
1429
0bd2e252 1430 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, LWResult* res, bool* chained) {
4fff116b
RG
1431
1432 if (isRootServer(ip)) {
1433
8455425c 1434 setLWResult(res, 0, false, false, true);
4fff116b
RG
1435
1436 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1437 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1438 return 1;
1439 } else if (ip == ComboAddress("192.0.2.1:53")) {
1440
1441 if (domain == target) {
1442 setLWResult(res, 0, true, false, false);
1443 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1444 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1445 return 1;
1446 } else if (domain == cnameTarget) {
1447 setLWResult(res, 0, true, false, false);
1448 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1449 return 1;
1450 }
1451
1452 return 1;
1453 }
1454
1455 return 0;
1456 });
1457
1458 vector<DNSRecord> ret;
1459 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1460 BOOST_CHECK_EQUAL(res, RCode::NoError);
4fff116b
RG
1461 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1462 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1463 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1464 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1465 BOOST_REQUIRE(ret[1].d_type == QType::A);
1466 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1467 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1468}
1469
778bcea6
RG
1470BOOST_AUTO_TEST_CASE(test_cname_loop) {
1471 std::unique_ptr<SyncRes> sr;
895449a5 1472 initSR(sr);
778bcea6
RG
1473
1474 primeHints();
1475
1476 size_t count = 0;
1477 const DNSName target("cname.powerdns.com.");
1478
0bd2e252 1479 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, LWResult* res, bool* chained) {
778bcea6
RG
1480
1481 count++;
1482
1483 if (isRootServer(ip)) {
778bcea6 1484
8455425c 1485 setLWResult(res, 0, false, false, true);
778bcea6
RG
1486 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1487 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1488 return 1;
1489 } else if (ip == ComboAddress("192.0.2.1:53")) {
1490
1491 if (domain == target) {
1492 setLWResult(res, 0, true, false, false);
1493 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1494 return 1;
1495 }
1496
1497 return 1;
1498 }
1499
1500 return 0;
1501 });
1502
1503 vector<DNSRecord> ret;
1504 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1505 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1506 BOOST_CHECK_GT(ret.size(), 0);
778bcea6 1507 BOOST_CHECK_EQUAL(count, 2);
e9f9b8ec
RG
1508}
1509
4fff116b
RG
1510BOOST_AUTO_TEST_CASE(test_cname_depth) {
1511 std::unique_ptr<SyncRes> sr;
895449a5 1512 initSR(sr);
4fff116b
RG
1513
1514 primeHints();
1515
1516 size_t depth = 0;
1517 const DNSName target("cname.powerdns.com.");
1518
0bd2e252 1519 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, LWResult* res, bool* chained) {
4fff116b
RG
1520
1521 if (isRootServer(ip)) {
4fff116b 1522
8455425c 1523 setLWResult(res, 0, false, false, true);
4fff116b
RG
1524 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1525 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1526 return 1;
1527 } else if (ip == ComboAddress("192.0.2.1:53")) {
1528
1529 setLWResult(res, 0, true, false, false);
1530 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1531 depth++;
1532 return 1;
1533 }
1534
1535 return 0;
1536 });
1537
1538 vector<DNSRecord> ret;
1539 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1540 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1541 BOOST_CHECK_EQUAL(ret.size(), depth);
4fff116b
RG
1542 /* we have an arbitrary limit at 10 when following a CNAME chain */
1543 BOOST_CHECK_EQUAL(depth, 10 + 2);
1544}
1545
d6e797b8
RG
1546BOOST_AUTO_TEST_CASE(test_time_limit) {
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("cname.powerdns.com.");
1554
0bd2e252 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, 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 /* Pretend that this query took 2000 ms */
1562 res->d_usec = 2000;
1563
1564 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1565 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1566 return 1;
1567 } else if (ip == ComboAddress("192.0.2.1:53")) {
1568
1569 setLWResult(res, 0, true, false, false);
1570 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1571 return 1;
1572 }
1573
1574 return 0;
1575 });
1576
1577 /* Set the maximum time to 1 ms */
1578 SyncRes::s_maxtotusec = 1000;
1579
1580 try {
1581 vector<DNSRecord> ret;
1582 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1583 BOOST_CHECK(false);
1584 }
1585 catch(const ImmediateServFailException& e) {
1586 }
1587 BOOST_CHECK_EQUAL(queries, 1);
1588}
1589
1590BOOST_AUTO_TEST_CASE(test_referral_depth) {
1591 std::unique_ptr<SyncRes> sr;
895449a5 1592 initSR(sr);
d6e797b8
RG
1593
1594 primeHints();
1595
1596 size_t queries = 0;
1597 const DNSName target("www.powerdns.com.");
1598
0bd2e252 1599 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, LWResult* res, bool* chained) {
d6e797b8
RG
1600
1601 queries++;
1602
1603 if (isRootServer(ip)) {
8455425c 1604 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1605
1606 if (domain == DNSName("www.powerdns.com.")) {
1607 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1608 }
1609 else if (domain == DNSName("ns.powerdns.com.")) {
1610 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1611 }
1612 else if (domain == DNSName("ns1.powerdns.org.")) {
1613 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1614 }
1615 else if (domain == DNSName("ns2.powerdns.org.")) {
1616 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1617 }
1618 else if (domain == DNSName("ns3.powerdns.org.")) {
1619 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1620 }
1621 else if (domain == DNSName("ns4.powerdns.org.")) {
1622 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1623 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1624 }
1625
1626 return 1;
1627 } else if (ip == ComboAddress("192.0.2.1:53")) {
1628
1629 setLWResult(res, 0, true, false, false);
1630 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1631 return 1;
1632 }
1633
1634 return 0;
1635 });
1636
1637 /* Set the maximum depth low */
1638 SyncRes::s_maxdepth = 10;
1639
1640 try {
1641 vector<DNSRecord> ret;
1642 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1643 BOOST_CHECK(false);
1644 }
1645 catch(const ImmediateServFailException& e) {
1646 }
1647}
1648
1649BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1650 std::unique_ptr<SyncRes> sr;
895449a5 1651 initSR(sr);
d6e797b8
RG
1652
1653 primeHints();
1654
1655 size_t queries = 0;
1656 const DNSName target("cname.powerdns.com.");
1657
0bd2e252 1658 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, LWResult* res, bool* chained) {
d6e797b8
RG
1659
1660 queries++;
1661
1662 if (isRootServer(ip)) {
1663
8455425c 1664 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1665 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1666 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1667 return 1;
1668 } else if (ip == ComboAddress("192.0.2.1:53")) {
1669
1670 setLWResult(res, 0, true, false, false);
1671 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1672 return 1;
1673 }
1674
1675 return 0;
1676 });
1677
1678 /* Set the maximum number of questions very low */
1679 SyncRes::s_maxqperq = 5;
1680
1681 try {
1682 vector<DNSRecord> ret;
1683 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1684 BOOST_CHECK(false);
1685 }
1686 catch(const ImmediateServFailException& e) {
1687 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1688 }
1689}
1690
ccb07d93
RG
1691BOOST_AUTO_TEST_CASE(test_throttled_server) {
1692 std::unique_ptr<SyncRes> sr;
895449a5 1693 initSR(sr);
ccb07d93
RG
1694
1695 primeHints();
1696
1697 const DNSName target("throttled.powerdns.com.");
1698 const ComboAddress ns("192.0.2.1:53");
1699 size_t queriesToNS = 0;
1700
0bd2e252 1701 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, LWResult* res, bool* chained) {
ccb07d93
RG
1702
1703 if (isRootServer(ip)) {
ccb07d93 1704
8455425c 1705 setLWResult(res, 0, false, false, true);
ccb07d93
RG
1706 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1707 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1708 return 1;
1709 } else if (ip == ns) {
1710
1711 queriesToNS++;
1712
1713 setLWResult(res, 0, true, false, false);
1714 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1715
1716 return 1;
1717 }
1718
1719 return 0;
1720 });
1721
1722 /* mark ns as down */
606accb0
RG
1723 time_t now = sr->getNow().tv_sec;
1724 SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, 10000);
ccb07d93
RG
1725
1726 vector<DNSRecord> ret;
1727 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1728 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1729 BOOST_CHECK_EQUAL(ret.size(), 0);
1730 /* we should not have sent any queries to ns */
ccb07d93
RG
1731 BOOST_CHECK_EQUAL(queriesToNS, 0);
1732}
1733
1734BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1735 std::unique_ptr<SyncRes> sr;
895449a5 1736 initSR(sr);
ccb07d93
RG
1737
1738 primeHints();
1739
1740 const ComboAddress ns("192.0.2.1:53");
1741
1742 const size_t blocks = 10;
1743 /* mark ns as down for 'blocks' queries */
606accb0
RG
1744 time_t now = sr->getNow().tv_sec;
1745 SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, blocks);
ccb07d93
RG
1746
1747 for (size_t idx = 0; idx < blocks; idx++) {
606accb0 1748 BOOST_CHECK(SyncRes::isThrottled(now, ns));
ccb07d93
RG
1749 }
1750
1751 /* we have been throttled 'blocks' times, we should not be throttled anymore */
606accb0 1752 BOOST_CHECK(!SyncRes::isThrottled(now, ns));
ccb07d93
RG
1753}
1754
1755BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1756 std::unique_ptr<SyncRes> sr;
895449a5 1757 initSR(sr);
ccb07d93
RG
1758
1759 primeHints();
1760
1761 const ComboAddress ns("192.0.2.1:53");
1762
1763 const size_t seconds = 1;
1764 /* mark ns as down for 'seconds' seconds */
606accb0
RG
1765 time_t now = sr->getNow().tv_sec;
1766 SyncRes::doThrottle(now, ns, seconds, 10000);
a712cb56 1767
606accb0 1768 BOOST_CHECK(SyncRes::isThrottled(now, ns));
ccb07d93
RG
1769
1770 /* we should not be throttled anymore */
606accb0 1771 BOOST_CHECK(!SyncRes::isThrottled(now + 2, ns));
ccb07d93
RG
1772}
1773
f58c8379
RG
1774BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1775 std::unique_ptr<SyncRes> sr;
895449a5 1776 initSR(sr);
f58c8379
RG
1777
1778 primeHints();
1779
1780 const DNSName target("throttled.powerdns.com.");
1781 const ComboAddress ns("192.0.2.1:53");
1782 size_t queriesToNS = 0;
1783
0bd2e252 1784 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, LWResult* res, bool* chained) {
f58c8379
RG
1785
1786 if (isRootServer(ip)) {
1787
8455425c 1788 setLWResult(res, 0, false, false, true);
f58c8379
RG
1789 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1790 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1791 return 1;
1792 } else if (ip == ns) {
1793
1794 queriesToNS++;
1795
1796 setLWResult(res, 0, true, false, false);
1797 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1798
1799 return 1;
1800 }
1801
1802 return 0;
1803 });
1804
1805 /* prevent querying this NS */
9065eb05 1806 SyncRes::addDontQuery(Netmask(ns));
f58c8379
RG
1807
1808 vector<DNSRecord> ret;
1809 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1810 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1811 BOOST_CHECK_EQUAL(ret.size(), 0);
1812 /* we should not have sent any queries to ns */
1813 BOOST_CHECK_EQUAL(queriesToNS, 0);
1814}
1815
1816BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1817 std::unique_ptr<SyncRes> sr;
895449a5 1818 initSR(sr);
f58c8379
RG
1819
1820 primeHints();
1821
1822 const DNSName target1("powerdns.com.");
1823 const DNSName target2("notpowerdns.com.");
1824 const ComboAddress ns("192.0.2.1:53");
1825 size_t queriesCount = 0;
1826
0bd2e252 1827 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, LWResult* res, bool* chained) {
f58c8379
RG
1828
1829 queriesCount++;
1830
1831 if (isRootServer(ip)) {
1832
1833 if (domain == target1) {
1834 setLWResult(res, RCode::NXDomain, true, false, true);
1835 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1836 }
1837 else {
1838 setLWResult(res, 0, true, false, true);
1839 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1840 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1841 }
1842
1843 return 1;
1844 } else if (ip == ns) {
1845
1846 setLWResult(res, 0, true, false, false);
1847 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1848
1849 return 1;
1850 }
1851
1852 return 0;
1853 });
1854
1855 vector<DNSRecord> ret;
1856 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1857 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1858 BOOST_CHECK_EQUAL(ret.size(), 1);
1859 /* one for target1 and one for the entire TLD */
a712cb56 1860 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1861
1862 ret.clear();
1863 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1864 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1865 BOOST_CHECK_EQUAL(ret.size(), 1);
1866 /* one for target1 and one for the entire TLD */
a712cb56 1867 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1868
1869 /* we should have sent only one query */
1870 BOOST_CHECK_EQUAL(queriesCount, 1);
1871}
1872
898856ca
RG
1873BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1874 std::unique_ptr<SyncRes> sr;
1875 init();
1876 initSR(sr, true, false);
1877
1878 primeHints();
1879
1880 const DNSName target1("powerdns.com.");
1881 const DNSName target2("notpowerdns.com.");
1882 const ComboAddress ns("192.0.2.1:53");
1883 size_t queriesCount = 0;
1884
1885 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1886 We should add target1 to the negcache, but not "com.". */
1887
0bd2e252 1888 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, LWResult* res, bool* chained) {
898856ca
RG
1889
1890 queriesCount++;
1891
1892 if (isRootServer(ip)) {
1893
1894 if (domain == target1) {
1895 setLWResult(res, RCode::NXDomain, true, false, true);
1896 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1897 }
1898 else {
1899 setLWResult(res, 0, true, false, true);
1900 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1901 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1902 }
1903
1904 return 1;
1905 } else if (ip == ns) {
1906
1907 setLWResult(res, 0, true, false, false);
1908 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1909
1910 return 1;
1911 }
1912
1913 return 0;
1914 });
1915
1916 vector<DNSRecord> ret;
1917 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1918 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1919 BOOST_CHECK_EQUAL(ret.size(), 1);
1920
1921 /* even with root-nx-trust on and a NX answer from the root,
1922 we should not have cached the entire TLD this time. */
a712cb56 1923 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1924
1925 ret.clear();
1926 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1927 BOOST_CHECK_EQUAL(res, RCode::NoError);
1928 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1929 BOOST_REQUIRE(ret[0].d_type == QType::A);
1930 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1931 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1932
a712cb56 1933 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1934
1935 BOOST_CHECK_EQUAL(queriesCount, 3);
1936}
1937
f58c8379
RG
1938BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1939 std::unique_ptr<SyncRes> sr;
895449a5 1940 initSR(sr);
f58c8379
RG
1941
1942 primeHints();
1943
1944 const DNSName target1("powerdns.com.");
1945 const DNSName target2("notpowerdns.com.");
1946 const ComboAddress ns("192.0.2.1:53");
1947 size_t queriesCount = 0;
1948
0bd2e252 1949 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, LWResult* res, bool* chained) {
f58c8379
RG
1950
1951 queriesCount++;
1952
1953 if (isRootServer(ip)) {
1954
1955 if (domain == target1) {
1956 setLWResult(res, RCode::NXDomain, true, false, true);
1957 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1958 }
1959 else {
1960 setLWResult(res, 0, true, false, true);
1961 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1962 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1963 }
1964
1965 return 1;
1966 } else if (ip == ns) {
1967
1968 setLWResult(res, 0, true, false, false);
1969 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1970
1971 return 1;
1972 }
1973
1974 return 0;
1975 });
1976
1977 SyncRes::s_rootNXTrust = false;
1978
1979 vector<DNSRecord> ret;
1980 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1981 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1982 BOOST_CHECK_EQUAL(ret.size(), 1);
1983 /* one for target1 */
a712cb56 1984 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1985
1986 ret.clear();
1987 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
b7f378d1 1988 BOOST_CHECK_EQUAL(res, RCode::NoError);
f58c8379
RG
1989 BOOST_CHECK_EQUAL(ret.size(), 1);
1990 /* one for target1 */
a712cb56 1991 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1992
1993 /* we should have sent three queries */
1994 BOOST_CHECK_EQUAL(queriesCount, 3);
1995}
1996
1997BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1998 std::unique_ptr<SyncRes> sr;
895449a5 1999 initSR(sr);
f58c8379
RG
2000
2001 primeHints();
2002
2003 const DNSName target("www.powerdns.com.");
2004 const DNSName cnameTarget("cname.powerdns.com.");
2005
9065eb05 2006 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
f58c8379
RG
2007
2008 EDNSSubnetOpts incomingECS;
2009 incomingECS.source = Netmask("192.0.2.128/32");
2fe3354d 2010 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
f58c8379 2011
0bd2e252 2012 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, LWResult* res, bool* chained) {
f58c8379
RG
2013
2014 BOOST_REQUIRE(srcmask);
2015 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
2016
2017 if (isRootServer(ip)) {
8455425c 2018 setLWResult(res, 0, false, false, true);
f58c8379
RG
2019 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2020 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2021
2022 return 1;
2023 } else if (ip == ComboAddress("192.0.2.1:53")) {
2024 if (domain == target) {
2025 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
2026 setLWResult(res, RCode::NXDomain, true, false, true);
2027 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
2028 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2029 }
2030 else if (domain == cnameTarget) {
2031 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
2032 but we might if we still chase the CNAME. */
2033 setLWResult(res, RCode::NXDomain, true, false, true);
2034 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2035 }
2036
2037 return 1;
2038 }
2039
2040 return 0;
2041 });
2042
2043 vector<DNSRecord> ret;
2044 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2045 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2046 BOOST_CHECK_EQUAL(ret.size(), 2);
2047 /* no negative cache entry because the response was variable */
a712cb56 2048 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
f58c8379
RG
2049}
2050
d6e797b8
RG
2051BOOST_AUTO_TEST_CASE(test_ns_speed) {
2052 std::unique_ptr<SyncRes> sr;
895449a5 2053 initSR(sr);
30ee601a 2054
d6e797b8 2055 primeHints();
30ee601a 2056
d6e797b8 2057 const DNSName target("powerdns.com.");
30ee601a 2058
d6e797b8 2059 std::map<ComboAddress, uint64_t> nsCounts;
30ee601a 2060
0bd2e252 2061 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, LWResult* res, bool* chained) {
30ee601a 2062
d6e797b8 2063 if (isRootServer(ip)) {
8455425c 2064 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2065 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2066 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2067 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
30ee601a 2068
d6e797b8
RG
2069 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2070 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
2071 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
2072 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
2073 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
2074 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
30ee601a 2075
d6e797b8
RG
2076 return 1;
2077 } else {
2078 nsCounts[ip]++;
30ee601a 2079
d6e797b8
RG
2080 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
2081 BOOST_CHECK_LT(nsCounts.size(), 3);
2082
2083 /* let's time out on pdns-public-ns2.powerdns.com. */
2084 return 0;
2085 }
2086 else if (ip == ComboAddress("192.0.2.1:53")) {
2087 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
2088
2089 setLWResult(res, 0, true, false, true);
2090 addRecordToLW(res, domain, QType::A, "192.0.2.254");
2091 return 1;
2092 }
2093
2094 return 0;
2095 }
30ee601a 2096
d6e797b8
RG
2097 return 0;
2098 });
30ee601a 2099
606accb0 2100 struct timeval now = sr->getNow();
30ee601a 2101
d6e797b8
RG
2102 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
2103 then pdns-public-ns1.powerdns.com. on IPv4 */
a712cb56
RG
2104 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
2105 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
2106 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
2107 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
2108 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
2109 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
30ee601a 2110
d6e797b8
RG
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 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
2116 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
2117 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
2118 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
2119}
30ee601a 2120
d6e797b8
RG
2121BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
2122 std::unique_ptr<SyncRes> sr;
895449a5 2123 initSR(sr);
30ee601a 2124
d6e797b8 2125 primeHints();
30ee601a 2126
d6e797b8 2127 const DNSName target("powerdns.com.");
30ee601a 2128
0bd2e252 2129 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, LWResult* res, bool* chained) {
d6e797b8
RG
2130
2131 if (isRootServer(ip)) {
8455425c 2132 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2133 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2134
2135 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2136
2137 return 1;
2138 } else if (ip == ComboAddress("192.0.2.1:53")) {
2139 setLWResult(res, 0, true, false, true);
2140 addRecordToLW(res, domain, QType::A, "192.0.2.254");
2141 return 1;
2142 }
2143
2144 return 0;
2145 });
2146
2147 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
a66eacd6 2148 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2149 std::vector<DNSRecord> records;
2150 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2151 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
2152
2b984251 2153 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2154
2155 vector<DNSRecord> ret;
2156 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2157 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2158 BOOST_CHECK_EQUAL(ret.size(), 1);
2159}
2160
3337c2f7
RG
2161BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
2162 std::unique_ptr<SyncRes> sr;
895449a5 2163 initSR(sr);
3337c2f7
RG
2164
2165 primeHints();
2166
2167 const DNSName target("powerdns.com.");
2168 size_t queriesCount = 0;
2169
0bd2e252 2170 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, LWResult* res, bool* chained) {
3337c2f7
RG
2171
2172 queriesCount++;
2173
2174 if (isRootServer(ip) && domain == target) {
8455425c 2175 setLWResult(res, 0, false, false, true);
3337c2f7
RG
2176 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2177 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2178 return 1;
2179 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
2180 setLWResult(res, 0, true, false, true);
2181 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2182 return 1;
2183 }
2184
2185 return 0;
2186 });
2187
2188 vector<DNSRecord> ret;
2189 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2190 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2191 BOOST_CHECK_EQUAL(ret.size(), 0);
2192 /* one query to get NSs, then A and AAAA for each NS */
2193 BOOST_CHECK_EQUAL(queriesCount, 5);
2194}
2195
d6e797b8
RG
2196BOOST_AUTO_TEST_CASE(test_cache_hit) {
2197 std::unique_ptr<SyncRes> sr;
895449a5 2198 initSR(sr);
d6e797b8
RG
2199
2200 primeHints();
2201
2202 const DNSName target("powerdns.com.");
2203
0bd2e252 2204 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, LWResult* res, bool* chained) {
d6e797b8
RG
2205
2206 return 0;
2207 });
2208
2209 /* we populate the cache with eveything we need */
a66eacd6 2210 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2211 std::vector<DNSRecord> records;
2212 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2213
2214 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
2b984251 2215 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2216
2217 vector<DNSRecord> ret;
2218 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2219 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2220 BOOST_CHECK_EQUAL(ret.size(), 1);
2221}
2222
648bcbd1
RG
2223BOOST_AUTO_TEST_CASE(test_no_rd) {
2224 std::unique_ptr<SyncRes> sr;
895449a5 2225 initSR(sr);
648bcbd1
RG
2226
2227 primeHints();
2228
2229 const DNSName target("powerdns.com.");
2230 size_t queriesCount = 0;
2231
2232 sr->setCacheOnly();
2233
0bd2e252 2234 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, LWResult* res, bool* chained) {
648bcbd1
RG
2235
2236 queriesCount++;
2237 return 0;
2238 });
2239
2240 vector<DNSRecord> ret;
2241 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2242 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2243 BOOST_CHECK_EQUAL(ret.size(), 0);
2244 BOOST_CHECK_EQUAL(queriesCount, 0);
2245}
2246
d6e797b8
RG
2247BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
2248 std::unique_ptr<SyncRes> sr;
895449a5 2249 initSR(sr);
d6e797b8
RG
2250
2251 primeHints();
2252
2253 const DNSName target("cachettl.powerdns.com.");
2254 const ComboAddress ns("192.0.2.1:53");
2255
0bd2e252 2256 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, LWResult* res, bool* chained) {
d6e797b8
RG
2257
2258 if (isRootServer(ip)) {
2259
8455425c 2260 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2261 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2262 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
2263 return 1;
2264 } else if (ip == ns) {
2265
2266 setLWResult(res, 0, true, false, false);
2267 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2268
2269 return 1;
2270 }
2271
2272 return 0;
2273 });
2274
a66eacd6 2275 const time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2276 SyncRes::s_minimumTTL = 60;
2277 SyncRes::s_maxcachettl = 3600;
2278
2279 vector<DNSRecord> ret;
2280 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2281 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2282 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2283 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
2284
2285 const ComboAddress who;
2286 vector<DNSRecord> cached;
24bb9b58 2287 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
d6e797b8
RG
2288 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2289 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2290 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
2291
2292 cached.clear();
24bb9b58 2293 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
d6e797b8
RG
2294 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2295 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2296 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
2297}
2298
2299BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
2300 std::unique_ptr<SyncRes> sr;
895449a5 2301 initSR(sr);
d6e797b8
RG
2302
2303 primeHints();
2304
2305 const DNSName target("powerdns.com.");
2306
0bd2e252 2307 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, LWResult* res, bool* chained) {
d6e797b8
RG
2308
2309 if (isRootServer(ip)) {
8455425c 2310 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2311 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2312
2313 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2314
2315 return 1;
2316 } else if (ip == ComboAddress("192.0.2.1:53")) {
2317 setLWResult(res, 0, true, false, true);
2318 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2319 return 1;
2320 }
2321
2322 return 0;
2323 });
2324
2325 /* we populate the cache with entries that expired 60s ago*/
129e658f
RG
2326 const time_t now = sr->getNow().tv_sec;
2327
d6e797b8
RG
2328 std::vector<DNSRecord> records;
2329 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2330 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
2331
2b984251 2332 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2333
2334 vector<DNSRecord> ret;
2335 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2336 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2337 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2338 BOOST_REQUIRE(ret[0].d_type == QType::A);
2339 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
2340}
2341
129e658f
RG
2342BOOST_AUTO_TEST_CASE(test_cache_auth) {
2343 std::unique_ptr<SyncRes> sr;
2344 initSR(sr);
2345
2346 primeHints();
2347
2348 /* the auth server is sending the same answer in answer and additional,
2349 check that we only return one result, and we only cache one too. */
2350 const DNSName target("cache-auth.powerdns.com.");
2351
0bd2e252 2352 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, LWResult* res, bool* chained) {
129e658f
RG
2353
2354 setLWResult(res, 0, true, false, true);
2355 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2356 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 10);
2357
2358 return 1;
2359 });
2360
2361 const time_t now = sr->getNow().tv_sec;
2362
2363 vector<DNSRecord> ret;
2364 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2365 BOOST_CHECK_EQUAL(res, RCode::NoError);
2366 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2367 BOOST_REQUIRE_EQUAL(QType(ret.at(0).d_type).getName(), QType(QType::A).getName());
2368 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2369
2370 /* check that we correctly cached only the answer entry, not the additional one */
2371 const ComboAddress who;
2372 vector<DNSRecord> cached;
2373 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
2374 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2375 BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).getName(), QType(QType::A).getName());
2376 BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2377}
2378
d6e797b8
RG
2379BOOST_AUTO_TEST_CASE(test_delegation_only) {
2380 std::unique_ptr<SyncRes> sr;
895449a5 2381 initSR(sr);
d6e797b8
RG
2382
2383 primeHints();
2384
2385 /* Thanks, Verisign */
9065eb05
RG
2386 SyncRes::addDelegationOnly(DNSName("com."));
2387 SyncRes::addDelegationOnly(DNSName("net."));
d6e797b8
RG
2388
2389 const DNSName target("nx-powerdns.com.");
2390
0bd2e252 2391 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, LWResult* res, bool* chained) {
d6e797b8
RG
2392
2393 if (isRootServer(ip)) {
8455425c 2394 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2395 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2396 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2397 return 1;
2398 } else if (ip == ComboAddress("192.0.2.1:53")) {
2399
2400 setLWResult(res, 0, true, false, true);
2401 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2402 return 1;
2403 }
2404
2405 return 0;
2406 });
2407
2408 vector<DNSRecord> ret;
2409 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2410 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2411 BOOST_CHECK_EQUAL(ret.size(), 0);
2412}
2413
2414BOOST_AUTO_TEST_CASE(test_unauth_any) {
2415 std::unique_ptr<SyncRes> sr;
895449a5 2416 initSR(sr);
d6e797b8
RG
2417
2418 primeHints();
2419
2420 const DNSName target("powerdns.com.");
2421
0bd2e252 2422 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, LWResult* res, bool* chained) {
d6e797b8
RG
2423
2424 if (isRootServer(ip)) {
8455425c 2425 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2426 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2427 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2428 return 1;
2429 } else if (ip == ComboAddress("192.0.2.1:53")) {
2430
2431 setLWResult(res, 0, false, false, true);
2432 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2433 return 1;
2434 }
2435
2436 return 0;
2437 });
2438
2439 vector<DNSRecord> ret;
2440 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2441 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2442 BOOST_CHECK_EQUAL(ret.size(), 0);
2443}
2444
2445BOOST_AUTO_TEST_CASE(test_no_data) {
2446 std::unique_ptr<SyncRes> sr;
895449a5 2447 initSR(sr);
d6e797b8
RG
2448
2449 primeHints();
2450
2451 const DNSName target("powerdns.com.");
2452
0bd2e252 2453 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, LWResult* res, bool* chained) {
d6e797b8
RG
2454
2455 setLWResult(res, 0, true, false, true);
2456 return 1;
2457 });
2458
2459 vector<DNSRecord> ret;
2460 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2461 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2462 BOOST_CHECK_EQUAL(ret.size(), 0);
2463}
2464
2465BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2466 std::unique_ptr<SyncRes> sr;
895449a5 2467 initSR(sr);
d6e797b8
RG
2468
2469 primeHints();
2470
2471 const DNSName target("powerdns.com.");
2472
0bd2e252 2473 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, LWResult* res, bool* chained) {
d6e797b8
RG
2474
2475 setLWResult(res, 0, true, false, true);
2476 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2477 addRecordToLW(res, domain, QType::ANY, "0 0");
2478 addRecordToLW(res, domain, QType::OPT, "");
2479 return 1;
2480 });
2481
2482 vector<DNSRecord> ret;
2483 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2484 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2485 BOOST_CHECK_EQUAL(ret.size(), 1);
2486}
2487
2488BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2489 std::unique_ptr<SyncRes> sr;
895449a5 2490 initSR(sr);
d6e797b8
RG
2491
2492 primeHints();
2493
2494 const DNSName target("powerdns.com.");
2495
0bd2e252 2496 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, LWResult* res, bool* chained) {
d6e797b8
RG
2497
2498 setLWResult(res, 0, true, false, true);
2499 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2500 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2501 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2502 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2503 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2504 return 1;
2505 });
2506
2507 vector<DNSRecord> ret;
2508 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2509 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2510 BOOST_CHECK_EQUAL(ret.size(), 1);
2511}
2512
2513BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2514 std::unique_ptr<SyncRes> sr;
895449a5 2515 initSR(sr, true);
d6e797b8
RG
2516
2517 primeHints();
2518
2519 const DNSName target("powerdns.com.");
2520
0bd2e252 2521 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, LWResult* res, bool* chained) {
d6e797b8
RG
2522
2523 setLWResult(res, 0, true, false, true);
2524 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2525 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2526 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2527 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2528 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2529 return 1;
2530 });
2531
2532 vector<DNSRecord> ret;
2533 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2534 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2535 BOOST_CHECK_EQUAL(ret.size(), 4);
2536}
2537
2538BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2539 std::unique_ptr<SyncRes> sr;
895449a5 2540 initSR(sr);
d6e797b8
RG
2541
2542 primeHints();
2543
2544 const DNSName target("powerdns.com.");
2545
0bd2e252 2546 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, LWResult* res, bool* chained) {
d6e797b8
RG
2547
2548 setLWResult(res, RCode::NXDomain, true, false, true);
2549 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2550 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2551 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2552 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2553 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2554 return 1;
2555 });
2556
2557 vector<DNSRecord> ret;
2558 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2559 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2560 BOOST_CHECK_EQUAL(ret.size(), 1);
2561}
2562
2563BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2564 std::unique_ptr<SyncRes> sr;
895449a5 2565 initSR(sr, true);
d6e797b8
RG
2566
2567 primeHints();
2568
2569 const DNSName target("powerdns.com.");
2570
0bd2e252 2571 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, LWResult* res, bool* chained) {
d6e797b8
RG
2572
2573 setLWResult(res, RCode::NXDomain, true, false, true);
2574 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2575 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2576 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2577 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2578 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2579 return 1;
2580 });
2581
2582 vector<DNSRecord> ret;
2583 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2584 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2585 BOOST_CHECK_EQUAL(ret.size(), 4);
2586}
2587
648bcbd1
RG
2588BOOST_AUTO_TEST_CASE(test_qclass_none) {
2589 std::unique_ptr<SyncRes> sr;
895449a5 2590 initSR(sr);
648bcbd1
RG
2591
2592 primeHints();
2593
2594 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2595 size_t queriesCount = 0;
2596
0bd2e252 2597 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, LWResult* res, bool* chained) {
648bcbd1
RG
2598
2599 queriesCount++;
2600 return 0;
2601 });
2602
2603 const DNSName target("powerdns.com.");
2604 vector<DNSRecord> ret;
2605 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2606 BOOST_CHECK_EQUAL(res, -1);
2607 BOOST_CHECK_EQUAL(ret.size(), 0);
2608 BOOST_CHECK_EQUAL(queriesCount, 0);
2609}
2610
70ea0c65
RG
2611BOOST_AUTO_TEST_CASE(test_answer_no_aa) {
2612 std::unique_ptr<SyncRes> sr;
2613 initSR(sr, true);
2614
2615 primeHints();
2616
2617 const DNSName target("powerdns.com.");
2618
2619 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, LWResult* res, bool* chained) {
2620
2621 setLWResult(res, 0, false, false, true);
2622 addRecordToLW(res, domain, QType::A, "192.0.2.1");
2623 return 1;
2624 });
2625
2626 const time_t now = sr->getNow().tv_sec;
2627
2628 vector<DNSRecord> ret;
2629 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2630 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2631 BOOST_CHECK_EQUAL(ret.size(), 0);
2632
2633 /* check that the record in the answer section has not been cached */
2634 const ComboAddress who;
2635 vector<DNSRecord> cached;
2636 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
2637 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), false, &cached, who, &signatures), -1);
2638}
2639
1f03b691 2640BOOST_AUTO_TEST_CASE(test_special_types) {
648bcbd1 2641 std::unique_ptr<SyncRes> sr;
895449a5 2642 initSR(sr);
648bcbd1
RG
2643
2644 primeHints();
2645
1f03b691 2646 /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
648bcbd1
RG
2647 size_t queriesCount = 0;
2648
0bd2e252 2649 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, LWResult* res, bool* chained) {
648bcbd1
RG
2650
2651 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2652 queriesCount++;
2653 return 0;
2654 });
2655
2656 const DNSName target("powerdns.com.");
2657 vector<DNSRecord> ret;
2658 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2659 BOOST_CHECK_EQUAL(res, -1);
2660 BOOST_CHECK_EQUAL(ret.size(), 0);
2661 BOOST_CHECK_EQUAL(queriesCount, 0);
2662
2663 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2664 BOOST_CHECK_EQUAL(res, -1);
2665 BOOST_CHECK_EQUAL(ret.size(), 0);
2666 BOOST_CHECK_EQUAL(queriesCount, 0);
1f03b691
RG
2667
2668 res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2669 BOOST_CHECK_EQUAL(res, -1);
2670 BOOST_CHECK_EQUAL(ret.size(), 0);
2671 BOOST_CHECK_EQUAL(queriesCount, 0);
2672
2673 res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
648bcbd1
RG
2674 BOOST_CHECK_EQUAL(res, -1);
2675 BOOST_CHECK_EQUAL(ret.size(), 0);
2676 BOOST_CHECK_EQUAL(queriesCount, 0);
2677}
2678
2679BOOST_AUTO_TEST_CASE(test_special_names) {
2680 std::unique_ptr<SyncRes> sr;
895449a5 2681 initSR(sr);
648bcbd1
RG
2682
2683 primeHints();
2684
2685 /* special names should be handled internally */
2686
2687 size_t queriesCount = 0;
2688
0bd2e252 2689 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, LWResult* res, bool* chained) {
648bcbd1
RG
2690
2691 queriesCount++;
2692 return 0;
2693 });
2694
2695 vector<DNSRecord> ret;
2696 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
b7f378d1 2697 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2698 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2699 BOOST_CHECK(ret[0].d_type == QType::PTR);
2700 BOOST_CHECK_EQUAL(queriesCount, 0);
2701
2702 ret.clear();
2703 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2704 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2705 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2706 BOOST_CHECK(ret[0].d_type == QType::PTR);
2707 BOOST_CHECK_EQUAL(queriesCount, 0);
2708
2709 ret.clear();
2710 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 2711 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2712 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2713 BOOST_CHECK(ret[0].d_type == QType::PTR);
2714 BOOST_CHECK_EQUAL(queriesCount, 0);
2715
2716 ret.clear();
2717 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 2718 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2719 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2720 BOOST_CHECK(ret[0].d_type == QType::PTR);
2721 BOOST_CHECK_EQUAL(queriesCount, 0);
2722
2723 ret.clear();
2724 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
b7f378d1 2725 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2726 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2727 BOOST_CHECK(ret[0].d_type == QType::A);
2728 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2729 BOOST_CHECK_EQUAL(queriesCount, 0);
2730
2731 ret.clear();
2732 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
b7f378d1 2733 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2734 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2735 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2736 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2737 BOOST_CHECK_EQUAL(queriesCount, 0);
2738
2739 ret.clear();
2740 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2741 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2742 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2743 for (const auto& rec : ret) {
2744 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2745 if (rec.d_type == QType::A) {
2746 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2747 }
2748 else {
2749 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2750 }
2751 }
2752 BOOST_CHECK_EQUAL(queriesCount, 0);
2753
2754 ret.clear();
2755 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2756 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2757 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2758 BOOST_CHECK(ret[0].d_type == QType::TXT);
2759 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2760 BOOST_CHECK_EQUAL(queriesCount, 0);
2761
2762 ret.clear();
2763 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2764 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2765 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2766 BOOST_CHECK(ret[0].d_type == QType::TXT);
2767 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2768 BOOST_CHECK_EQUAL(queriesCount, 0);
2769
2770 ret.clear();
2771 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2772 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2773 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2774 BOOST_CHECK(ret[0].d_type == QType::TXT);
2775 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2776 BOOST_CHECK_EQUAL(queriesCount, 0);
2777
2778 ret.clear();
2779 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2780 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2781 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2782 BOOST_CHECK(ret[0].d_type == QType::TXT);
2783 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2784 BOOST_CHECK_EQUAL(queriesCount, 0);
2785
2786 ret.clear();
2787 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2788 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2789 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2790 BOOST_CHECK(ret[0].d_type == QType::TXT);
2791 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2792 BOOST_CHECK_EQUAL(queriesCount, 0);
2793
2794 ret.clear();
2795 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2796 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2797 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2798 BOOST_CHECK(ret[0].d_type == QType::TXT);
2799 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2800 BOOST_CHECK_EQUAL(queriesCount, 0);
2801}
2802
2803BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2804 std::unique_ptr<SyncRes> sr;
895449a5 2805 initSR(sr);
648bcbd1
RG
2806
2807 primeHints();
2808
2809 const DNSName target("rpz.powerdns.com.");
2810 const ComboAddress ns("192.0.2.1:53");
2811
0bd2e252 2812 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, LWResult* res, bool* chained) {
648bcbd1
RG
2813
2814 if (isRootServer(ip)) {
8455425c 2815 setLWResult(res, false, true, false, true);
648bcbd1
RG
2816 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2817 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2818 return 1;
2819 } else if (ip == ns) {
2820
2821 setLWResult(res, 0, true, false, true);
2822 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2823 return 1;
2824 }
2825
2826 return 0;
2827 });
2828
2829 DNSFilterEngine::Policy pol;
2830 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2831 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2832 zone->setName("Unit test policy 0");
6da513b2 2833 zone->addNSIPTrigger(Netmask(ns, 32), std::move(pol));
648bcbd1 2834 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2835 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2836 g_luaconfs.setState(luaconfsCopy);
2837
2838 vector<DNSRecord> ret;
2839 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2840 BOOST_CHECK_EQUAL(res, -2);
2841 BOOST_CHECK_EQUAL(ret.size(), 0);
2842}
2843
2844BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2845 std::unique_ptr<SyncRes> sr;
895449a5 2846 initSR(sr);
648bcbd1
RG
2847
2848 primeHints();
2849
2850 const DNSName target("rpz.powerdns.com.");
2851 const ComboAddress ns("[2001:DB8::42]:53");
2852
0bd2e252 2853 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, LWResult* res, bool* chained) {
648bcbd1
RG
2854
2855 if (isRootServer(ip)) {
8455425c 2856 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2857 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2858 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2859 return 1;
2860 } else if (ip == ns) {
2861
2862 setLWResult(res, 0, true, false, true);
2863 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2864 return 1;
2865 }
2866
2867 return 0;
2868 });
2869
2870 DNSFilterEngine::Policy pol;
2871 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2872 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2873 zone->setName("Unit test policy 0");
6da513b2 2874 zone->addNSIPTrigger(Netmask(ns, 128), std::move(pol));
648bcbd1 2875 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2876 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2877 g_luaconfs.setState(luaconfsCopy);
2878
2879 vector<DNSRecord> ret;
2880 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2881 BOOST_CHECK_EQUAL(res, -2);
2882 BOOST_CHECK_EQUAL(ret.size(), 0);
2883}
2884
2885BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2886 std::unique_ptr<SyncRes> sr;
895449a5 2887 initSR(sr);
648bcbd1
RG
2888
2889 primeHints();
2890
2891 const DNSName target("rpz.powerdns.com.");
2892 const ComboAddress ns("192.0.2.1:53");
2893 const DNSName nsName("ns1.powerdns.com.");
2894
0bd2e252 2895 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, LWResult* res, bool* chained) {
648bcbd1
RG
2896
2897 if (isRootServer(ip)) {
8455425c 2898 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2899 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2900 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2901 return 1;
2902 } else if (ip == ns) {
2903
2904 setLWResult(res, 0, true, false, true);
2905 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2906 return 1;
2907 }
2908
2909 return 0;
2910 });
2911
2912 DNSFilterEngine::Policy pol;
2913 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2914 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2915 zone->setName("Unit test policy 0");
6da513b2 2916 zone->addNSTrigger(nsName, std::move(pol));
648bcbd1 2917 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2918 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2919 g_luaconfs.setState(luaconfsCopy);
2920
2921 vector<DNSRecord> ret;
2922 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2923 BOOST_CHECK_EQUAL(res, -2);
2924 BOOST_CHECK_EQUAL(ret.size(), 0);
2925}
2926
2927BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2928 std::unique_ptr<SyncRes> sr;
895449a5 2929 initSR(sr);
648bcbd1
RG
2930
2931 primeHints();
2932
2933 const DNSName target("rpz.powerdns.com.");
2934 const ComboAddress ns("192.0.2.1:53");
2935 const DNSName nsName("ns1.powerdns.com.");
2936
0bd2e252 2937 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, LWResult* res, bool* chained) {
648bcbd1
RG
2938
2939 if (isRootServer(ip)) {
8455425c 2940 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2941 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2942 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2943 return 1;
2944 } else if (ip == ns) {
2945
2946 setLWResult(res, 0, true, false, true);
2947 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2948 return 1;
2949 }
2950
2951 return 0;
2952 });
2953
2954 DNSFilterEngine::Policy pol;
2955 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2956 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2957 zone->setName("Unit test policy 0");
6da513b2
RG
2958 zone->addNSIPTrigger(Netmask(ns, 128), DNSFilterEngine::Policy(pol));
2959 zone->addNSTrigger(nsName, std::move(pol));
648bcbd1 2960 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2961 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2962 g_luaconfs.setState(luaconfsCopy);
2963
2964 /* RPZ is disabled for this query, we should not be blocked */
2965 sr->setWantsRPZ(false);
2966
2967 vector<DNSRecord> ret;
2968 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2969 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2970 BOOST_CHECK_EQUAL(ret.size(), 1);
2971}
2972
3e59ff53
RG
2973BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2974 std::unique_ptr<SyncRes> sr;
895449a5 2975 initSR(sr);
3e59ff53
RG
2976
2977 primeHints();
2978
2979 const DNSName target("powerdns.com.");
2980 const ComboAddress ns("192.0.2.1:53");
2981 const ComboAddress forwardedNS("192.0.2.42:53");
2982
2983 SyncRes::AuthDomain ad;
2984 ad.d_rdForward = false;
2985 ad.d_servers.push_back(forwardedNS);
a712cb56 2986 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2987
0bd2e252 2988 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, LWResult* res, bool* chained) {
3e59ff53
RG
2989
2990 if (ip == forwardedNS) {
6dfff36f
RG
2991 BOOST_CHECK_EQUAL(sendRDQuery, false);
2992
3e59ff53
RG
2993 setLWResult(res, 0, true, false, true);
2994 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2995 return 1;
2996 }
2997
2998 return 0;
2999 });
3000
3001 /* simulate a no-RD query */
3002 sr->setCacheOnly();
3003
3004 vector<DNSRecord> ret;
3005 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3006 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
3007 BOOST_CHECK_EQUAL(ret.size(), 1);
3008}
3009
3010BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
3011 std::unique_ptr<SyncRes> sr;
895449a5 3012 initSR(sr);
3e59ff53
RG
3013
3014 primeHints();
3015
3016 const DNSName target("powerdns.com.");
3017 const ComboAddress ns("192.0.2.1:53");
3018 const ComboAddress forwardedNS("192.0.2.42:53");
3019
ad797d94 3020 size_t queriesCount = 0;
3e59ff53 3021 SyncRes::AuthDomain ad;
ad797d94 3022 ad.d_rdForward = true;
3e59ff53 3023 ad.d_servers.push_back(forwardedNS);
a712cb56 3024 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 3025
0bd2e252 3026 sr->setAsyncCallback([forwardedNS, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
ad797d94
RG
3027
3028 queriesCount++;
3e59ff53
RG
3029
3030 if (ip == forwardedNS) {
ad797d94 3031 BOOST_CHECK_EQUAL(sendRDQuery, true);
6dfff36f 3032
ad797d94
RG
3033 /* set AA=0, we are a recursor */
3034 setLWResult(res, 0, false, false, true);
3e59ff53
RG
3035 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3036 return 1;
3037 }
3038
3039 return 0;
3040 });
3041
3042 vector<DNSRecord> ret;
3043 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3044 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53 3045 BOOST_CHECK_EQUAL(ret.size(), 1);
ad797d94
RG
3046 BOOST_CHECK_EQUAL(queriesCount, 1);
3047
3048 /* now make sure we can resolve from the cache (see #6340
3049 where the entries were added to the cache but not retrieved,
3050 because the recursor doesn't set the AA bit and we require
3051 it. We fixed it by not requiring the AA bit for forward-recurse
3052 answers. */
3053 ret.clear();
3054 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3055 BOOST_CHECK_EQUAL(res, RCode::NoError);
3056 BOOST_CHECK_EQUAL(ret.size(), 1);
3057 BOOST_CHECK_EQUAL(queriesCount, 1);
3e59ff53
RG
3058}
3059
3060BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
3061 std::unique_ptr<SyncRes> sr;
895449a5 3062 initSR(sr);
3e59ff53
RG
3063
3064 primeHints();
3065
3066 const DNSName target("powerdns.com.");
3067 const ComboAddress ns("192.0.2.1:53");
3068 const ComboAddress forwardedNS("192.0.2.42:53");
3069
3070 SyncRes::AuthDomain ad;
3071 ad.d_rdForward = true;
3072 ad.d_servers.push_back(forwardedNS);
a712cb56 3073 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 3074
0bd2e252 3075 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, LWResult* res, bool* chained) {
3e59ff53
RG
3076
3077 if (ip == forwardedNS) {
6dfff36f
RG
3078 BOOST_CHECK_EQUAL(sendRDQuery, false);
3079
3e59ff53
RG
3080 setLWResult(res, 0, true, false, true);
3081 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3082 return 1;
3083 }
3084
3085 return 0;
3086 });
3087
3088 /* simulate a no-RD query */
3089 sr->setCacheOnly();
3090
3091 vector<DNSRecord> ret;
3092 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3093 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
3094 BOOST_CHECK_EQUAL(ret.size(), 1);
3095}
3096
3097BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
3098 std::unique_ptr<SyncRes> sr;
895449a5 3099 initSR(sr);
3e59ff53
RG
3100
3101 primeHints();
3102
3103 const DNSName target("powerdns.com.");
3104 const ComboAddress ns("192.0.2.1:53");
3105 const ComboAddress forwardedNS("192.0.2.42:53");
3106
3107 SyncRes::AuthDomain ad;
3108 ad.d_rdForward = true;
3109 ad.d_servers.push_back(forwardedNS);
a712cb56 3110 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 3111
0bd2e252 3112 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, LWResult* res, bool* chained) {
3e59ff53
RG
3113
3114 if (ip == forwardedNS) {
6dfff36f
RG
3115 BOOST_CHECK_EQUAL(sendRDQuery, true);
3116
3e59ff53
RG
3117 setLWResult(res, 0, true, false, true);
3118 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3119 return 1;
3120 }
3121
3122 return 0;
3123 });
3124
3125 vector<DNSRecord> ret;
3126 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3127 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
3128 BOOST_CHECK_EQUAL(ret.size(), 1);
3129}
3130
dff3ef07
RG
3131BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd_dnssec) {
3132 std::unique_ptr<SyncRes> sr;
3133 initSR(sr, true);
3134
3135 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3136
3137 primeHints();
3138 /* signed */
3139 const DNSName target("test.");
3140 /* unsigned */
3141 const DNSName cnameTarget("cname.");
3142 testkeysset_t keys;
3143
3144 auto luaconfsCopy = g_luaconfs.getCopy();
3145 luaconfsCopy.dsAnchors.clear();
3146 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3147 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3148 g_luaconfs.setState(luaconfsCopy);
3149
3150 const ComboAddress forwardedNS("192.0.2.42:53");
3151 size_t queriesCount = 0;
3152
3153 SyncRes::AuthDomain ad;
3154 ad.d_rdForward = true;
3155 ad.d_servers.push_back(forwardedNS);
3156 (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = ad;
3157
3158 sr->setAsyncCallback([target,cnameTarget,keys,forwardedNS,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
3159 queriesCount++;
3160
3161 BOOST_CHECK_EQUAL(sendRDQuery, true);
3162
3163 if (ip != forwardedNS) {
3164 return 0;
3165 }
3166
3167 if (type == QType::DS || type == QType::DNSKEY) {
3168 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
3169 }
3170
3171 if (domain == target && type == QType::A) {
3172
3173 setLWResult(res, 0, false, false, true);
3174 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
3175 addRRSIG(keys, res->d_records, domain, 300);
3176 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
3177
3178 return 1;
3179 }
3180 return 0;
3181 });
3182
3183 vector<DNSRecord> ret;
3184 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3185 BOOST_CHECK_EQUAL(res, RCode::NoError);
3186 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3187 BOOST_REQUIRE_EQUAL(ret.size(), 3);
3188 BOOST_CHECK_EQUAL(queriesCount, 5);
3189
3190 /* again, to test the cache */
3191 ret.clear();
3192 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3193 BOOST_CHECK_EQUAL(res, RCode::NoError);
3194 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
3195 BOOST_REQUIRE_EQUAL(ret.size(), 3);
3196 BOOST_CHECK_EQUAL(queriesCount, 5);
3197}
3198
3199BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd_dnssec_bogus) {
3200 std::unique_ptr<SyncRes> sr;
3201 initSR(sr, true);
3202
3203 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3204
3205 primeHints();
3206 /* signed */
3207 const DNSName target("test.");
3208 /* signed */
3209 const DNSName cnameTarget("cname.");
3210 testkeysset_t keys;
3211
3212 auto luaconfsCopy = g_luaconfs.getCopy();
3213 luaconfsCopy.dsAnchors.clear();
3214 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3215 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3216 generateKeyMaterial(cnameTarget, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3217 g_luaconfs.setState(luaconfsCopy);
3218
3219 const ComboAddress forwardedNS("192.0.2.42:53");
3220 size_t queriesCount = 0;
3221
3222 SyncRes::AuthDomain ad;
3223 ad.d_rdForward = true;
3224 ad.d_servers.push_back(forwardedNS);
3225 (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = ad;
3226
3227 sr->setAsyncCallback([target,cnameTarget,keys,forwardedNS,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
3228 queriesCount++;
3229
3230 BOOST_CHECK_EQUAL(sendRDQuery, true);
3231
3232 if (ip != forwardedNS) {
3233 return 0;
3234 }
3235
3236 if (type == QType::DS || type == QType::DNSKEY) {
3237 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys);
3238 }
3239
3240 if (domain == target && type == QType::A) {
3241
3242 setLWResult(res, 0, false, false, true);
3243 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
3244 addRRSIG(keys, res->d_records, domain, 300);
3245 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
3246 /* no RRSIG in a signed zone, Bogus ! */
3247
3248 return 1;
3249 }
3250 return 0;
3251 });
3252
3253 vector<DNSRecord> ret;
3254 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3255 BOOST_CHECK_EQUAL(res, RCode::NoError);
3256 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3257 BOOST_REQUIRE_EQUAL(ret.size(), 3);
3258 BOOST_CHECK_EQUAL(queriesCount, 5);
3259
3260 /* again, to test the cache */
3261 ret.clear();
3262 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3263 BOOST_CHECK_EQUAL(res, RCode::NoError);
3264 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3265 BOOST_REQUIRE_EQUAL(ret.size(), 3);
3266 BOOST_CHECK_EQUAL(queriesCount, 5);
3267}
3268
6e9d3cae
RG
3269BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd_dnssec_nodata_bogus) {
3270 std::unique_ptr<SyncRes> sr;
3271 initSR(sr, true);
3272
3273 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3274
3275 primeHints();
3276 const DNSName target("powerdns.com.");
3277 testkeysset_t keys;
3278
3279 auto luaconfsCopy = g_luaconfs.getCopy();
3280 luaconfsCopy.dsAnchors.clear();
3281 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3282 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3283 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3284 g_luaconfs.setState(luaconfsCopy);
3285
3286 const ComboAddress forwardedNS("192.0.2.42:53");
3287 SyncRes::AuthDomain ad;
3288 ad.d_rdForward = true;
3289 ad.d_servers.push_back(forwardedNS);
3290 (*SyncRes::t_sstorage.domainmap)[g_rootdnsname] = ad;
3291
3292 size_t queriesCount = 0;
3293
3294 sr->setAsyncCallback([target,forwardedNS,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
3295 queriesCount++;
3296
3297 BOOST_CHECK_EQUAL(sendRDQuery, true);
3298
3299 if (ip != forwardedNS) {
3300 return 0;
3301 }
3302
3303 if (type == QType::DS || type == QType::DNSKEY) {
3304 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3305 }
3306 else {
3307
3308 setLWResult(res, 0, false, false, true);
3309 return 1;
3310 }
3311
3312 return 0;
3313 });
3314
3315 vector<DNSRecord> ret;
3316 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3317 BOOST_CHECK_EQUAL(res, RCode::NoError);
3318 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3319 BOOST_REQUIRE_EQUAL(ret.size(), 0);
3320 /* com|NS, powerdns.com|NS, powerdns.com|A */
3321 BOOST_CHECK_EQUAL(queriesCount, 3);
3322
3323 /* again, to test the cache */
3324 ret.clear();
3325 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3326 BOOST_CHECK_EQUAL(res, RCode::NoError);
3327 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
3328 BOOST_REQUIRE_EQUAL(ret.size(), 0);
3329 /* we don't store empty results */
3330 BOOST_CHECK_EQUAL(queriesCount, 4);
3331}
3332
e1636f82 3333BOOST_AUTO_TEST_CASE(test_auth_zone_oob) {
f79a4e30 3334 std::unique_ptr<SyncRes> sr;
e1636f82 3335 initSR(sr, true);
f79a4e30
RG
3336
3337 primeHints();
3338
3339 size_t queriesCount = 0;
3340 const DNSName target("test.xx.");
3341 const ComboAddress targetAddr("127.0.0.1");
f79a4e30
RG
3342 const DNSName authZone("test.xx");
3343
3344 SyncRes::AuthDomain ad;
3345 DNSRecord dr;
f79a4e30
RG
3346
3347 dr.d_place = DNSResourceRecord::ANSWER;
e1636f82 3348 dr.d_name = target;
f79a4e30
RG
3349 dr.d_type = QType::A;
3350 dr.d_ttl = 1800;
e1636f82 3351 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
f79a4e30
RG
3352 ad.d_records.insert(dr);
3353
a712cb56 3354 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
f79a4e30 3355
0bd2e252 3356 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, LWResult* res, bool* chained) {
f79a4e30
RG
3357 queriesCount++;
3358 return 0;
3359 });
3360
3361 vector<DNSRecord> ret;
3362 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3363 BOOST_CHECK_EQUAL(res, 0);
3364 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3365 BOOST_CHECK(ret[0].d_type == QType::A);
3366 BOOST_CHECK_EQUAL(queriesCount, 0);
3367 BOOST_CHECK(sr->wasOutOfBand());
e1636f82 3368 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
3369
3370 /* a second time, to check that the OOB flag is set when the query cache is used */
3371 ret.clear();
3372 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3373 BOOST_CHECK_EQUAL(res, 0);
3374 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3375 BOOST_CHECK(ret[0].d_type == QType::A);
3376 BOOST_CHECK_EQUAL(queriesCount, 0);
3377 BOOST_CHECK(sr->wasOutOfBand());
e1636f82
RG
3378 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3379
3380 /* a third time, to check that the validation is disabled when the OOB flag is set */
3381 ret.clear();
3382 sr->setDNSSECValidationRequested(true);
3383 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3384 BOOST_CHECK_EQUAL(res, 0);
3385 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3386 BOOST_CHECK(ret[0].d_type == QType::A);
3387 BOOST_CHECK_EQUAL(queriesCount, 0);
3388 BOOST_CHECK(sr->wasOutOfBand());
3389 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3390}
3391
3392BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) {
3393 std::unique_ptr<SyncRes> sr;
3394 initSR(sr, true);
3395
3396 primeHints();
3397
3398 size_t queriesCount = 0;
3399 const DNSName target("cname.test.xx.");
3400 const DNSName targetCname("cname-target.test.xx.");
3401 const ComboAddress targetCnameAddr("127.0.0.1");
3402 const DNSName authZone("test.xx");
3403
3404 SyncRes::AuthDomain ad;
3405 DNSRecord dr;
3406
3407 dr.d_place = DNSResourceRecord::ANSWER;
3408 dr.d_name = target;
3409 dr.d_type = QType::CNAME;
3410 dr.d_ttl = 1800;
3411 dr.d_content = std::make_shared<CNAMERecordContent>(targetCname);
3412 ad.d_records.insert(dr);
3413
3414 dr.d_place = DNSResourceRecord::ANSWER;
3415 dr.d_name = targetCname;
3416 dr.d_type = QType::A;
3417 dr.d_ttl = 1800;
3418 dr.d_content = std::make_shared<ARecordContent>(targetCnameAddr);
3419 ad.d_records.insert(dr);
3420
3421 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
3422
0bd2e252 3423 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, LWResult* res, bool* chained) {
e1636f82
RG
3424 queriesCount++;
3425 return 0;
3426 });
3427
3428 vector<DNSRecord> ret;
3429 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3430 BOOST_CHECK_EQUAL(res, 0);
3431 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3432 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3433 BOOST_CHECK(ret[1].d_type == QType::A);
3434 BOOST_CHECK_EQUAL(queriesCount, 0);
3435 BOOST_CHECK(sr->wasOutOfBand());
3436 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3437
3438 /* a second time, to check that the OOB flag is set when the query cache is used */
3439 ret.clear();
3440 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3441 BOOST_CHECK_EQUAL(res, 0);
3442 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3443 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3444 BOOST_CHECK(ret[1].d_type == QType::A);
3445 BOOST_CHECK_EQUAL(queriesCount, 0);
3446 BOOST_CHECK(sr->wasOutOfBand());
3447 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3448
3449 /* a third time, to check that the validation is disabled when the OOB flag is set */
3450 ret.clear();
3451 sr->setDNSSECValidationRequested(true);
3452 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3453 BOOST_CHECK_EQUAL(res, 0);
3454 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3455 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3456 BOOST_CHECK(ret[1].d_type == QType::A);
3457 BOOST_CHECK_EQUAL(queriesCount, 0);
3458 BOOST_CHECK(sr->wasOutOfBand());
3459 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
3460}
3461
3337c2f7
RG
3462BOOST_AUTO_TEST_CASE(test_auth_zone) {
3463 std::unique_ptr<SyncRes> sr;
895449a5 3464 initSR(sr);
3337c2f7
RG
3465
3466 primeHints();
3467
3468 size_t queriesCount = 0;
3469 const DNSName target("powerdns.com.");
3470 const ComboAddress addr("192.0.2.5");
3471
3472 SyncRes::AuthDomain ad;
3473 ad.d_name = target;
3474 DNSRecord dr;
3475 dr.d_place = DNSResourceRecord::ANSWER;
3476 dr.d_name = target;
3477 dr.d_type = QType::SOA;
3478 dr.d_ttl = 3600;
3479 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3480 ad.d_records.insert(dr);
3481
3482 dr.d_place = DNSResourceRecord::ANSWER;
3483 dr.d_name = target;
3484 dr.d_type = QType::A;
3485 dr.d_ttl = 3600;
3486 dr.d_content = std::make_shared<ARecordContent>(addr);
3487 ad.d_records.insert(dr);
3488
3489 auto map = std::make_shared<SyncRes::domainmap_t>();
3490 (*map)[target] = ad;
3491 SyncRes::setDomainMap(map);
3492
0bd2e252 3493 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, LWResult* res, bool* chained) {
3337c2f7
RG
3494
3495 queriesCount++;
3496 setLWResult(res, 0, true, false, true);
3497 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3498 return 1;
3499 });
3500
3501 vector<DNSRecord> ret;
3502 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3503 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3504 BOOST_CHECK_EQUAL(ret.size(), 1);
3505 BOOST_CHECK(ret[0].d_type == QType::A);
3506 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3507 BOOST_CHECK_EQUAL(queriesCount, 0);
3508}
3509
3510BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
3511 std::unique_ptr<SyncRes> sr;
895449a5 3512 initSR(sr);
3337c2f7
RG
3513
3514 primeHints();
3515
3516 size_t queriesCount = 0;
3517 const DNSName target("powerdns.com.");
3518 const DNSName authZone("internal.powerdns.com.");
3519 const ComboAddress addr("192.0.2.5");
3520
3521 SyncRes::AuthDomain ad;
3522 ad.d_name = authZone;
3523 DNSRecord dr;
3524 dr.d_place = DNSResourceRecord::ANSWER;
3525 dr.d_name = authZone;
3526 dr.d_type = QType::SOA;
3527 dr.d_ttl = 3600;
3528 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3529 ad.d_records.insert(dr);
3530
3531 dr.d_place = DNSResourceRecord::ANSWER;
3532 dr.d_name = authZone;
3533 dr.d_type = QType::A;
3534 dr.d_ttl = 3600;
3535 dr.d_content = std::make_shared<ARecordContent>(addr);
3536 ad.d_records.insert(dr);
3537
3538 auto map = std::make_shared<SyncRes::domainmap_t>();
3539 (*map)[authZone] = ad;
3540 SyncRes::setDomainMap(map);
3541
0bd2e252 3542 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, LWResult* res, bool* chained) {
3337c2f7
RG
3543
3544 queriesCount++;
3545
3546 if (domain == target) {
3547 setLWResult(res, 0, true, false, true);
3548 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
3549 return 1;
3550 }
3551
3552 return 0;
3553 });
3554
3555 vector<DNSRecord> ret;
3556 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3557 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3558 BOOST_CHECK_EQUAL(ret.size(), 2);
3559 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3560 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
3561 BOOST_CHECK(ret[1].d_type == QType::A);
3562 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3563 BOOST_CHECK_EQUAL(queriesCount, 1);
3564}
3565
3566BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
3567 std::unique_ptr<SyncRes> sr;
895449a5 3568 initSR(sr);
3337c2f7
RG
3569
3570 primeHints();
3571
3572 size_t queriesCount = 0;
3573 const DNSName target("powerdns.com.");
3574 const DNSName externalCNAME("www.open-xchange.com.");
3575 const ComboAddress addr("192.0.2.5");
3576
3577 SyncRes::AuthDomain ad;
3578 ad.d_name = target;
3579 DNSRecord dr;
3580 dr.d_place = DNSResourceRecord::ANSWER;
3581 dr.d_name = target;
3582 dr.d_type = QType::SOA;
3583 dr.d_ttl = 3600;
3584 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3585 ad.d_records.insert(dr);
3586
3587 dr.d_place = DNSResourceRecord::ANSWER;
3588 dr.d_name = target;
3589 dr.d_type = QType::CNAME;
3590 dr.d_ttl = 3600;
3591 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
3592 ad.d_records.insert(dr);
3593
3594 auto map = std::make_shared<SyncRes::domainmap_t>();
3595 (*map)[target] = ad;
3596 SyncRes::setDomainMap(map);
3597
0bd2e252 3598 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, LWResult* res, bool* chained) {
3337c2f7
RG
3599
3600 queriesCount++;
3601
3602 if (domain == externalCNAME) {
3603 setLWResult(res, 0, true, false, true);
3604 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
3605 return 1;
3606 }
3607
3608 return 0;
3609 });
3610
3611 vector<DNSRecord> ret;
3612 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3613 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3614 BOOST_CHECK_EQUAL(ret.size(), 2);
3615 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3616 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
3617 BOOST_CHECK(ret[1].d_type == QType::A);
3618 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3619 BOOST_CHECK_EQUAL(queriesCount, 1);
3620}
3621
3622BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
3623 std::unique_ptr<SyncRes> sr;
895449a5 3624 initSR(sr);
3337c2f7
RG
3625
3626 primeHints();
3627
3628 size_t queriesCount = 0;
3629 const DNSName target("nodata.powerdns.com.");
3630 const DNSName authZone("powerdns.com");
3631
3632 SyncRes::AuthDomain ad;
3633 ad.d_name = authZone;
3634 DNSRecord dr;
3635 dr.d_place = DNSResourceRecord::ANSWER;
3636 dr.d_name = target;
3637 dr.d_type = QType::A;
3638 dr.d_ttl = 3600;
3639 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3640 ad.d_records.insert(dr);
3641
3642 dr.d_place = DNSResourceRecord::ANSWER;
3643 dr.d_name = authZone;
3644 dr.d_type = QType::SOA;
3645 dr.d_ttl = 3600;
3646 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3647 ad.d_records.insert(dr);
3648
3649 auto map = std::make_shared<SyncRes::domainmap_t>();
3650 (*map)[authZone] = ad;
3651 SyncRes::setDomainMap(map);
3652
0bd2e252 3653 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, LWResult* res, bool* chained) {
3337c2f7
RG
3654
3655 queriesCount++;
3656
3657 return 0;
3658 });
3659
3660 vector<DNSRecord> ret;
3661 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3662 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3663 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3664 BOOST_CHECK(ret[0].d_type == QType::SOA);
3665 BOOST_CHECK_EQUAL(queriesCount, 0);
3666}
3667
3668BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3669 std::unique_ptr<SyncRes> sr;
895449a5 3670 initSR(sr);
3337c2f7
RG
3671
3672 primeHints();
3673
3674 size_t queriesCount = 0;
3675 const DNSName target("nx.powerdns.com.");
3676 const DNSName authZone("powerdns.com");
3677
3678 SyncRes::AuthDomain ad;
3679 ad.d_name = authZone;
3680 DNSRecord dr;
3681 dr.d_place = DNSResourceRecord::ANSWER;
3682 dr.d_name = DNSName("powerdns.com.");
3683 dr.d_type = QType::SOA;
3684 dr.d_ttl = 3600;
3685 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3686 ad.d_records.insert(dr);
3687
3688 auto map = std::make_shared<SyncRes::domainmap_t>();
3689 (*map)[authZone] = ad;
3690 SyncRes::setDomainMap(map);
3691
0bd2e252 3692 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, LWResult* res, bool* chained) {
3337c2f7
RG
3693
3694 queriesCount++;
3695
3696 return 0;
3697 });
3698
3699 vector<DNSRecord> ret;
3700 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3701 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3702 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3703 BOOST_CHECK(ret[0].d_type == QType::SOA);
3704 BOOST_CHECK_EQUAL(queriesCount, 0);
3705}
3706
3707BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3708 std::unique_ptr<SyncRes> sr;
e1636f82 3709 initSR(sr, true, false);
3337c2f7
RG
3710
3711 primeHints();
3712
3713 size_t queriesCount = 0;
3714 const DNSName target("www.test.powerdns.com.");
3715 const ComboAddress targetAddr("192.0.2.2");
3716 const DNSName ns("ns1.test.powerdns.com.");
3717 const ComboAddress nsAddr("192.0.2.1");
3718 const DNSName authZone("powerdns.com");
3719
3720 SyncRes::AuthDomain ad;
3721 ad.d_name = authZone;
3722 DNSRecord dr;
3723 dr.d_place = DNSResourceRecord::ANSWER;
3724 dr.d_name = authZone;
3725 dr.d_type = QType::SOA;
3726 dr.d_ttl = 3600;
3727 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3728 ad.d_records.insert(dr);
3729
3730 dr.d_place = DNSResourceRecord::ANSWER;
3731 dr.d_name = DNSName("test.powerdns.com.");
3732 dr.d_type = QType::NS;
3733 dr.d_ttl = 3600;
3734 dr.d_content = std::make_shared<NSRecordContent>(ns);
3735 ad.d_records.insert(dr);
3736
3737 dr.d_place = DNSResourceRecord::ANSWER;
3738 dr.d_name = ns;
3739 dr.d_type = QType::A;
3740 dr.d_ttl = 3600;
3741 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3742 ad.d_records.insert(dr);
3743
3744 auto map = std::make_shared<SyncRes::domainmap_t>();
3745 (*map)[authZone] = ad;
3746 SyncRes::setDomainMap(map);
3747
e1636f82
RG
3748 testkeysset_t keys;
3749 auto luaconfsCopy = g_luaconfs.getCopy();
3750 luaconfsCopy.dsAnchors.clear();
3751 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3752 g_luaconfs.setState(luaconfsCopy);
3753
0bd2e252 3754 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, LWResult* res, bool* chained) {
3337c2f7
RG
3755
3756 queriesCount++;
e1636f82
RG
3757 if (type == QType::DS || type == QType::DNSKEY) {
3758 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone);
3759 }
3760
3337c2f7
RG
3761 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3762 setLWResult(res, 0, true, false, true);
3763 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3764 return 1;
3765 }
3766
3767 return 0;
3768 });
3769
e1636f82 3770 sr->setDNSSECValidationRequested(true);
3337c2f7
RG
3771 vector<DNSRecord> ret;
3772 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3773 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3774 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3775 BOOST_CHECK(ret[0].d_type == QType::A);
e1636f82
RG
3776 BOOST_CHECK_EQUAL(queriesCount, 4);
3777 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3337c2f7
RG
3778}
3779
3780BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3781 std::unique_ptr<SyncRes> sr;
895449a5 3782 initSR(sr);
3337c2f7
RG
3783
3784 primeHints();
3785
3786 size_t queriesCount = 0;
3787 const DNSName target("test.powerdns.com.");
3788 const ComboAddress targetAddr("192.0.2.2");
3789 const DNSName ns("ns1.test.powerdns.com.");
3790 const ComboAddress nsAddr("192.0.2.1");
3791 const DNSName authZone("powerdns.com");
3792
3793 SyncRes::AuthDomain ad;
3794 ad.d_name = authZone;
3795 DNSRecord dr;
3796 dr.d_place = DNSResourceRecord::ANSWER;
3797 dr.d_name = authZone;
3798 dr.d_type = QType::SOA;
3799 dr.d_ttl = 3600;
3800 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3801 ad.d_records.insert(dr);
3802
3803 dr.d_place = DNSResourceRecord::ANSWER;
3804 dr.d_name = DNSName("test.powerdns.com.");
3805 dr.d_type = QType::NS;
3806 dr.d_ttl = 3600;
3807 dr.d_content = std::make_shared<NSRecordContent>(ns);
3808 ad.d_records.insert(dr);
3809
3810 dr.d_place = DNSResourceRecord::ANSWER;
3811 dr.d_name = ns;
3812 dr.d_type = QType::A;
3813 dr.d_ttl = 3600;
3814 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3815 ad.d_records.insert(dr);
3816
3817 auto map = std::make_shared<SyncRes::domainmap_t>();
3818 (*map)[authZone] = ad;
3819 SyncRes::setDomainMap(map);
3820
0bd2e252 3821 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, LWResult* res, bool* chained) {
3337c2f7
RG
3822
3823 queriesCount++;
3824
3825 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3826 setLWResult(res, 0, true, false, true);
3827 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3828 return 1;
3829 }
3830
3831 return 0;
3832 });
3833
3834 vector<DNSRecord> ret;
3835 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3836 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3837 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3838 BOOST_CHECK(ret[0].d_type == QType::A);
3839 BOOST_CHECK_EQUAL(queriesCount, 1);
3840}
3841
3842BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3843 std::unique_ptr<SyncRes> sr;
895449a5 3844 initSR(sr);
3337c2f7
RG
3845
3846 primeHints();
3847
3848 size_t queriesCount = 0;
3849 const DNSName target("test.powerdns.com.");
3850 const ComboAddress targetAddr("192.0.2.2");
3851 const DNSName authZone("powerdns.com");
3852
3853 SyncRes::AuthDomain ad;
3854 ad.d_name = authZone;
3855 DNSRecord dr;
3856 dr.d_place = DNSResourceRecord::ANSWER;
3857 dr.d_name = authZone;
3858 dr.d_type = QType::SOA;
3859 dr.d_ttl = 3600;
3860 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3861 ad.d_records.insert(dr);
3862
3863 dr.d_place = DNSResourceRecord::ANSWER;
3864 dr.d_name = DNSName("*.powerdns.com.");
3865 dr.d_type = QType::A;
3866 dr.d_ttl = 3600;
3867 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3868 ad.d_records.insert(dr);
3869
3870 auto map = std::make_shared<SyncRes::domainmap_t>();
3871 (*map)[authZone] = ad;
3872 SyncRes::setDomainMap(map);
3873
0bd2e252 3874 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, LWResult* res, bool* chained) {
3337c2f7
RG
3875
3876 queriesCount++;
3877
3878 return 0;
3879 });
3880
3881 vector<DNSRecord> ret;
3882 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3883 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3884 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3885 BOOST_CHECK(ret[0].d_type == QType::A);
3886 BOOST_CHECK_EQUAL(queriesCount, 0);
3887}
3888
3889BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3890 std::unique_ptr<SyncRes> sr;
895449a5 3891 initSR(sr);
3337c2f7
RG
3892
3893 primeHints();
3894
3895 size_t queriesCount = 0;
3896 const DNSName target("test.powerdns.com.");
3897 const ComboAddress targetAddr("192.0.2.2");
3898 const DNSName authZone("powerdns.com");
3899
3900 SyncRes::AuthDomain ad;
3901 ad.d_name = authZone;
3902 DNSRecord dr;
3903 dr.d_place = DNSResourceRecord::ANSWER;
3904 dr.d_name = authZone;
3905 dr.d_type = QType::SOA;
3906 dr.d_ttl = 3600;
3907 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3908 ad.d_records.insert(dr);
3909
3910 dr.d_place = DNSResourceRecord::ANSWER;
3911 dr.d_name = DNSName("*.powerdns.com.");
3912 dr.d_type = QType::A;
3913 dr.d_ttl = 3600;
3914 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3915 ad.d_records.insert(dr);
3916
3917 auto map = std::make_shared<SyncRes::domainmap_t>();
3918 (*map)[authZone] = ad;
3919 SyncRes::setDomainMap(map);
3920
0bd2e252 3921 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, LWResult* res, bool* chained) {
3337c2f7
RG
3922
3923 queriesCount++;
3924
3925 return 0;
3926 });
3927
3928 vector<DNSRecord> ret;
3929 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3930 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3931 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3932 BOOST_CHECK(ret[0].d_type == QType::SOA);
3933 BOOST_CHECK_EQUAL(queriesCount, 0);
3934}
3935
3936BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3937 std::unique_ptr<SyncRes> sr;
895449a5 3938 initSR(sr);
3337c2f7
RG
3939
3940 primeHints();
3941
3942 size_t queriesCount = 0;
3943 const DNSName target("powerdns.com.");
3944 const ComboAddress addr("192.0.2.5");
3945
3946 SyncRes::AuthDomain ad;
3947 ad.d_name = target;
3948 DNSRecord dr;
3949 dr.d_place = DNSResourceRecord::ANSWER;
3950 dr.d_name = target;
3951 dr.d_type = QType::SOA;
3952 dr.d_ttl = 3600;
3953 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3954 ad.d_records.insert(dr);
3955
3956 dr.d_place = DNSResourceRecord::ANSWER;
3957 dr.d_name = target;
3958 dr.d_type = QType::A;
3959 dr.d_ttl = 3600;
3960 dr.d_content = std::make_shared<ARecordContent>(addr);
3961 ad.d_records.insert(dr);
3962
3963 auto map = std::make_shared<SyncRes::domainmap_t>();
3964 (*map)[target] = ad;
3965 SyncRes::setDomainMap(map);
3966
0bd2e252 3967 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, LWResult* res, bool* chained) {
3337c2f7
RG
3968
3969 queriesCount++;
3970 setLWResult(res, 0, true, false, true);
3971 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3972 return 1;
3973 });
3974
3975 /* simulate a no-RD query */
3976 sr->setCacheOnly();
3977
3978 vector<DNSRecord> ret;
3979 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3980 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3981 BOOST_CHECK_EQUAL(ret.size(), 1);
3982 BOOST_CHECK(ret[0].d_type == QType::A);
3983 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3984 BOOST_CHECK_EQUAL(queriesCount, 0);
3985}
3986
8455425c 3987BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
8455425c
RG
3988 init();
3989
3990 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3991 dcke->create(dcke->getBits());
3992 // cerr<<dcke->convertToISC()<<endl;
3993 DNSSECPrivateKey dpk;
3994 dpk.d_flags = 256;
3995 dpk.setKey(dcke);
3996
3997 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3998 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3999
4000 DNSName qname("powerdns.com.");
4001
179b340d 4002 time_t now = time(nullptr);
8455425c 4003 RRSIGRecordContent rrc;
179b340d
RG
4004 /* this RRSIG is valid for the current second only */
4005 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
8455425c
RG
4006
4007 skeyset_t keyset;
4008 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
4009
4010 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
4011 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
4012
179b340d 4013 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
8455425c
RG
4014}
4015
4016BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
4017 std::unique_ptr<SyncRes> sr;
895449a5 4018 initSR(sr, true);
8455425c 4019
0c43f455 4020 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4021
4022 primeHints();
4023 const DNSName target(".");
b7f378d1 4024 testkeysset_t keys;
8455425c
RG
4025
4026 auto luaconfsCopy = g_luaconfs.getCopy();
4027 luaconfsCopy.dsAnchors.clear();
4028 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4029 g_luaconfs.setState(luaconfsCopy);
4030
4031 size_t queriesCount = 0;
4032
0bd2e252 4033 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, LWResult* res, bool* chained) {
8455425c
RG
4034 queriesCount++;
4035
4036 if (domain == target && type == QType::NS) {
4037
4038 setLWResult(res, 0, true, false, true);
4039 char addr[] = "a.root-servers.net.";
4040 for (char idx = 'a'; idx <= 'm'; idx++) {
4041 addr[0] = idx;
4042 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4043 }
4044
4045 addRRSIG(keys, res->d_records, domain, 300);
4046
4047 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4048 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4049
4050 return 1;
4051 } else if (domain == target && type == QType::DNSKEY) {
4052
4053 setLWResult(res, 0, true, false, true);
4054
4055 addDNSKEY(keys, domain, 300, res->d_records);
4056 addRRSIG(keys, res->d_records, domain, 300);
4057
4058 return 1;
4059 }
4060
4061 return 0;
4062 });
4063
4064 vector<DNSRecord> ret;
4065 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4066 BOOST_CHECK_EQUAL(res, RCode::NoError);
4067 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
4068 /* 13 NS + 1 RRSIG */
4069 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4070 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
4071
4072 /* again, to test the cache */
4073 ret.clear();
4074 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4075 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4076 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
4077 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4078 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
4079}
4080
4081BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
4082 std::unique_ptr<SyncRes> sr;
895449a5 4083 initSR(sr, true);
8455425c 4084
0c43f455 4085 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4086
4087 primeHints();
4088 const DNSName target(".");
b7f378d1
RG
4089 testkeysset_t zskeys;
4090 testkeysset_t kskeys;
8455425c
RG
4091
4092 /* Generate key material for "." */
4093 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4094 dckeZ->create(dckeZ->getBits());
4095 DNSSECPrivateKey ksk;
4096 ksk.d_flags = 257;
4097 ksk.setKey(dckeZ);
b7f378d1
RG
4098 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
4099
8455425c
RG
4100 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4101 dckeK->create(dckeK->getBits());
4102 DNSSECPrivateKey zsk;
4103 zsk.d_flags = 256;
4104 zsk.setKey(dckeK);
b7f378d1 4105 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 4106
b7f378d1
RG
4107 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
4108 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
8455425c
RG
4109
4110 /* Set the root DS */
8455425c
RG
4111 auto luaconfsCopy = g_luaconfs.getCopy();
4112 luaconfsCopy.dsAnchors.clear();
b7f378d1 4113 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
8455425c
RG
4114 g_luaconfs.setState(luaconfsCopy);
4115
4116 size_t queriesCount = 0;
4117
0bd2e252 4118 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, LWResult* res, bool* chained) {
8455425c
RG
4119 queriesCount++;
4120
4121 if (domain == target && type == QType::NS) {
4122
4123 setLWResult(res, 0, true, false, true);
4124 char addr[] = "a.root-servers.net.";
4125 for (char idx = 'a'; idx <= 'm'; idx++) {
4126 addr[0] = idx;
4127 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4128 }
4129
4130 addRRSIG(zskeys, res->d_records, domain, 300);
4131
4132 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4133 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4134
4135 return 1;
4136 } else if (domain == target && type == QType::DNSKEY) {
4137
4138 setLWResult(res, 0, true, false, true);
4139
4140 addDNSKEY(kskeys, domain, 300, res->d_records);
4141 addDNSKEY(zskeys, domain, 300, res->d_records);
4142 addRRSIG(kskeys, res->d_records, domain, 300);
4143
4144 return 1;
4145 }
4146
4147 return 0;
4148 });
4149
4150 vector<DNSRecord> ret;
4151 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4152 BOOST_CHECK_EQUAL(res, RCode::NoError);
4153 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
4154 /* 13 NS + 1 RRSIG */
4155 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4156 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
4157
4158 /* again, to test the cache */
4159 ret.clear();
4160 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4161 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4162 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
4163 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4164 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
4165}
4166
4167BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
4168 std::unique_ptr<SyncRes> sr;
895449a5 4169 initSR(sr, true);
8455425c 4170
0c43f455 4171 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4172
4173 primeHints();
4174 const DNSName target(".");
b7f378d1 4175 testkeysset_t keys;
8455425c
RG
4176
4177 auto luaconfsCopy = g_luaconfs.getCopy();
4178 luaconfsCopy.dsAnchors.clear();
4179 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4180 g_luaconfs.setState(luaconfsCopy);
4181
4182 size_t queriesCount = 0;
4183
0bd2e252 4184 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, LWResult* res, bool* chained) {
8455425c
RG
4185 queriesCount++;
4186
4187 if (domain == target && type == QType::NS) {
4188
4189 setLWResult(res, 0, true, false, true);
4190 char addr[] = "a.root-servers.net.";
4191 for (char idx = 'a'; idx <= 'm'; idx++) {
4192 addr[0] = idx;
4193 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4194 }
4195
4196 addRRSIG(keys, res->d_records, domain, 300);
4197
4198 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4199 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4200
4201 return 1;
4202 } else if (domain == target && type == QType::DNSKEY) {
4203
4204 setLWResult(res, 0, true, false, true);
4205
4206 /* No DNSKEY */
4207
4208 return 1;
4209 }
4210
4211 return 0;
4212 });
4213
4214 vector<DNSRecord> ret;
4215 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4216 BOOST_CHECK_EQUAL(res, RCode::NoError);
4217 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
4218 /* 13 NS + 1 RRSIG */
4219 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4220 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
4221
4222 /* again, to test the cache */
4223 ret.clear();
4224 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4225 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4226 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4227 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4228 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
4229}
4230
4231BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
4232 std::unique_ptr<SyncRes> sr;
895449a5 4233 initSR(sr, true);
8455425c 4234
0c43f455 4235 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4236
4237 primeHints();
4238 const DNSName target(".");
b7f378d1
RG
4239 testkeysset_t dskeys;
4240 testkeysset_t keys;
8455425c
RG
4241
4242 /* Generate key material for "." */
4243 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4244 dckeDS->create(dckeDS->getBits());
4245 DNSSECPrivateKey dskey;
4246 dskey.d_flags = 257;
4247 dskey.setKey(dckeDS);
b7f378d1
RG
4248 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
4249
8455425c
RG
4250 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4251 dcke->create(dcke->getBits());
4252 DNSSECPrivateKey dpk;
4253 dpk.d_flags = 256;
4254 dpk.setKey(dcke);
b7f378d1 4255 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 4256
b7f378d1
RG
4257 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
4258 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
8455425c
RG
4259
4260 /* Set the root DS */
8455425c
RG
4261 auto luaconfsCopy = g_luaconfs.getCopy();
4262 luaconfsCopy.dsAnchors.clear();
4263 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4264 g_luaconfs.setState(luaconfsCopy);
4265
4266 size_t queriesCount = 0;
4267
0bd2e252 4268 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, LWResult* res, bool* chained) {
8455425c
RG
4269 queriesCount++;
4270
4271 if (domain == target && type == QType::NS) {
4272
4273 setLWResult(res, 0, true, false, true);
4274 char addr[] = "a.root-servers.net.";
4275 for (char idx = 'a'; idx <= 'm'; idx++) {
4276 addr[0] = idx;
4277 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4278 }
4279
4280 addRRSIG(keys, res->d_records, domain, 300);
4281
4282 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4283 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4284
4285 return 1;
4286 } else if (domain == target && type == QType::DNSKEY) {
4287
4288 setLWResult(res, 0, true, false, true);
4289
4290 addDNSKEY(keys, domain, 300, res->d_records);
4291 addRRSIG(keys, res->d_records, domain, 300);
4292
4293 return 1;
4294 }
4295
4296 return 0;
4297 });
4298
4299 vector<DNSRecord> ret;
4300 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4301 BOOST_CHECK_EQUAL(res, RCode::NoError);
4302 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
4303 /* 13 NS + 1 RRSIG */
4304 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4305 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
4306
4307 /* again, to test the cache */
4308 ret.clear();
4309 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4310 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4311 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4312 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4313 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
4314}
4315
4316BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
4317 std::unique_ptr<SyncRes> sr;
895449a5 4318 initSR(sr, true);
8455425c 4319
0c43f455 4320 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4321
4322 primeHints();
4323 const DNSName target(".");
b7f378d1
RG
4324 testkeysset_t keys;
4325 testkeysset_t rrsigkeys;
8455425c
RG
4326
4327 auto luaconfsCopy = g_luaconfs.getCopy();
4328 luaconfsCopy.dsAnchors.clear();
4329 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4330 g_luaconfs.setState(luaconfsCopy);
4331
4332 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4333 dckeRRSIG->create(dckeRRSIG->getBits());
4334 DNSSECPrivateKey rrsigkey;
4335 rrsigkey.d_flags = 257;
4336 rrsigkey.setKey(dckeRRSIG);
b7f378d1
RG
4337 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
4338
4339 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
8455425c
RG
4340
4341 size_t queriesCount = 0;
4342
0bd2e252 4343 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, LWResult* res, bool* chained) {
8455425c
RG
4344 queriesCount++;
4345
4346 if (domain == target && type == QType::NS) {
4347
4348 setLWResult(res, 0, true, false, true);
4349 char addr[] = "a.root-servers.net.";
4350 for (char idx = 'a'; idx <= 'm'; idx++) {
4351 addr[0] = idx;
4352 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4353 }
4354
4355 addRRSIG(rrsigkeys, res->d_records, domain, 300);
4356
4357 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4358 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4359
4360 return 1;
4361 } else if (domain == target && type == QType::DNSKEY) {
4362
4363 setLWResult(res, 0, true, false, true);
4364
4365 addDNSKEY(keys, domain, 300, res->d_records);
4366 addRRSIG(rrsigkeys, res->d_records, domain, 300);
4367
4368 return 1;
4369 }
4370
4371 return 0;
4372 });
4373
4374 vector<DNSRecord> ret;
4375 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4376 BOOST_CHECK_EQUAL(res, RCode::NoError);
4377 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
4378 /* 13 NS + 1 RRSIG */
4379 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4380 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
4381
4382 /* again, to test the cache */
4383 ret.clear();
4384 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4385 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4386 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4387 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4388 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
4389}
4390
4391BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
4392 std::unique_ptr<SyncRes> sr;
895449a5 4393 initSR(sr, true);
8455425c 4394
0c43f455 4395 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4396
4397 primeHints();
4398 const DNSName target(".");
b7f378d1 4399 testkeysset_t keys;
8455425c
RG
4400
4401 auto luaconfsCopy = g_luaconfs.getCopy();
4402 luaconfsCopy.dsAnchors.clear();
4403 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4404 g_luaconfs.setState(luaconfsCopy);
4405
4406 size_t queriesCount = 0;
4407
0bd2e252 4408 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, LWResult* res, bool* chained) {
8455425c
RG
4409 queriesCount++;
4410
4411 if (domain == target && type == QType::NS) {
4412
4413 setLWResult(res, 0, true, false, true);
4414 char addr[] = "a.root-servers.net.";
4415 for (char idx = 'a'; idx <= 'm'; idx++) {
4416 addr[0] = idx;
4417 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4418 }
4419
4420 /* No RRSIG */
4421
4422 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4423 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4424
4425 return 1;
4426 } else if (domain == target && type == QType::DNSKEY) {
4427
4428 setLWResult(res, 0, true, false, true);
4429
4430 addDNSKEY(keys, domain, 300, res->d_records);
4431 addRRSIG(keys, res->d_records, domain, 300);
4432
4433 return 1;
4434 }
4435
4436 return 0;
4437 });
4438
4439 vector<DNSRecord> ret;
4440 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4441 BOOST_CHECK_EQUAL(res, RCode::NoError);
4442 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
4443 /* 13 NS + 0 RRSIG */
4444 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4445 /* no RRSIG so no query for DNSKEYs */
4446 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4447
4448 /* again, to test the cache */
4449 ret.clear();
4450 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4451 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4452 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4453 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4454 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4455}
4456
4457BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
4458 std::unique_ptr<SyncRes> sr;
895449a5 4459 initSR(sr, true);
8455425c 4460
0c43f455 4461 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4462
4463 primeHints();
4464 const DNSName target(".");
b7f378d1 4465 testkeysset_t keys;
8455425c
RG
4466
4467 /* Generate key material for "." */
4468 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4469 dcke->create(dcke->getBits());
4470 DNSSECPrivateKey dpk;
4471 dpk.d_flags = 256;
4472 dpk.setKey(dcke);
4473 /* Fake algorithm number (private) */
4474 dpk.d_algorithm = 253;
4475
8455425c 4476 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
b7f378d1 4477 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
8455425c
RG
4478 /* Fake algorithm number (private) */
4479 drc.d_algorithm = 253;
4480
b7f378d1 4481 /* Set the root DS */
8455425c
RG
4482 auto luaconfsCopy = g_luaconfs.getCopy();
4483 luaconfsCopy.dsAnchors.clear();
4484 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4485 g_luaconfs.setState(luaconfsCopy);
4486
4487 size_t queriesCount = 0;
4488
0bd2e252 4489 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, LWResult* res, bool* chained) {
8455425c
RG
4490 queriesCount++;
4491
4492 if (domain == target && type == QType::NS) {
4493
4494 setLWResult(res, 0, true, false, true);
4495 char addr[] = "a.root-servers.net.";
4496 for (char idx = 'a'; idx <= 'm'; idx++) {
4497 addr[0] = idx;
4498 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4499 }
4500
4501 addRRSIG(keys, res->d_records, domain, 300);
4502
4503 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4504 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4505
4506 return 1;
4507 } else if (domain == target && type == QType::DNSKEY) {
4508
4509 setLWResult(res, 0, true, false, true);
4510
4511 addDNSKEY(keys, domain, 300, res->d_records);
4512 addRRSIG(keys, res->d_records, domain, 300);
4513
4514 return 1;
4515 }
4516
4517 return 0;
4518 });
4519
4520 vector<DNSRecord> ret;
4521 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4522 BOOST_CHECK_EQUAL(res, RCode::NoError);
4523 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4524 /* 13 NS + 1 RRSIG */
4525 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4526 /* no supported DS so no query for DNSKEYs */
4527 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4528
4529 /* again, to test the cache */
4530 ret.clear();
4531 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4532 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4533 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4534 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4535 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4536}
4537
4538BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
4539 std::unique_ptr<SyncRes> sr;
895449a5 4540 initSR(sr, true);
8455425c 4541
0c43f455 4542 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4543
4544 primeHints();
4545 const DNSName target(".");
b7f378d1 4546 testkeysset_t keys;
8455425c
RG
4547
4548 /* Generate key material for "." */
4549 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4550 dcke->create(dcke->getBits());
4551 DNSSECPrivateKey dpk;
4552 dpk.d_flags = 256;
4553 dpk.setKey(dcke);
8455425c
RG
4554 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
4555 /* Fake digest number (reserved) */
4556 drc.d_digesttype = 0;
4557
b7f378d1
RG
4558 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
4559
4560 /* Set the root DS */
8455425c
RG
4561 auto luaconfsCopy = g_luaconfs.getCopy();
4562 luaconfsCopy.dsAnchors.clear();
4563 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4564 g_luaconfs.setState(luaconfsCopy);
4565
4566 size_t queriesCount = 0;
4567
0bd2e252 4568 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, LWResult* res, bool* chained) {
8455425c
RG
4569 queriesCount++;
4570
4571 if (domain == target && type == QType::NS) {
4572
4573 setLWResult(res, 0, true, false, true);
4574 char addr[] = "a.root-servers.net.";
4575 for (char idx = 'a'; idx <= 'm'; idx++) {
4576 addr[0] = idx;
4577 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4578 }
4579
4580 addRRSIG(keys, res->d_records, domain, 300);
4581
4582 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4583 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4584
4585 return 1;
4586 } else if (domain == target && type == QType::DNSKEY) {
4587
4588 setLWResult(res, 0, true, false, true);
4589
4590 addDNSKEY(keys, domain, 300, res->d_records);
4591 addRRSIG(keys, res->d_records, domain, 300);
4592
4593 return 1;
4594 }
4595
4596 return 0;
4597 });
4598
4599 vector<DNSRecord> ret;
4600 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4601 BOOST_CHECK_EQUAL(res, RCode::NoError);
4602 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4603 /* 13 NS + 1 RRSIG */
4604 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4605 /* no supported DS so no query for DNSKEYs */
4606 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4607
4608 /* again, to test the cache */
4609 ret.clear();
4610 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4611 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4612 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4613 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4614 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4615}
4616
3d5ebf10
RG
4617BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
4618 std::unique_ptr<SyncRes> sr;
4619 initSR(sr, true);
4620
0c43f455 4621 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4622
4623 primeHints();
4624 const DNSName target(".");
4625 testkeysset_t keys;
4626
4627 auto luaconfsCopy = g_luaconfs.getCopy();
4628 luaconfsCopy.dsAnchors.clear();
4629 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4630
4631 g_luaconfs.setState(luaconfsCopy);
4632
4633 size_t queriesCount = 0;
4634
0bd2e252 4635 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, LWResult* res, bool* chained) {
3d5ebf10
RG
4636 queriesCount++;
4637
4638 if (domain == target && type == QType::NS) {
4639
4640 setLWResult(res, 0, true, false, true);
4641 char addr[] = "a.root-servers.net.";
4642 for (char idx = 'a'; idx <= 'm'; idx++) {
4643 addr[0] = idx;
4644 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4645 }
4646
4647 addRRSIG(keys, res->d_records, domain, 300, true);
4648
4649 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4650 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4651
4652 return 1;
4653 } else if (domain == target && type == QType::DNSKEY) {
4654
4655 setLWResult(res, 0, true, false, true);
4656
4657 addDNSKEY(keys, domain, 300, res->d_records);
4658 addRRSIG(keys, res->d_records, domain, 300);
4659
4660 return 1;
4661 }
4662
4663 return 0;
4664 });
4665
4666 vector<DNSRecord> ret;
4667 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4668 BOOST_CHECK_EQUAL(res, RCode::NoError);
4669 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4670 /* 13 NS + 1 RRSIG */
4671 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4672 BOOST_CHECK_EQUAL(queriesCount, 2);
4673
4674 /* again, to test the cache */
4675 ret.clear();
4676 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4677 BOOST_CHECK_EQUAL(res, RCode::NoError);
4678 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4679 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4680 BOOST_CHECK_EQUAL(queriesCount, 2);
4681}
4682
4683BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
4684 std::unique_ptr<SyncRes> sr;
4685 initSR(sr, true);
4686
0c43f455 4687 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4688
4689 primeHints();
4690 const DNSName target(".");
4691 testkeysset_t keys;
4692
4693 auto luaconfsCopy = g_luaconfs.getCopy();
4694 luaconfsCopy.dsAnchors.clear();
4695 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4696
4697 g_luaconfs.setState(luaconfsCopy);
4698
4699 size_t queriesCount = 0;
4700
0bd2e252 4701 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, LWResult* res, bool* chained) {
3d5ebf10
RG
4702 queriesCount++;
4703
4704 if (domain == target && type == QType::NS) {
4705
4706 setLWResult(res, 0, true, false, true);
4707 char addr[] = "a.root-servers.net.";
4708 for (char idx = 'a'; idx <= 'm'; idx++) {
4709 addr[0] = idx;
4710 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4711 }
4712
4713 /* FORCE WRONG ALGO */
4714 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4715
4716 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4717 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4718
4719 return 1;
4720 } else if (domain == target && type == QType::DNSKEY) {
4721
4722 setLWResult(res, 0, true, false, true);
4723
4724 addDNSKEY(keys, domain, 300, res->d_records);
4725 addRRSIG(keys, res->d_records, domain, 300);
4726
4727 return 1;
4728 }
4729
4730 return 0;
4731 });
4732
4733 vector<DNSRecord> ret;
4734 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4735 BOOST_CHECK_EQUAL(res, RCode::NoError);
4736 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4737 /* 13 NS + 1 RRSIG */
4738 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4739 BOOST_CHECK_EQUAL(queriesCount, 2);
4740
4741 /* again, to test the cache */
4742 ret.clear();
4743 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4744 BOOST_CHECK_EQUAL(res, RCode::NoError);
4745 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4746 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4747 BOOST_CHECK_EQUAL(queriesCount, 2);
4748}
4749
f100caac
RG
4750BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds) {
4751 std::unique_ptr<SyncRes> sr;
4752 initSR(sr, true);
4753
4754 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4755
4756 primeHints();
4757 const DNSName target("com.");
4758 const ComboAddress targetAddr("192.0.2.42");
4759 testkeysset_t keys;
4760
4761 auto luaconfsCopy = g_luaconfs.getCopy();
4762 luaconfsCopy.dsAnchors.clear();
4763 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4764 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4765
4766 g_luaconfs.setState(luaconfsCopy);
4767
4768 size_t queriesCount = 0;
4769
0bd2e252 4770 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, LWResult* res, bool* chained) {
f100caac
RG
4771 queriesCount++;
4772
4773 DNSName auth = domain;
4774
4775 if (type == QType::DS || type == QType::DNSKEY) {
4776 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4777 return 0;
4778 }
4779
4780 if (type == QType::DS && domain == target) {
4781 /* remove the last record, which is the DS's RRSIG */
4782 res->d_records.pop_back();
4783 }
4784
4785 return 1;
4786 }
4787
4788 if (isRootServer(ip)) {
4789 setLWResult(res, 0, false, false, true);
4790 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4791 /* Include the DS but omit the RRSIG*/
4792 addDS(DNSName("com."), 300, res->d_records, keys);
4793 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4794 return 1;
4795 }
4796
4797 if (ip == ComboAddress("192.0.2.1:53")) {
4798 setLWResult(res, RCode::NoError, true, false, true);
4799 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4800 addRRSIG(keys, res->d_records, auth, 300);
4801 return 1;
4802 }
4803
4804 return 0;
4805 });
4806
4807 vector<DNSRecord> ret;
4808 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4809 BOOST_CHECK_EQUAL(res, RCode::NoError);
4810 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4811 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4812 BOOST_CHECK_EQUAL(queriesCount, 4);
4813
4814 /* again, to test the cache */
4815 ret.clear();
4816 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4817 BOOST_CHECK_EQUAL(res, RCode::NoError);
4818 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4819 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4820 BOOST_CHECK_EQUAL(queriesCount, 4);
4821
4822 /* now we ask directly for the DS */
4823 ret.clear();
4824 res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4825 BOOST_CHECK_EQUAL(res, RCode::NoError);
4826 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4827 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4828 BOOST_CHECK_EQUAL(queriesCount, 4);
4829}
4830
4831BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds_direct) {
4832 std::unique_ptr<SyncRes> sr;
4833 initSR(sr, true);
4834
4835 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4836
4837 primeHints();
4838 const DNSName target("com.");
4839 testkeysset_t keys;
4840
4841 auto luaconfsCopy = g_luaconfs.getCopy();
4842 luaconfsCopy.dsAnchors.clear();
4843 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4844 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4845
4846 g_luaconfs.setState(luaconfsCopy);
4847
4848 size_t queriesCount = 0;
4849
0bd2e252 4850 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, LWResult* res, bool* chained) {
f100caac
RG
4851 queriesCount++;
4852
4853 DNSName auth = domain;
4854
4855 if (type == QType::DS || type == QType::DNSKEY) {
4856 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4857 return 0;
4858 }
4859
4860 if (type == QType::DS && domain == target) {
4861 /* remove the last record, which is the DS's RRSIG */
4862 res->d_records.pop_back();
4863 }
4864
4865 return 1;
4866 }
4867
4868 if (isRootServer(ip)) {
4869 setLWResult(res, 0, false, false, true);
4870 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4871 /* Include the DS but omit the RRSIG*/
4872 addDS(DNSName("com."), 300, res->d_records, keys);
4873 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4874 return 1;
4875 }
4876
4877 return 0;
4878 });
4879
4880 vector<DNSRecord> ret;
4881 int res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4882 BOOST_CHECK_EQUAL(res, RCode::NoError);
4883 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4884 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4885 BOOST_CHECK_EQUAL(queriesCount, 1);
4886}
4887
b7f378d1 4888BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
8455425c 4889 std::unique_ptr<SyncRes> sr;
895449a5 4890 initSR(sr, true);
8455425c 4891
0c43f455 4892 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4893
4894 primeHints();
4895 const DNSName target("powerdns.com.");
b7f378d1
RG
4896 const ComboAddress targetAddr("192.0.2.42");
4897 testkeysset_t keys;
8455425c
RG
4898
4899 auto luaconfsCopy = g_luaconfs.getCopy();
4900 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4901 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4902 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4903 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
8455425c
RG
4904
4905 g_luaconfs.setState(luaconfsCopy);
4906
4907 size_t queriesCount = 0;
4908
0bd2e252 4909 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, LWResult* res, bool* chained) {
8455425c
RG
4910 queriesCount++;
4911
b7f378d1
RG
4912 DNSName auth = domain;
4913 if (domain == target) {
4914 auth = DNSName("powerdns.com.");
4915 }
5374b03b
RG
4916
4917 if (type == QType::DS || type == QType::DNSKEY) {
4918 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8455425c 4919 }
5374b03b
RG
4920
4921 if (isRootServer(ip)) {
4922 setLWResult(res, 0, false, false, true);
4923 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4924 addDS(DNSName("com."), 300, res->d_records, keys);
4925 addRRSIG(keys, res->d_records, DNSName("."), 300);
4926 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8455425c
RG
4927 return 1;
4928 }
5374b03b
RG
4929
4930 if (ip == ComboAddress("192.0.2.1:53")) {
4931 if (domain == DNSName("com.")) {
4932 setLWResult(res, 0, true, false, true);
4933 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4934 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4935 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4936 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4937 }
5374b03b
RG
4938 else {
4939 setLWResult(res, 0, false, false, true);
4940 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4941 addDS(auth, 300, res->d_records, keys);
4942 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4943 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8455425c 4944 }
5374b03b
RG
4945 return 1;
4946 }
4947
4948 if (ip == ComboAddress("192.0.2.2:53")) {
4949 if (type == QType::NS) {
4950 setLWResult(res, 0, true, false, true);
4951 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4952 addRRSIG(keys, res->d_records, auth, 300);
4953 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4954 addRRSIG(keys, res->d_records, auth, 300);
8455425c 4955 }
5374b03b
RG
4956 else {
4957 setLWResult(res, RCode::NoError, true, false, true);
4958 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4959 addRRSIG(keys, res->d_records, auth, 300);
4960 }
4961 return 1;
8455425c
RG
4962 }
4963
4964 return 0;
4965 });
4966
4967 vector<DNSRecord> ret;
4968 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1
RG
4969 BOOST_CHECK_EQUAL(res, RCode::NoError);
4970 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4971 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4972 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4973
4974 /* again, to test the cache */
4975 ret.clear();
4976 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4977 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4978 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1 4979 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4980 BOOST_CHECK_EQUAL(queriesCount, 8);
8455425c
RG
4981}
4982
428f41b7
RG
4983BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4984 std::unique_ptr<SyncRes> sr;
4985 initSR(sr, true);
4986
0c43f455 4987 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4988
4989 primeHints();
4990 const DNSName target("powerdns.com.");
4991 const ComboAddress targetAddr("192.0.2.42");
4992 testkeysset_t keys;
4993
4994 auto luaconfsCopy = g_luaconfs.getCopy();
4995 luaconfsCopy.dsAnchors.clear();
4996 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4997 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4998 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4999 g_luaconfs.setState(luaconfsCopy);
5000
5001 size_t queriesCount = 0;
5002
0bd2e252 5003 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, LWResult* res, bool* chained) {
428f41b7
RG
5004 queriesCount++;
5005
5006 DNSName auth = domain;
5007 if (domain == target) {
5008 auth = DNSName("powerdns.com.");
5009 }
5374b03b
RG
5010
5011 if (type == QType::DS || type == QType::DNSKEY) {
5012 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 5013 }
5374b03b
RG
5014
5015 if (isRootServer(ip)) {
5016 setLWResult(res, 0, false, false, true);
5017 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5018 addDS(DNSName("com."), 300, res->d_records, keys);
5019 addRRSIG(keys, res->d_records, DNSName("."), 300);
5020 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
5021 return 1;
5022 }
5374b03b
RG
5023
5024 if (ip == ComboAddress("192.0.2.1:53")) {
5025 if (domain == DNSName("com.")) {
5026 setLWResult(res, 0, true, false, true);
5027 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5028 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 5029 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 5030 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 5031 }
5374b03b
RG
5032 else {
5033 setLWResult(res, 0, false, false, true);
5034 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5035 addDS(auth, 300, res->d_records, keys);
5036 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5037 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 5038 }
5374b03b
RG
5039 return 1;
5040 }
5041
5042 if (ip == ComboAddress("192.0.2.2:53")) {
5043 if (type == QType::NS) {
5044 setLWResult(res, 0, true, false, true);
5045 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5046 addRRSIG(keys, res->d_records, auth, 300);
5047 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5048 addRRSIG(keys, res->d_records, auth, 300);
5049 }
5050 else {
5051 setLWResult(res, RCode::NoError, true, false, true);
5052 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
5053 addRRSIG(keys, res->d_records, auth, 300);
428f41b7 5054 }
5374b03b 5055 return 1;
428f41b7
RG
5056 }
5057
5058 return 0;
5059 });
5060
5061 vector<DNSRecord> ret;
5062 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5063 BOOST_CHECK_EQUAL(res, RCode::NoError);
5064 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5065 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5066 BOOST_CHECK_EQUAL(queriesCount, 8);
5067
5068 /* again, to test the cache */
5069 ret.clear();
5070 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5071 BOOST_CHECK_EQUAL(res, RCode::NoError);
5072 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5073 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5074 BOOST_CHECK_EQUAL(queriesCount, 8);
5075
5076 /* this time we ask for the NS that should be in the cache, to check
5077 the validation status */
5078 ret.clear();
5079 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
5080 BOOST_CHECK_EQUAL(res, RCode::NoError);
5081 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5082 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 5083 BOOST_CHECK_EQUAL(queriesCount, 9);
428f41b7
RG
5084
5085}
5086
5087BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
5088 std::unique_ptr<SyncRes> sr;
5089 initSR(sr, true);
5090
0c43f455 5091 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
5092
5093 primeHints();
5094 const DNSName target("powerdns.com.");
5095 const ComboAddress targetAddr("192.0.2.42");
5096 testkeysset_t keys;
5097
5098 auto luaconfsCopy = g_luaconfs.getCopy();
5099 luaconfsCopy.dsAnchors.clear();
5100 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5101 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5102 g_luaconfs.setState(luaconfsCopy);
5103
5104 size_t queriesCount = 0;
5105
0bd2e252 5106 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, LWResult* res, bool* chained) {
428f41b7
RG
5107 queriesCount++;
5108
5109 DNSName auth = domain;
5110 if (domain == target) {
5111 auth = DNSName("powerdns.com.");
5112 }
5374b03b
RG
5113
5114 if (type == QType::DS || type == QType::DNSKEY) {
5115 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 5116 }
5374b03b
RG
5117
5118 if (isRootServer(ip)) {
5119 setLWResult(res, 0, false, false, true);
5120 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5121 addDS(DNSName("com."), 300, res->d_records, keys);
5122 addRRSIG(keys, res->d_records, DNSName("."), 300);
5123 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
5124 return 1;
5125 }
5374b03b
RG
5126
5127 if (ip == ComboAddress("192.0.2.1:53")) {
5128 if (domain == DNSName("com.")) {
5129 setLWResult(res, 0, true, false, true);
5130 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5131 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 5132 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 5133 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 5134 }
5374b03b
RG
5135 else {
5136 setLWResult(res, 0, false, false, true);
5137 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5138 /* no DS */
5139 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5140 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5141 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 5142 }
5374b03b
RG
5143 return 1;
5144 }
5145
5146 if (ip == ComboAddress("192.0.2.2:53")) {
5147 if (type == QType::NS) {
5148 setLWResult(res, 0, true, false, true);
5149 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5150 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 5151 }
5374b03b
RG
5152 else {
5153 setLWResult(res, RCode::NoError, true, false, true);
5154 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
5155 }
5156 return 1;
428f41b7
RG
5157 }
5158
5159 return 0;
5160 });
5161
5162 vector<DNSRecord> ret;
5163 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5164 BOOST_CHECK_EQUAL(res, RCode::NoError);
5165 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5166 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5167 BOOST_CHECK_EQUAL(queriesCount, 7);
5168
5169 /* again, to test the cache */
5170 ret.clear();
5171 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5172 BOOST_CHECK_EQUAL(res, RCode::NoError);
5173 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5174 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5175 BOOST_CHECK_EQUAL(queriesCount, 7);
5176
5177 /* this time we ask for the NS that should be in the cache, to check
5178 the validation status */
5179 ret.clear();
5180 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
5181 BOOST_CHECK_EQUAL(res, RCode::NoError);
5182 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5183 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 5184 BOOST_CHECK_EQUAL(queriesCount, 8);
428f41b7
RG
5185}
5186
b7f378d1 5187BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
8455425c 5188 std::unique_ptr<SyncRes> sr;
895449a5 5189 initSR(sr, true);
8455425c 5190
0c43f455 5191 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
5192
5193 primeHints();
b7f378d1
RG
5194 const DNSName target("powerdns.com.");
5195 const ComboAddress targetAddr("192.0.2.42");
5196 testkeysset_t keys;
8455425c
RG
5197
5198 auto luaconfsCopy = g_luaconfs.getCopy();
5199 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
5200 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5201 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5202 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5203
5204 /* Add a NTA for "powerdns.com" */
5205 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
8455425c 5206
8455425c
RG
5207 g_luaconfs.setState(luaconfsCopy);
5208
5209 size_t queriesCount = 0;
5210
0bd2e252 5211 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, LWResult* res, bool* chained) {
8455425c
RG
5212 queriesCount++;
5213
b7f378d1
RG
5214 DNSName auth = domain;
5215 if (domain == target) {
5216 auth = DNSName("powerdns.com.");
5217 }
5374b03b
RG
5218
5219 if (type == QType::DS || type == QType::DNSKEY) {
5220 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
b7f378d1 5221 }
5374b03b
RG
5222
5223 if (isRootServer(ip)) {
5224 setLWResult(res, 0, false, false, true);
5225 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5226 addDS(DNSName("com."), 300, res->d_records, keys);
5227 addRRSIG(keys, res->d_records, DNSName("."), 300);
5228 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1
RG
5229 return 1;
5230 }
5374b03b
RG
5231
5232 if (ip == ComboAddress("192.0.2.1:53")) {
5233 if (domain == DNSName("com.")) {
5234 setLWResult(res, 0, true, false, true);
5235 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5236 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 5237 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 5238 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 5239 }
5374b03b
RG
5240 else {
5241 setLWResult(res, 0, false, false, true);
5242 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5243 addDS(auth, 300, res->d_records, keys);
5244 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5245 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1 5246 }
5374b03b
RG
5247 return 1;
5248 }
5249
5250 if (ip == ComboAddress("192.0.2.2:53")) {
5251 if (type == QType::NS) {
5252 setLWResult(res, 0, true, false, true);
5253 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5254 addRRSIG(keys, res->d_records, auth, 300);
5255 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5256 addRRSIG(keys, res->d_records, auth, 300);
5257 }
5258 else {
5259 setLWResult(res, RCode::NoError, true, false, true);
5260 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
5261 addRRSIG(keys, res->d_records, auth, 300);
b7f378d1 5262 }
5374b03b 5263 return 1;
b7f378d1
RG
5264 }
5265
5266 return 0;
5267 });
5268
5269 vector<DNSRecord> ret;
5270 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5271 BOOST_CHECK_EQUAL(res, RCode::NoError);
5272 /* Should be insecure because of the NTA */
5273 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5274 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 5275 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
5276
5277 /* again, to test the cache */
5278 ret.clear();
5279 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5280 BOOST_CHECK_EQUAL(res, RCode::NoError);
5281 /* Should be insecure because of the NTA */
5282 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5283 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 5284 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
5285}
5286
5287BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
5288 std::unique_ptr<SyncRes> sr;
895449a5 5289 initSR(sr, true);
b7f378d1 5290
0c43f455 5291 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5292
5293 primeHints();
5294 const DNSName target("powerdns.com.");
5295 const ComboAddress targetAddr("192.0.2.42");
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 /* Add a NTA for "powerdns.com" */
5305 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
5306
5307 g_luaconfs.setState(luaconfsCopy);
5308
5309 size_t queriesCount = 0;
5310
0bd2e252 5311 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, LWResult* res, bool* chained) {
b7f378d1
RG
5312 queriesCount++;
5313
5314 if (type == QType::DS || type == QType::DNSKEY) {
5e543cab 5315 setLWResult(res, 0, true, false, true);
b7f378d1
RG
5316 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5317 return 1;
5318 }
f24465e5 5319 else {
b7f378d1
RG
5320 if (isRootServer(ip)) {
5321 setLWResult(res, 0, false, false, true);
5322 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5323 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5324 return 1;
5325 }
5326 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5327 if (domain == DNSName("com.")) {
5328 setLWResult(res, 0, true, false, true);
5329 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5330 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5331 }
5332 else {
5333 setLWResult(res, 0, false, false, true);
5334 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5335 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5336 }
b7f378d1
RG
5337 return 1;
5338 }
5339 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5340 if (type == QType::NS) {
5341 setLWResult(res, 0, true, false, true);
5342 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5343 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5344 }
5345 else {
5346 setLWResult(res, RCode::NoError, true, false, true);
5347 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
5348 }
b7f378d1
RG
5349 return 1;
5350 }
5351 }
5352
5353 return 0;
5354 });
5355
5356 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
5357 vector<DNSRecord> ret;
5358 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5359 BOOST_CHECK_EQUAL(res, RCode::NoError);
5360 /* Should be insecure because of the NTA */
5361 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5362 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 5363 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
5364
5365 /* again, to test the cache */
5366 ret.clear();
5367 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5368 BOOST_CHECK_EQUAL(res, RCode::NoError);
5369 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5370 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 5371 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
5372}
5373
5374BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
5375 std::unique_ptr<SyncRes> sr;
895449a5 5376 initSR(sr, true);
b7f378d1 5377
0c43f455 5378 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5379
5380 primeHints();
5381 const DNSName target("powerdns.com.");
5382 testkeysset_t keys;
5383
5384 auto luaconfsCopy = g_luaconfs.getCopy();
5385 luaconfsCopy.dsAnchors.clear();
5386 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5387 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5388 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5389
5390 g_luaconfs.setState(luaconfsCopy);
5391
5392 size_t queriesCount = 0;
5393
0bd2e252 5394 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, LWResult* res, bool* chained) {
b7f378d1
RG
5395 queriesCount++;
5396
5374b03b
RG
5397 if (type == QType::DS || type == QType::DNSKEY) {
5398 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 5399 }
f24465e5 5400 else {
b7f378d1
RG
5401 if (isRootServer(ip)) {
5402 setLWResult(res, 0, false, false, true);
5403 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5404 addDS(DNSName("com."), 300, res->d_records, keys);
5405 addRRSIG(keys, res->d_records, DNSName("."), 300);
5406 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5407 return 1;
5408 }
5409 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5410 if (domain == DNSName("com.")) {
5411 setLWResult(res, 0, true, false, true);
5412 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5413 addRRSIG(keys, res->d_records, domain, 300);
5414 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5415 addRRSIG(keys, res->d_records, domain, 300);
5416 }
5417 else {
5418 setLWResult(res, 0, false, false, true);
5419 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5420 addDS(domain, 300, res->d_records, keys);
5421 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5422 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5423 }
b7f378d1
RG
5424 return 1;
5425 }
5426 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5427 if (type == QType::NS) {
5428 setLWResult(res, 0, true, false, true);
5429 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5430 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5431 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5432 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5433 }
5434 else {
5435 setLWResult(res, 0, true, false, true);
5436 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5437 addRRSIG(keys, res->d_records, domain, 300);
5438 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
5439 addRRSIG(keys, res->d_records, domain, 300);
5440 }
b7f378d1
RG
5441 return 1;
5442 }
5443 }
5444
5445 return 0;
5446 });
5447
5448 vector<DNSRecord> ret;
5449 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5450 BOOST_CHECK_EQUAL(res, RCode::NoError);
5451 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5452 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5453 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5454
5455 /* again, to test the cache */
5456 ret.clear();
5457 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5458 BOOST_CHECK_EQUAL(res, RCode::NoError);
5459 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5460 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5461 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5462}
5463
5464BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
5465 std::unique_ptr<SyncRes> sr;
895449a5 5466 initSR(sr, true);
b7f378d1 5467
0c43f455 5468 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5469
5470 primeHints();
5471 const DNSName target("nx.powerdns.com.");
5472 testkeysset_t keys;
5473
5474 auto luaconfsCopy = g_luaconfs.getCopy();
5475 luaconfsCopy.dsAnchors.clear();
5476 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5477 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5478 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5479
5480 g_luaconfs.setState(luaconfsCopy);
5481
5482 size_t queriesCount = 0;
5483
0bd2e252 5484 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, LWResult* res, bool* chained) {
b7f378d1
RG
5485 queriesCount++;
5486
5487 DNSName auth = domain;
5488 if (domain == target) {
5489 auth = DNSName("powerdns.com.");
5490 }
5374b03b
RG
5491 if (type == QType::DS || type == QType::DNSKEY) {
5492 if (type == QType::DS && domain == target) {
5493 setLWResult(res, RCode::NXDomain, true, false, true);
5494 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5495 addRRSIG(keys, res->d_records, auth, 300);
5496 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5497 addRRSIG(keys, res->d_records, auth, 300);
5498 return 1;
5499 }
5500 else {
5501 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
5502 }
b7f378d1 5503 }
f24465e5 5504 else {
b7f378d1
RG
5505 if (isRootServer(ip)) {
5506 setLWResult(res, 0, false, false, true);
5507 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5508 addDS(DNSName("com."), 300, res->d_records, keys);
5509 addRRSIG(keys, res->d_records, DNSName("."), 300);
5510 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5511 return 1;
5512 }
5513 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5514 if (domain == DNSName("com.")) {
5515 setLWResult(res, 0, true, false, true);
5516 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5517 addRRSIG(keys, res->d_records, domain, 300);
5518 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5519 addRRSIG(keys, res->d_records, domain, 300);
5520 }
5521 else {
5522 setLWResult(res, 0, false, false, true);
5523 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5524 addDS(auth, 300, res->d_records, keys);
5525 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5526 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5527 }
b7f378d1
RG
5528 return 1;
5529 }
5530 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5531 if (type == QType::NS) {
5532 setLWResult(res, 0, true, false, true);
5533 if (domain == DNSName("powerdns.com.")) {
5534 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5535 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5536 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5537 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5538 }
5539 else {
5540 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5541 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5542 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5543 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5544 }
5545 }
5546 else {
5547 setLWResult(res, RCode::NXDomain, true, false, true);
5548 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5549 addRRSIG(keys, res->d_records, auth, 300);
5550 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5551 addRRSIG(keys, res->d_records, auth, 300);
9b061cf5
RG
5552 /* add wildcard denial */
5553 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5554 addRRSIG(keys, res->d_records, auth, 300);
f24465e5 5555 }
b7f378d1
RG
5556 return 1;
5557 }
5558 }
5559
5560 return 0;
5561 });
5562
5563 vector<DNSRecord> ret;
5564 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5565 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5566 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5567 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5568 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5569
5570 /* again, to test the cache */
5571 ret.clear();
5572 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5573 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5574 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5575 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5576 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5577}
5578
2b984251
RG
5579BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
5580 std::unique_ptr<SyncRes> sr;
5581 initSR(sr, true);
5582
0c43f455 5583 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2b984251
RG
5584
5585 primeHints();
5586 const DNSName target("www.powerdns.com.");
5587 testkeysset_t keys;
5588
5589 auto luaconfsCopy = g_luaconfs.getCopy();
5590 luaconfsCopy.dsAnchors.clear();
5591 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5592 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5593 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5594
5595 g_luaconfs.setState(luaconfsCopy);
5596
5597 size_t queriesCount = 0;
5598
0bd2e252 5599 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, LWResult* res, bool* chained) {
2b984251
RG
5600 queriesCount++;
5601
5374b03b
RG
5602 if (type == QType::DS || type == QType::DNSKEY) {
5603 if (type == QType::DS && domain == target) {
5604 setLWResult(res, RCode::NoError, true, false, true);
5605 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5606 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5607 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5608 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5609 return 1;
5610 }
5611 else {
5612 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5613 }
2b984251 5614 }
f24465e5 5615 else {
2b984251
RG
5616 if (isRootServer(ip)) {
5617 setLWResult(res, 0, false, false, true);
5618 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5619 addDS(DNSName("com."), 300, res->d_records, keys);
5620 addRRSIG(keys, res->d_records, DNSName("."), 300);
5621 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5622 return 1;
5623 }
5624 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5625 if (domain == DNSName("com.")) {
5626 setLWResult(res, 0, true, false, true);
5627 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5628 addRRSIG(keys, res->d_records, domain, 300);
5629 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5630 addRRSIG(keys, res->d_records, domain, 300);
5631 }
5632 else {
5633 setLWResult(res, 0, false, false, true);
5634 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5635 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5636 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5637 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5638 }
2b984251
RG
5639 return 1;
5640 }
5641 else if (ip == ComboAddress("192.0.2.2:53")) {
5642 setLWResult(res, 0, true, false, true);
f24465e5
RG
5643 if (type == QType::NS) {
5644 if (domain == DNSName("powerdns.com.")) {
5645 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5646 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5647 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5648 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5649 }
5650 else {
5651 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5652 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5653 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5654 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5655 }
5656 }
5657 else {
5658 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5659 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
9b061cf5 5660 /* we need to add the proof that this name does not exist, so the wildcard may apply */
f24465e5
RG
5661 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5662 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5663 }
2b984251
RG
5664 return 1;
5665 }
5666 }
5667
5668 return 0;
5669 });
5670
5671 vector<DNSRecord> ret;
5672 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5673 BOOST_CHECK_EQUAL(res, RCode::NoError);
5674 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5675 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5676 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5677
5678 /* again, to test the cache */
5679 ret.clear();
5680 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5681 BOOST_CHECK_EQUAL(res, RCode::NoError);
5682 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5683 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5684 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5685}
5686
9b061cf5
RG
5687BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
5688 std::unique_ptr<SyncRes> sr;
5689 initSR(sr, true);
5690
5691 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5692
5693 primeHints();
5694 const DNSName target("www.com.");
5695 testkeysset_t keys;
5696
5697 auto luaconfsCopy = g_luaconfs.getCopy();
5698 luaconfsCopy.dsAnchors.clear();
5699 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5700 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5701
5702 g_luaconfs.setState(luaconfsCopy);
5703
5704 size_t queriesCount = 0;
5705
0bd2e252 5706 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, LWResult* res, bool* chained) {
9b061cf5
RG
5707 queriesCount++;
5708
5709 if (type == QType::DS || type == QType::DNSKEY) {
5710 if (type == QType::DS && domain == target) {
5711 DNSName auth("com.");
5712 setLWResult(res, 0, true, false, true);
5713
5714 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5715 addRRSIG(keys, res->d_records, auth, 300);
5716 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
5717 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
5718 addRRSIG(keys, res->d_records, auth, 300);
5719 return 1;
5720 }
5721 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5722 }
5723 else {
5724 if (isRootServer(ip)) {
5725 setLWResult(res, 0, false, false, true);
5726 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5727 addDS(DNSName("com."), 300, res->d_records, keys);
5728 addRRSIG(keys, res->d_records, DNSName("."), 300);
5729 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5730 return 1;
5731 }
5732 else if (ip == ComboAddress("192.0.2.1:53")) {
5733 setLWResult(res, 0, true, false, true);
5734 /* no data */
5735 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5736 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5737 /* no record for this name */
5738 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
5739 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5740 /* a wildcard matches but has no record for this type */
5741 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5742 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5743 return 1;
5744 }
5745 }
5746
5747 return 0;
5748 });
5749
5750 vector<DNSRecord> ret;
5751 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5752 BOOST_CHECK_EQUAL(res, RCode::NoError);
5753 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5754 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5755 BOOST_CHECK_EQUAL(queriesCount, 6);
5756
5757 /* again, to test the cache */
5758 ret.clear();
5759 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5760 BOOST_CHECK_EQUAL(res, RCode::NoError);
5761 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5762 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5763 BOOST_CHECK_EQUAL(queriesCount, 6);
5764}
5765
5766BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
5767 std::unique_ptr<SyncRes> sr;
5768 initSR(sr, true);
5769
5770 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5771
5772 primeHints();
5773 const DNSName target("www.com.");
5774 testkeysset_t keys;
5775
5776 auto luaconfsCopy = g_luaconfs.getCopy();
5777 luaconfsCopy.dsAnchors.clear();
5778 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5779 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5780
5781 g_luaconfs.setState(luaconfsCopy);
5782
5783 size_t queriesCount = 0;
5784
0bd2e252 5785 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, LWResult* res, bool* chained) {
9b061cf5
RG
5786 queriesCount++;
5787
5788 if (type == QType::DS || type == QType::DNSKEY) {
5789 if (type == QType::DS && domain == target) {
5790 DNSName auth("com.");
5791 setLWResult(res, 0, true, false, true);
5792
5793 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5794 addRRSIG(keys, res->d_records, auth, 300);
5795 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5796 /* first the closest encloser */
5797 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5798 addRRSIG(keys, res->d_records, auth, 300);
5799 /* then the next closer */
5800 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5801 addRRSIG(keys, res->d_records, auth, 300);
5802 /* a wildcard matches but has no record for this type */
5803 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5804 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5805 return 1;
5806 }
5807 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
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 setLWResult(res, 0, true, false, true);
5820 /* no data */
5821 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5822 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5823 /* no record for this name */
5824 /* first the closest encloser */
5825 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5826 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5827 /* then the next closer */
5828 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5829 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5830 /* a wildcard matches but has no record for this type */
5831 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5832 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5833 return 1;
5834 }
5835 }
5836
5837 return 0;
5838 });
5839
5840 vector<DNSRecord> ret;
5841 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5842 BOOST_CHECK_EQUAL(res, RCode::NoError);
5843 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5844 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5845 BOOST_CHECK_EQUAL(queriesCount, 6);
5846
5847 /* again, to test the cache */
5848 ret.clear();
5849 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5850 BOOST_CHECK_EQUAL(res, RCode::NoError);
5851 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5852 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5853 BOOST_CHECK_EQUAL(queriesCount, 6);
5854}
5855
b7c40613
RG
5856BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5857 std::unique_ptr<SyncRes> sr;
5858 initSR(sr, true);
5859
5860 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5861
5862 primeHints();
5863 const DNSName target("www.com.");
5864 testkeysset_t keys;
5865
5866 auto luaconfsCopy = g_luaconfs.getCopy();
5867 luaconfsCopy.dsAnchors.clear();
5868 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5869 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5870
5871 g_luaconfs.setState(luaconfsCopy);
5872
5873 size_t queriesCount = 0;
5874
0bd2e252 5875 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, LWResult* res, bool* chained) {
b7c40613
RG
5876 queriesCount++;
5877
5878 if (type == QType::DS || type == QType::DNSKEY) {
5879 if (type == QType::DS && domain == target) {
5880 DNSName auth("com.");
5881 setLWResult(res, 0, true, false, true);
5882
5883 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5884 addRRSIG(keys, res->d_records, auth, 300);
5885 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5886 /* first the closest encloser */
5887 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5888 addRRSIG(keys, res->d_records, auth, 300);
5889 /* then the next closer */
5890 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5891 addRRSIG(keys, res->d_records, auth, 300);
5892 /* a wildcard matches but has no record for this type */
5893 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5894 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5895 return 1;
5896 }
5897 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5898 }
5899 else {
5900 if (isRootServer(ip)) {
5901 setLWResult(res, 0, false, false, true);
5902 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5903 addDS(DNSName("com."), 300, res->d_records, keys);
5904 addRRSIG(keys, res->d_records, DNSName("."), 300);
5905 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5906 return 1;
5907 }
5908 else if (ip == ComboAddress("192.0.2.1:53")) {
5909 setLWResult(res, 0, true, false, true);
5910 /* no data */
5911 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5912 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5913 /* no record for this name */
5914 /* first the closest encloser */
5915 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5916 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5917 /* then the next closer */
5918 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5919 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5920 /* a wildcard matches but has no record for this type */
5921 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5922 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5923 return 1;
5924 }
5925 }
5926
5927 return 0;
5928 });
5929
5930 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5931 vector<DNSRecord> ret;
5932 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5933 BOOST_CHECK_EQUAL(res, RCode::NoError);
5934 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5935 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5936 BOOST_CHECK_EQUAL(queriesCount, 6);
5937
5938 /* again, to test the cache */
5939 ret.clear();
5940 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5941 BOOST_CHECK_EQUAL(res, RCode::NoError);
5942 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5943 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5944 BOOST_CHECK_EQUAL(queriesCount, 6);
5945}
5946
9b061cf5
RG
5947BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5948 std::unique_ptr<SyncRes> sr;
5949 initSR(sr, true);
5950
5951 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5952
5953 primeHints();
e4894ce0 5954 const DNSName target("www.sub.powerdns.com.");
9b061cf5
RG
5955 testkeysset_t keys;
5956
5957 auto luaconfsCopy = g_luaconfs.getCopy();
5958 luaconfsCopy.dsAnchors.clear();
5959 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5960 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5961 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5962
5963 g_luaconfs.setState(luaconfsCopy);
5964
5965 size_t queriesCount = 0;
5966
0bd2e252 5967 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, LWResult* res, bool* chained) {
9b061cf5
RG
5968 queriesCount++;
5969
5970 if (type == QType::DS || type == QType::DNSKEY) {
e4894ce0 5971 if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) {
9b061cf5
RG
5972 setLWResult(res, RCode::NoError, true, false, true);
5973 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5974 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
e4894ce0
RG
5975 if (domain == DNSName("sub.powerdns.com")) {
5976 addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5977 }
5978 else if (domain == target) {
5979 addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5980 }
9b061cf5
RG
5981 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5982 return 1;
5983 }
5984 else {
5985 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5986 }
5987 }
5988 else {
5989 if (isRootServer(ip)) {
5990 setLWResult(res, 0, false, false, true);
5991 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5992 addDS(DNSName("com."), 300, res->d_records, keys);
5993 addRRSIG(keys, res->d_records, DNSName("."), 300);
5994 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5995 return 1;
5996 }
5997 else if (ip == ComboAddress("192.0.2.1:53")) {
5998 if (domain == DNSName("com.")) {
5999 setLWResult(res, 0, true, false, true);
6000 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6001 addRRSIG(keys, res->d_records, domain, 300);
6002 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6003 addRRSIG(keys, res->d_records, domain, 300);
6004 }
6005 else {
6006 setLWResult(res, 0, false, false, true);
6007 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6008 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6009 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6010 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6011 }
6012 return 1;
6013 }
6014 else if (ip == ComboAddress("192.0.2.2:53")) {
6015 setLWResult(res, 0, true, false, true);
6016 if (type == QType::NS) {
6017 if (domain == DNSName("powerdns.com.")) {
6018 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6019 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6020 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6021 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6022 }
6023 else {
6024 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6025 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6026 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
6027 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6028 }
6029 }
6030 else {
6031 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6032 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
6033 /* we need to add the proof that this name does not exist, so the wildcard may apply */
6034 /* first the closest encloser */
6035 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
6036 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6037 /* then the next closer */
e4894ce0 6038 addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
9b061cf5
RG
6039 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6040 }
6041 return 1;
6042 }
6043 }
6044
6045 return 0;
6046 });
6047
6048 vector<DNSRecord> ret;
6049 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6050 BOOST_CHECK_EQUAL(res, RCode::NoError);
6051 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6052 BOOST_REQUIRE_EQUAL(ret.size(), 6);
e4894ce0 6053 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
6054
6055 /* again, to test the cache */
6056 ret.clear();
6057 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6058 BOOST_CHECK_EQUAL(res, RCode::NoError);
6059 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6060 BOOST_REQUIRE_EQUAL(ret.size(), 6);
e4894ce0 6061 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
6062}
6063
b7c40613
RG
6064BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
6065 std::unique_ptr<SyncRes> sr;
6066 initSR(sr, true);
6067
6068 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6069
6070 primeHints();
6071 const DNSName target("www.powerdns.com.");
6072 testkeysset_t keys;
6073
6074 auto luaconfsCopy = g_luaconfs.getCopy();
6075 luaconfsCopy.dsAnchors.clear();
6076 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6077 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6078 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6079
6080 g_luaconfs.setState(luaconfsCopy);
6081
6082 size_t queriesCount = 0;
6083
0bd2e252 6084 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, LWResult* res, bool* chained) {
b7c40613
RG
6085 queriesCount++;
6086
6087 if (type == QType::DS || type == QType::DNSKEY) {
6088 if (type == QType::DS && domain == target) {
6089 setLWResult(res, RCode::NoError, true, false, true);
6090 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6091 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6092 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
6093 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6094 return 1;
6095 }
6096 else {
6097 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6098 }
6099 }
6100 else {
6101 if (isRootServer(ip)) {
6102 setLWResult(res, 0, false, false, true);
6103 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6104 addDS(DNSName("com."), 300, res->d_records, keys);
6105 addRRSIG(keys, res->d_records, DNSName("."), 300);
6106 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6107 return 1;
6108 }
6109 else if (ip == ComboAddress("192.0.2.1:53")) {
6110 if (domain == DNSName("com.")) {
6111 setLWResult(res, 0, true, false, true);
6112 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6113 addRRSIG(keys, res->d_records, domain, 300);
6114 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6115 addRRSIG(keys, res->d_records, domain, 300);
6116 }
6117 else {
6118 setLWResult(res, 0, false, false, true);
6119 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6120 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6121 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6122 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6123 }
6124 return 1;
6125 }
6126 else if (ip == ComboAddress("192.0.2.2:53")) {
6127 setLWResult(res, 0, true, false, true);
6128 if (type == QType::NS) {
6129 if (domain == DNSName("powerdns.com.")) {
6130 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6131 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6132 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6133 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6134 }
6135 else {
6136 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6137 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6138 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
6139 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6140 }
6141 }
6142 else {
6143 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6144 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
6145 /* we need to add the proof that this name does not exist, so the wildcard may apply */
6146 /* first the closest encloser */
6147 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
6148 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6149 /* then the next closer */
6150 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
6151 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6152 }
6153 return 1;
6154 }
6155 }
6156
6157 return 0;
6158 });
6159
6160 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
6161 we should end up Insecure */
6162 vector<DNSRecord> ret;
6163 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6164 BOOST_CHECK_EQUAL(res, RCode::NoError);
6165 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6166 BOOST_REQUIRE_EQUAL(ret.size(), 6);
6167 BOOST_CHECK_EQUAL(queriesCount, 9);
6168
6169 /* again, to test the cache */
6170 ret.clear();
6171 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6172 BOOST_CHECK_EQUAL(res, RCode::NoError);
6173 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6174 BOOST_REQUIRE_EQUAL(ret.size(), 6);
6175 BOOST_CHECK_EQUAL(queriesCount, 9);
6176}
6177
9b061cf5
RG
6178BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
6179 std::unique_ptr<SyncRes> sr;
6180 initSR(sr, true);
6181
6182 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6183
6184 primeHints();
6185 const DNSName target("www.powerdns.com.");
6186 testkeysset_t keys;
6187
6188 auto luaconfsCopy = g_luaconfs.getCopy();
6189 luaconfsCopy.dsAnchors.clear();
6190 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6191 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6192 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6193
6194 g_luaconfs.setState(luaconfsCopy);
6195
6196 size_t queriesCount = 0;
6197
0bd2e252 6198 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, LWResult* res, bool* chained) {
9b061cf5
RG
6199 queriesCount++;
6200
6201 if (type == QType::DS || type == QType::DNSKEY) {
6202 if (type == QType::DS && domain == target) {
6203 setLWResult(res, RCode::NoError, true, false, true);
6204 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6205 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6206 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
6207 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6208 return 1;
6209 }
6210 else {
6211 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6212 }
6213 }
6214 else {
6215 if (isRootServer(ip)) {
6216 setLWResult(res, 0, false, false, true);
6217 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6218 addDS(DNSName("com."), 300, res->d_records, keys);
6219 addRRSIG(keys, res->d_records, DNSName("."), 300);
6220 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6221 return 1;
6222 }
6223 else if (ip == ComboAddress("192.0.2.1:53")) {
6224 if (domain == DNSName("com.")) {
6225 setLWResult(res, 0, true, false, true);
6226 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6227 addRRSIG(keys, res->d_records, domain, 300);
6228 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6229 addRRSIG(keys, res->d_records, domain, 300);
6230 }
6231 else {
6232 setLWResult(res, 0, false, false, true);
6233 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6234 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6235 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6236 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6237 }
6238 return 1;
6239 }
6240 else if (ip == ComboAddress("192.0.2.2:53")) {
6241 setLWResult(res, 0, true, false, true);
6242 if (type == QType::NS) {
6243 if (domain == DNSName("powerdns.com.")) {
6244 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6245 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6246 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6247 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6248 }
6249 else {
6250 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6251 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6252 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
6253 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6254 }
6255 }
6256 else {
6257 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6258 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
6259 }
6260 return 1;
6261 }
6262 }
6263
6264 return 0;
6265 });
6266
6267 vector<DNSRecord> ret;
6268 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6269 BOOST_CHECK_EQUAL(res, RCode::NoError);
6270 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6271 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6272 BOOST_CHECK_EQUAL(queriesCount, 9);
6273
6274 /* again, to test the cache */
6275 ret.clear();
6276 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6277 BOOST_CHECK_EQUAL(res, RCode::NoError);
6278 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6279 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6280 BOOST_CHECK_EQUAL(queriesCount, 9);
6281}
6282
a53e8fe3
RG
6283BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
6284 std::unique_ptr<SyncRes> sr;
6285 initSR(sr, true);
6286
0c43f455 6287 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
6288
6289 primeHints();
6290 const DNSName target("www.powerdns.com.");
6291 testkeysset_t keys;
6292
6293 auto luaconfsCopy = g_luaconfs.getCopy();
6294 luaconfsCopy.dsAnchors.clear();
6295 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6296 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6297 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6298
6299 g_luaconfs.setState(luaconfsCopy);
6300
6301 size_t queriesCount = 0;
6302 size_t dsQueriesCount = 0;
6303
0bd2e252 6304 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, LWResult* res, bool* chained) {
a53e8fe3
RG
6305 queriesCount++;
6306
6307 if (type == QType::DS) {
6308 DNSName auth(domain);
6309 auth.chopOff();
6310 dsQueriesCount++;
6311
6312 setLWResult(res, 0, true, false, true);
6313 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6314 addRRSIG(keys, res->d_records, auth, 300);
6315 return 1;
6316 }
6317 else if (type == QType::DNSKEY) {
6318 setLWResult(res, 0, true, false, true);
6319 addDNSKEY(keys, domain, 300, res->d_records);
6320 addRRSIG(keys, res->d_records, domain, 300);
6321 return 1;
6322 }
f24465e5 6323 else {
a53e8fe3
RG
6324 if (isRootServer(ip)) {
6325 setLWResult(res, 0, false, false, true);
6326 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6327 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6328 /* No DS on referral, and no denial of the DS either */
6329 return 1;
6330 }
6331 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
6332 if (domain == DNSName("com.")) {
6333 setLWResult(res, 0, true, false, true);
6334 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6335 addRRSIG(keys, res->d_records, domain, 300);
6336 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6337 addRRSIG(keys, res->d_records, domain, 300);
6338 }
6339 else {
6340 setLWResult(res, 0, false, false, true);
6341 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6342 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6343 /* No DS on referral, and no denial of the DS either */
6344 }
a53e8fe3
RG
6345 return 1;
6346 }
6347 else if (ip == ComboAddress("192.0.2.2:53")) {
6348 setLWResult(res, 0, true, false, true);
f24465e5
RG
6349 if (type == QType::NS) {
6350 if (domain == DNSName("powerdns.com.")) {
6351 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6352 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6353 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6354 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6355 }
6356 else {
6357 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6358 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6359 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
6360 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6361 }
6362 }
6363 else {
6364 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6365 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6366 }
6367
a53e8fe3
RG
6368 return 1;
6369 }
6370 }
6371
6372 return 0;
6373 });
6374
6375 vector<DNSRecord> ret;
6376 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6377 BOOST_CHECK_EQUAL(res, RCode::NoError);
6378 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 6379 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
6380 BOOST_CHECK_EQUAL(queriesCount, 9);
6381 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
6382
6383 /* again, to test the cache */
6384 ret.clear();
6385 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6386 BOOST_CHECK_EQUAL(res, RCode::NoError);
6387 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 6388 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
6389 BOOST_CHECK_EQUAL(queriesCount, 9);
6390 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
6391}
6392
f715542c
RG
6393BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
6394 std::unique_ptr<SyncRes> sr;
6395 initSR(sr, true);
6396
5d7b19c5 6397 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
f715542c
RG
6398
6399 primeHints();
6400 const DNSName target("www.powerdns.com.");
6401 testkeysset_t keys;
6402
6403 auto luaconfsCopy = g_luaconfs.getCopy();
6404 luaconfsCopy.dsAnchors.clear();
6405 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6406 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3cef03e9 6407 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
f715542c
RG
6408 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6409
6410 g_luaconfs.setState(luaconfsCopy);
6411
6412 size_t queriesCount = 0;
6413
0bd2e252 6414 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, LWResult* res, bool* chained) {
f715542c
RG
6415 queriesCount++;
6416
6417 if (type == QType::DS) {
6418 DNSName auth(domain);
6419 auth.chopOff();
6420
6421 setLWResult(res, 0, true, false, true);
6422 if (domain == target) {
6423 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6424 addRRSIG(keys, res->d_records, target, 300);
6425 }
6426 else {
6427 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6428 addRRSIG(keys, res->d_records, auth, 300);
6429 }
6430 return 1;
6431 }
6432 else if (type == QType::DNSKEY) {
6433 setLWResult(res, 0, true, false, true);
6434 addDNSKEY(keys, domain, 300, res->d_records);
6435 addRRSIG(keys, res->d_records, domain, 300);
6436 return 1;
6437 }
6438 else {
6439 if (isRootServer(ip)) {
6440 setLWResult(res, 0, false, false, true);
6441 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6442 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6443 addDS(DNSName("com."), 300, res->d_records, keys);
6444 addRRSIG(keys, res->d_records, DNSName("."), 300);
6445 return 1;
6446 }
6447 else if (ip == ComboAddress("192.0.2.1:53")) {
6448 if (domain == DNSName("com.")) {
6449 setLWResult(res, 0, true, false, true);
6450 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6451 addRRSIG(keys, res->d_records, domain, 300);
6452 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6453 addRRSIG(keys, res->d_records, domain, 300);
6454 }
6455 else {
6456 setLWResult(res, 0, false, false, true);
6457 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6458 /* no DS */
6459 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6460 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6461 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6462 }
6463 return 1;
6464 }
6465 else if (ip == ComboAddress("192.0.2.2:53")) {
6466 if (type == QType::NS) {
6467 if (domain == DNSName("powerdns.com.")) {
6468 setLWResult(res, RCode::Refused, false, false, true);
6469 }
6470 else {
6471 setLWResult(res, 0, true, false, true);
6472 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6473 addRRSIG(keys, res->d_records, domain, 300);
6474 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6475 addRRSIG(keys, res->d_records, domain, 300);
6476 }
6477 }
6478 else {
6479 setLWResult(res, 0, true, false, true);
6480 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6481 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
6482 }
6483
6484 return 1;
6485 }
6486 }
6487
6488 return 0;
6489 });
6490
6491 vector<DNSRecord> ret;
6492 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6493 BOOST_CHECK_EQUAL(res, RCode::NoError);
6494 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6495 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6496 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6497
6498 /* again, to test the cache */
6499 ret.clear();
6500 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6501 BOOST_CHECK_EQUAL(res, RCode::NoError);
6502 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6503 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6504 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6505}
6506
8d2e7fa1
RG
6507BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) {
6508 /* check that we don't accept a signer below us */
6509 std::unique_ptr<SyncRes> sr;
6510 initSR(sr, true);
6511
6512 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6513
6514 primeHints();
6515 const DNSName target("www.powerdns.com.");
6516 testkeysset_t keys;
6517
6518 auto luaconfsCopy = g_luaconfs.getCopy();
6519 luaconfsCopy.dsAnchors.clear();
6520 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6521 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6522 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6523 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6524 generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6525
6526 g_luaconfs.setState(luaconfsCopy);
6527
6528 size_t queriesCount = 0;
6529
0bd2e252 6530 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, LWResult* res, bool* chained) {
8d2e7fa1
RG
6531 queriesCount++;
6532
6533 if (type == QType::DS) {
6534 DNSName auth(domain);
6535 auth.chopOff();
6536
6537 setLWResult(res, 0, true, false, true);
6538 if (domain == target) {
6539 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6540 addRRSIG(keys, res->d_records, target, 300);
6541 }
6542 else {
6543 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6544 addRRSIG(keys, res->d_records, auth, 300);
6545 }
6546 return 1;
6547 }
6548 else if (type == QType::DNSKEY) {
6549 setLWResult(res, 0, true, false, true);
6550 addDNSKEY(keys, domain, 300, res->d_records);
6551 if (domain == DNSName("www.powerdns.com.")) {
6552 addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
6553 }
6554 else {
6555 addRRSIG(keys, res->d_records, domain, 300);
6556 }
6557 return 1;
6558 }
6559 else {
6560 if (isRootServer(ip)) {
6561 setLWResult(res, 0, false, false, true);
6562 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6563 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6564 addDS(DNSName("com."), 300, res->d_records, keys);
6565 addRRSIG(keys, res->d_records, DNSName("."), 300);
6566 return 1;
6567 }
6568 else if (ip == ComboAddress("192.0.2.1:53")) {
6569 if (domain == DNSName("com.")) {
6570 setLWResult(res, 0, true, false, true);
6571 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6572 addRRSIG(keys, res->d_records, domain, 300);
6573 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6574 addRRSIG(keys, res->d_records, domain, 300);
6575 }
6576 else {
6577 setLWResult(res, 0, false, false, true);
6578 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6579 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6580 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6581 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6582 }
6583 return 1;
6584 }
6585 else if (ip == ComboAddress("192.0.2.2:53")) {
6586 if (type == QType::NS) {
6587 setLWResult(res, 0, true, false, true);
6588 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6589 addRRSIG(keys, res->d_records, domain, 300);
6590 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6591 addRRSIG(keys, res->d_records, domain, 300);
6592 }
6593 else {
6594 setLWResult(res, 0, true, false, true);
6595 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6596 addRRSIG(keys, res->d_records, domain, 300);
6597 }
6598
6599 return 1;
6600 }
6601 }
6602
f715542c
RG
6603 return 0;
6604 });
6605
6606 vector<DNSRecord> ret;
6607 int 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);
3cef03e9 6611 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6612
6613 /* again, to test the cache */
6614 ret.clear();
6615 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6616 BOOST_CHECK_EQUAL(res, RCode::NoError);
6617 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6618 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6619 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6620}
6621
a53e8fe3
RG
6622BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
6623 std::unique_ptr<SyncRes> sr;
f24465e5 6624 initSR(sr, true);
a53e8fe3 6625
0c43f455 6626 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
6627
6628 primeHints();
6629 const DNSName target("www.powerdns.com.");
6630 testkeysset_t keys;
6631
6632 auto luaconfsCopy = g_luaconfs.getCopy();
6633 luaconfsCopy.dsAnchors.clear();
6634 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6635 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6636
6637 g_luaconfs.setState(luaconfsCopy);
6638
6639 size_t queriesCount = 0;
6640 size_t dsQueriesCount = 0;
6641
0bd2e252 6642 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, LWResult* res, bool* chained) {
a53e8fe3
RG
6643 queriesCount++;
6644
6645 if (type == QType::DS) {
6646 DNSName auth(domain);
6647 auth.chopOff();
6648 dsQueriesCount++;
6649
6650 setLWResult(res, 0, true, false, true);
6651 if (domain == DNSName("com.")) {
6652 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6653 }
6654 else {
f24465e5
RG
6655 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6656 addRRSIG(keys, res->d_records, DNSName("com."), 300);
a53e8fe3
RG
6657 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
6658 }
6659 addRRSIG(keys, res->d_records, auth, 300);
6660 return 1;
6661 }
6662 else if (type == QType::DNSKEY) {
6663 setLWResult(res, 0, true, false, true);
6664 addDNSKEY(keys, domain, 300, res->d_records);
6665 addRRSIG(keys, res->d_records, domain, 300);
6666 return 1;
6667 }
a69867f2 6668 else {
a53e8fe3
RG
6669 if (isRootServer(ip)) {
6670 setLWResult(res, 0, false, false, true);
6671 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6672 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6673 /* No DS on referral, and no denial of the DS either */
6674 return 1;
6675 }
6676 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6677 if (domain == DNSName("com.")) {
6678 setLWResult(res, 0, true, false, true);
6679 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
f24465e5 6680 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 6681 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
f24465e5 6682 addRRSIG(keys, res->d_records, domain, 300);
a69867f2
RG
6683 }
6684 else {
6685 setLWResult(res, 0, false, false, true);
6686 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6687 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6688 /* No DS on referral, and no denial of the DS either */
6689 }
a53e8fe3
RG
6690 return 1;
6691 }
6692 else if (ip == ComboAddress("192.0.2.2:53")) {
6693 setLWResult(res, 0, true, false, true);
f24465e5
RG
6694 if (type == QType::NS) {
6695 if (domain == DNSName("powerdns.com.")) {
6696 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6697 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6698 }
6699 else {
6700 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6701 }
6702 }
6703 else {
6704 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6705 }
a53e8fe3
RG
6706 return 1;
6707 }
6708 }
6709
6710 return 0;
6711 });
6712
6713 vector<DNSRecord> ret;
6714 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6715 BOOST_CHECK_EQUAL(res, RCode::NoError);
6716 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6717 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6718 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6719 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6720
6721 /* again, to test the cache */
6722 ret.clear();
6723 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6724 BOOST_CHECK_EQUAL(res, RCode::NoError);
6725 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6726 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6727 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6728 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6729}
6730
e59c8907 6731BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
b7f378d1 6732 std::unique_ptr<SyncRes> sr;
895449a5 6733 initSR(sr, true);
b7f378d1 6734
0c43f455 6735 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6736
6737 primeHints();
6738 const DNSName target("powerdns.com.");
6739 testkeysset_t keys;
6740
6741 auto luaconfsCopy = g_luaconfs.getCopy();
6742 luaconfsCopy.dsAnchors.clear();
6743 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6744 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6745 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6746
6747 g_luaconfs.setState(luaconfsCopy);
6748
6749 size_t queriesCount = 0;
6750
0bd2e252 6751 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, LWResult* res, bool* chained) {
b7f378d1
RG
6752 queriesCount++;
6753
5374b03b
RG
6754 if (type == QType::DS || type == QType::DNSKEY) {
6755 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6756 }
a69867f2 6757 else {
b7f378d1
RG
6758 if (isRootServer(ip)) {
6759 setLWResult(res, 0, false, false, true);
6760 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6761 addDS(DNSName("com."), 300, res->d_records, keys);
6762 addRRSIG(keys, res->d_records, DNSName("."), 300);
6763 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6764 return 1;
6765 }
6766 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6767 if (domain == DNSName("com.")) {
6768 setLWResult(res, 0, true, false, true);
6769 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6770 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6771 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6772 }
6773 else {
6774 setLWResult(res, 0, false, false, true);
6775 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6776 addDS(domain, 300, res->d_records, keys);
6777 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6778 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6779 }
b7f378d1
RG
6780 return 1;
6781 }
6782 else if (ip == ComboAddress("192.0.2.2:53")) {
6783 setLWResult(res, 0, true, false, true);
a69867f2
RG
6784 if (type == QType::NS) {
6785 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6786 addRRSIG(keys, res->d_records, domain, 300);
6787 }
6788 else {
6789 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6790 addRRSIG(keys, res->d_records, domain, 300);
6791 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
6792 /* NO RRSIG for the NSEC record! */
6793 }
b7f378d1
RG
6794 return 1;
6795 }
6796 }
6797
6798 return 0;
6799 });
6800
6801 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
6802 vector<DNSRecord> ret;
6803 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6804 BOOST_CHECK_EQUAL(res, RCode::NoError);
6805 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6806 BOOST_CHECK_EQUAL(ret.size(), 3);
a69867f2 6807 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6808
6809 /* again, to test the cache */
6810 ret.clear();
6811 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6812 BOOST_CHECK_EQUAL(res, RCode::NoError);
6813 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6814 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 6815 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6816}
6817
e59c8907 6818BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
b7f378d1 6819 std::unique_ptr<SyncRes> sr;
895449a5 6820 initSR(sr, true);
b7f378d1 6821
0c43f455 6822 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6823
6824 primeHints();
6825 const DNSName target("powerdns.com.");
6826 testkeysset_t keys;
6827
6828 auto luaconfsCopy = g_luaconfs.getCopy();
6829 luaconfsCopy.dsAnchors.clear();
6830 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6831 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6832 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6833
6834 g_luaconfs.setState(luaconfsCopy);
6835
6836 size_t queriesCount = 0;
6837
0bd2e252 6838 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, LWResult* res, bool* chained) {
b7f378d1
RG
6839 queriesCount++;
6840
5374b03b
RG
6841 if (type == QType::DS || type == QType::DNSKEY) {
6842 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6843 }
a69867f2 6844 else {
b7f378d1
RG
6845 if (isRootServer(ip)) {
6846 setLWResult(res, 0, false, false, true);
6847 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6848 addDS(DNSName("com."), 300, res->d_records, keys);
6849 addRRSIG(keys, res->d_records, DNSName("."), 300);
6850 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6851 return 1;
6852 }
6853 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6854 if (domain == DNSName("com.")) {
6855 setLWResult(res, 0, true, false, true);
6856 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6857 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6858 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6859 }
6860 else {
6861 setLWResult(res, 0, false, false, true);
6862 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6863 addDS(domain, 300, res->d_records, keys);
6864 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6865 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6866 }
b7f378d1
RG
6867 return 1;
6868 }
6869 else if (ip == ComboAddress("192.0.2.2:53")) {
6870 setLWResult(res, 0, true, false, true);
a69867f2
RG
6871 if (type == QType::NS) {
6872 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6873 addRRSIG(keys, res->d_records, domain, 300);
6874 }
6875 else {
6876 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6877 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 6878
a69867f2
RG
6879 /* NO NSEC record! */
6880 }
b7f378d1
RG
6881 return 1;
6882 }
6883 }
6884
6885 return 0;
6886 });
6887
6888 /* no NSEC record in a secure zone, should be Bogus! */
6889 vector<DNSRecord> ret;
6890 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6891 BOOST_CHECK_EQUAL(res, RCode::NoError);
6892 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6893 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 6894 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6895
6896 /* again, to test the cache */
6897 ret.clear();
6898 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6899 BOOST_CHECK_EQUAL(res, RCode::NoError);
6900 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6901 BOOST_REQUIRE_EQUAL(ret.size(), 2);
a69867f2 6902 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6903}
6904
6905BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6906 std::unique_ptr<SyncRes> sr;
895449a5 6907 initSR(sr, true);
b7f378d1 6908
0c43f455 6909 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6910
6911 primeHints();
6912 const DNSName target("powerdns.com.");
6913 const ComboAddress targetAddr("192.0.2.42");
6914 testkeysset_t keys;
6915
6916 auto luaconfsCopy = g_luaconfs.getCopy();
6917 luaconfsCopy.dsAnchors.clear();
6918 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6919 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6920
6921 g_luaconfs.setState(luaconfsCopy);
6922
6923 size_t queriesCount = 0;
6924
0bd2e252 6925 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, LWResult* res, bool* chained) {
b7f378d1
RG
6926 queriesCount++;
6927
6928 if (type == QType::DS) {
a53e8fe3 6929 if (domain == target) {
5e543cab 6930 setLWResult(res, 0, true, false, true);
895449a5 6931 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5e543cab 6932 addRRSIG(keys, res->d_records, DNSName("com."), 300);
b7f378d1
RG
6933 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6934 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6935 return 1;
5374b03b
RG
6936 } else {
6937 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1
RG
6938 }
6939 }
6940 else if (type == QType::DNSKEY) {
6941 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6942 setLWResult(res, 0, true, false, true);
6943 addDNSKEY(keys, domain, 300, res->d_records);
6944 addRRSIG(keys, res->d_records, domain, 300);
6945 return 1;
6946 }
6947 else {
5e543cab 6948 setLWResult(res, 0, true, false, true);
895449a5 6949 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6950 return 1;
6951 }
6952 }
a69867f2 6953 else {
b7f378d1
RG
6954 if (isRootServer(ip)) {
6955 setLWResult(res, 0, false, false, true);
6956 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6957 addDS(DNSName("com."), 300, res->d_records, keys);
6958 addRRSIG(keys, res->d_records, DNSName("."), 300);
6959 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6960 return 1;
6961 }
6962 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6963 if (domain == DNSName("com.")) {
6964 setLWResult(res, 0, true, false, true);
6965 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6966 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6967 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6968 }
6969 else {
6970 setLWResult(res, 0, false, false, true);
6971 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6972 /* no DS */
6973 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6974 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6975 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6976 }
b7f378d1
RG
6977 return 1;
6978 }
6979 else if (ip == ComboAddress("192.0.2.2:53")) {
6980 setLWResult(res, 0, true, false, true);
a69867f2
RG
6981 if (type == QType::NS) {
6982 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6983 }
6984 else {
6985 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6986 }
b7f378d1
RG
6987 return 1;
6988 }
6989 }
6990
6991 return 0;
6992 });
6993
6994 vector<DNSRecord> ret;
6995 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6996 BOOST_CHECK_EQUAL(res, RCode::NoError);
6997 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6998 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6999 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2
RG
7000 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
7001 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
7002 1 query for A */
7003 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7004
7005 /* again, to test the cache */
7006 ret.clear();
7007 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7008 BOOST_CHECK_EQUAL(res, RCode::NoError);
7009 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7010 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7011 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2 7012 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7013}
7014
3cef03e9
RG
7015
7016BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
7017 /*
7018 Direct DS query:
7019 - parent is secure, zone is secure: DS should be secure
7020 */
7021 std::unique_ptr<SyncRes> sr;
7022 initSR(sr, true);
7023
7024 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7025
7026 primeHints();
7027 const DNSName target("powerdns.com.");
7028 testkeysset_t keys;
7029
7030 auto luaconfsCopy = g_luaconfs.getCopy();
7031 luaconfsCopy.dsAnchors.clear();
7032 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7033 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7034 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7035
7036 g_luaconfs.setState(luaconfsCopy);
7037
7038 size_t queriesCount = 0;
7039
0bd2e252 7040 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, LWResult* res, bool* chained) {
3cef03e9
RG
7041 queriesCount++;
7042
7043 if (type == QType::DS || type == QType::DNSKEY) {
7044 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7045 }
7046 else {
7047 if (isRootServer(ip)) {
7048 setLWResult(res, 0, false, false, true);
7049 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7050 addDS(DNSName("com."), 300, res->d_records, keys);
7051 addRRSIG(keys, res->d_records, DNSName("."), 300);
7052 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7053 return 1;
7054 }
7055 }
7056
7057 return 0;
7058 });
7059
7060 vector<DNSRecord> ret;
7061 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
7062 BOOST_CHECK_EQUAL(res, RCode::NoError);
7063 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7064 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7065 for (const auto& record : ret) {
7066 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
7067 }
7068 BOOST_CHECK_EQUAL(queriesCount, 4);
7069
7070 /* again, to test the cache */
7071 ret.clear();
7072 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
7073 BOOST_CHECK_EQUAL(res, RCode::NoError);
7074 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7075 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7076 for (const auto& record : ret) {
7077 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
7078 }
7079 BOOST_CHECK_EQUAL(queriesCount, 4);
7080}
7081
7082BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
7083 /*
7084 Direct DS query:
7085 - parent is secure, zone is insecure: DS denial should be secure
7086 */
7087 std::unique_ptr<SyncRes> sr;
7088 initSR(sr, true);
7089
7090 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7091
7092 primeHints();
7093 const DNSName target("powerdns.com.");
7094 testkeysset_t keys;
7095
7096 auto luaconfsCopy = g_luaconfs.getCopy();
7097 luaconfsCopy.dsAnchors.clear();
7098 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7099 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7100
7101 g_luaconfs.setState(luaconfsCopy);
7102
7103 size_t queriesCount = 0;
7104
0bd2e252 7105 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, LWResult* res, bool* chained) {
3cef03e9
RG
7106 queriesCount++;
7107
7108 if (type == QType::DS || type == QType::DNSKEY) {
7109 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7110 }
7111 else {
7112 if (isRootServer(ip)) {
7113 setLWResult(res, 0, false, false, true);
7114 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7115 addDS(DNSName("com."), 300, res->d_records, keys);
7116 addRRSIG(keys, res->d_records, DNSName("."), 300);
7117 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7118 return 1;
7119 }
7120 }
7121
7122 return 0;
7123 });
7124
7125 vector<DNSRecord> ret;
7126 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
7127 BOOST_CHECK_EQUAL(res, RCode::NoError);
7128 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7129 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7130 for (const auto& record : ret) {
7131 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
7132 }
7133 BOOST_CHECK_EQUAL(queriesCount, 4);
7134
7135 /* again, to test the cache */
7136 ret.clear();
7137 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
7138 BOOST_CHECK_EQUAL(res, RCode::NoError);
7139 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7140 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7141 for (const auto& record : ret) {
7142 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
7143 }
7144 BOOST_CHECK_EQUAL(queriesCount, 4);
7145}
7146
70b3fe7a
RG
7147BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
7148 std::unique_ptr<SyncRes> sr;
a69867f2 7149 initSR(sr, true);
70b3fe7a 7150
0c43f455 7151 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
7152
7153 primeHints();
7154 const DNSName target("www.sub.powerdns.com.");
7155 const ComboAddress targetAddr("192.0.2.42");
7156 testkeysset_t keys;
7157
7158 auto luaconfsCopy = g_luaconfs.getCopy();
7159 luaconfsCopy.dsAnchors.clear();
7160 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7161 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7162 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7163
7164 g_luaconfs.setState(luaconfsCopy);
7165
7166 size_t queriesCount = 0;
7167
0bd2e252 7168 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, LWResult* res, bool* chained) {
70b3fe7a
RG
7169 queriesCount++;
7170
7171 if (type == QType::DS) {
7172 if (domain == DNSName("sub.powerdns.com.")) {
5e543cab 7173 setLWResult(res, 0, true, false, true);
70b3fe7a
RG
7174 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7175 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
7176 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7177 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
7178 return 1;
7179 }
7180 else if (domain == DNSName("www.sub.powerdns.com.")) {
5e543cab 7181 setLWResult(res, 0, true, false, true);
70b3fe7a
RG
7182 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);
7183 return 1;
7184 }
5374b03b
RG
7185 else {
7186 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7187 }
70b3fe7a
RG
7188 }
7189 else if (type == QType::DNSKEY) {
a69867f2 7190 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
70b3fe7a
RG
7191 setLWResult(res, 0, true, false, true);
7192 addDNSKEY(keys, domain, 300, res->d_records);
7193 addRRSIG(keys, res->d_records, domain, 300);
7194 return 1;
7195 }
7196 else {
5e543cab 7197 setLWResult(res, 0, true, false, true);
70b3fe7a
RG
7198 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7199 return 1;
7200 }
7201 }
88cb0fe0 7202 else {
70b3fe7a
RG
7203 if (isRootServer(ip)) {
7204 setLWResult(res, 0, false, false, true);
7205 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7206 addDS(DNSName("com."), 300, res->d_records, keys);
7207 addRRSIG(keys, res->d_records, DNSName("."), 300);
7208 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7209 return 1;
7210 }
7211 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7212 if (domain == DNSName("com.")) {
7213 setLWResult(res, 0, true, false, true);
7214 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
7215 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7216 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7217 }
7218 else {
7219 setLWResult(res, 0, false, false, true);
7220 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7221 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7222 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7223 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7224 }
70b3fe7a
RG
7225 return 1;
7226 }
7227 else if (ip == ComboAddress("192.0.2.2:53")) {
7228 setLWResult(res, 0, true, false, true);
a69867f2
RG
7229 if (type == QType::NS) {
7230 if (domain == DNSName("www.sub.powerdns.com.")) {
7231 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);
7232 }
7233 else if (domain == DNSName("sub.powerdns.com.")) {
7234 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
a69867f2
RG
7235 }
7236 else if (domain == DNSName("powerdns.com.")) {
7237 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7238 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
7239 }
7240 } else {
7241 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7242 }
70b3fe7a
RG
7243 return 1;
7244 }
7245 }
7246
7247 return 0;
7248 });
7249
7250 vector<DNSRecord> ret;
7251 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7252 BOOST_CHECK_EQUAL(res, RCode::NoError);
7253 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7254 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7255 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7256 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
7257
7258 /* again, to test the cache */
7259 ret.clear();
7260 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7261 BOOST_CHECK_EQUAL(res, RCode::NoError);
7262 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7263 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7264 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7265 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
7266}
7267
7268BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
7269 std::unique_ptr<SyncRes> sr;
a69867f2 7270 initSR(sr, true);
70b3fe7a 7271
0c43f455 7272 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
7273
7274 primeHints();
7275 const DNSName target("www.sub.powerdns.com.");
7276 const ComboAddress targetAddr("192.0.2.42");
7277 testkeysset_t keys;
7278
7279 auto luaconfsCopy = g_luaconfs.getCopy();
7280 luaconfsCopy.dsAnchors.clear();
7281 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7282 /* No key material for .com */
7283 /* But TA for sub.powerdns.com. */
7284 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7285 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
7286 g_luaconfs.setState(luaconfsCopy);
7287
7288 size_t queriesCount = 0;
7289
0bd2e252 7290 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, LWResult* res, bool* chained) {
70b3fe7a
RG
7291 queriesCount++;
7292
7293 if (type == QType::DS) {
88cb0fe0 7294 if (domain == DNSName("www.sub.powerdns.com")) {
5e543cab 7295 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7296 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);
7297 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7298 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
7299 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7300 }
7301 else {
5e543cab 7302 setLWResult(res, 0, true, false, true);
5374b03b
RG
7303
7304 if (domain == DNSName("com.")) {
7305 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7306 /* no DS */
7307 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
7308 addRRSIG(keys, res->d_records, DNSName("."), 300);
7309 }
7310 else {
5e543cab 7311 setLWResult(res, 0, true, false, true);
5374b03b
RG
7312 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7313 }
88cb0fe0 7314 }
70b3fe7a
RG
7315 return 1;
7316 }
7317 else if (type == QType::DNSKEY) {
7318 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
7319 setLWResult(res, 0, true, false, true);
7320 addDNSKEY(keys, domain, 300, res->d_records);
7321 addRRSIG(keys, res->d_records, domain, 300);
7322 return 1;
7323 }
7324 }
88cb0fe0 7325 else {
70b3fe7a
RG
7326 if (isRootServer(ip)) {
7327 setLWResult(res, 0, false, false, true);
7328 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7329 /* no DS */
7330 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
7331 addRRSIG(keys, res->d_records, DNSName("."), 300);
7332 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7333 return 1;
7334 }
7335 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7336 if (domain == DNSName("com.")) {
7337 setLWResult(res, 0, true, false, true);
7338 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
7339 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7340 }
5374b03b 7341 else if (domain.isPartOf(DNSName("powerdns.com."))) {
88cb0fe0
RG
7342 setLWResult(res, 0, false, false, true);
7343 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7344 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7345 }
70b3fe7a
RG
7346 return 1;
7347 }
7348 else if (ip == ComboAddress("192.0.2.2:53")) {
7349 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7350 if (type == QType::NS) {
7351 if (domain == DNSName("www.sub.powerdns.com.")) {
7352 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);
7353 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7354 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
7355 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7356 }
7357 else if (domain == DNSName("sub.powerdns.com.")) {
7358 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7359 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
7360 }
7361 else if (domain == DNSName("powerdns.com.")) {
7362 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7363 }
7364 }
7365 else if (domain == DNSName("www.sub.powerdns.com.")) {
7366 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7367 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
7368 }
70b3fe7a
RG
7369 return 1;
7370 }
7371 }
7372
7373 return 0;
7374 });
7375
7376 vector<DNSRecord> ret;
7377 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7378 BOOST_CHECK_EQUAL(res, RCode::NoError);
7379 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 7380 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 7381 BOOST_CHECK(ret[0].d_type == QType::A);
5e543cab 7382 BOOST_CHECK_EQUAL(queriesCount, 8);
70b3fe7a
RG
7383
7384 /* again, to test the cache */
7385 ret.clear();
7386 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7387 BOOST_CHECK_EQUAL(res, RCode::NoError);
7388 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 7389 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 7390 BOOST_CHECK(ret[0].d_type == QType::A);
5e543cab 7391 BOOST_CHECK_EQUAL(queriesCount, 8);
70b3fe7a
RG
7392}
7393
b7f378d1
RG
7394BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
7395 std::unique_ptr<SyncRes> sr;
895449a5 7396 initSR(sr, true);
b7f378d1 7397
0c43f455 7398 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
7399
7400 primeHints();
7401 const DNSName target("powerdns.com.");
7402 testkeysset_t keys;
7403
7404 auto luaconfsCopy = g_luaconfs.getCopy();
7405 luaconfsCopy.dsAnchors.clear();
7406 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7407 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7408
7409 g_luaconfs.setState(luaconfsCopy);
7410
7411 size_t queriesCount = 0;
7412
0bd2e252 7413 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, LWResult* res, bool* chained) {
b7f378d1
RG
7414 queriesCount++;
7415
7416 if (type == QType::DS) {
a53e8fe3 7417 if (domain == target) {
5e543cab 7418 setLWResult(res, 0, true, false, true);
895449a5 7419 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5e543cab 7420 addRRSIG(keys, res->d_records, DNSName("com."), 300);
b7f378d1
RG
7421 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7422 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7423 return 1;
7424 }
5374b03b
RG
7425 else {
7426 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7427 }
b7f378d1
RG
7428 }
7429 else if (type == QType::DNSKEY) {
7430 if (domain == g_rootdnsname || domain == DNSName("com.")) {
7431 setLWResult(res, 0, true, false, true);
7432 addDNSKEY(keys, domain, 300, res->d_records);
7433 addRRSIG(keys, res->d_records, domain, 300);
7434 return 1;
7435 }
7436 else {
5e543cab 7437 setLWResult(res, 0, true, false, true);
895449a5 7438 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
7439 return 1;
7440 }
7441 }
a69867f2 7442 else {
b7f378d1
RG
7443 if (isRootServer(ip)) {
7444 setLWResult(res, 0, false, false, true);
7445 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7446 addDS(DNSName("com."), 300, res->d_records, keys);
7447 addRRSIG(keys, res->d_records, DNSName("."), 300);
7448 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7449 return 1;
7450 }
7451 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7452 if (domain == DNSName("com.")) {
7453 setLWResult(res, 0, true, false, true);
7454 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7455 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7456 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7457 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7458 }
7459 else {
7460 setLWResult(res, 0, false, false, true);
7461 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7462 /* no DS */
7463 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7464 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7465 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7466 }
b7f378d1
RG
7467 return 1;
7468 }
7469 else if (ip == ComboAddress("192.0.2.2:53")) {
a69867f2
RG
7470 if (type == QType::NS) {
7471 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7472 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7473 }
7474 else {
7475 setLWResult(res, 0, true, false, true);
7476 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7477 }
b7f378d1
RG
7478 return 1;
7479 }
7480 }
7481
7482 return 0;
7483 });
7484
7485 vector<DNSRecord> ret;
7486 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7487 BOOST_CHECK_EQUAL(res, RCode::NoError);
7488 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7489 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2
RG
7490 /* 4 NS (com from root, com from com, powerdns.com from com,
7491 powerdns.com from powerdns.com)
7492 2 DNSKEY (. and com., none for powerdns.com because no DS)
7493 1 query for A
7494 */
7495 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7496
7497 /* again, to test the cache */
7498 ret.clear();
7499 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7500 BOOST_CHECK_EQUAL(res, RCode::NoError);
7501 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7502 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2 7503 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7504}
7505
895449a5 7506BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
b7f378d1 7507 std::unique_ptr<SyncRes> sr;
860d5e8e 7508 initSR(sr, true);
b7f378d1 7509
0c43f455 7510 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1 7511
895449a5
RG
7512 primeHints();
7513 const DNSName target("powerdns.com.");
7514 const DNSName targetCName("power-dns.com.");
7515 const ComboAddress targetCNameAddr("192.0.2.42");
7516 testkeysset_t keys;
7517
7518 auto luaconfsCopy = g_luaconfs.getCopy();
7519 luaconfsCopy.dsAnchors.clear();
7520 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7521 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7522 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7523 g_luaconfs.setState(luaconfsCopy);
7524
7525 size_t queriesCount = 0;
7526
0bd2e252 7527 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, LWResult* res, bool* chained) {
895449a5
RG
7528 queriesCount++;
7529
7530 if (type == QType::DS) {
5374b03b 7531 if (domain == targetCName) {
5e543cab 7532 setLWResult(res, 0, true, false, true);
895449a5 7533 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5e543cab 7534 addRRSIG(keys, res->d_records, DNSName("com."), 300);
895449a5
RG
7535 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7536 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7537 return 1;
7538 }
5374b03b
RG
7539 else {
7540 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7541 }
895449a5
RG
7542 }
7543 else if (type == QType::DNSKEY) {
7544 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7545 setLWResult(res, 0, true, false, true);
7546 addDNSKEY(keys, domain, 300, res->d_records);
7547 addRRSIG(keys, res->d_records, domain, 300);
7548 return 1;
7549 }
7550 else {
5e543cab 7551 setLWResult(res, 0, true, false, true);
895449a5
RG
7552 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7553 return 1;
7554 }
7555 }
7556 else {
7557 if (isRootServer(ip)) {
7558 setLWResult(res, 0, false, false, true);
7559 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7560 addDS(DNSName("com."), 300, res->d_records, keys);
7561 addRRSIG(keys, res->d_records, DNSName("."), 300);
7562 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7563 return 1;
7564 }
7565 else if (ip == ComboAddress("192.0.2.1:53")) {
7566 setLWResult(res, 0, false, false, true);
a69867f2
RG
7567 if (domain == DNSName("com.")) {
7568 setLWResult(res, 0, true, false, true);
7569 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7570 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7571 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7572 addRRSIG(keys, res->d_records, DNSName("com."), 300);
895449a5 7573 }
a69867f2
RG
7574 else {
7575 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7576 if (domain == DNSName("powerdns.com.")) {
7577 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7578 }
7579 else if (domain == targetCName) {
7580 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7581 }
7582 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7583 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
895449a5 7584 }
a69867f2 7585
895449a5
RG
7586 return 1;
7587 }
7588 else if (ip == ComboAddress("192.0.2.2:53")) {
7589 setLWResult(res, 0, true, false, true);
a69867f2
RG
7590
7591 if (type == QType::NS) {
7592 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7593 if (domain == DNSName("powerdns.com.")) {
7594 addRRSIG(keys, res->d_records, domain, 300);
7595 }
7596 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7597 if (domain == DNSName("powerdns.com.")) {
7598 addRRSIG(keys, res->d_records, domain, 300);
7599 }
895449a5 7600 }
a69867f2
RG
7601 else {
7602 if (domain == DNSName("powerdns.com.")) {
7603 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7604 addRRSIG(keys, res->d_records, domain, 300);
7605 }
7606 else if (domain == targetCName) {
7607 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7608 }
895449a5 7609 }
a69867f2 7610
895449a5
RG
7611 return 1;
7612 }
7613 }
7614
7615 return 0;
7616 });
7617
7618 vector<DNSRecord> ret;
7619 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7620 BOOST_CHECK_EQUAL(res, RCode::NoError);
7621 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7622 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7623 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7624
7625 /* again, to test the cache */
7626 ret.clear();
7627 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7628 BOOST_CHECK_EQUAL(res, RCode::NoError);
7629 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7630 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7631 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7632}
7633
933299e8
RG
7634BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname_glue) {
7635 std::unique_ptr<SyncRes> sr;
f100caac 7636 initSR(sr, true);
933299e8
RG
7637
7638 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7639
7640 primeHints();
7641 const DNSName target("powerdns.com.");
7642 const DNSName targetCName1("cname.sub.powerdns.com.");
7643 const DNSName targetCName2("cname2.sub.powerdns.com.");
7644 const ComboAddress targetCName2Addr("192.0.2.42");
7645 testkeysset_t keys;
7646
7647 auto luaconfsCopy = g_luaconfs.getCopy();
7648 luaconfsCopy.dsAnchors.clear();
7649 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7650 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7651 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7652 g_luaconfs.setState(luaconfsCopy);
7653
7654 size_t queriesCount = 0;
7655
0bd2e252 7656 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, LWResult* res, bool* chained) {
933299e8
RG
7657 queriesCount++;
7658
7659 if (type == QType::DS || type == QType::DNSKEY) {
7660 if (domain == DNSName("sub.powerdns.com")) {
5e543cab 7661 setLWResult(res, 0, true, false, true);
933299e8 7662 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5e543cab 7663 addRRSIG(keys, res->d_records, DNSName("com."), 300);
933299e8
RG
7664 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7665 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7666 return 1;
7667 }
7668 else {
7669 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7670 }
7671 }
7672 else {
7673 if (isRootServer(ip)) {
7674 setLWResult(res, 0, false, false, true);
7675 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7676 addDS(DNSName("com."), 300, res->d_records, keys);
7677 addRRSIG(keys, res->d_records, DNSName("."), 300);
7678 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7679 return 1;
7680 }
7681 else if (ip == ComboAddress("192.0.2.1:53")) {
7682 setLWResult(res, 0, false, false, true);
7683 if (domain == DNSName("com.")) {
7684 setLWResult(res, 0, true, false, true);
7685 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7686 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7687 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7688 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7689 }
7690 else {
7691 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7692 if (domain == DNSName("powerdns.com.")) {
7693 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7694 }
7695 else if (domain == DNSName("sub.powerdns.com")) {
7696 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7697 }
7698 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7699 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7700 }
7701
7702 return 1;
7703 }
7704 else if (ip == ComboAddress("192.0.2.2:53")) {
7705 setLWResult(res, 0, true, false, true);
7706
7707 if (type == QType::NS) {
7708 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7709 if (domain == DNSName("powerdns.com.")) {
7710 addRRSIG(keys, res->d_records, domain, 300);
7711 }
7712 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7713 if (domain == DNSName("powerdns.com.")) {
7714 addRRSIG(keys, res->d_records, domain, 300);
7715 }
7716 }
7717 else {
7718 if (domain == DNSName("powerdns.com.")) {
7719 addRecordToLW(res, domain, QType::CNAME, targetCName1.toString());
7720 addRRSIG(keys, res->d_records, domain, 300);
7721 /* add the CNAME target as a glue, with no RRSIG since the sub zone is insecure */
7722 addRecordToLW(res, targetCName1, QType::CNAME, targetCName2.toString());
7723 addRecordToLW(res, targetCName2, QType::A, targetCName2Addr.toString());
7724 }
7725 else if (domain == targetCName1) {
7726 addRecordToLW(res, domain, QType::CNAME, targetCName2.toString());
7727 }
7728 else if (domain == targetCName2) {
7729 addRecordToLW(res, domain, QType::A, targetCName2Addr.toString());
7730 }
7731 }
7732
7733 return 1;
7734 }
7735 }
7736
7737 return 0;
7738 });
7739
7740 vector<DNSRecord> ret;
7741 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7742 BOOST_CHECK_EQUAL(res, RCode::NoError);
7743 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7744 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7745 BOOST_CHECK_EQUAL(queriesCount, 11);
7746
7747 /* again, to test the cache */
7748 ret.clear();
7749 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7750 BOOST_CHECK_EQUAL(res, RCode::NoError);
7751 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7752 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7753 BOOST_CHECK_EQUAL(queriesCount, 11);
7754}
7755
3d5ebf10
RG
7756BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
7757 std::unique_ptr<SyncRes> sr;
7758 initSR(sr, true);
7759
0c43f455 7760 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7761
7762 primeHints();
7763 const DNSName target("power-dns.com.");
7764 const DNSName targetCName("powerdns.com.");
7765 const ComboAddress targetCNameAddr("192.0.2.42");
7766 testkeysset_t keys;
7767
7768 auto luaconfsCopy = g_luaconfs.getCopy();
7769 luaconfsCopy.dsAnchors.clear();
7770 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7771 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7772 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7773 g_luaconfs.setState(luaconfsCopy);
7774
7775 size_t queriesCount = 0;
7776
0bd2e252 7777 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, LWResult* res, bool* chained) {
3d5ebf10
RG
7778 queriesCount++;
7779
7780 if (type == QType::DS) {
a53e8fe3 7781 if (domain == DNSName("power-dns.com.")) {
5e543cab 7782 setLWResult(res, 0, true, false, true);
3d5ebf10 7783 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5e543cab 7784 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10
RG
7785 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7786 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7787 return 1;
7788 }
5374b03b
RG
7789 else {
7790 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7791 }
3d5ebf10
RG
7792 }
7793 else if (type == QType::DNSKEY) {
7794 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7795 setLWResult(res, 0, true, false, true);
7796 addDNSKEY(keys, domain, 300, res->d_records);
7797 addRRSIG(keys, res->d_records, domain, 300);
7798 return 1;
7799 }
7800 else {
5e543cab 7801 setLWResult(res, 0, true, false, true);
3d5ebf10
RG
7802 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7803 return 1;
7804 }
7805 }
7806 else {
7807 if (isRootServer(ip)) {
7808 setLWResult(res, 0, false, false, true);
7809 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7810 addDS(DNSName("com."), 300, res->d_records, keys);
7811 addRRSIG(keys, res->d_records, DNSName("."), 300);
7812 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7813 return 1;
7814 }
7815 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7816 if (domain == DNSName("com.")) {
7817 setLWResult(res, 0, true, false, true);
7818 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7819 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7820 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7821 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7822 }
a69867f2
RG
7823 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7824 setLWResult(res, 0, false, false, true);
7825 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7826 if (domain == targetCName) {
7827 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7828 }
7829 else if (domain == target) {
7830 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7831 }
7832 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7833 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7834 }
3d5ebf10
RG
7835 return 1;
7836 }
7837 else if (ip == ComboAddress("192.0.2.2:53")) {
7838 setLWResult(res, 0, true, false, true);
a69867f2
RG
7839 if (type == QType::NS) {
7840 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7841 if (domain == DNSName("powerdns.com.")) {
7842 addRRSIG(keys, res->d_records, domain, 300);
7843 }
7844 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7845 if (domain == DNSName("powerdns.com.")) {
7846 addRRSIG(keys, res->d_records, domain, 300);
7847 }
3d5ebf10 7848 }
a69867f2
RG
7849 else {
7850 if (domain == target) {
7851 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7852 }
7853 else if (domain == targetCName) {
7854 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7855 addRRSIG(keys, res->d_records, domain, 300);
7856 }
3d5ebf10
RG
7857 }
7858 return 1;
7859 }
7860 }
7861
7862 return 0;
7863 });
7864
7865 vector<DNSRecord> ret;
7866 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7867 BOOST_CHECK_EQUAL(res, RCode::NoError);
7868 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7869 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7870 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7871
7872 /* again, to test the cache */
7873 ret.clear();
7874 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7875 BOOST_CHECK_EQUAL(res, RCode::NoError);
7876 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7877 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7878 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7879}
7880
7881BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
7882 std::unique_ptr<SyncRes> sr;
7883 initSR(sr, true);
7884
0c43f455 7885 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7886
7887 primeHints();
7888 const DNSName target("power-dns.com.");
7889 const DNSName targetCName("powerdns.com.");
7890 const ComboAddress targetCNameAddr("192.0.2.42");
7891 testkeysset_t keys;
7892
7893 auto luaconfsCopy = g_luaconfs.getCopy();
7894 luaconfsCopy.dsAnchors.clear();
7895 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7896 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7897 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7898 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7899 g_luaconfs.setState(luaconfsCopy);
7900
7901 size_t queriesCount = 0;
7902
0bd2e252 7903 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, LWResult* res, bool* chained) {
3d5ebf10
RG
7904 queriesCount++;
7905
5374b03b
RG
7906 if (type == QType::DS || type == QType::DNSKEY) {
7907 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7908 }
7909 else {
7910 if (isRootServer(ip)) {
7911 setLWResult(res, 0, false, false, true);
7912 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7913 addDS(DNSName("com."), 300, res->d_records, keys);
7914 addRRSIG(keys, res->d_records, DNSName("."), 300);
7915 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7916 return 1;
7917 }
7918 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7919 if (domain == DNSName("com.")) {
7920 setLWResult(res, 0, true, false, true);
7921 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7922 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7923 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7924 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7925 }
7926 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7927 setLWResult(res, 0, false, false, true);
7928 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7929 addDS(DNSName(domain), 300, res->d_records, keys);
7930 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7931 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7932 }
3d5ebf10
RG
7933 return 1;
7934 }
7935 else if (ip == ComboAddress("192.0.2.2:53")) {
7936 setLWResult(res, 0, true, false, true);
a69867f2
RG
7937 if (type == QType::NS) {
7938 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7939 addRRSIG(keys, res->d_records, domain, 300);
7940 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7941 addRRSIG(keys, res->d_records, domain, 300);
7942 }
a69867f2
RG
7943 else {
7944 if (domain == target) {
7945 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7946 /* No RRSIG, leading to bogus */
7947 }
7948 else if (domain == targetCName) {
7949 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7950 addRRSIG(keys, res->d_records, domain, 300);
7951 }
7952 }
3d5ebf10
RG
7953 return 1;
7954 }
7955 }
7956
7957 return 0;
7958 });
7959
7960 vector<DNSRecord> ret;
7961 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7962 BOOST_CHECK_EQUAL(res, RCode::NoError);
7963 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7964 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7965 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7966
7967 /* again, to test the cache */
7968 ret.clear();
7969 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7970 BOOST_CHECK_EQUAL(res, RCode::NoError);
7971 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7972 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7973 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7974}
7975
7976BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7977 std::unique_ptr<SyncRes> sr;
7978 initSR(sr, true);
7979
0c43f455 7980 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7981
7982 primeHints();
7983 const DNSName target("power-dns.com.");
7984 const DNSName targetCName("powerdns.com.");
7985 const ComboAddress targetCNameAddr("192.0.2.42");
7986 testkeysset_t keys;
7987
7988 auto luaconfsCopy = g_luaconfs.getCopy();
7989 luaconfsCopy.dsAnchors.clear();
7990 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7991 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7992 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7993 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7994 g_luaconfs.setState(luaconfsCopy);
7995
7996 size_t queriesCount = 0;
7997
0bd2e252 7998 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, LWResult* res, bool* chained) {
3d5ebf10
RG
7999 queriesCount++;
8000
5374b03b
RG
8001 if (type == QType::DS || type == QType::DNSKEY) {
8002 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
8003 }
8004 else {
8005 if (isRootServer(ip)) {
8006 setLWResult(res, 0, false, false, true);
8007 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8008 addDS(DNSName("com."), 300, res->d_records, keys);
8009 addRRSIG(keys, res->d_records, DNSName("."), 300);
8010 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8011 return 1;
8012 }
8013 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
8014 if (domain == DNSName("com.")) {
8015 setLWResult(res, 0, true, false, true);
8016 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
8017 addRRSIG(keys, res->d_records, DNSName("com."), 300);
8018 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8019 addRRSIG(keys, res->d_records, DNSName("com."), 300);
8020 }
8021 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
8022 setLWResult(res, 0, false, false, true);
8023 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8024 addDS(DNSName(domain), 300, res->d_records, keys);
8025 addRRSIG(keys, res->d_records, DNSName("com."), 300);
8026 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8027 }
3d5ebf10
RG
8028 return 1;
8029 }
8030 else if (ip == ComboAddress("192.0.2.2:53")) {
8031 setLWResult(res, 0, true, false, true);
a69867f2
RG
8032 if (type == QType::NS) {
8033 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8034 addRRSIG(keys, res->d_records, domain, 300);
8035 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
8036 addRRSIG(keys, res->d_records, domain, 300);
8037 }
a69867f2
RG
8038 else {
8039 if (domain == target) {
8040 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
8041 addRRSIG(keys, res->d_records, domain, 300);
8042 }
8043 else if (domain == targetCName) {
8044 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
8045 /* No RRSIG, leading to bogus */
8046 }
3d5ebf10
RG
8047 }
8048 return 1;
8049 }
8050 }
8051
8052 return 0;
8053 });
8054
8055 vector<DNSRecord> ret;
8056 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8057 BOOST_CHECK_EQUAL(res, RCode::NoError);
8058 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8059 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 8060 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
8061
8062 /* again, to test the cache */
8063 ret.clear();
8064 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8065 BOOST_CHECK_EQUAL(res, RCode::NoError);
8066 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8067 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 8068 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
8069}
8070
8071BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
8072 std::unique_ptr<SyncRes> sr;
8073 initSR(sr, true);
8074
0c43f455 8075 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
8076
8077 primeHints();
8078 const DNSName target("power-dns.com.");
8079 const DNSName targetCName("powerdns.com.");
8080 const ComboAddress targetCNameAddr("192.0.2.42");
8081 testkeysset_t keys;
8082
8083 auto luaconfsCopy = g_luaconfs.getCopy();
8084 luaconfsCopy.dsAnchors.clear();
8085 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8086 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8087 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8088 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8089 g_luaconfs.setState(luaconfsCopy);
8090
8091 size_t queriesCount = 0;
8092
0bd2e252 8093 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, LWResult* res, bool* chained) {
3d5ebf10
RG
8094 queriesCount++;
8095
5374b03b
RG
8096 if (type == QType::DS || type == QType::DNSKEY) {
8097 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
8098 }
8099 else {
8100 if (isRootServer(ip)) {
8101 setLWResult(res, 0, false, false, true);
8102 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8103 addDS(DNSName("com."), 300, res->d_records, keys);
8104 addRRSIG(keys, res->d_records, DNSName("."), 300);
8105 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8106 return 1;
8107 }
8108 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
8109 if (domain == DNSName("com.")) {
8110 setLWResult(res, 0, true, false, true);
8111 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
8112 addRRSIG(keys, res->d_records, DNSName("com."), 300);
8113 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8114 addRRSIG(keys, res->d_records, DNSName("com."), 300);
8115 }
8116 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
8117 setLWResult(res, 0, false, false, true);
8118 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8119 addDS(DNSName(domain), 300, res->d_records, keys);
8120 addRRSIG(keys, res->d_records, DNSName("com."), 300);
8121 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8122 }
3d5ebf10
RG
8123 return 1;
8124 }
8125 else if (ip == ComboAddress("192.0.2.2:53")) {
8126 setLWResult(res, 0, true, false, true);
a69867f2
RG
8127 if (type == QType::NS) {
8128 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
3d5ebf10 8129 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 8130 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
8131 addRRSIG(keys, res->d_records, domain, 300);
8132 }
a69867f2
RG
8133 else {
8134 if (domain == target) {
8135 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
8136 addRRSIG(keys, res->d_records, domain, 300);
8137 }
8138 else if (domain == targetCName) {
8139 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
8140 addRRSIG(keys, res->d_records, domain, 300);
8141 }
8142 }
3d5ebf10
RG
8143 return 1;
8144 }
8145 }
8146
8147 return 0;
8148 });
8149
8150 vector<DNSRecord> ret;
8151 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8152 BOOST_CHECK_EQUAL(res, RCode::NoError);
8153 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8154 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 8155 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
8156
8157 /* again, to test the cache */
8158 ret.clear();
8159 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8160 BOOST_CHECK_EQUAL(res, RCode::NoError);
8161 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8162 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 8163 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
8164}
8165
8166BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
8167 std::unique_ptr<SyncRes> sr;
a69867f2 8168 initSR(sr, true);
3d5ebf10 8169
0c43f455 8170 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
8171
8172 primeHints();
8173 const DNSName target("powerdns.com.");
8174 const DNSName targetCName("power-dns.com.");
8175 const ComboAddress targetCNameAddr("192.0.2.42");
8176 testkeysset_t keys;
8177
8178 auto luaconfsCopy = g_luaconfs.getCopy();
8179 luaconfsCopy.dsAnchors.clear();
8180 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8181 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8182 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8183 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8184 g_luaconfs.setState(luaconfsCopy);
8185
8186 size_t queriesCount = 0;
8187
0bd2e252 8188 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, LWResult* res, bool* chained) {
3d5ebf10
RG
8189 queriesCount++;
8190
8191 if (type == QType::DS) {
a53e8fe3 8192 if (domain == DNSName("power-dns.com.")) {
5e543cab 8193 setLWResult(res, 0, true, false, true);
3d5ebf10 8194 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5e543cab 8195 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10
RG
8196 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
8197 addRRSIG(keys, res->d_records, DNSName("com."), 300);
8198 return 1;
8199 }
5374b03b
RG
8200 else {
8201 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
8202 }
3d5ebf10
RG
8203 }
8204 else if (type == QType::DNSKEY) {
8205 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
8206 setLWResult(res, 0, true, false, true);
8207 addDNSKEY(keys, domain, 300, res->d_records);
8208 addRRSIG(keys, res->d_records, domain, 300);
8209 return 1;
8210 }
8211 else {
5e543cab 8212 setLWResult(res, 0, true, false, true);
3d5ebf10
RG
8213 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8214 return 1;
8215 }
8216 }
8217 else {
8218 if (isRootServer(ip)) {
8219 setLWResult(res, 0, false, false, true);
8220 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8221 addDS(DNSName("com."), 300, res->d_records, keys);
8222 addRRSIG(keys, res->d_records, DNSName("."), 300);
8223 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8224 return 1;
8225 }
8226 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
8227 if (domain == DNSName("com.")) {
8228 setLWResult(res, 0, true, false, true);
a69867f2 8229 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0
RG
8230 addRRSIG(keys, res->d_records, DNSName("com."), 300);
8231 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8232 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 8233 }
88cb0fe0
RG
8234 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
8235 setLWResult(res, 0, false, false, true);
8236 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8237 if (domain == DNSName("powerdns.com.")) {
8238 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
8239 }
8240 else if (domain == targetCName) {
8241 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
8242 }
8243 addRRSIG(keys, res->d_records, DNSName("com."), 300);
8244 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 8245 }
3d5ebf10
RG
8246 return 1;
8247 }
8248 else if (ip == ComboAddress("192.0.2.2:53")) {
8249 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
8250 if (type == QType::NS) {
8251 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8252 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 8253 }
88cb0fe0
RG
8254 else {
8255 if (domain == DNSName("powerdns.com.")) {
8256 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
8257 /* No RRSIG -> Bogus */
8258 }
8259 else if (domain == targetCName) {
8260 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
8261 }
3d5ebf10
RG
8262 }
8263 return 1;
8264 }
8265 }
8266
8267 return 0;
8268 });
8269
8270 vector<DNSRecord> ret;
8271 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8272 BOOST_CHECK_EQUAL(res, RCode::NoError);
8273 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8274 /* no RRSIG to show */
8275 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 8276 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
8277
8278 /* again, to test the cache */
8279 ret.clear();
8280 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8281 BOOST_CHECK_EQUAL(res, RCode::NoError);
8282 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8283 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 8284 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
8285}
8286
895449a5
RG
8287BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
8288 std::unique_ptr<SyncRes> sr;
8289 initSR(sr, true);
8290
0c43f455 8291 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
8292
8293 primeHints();
8294 const DNSName target("powerdns.com.");
8295 const ComboAddress targetAddr("192.0.2.42");
8296 testkeysset_t keys;
8297
8298 auto luaconfsCopy = g_luaconfs.getCopy();
8299 luaconfsCopy.dsAnchors.clear();
8300 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8301 /* No key material for .com */
8302 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8303 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
8304 g_luaconfs.setState(luaconfsCopy);
8305
8306 size_t queriesCount = 0;
8307
0bd2e252 8308 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, LWResult* res, bool* chained) {
895449a5
RG
8309 queriesCount++;
8310
a53e8fe3 8311 if (type == QType::DNSKEY) {
895449a5
RG
8312 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
8313 setLWResult(res, 0, true, false, true);
8314 addDNSKEY(keys, domain, 300, res->d_records);
8315 addRRSIG(keys, res->d_records, domain, 300);
8316 return 1;
8317 }
8318 else if (domain == DNSName("com.")) {
5e543cab 8319 setLWResult(res, 0, true, false, true);
895449a5
RG
8320 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8321 return 1;
8322 }
8323 }
88cb0fe0 8324 else {
895449a5
RG
8325 if (isRootServer(ip)) {
8326 setLWResult(res, 0, false, false, true);
8327 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8328 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
8329 addRRSIG(keys, res->d_records, DNSName("."), 300);
8330 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8331 return 1;
8332 }
8333 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
8334 if (target == domain) {
8335 setLWResult(res, 0, false, false, true);
8336 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8337 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8338 }
8339 else if (domain == DNSName("com.")) {
8340 setLWResult(res, 0, true, false, true);
8341 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
8342 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8343 }
895449a5
RG
8344 return 1;
8345 }
8346 else if (ip == ComboAddress("192.0.2.2:53")) {
8347 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
8348 if (type == QType::NS) {
8349 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8350 }
8351 else {
8352 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8353 }
895449a5
RG
8354 addRRSIG(keys, res->d_records, domain, 300);
8355 return 1;
8356 }
8357 }
8358
8359 return 0;
8360 });
8361
8362 vector<DNSRecord> ret;
8363 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8364 BOOST_CHECK_EQUAL(res, RCode::NoError);
8365 /* should be insecure but we have a TA for powerdns.com. */
8366 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8367 /* We got a RRSIG */
8368 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8369 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8370 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
8371
8372 /* again, to test the cache */
8373 ret.clear();
8374 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8375 BOOST_CHECK_EQUAL(res, RCode::NoError);
8376 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8377 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8378 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8379 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
8380}
8381
8382BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
8383 std::unique_ptr<SyncRes> sr;
8384 initSR(sr, true);
8385
0c43f455 8386 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
8387
8388 primeHints();
8389 const DNSName target("powerdns.com.");
8390 const ComboAddress targetAddr("192.0.2.42");
8391 testkeysset_t keys;
8392
8393 auto luaconfsCopy = g_luaconfs.getCopy();
8394 luaconfsCopy.dsAnchors.clear();
8395 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8396 /* No key material for .com */
8397 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8398 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
8399 g_luaconfs.setState(luaconfsCopy);
8400
8401 size_t queriesCount = 0;
8402
0bd2e252 8403 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, LWResult* res, bool* chained) {
895449a5
RG
8404 queriesCount++;
8405
a53e8fe3 8406 if (type == QType::DNSKEY) {
895449a5
RG
8407 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
8408 setLWResult(res, 0, true, false, true);
8409 addDNSKEY(keys, domain, 300, res->d_records);
8410 addRRSIG(keys, res->d_records, domain, 300);
8411 return 1;
8412 }
8413 else if (domain == DNSName("com.")) {
5e543cab 8414 setLWResult(res, 0, true, false, true);
895449a5
RG
8415 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8416 return 1;
8417 }
8418 }
70b3fe7a
RG
8419 else {
8420 if (target.isPartOf(domain) && isRootServer(ip)) {
895449a5
RG
8421 setLWResult(res, 0, false, false, true);
8422 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8423 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
8424 addRRSIG(keys, res->d_records, DNSName("."), 300);
8425 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8426 return 1;
8427 }
8428 else if (ip == ComboAddress("192.0.2.1:53")) {
70b3fe7a
RG
8429 if (target == domain) {
8430 setLWResult(res, 0, false, false, true);
8431 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8432 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8433 }
8434 else if (domain == DNSName("com.")) {
8435 setLWResult(res, 0, true, false, true);
8436 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0 8437 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
70b3fe7a 8438 }
895449a5
RG
8439 return 1;
8440 }
70b3fe7a 8441 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
895449a5 8442 setLWResult(res, 0, true, false, true);
70b3fe7a
RG
8443 if (type == QType::NS) {
8444 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8445 }
8446 else {
8447 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8448 }
895449a5
RG
8449 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
8450 return 1;
8451 }
8452 }
8453
8454 return 0;
8455 });
8456
8457 vector<DNSRecord> ret;
8458 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8459 BOOST_CHECK_EQUAL(res, RCode::NoError);
8460 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
8461 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8462 /* No RRSIG */
8463 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8464 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8465 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
8466
8467 /* again, to test the cache */
8468 ret.clear();
8469 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8470 BOOST_CHECK_EQUAL(res, RCode::NoError);
8471 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8472 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8473 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8474 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
8475}
8476
895449a5
RG
8477BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
8478 std::unique_ptr<SyncRes> sr;
8479 initSR(sr, true);
8480
0c43f455 8481 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5 8482
b7f378d1
RG
8483 primeHints();
8484 const DNSName target(".");
8485 testkeysset_t keys;
8486
8487 auto luaconfsCopy = g_luaconfs.getCopy();
8488 luaconfsCopy.dsAnchors.clear();
8489 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8490 /* Add a NTA for "." */
8491 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
8492 g_luaconfs.setState(luaconfsCopy);
8493
8494 size_t queriesCount = 0;
8495
0bd2e252 8496 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, LWResult* res, bool* chained) {
b7f378d1
RG
8497 queriesCount++;
8498
8499 if (domain == target && type == QType::NS) {
8500
8501 setLWResult(res, 0, true, false, true);
8502 char addr[] = "a.root-servers.net.";
8503 for (char idx = 'a'; idx <= 'm'; idx++) {
8504 addr[0] = idx;
8455425c
RG
8505 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8506 }
8507
8508 addRRSIG(keys, res->d_records, domain, 300);
8509
8510 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8511 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8512
8513 return 1;
8514 } else if (domain == target && type == QType::DNSKEY) {
8515
8516 setLWResult(res, 0, true, false, true);
8517
8518 /* No DNSKEY */
8519
8520 return 1;
8521 }
8522
8523 return 0;
8524 });
8525
8526 vector<DNSRecord> ret;
8527 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8528 BOOST_CHECK_EQUAL(res, RCode::NoError);
8529 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8530 /* 13 NS + 1 RRSIG */
8531 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8532 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8533
8534 /* again, to test the cache */
8535 ret.clear();
8536 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8537 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8538 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8539 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8540 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8541}
8542
8543BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
8544 std::unique_ptr<SyncRes> sr;
895449a5 8545 initSR(sr, true);
8455425c 8546
0c43f455 8547 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
8548
8549 primeHints();
8550 const DNSName target(".");
b7f378d1 8551 testkeysset_t keys;
8455425c
RG
8552
8553 /* Remove the root DS */
8554 auto luaconfsCopy = g_luaconfs.getCopy();
8555 luaconfsCopy.dsAnchors.clear();
8556 g_luaconfs.setState(luaconfsCopy);
8557
8558 size_t queriesCount = 0;
8559
0bd2e252 8560 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, LWResult* res, bool* chained) {
8455425c
RG
8561 queriesCount++;
8562
8563 if (domain == target && type == QType::NS) {
8564
8565 setLWResult(res, 0, true, false, true);
8566 char addr[] = "a.root-servers.net.";
8567 for (char idx = 'a'; idx <= 'm'; idx++) {
8568 addr[0] = idx;
8569 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8570 }
8571
8572 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8573 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8574
8575 return 1;
8576 }
8577
8578 return 0;
8579 });
8580
8581 vector<DNSRecord> ret;
8582 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8583 BOOST_CHECK_EQUAL(res, RCode::NoError);
8584 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8585 /* 13 NS + 0 RRSIG */
8586 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8587 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8588
8589 /* again, to test the cache */
8590 ret.clear();
8591 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8592 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8593 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8594 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8595 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8596}
8597
114829cc
RG
8598BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
8599 std::unique_ptr<SyncRes> sr;
8600 initSR(sr, true);
8601
5d7b19c5 8602 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
114829cc
RG
8603
8604 primeHints();
8605 const DNSName target("powerdns.com.");
8606 testkeysset_t keys;
8607
8608 auto luaconfsCopy = g_luaconfs.getCopy();
8609 luaconfsCopy.dsAnchors.clear();
8610 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5374b03b 8611 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
114829cc
RG
8612 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8613 g_luaconfs.setState(luaconfsCopy);
8614
8615 size_t queriesCount = 0;
8616
0bd2e252 8617 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, LWResult* res, bool* chained) {
114829cc
RG
8618 queriesCount++;
8619
5374b03b
RG
8620 if (type == QType::DS || type == QType::DNSKEY) {
8621 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
114829cc
RG
8622 }
8623 else {
8624
8625 setLWResult(res, 0, true, false, true);
8626 return 1;
8627 }
8628
8629 return 0;
8630 });
8631
8632 vector<DNSRecord> ret;
8633 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8634 BOOST_CHECK_EQUAL(res, RCode::NoError);
8635 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8636 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8637 /* com|NS, powerdns.com|NS, powerdns.com|A */
8638 BOOST_CHECK_EQUAL(queriesCount, 3);
8639
8640 /* again, to test the cache */
8641 ret.clear();
8642 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8643 BOOST_CHECK_EQUAL(res, RCode::NoError);
8644 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8645 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8646 /* we don't store empty results */
5374b03b 8647 BOOST_CHECK_EQUAL(queriesCount, 4);
114829cc
RG
8648}
8649
db04449e
RG
8650BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
8651 init();
8652
8653 testkeysset_t keys;
8654 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8655
8656 vector<DNSRecord> records;
8657
8658 vector<shared_ptr<DNSRecordContent>> recordContents;
8659 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8660
8661 /*
8662 No wrap test case:
8663 a.example.org. -> d.example.org. denies the existence of b.example.org.
8664 */
8665 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8666 recordContents.push_back(records.at(0).d_content);
8667 addRRSIG(keys, records, DNSName("example.org."), 300);
8668 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8669 records.clear();
8670
8671 ContentSigPair pair;
8672 pair.records = recordContents;
8673 pair.signatures = signatureContents;
8674 cspmap_t denialMap;
8675 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8676
9b061cf5
RG
8677 /* add wildcard denial */
8678 recordContents.clear();
8679 signatureContents.clear();
8680 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8681 recordContents.push_back(records.at(0).d_content);
8682 addRRSIG(keys, records, DNSName("example.org."), 300);
8683 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8684 records.clear();
8685
8686 pair.records = recordContents;
8687 pair.signatures = signatureContents;
8688 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
8689
00e3fef4 8690 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8691 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8692
00e3fef4 8693 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8694 /* let's check that d.example.org. is not denied by this proof */
8695 BOOST_CHECK_EQUAL(denialState, NODATA);
8696}
8697
8698BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
8699 init();
8700
8701 testkeysset_t keys;
8702 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8703
8704 vector<DNSRecord> records;
8705
8706 vector<shared_ptr<DNSRecordContent>> recordContents;
8707 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8708
8709 /*
8710 Wrap case 1 test case:
8711 z.example.org. -> b.example.org. denies the existence of a.example.org.
8712 */
8713 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8714 recordContents.push_back(records.at(0).d_content);
8715 addRRSIG(keys, records, DNSName("example.org."), 300);
8716 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8717 records.clear();
8718
8719 ContentSigPair pair;
8720 pair.records = recordContents;
8721 pair.signatures = signatureContents;
8722 cspmap_t denialMap;
8723 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
8724
00e3fef4 8725 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8726 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8727
00e3fef4 8728 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8729 /* let's check that d.example.org. is not denied by this proof */
8730 BOOST_CHECK_EQUAL(denialState, NODATA);
8731}
8732
8733BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
8734 init();
8735
8736 testkeysset_t keys;
8737 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8738
8739 vector<DNSRecord> records;
8740
8741 vector<shared_ptr<DNSRecordContent>> recordContents;
8742 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8743
8744 /*
8745 Wrap case 2 test case:
8746 y.example.org. -> a.example.org. denies the existence of z.example.org.
8747 */
8748 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8749 recordContents.push_back(records.at(0).d_content);
8750 addRRSIG(keys, records, DNSName("example.org."), 300);
8751 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8752 records.clear();
8753
8754 ContentSigPair pair;
8755 pair.records = recordContents;
8756 pair.signatures = signatureContents;
8757 cspmap_t denialMap;
8758 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
8759
00e3fef4 8760 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
db04449e
RG
8761 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8762
00e3fef4 8763 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8764 /* let's check that d.example.org. is not denied by this proof */
8765 BOOST_CHECK_EQUAL(denialState, NODATA);
8766}
8767
8768BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
8769 init();
8770
8771 testkeysset_t keys;
8772 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8773
8774 vector<DNSRecord> records;
8775
8776 vector<shared_ptr<DNSRecordContent>> recordContents;
8777 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8778
8779 /*
8780 Only one NSEC in the whole zone test case:
8781 a.example.org. -> a.example.org. denies the existence of b.example.org.
8782 */
8783 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8784 recordContents.push_back(records.at(0).d_content);
8785 addRRSIG(keys, records, DNSName("example.org."), 300);
8786 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8787 records.clear();
8788
8789 ContentSigPair pair;
8790 pair.records = recordContents;
8791 pair.signatures = signatureContents;
8792 cspmap_t denialMap;
8793 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8794
00e3fef4 8795 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8796 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8797
00e3fef4 8798 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8799 /* let's check that d.example.org. is not denied by this proof */
8800 BOOST_CHECK_EQUAL(denialState, NODATA);
8801}
8802
1efd998a
RG
8803BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
8804 init();
8805
8806 testkeysset_t keys;
8807 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8808
8809 vector<DNSRecord> records;
8810
8811 vector<shared_ptr<DNSRecordContent>> recordContents;
8812 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8813
8814 /*
8815 The RRSIG from "." denies the existence of anything between a. and c.,
8816 including b.
8817 */
8818 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
8819 recordContents.push_back(records.at(0).d_content);
8820 addRRSIG(keys, records, DNSName("."), 300);
8821 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8822 records.clear();
8823
8824 ContentSigPair pair;
8825 pair.records = recordContents;
8826 pair.signatures = signatureContents;
8827 cspmap_t denialMap;
8828 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8829
9b061cf5
RG
8830 /* add wildcard denial */
8831 recordContents.clear();
8832 signatureContents.clear();
8833 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8834 recordContents.push_back(records.at(0).d_content);
8835 addRRSIG(keys, records, DNSName("."), 300);
8836 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8837 records.clear();
8838
8839 pair.records = recordContents;
8840 pair.signatures = signatureContents;
8841 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
8842
00e3fef4 8843 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
1efd998a
RG
8844 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8845}
8846
8847BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
8848 init();
8849
8850 testkeysset_t keys;
8851 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8852
8853 vector<DNSRecord> records;
8854
8855 vector<shared_ptr<DNSRecordContent>> recordContents;
8856 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8857
8858 /*
8859 The RRSIG from "." denies the existence of any type except NS at a.
8860 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8861 signer field that is shorter than the owner name of the NSEC RR) it can't
8862 be used to deny anything except the whole name or a DS.
8863 */
8864 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 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 records.clear();
8869
8870 ContentSigPair pair;
8871 pair.records = recordContents;
8872 pair.signatures = signatureContents;
8873 cspmap_t denialMap;
8874 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8875
8876 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8877 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8878 nonexistence of any RRs below that zone cut, which include all RRs at
8879 that (original) owner name other than DS RRs, and all RRs below that
8880 owner name regardless of type.
8881 */
8882
00e3fef4 8883 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
1efd998a
RG
8884 /* no data means the qname/qtype is not denied, because an ancestor
8885 delegation NSEC can only deny the DS */
8886 BOOST_CHECK_EQUAL(denialState, NODATA);
8887
5b522864
RG
8888 /* it can not be used to deny any RRs below that owner name either */
8889 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false);
8890 BOOST_CHECK_EQUAL(denialState, NODATA);
8891
00e3fef4 8892 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
1efd998a
RG
8893 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8894}
8895
95823c07
RG
8896BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
8897 init();
8898
8899 testkeysset_t keys;
8900 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8901
8902 vector<DNSRecord> records;
8903
8904 vector<shared_ptr<DNSRecordContent>> recordContents;
8905 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8906
8907 /*
8908 * RFC 5155 section 8.9:
8909 * If there is an NSEC3 RR present in the response that matches the
8910 * delegation name, then the validator MUST ensure that the NS bit is
8911 * set and that the DS bit is not set in the Type Bit Maps field of the
8912 * NSEC3 RR.
8913 */
8914 /*
8915 The RRSIG from "." denies the existence of any type at a.
8916 NS should be set if it was proving an insecure delegation, let's check that
8917 we correctly detect that it's not.
8918 */
8919 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
8920 recordContents.push_back(records.at(0).d_content);
8921 addRRSIG(keys, records, DNSName("."), 300);
8922 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8923 records.clear();
8924
8925 ContentSigPair pair;
8926 pair.records = recordContents;
8927 pair.signatures = signatureContents;
8928 cspmap_t denialMap;
8929 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8930
8931 /* Insecure because the NS is not set, so while it does
8932 denies the DS, it can't prove an insecure delegation */
00e3fef4 8933 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8934 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8935}
8936
9b061cf5
RG
8937BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
8938 init();
8939
8940 testkeysset_t keys;
8941 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8942
8943 vector<DNSRecord> records;
8944
8945 vector<shared_ptr<DNSRecordContent>> recordContents;
8946 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8947
8948 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
8949 recordContents.push_back(records.at(0).d_content);
8950 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8951 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8952 records.clear();
8953
8954 ContentSigPair pair;
8955 pair.records = recordContents;
8956 pair.signatures = signatureContents;
8957 cspmap_t denialMap;
8958 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8959
8960 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8961 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
8962 BOOST_CHECK_EQUAL(denialState, NODATA);
8963}
8964
8965BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
8966 init();
8967
8968 testkeysset_t keys;
8969 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8970
8971 vector<DNSRecord> records;
8972
8973 vector<shared_ptr<DNSRecordContent>> recordContents;
8974 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8975
8976 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
8977 recordContents.push_back(records.at(0).d_content);
8978 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8979 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8980
8981 ContentSigPair pair;
8982 pair.records = recordContents;
8983 pair.signatures = signatureContents;
8984 cspmap_t denialMap;
8985 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8986 records.clear();
8987
8988 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8989 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8990 BOOST_CHECK_EQUAL(denialState, NODATA);
8991}
8992
8993BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8994 init();
8995
8996 testkeysset_t keys;
8997 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8998
8999 vector<DNSRecord> records;
9000
9001 vector<shared_ptr<DNSRecordContent>> recordContents;
9002 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
9003
9004 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
9005 recordContents.push_back(records.at(0).d_content);
9006 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
9007 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9008 records.clear();
9009
9010 ContentSigPair pair;
9011 pair.records = recordContents;
9012 pair.signatures = signatureContents;
9013 cspmap_t denialMap;
9014 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
9015
9016 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
9017 BOOST_CHECK_EQUAL(denialState, NODATA);
9018}
9019
9020BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
9021 init();
9022
9023 testkeysset_t keys;
9024 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9025
9026 vector<DNSRecord> records;
9027
9028 vector<shared_ptr<DNSRecordContent>> recordContents;
9029 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
9030
9031 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
9032 recordContents.push_back(records.at(0).d_content);
9033 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
9034 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9035
9036 ContentSigPair pair;
9037 pair.records = recordContents;
9038 pair.signatures = signatureContents;
9039 cspmap_t denialMap;
9040 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
9041
9042 /* Add NSEC3 for the closest encloser */
9043 recordContents.clear();
9044 signatureContents.clear();
9045 records.clear();
9046 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
9047 recordContents.push_back(records.at(0).d_content);
9048 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
9049 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9050
9051 pair.records = recordContents;
9052 pair.signatures = signatureContents;
9053 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
9054
9055 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
9056 BOOST_CHECK_EQUAL(denialState, NODATA);
9057}
9058
00e3fef4
RG
9059BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
9060 init();
9061
9062 testkeysset_t keys;
9063 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9064
9065 vector<DNSRecord> records;
9066
9067 vector<shared_ptr<DNSRecordContent>> recordContents;
9068 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
9069
9070 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
9071 recordContents.push_back(records.at(0).d_content);
9072 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
9073 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9074 records.clear();
9075
9076 ContentSigPair pair;
9077 pair.records = recordContents;
9078 pair.signatures = signatureContents;
9079 cspmap_t denialMap;
9080 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
9081
9b061cf5 9082 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
00e3fef4 9083 it is an ENT */
9b061cf5 9084 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
00e3fef4 9085 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
00be1ff6 9086
9b061cf5
RG
9087 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
9088 it could prove a NXDOMAIN if it had an additional wildcard denial */
9089 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
9090 BOOST_CHECK_EQUAL(denialState, NODATA);
9091
00be1ff6
RG
9092 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
9093 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
9094 BOOST_CHECK_EQUAL(denialState, NODATA);
9b061cf5
RG
9095
9096 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
9097 recordContents.clear();
9098 signatureContents.clear();
9099 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
9100 recordContents.push_back(records.at(0).d_content);
9101 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
9102 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9103 records.clear();
9104 pair.records = recordContents;
9105 pair.signatures = signatureContents;
9106 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
9107
82566a96 9108 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
9b061cf5 9109 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
00e3fef4
RG
9110}
9111
95823c07
RG
9112BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
9113 init();
9114
9115 testkeysset_t keys;
9116 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9117
9118 vector<DNSRecord> records;
9119
9120 vector<shared_ptr<DNSRecordContent>> recordContents;
9121 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
9122
9123 /*
9124 The RRSIG from "." denies the existence of any type except NS at a.
9125 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
9126 signer field that is shorter than the owner name of the NSEC RR) it can't
9127 be used to deny anything except the whole name or a DS.
9128 */
9b061cf5 9129 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
95823c07
RG
9130 recordContents.push_back(records.at(0).d_content);
9131 addRRSIG(keys, records, DNSName("."), 300);
9132 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9133
9134 ContentSigPair pair;
9135 pair.records = recordContents;
9136 pair.signatures = signatureContents;
9137 cspmap_t denialMap;
9138 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
9139 records.clear();
9140
9141 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
9142 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
9143 nonexistence of any RRs below that zone cut, which include all RRs at
9144 that (original) owner name other than DS RRs, and all RRs below that
9145 owner name regardless of type.
9146 */
9147
00e3fef4 9148 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
95823c07
RG
9149 /* no data means the qname/qtype is not denied, because an ancestor
9150 delegation NSEC3 can only deny the DS */
9151 BOOST_CHECK_EQUAL(denialState, NODATA);
9152
00e3fef4 9153 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
95823c07 9154 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
5b522864
RG
9155
9156 /* it can not be used to deny any RRs below that owner name either */
9157 /* Add NSEC3 for the next closer */
9158 recordContents.clear();
9159 signatureContents.clear();
9160 records.clear();
9161 addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
9162 recordContents.push_back(records.at(0).d_content);
9163 addRRSIG(keys, records, DNSName("."), 300);
9164 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9165
9166 pair.records = recordContents;
9167 pair.signatures = signatureContents;
9168 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
9169
9170 /* add wildcard denial */
9171 recordContents.clear();
9172 signatureContents.clear();
9173 records.clear();
9174 addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
9175 recordContents.push_back(records.at(0).d_content);
9176 addRRSIG(keys, records, DNSName("."), 300);
9177 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9178
9179 pair.records = recordContents;
9180 pair.signatures = signatureContents;
9181 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
9182
9183 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true);
9184 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
9185}
9186
b7c40613
RG
9187BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
9188 init();
9189
9190 testkeysset_t keys;
9191 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9192
9193 vector<DNSRecord> records;
9194
9195 vector<shared_ptr<DNSRecordContent>> recordContents;
9196 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
9197
9198 /* adding a NSEC3 with more iterations that we support */
9199 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
9200 recordContents.push_back(records.at(0).d_content);
9201 addRRSIG(keys, records, DNSName("."), 300);
9202 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9203
9204 ContentSigPair pair;
9205 pair.records = recordContents;
9206 pair.signatures = signatureContents;
9207 cspmap_t denialMap;
9208 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
9209 records.clear();
9210
9211 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
9212 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
9213 BOOST_CHECK_EQUAL(denialState, INSECURE);
9214}
9215
95823c07
RG
9216BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
9217 init();
9218
9219 testkeysset_t keys;
9220 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9221
9222 vector<DNSRecord> records;
9223
9224 vector<shared_ptr<DNSRecordContent>> recordContents;
9225 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
9226
9227 /*
9228 * RFC 5155 section 8.9:
9229 * If there is an NSEC3 RR present in the response that matches the
9230 * delegation name, then the validator MUST ensure that the NS bit is
9231 * set and that the DS bit is not set in the Type Bit Maps field of the
9232 * NSEC3 RR.
9233 */
9234 /*
9235 The RRSIG from "." denies the existence of any type at a.
9236 NS should be set if it was proving an insecure delegation, let's check that
9237 we correctly detect that it's not.
9238 */
9b061cf5 9239 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
95823c07
RG
9240 recordContents.push_back(records.at(0).d_content);
9241 addRRSIG(keys, records, DNSName("."), 300);
9242 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
9243
9244 ContentSigPair pair;
9245 pair.records = recordContents;
9246 pair.signatures = signatureContents;
9247 cspmap_t denialMap;
9248 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
9249 records.clear();
9250
9251 /* Insecure because the NS is not set, so while it does
9252 denies the DS, it can't prove an insecure delegation */
00e3fef4 9253 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 9254 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
9255}
9256
dbbef467
RG
9257BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
9258 std::unique_ptr<SyncRes> sr;
dbbef467
RG
9259 initSR(sr, true);
9260
9261 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9262
9263 primeHints();
9264 const DNSName target("com.");
9265 testkeysset_t keys;
9266
9267 auto luaconfsCopy = g_luaconfs.getCopy();
9268 luaconfsCopy.dsAnchors.clear();
9269 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9270 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9271 g_luaconfs.setState(luaconfsCopy);
9272
9273 size_t queriesCount = 0;
1e2e06f1 9274 const time_t fixedNow = sr->getNow().tv_sec;
dbbef467 9275
1e2e06f1 9276 sr->setAsyncCallback([target,&queriesCount,keys,fixedNow](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
dbbef467
RG
9277 queriesCount++;
9278
9279 DNSName auth = domain;
9280 auth.chopOff();
9281
9282 if (type == QType::DS || type == QType::DNSKEY) {
9283 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9284 }
9285 else {
9286 setLWResult(res, RCode::NoError, true, false, true);
9287 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9288 addRRSIG(keys, res->d_records, domain, 300);
9289 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
1e2e06f1 9290 addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, fixedNow);
dbbef467
RG
9291 return 1;
9292 }
9293
9294 return 0;
9295 });
9296
9297 vector<DNSRecord> ret;
9298 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9299 BOOST_CHECK_EQUAL(res, RCode::NoError);
9300 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9301 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9302 BOOST_CHECK_EQUAL(queriesCount, 4);
9303
9304 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
28364e4b 9305 const NegCache::NegCacheEntry* ne = nullptr;
dbbef467 9306 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b 9307 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
1e2e06f1 9308 BOOST_CHECK_EQUAL(ne->d_ttd, fixedNow + 1);
28364e4b
RG
9309 BOOST_CHECK_EQUAL(ne->d_validationState, Secure);
9310 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9311 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9312 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
9313 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 1);
dbbef467
RG
9314
9315 /* again, to test the cache */
9316 ret.clear();
9317 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9318 BOOST_CHECK_EQUAL(res, RCode::NoError);
9319 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9320 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9321 BOOST_CHECK_EQUAL(queriesCount, 4);
9322}
9323
9324BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
9325 std::unique_ptr<SyncRes> sr;
dbbef467
RG
9326 initSR(sr, true);
9327
9328 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9329
9330 primeHints();
9331 const DNSName target("com.");
9332 const ComboAddress targetAddr("192.0.2.42");
9333 testkeysset_t keys;
9334
9335 auto luaconfsCopy = g_luaconfs.getCopy();
9336 luaconfsCopy.dsAnchors.clear();
9337 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9338 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9339 g_luaconfs.setState(luaconfsCopy);
9340
9341 size_t queriesCount = 0;
73c165ed 9342 const time_t tnow = sr->getNow().tv_sec;
dbbef467 9343
73c165ed 9344 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys,tnow](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
dbbef467
RG
9345 queriesCount++;
9346
9347 DNSName auth = domain;
9348 auth.chopOff();
9349
9350 if (type == QType::DS || type == QType::DNSKEY) {
9351 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9352 }
9353 else {
9354 setLWResult(res, RCode::NoError, true, false, true);
9355 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
73c165ed 9356 addRRSIG(keys, res->d_records, domain, 1, false, boost::none, boost::none, tnow);
dbbef467
RG
9357 return 1;
9358 }
9359
9360 return 0;
9361 });
9362
9363 vector<DNSRecord> ret;
9364 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9365 BOOST_CHECK_EQUAL(res, RCode::NoError);
9366 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9367 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9368 BOOST_CHECK_EQUAL(queriesCount, 4);
9369
9370 /* check that the entry has not been cached for longer than the RRSIG validity */
9371 const ComboAddress who;
9372 vector<DNSRecord> cached;
9373 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
73c165ed 9374 BOOST_REQUIRE_EQUAL(t_RC->get(tnow, target, QType(QType::A), true, &cached, who, &signatures), 1);
dbbef467
RG
9375 BOOST_REQUIRE_EQUAL(cached.size(), 1);
9376 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
73c165ed 9377 BOOST_CHECK_EQUAL((cached[0].d_ttl - tnow), 1);
dbbef467
RG
9378
9379 /* again, to test the cache */
9380 ret.clear();
9381 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9382 BOOST_CHECK_EQUAL(res, RCode::NoError);
9383 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9384 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9385 BOOST_CHECK_EQUAL(queriesCount, 4);
9386}
9387
f4de85a3
RG
9388BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
9389 /*
9390 Validation is optional, and the first query does not ask for it,
9391 so the answer is cached as Indeterminate.
9392 The second query asks for validation, answer should be marked as
9393 Secure.
9394 */
9395 std::unique_ptr<SyncRes> sr;
9396 initSR(sr, true);
9397
9398 setDNSSECValidation(sr, DNSSECMode::Process);
9399
9400 primeHints();
9401 const DNSName target("com.");
9402 testkeysset_t keys;
9403
9404 auto luaconfsCopy = g_luaconfs.getCopy();
9405 luaconfsCopy.dsAnchors.clear();
9406 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9407 g_luaconfs.setState(luaconfsCopy);
9408
9409 size_t queriesCount = 0;
9410
0bd2e252 9411 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, LWResult* res, bool* chained) {
f4de85a3
RG
9412 queriesCount++;
9413
9414 if (type == QType::DS || type == QType::DNSKEY) {
9415 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9416 }
9417 else {
9418 if (domain == target && type == QType::A) {
9419 setLWResult(res, 0, true, false, true);
9420 addRecordToLW(res, target, QType::A, "192.0.2.1");
9421 addRRSIG(keys, res->d_records, DNSName("."), 300);
9422 return 1;
9423 }
9424 }
9425
9426 return 0;
9427 });
9428
9429 vector<DNSRecord> ret;
9430 /* first query does not require validation */
9431 sr->setDNSSECValidationRequested(false);
9432 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9433 BOOST_CHECK_EQUAL(res, RCode::NoError);
9434 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9435 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9436 for (const auto& record : ret) {
9437 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
9438 }
9439 BOOST_CHECK_EQUAL(queriesCount, 1);
9440
9441
9442 ret.clear();
9443 /* second one _does_ require validation */
9444 sr->setDNSSECValidationRequested(true);
9445 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9446 BOOST_CHECK_EQUAL(res, RCode::NoError);
9447 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9448 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9449 for (const auto& record : ret) {
9450 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
9451 }
9452 BOOST_CHECK_EQUAL(queriesCount, 3);
9453}
9454
9455BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
9456 /*
9457 Validation is optional, and the first query does not ask for it,
9458 so the answer is cached as Indeterminate.
9459 The second query asks for validation, answer should be marked as
9460 Insecure.
9461 */
9462 std::unique_ptr<SyncRes> sr;
9463 initSR(sr, true);
9464
9465 setDNSSECValidation(sr, DNSSECMode::Process);
9466
9467 primeHints();
9468 const DNSName target("com.");
9469 testkeysset_t keys;
9470
9471 auto luaconfsCopy = g_luaconfs.getCopy();
9472 luaconfsCopy.dsAnchors.clear();
9473 g_luaconfs.setState(luaconfsCopy);
9474
9475 size_t queriesCount = 0;
9476
0bd2e252 9477 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, LWResult* res, bool* chained) {
f4de85a3
RG
9478 queriesCount++;
9479
9480 if (type == QType::DS || type == QType::DNSKEY) {
9481 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9482 }
9483 else {
9484 if (domain == target && type == QType::A) {
9485 setLWResult(res, 0, true, false, true);
9486 addRecordToLW(res, target, QType::A, "192.0.2.1");
9487 return 1;
9488 }
9489 }
9490
9491 return 0;
9492 });
9493
9494 vector<DNSRecord> ret;
9495 /* first query does not require validation */
9496 sr->setDNSSECValidationRequested(false);
9497 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9498 BOOST_CHECK_EQUAL(res, RCode::NoError);
9499 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9500 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9501 for (const auto& record : ret) {
55acb073 9502 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9503 }
9504 BOOST_CHECK_EQUAL(queriesCount, 1);
9505
9506
9507 ret.clear();
9508 /* second one _does_ require validation */
9509 sr->setDNSSECValidationRequested(true);
9510 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9511 BOOST_CHECK_EQUAL(res, RCode::NoError);
9512 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9513 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9514 for (const auto& record : ret) {
55acb073 9515 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9516 }
9517 BOOST_CHECK_EQUAL(queriesCount, 1);
9518}
9519
9520BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
9521 /*
9522 Validation is optional, and the first query does not ask for it,
9523 so the answer is cached as Indeterminate.
9524 The second query asks for validation, answer should be marked as
9525 Bogus.
9526 */
9527 std::unique_ptr<SyncRes> sr;
9528 initSR(sr, true);
9529
9530 setDNSSECValidation(sr, DNSSECMode::Process);
9531
9532 primeHints();
9533 const DNSName target("com.");
9534 testkeysset_t keys;
9535
9536 auto luaconfsCopy = g_luaconfs.getCopy();
9537 luaconfsCopy.dsAnchors.clear();
9538 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9539 g_luaconfs.setState(luaconfsCopy);
9540
9541 size_t queriesCount = 0;
9542
0bd2e252 9543 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, LWResult* res, bool* chained) {
f4de85a3
RG
9544 queriesCount++;
9545
9546 if (type == QType::DS || type == QType::DNSKEY) {
9547 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9548 }
9549 else {
9550 if (domain == target && type == QType::A) {
9551 setLWResult(res, 0, true, false, true);
9552 addRecordToLW(res, target, QType::A, "192.0.2.1");
9553 /* no RRSIG */
9554 return 1;
9555 }
9556 }
9557
9558 return 0;
9559 });
9560
9561 vector<DNSRecord> ret;
9562 /* first query does not require validation */
9563 sr->setDNSSECValidationRequested(false);
9564 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9565 BOOST_CHECK_EQUAL(res, RCode::NoError);
9566 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9567 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9568 for (const auto& record : ret) {
55acb073 9569 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9570 }
9571 BOOST_CHECK_EQUAL(queriesCount, 1);
9572
9573
9574 ret.clear();
9575 /* second one _does_ require validation */
9576 sr->setDNSSECValidationRequested(true);
9577 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9578 BOOST_CHECK_EQUAL(res, RCode::NoError);
9579 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9580 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9581 for (const auto& record : ret) {
55acb073 9582 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9583 }
9584 BOOST_CHECK_EQUAL(queriesCount, 3);
9585}
9586
55acb073
RG
9587BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
9588 /*
9589 Validation is optional, and the first query does not ask for it,
9590 so the answer is cached as Indeterminate.
9591 The second query asks for validation, answer should be marked as
9592 Secure.
9593 */
9594 std::unique_ptr<SyncRes> sr;
9595 initSR(sr, true);
9596
9597 setDNSSECValidation(sr, DNSSECMode::Process);
9598
9599 primeHints();
9600 const DNSName target("com.");
9601 const DNSName cnameTarget("cname-com.");
9602 testkeysset_t keys;
9603
9604 auto luaconfsCopy = g_luaconfs.getCopy();
9605 luaconfsCopy.dsAnchors.clear();
9606 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9607 g_luaconfs.setState(luaconfsCopy);
9608
9609 size_t queriesCount = 0;
9610
0bd2e252 9611 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, LWResult* res, bool* chained) {
55acb073
RG
9612 queriesCount++;
9613
9614 if (type == QType::DS || type == QType::DNSKEY) {
9615 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9616 }
9617 else {
9618 if (domain == target && type == QType::A) {
9619 setLWResult(res, 0, true, false, true);
9620 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9621 addRRSIG(keys, res->d_records, DNSName("."), 300);
9622 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9623 addRRSIG(keys, res->d_records, DNSName("."), 300);
9624 return 1;
9625 } else if (domain == cnameTarget && type == QType::A) {
9626 setLWResult(res, 0, true, false, true);
9627 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9628 addRRSIG(keys, res->d_records, DNSName("."), 300);
9629 return 1;
9630 }
9631 }
9632
9633 return 0;
9634 });
9635
9636 vector<DNSRecord> ret;
9637 /* first query does not require validation */
9638 sr->setDNSSECValidationRequested(false);
9639 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9640 BOOST_CHECK_EQUAL(res, RCode::NoError);
9641 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9642 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9643 for (const auto& record : ret) {
9644 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9645 }
9646 BOOST_CHECK_EQUAL(queriesCount, 2);
9647
9648
9649 ret.clear();
9650 /* second one _does_ require validation */
9651 sr->setDNSSECValidationRequested(true);
9652 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9653 BOOST_CHECK_EQUAL(res, RCode::NoError);
9654 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9655 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9656 for (const auto& record : ret) {
9657 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9658 }
9659 BOOST_CHECK_EQUAL(queriesCount, 5);
9660}
9661
9662BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
9663 /*
9664 Validation is optional, and the first query does not ask for it,
9665 so the answer is cached as Indeterminate.
9666 The second query asks for validation, answer should be marked as
9667 Insecure.
9668 */
9669 std::unique_ptr<SyncRes> sr;
9670 initSR(sr, true);
9671
9672 setDNSSECValidation(sr, DNSSECMode::Process);
9673
9674 primeHints();
9675 const DNSName target("com.");
9676 const DNSName cnameTarget("cname-com.");
9677 testkeysset_t keys;
9678
9679 auto luaconfsCopy = g_luaconfs.getCopy();
9680 luaconfsCopy.dsAnchors.clear();
9681 g_luaconfs.setState(luaconfsCopy);
9682
9683 size_t queriesCount = 0;
9684
0bd2e252 9685 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, LWResult* res, bool* chained) {
55acb073
RG
9686 queriesCount++;
9687
9688 if (type == QType::DS || type == QType::DNSKEY) {
9689 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9690 }
9691 else {
9692 if (domain == target && type == QType::A) {
9693 setLWResult(res, 0, true, false, true);
9694 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9695 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9696 return 1;
9697 } else if (domain == cnameTarget && type == QType::A) {
9698 setLWResult(res, 0, true, false, true);
9699 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9700 return 1;
9701 }
9702 }
9703
9704 return 0;
9705 });
9706
9707 vector<DNSRecord> ret;
9708 /* first query does not require validation */
9709 sr->setDNSSECValidationRequested(false);
9710 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9711 BOOST_CHECK_EQUAL(res, RCode::NoError);
9712 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9713 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9714 for (const auto& record : ret) {
9715 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9716 }
9717 BOOST_CHECK_EQUAL(queriesCount, 2);
9718
9719
9720 ret.clear();
9721 /* second one _does_ require validation */
9722 sr->setDNSSECValidationRequested(true);
9723 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9724 BOOST_CHECK_EQUAL(res, RCode::NoError);
9725 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9726 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9727 for (const auto& record : ret) {
9728 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9729 }
9730 BOOST_CHECK_EQUAL(queriesCount, 2);
9731}
9732
9733BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
9734 /*
9735 Validation is optional, and the first query does not ask for it,
9736 so the answer is cached as Indeterminate.
9737 The second query asks for validation, answer should be marked as
9738 Bogus.
9739 */
9740 std::unique_ptr<SyncRes> sr;
9741 initSR(sr, true);
9742
9743 setDNSSECValidation(sr, DNSSECMode::Process);
9744
9745 primeHints();
9746 const DNSName target("com.");
9747 const DNSName cnameTarget("cname-com.");
9748 testkeysset_t keys;
9749
9750 auto luaconfsCopy = g_luaconfs.getCopy();
9751 luaconfsCopy.dsAnchors.clear();
9752 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9753 g_luaconfs.setState(luaconfsCopy);
9754
9755 size_t queriesCount = 0;
9756
0bd2e252 9757 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, LWResult* res, bool* chained) {
55acb073
RG
9758 queriesCount++;
9759
9760 if (type == QType::DS || type == QType::DNSKEY) {
9761 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9762 }
9763 else {
9764 if (domain == target && type == QType::A) {
9765 setLWResult(res, 0, true, false, true);
9766 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9767 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9768 /* no RRSIG */
9769 return 1;
9770 } else if (domain == cnameTarget && type == QType::A) {
9771 setLWResult(res, 0, true, false, true);
9772 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9773 /* no RRSIG */
9774 return 1;
9775 }
9776 }
9777
9778 return 0;
9779 });
9780
9781 vector<DNSRecord> ret;
9782 /* first query does not require validation */
9783 sr->setDNSSECValidationRequested(false);
9784 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9785 BOOST_CHECK_EQUAL(res, RCode::NoError);
9786 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9787 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9788 for (const auto& record : ret) {
9789 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9790 }
9791 BOOST_CHECK_EQUAL(queriesCount, 2);
9792
9793
9794 ret.clear();
9795 /* second one _does_ require validation */
9796 sr->setDNSSECValidationRequested(true);
9797 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9798 BOOST_CHECK_EQUAL(res, RCode::NoError);
9799 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9800 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9801 for (const auto& record : ret) {
9802 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9803 }
9804 BOOST_CHECK_EQUAL(queriesCount, 5);
9805}
9806
405a26bd
RG
9807BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) {
9808 /*
9809 We get a record from a secure zone in the additional section, without
9810 the corresponding RRSIG. The record should not be marked as authoritative
9811 and should be correctly validated.
9812 */
9813 std::unique_ptr<SyncRes> sr;
9814 initSR(sr, true);
9815
9816 setDNSSECValidation(sr, DNSSECMode::Process);
9817
9818 primeHints();
9819 const DNSName target("com.");
9820 const DNSName addTarget("nsX.com.");
9821 testkeysset_t keys;
9822
9823 auto luaconfsCopy = g_luaconfs.getCopy();
9824 luaconfsCopy.dsAnchors.clear();
9825 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9826 g_luaconfs.setState(luaconfsCopy);
9827
9828 size_t queriesCount = 0;
9829
0bd2e252 9830 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, LWResult* res, bool* chained) {
405a26bd
RG
9831 queriesCount++;
9832
9833 if (type == QType::DS || type == QType::DNSKEY) {
9834 if (domain == addTarget) {
9835 DNSName auth(domain);
9836 /* no DS for com, auth will be . */
9837 auth.chopOff();
9838 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false);
9839 }
9840 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9841 }
9842 else {
9843 if (domain == target && type == QType::A) {
9844 setLWResult(res, 0, true, false, true);
9845 addRecordToLW(res, target, QType::A, "192.0.2.1");
9846 addRRSIG(keys, res->d_records, DNSName("."), 300);
9847 addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL);
9848 /* no RRSIG for the additional record */
9849 return 1;
9850 } else if (domain == addTarget && type == QType::A) {
9851 setLWResult(res, 0, true, false, true);
9852 addRecordToLW(res, addTarget, QType::A, "192.0.2.42");
9853 addRRSIG(keys, res->d_records, DNSName("."), 300);
9854 return 1;
9855 }
9856 }
9857
9858 return 0;
9859 });
9860
9861 vector<DNSRecord> ret;
9862 /* first query for target/A, will pick up the additional record as non-auth / unvalidated */
9863 sr->setDNSSECValidationRequested(false);
9864 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9865 BOOST_CHECK_EQUAL(res, RCode::NoError);
9866 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9867 BOOST_CHECK_EQUAL(ret.size(), 2);
9868 for (const auto& record : ret) {
9869 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9870 }
9871 BOOST_CHECK_EQUAL(queriesCount, 1);
9872
9873 ret.clear();
9874 /* ask for the additional record directly, we should not use
9875 the non-auth one and issue a new query, properly validated */
9876 sr->setDNSSECValidationRequested(true);
9877 res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret);
9878 BOOST_CHECK_EQUAL(res, RCode::NoError);
9879 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9880 BOOST_CHECK_EQUAL(ret.size(), 2);
9881 for (const auto& record : ret) {
9882 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9883 }
9884 BOOST_CHECK_EQUAL(queriesCount, 5);
9885}
9886
f4de85a3
RG
9887BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
9888 /*
9889 Validation is optional, and the first query does not ask for it,
9890 so the answer is negatively cached as Indeterminate.
9891 The second query asks for validation, answer should be marked as
9892 Secure.
9893 */
9894 std::unique_ptr<SyncRes> sr;
9895 initSR(sr, true);
9896
9897 setDNSSECValidation(sr, DNSSECMode::Process);
9898
9899 primeHints();
9900 const DNSName target("com.");
9901 testkeysset_t keys;
9902
9903 auto luaconfsCopy = g_luaconfs.getCopy();
9904 luaconfsCopy.dsAnchors.clear();
9905 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9906 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9907 g_luaconfs.setState(luaconfsCopy);
9908
9909 size_t queriesCount = 0;
9910
0bd2e252 9911 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, LWResult* res, bool* chained) {
f4de85a3
RG
9912 queriesCount++;
9913
9914 DNSName auth = domain;
9915 auth.chopOff();
9916
9917 if (type == QType::DS || type == QType::DNSKEY) {
9918 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9919 }
9920 else {
9921 setLWResult(res, RCode::NoError, true, false, true);
9922 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9923 addRRSIG(keys, res->d_records, domain, 300);
9924 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
9925 addRRSIG(keys, res->d_records, domain, 1);
9926 return 1;
9927 }
9928
9929 return 0;
9930 });
9931
9932 vector<DNSRecord> ret;
9933 /* first query does not require validation */
9934 sr->setDNSSECValidationRequested(false);
9935 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9936 BOOST_CHECK_EQUAL(res, RCode::NoError);
9937 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9938 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9939 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd 9940 /* check that the entry has not been negatively cached */
28364e4b 9941 const NegCache::NegCacheEntry* ne = nullptr;
b25712fd 9942 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9943 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9944 BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
9945 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9946 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9947 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
9948 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9949
9950 ret.clear();
9951 /* second one _does_ require validation */
9952 sr->setDNSSECValidationRequested(true);
9953 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9954 BOOST_CHECK_EQUAL(res, RCode::NoError);
9955 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9956 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9957 BOOST_CHECK_EQUAL(queriesCount, 4);
b25712fd 9958 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9959 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9960 BOOST_CHECK_EQUAL(ne->d_validationState, Secure);
9961 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9962 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9963 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
9964 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9965}
9966
f5a747bb
RG
9967BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
9968 /*
9969 Validation is optional, and the first query does not ask for it,
9970 so the answer is negatively cached as Indeterminate.
9971 The second query asks for validation, answer should be marked as
9972 Secure.
9973 The difference with test_dnssec_validation_from_negcache_secure is
9974 that have one more level here, so we are going to look for the proof
9975 that the DS does not exist for the last level. Since there is no cut,
9976 we should accept the fact that the NSEC denies DS and NS both.
9977 */
9978 std::unique_ptr<SyncRes> sr;
9979 initSR(sr, true);
9980
9981 setDNSSECValidation(sr, DNSSECMode::Process);
9982
9983 primeHints();
9984 const DNSName target("www.com.");
9985 testkeysset_t keys;
9986
9987 auto luaconfsCopy = g_luaconfs.getCopy();
9988 luaconfsCopy.dsAnchors.clear();
9989 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9990 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9991 g_luaconfs.setState(luaconfsCopy);
9992
9993 size_t queriesCount = 0;
9994
0bd2e252 9995 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, LWResult* res, bool* chained) {
f5a747bb
RG
9996 queriesCount++;
9997
9998 if (type == QType::DS || type == QType::DNSKEY) {
9999 if (domain == target) {
10000 /* there is no cut */
10001 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
10002 }
10003 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
10004 }
10005
10006 return 0;
10007 });
10008
10009 vector<DNSRecord> ret;
10010 /* first query does not require validation */
10011 sr->setDNSSECValidationRequested(false);
10012 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
10013 BOOST_CHECK_EQUAL(res, RCode::NoError);
10014 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
10015 BOOST_REQUIRE_EQUAL(ret.size(), 4);
10016 BOOST_CHECK_EQUAL(queriesCount, 1);
10017
10018 ret.clear();
10019 /* second one _does_ require validation */
10020 sr->setDNSSECValidationRequested(true);
10021 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
10022 BOOST_CHECK_EQUAL(res, RCode::NoError);
10023 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
10024 BOOST_REQUIRE_EQUAL(ret.size(), 4);
10025 BOOST_CHECK_EQUAL(queriesCount, 4);
10026}
10027
f4de85a3
RG
10028BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
10029 /*
10030 Validation is optional, and the first query does not ask for it,
10031 so the answer is negatively cached as Indeterminate.
10032 The second query asks for validation, answer should be marked as
10033 Insecure.
10034 */
10035 std::unique_ptr<SyncRes> sr;
10036 initSR(sr, true);
10037
10038 setDNSSECValidation(sr, DNSSECMode::Process);
10039
10040 primeHints();
10041 const DNSName target("com.");
10042 testkeysset_t keys;
10043
10044 auto luaconfsCopy = g_luaconfs.getCopy();
10045 luaconfsCopy.dsAnchors.clear();
10046 g_luaconfs.setState(luaconfsCopy);
10047
10048 size_t queriesCount = 0;
10049
0bd2e252 10050 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, LWResult* res, bool* chained) {
f4de85a3
RG
10051 queriesCount++;
10052
10053 DNSName auth = domain;
10054 auth.chopOff();
10055
10056 if (type == QType::DS || type == QType::DNSKEY) {
10057 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10058 }
10059 else {
10060 setLWResult(res, RCode::NoError, true, false, true);
10061 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
10062 return 1;
10063 }
10064
10065 return 0;
10066 });
10067
10068 vector<DNSRecord> ret;
10069 /* first query does not require validation */
10070 sr->setDNSSECValidationRequested(false);
10071 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10072 BOOST_CHECK_EQUAL(res, RCode::NoError);
10073 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
10074 BOOST_REQUIRE_EQUAL(ret.size(), 1);
10075 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd 10076 /* check that the entry has not been negatively cached */
28364e4b 10077 const NegCache::NegCacheEntry* ne = nullptr;
b25712fd 10078 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
10079 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
10080 BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
10081 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
10082 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 0);
10083 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
10084 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
10085
10086 ret.clear();
10087 /* second one _does_ require validation */
10088 sr->setDNSSECValidationRequested(true);
10089 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10090 BOOST_CHECK_EQUAL(res, RCode::NoError);
10091 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
10092 BOOST_REQUIRE_EQUAL(ret.size(), 1);
10093 BOOST_CHECK_EQUAL(queriesCount, 1);
28364e4b
RG
10094 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
10095 BOOST_CHECK_EQUAL(ne->d_validationState, Insecure);
10096 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
10097 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 0);
10098 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
10099 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
10100}
10101
10102BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
10103 /*
10104 Validation is optional, and the first query does not ask for it,
10105 so the answer is negatively cached as Indeterminate.
10106 The second query asks for validation, answer should be marked as
10107 Bogus.
10108 */
10109 std::unique_ptr<SyncRes> sr;
10110 initSR(sr, true);
10111
10112 setDNSSECValidation(sr, DNSSECMode::Process);
10113
10114 primeHints();
10115 const DNSName target("com.");
10116 testkeysset_t keys;
10117
10118 auto luaconfsCopy = g_luaconfs.getCopy();
10119 luaconfsCopy.dsAnchors.clear();
10120 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10121 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10122 g_luaconfs.setState(luaconfsCopy);
10123
10124 size_t queriesCount = 0;
10125
0bd2e252 10126 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, LWResult* res, bool* chained) {
f4de85a3
RG
10127 queriesCount++;
10128
10129 DNSName auth = domain;
10130 auth.chopOff();
10131
10132 if (type == QType::DS || type == QType::DNSKEY) {
10133 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10134 }
10135 else {
10136 setLWResult(res, RCode::NoError, true, false, true);
10137 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
10138 addRRSIG(keys, res->d_records, domain, 300);
10139 /* no denial */
10140 return 1;
10141 }
10142
10143 return 0;
10144 });
10145
10146 vector<DNSRecord> ret;
10147 /* first query does not require validation */
10148 sr->setDNSSECValidationRequested(false);
10149 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10150 BOOST_CHECK_EQUAL(res, RCode::NoError);
10151 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
10152 BOOST_REQUIRE_EQUAL(ret.size(), 2);
10153 BOOST_CHECK_EQUAL(queriesCount, 1);
28364e4b 10154 const NegCache::NegCacheEntry* ne = nullptr;
b25712fd 10155 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
10156 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
10157 BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
10158 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
10159 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
10160 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
10161 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
10162
10163 ret.clear();
10164 /* second one _does_ require validation */
10165 sr->setDNSSECValidationRequested(true);
10166 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10167 BOOST_CHECK_EQUAL(res, RCode::NoError);
10168 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
10169 BOOST_REQUIRE_EQUAL(ret.size(), 2);
10170 BOOST_CHECK_EQUAL(queriesCount, 4);
28364e4b
RG
10171 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
10172 BOOST_CHECK_EQUAL(ne->d_validationState, Bogus);
10173 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
10174 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
10175 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
10176 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
10177}
10178
429ce1da
PL
10179BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
10180 g_lowercaseOutgoing = true;
10181 std::unique_ptr<SyncRes> sr;
10182 initSR(sr);
10183
10184 primeHints();
10185
10186 vector<DNSName> sentOutQnames;
10187
10188 const DNSName target("WWW.POWERDNS.COM");
10189 const DNSName cname("WWW.PowerDNS.org");
10190
0bd2e252 10191 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, LWResult* res, bool* chained) {
429ce1da
PL
10192
10193 sentOutQnames.push_back(domain);
10194
10195 if (isRootServer(ip)) {
10196 if (domain == target) {
10197 setLWResult(res, 0, false, false, true);
10198 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
10199 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
10200 return 1;
10201 }
10202 if (domain == cname) {
10203 setLWResult(res, 0, false, false, true);
10204 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
10205 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
10206 return 1;
10207 }
10208 } else if (ip == ComboAddress("192.0.2.1:53")) {
10209 if (domain == target) {
10210 setLWResult(res, 0, true, false, false);
10211 addRecordToLW(res, domain, QType::CNAME, cname.toString());
10212 return 1;
10213 }
10214 } else if (ip == ComboAddress("192.0.2.2:53")) {
10215 if (domain == cname) {
10216 setLWResult(res, 0, true, false, false);
10217 addRecordToLW(res, domain, QType::A, "127.0.0.1");
10218 return 1;
10219 }
10220 }
10221 return 0;
10222 });
10223
10224 vector<DNSRecord> ret;
10225 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10226
10227 BOOST_CHECK_EQUAL(res, RCode::NoError);
10228
10229 BOOST_REQUIRE_EQUAL(ret.size(), 2);
10230 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
10231
10232 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
10233 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
10234 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
10235 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
10236 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
10237
10238 g_lowercaseOutgoing = false;
10239}
10240
4d787d30
PL
10241BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
10242 std::unique_ptr<SyncRes> sr;
10243 initSR(sr, true);
10244
10245 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10246
10247 primeHints();
10248 const DNSName target("com.");
10249 testkeysset_t keys, keys2;
10250
10251 auto luaconfsCopy = g_luaconfs.getCopy();
10252 luaconfsCopy.dsAnchors.clear();
10253 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10254 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10255 g_luaconfs.setState(luaconfsCopy);
10256
10257 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10258 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
10259 // But add the existing root key otherwise no RRSIG can be created
10260 auto rootkey = keys.find(g_rootdnsname);
10261 keys2.insert(*rootkey);
10262
0bd2e252 10263 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, LWResult* res, bool* chained) {
4d787d30
PL
10264 DNSName auth = domain;
10265 auth.chopOff();
10266 if (type == QType::DS || type == QType::DNSKEY) {
10267 if (domain == target) {
10268 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10269 return 0;
10270 }
10271 }
10272 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10273 }
10274 return 0;
10275 });
10276
10277 dsmap_t ds;
10278 auto state = sr->getDSRecords(target, ds, false, 0, false);
10279 BOOST_CHECK_EQUAL(state, Secure);
10280 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10281 for (const auto& i : ds) {
10282 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
10283 }
10284}
10285
10286BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
10287 std::unique_ptr<SyncRes> sr;
10288 initSR(sr, true);
10289
10290 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10291
10292 primeHints();
10293 const DNSName target("com.");
10294 testkeysset_t keys, keys2, keys3;
10295
10296 auto luaconfsCopy = g_luaconfs.getCopy();
10297 luaconfsCopy.dsAnchors.clear();
10298 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10299 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10300 g_luaconfs.setState(luaconfsCopy);
10301
10302 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10303 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
10304 // But add the existing root key otherwise no RRSIG can be created
10305 auto rootkey = keys.find(g_rootdnsname);
10306 keys2.insert(*rootkey);
10307
10308 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
10309 // But add the existing root key otherwise no RRSIG can be created
10310 keys3.insert(*rootkey);
10311
0bd2e252 10312 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, LWResult* res, bool* chained) {
4d787d30
PL
10313 DNSName auth = domain;
10314 auth.chopOff();
10315 if (type == QType::DS || type == QType::DNSKEY) {
10316 if (domain == target) {
10317 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10318 return 0;
10319 }
10320 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
10321 return 0;
10322 }
10323 }
10324 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10325 }
10326 return 0;
10327 });
10328
10329 dsmap_t ds;
10330 auto state = sr->getDSRecords(target, ds, false, 0, false);
10331 BOOST_CHECK_EQUAL(state, Secure);
10332 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10333 for (const auto& i : ds) {
10334 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
10335 }
10336}
10337
10338BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
10339 std::unique_ptr<SyncRes> sr;
10340 initSR(sr, true);
10341
10342 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10343
10344 primeHints();
10345 const DNSName target("com.");
10346 testkeysset_t keys, keys2, keys3;
10347
10348 auto luaconfsCopy = g_luaconfs.getCopy();
10349 luaconfsCopy.dsAnchors.clear();
10350 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10351 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10352 g_luaconfs.setState(luaconfsCopy);
10353
10354 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10355 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
10356 // But add the existing root key otherwise no RRSIG can be created
10357 auto rootkey = keys.find(g_rootdnsname);
10358 keys2.insert(*rootkey);
10359
10360 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
10361 // But add the existing root key otherwise no RRSIG can be created
10362 keys3.insert(*rootkey);
10363
0bd2e252 10364 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, LWResult* res, bool* chained) {
4d787d30
PL
10365 DNSName auth = domain;
10366 auth.chopOff();
10367 if (type == QType::DS || type == QType::DNSKEY) {
10368 if (domain == target) {
10369 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10370 return 0;
10371 }
10372 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
10373 return 0;
10374 }
10375 }
10376 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10377 }
10378 return 0;
10379 });
10380
10381 dsmap_t ds;
10382 auto state = sr->getDSRecords(target, ds, false, 0, false);
10383 BOOST_CHECK_EQUAL(state, Secure);
10384 BOOST_REQUIRE_EQUAL(ds.size(), 2);
10385 for (const auto& i : ds) {
10386 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
10387 }
10388}
10389
d9c32b52
RG
10390BOOST_AUTO_TEST_CASE(test_cname_plus_authority_ns_ttl) {
10391 std::unique_ptr<SyncRes> sr;
10392 initSR(sr);
10393
10394 primeHints();
10395
10396 const DNSName target("cname.powerdns.com.");
10397 const DNSName cnameTarget("cname-target.powerdns.com");
10398 size_t queriesCount = 0;
10399
10400 sr->setAsyncCallback([target, cnameTarget, &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, LWResult* res, bool* chained) {
10401
10402 queriesCount++;
10403
10404 if (isRootServer(ip)) {
10405 setLWResult(res, 0, false, false, true);
10406 addRecordToLW(res, DNSName("powerdns.com"), QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 42);
10407 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
10408 return 1;
10409 } else if (ip == ComboAddress("192.0.2.1:53")) {
10410 if (domain == target) {
10411 setLWResult(res, 0, true, false, false);
10412 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
10413 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2");
10414 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
fc8c01f4 10415 addRecordToLW(res, DNSName("a.gtld-servers.net."), QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
d9c32b52
RG
10416 return 1;
10417 }
10418 else if (domain == cnameTarget) {
10419 setLWResult(res, 0, true, false, false);
10420 addRecordToLW(res, domain, QType::A, "192.0.2.2");
10421 }
10422
10423 return 1;
10424 }
10425
10426 return 0;
10427 });
10428
10429 const time_t now = sr->getNow().tv_sec;
10430 vector<DNSRecord> ret;
10431 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10432 BOOST_CHECK_EQUAL(res, RCode::NoError);
10433 BOOST_REQUIRE_EQUAL(ret.size(), 2);
10434 BOOST_CHECK(ret[0].d_type == QType::CNAME);
10435 BOOST_CHECK_EQUAL(ret[0].d_name, target);
10436 BOOST_CHECK(ret[1].d_type == QType::A);
10437 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
10438
10439 /* check that the NS in authority has not replaced the one in the cache
10440 with auth=0 (or at least has not raised the TTL since it could otherwise
10441 be used to create a never-ending ghost zone even after the NS have been
10442 changed in the parent.
d9c32b52
RG
10443 */
10444 const ComboAddress who;
10445 vector<DNSRecord> cached;
10446 bool wasAuth = false;
10447
10448 auto ttl = t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth);
10449 BOOST_REQUIRE_GE(ttl, 1);
10450 BOOST_REQUIRE_LE(ttl, 42);
10451 BOOST_CHECK_EQUAL(cached.size(), 1);
10452 BOOST_CHECK_EQUAL(wasAuth, false);
10453
10454 cached.clear();
fc8c01f4
RG
10455
10456 /* Also check that the the part in additional is still not auth */
10457 BOOST_REQUIRE_GE(t_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth), -1);
d9c32b52
RG
10458 BOOST_CHECK_EQUAL(cached.size(), 1);
10459 BOOST_CHECK_EQUAL(wasAuth, false);
10460}
10461
8416631b
RG
10462BOOST_AUTO_TEST_CASE(test_records_sanitization_general) {
10463 std::unique_ptr<SyncRes> sr;
10464 initSR(sr);
10465
10466 primeHints();
10467
10468 const DNSName target("sanitization.powerdns.com.");
10469
10470 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, LWResult* res, bool* chained) {
10471
10472 setLWResult(res, 0, true, false, true);
10473 addRecordToLW(res, domain, QType::A, "192.0.2.1");
10474 /* should be scrubbed because it doesn't match the QType */
10475 addRecordToLW(res, domain, QType::AAAA, "2001:db8::1");
10476 /* should be scrubbed because the DNAME is not relevant to the qname */
10477 addRecordToLW(res, DNSName("not-sanitization.powerdns.com."), QType::DNAME, "not-sanitization.powerdns.net.");
10478 /* should be scrubbed because a MX has no reason to show up in AUTHORITY */
10479 addRecordToLW(res, domain, QType::MX, "10 mx.powerdns.com.", DNSResourceRecord::AUTHORITY);
10480 /* should be scrubbed because the SOA name is not relevant to the qname */
10481 addRecordToLW(res, DNSName("not-sanitization.powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY);
10482 /* should be scrubbed because types other than A or AAAA are not really supposed to show up in ADDITIONAL */
10483 addRecordToLW(res, domain, QType::TXT, "TXT", DNSResourceRecord::ADDITIONAL);
10484 /* should be scrubbed because it doesn't match any of the accepted names in this answer (mostly 'domain') */
10485 addRecordToLW(res, DNSName("powerdns.com."), QType::AAAA, "2001:db8::1", DNSResourceRecord::ADDITIONAL);
10486 return 1;
8416631b
RG
10487 });
10488
10489 const time_t now = sr->getNow().tv_sec;
10490
10491 vector<DNSRecord> ret;
10492 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10493 BOOST_CHECK_EQUAL(res, RCode::NoError);
10494 BOOST_REQUIRE_EQUAL(ret.size(), 1);
10495
10496 const ComboAddress who;
10497 vector<DNSRecord> cached;
10498 BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
10499 cached.clear();
10500 BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::AAAA), true, &cached, who), 0);
10501 BOOST_CHECK_EQUAL(t_RC->get(now, DNSName("not-sanitization.powerdns.com."), QType(QType::DNAME), true, &cached, who), -1);
10502 BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::MX), true, &cached, who), 0);
10503 BOOST_CHECK_EQUAL(t_RC->get(now, DNSName("not-sanitization.powerdns.com."), QType(QType::SOA), true, &cached, who), -1);
10504 BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::TXT), false, &cached, who), 0);
10505 BOOST_CHECK_EQUAL(t_RC->get(now, DNSName("powerdns.com."), QType(QType::AAAA), false, &cached, who), -1);
10506}
10507
10508BOOST_AUTO_TEST_CASE(test_records_sanitization_keep_relevant_additional_aaaa) {
10509 std::unique_ptr<SyncRes> sr;
10510 initSR(sr);
10511
10512 primeHints();
10513
10514 const DNSName target("sanitization.powerdns.com.");
10515
10516 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, LWResult* res, bool* chained) {
10517
10518 setLWResult(res, 0, true, false, true);
10519 addRecordToLW(res, domain, QType::A, "192.0.2.1");
10520 addRecordToLW(res, domain, QType::AAAA, "2001:db8::1", DNSResourceRecord::ADDITIONAL);
10521 return 1;
8416631b
RG
10522 });
10523
10524 const time_t now = sr->getNow().tv_sec;
10525
10526 vector<DNSRecord> ret;
10527 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10528 BOOST_CHECK_EQUAL(res, RCode::NoError);
10529 BOOST_REQUIRE_EQUAL(ret.size(), 1);
10530
10531 const ComboAddress who;
10532 vector<DNSRecord> cached;
10533 BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
10534 cached.clear();
10535 /* not auth since it was in the additional section */
10536 BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::AAAA), true, &cached, who), 0);
10537 BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::AAAA), false, &cached, who), 0);
10538}
10539
10540BOOST_AUTO_TEST_CASE(test_records_sanitization_keep_glue) {
10541 std::unique_ptr<SyncRes> sr;
10542 initSR(sr);
10543
10544 primeHints();
10545
10546 const DNSName target("sanitization-glue.powerdns.com.");
10547
10548 size_t queriesCount = 0;
10549
10550 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, LWResult* res, bool* chained) {
10551
10552 queriesCount++;
10553
10554 if (isRootServer(ip)) {
10555 setLWResult(res, 0, false, false, true);
10556 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
10557 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
10558 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
10559 return 1;
10560 }
10561 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
10562 setLWResult(res, 0, false, false, true);
10563 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
10564 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
10565 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
10566 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
10567 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
10568 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
10569 return 1;
10570 }
10571 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")) {
10572 setLWResult(res, 0, true, false, true);
10573 addRecordToLW(res, target, QType::A, "192.0.2.4");
10574 return 1;
10575 }
10576 else {
10577 return 0;
10578 }
10579 });
10580
10581 const time_t now = sr->getNow().tv_sec;
10582
10583 vector<DNSRecord> ret;
10584 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10585 BOOST_CHECK_EQUAL(res, RCode::NoError);
10586 BOOST_CHECK_EQUAL(ret.size(), 1);
10587 BOOST_CHECK_EQUAL(queriesCount, 3);
10588
10589 const ComboAddress who;
10590 vector<DNSRecord> cached;
10591 BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
10592 cached.clear();
10593
10594 BOOST_CHECK_GT(t_RC->get(now, DNSName("com."), QType(QType::NS), false, &cached, who), 0);
10595 BOOST_CHECK_GT(t_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who), 0);
10596 BOOST_CHECK_GT(t_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::AAAA), false, &cached, who), 0);
10597 BOOST_CHECK_GT(t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who), 0);
10598 BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns1.powerdns.com."), QType(QType::A), false, &cached, who), 0);
10599 BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns1.powerdns.com."), QType(QType::AAAA), false, &cached, who), 0);
10600 BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns2.powerdns.com."), QType(QType::A), false, &cached, who), 0);
10601 BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns2.powerdns.com."), QType(QType::AAAA), false, &cached, who), 0);
10602}
10603
10604BOOST_AUTO_TEST_CASE(test_records_sanitization_scrubs_ns_nxd) {
10605 std::unique_ptr<SyncRes> sr;
10606 initSR(sr);
10607
10608 primeHints();
10609
10610 const DNSName target("sanitization-ns-nxd.powerdns.com.");
10611
10612 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, LWResult* res, bool* chained) {
10613
10614 setLWResult(res, RCode::NXDomain, true, false, true);
10615 addRecordToLW(res, "powerdns.com.", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY);
10616 addRecordToLW(res, "powerdns.com.", QType::NS, "spoofed.ns.", DNSResourceRecord::AUTHORITY, 172800);
10617 addRecordToLW(res, "spoofed.ns.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
10618 addRecordToLW(res, "spoofed.ns.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
10619 return 1;
10620 });
10621
10622 const time_t now = sr->getNow().tv_sec;
10623
10624 vector<DNSRecord> ret;
10625 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10626 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
10627 BOOST_CHECK_EQUAL(ret.size(), 1);
10628
10629 const ComboAddress who;
10630 vector<DNSRecord> cached;
10631 BOOST_CHECK_GT(t_RC->get(now, DNSName("powerdns.com."), QType(QType::SOA), true, &cached, who), 0);
10632 cached.clear();
10633
10634 BOOST_CHECK_LT(t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who), 0);
10635 BOOST_CHECK_LT(t_RC->get(now, DNSName("spoofed.ns."), QType(QType::A), false, &cached, who), 0);
10636 BOOST_CHECK_LT(t_RC->get(now, DNSName("spoofed.ns."), QType(QType::AAAA), false, &cached, who), 0);
10637}
10638
d6e797b8
RG
10639/*
10640// cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
10641
648bcbd1 10642- check out of band support
d6e797b8 10643
648bcbd1 10644- check preoutquery
d6e797b8 10645
30ee601a
RG
10646*/
10647
10648BOOST_AUTO_TEST_SUITE_END()