]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/test-syncres_cc.cc
rec: Add support for more than one protobuf server
[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
b773359c 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::shared_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) {
95 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
96 dsAnchors[g_rootdnsname].insert(*ds);
97 }
98}
99
100/* Some helpers functions */
101
102static void init(bool debug=false)
103{
e6a9dde5
PL
104 g_log.setName("test");
105 g_log.disableSyslog(true);
b4c8789a 106
30ee601a 107 if (debug) {
e6a9dde5
PL
108 g_log.setLoglevel((Logger::Urgency)(6)); // info and up
109 g_log.toConsole(Logger::Info);
30ee601a 110 }
b4c8789a 111 else {
e6a9dde5
PL
112 g_log.setLoglevel(Logger::None);
113 g_log.toConsole(Logger::Error);
b4c8789a 114 }
30ee601a 115
d6e797b8 116 reportAllTypes();
30ee601a 117
f26bf547 118 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
30ee601a 119
30ee601a
RG
120 SyncRes::s_maxqperq = 50;
121 SyncRes::s_maxtotusec = 1000*7000;
122 SyncRes::s_maxdepth = 40;
123 SyncRes::s_maxnegttl = 3600;
124 SyncRes::s_maxcachettl = 86400;
125 SyncRes::s_packetcachettl = 3600;
126 SyncRes::s_packetcacheservfailttl = 60;
127 SyncRes::s_serverdownmaxfails = 64;
128 SyncRes::s_serverdownthrottletime = 60;
129 SyncRes::s_doIPv6 = true;
e9f9b8ec
RG
130 SyncRes::s_ecsipv4limit = 24;
131 SyncRes::s_ecsipv6limit = 56;
f58c8379 132 SyncRes::s_rootNXTrust = true;
d6e797b8 133 SyncRes::s_minimumTTL = 0;
648bcbd1 134 SyncRes::s_serverID = "PowerDNS Unit Tests Server ID";
2fe3354d
CH
135 SyncRes::clearEDNSLocalSubnets();
136 SyncRes::addEDNSLocalSubnet("0.0.0.0/0");
137 SyncRes::addEDNSLocalSubnet("::/0");
138 SyncRes::clearEDNSRemoteSubnets();
9065eb05
RG
139 SyncRes::clearEDNSDomains();
140 SyncRes::clearDelegationOnly();
141 SyncRes::clearDontQuery();
2fe3354d 142 SyncRes::setECSScopeZeroAddress(Netmask("127.0.0.1/32"));
648bcbd1 143
a712cb56 144 SyncRes::clearNSSpeeds();
6dfff36f 145 BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0);
a712cb56 146 SyncRes::clearEDNSStatuses();
6dfff36f 147 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0);
a712cb56 148 SyncRes::clearThrottle();
6dfff36f 149 BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0);
a712cb56 150 SyncRes::clearFailedServers();
6dfff36f 151 BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0);
a712cb56 152
648bcbd1
RG
153 auto luaconfsCopy = g_luaconfs.getCopy();
154 luaconfsCopy.dfe.clear();
8455425c
RG
155 luaconfsCopy.dsAnchors.clear();
156 for (const auto &dsRecord : rootDSs) {
157 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
158 luaconfsCopy.dsAnchors[g_rootdnsname].insert(*ds);
159 }
160 luaconfsCopy.negAnchors.clear();
648bcbd1
RG
161 g_luaconfs.setState(luaconfsCopy);
162
8455425c 163 g_dnssecmode = DNSSECMode::Off;
895449a5 164 g_dnssecLOG = debug;
b7c40613 165 g_maxNSEC3Iterations = 2500;
8455425c 166
648bcbd1 167 ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Unit Tests";
964ee532
RG
168 ::arg().set("rng")="auto";
169 ::arg().set("entropy-source")="/dev/urandom";
30ee601a
RG
170}
171
895449a5 172static void initSR(std::unique_ptr<SyncRes>& sr, bool dnssec=false, bool debug=false, time_t fakeNow=0)
30ee601a
RG
173{
174 struct timeval now;
d6e797b8
RG
175 if (fakeNow > 0) {
176 now.tv_sec = fakeNow;
177 now.tv_usec = 0;
178 }
179 else {
180 Utility::gettimeofday(&now, 0);
181 }
182
895449a5
RG
183 init(debug);
184
30ee601a 185 sr = std::unique_ptr<SyncRes>(new SyncRes(now));
895449a5 186 sr->setDoEDNS0(true);
0c43f455
RG
187 if (dnssec) {
188 sr->setDoDNSSEC(dnssec);
189 }
190
895449a5
RG
191 sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
192
a712cb56
RG
193 SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
194 SyncRes::clearNegCache();
30ee601a
RG
195}
196
0c43f455
RG
197static void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
198{
199 sr->setDNSSECValidationRequested(true);
200 g_dnssecmode = mode;
201}
202
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
179b340d 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)
8455425c
RG
243{
244 time_t now = time(nullptr);
245 DNSKEYRecordContent drc = dpk.getDNSKEY();
246 const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
247
248 rrc.d_type = signQType;
249 rrc.d_labels = signQName.countLabels() - signQName.isWildcard();
250 rrc.d_originalttl = signTTL;
179b340d 251 rrc.d_siginception = inception ? *inception : (now - 10);
8455425c
RG
252 rrc.d_sigexpire = now + sigValidity;
253 rrc.d_signer = signer;
254 rrc.d_tag = 0;
255 rrc.d_tag = drc.getTag();
3d5ebf10 256 rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
8455425c
RG
257
258 std::string msg = getMessageForRRSET(signQName, rrc, toSign);
259
260 rrc.d_signature = rc->sign(msg);
261}
262
b7f378d1
RG
263typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t;
264
5374b03b 265static bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional<uint8_t> algo=boost::none, boost::optional<DNSName> wildcard=boost::none)
8455425c
RG
266{
267 if (records.empty()) {
5374b03b 268 return false;
8455425c
RG
269 }
270
271 const auto it = keys.find(signer);
272 if (it == keys.cend()) {
86f1af1c 273 throw std::runtime_error("No DNSKEY found for " + signer.toLogString() + ", unable to compute the requested RRSIG");
8455425c
RG
274 }
275
276 size_t recordsCount = records.size();
277 const DNSName& name = records[recordsCount-1].d_name;
278 const uint16_t type = records[recordsCount-1].d_type;
279
280 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
281 for (const auto record : records) {
282 if (record.d_name == name && record.d_type == type) {
283 recordcontents.push_back(record.d_content);
284 }
285 }
286
287 RRSIGRecordContent rrc;
82fbd934 288 computeRRSIG(it->second.first, signer, wildcard ? *wildcard : records[recordsCount-1].d_name, records[recordsCount-1].d_type, records[recordsCount-1].d_ttl, sigValidity, rrc, recordcontents, algo);
3d5ebf10
RG
289 if (broken) {
290 rrc.d_signature[0] ^= 42;
291 }
8455425c
RG
292
293 DNSRecord rec;
dbbef467 294 rec.d_type = QType::RRSIG;
8455425c
RG
295 rec.d_place = records[recordsCount-1].d_place;
296 rec.d_name = records[recordsCount-1].d_name;
dbbef467 297 rec.d_ttl = records[recordsCount-1].d_ttl;
8455425c
RG
298
299 rec.d_content = std::make_shared<RRSIGRecordContent>(rrc);
300 records.push_back(rec);
5374b03b
RG
301
302 return true;
8455425c
RG
303}
304
b7f378d1 305static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records)
8455425c
RG
306{
307 const auto it = keys.find(signer);
308 if (it == keys.cend()) {
86f1af1c 309 throw std::runtime_error("No DNSKEY found for " + signer.toLogString());
8455425c
RG
310 }
311
312 DNSRecord rec;
313 rec.d_place = DNSResourceRecord::ANSWER;
314 rec.d_name = signer;
315 rec.d_type = QType::DNSKEY;
316 rec.d_ttl = ttl;
317
b7f378d1 318 rec.d_content = std::make_shared<DNSKEYRecordContent>(it->second.first.getDNSKEY());
8455425c
RG
319 records.push_back(rec);
320}
321
5374b03b 322static bool addDS(const DNSName& domain, uint32_t ttl, std::vector<DNSRecord>& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY)
8455425c 323{
b7f378d1
RG
324 const auto it = keys.find(domain);
325 if (it == keys.cend()) {
5374b03b 326 return false;
8455425c
RG
327 }
328
b7f378d1
RG
329 DNSRecord rec;
330 rec.d_name = domain;
331 rec.d_type = QType::DS;
a53e8fe3 332 rec.d_place = place;
b7f378d1
RG
333 rec.d_ttl = ttl;
334 rec.d_content = std::make_shared<DSRecordContent>(it->second.second);
8455425c 335
b7f378d1 336 records.push_back(rec);
5374b03b 337 return true;
8455425c
RG
338}
339
340static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
341{
342 NSECRecordContent nrc;
343 nrc.d_next = next;
344 nrc.d_set = types;
345
346 DNSRecord rec;
347 rec.d_name = domain;
348 rec.d_ttl = ttl;
349 rec.d_type = QType::NSEC;
350 rec.d_content = std::make_shared<NSECRecordContent>(nrc);
351 rec.d_place = DNSResourceRecord::AUTHORITY;
352
353 records.push_back(rec);
354}
355
95823c07
RG
356static 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)
357{
358 NSEC3RecordContent nrc;
359 nrc.d_algorithm = 1;
360 nrc.d_flags = 0;
361 nrc.d_iterations = iterations;
362 nrc.d_salt = salt;
363 nrc.d_nexthash = hashedNext;
364 nrc.d_set = types;
365
366 DNSRecord rec;
367 rec.d_name = hashedName;
368 rec.d_ttl = ttl;
369 rec.d_type = QType::NSEC3;
370 rec.d_content = std::make_shared<NSEC3RecordContent>(nrc);
371 rec.d_place = DNSResourceRecord::AUTHORITY;
372
373 records.push_back(rec);
374}
375
b7c40613 376static 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
377{
378 static const std::string salt = "deadbeef";
95823c07
RG
379 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
380
9b061cf5 381 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, next, salt, iterations, types, ttl, records);
95823c07
RG
382}
383
b7c40613 384static 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
385{
386 static const std::string salt = "deadbeef";
95823c07 387 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
95823c07
RG
388 std::string hashedNext(hashed);
389 incrementHash(hashedNext);
390 decrementHash(hashed);
391
9b061cf5 392 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, hashedNext, salt, iterations, types, ttl, records);
95823c07
RG
393}
394
b7f378d1 395static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys)
8455425c
RG
396{
397 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(algo));
b7f378d1 398 dcke->create((algo <= 10) ? 2048 : dcke->getBits());
8455425c
RG
399 DNSSECPrivateKey dpk;
400 dpk.d_flags = 256;
401 dpk.setKey(dcke);
8455425c 402 DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest);
b7f378d1
RG
403 keys[name] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk,ds);
404}
405
406static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map<DNSName,dsmap_t>& dsAnchors)
407{
408 generateKeyMaterial(name, algo, digest, keys);
409 dsAnchors[name].insert(keys[name].second);
8455425c
RG
410}
411
f4de85a3 412static int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut=true)
5374b03b
RG
413{
414 if (type == QType::DS) {
415 auth.chopOff();
416
417 setLWResult(res, 0, true, false, true);
418
419 if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) {
420 addRRSIG(keys, res->d_records, auth, 300);
421 }
422 else {
423 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
424
425 /* if the auth zone is signed, we need to provide a secure denial */
426 const auto it = keys.find(auth);
427 if (it != keys.cend()) {
428 /* sign the SOA */
429 addRRSIG(keys, res->d_records, auth, 300);
430 /* add a NSEC denying the DS */
f4de85a3
RG
431 std::set<uint16_t> types = { QType::NSEC };
432 if (proveCut) {
433 types.insert(QType::NS);
434 }
435
436 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
5374b03b
RG
437 addRRSIG(keys, res->d_records, auth, 300);
438 }
439 }
440
441 return 1;
442 }
443
444 if (type == QType::DNSKEY) {
445 setLWResult(res, 0, true, false, true);
dbbef467
RG
446 addDNSKEY(keys, domain, 300, res->d_records);
447 addRRSIG(keys, res->d_records, domain, 300);
5374b03b
RG
448 return 1;
449 }
450
451 return 0;
452}
453
30ee601a
RG
454/* Real tests */
455
456BOOST_AUTO_TEST_SUITE(syncres_cc)
457
458BOOST_AUTO_TEST_CASE(test_root_primed) {
459 std::unique_ptr<SyncRes> sr;
895449a5 460 initSR(sr);
30ee601a
RG
461
462 primeHints();
895449a5 463
4d2be65d 464 const DNSName target("a.root-servers.net.");
30ee601a 465
4d2be65d 466 /* we are primed, we should be able to resolve A a.root-servers.net. without any query */
30ee601a 467 vector<DNSRecord> ret;
4d2be65d 468 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 469 BOOST_CHECK_EQUAL(res, RCode::NoError);
4d2be65d
RG
470 BOOST_REQUIRE_EQUAL(ret.size(), 1);
471 BOOST_CHECK(ret[0].d_type == QType::A);
472 BOOST_CHECK_EQUAL(ret[0].d_name, target);
473
474 ret.clear();
475 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1
RG
476 BOOST_CHECK_EQUAL(res, RCode::NoError);
477 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
4d2be65d
RG
478 BOOST_REQUIRE_EQUAL(ret.size(), 1);
479 BOOST_CHECK(ret[0].d_type == QType::AAAA);
480 BOOST_CHECK_EQUAL(ret[0].d_name, target);
4d2be65d
RG
481}
482
483BOOST_AUTO_TEST_CASE(test_root_primed_ns) {
484 std::unique_ptr<SyncRes> sr;
895449a5 485 initSR(sr);
4d2be65d
RG
486
487 primeHints();
488 const DNSName target(".");
489
490 /* we are primed, but we should not be able to NS . without any query
491 because the . NS entry is not stored as authoritative */
492
493 size_t queriesCount = 0;
494
0bd2e252 495 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
496 queriesCount++;
497
498 if (domain == target && type == QType::NS) {
499
500 setLWResult(res, 0, true, false, true);
8455425c 501 char addr[] = "a.root-servers.net.";
4d2be65d 502 for (char idx = 'a'; idx <= 'm'; idx++) {
8455425c
RG
503 addr[0] = idx;
504 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4d2be65d
RG
505 }
506
507 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
508 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
509
510 return 1;
511 }
512
513 return 0;
514 });
515
516 vector<DNSRecord> ret;
517 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1 518 BOOST_CHECK_EQUAL(res, RCode::NoError);
4d2be65d
RG
519 BOOST_REQUIRE_EQUAL(ret.size(), 13);
520 BOOST_CHECK_EQUAL(queriesCount, 1);
30ee601a
RG
521}
522
523BOOST_AUTO_TEST_CASE(test_root_not_primed) {
524 std::unique_ptr<SyncRes> sr;
895449a5 525 initSR(sr);
30ee601a
RG
526
527 size_t queriesCount = 0;
528
0bd2e252 529 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
530 queriesCount++;
531
532 if (domain == g_rootdnsname && type == QType::NS) {
533 setLWResult(res, 0, true, false, true);
534 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
535 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
536 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
537
538 return 1;
539 }
540
541 return 0;
542 });
543
544 /* we are not primed yet, so SyncRes will have to call primeHints()
545 then call getRootNS(), for which at least one of the root servers needs to answer */
546 vector<DNSRecord> ret;
547 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
b7f378d1 548 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
549 BOOST_CHECK_EQUAL(ret.size(), 1);
550 BOOST_CHECK_EQUAL(queriesCount, 2);
551}
552
553BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
554 std::unique_ptr<SyncRes> sr;
895449a5 555 initSR(sr);
30ee601a
RG
556 std::set<ComboAddress> downServers;
557
558 /* we are not primed yet, so SyncRes will have to call primeHints()
559 then call getRootNS(), for which at least one of the root servers needs to answer.
560 None will, so it should ServFail.
561 */
0bd2e252 562 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
563
564 downServers.insert(ip);
565 return 0;
566 });
567
568 vector<DNSRecord> ret;
569 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
f58c8379 570 BOOST_CHECK_EQUAL(res, RCode::ServFail);
30ee601a
RG
571 BOOST_CHECK_EQUAL(ret.size(), 0);
572 BOOST_CHECK(downServers.size() > 0);
573 /* we explicitly refuse to mark the root servers down */
574 for (const auto& server : downServers) {
a712cb56 575 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
30ee601a
RG
576 }
577}
578
579BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
580 std::unique_ptr<SyncRes> sr;
895449a5 581 initSR(sr);
30ee601a
RG
582
583 ComboAddress noEDNSServer;
584 size_t queriesWithEDNS = 0;
585 size_t queriesWithoutEDNS = 0;
586
0bd2e252 587 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
588 if (EDNS0Level != 0) {
589 queriesWithEDNS++;
590 noEDNSServer = ip;
591
592 setLWResult(res, RCode::FormErr);
593 return 1;
594 }
595
596 queriesWithoutEDNS++;
597
598 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
599 setLWResult(res, 0, true, false, false);
600 addRecordToLW(res, domain, QType::A, "192.0.2.1");
601 return 1;
602 }
603
604 return 0;
605 });
606
607 primeHints();
608
609 /* fake that the root NS doesn't handle EDNS, check that we fallback */
610 vector<DNSRecord> ret;
611 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 612 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
613 BOOST_CHECK_EQUAL(ret.size(), 1);
614 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
615 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
a712cb56
RG
616 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
617 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
30ee601a
RG
618}
619
30ee601a
RG
620BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
621 std::unique_ptr<SyncRes> sr;
895449a5 622 initSR(sr);
30ee601a 623
0bd2e252 624 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
625 if (!doTCP) {
626 setLWResult(res, 0, false, true, false);
627 return 1;
628 }
629 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
630 setLWResult(res, 0, true, false, false);
631 addRecordToLW(res, domain, QType::A, "192.0.2.1");
632 return 1;
633 }
634
635 return 0;
636 });
637
638 primeHints();
639
640 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
641 vector<DNSRecord> ret;
642 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 643 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
644}
645
3337c2f7
RG
646BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
647 std::unique_ptr<SyncRes> sr;
895449a5 648 initSR(sr);
3337c2f7
RG
649
650 size_t tcpQueriesCount = 0;
651
0bd2e252 652 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
653 if (!doTCP) {
654 setLWResult(res, 0, true, true, false);
655 return 1;
656 }
657
658 /* first TCP query is answered with a TC response */
659 tcpQueriesCount++;
660 if (tcpQueriesCount == 1) {
661 setLWResult(res, 0, true, true, false);
662 }
663 else {
664 setLWResult(res, 0, true, false, false);
665 }
666
667 addRecordToLW(res, domain, QType::A, "192.0.2.1");
668 return 1;
669 });
670
671 primeHints();
672
673 vector<DNSRecord> ret;
674 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 675 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
676 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
677}
678
30ee601a
RG
679BOOST_AUTO_TEST_CASE(test_all_nss_down) {
680 std::unique_ptr<SyncRes> sr;
895449a5 681 initSR(sr);
30ee601a
RG
682 std::set<ComboAddress> downServers;
683
684 primeHints();
685
0bd2e252 686 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
687
688 if (isRootServer(ip)) {
8455425c 689 setLWResult(res, 0, false, false, true);
30ee601a
RG
690 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
691 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
692 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
693 return 1;
694 }
695 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 696 setLWResult(res, 0, false, false, true);
30ee601a
RG
697 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
698 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
699 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
700 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
701 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
702 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
703 return 1;
704 }
705 else {
706 downServers.insert(ip);
707 return 0;
708 }
709 });
710
ccb07d93
RG
711 DNSName target("powerdns.com.");
712
30ee601a 713 vector<DNSRecord> ret;
ccb07d93 714 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 715 BOOST_CHECK_EQUAL(res, RCode::ServFail);
30ee601a
RG
716 BOOST_CHECK_EQUAL(ret.size(), 0);
717 BOOST_CHECK_EQUAL(downServers.size(), 4);
718
606accb0 719 time_t now = sr->getNow().tv_sec;
30ee601a 720 for (const auto& server : downServers) {
a712cb56 721 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
606accb0 722 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
30ee601a
RG
723 }
724}
725
648bcbd1
RG
726BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
727 std::unique_ptr<SyncRes> sr;
895449a5 728 initSR(sr);
648bcbd1
RG
729 std::set<ComboAddress> downServers;
730
731 primeHints();
732
0bd2e252 733 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
734
735 if (isRootServer(ip)) {
8455425c 736 setLWResult(res, 0, false, false, true);
648bcbd1
RG
737 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
738 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
739 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
740 return 1;
741 }
742 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 743 setLWResult(res, 0, false, false, true);
648bcbd1
RG
744 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
745 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
746 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
747 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
748 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
749 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
750 return 1;
751 }
752 else {
753 downServers.insert(ip);
b4c8789a 754 return 0;
648bcbd1
RG
755 }
756 });
757
758 /* exact same test than the previous one, except instead of a time out we fake a network error */
759 DNSName target("powerdns.com.");
760
761 vector<DNSRecord> ret;
762 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
763 BOOST_CHECK_EQUAL(res, RCode::ServFail);
764 BOOST_CHECK_EQUAL(ret.size(), 0);
765 BOOST_CHECK_EQUAL(downServers.size(), 4);
766
606accb0 767 time_t now = sr->getNow().tv_sec;
648bcbd1 768 for (const auto& server : downServers) {
a712cb56 769 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
606accb0 770 BOOST_CHECK(SyncRes::isThrottled(now, server, target, QType::A));
648bcbd1
RG
771 }
772}
773
b4c8789a
RG
774BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) {
775 std::unique_ptr<SyncRes> sr;
776 initSR(sr);
777
778 primeHints();
779
780 DNSName target("www.powerdns.com.");
781
0bd2e252 782 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
783
784 if (isRootServer(ip)) {
785 setLWResult(res, 0, false, false, true);
786 if (domain == target) {
787 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
788 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
789 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
790 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
791 }
792 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
793 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
794 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
795 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
796 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
797 }
798 return 1;
799 }
800 else if (ip == ComboAddress("192.0.2.3:53")) {
801 setLWResult(res, 0, true, false, true);
802 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
803 if (type == QType::A) {
804 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
805 }
806 else if (type == QType::AAAA) {
807 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
808 }
809 }
810 else if (domain == target) {
811 if (type == QType::A) {
812 addRecordToLW(res, domain, QType::A, "192.0.2.1");
813 }
814 else if (type == QType::AAAA) {
815 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
816 }
817 }
818 return 1;
819 }
820 return 0;
821 });
822
823 vector<DNSRecord> ret;
824 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
825 BOOST_CHECK_EQUAL(res, RCode::NoError);
826 BOOST_CHECK_EQUAL(ret.size(), 1);
827}
828
648bcbd1
RG
829BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
830 std::unique_ptr<SyncRes> sr;
895449a5 831 initSR(sr);
648bcbd1
RG
832 std::set<ComboAddress> downServers;
833
834 primeHints();
835
0bd2e252 836 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
837
838 if (isRootServer(ip)) {
8455425c 839 setLWResult(res, 0, false, false, true);
648bcbd1
RG
840 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
841 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
842 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
843 return 1;
844 }
845 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 846 setLWResult(res, 0, false, false, true);
648bcbd1
RG
847 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
848 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
849 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
850 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
851 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
852 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
853 return 1;
854 }
855 else {
856 if (downServers.size() < 3) {
857 /* only the last one will answer */
858 downServers.insert(ip);
859 return -2;
860 }
861 else {
862 setLWResult(res, 0, true, false, true);
863 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
864 return 1;
865 }
866 }
867 });
868
869 DNSName target("powerdns.com.");
870
871 vector<DNSRecord> ret;
872 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 873 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
874 BOOST_CHECK_EQUAL(ret.size(), 1);
875 BOOST_CHECK_EQUAL(downServers.size(), 3);
876
877 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
606accb0 878 time_t now = sr->getNow().tv_sec;
648bcbd1 879 for (const auto& server : downServers) {
a712cb56 880 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
606accb0 881 BOOST_CHECK(!SyncRes::isThrottled(now, server, target, QType::A));
648bcbd1
RG
882 }
883}
884
30ee601a
RG
885BOOST_AUTO_TEST_CASE(test_glued_referral) {
886 std::unique_ptr<SyncRes> sr;
895449a5 887 initSR(sr);
30ee601a
RG
888
889 primeHints();
890
891 const DNSName target("powerdns.com.");
892
0bd2e252 893 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
894 /* this will cause issue with qname minimization if we ever implement it */
895 if (domain != target) {
896 return 0;
897 }
898
899 if (isRootServer(ip)) {
8455425c 900 setLWResult(res, 0, false, false, true);
30ee601a
RG
901 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
902 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
903 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
904 return 1;
905 }
906 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 907 setLWResult(res, 0, false, false, true);
30ee601a
RG
908 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
909 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
910 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
911 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
912 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
913 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
914 return 1;
915 }
916 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")) {
917 setLWResult(res, 0, true, false, true);
918 addRecordToLW(res, target, QType::A, "192.0.2.4");
919 return 1;
920 }
921 else {
922 return 0;
923 }
924 });
925
926 vector<DNSRecord> ret;
927 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 928 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 929 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 930 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
931 BOOST_CHECK_EQUAL(ret[0].d_name, target);
932}
933
934BOOST_AUTO_TEST_CASE(test_glueless_referral) {
935 std::unique_ptr<SyncRes> sr;
895449a5 936 initSR(sr);
30ee601a
RG
937
938 primeHints();
939
940 const DNSName target("powerdns.com.");
941
0bd2e252 942 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
943
944 if (isRootServer(ip)) {
8455425c 945 setLWResult(res, 0, false, false, true);
30ee601a
RG
946
947 if (domain.isPartOf(DNSName("com."))) {
948 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
949 } else if (domain.isPartOf(DNSName("org."))) {
950 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
951 }
952 else {
953 setLWResult(res, RCode::NXDomain, false, false, true);
954 return 1;
955 }
956
957 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
958 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
959 return 1;
960 }
961 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
962 if (domain == target) {
8455425c 963 setLWResult(res, 0, false, false, true);
30ee601a
RG
964 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
965 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
966 return 1;
967 }
968 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
969 setLWResult(res, 0, true, false, true);
970 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
971 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
972 return 1;
973 }
974 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
975 setLWResult(res, 0, true, false, true);
976 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
977 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
978 return 1;
979 }
980
981 setLWResult(res, RCode::NXDomain, false, false, true);
982 return 1;
983 }
984 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")) {
985 setLWResult(res, 0, true, false, true);
986 addRecordToLW(res, target, QType::A, "192.0.2.4");
987 return 1;
988 }
989 else {
990 return 0;
991 }
992 });
993
994 vector<DNSRecord> ret;
995 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 996 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 997 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 998 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
999 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1000}
1001
e9f9b8ec
RG
1002BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
1003 std::unique_ptr<SyncRes> sr;
895449a5 1004 initSR(sr);
e9f9b8ec
RG
1005
1006 primeHints();
1007
1008 const DNSName target("powerdns.com.");
9065eb05 1009 SyncRes::addEDNSDomain(target);
e9f9b8ec
RG
1010
1011 EDNSSubnetOpts incomingECS;
1012 incomingECS.source = Netmask("192.0.2.128/32");
2fe3354d 1013 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
e9f9b8ec 1014
0bd2e252 1015 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
1016
1017 BOOST_REQUIRE(srcmask);
1018 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1019 return 0;
1020 });
1021
1022 vector<DNSRecord> ret;
1023 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 1024 BOOST_CHECK_EQUAL(res, RCode::ServFail);
e9f9b8ec
RG
1025}
1026
1027BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
1028 std::unique_ptr<SyncRes> sr;
895449a5 1029 initSR(sr);
e9f9b8ec
RG
1030
1031 primeHints();
1032
1033 const DNSName target("powerdns.com.");
2fe3354d 1034 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
e9f9b8ec
RG
1035
1036 EDNSSubnetOpts incomingECS;
1037 incomingECS.source = Netmask("2001:DB8::FF/128");
2fe3354d 1038 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
e9f9b8ec 1039
0bd2e252 1040 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
1041
1042 if (isRootServer(ip)) {
1043 BOOST_REQUIRE(!srcmask);
1044
8455425c 1045 setLWResult(res, 0, false, false, true);
e9f9b8ec
RG
1046 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1047 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1048 return 1;
1049 } else if (ip == ComboAddress("192.0.2.1:53")) {
1050
1051 BOOST_REQUIRE(srcmask);
1052 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1053
1054 setLWResult(res, 0, true, false, false);
1055 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1056 return 1;
1057 }
1058
1059 return 0;
1060 });
1061
1062 vector<DNSRecord> ret;
1063 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1064 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
1065 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1066 BOOST_CHECK(ret[0].d_type == QType::A);
1067 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1068}
1069
2fe3354d
CH
1070BOOST_AUTO_TEST_CASE(test_ecs_use_requestor) {
1071 std::unique_ptr<SyncRes> sr;
1072 initSR(sr);
1073
1074 primeHints();
1075
1076 const DNSName target("powerdns.com.");
1077 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1078 // No incoming ECS data
1079 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
1080
0bd2e252 1081 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
1082
1083 if (isRootServer(ip)) {
1084 BOOST_REQUIRE(!srcmask);
1085
1086 setLWResult(res, 0, false, false, true);
1087 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1088 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1089 return 1;
1090 } else if (ip == ComboAddress("192.0.2.1:53")) {
1091
1092 BOOST_REQUIRE(srcmask);
1093 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1094
1095 setLWResult(res, 0, true, false, false);
1096 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1097 return 1;
1098 }
1099
1100 return 0;
1101 });
1102
1103 vector<DNSRecord> ret;
1104 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1105 BOOST_CHECK_EQUAL(res, RCode::NoError);
1106 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1107 BOOST_CHECK(ret[0].d_type == QType::A);
1108 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1109}
1110
1111BOOST_AUTO_TEST_CASE(test_ecs_use_scope_zero) {
1112 std::unique_ptr<SyncRes> sr;
1113 initSR(sr);
1114
1115 primeHints();
1116
1117 const DNSName target("powerdns.com.");
1118 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1119 SyncRes::clearEDNSLocalSubnets();
1120 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1121 // No incoming ECS data, Requestor IP not in ecs-add-for
1122 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::none);
1123
0bd2e252 1124 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
1125
1126 if (isRootServer(ip)) {
1127 BOOST_REQUIRE(!srcmask);
1128
1129 setLWResult(res, 0, false, false, true);
1130 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1131 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1132 return 1;
1133 } else if (ip == ComboAddress("192.0.2.1:53")) {
1134
1135 BOOST_REQUIRE(srcmask);
1136 BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
1137
1138 setLWResult(res, 0, true, false, false);
1139 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1140 return 1;
1141 }
1142
1143 return 0;
1144 });
1145
1146 vector<DNSRecord> ret;
1147 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1148 BOOST_CHECK_EQUAL(res, RCode::NoError);
1149 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1150 BOOST_CHECK(ret[0].d_type == QType::A);
1151 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1152}
1153
1154BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask) {
1155 std::unique_ptr<SyncRes> sr;
1156 initSR(sr);
1157
1158 primeHints();
1159
1160 const DNSName target("powerdns.com.");
1161 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1162 SyncRes::clearEDNSLocalSubnets();
1163 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1164 EDNSSubnetOpts incomingECS;
1165 incomingECS.source = Netmask("192.0.0.0/16");
1166 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1167
0bd2e252 1168 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
1169
1170 if (isRootServer(ip)) {
1171 BOOST_REQUIRE(!srcmask);
1172
1173 setLWResult(res, 0, false, false, true);
1174 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1175 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1176 return 1;
1177 } else if (ip == ComboAddress("192.0.2.1:53")) {
1178
1179 BOOST_REQUIRE(srcmask);
1180 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.0.0/16");
1181
1182 setLWResult(res, 0, true, false, false);
1183 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1184 return 1;
1185 }
1186
1187 return 0;
1188 });
1189
1190 vector<DNSRecord> ret;
1191 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1192 BOOST_CHECK_EQUAL(res, RCode::NoError);
1193 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1194 BOOST_CHECK(ret[0].d_type == QType::A);
1195 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1196}
1197
1198BOOST_AUTO_TEST_CASE(test_ecs_honor_incoming_mask_zero) {
1199 std::unique_ptr<SyncRes> sr;
1200 initSR(sr);
1201
1202 primeHints();
1203
1204 const DNSName target("powerdns.com.");
1205 SyncRes::addEDNSRemoteSubnet("192.0.2.1/32");
1206 SyncRes::clearEDNSLocalSubnets();
1207 SyncRes::addEDNSLocalSubnet("192.0.2.254/32");
1208 EDNSSubnetOpts incomingECS;
1209 incomingECS.source = Netmask("0.0.0.0/0");
1210 sr->setQuerySource(ComboAddress("192.0.2.127"), boost::optional<const EDNSSubnetOpts&>(incomingECS));
1211
0bd2e252 1212 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
1213
1214 if (isRootServer(ip)) {
1215 BOOST_REQUIRE(!srcmask);
1216
1217 setLWResult(res, 0, false, false, true);
1218 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1219 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1220 return 1;
1221 } else if (ip == ComboAddress("192.0.2.1:53")) {
1222
1223 BOOST_REQUIRE(srcmask);
1224 BOOST_CHECK_EQUAL(srcmask->toString(), "127.0.0.1/32");
1225
1226 setLWResult(res, 0, true, false, false);
1227 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1228 return 1;
1229 }
1230
1231 return 0;
1232 });
1233
1234 vector<DNSRecord> ret;
1235 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1236 BOOST_CHECK_EQUAL(res, RCode::NoError);
1237 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1238 BOOST_CHECK(ret[0].d_type == QType::A);
1239 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1240}
1241
778bcea6
RG
1242BOOST_AUTO_TEST_CASE(test_following_cname) {
1243 std::unique_ptr<SyncRes> sr;
895449a5 1244 initSR(sr);
778bcea6
RG
1245
1246 primeHints();
1247
1248 const DNSName target("cname.powerdns.com.");
1249 const DNSName cnameTarget("cname-target.powerdns.com");
1250
0bd2e252 1251 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
1252
1253 if (isRootServer(ip)) {
8455425c 1254 setLWResult(res, 0, false, false, true);
778bcea6
RG
1255 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1256 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1257 return 1;
1258 } else if (ip == ComboAddress("192.0.2.1:53")) {
1259
1260 if (domain == target) {
1261 setLWResult(res, 0, true, false, false);
1262 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1263 return 1;
1264 }
1265 else if (domain == cnameTarget) {
1266 setLWResult(res, 0, true, false, false);
1267 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1268 }
1269
1270 return 1;
1271 }
1272
1273 return 0;
1274 });
1275
1276 vector<DNSRecord> ret;
1277 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1278 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
1279 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1280 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1281 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1282 BOOST_CHECK(ret[1].d_type == QType::A);
1283 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1284}
1285
9b061cf5
RG
1286BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
1287 std::unique_ptr<SyncRes> sr;
1288 initSR(sr);
1289
1290 primeHints();
1291
1292 const DNSName target("cname.powerdns.com.");
1293 const DNSName cnameTarget("cname-target.powerdns.com");
1294
0bd2e252 1295 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
1296
1297 if (isRootServer(ip)) {
1298 setLWResult(res, 0, false, false, true);
1299 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1300 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1301 return 1;
1302 } else if (ip == ComboAddress("192.0.2.1:53")) {
1303
1304 if (domain == target) {
1305 setLWResult(res, RCode::NXDomain, true, false, false);
1306 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1307 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1308 } else if (domain == cnameTarget) {
1309 setLWResult(res, RCode::NXDomain, true, false, false);
1310 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1311 return 1;
1312 }
1313
1314 return 1;
1315 }
1316
1317 return 0;
1318 });
1319
1320 vector<DNSRecord> ret;
1321 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1322 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1323 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1324 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1325 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1326 BOOST_CHECK(ret[1].d_type == QType::SOA);
1327
1328 /* a second time, to check the cache */
1329 ret.clear();
1330 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1331 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1332 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1333 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1334 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1335 BOOST_CHECK(ret[1].d_type == QType::SOA);
1336}
1337
4fff116b
RG
1338BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1339 std::unique_ptr<SyncRes> sr;
895449a5 1340 initSR(sr);
4fff116b
RG
1341
1342 primeHints();
1343
1344 /* In this test we directly get the NS server for cname.powerdns.com.,
1345 and we don't know whether it's also authoritative for
1346 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1347 the additional A record for cname-target.powerdns.com. */
1348 const DNSName target("cname.powerdns.com.");
1349 const DNSName cnameTarget("cname-target.powerdns.com");
1350
0bd2e252 1351 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
1352
1353 if (isRootServer(ip)) {
1354
8455425c 1355 setLWResult(res, 0, false, false, true);
4fff116b
RG
1356
1357 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1358 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1359 return 1;
1360 } else if (ip == ComboAddress("192.0.2.1:53")) {
1361
1362 if (domain == target) {
1363 setLWResult(res, 0, true, false, false);
1364 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1365 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1366 return 1;
1367 } else if (domain == cnameTarget) {
1368 setLWResult(res, 0, true, false, false);
1369 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1370 return 1;
1371 }
1372
1373 return 1;
1374 }
1375
1376 return 0;
1377 });
1378
1379 vector<DNSRecord> ret;
1380 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1381 BOOST_CHECK_EQUAL(res, RCode::NoError);
4fff116b
RG
1382 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1383 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1384 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1385 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1386 BOOST_REQUIRE(ret[1].d_type == QType::A);
1387 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1388 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1389}
1390
778bcea6
RG
1391BOOST_AUTO_TEST_CASE(test_cname_loop) {
1392 std::unique_ptr<SyncRes> sr;
895449a5 1393 initSR(sr);
778bcea6
RG
1394
1395 primeHints();
1396
1397 size_t count = 0;
1398 const DNSName target("cname.powerdns.com.");
1399
0bd2e252 1400 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
1401
1402 count++;
1403
1404 if (isRootServer(ip)) {
778bcea6 1405
8455425c 1406 setLWResult(res, 0, false, false, true);
778bcea6
RG
1407 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1408 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1409 return 1;
1410 } else if (ip == ComboAddress("192.0.2.1:53")) {
1411
1412 if (domain == target) {
1413 setLWResult(res, 0, true, false, false);
1414 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1415 return 1;
1416 }
1417
1418 return 1;
1419 }
1420
1421 return 0;
1422 });
1423
1424 vector<DNSRecord> ret;
1425 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1426 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1427 BOOST_CHECK_GT(ret.size(), 0);
778bcea6 1428 BOOST_CHECK_EQUAL(count, 2);
e9f9b8ec
RG
1429}
1430
4fff116b
RG
1431BOOST_AUTO_TEST_CASE(test_cname_depth) {
1432 std::unique_ptr<SyncRes> sr;
895449a5 1433 initSR(sr);
4fff116b
RG
1434
1435 primeHints();
1436
1437 size_t depth = 0;
1438 const DNSName target("cname.powerdns.com.");
1439
0bd2e252 1440 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
1441
1442 if (isRootServer(ip)) {
4fff116b 1443
8455425c 1444 setLWResult(res, 0, false, false, true);
4fff116b
RG
1445 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1446 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1447 return 1;
1448 } else if (ip == ComboAddress("192.0.2.1:53")) {
1449
1450 setLWResult(res, 0, true, false, false);
1451 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1452 depth++;
1453 return 1;
1454 }
1455
1456 return 0;
1457 });
1458
1459 vector<DNSRecord> ret;
1460 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1461 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1462 BOOST_CHECK_EQUAL(ret.size(), depth);
4fff116b
RG
1463 /* we have an arbitrary limit at 10 when following a CNAME chain */
1464 BOOST_CHECK_EQUAL(depth, 10 + 2);
1465}
1466
d6e797b8
RG
1467BOOST_AUTO_TEST_CASE(test_time_limit) {
1468 std::unique_ptr<SyncRes> sr;
895449a5 1469 initSR(sr);
d6e797b8
RG
1470
1471 primeHints();
1472
1473 size_t queries = 0;
1474 const DNSName target("cname.powerdns.com.");
1475
0bd2e252 1476 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
1477
1478 queries++;
1479
1480 if (isRootServer(ip)) {
8455425c 1481 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1482 /* Pretend that this query took 2000 ms */
1483 res->d_usec = 2000;
1484
1485 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1486 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1487 return 1;
1488 } else if (ip == ComboAddress("192.0.2.1:53")) {
1489
1490 setLWResult(res, 0, true, false, false);
1491 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1492 return 1;
1493 }
1494
1495 return 0;
1496 });
1497
1498 /* Set the maximum time to 1 ms */
1499 SyncRes::s_maxtotusec = 1000;
1500
1501 try {
1502 vector<DNSRecord> ret;
1503 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1504 BOOST_CHECK(false);
1505 }
1506 catch(const ImmediateServFailException& e) {
1507 }
1508 BOOST_CHECK_EQUAL(queries, 1);
1509}
1510
1511BOOST_AUTO_TEST_CASE(test_referral_depth) {
1512 std::unique_ptr<SyncRes> sr;
895449a5 1513 initSR(sr);
d6e797b8
RG
1514
1515 primeHints();
1516
1517 size_t queries = 0;
1518 const DNSName target("www.powerdns.com.");
1519
0bd2e252 1520 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
1521
1522 queries++;
1523
1524 if (isRootServer(ip)) {
8455425c 1525 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1526
1527 if (domain == DNSName("www.powerdns.com.")) {
1528 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1529 }
1530 else if (domain == DNSName("ns.powerdns.com.")) {
1531 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1532 }
1533 else if (domain == DNSName("ns1.powerdns.org.")) {
1534 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1535 }
1536 else if (domain == DNSName("ns2.powerdns.org.")) {
1537 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1538 }
1539 else if (domain == DNSName("ns3.powerdns.org.")) {
1540 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1541 }
1542 else if (domain == DNSName("ns4.powerdns.org.")) {
1543 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1544 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1545 }
1546
1547 return 1;
1548 } else if (ip == ComboAddress("192.0.2.1:53")) {
1549
1550 setLWResult(res, 0, true, false, false);
1551 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1552 return 1;
1553 }
1554
1555 return 0;
1556 });
1557
1558 /* Set the maximum depth low */
1559 SyncRes::s_maxdepth = 10;
1560
1561 try {
1562 vector<DNSRecord> ret;
1563 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1564 BOOST_CHECK(false);
1565 }
1566 catch(const ImmediateServFailException& e) {
1567 }
1568}
1569
1570BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1571 std::unique_ptr<SyncRes> sr;
895449a5 1572 initSR(sr);
d6e797b8
RG
1573
1574 primeHints();
1575
1576 size_t queries = 0;
1577 const DNSName target("cname.powerdns.com.");
1578
0bd2e252 1579 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
1580
1581 queries++;
1582
1583 if (isRootServer(ip)) {
1584
8455425c 1585 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1586 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1587 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1588 return 1;
1589 } else if (ip == ComboAddress("192.0.2.1:53")) {
1590
1591 setLWResult(res, 0, true, false, false);
1592 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1593 return 1;
1594 }
1595
1596 return 0;
1597 });
1598
1599 /* Set the maximum number of questions very low */
1600 SyncRes::s_maxqperq = 5;
1601
1602 try {
1603 vector<DNSRecord> ret;
1604 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1605 BOOST_CHECK(false);
1606 }
1607 catch(const ImmediateServFailException& e) {
1608 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1609 }
1610}
1611
ccb07d93
RG
1612BOOST_AUTO_TEST_CASE(test_throttled_server) {
1613 std::unique_ptr<SyncRes> sr;
895449a5 1614 initSR(sr);
ccb07d93
RG
1615
1616 primeHints();
1617
1618 const DNSName target("throttled.powerdns.com.");
1619 const ComboAddress ns("192.0.2.1:53");
1620 size_t queriesToNS = 0;
1621
0bd2e252 1622 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
1623
1624 if (isRootServer(ip)) {
ccb07d93 1625
8455425c 1626 setLWResult(res, 0, false, false, true);
ccb07d93
RG
1627 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1628 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1629 return 1;
1630 } else if (ip == ns) {
1631
1632 queriesToNS++;
1633
1634 setLWResult(res, 0, true, false, false);
1635 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1636
1637 return 1;
1638 }
1639
1640 return 0;
1641 });
1642
1643 /* mark ns as down */
606accb0
RG
1644 time_t now = sr->getNow().tv_sec;
1645 SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, 10000);
ccb07d93
RG
1646
1647 vector<DNSRecord> ret;
1648 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1649 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1650 BOOST_CHECK_EQUAL(ret.size(), 0);
1651 /* we should not have sent any queries to ns */
ccb07d93
RG
1652 BOOST_CHECK_EQUAL(queriesToNS, 0);
1653}
1654
1655BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1656 std::unique_ptr<SyncRes> sr;
895449a5 1657 initSR(sr);
ccb07d93
RG
1658
1659 primeHints();
1660
1661 const ComboAddress ns("192.0.2.1:53");
1662
1663 const size_t blocks = 10;
1664 /* mark ns as down for 'blocks' queries */
606accb0
RG
1665 time_t now = sr->getNow().tv_sec;
1666 SyncRes::doThrottle(now, ns, SyncRes::s_serverdownthrottletime, blocks);
ccb07d93
RG
1667
1668 for (size_t idx = 0; idx < blocks; idx++) {
606accb0 1669 BOOST_CHECK(SyncRes::isThrottled(now, ns));
ccb07d93
RG
1670 }
1671
1672 /* we have been throttled 'blocks' times, we should not be throttled anymore */
606accb0 1673 BOOST_CHECK(!SyncRes::isThrottled(now, ns));
ccb07d93
RG
1674}
1675
1676BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1677 std::unique_ptr<SyncRes> sr;
895449a5 1678 initSR(sr);
ccb07d93
RG
1679
1680 primeHints();
1681
1682 const ComboAddress ns("192.0.2.1:53");
1683
1684 const size_t seconds = 1;
1685 /* mark ns as down for 'seconds' seconds */
606accb0
RG
1686 time_t now = sr->getNow().tv_sec;
1687 SyncRes::doThrottle(now, ns, seconds, 10000);
a712cb56 1688
606accb0 1689 BOOST_CHECK(SyncRes::isThrottled(now, ns));
ccb07d93
RG
1690
1691 /* we should not be throttled anymore */
606accb0 1692 BOOST_CHECK(!SyncRes::isThrottled(now + 2, ns));
ccb07d93
RG
1693}
1694
f58c8379
RG
1695BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1696 std::unique_ptr<SyncRes> sr;
895449a5 1697 initSR(sr);
f58c8379
RG
1698
1699 primeHints();
1700
1701 const DNSName target("throttled.powerdns.com.");
1702 const ComboAddress ns("192.0.2.1:53");
1703 size_t queriesToNS = 0;
1704
0bd2e252 1705 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
1706
1707 if (isRootServer(ip)) {
1708
8455425c 1709 setLWResult(res, 0, false, false, true);
f58c8379
RG
1710 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1711 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1712 return 1;
1713 } else if (ip == ns) {
1714
1715 queriesToNS++;
1716
1717 setLWResult(res, 0, true, false, false);
1718 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1719
1720 return 1;
1721 }
1722
1723 return 0;
1724 });
1725
1726 /* prevent querying this NS */
9065eb05 1727 SyncRes::addDontQuery(Netmask(ns));
f58c8379
RG
1728
1729 vector<DNSRecord> ret;
1730 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1731 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1732 BOOST_CHECK_EQUAL(ret.size(), 0);
1733 /* we should not have sent any queries to ns */
1734 BOOST_CHECK_EQUAL(queriesToNS, 0);
1735}
1736
1737BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1738 std::unique_ptr<SyncRes> sr;
895449a5 1739 initSR(sr);
f58c8379
RG
1740
1741 primeHints();
1742
1743 const DNSName target1("powerdns.com.");
1744 const DNSName target2("notpowerdns.com.");
1745 const ComboAddress ns("192.0.2.1:53");
1746 size_t queriesCount = 0;
1747
0bd2e252 1748 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
1749
1750 queriesCount++;
1751
1752 if (isRootServer(ip)) {
1753
1754 if (domain == target1) {
1755 setLWResult(res, RCode::NXDomain, true, false, true);
1756 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1757 }
1758 else {
1759 setLWResult(res, 0, true, false, true);
1760 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1761 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1762 }
1763
1764 return 1;
1765 } else if (ip == ns) {
1766
1767 setLWResult(res, 0, true, false, false);
1768 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1769
1770 return 1;
1771 }
1772
1773 return 0;
1774 });
1775
1776 vector<DNSRecord> ret;
1777 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1778 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1779 BOOST_CHECK_EQUAL(ret.size(), 1);
1780 /* one for target1 and one for the entire TLD */
a712cb56 1781 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1782
1783 ret.clear();
1784 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1785 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1786 BOOST_CHECK_EQUAL(ret.size(), 1);
1787 /* one for target1 and one for the entire TLD */
a712cb56 1788 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1789
1790 /* we should have sent only one query */
1791 BOOST_CHECK_EQUAL(queriesCount, 1);
1792}
1793
898856ca
RG
1794BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1795 std::unique_ptr<SyncRes> sr;
1796 init();
1797 initSR(sr, true, false);
1798
1799 primeHints();
1800
1801 const DNSName target1("powerdns.com.");
1802 const DNSName target2("notpowerdns.com.");
1803 const ComboAddress ns("192.0.2.1:53");
1804 size_t queriesCount = 0;
1805
1806 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1807 We should add target1 to the negcache, but not "com.". */
1808
0bd2e252 1809 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
1810
1811 queriesCount++;
1812
1813 if (isRootServer(ip)) {
1814
1815 if (domain == target1) {
1816 setLWResult(res, RCode::NXDomain, true, false, true);
1817 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1818 }
1819 else {
1820 setLWResult(res, 0, true, false, true);
1821 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1822 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1823 }
1824
1825 return 1;
1826 } else if (ip == ns) {
1827
1828 setLWResult(res, 0, true, false, false);
1829 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1830
1831 return 1;
1832 }
1833
1834 return 0;
1835 });
1836
1837 vector<DNSRecord> ret;
1838 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1839 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1840 BOOST_CHECK_EQUAL(ret.size(), 1);
1841
1842 /* even with root-nx-trust on and a NX answer from the root,
1843 we should not have cached the entire TLD this time. */
a712cb56 1844 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1845
1846 ret.clear();
1847 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1848 BOOST_CHECK_EQUAL(res, RCode::NoError);
1849 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1850 BOOST_REQUIRE(ret[0].d_type == QType::A);
1851 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1852 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1853
a712cb56 1854 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1855
1856 BOOST_CHECK_EQUAL(queriesCount, 3);
1857}
1858
f58c8379
RG
1859BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1860 std::unique_ptr<SyncRes> sr;
895449a5 1861 initSR(sr);
f58c8379
RG
1862
1863 primeHints();
1864
1865 const DNSName target1("powerdns.com.");
1866 const DNSName target2("notpowerdns.com.");
1867 const ComboAddress ns("192.0.2.1:53");
1868 size_t queriesCount = 0;
1869
0bd2e252 1870 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
1871
1872 queriesCount++;
1873
1874 if (isRootServer(ip)) {
1875
1876 if (domain == target1) {
1877 setLWResult(res, RCode::NXDomain, true, false, true);
1878 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1879 }
1880 else {
1881 setLWResult(res, 0, true, false, true);
1882 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1883 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1884 }
1885
1886 return 1;
1887 } else if (ip == ns) {
1888
1889 setLWResult(res, 0, true, false, false);
1890 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1891
1892 return 1;
1893 }
1894
1895 return 0;
1896 });
1897
1898 SyncRes::s_rootNXTrust = false;
1899
1900 vector<DNSRecord> ret;
1901 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1902 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1903 BOOST_CHECK_EQUAL(ret.size(), 1);
1904 /* one for target1 */
a712cb56 1905 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1906
1907 ret.clear();
1908 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
b7f378d1 1909 BOOST_CHECK_EQUAL(res, RCode::NoError);
f58c8379
RG
1910 BOOST_CHECK_EQUAL(ret.size(), 1);
1911 /* one for target1 */
a712cb56 1912 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1913
1914 /* we should have sent three queries */
1915 BOOST_CHECK_EQUAL(queriesCount, 3);
1916}
1917
1918BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1919 std::unique_ptr<SyncRes> sr;
895449a5 1920 initSR(sr);
f58c8379
RG
1921
1922 primeHints();
1923
1924 const DNSName target("www.powerdns.com.");
1925 const DNSName cnameTarget("cname.powerdns.com.");
1926
9065eb05 1927 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
f58c8379
RG
1928
1929 EDNSSubnetOpts incomingECS;
1930 incomingECS.source = Netmask("192.0.2.128/32");
2fe3354d 1931 sr->setQuerySource(ComboAddress(), boost::optional<const EDNSSubnetOpts&>(incomingECS));
f58c8379 1932
0bd2e252 1933 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
1934
1935 BOOST_REQUIRE(srcmask);
1936 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1937
1938 if (isRootServer(ip)) {
8455425c 1939 setLWResult(res, 0, false, false, true);
f58c8379
RG
1940 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1941 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1942
1943 return 1;
1944 } else if (ip == ComboAddress("192.0.2.1:53")) {
1945 if (domain == target) {
1946 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
1947 setLWResult(res, RCode::NXDomain, true, false, true);
1948 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1949 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1950 }
1951 else if (domain == cnameTarget) {
1952 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
1953 but we might if we still chase the CNAME. */
1954 setLWResult(res, RCode::NXDomain, true, false, true);
1955 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1956 }
1957
1958 return 1;
1959 }
1960
1961 return 0;
1962 });
1963
1964 vector<DNSRecord> ret;
1965 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1966 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1967 BOOST_CHECK_EQUAL(ret.size(), 2);
1968 /* no negative cache entry because the response was variable */
a712cb56 1969 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
f58c8379
RG
1970}
1971
d6e797b8
RG
1972BOOST_AUTO_TEST_CASE(test_ns_speed) {
1973 std::unique_ptr<SyncRes> sr;
895449a5 1974 initSR(sr);
30ee601a 1975
d6e797b8 1976 primeHints();
30ee601a 1977
d6e797b8 1978 const DNSName target("powerdns.com.");
30ee601a 1979
d6e797b8 1980 std::map<ComboAddress, uint64_t> nsCounts;
30ee601a 1981
0bd2e252 1982 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 1983
d6e797b8 1984 if (isRootServer(ip)) {
8455425c 1985 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1986 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1987 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1988 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
30ee601a 1989
d6e797b8
RG
1990 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1991 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1992 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1993 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
1994 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
1995 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
30ee601a 1996
d6e797b8
RG
1997 return 1;
1998 } else {
1999 nsCounts[ip]++;
30ee601a 2000
d6e797b8
RG
2001 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
2002 BOOST_CHECK_LT(nsCounts.size(), 3);
2003
2004 /* let's time out on pdns-public-ns2.powerdns.com. */
2005 return 0;
2006 }
2007 else if (ip == ComboAddress("192.0.2.1:53")) {
2008 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
2009
2010 setLWResult(res, 0, true, false, true);
2011 addRecordToLW(res, domain, QType::A, "192.0.2.254");
2012 return 1;
2013 }
2014
2015 return 0;
2016 }
30ee601a 2017
d6e797b8
RG
2018 return 0;
2019 });
30ee601a 2020
606accb0 2021 struct timeval now = sr->getNow();
30ee601a 2022
d6e797b8
RG
2023 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
2024 then pdns-public-ns1.powerdns.com. on IPv4 */
a712cb56
RG
2025 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
2026 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
2027 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
2028 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
2029 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
2030 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
30ee601a 2031
d6e797b8
RG
2032 vector<DNSRecord> ret;
2033 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2034 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2035 BOOST_CHECK_EQUAL(ret.size(), 1);
2036 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
2037 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
2038 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
2039 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
2040}
30ee601a 2041
d6e797b8
RG
2042BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
2043 std::unique_ptr<SyncRes> sr;
895449a5 2044 initSR(sr);
30ee601a 2045
d6e797b8 2046 primeHints();
30ee601a 2047
d6e797b8 2048 const DNSName target("powerdns.com.");
30ee601a 2049
0bd2e252 2050 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
2051
2052 if (isRootServer(ip)) {
8455425c 2053 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2054 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2055
2056 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2057
2058 return 1;
2059 } else if (ip == ComboAddress("192.0.2.1:53")) {
2060 setLWResult(res, 0, true, false, true);
2061 addRecordToLW(res, domain, QType::A, "192.0.2.254");
2062 return 1;
2063 }
2064
2065 return 0;
2066 });
2067
2068 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
a66eacd6 2069 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2070 std::vector<DNSRecord> records;
2071 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2072 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
2073
2b984251 2074 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2075
2076 vector<DNSRecord> ret;
2077 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2078 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2079 BOOST_CHECK_EQUAL(ret.size(), 1);
2080}
2081
3337c2f7
RG
2082BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
2083 std::unique_ptr<SyncRes> sr;
895449a5 2084 initSR(sr);
3337c2f7
RG
2085
2086 primeHints();
2087
2088 const DNSName target("powerdns.com.");
2089 size_t queriesCount = 0;
2090
0bd2e252 2091 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
2092
2093 queriesCount++;
2094
2095 if (isRootServer(ip) && domain == target) {
8455425c 2096 setLWResult(res, 0, false, false, true);
3337c2f7
RG
2097 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2098 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2099 return 1;
2100 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
2101 setLWResult(res, 0, true, false, true);
2102 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2103 return 1;
2104 }
2105
2106 return 0;
2107 });
2108
2109 vector<DNSRecord> ret;
2110 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2111 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2112 BOOST_CHECK_EQUAL(ret.size(), 0);
2113 /* one query to get NSs, then A and AAAA for each NS */
2114 BOOST_CHECK_EQUAL(queriesCount, 5);
2115}
2116
d6e797b8
RG
2117BOOST_AUTO_TEST_CASE(test_cache_hit) {
2118 std::unique_ptr<SyncRes> sr;
895449a5 2119 initSR(sr);
d6e797b8
RG
2120
2121 primeHints();
2122
2123 const DNSName target("powerdns.com.");
2124
0bd2e252 2125 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
2126
2127 return 0;
2128 });
2129
2130 /* we populate the cache with eveything we need */
a66eacd6 2131 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2132 std::vector<DNSRecord> records;
2133 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2134
2135 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
2b984251 2136 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2137
2138 vector<DNSRecord> ret;
2139 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2140 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2141 BOOST_CHECK_EQUAL(ret.size(), 1);
2142}
2143
648bcbd1
RG
2144BOOST_AUTO_TEST_CASE(test_no_rd) {
2145 std::unique_ptr<SyncRes> sr;
895449a5 2146 initSR(sr);
648bcbd1
RG
2147
2148 primeHints();
2149
2150 const DNSName target("powerdns.com.");
2151 size_t queriesCount = 0;
2152
2153 sr->setCacheOnly();
2154
0bd2e252 2155 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
2156
2157 queriesCount++;
2158 return 0;
2159 });
2160
2161 vector<DNSRecord> ret;
2162 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2163 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2164 BOOST_CHECK_EQUAL(ret.size(), 0);
2165 BOOST_CHECK_EQUAL(queriesCount, 0);
2166}
2167
d6e797b8
RG
2168BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
2169 std::unique_ptr<SyncRes> sr;
895449a5 2170 initSR(sr);
d6e797b8
RG
2171
2172 primeHints();
2173
2174 const DNSName target("cachettl.powerdns.com.");
2175 const ComboAddress ns("192.0.2.1:53");
2176
0bd2e252 2177 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
2178
2179 if (isRootServer(ip)) {
2180
8455425c 2181 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2182 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2183 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
2184 return 1;
2185 } else if (ip == ns) {
2186
2187 setLWResult(res, 0, true, false, false);
2188 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2189
2190 return 1;
2191 }
2192
2193 return 0;
2194 });
2195
a66eacd6 2196 const time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2197 SyncRes::s_minimumTTL = 60;
2198 SyncRes::s_maxcachettl = 3600;
2199
2200 vector<DNSRecord> ret;
2201 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2202 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2203 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2204 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
2205
2206 const ComboAddress who;
2207 vector<DNSRecord> cached;
24bb9b58 2208 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
d6e797b8
RG
2209 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2210 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2211 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
2212
2213 cached.clear();
24bb9b58 2214 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
d6e797b8
RG
2215 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2216 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2217 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
2218}
2219
2220BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
2221 std::unique_ptr<SyncRes> sr;
895449a5 2222 initSR(sr);
d6e797b8
RG
2223
2224 primeHints();
2225
2226 const DNSName target("powerdns.com.");
2227
0bd2e252 2228 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
2229
2230 if (isRootServer(ip)) {
8455425c 2231 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2232 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2233
2234 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2235
2236 return 1;
2237 } else if (ip == ComboAddress("192.0.2.1:53")) {
2238 setLWResult(res, 0, true, false, true);
2239 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2240 return 1;
2241 }
2242
2243 return 0;
2244 });
2245
2246 /* we populate the cache with entries that expired 60s ago*/
129e658f
RG
2247 const time_t now = sr->getNow().tv_sec;
2248
d6e797b8
RG
2249 std::vector<DNSRecord> records;
2250 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2251 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
2252
2b984251 2253 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2254
2255 vector<DNSRecord> ret;
2256 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2257 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2258 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2259 BOOST_REQUIRE(ret[0].d_type == QType::A);
2260 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
2261}
2262
129e658f
RG
2263BOOST_AUTO_TEST_CASE(test_cache_auth) {
2264 std::unique_ptr<SyncRes> sr;
2265 initSR(sr);
2266
2267 primeHints();
2268
2269 /* the auth server is sending the same answer in answer and additional,
2270 check that we only return one result, and we only cache one too. */
2271 const DNSName target("cache-auth.powerdns.com.");
2272
0bd2e252 2273 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
2274
2275 setLWResult(res, 0, true, false, true);
2276 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2277 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 10);
2278
2279 return 1;
2280 });
2281
2282 const time_t now = sr->getNow().tv_sec;
2283
2284 vector<DNSRecord> ret;
2285 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2286 BOOST_CHECK_EQUAL(res, RCode::NoError);
2287 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2288 BOOST_REQUIRE_EQUAL(QType(ret.at(0).d_type).getName(), QType(QType::A).getName());
2289 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2290
2291 /* check that we correctly cached only the answer entry, not the additional one */
2292 const ComboAddress who;
2293 vector<DNSRecord> cached;
2294 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
2295 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2296 BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).getName(), QType(QType::A).getName());
2297 BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
2298}
2299
d6e797b8
RG
2300BOOST_AUTO_TEST_CASE(test_delegation_only) {
2301 std::unique_ptr<SyncRes> sr;
895449a5 2302 initSR(sr);
d6e797b8
RG
2303
2304 primeHints();
2305
2306 /* Thanks, Verisign */
9065eb05
RG
2307 SyncRes::addDelegationOnly(DNSName("com."));
2308 SyncRes::addDelegationOnly(DNSName("net."));
d6e797b8
RG
2309
2310 const DNSName target("nx-powerdns.com.");
2311
0bd2e252 2312 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult* res, bool* chained) {
d6e797b8
RG
2313
2314 if (isRootServer(ip)) {
8455425c 2315 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2316 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2317 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2318 return 1;
2319 } else if (ip == ComboAddress("192.0.2.1:53")) {
2320
2321 setLWResult(res, 0, true, false, true);
2322 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2323 return 1;
2324 }
2325
2326 return 0;
2327 });
2328
2329 vector<DNSRecord> ret;
2330 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2331 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2332 BOOST_CHECK_EQUAL(ret.size(), 0);
2333}
2334
2335BOOST_AUTO_TEST_CASE(test_unauth_any) {
2336 std::unique_ptr<SyncRes> sr;
895449a5 2337 initSR(sr);
d6e797b8
RG
2338
2339 primeHints();
2340
2341 const DNSName target("powerdns.com.");
2342
0bd2e252 2343 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
2344
2345 if (isRootServer(ip)) {
8455425c 2346 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2347 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2348 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2349 return 1;
2350 } else if (ip == ComboAddress("192.0.2.1:53")) {
2351
2352 setLWResult(res, 0, false, false, true);
2353 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2354 return 1;
2355 }
2356
2357 return 0;
2358 });
2359
2360 vector<DNSRecord> ret;
2361 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2362 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2363 BOOST_CHECK_EQUAL(ret.size(), 0);
2364}
2365
2366BOOST_AUTO_TEST_CASE(test_no_data) {
2367 std::unique_ptr<SyncRes> sr;
895449a5 2368 initSR(sr);
d6e797b8
RG
2369
2370 primeHints();
2371
2372 const DNSName target("powerdns.com.");
2373
0bd2e252 2374 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
2375
2376 setLWResult(res, 0, true, false, true);
2377 return 1;
2378 });
2379
2380 vector<DNSRecord> ret;
2381 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2382 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2383 BOOST_CHECK_EQUAL(ret.size(), 0);
2384}
2385
2386BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2387 std::unique_ptr<SyncRes> sr;
895449a5 2388 initSR(sr);
d6e797b8
RG
2389
2390 primeHints();
2391
2392 const DNSName target("powerdns.com.");
2393
0bd2e252 2394 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
2395
2396 setLWResult(res, 0, true, false, true);
2397 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2398 addRecordToLW(res, domain, QType::ANY, "0 0");
2399 addRecordToLW(res, domain, QType::OPT, "");
2400 return 1;
2401 });
2402
2403 vector<DNSRecord> ret;
2404 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2405 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2406 BOOST_CHECK_EQUAL(ret.size(), 1);
2407}
2408
2409BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2410 std::unique_ptr<SyncRes> sr;
895449a5 2411 initSR(sr);
d6e797b8
RG
2412
2413 primeHints();
2414
2415 const DNSName target("powerdns.com.");
2416
0bd2e252 2417 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
2418
2419 setLWResult(res, 0, true, false, true);
2420 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2421 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2422 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2423 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2424 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2425 return 1;
2426 });
2427
2428 vector<DNSRecord> ret;
2429 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2430 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2431 BOOST_CHECK_EQUAL(ret.size(), 1);
2432}
2433
2434BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2435 std::unique_ptr<SyncRes> sr;
895449a5 2436 initSR(sr, true);
d6e797b8
RG
2437
2438 primeHints();
2439
2440 const DNSName target("powerdns.com.");
2441
0bd2e252 2442 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
2443
2444 setLWResult(res, 0, true, false, true);
2445 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2446 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2447 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2448 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2449 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2450 return 1;
2451 });
2452
2453 vector<DNSRecord> ret;
2454 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2455 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2456 BOOST_CHECK_EQUAL(ret.size(), 4);
2457}
2458
2459BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2460 std::unique_ptr<SyncRes> sr;
895449a5 2461 initSR(sr);
d6e797b8
RG
2462
2463 primeHints();
2464
2465 const DNSName target("powerdns.com.");
2466
0bd2e252 2467 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
2468
2469 setLWResult(res, RCode::NXDomain, true, false, true);
2470 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2471 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2472 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2473 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2474 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2475 return 1;
2476 });
2477
2478 vector<DNSRecord> ret;
2479 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2480 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2481 BOOST_CHECK_EQUAL(ret.size(), 1);
2482}
2483
2484BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2485 std::unique_ptr<SyncRes> sr;
895449a5 2486 initSR(sr, true);
d6e797b8
RG
2487
2488 primeHints();
2489
2490 const DNSName target("powerdns.com.");
2491
0bd2e252 2492 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
2493
2494 setLWResult(res, RCode::NXDomain, true, false, true);
2495 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2496 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2497 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2498 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2499 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2500 return 1;
2501 });
2502
2503 vector<DNSRecord> ret;
2504 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2505 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2506 BOOST_CHECK_EQUAL(ret.size(), 4);
2507}
2508
648bcbd1
RG
2509BOOST_AUTO_TEST_CASE(test_qclass_none) {
2510 std::unique_ptr<SyncRes> sr;
895449a5 2511 initSR(sr);
648bcbd1
RG
2512
2513 primeHints();
2514
2515 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2516 size_t queriesCount = 0;
2517
0bd2e252 2518 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
2519
2520 queriesCount++;
2521 return 0;
2522 });
2523
2524 const DNSName target("powerdns.com.");
2525 vector<DNSRecord> ret;
2526 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2527 BOOST_CHECK_EQUAL(res, -1);
2528 BOOST_CHECK_EQUAL(ret.size(), 0);
2529 BOOST_CHECK_EQUAL(queriesCount, 0);
2530}
2531
1f03b691 2532BOOST_AUTO_TEST_CASE(test_special_types) {
648bcbd1 2533 std::unique_ptr<SyncRes> sr;
895449a5 2534 initSR(sr);
648bcbd1
RG
2535
2536 primeHints();
2537
1f03b691 2538 /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
648bcbd1
RG
2539 size_t queriesCount = 0;
2540
0bd2e252 2541 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
2542
2543 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2544 queriesCount++;
2545 return 0;
2546 });
2547
2548 const DNSName target("powerdns.com.");
2549 vector<DNSRecord> ret;
2550 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2551 BOOST_CHECK_EQUAL(res, -1);
2552 BOOST_CHECK_EQUAL(ret.size(), 0);
2553 BOOST_CHECK_EQUAL(queriesCount, 0);
2554
2555 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2556 BOOST_CHECK_EQUAL(res, -1);
2557 BOOST_CHECK_EQUAL(ret.size(), 0);
2558 BOOST_CHECK_EQUAL(queriesCount, 0);
1f03b691
RG
2559
2560 res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2561 BOOST_CHECK_EQUAL(res, -1);
2562 BOOST_CHECK_EQUAL(ret.size(), 0);
2563 BOOST_CHECK_EQUAL(queriesCount, 0);
2564
2565 res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
648bcbd1
RG
2566 BOOST_CHECK_EQUAL(res, -1);
2567 BOOST_CHECK_EQUAL(ret.size(), 0);
2568 BOOST_CHECK_EQUAL(queriesCount, 0);
2569}
2570
2571BOOST_AUTO_TEST_CASE(test_special_names) {
2572 std::unique_ptr<SyncRes> sr;
895449a5 2573 initSR(sr);
648bcbd1
RG
2574
2575 primeHints();
2576
2577 /* special names should be handled internally */
2578
2579 size_t queriesCount = 0;
2580
0bd2e252 2581 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
2582
2583 queriesCount++;
2584 return 0;
2585 });
2586
2587 vector<DNSRecord> ret;
2588 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
b7f378d1 2589 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2590 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2591 BOOST_CHECK(ret[0].d_type == QType::PTR);
2592 BOOST_CHECK_EQUAL(queriesCount, 0);
2593
2594 ret.clear();
2595 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2596 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2597 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2598 BOOST_CHECK(ret[0].d_type == QType::PTR);
2599 BOOST_CHECK_EQUAL(queriesCount, 0);
2600
2601 ret.clear();
2602 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 2603 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2604 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2605 BOOST_CHECK(ret[0].d_type == QType::PTR);
2606 BOOST_CHECK_EQUAL(queriesCount, 0);
2607
2608 ret.clear();
2609 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 2610 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2611 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2612 BOOST_CHECK(ret[0].d_type == QType::PTR);
2613 BOOST_CHECK_EQUAL(queriesCount, 0);
2614
2615 ret.clear();
2616 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
b7f378d1 2617 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2618 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2619 BOOST_CHECK(ret[0].d_type == QType::A);
2620 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2621 BOOST_CHECK_EQUAL(queriesCount, 0);
2622
2623 ret.clear();
2624 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
b7f378d1 2625 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2626 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2627 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2628 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2629 BOOST_CHECK_EQUAL(queriesCount, 0);
2630
2631 ret.clear();
2632 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2633 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2634 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2635 for (const auto& rec : ret) {
2636 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2637 if (rec.d_type == QType::A) {
2638 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2639 }
2640 else {
2641 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2642 }
2643 }
2644 BOOST_CHECK_EQUAL(queriesCount, 0);
2645
2646 ret.clear();
2647 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2648 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2649 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2650 BOOST_CHECK(ret[0].d_type == QType::TXT);
2651 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2652 BOOST_CHECK_EQUAL(queriesCount, 0);
2653
2654 ret.clear();
2655 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2656 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2657 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2658 BOOST_CHECK(ret[0].d_type == QType::TXT);
2659 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2660 BOOST_CHECK_EQUAL(queriesCount, 0);
2661
2662 ret.clear();
2663 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2664 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2665 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2666 BOOST_CHECK(ret[0].d_type == QType::TXT);
2667 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2668 BOOST_CHECK_EQUAL(queriesCount, 0);
2669
2670 ret.clear();
2671 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2672 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2673 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2674 BOOST_CHECK(ret[0].d_type == QType::TXT);
2675 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2676 BOOST_CHECK_EQUAL(queriesCount, 0);
2677
2678 ret.clear();
2679 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2680 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2681 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2682 BOOST_CHECK(ret[0].d_type == QType::TXT);
2683 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2684 BOOST_CHECK_EQUAL(queriesCount, 0);
2685
2686 ret.clear();
2687 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2688 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2689 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2690 BOOST_CHECK(ret[0].d_type == QType::TXT);
2691 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2692 BOOST_CHECK_EQUAL(queriesCount, 0);
2693}
2694
2695BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2696 std::unique_ptr<SyncRes> sr;
895449a5 2697 initSR(sr);
648bcbd1
RG
2698
2699 primeHints();
2700
2701 const DNSName target("rpz.powerdns.com.");
2702 const ComboAddress ns("192.0.2.1:53");
2703
0bd2e252 2704 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
2705
2706 if (isRootServer(ip)) {
8455425c 2707 setLWResult(res, false, true, false, true);
648bcbd1
RG
2708 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2709 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2710 return 1;
2711 } else if (ip == ns) {
2712
2713 setLWResult(res, 0, true, false, true);
2714 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2715 return 1;
2716 }
2717
2718 return 0;
2719 });
2720
2721 DNSFilterEngine::Policy pol;
2722 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2723 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2724 zone->setName("Unit test policy 0");
2725 zone->addNSIPTrigger(Netmask(ns, 32), pol);
648bcbd1 2726 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2727 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2728 g_luaconfs.setState(luaconfsCopy);
2729
2730 vector<DNSRecord> ret;
2731 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2732 BOOST_CHECK_EQUAL(res, -2);
2733 BOOST_CHECK_EQUAL(ret.size(), 0);
2734}
2735
2736BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2737 std::unique_ptr<SyncRes> sr;
895449a5 2738 initSR(sr);
648bcbd1
RG
2739
2740 primeHints();
2741
2742 const DNSName target("rpz.powerdns.com.");
2743 const ComboAddress ns("[2001:DB8::42]:53");
2744
0bd2e252 2745 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
2746
2747 if (isRootServer(ip)) {
8455425c 2748 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2749 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2750 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2751 return 1;
2752 } else if (ip == ns) {
2753
2754 setLWResult(res, 0, true, false, true);
2755 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2756 return 1;
2757 }
2758
2759 return 0;
2760 });
2761
2762 DNSFilterEngine::Policy pol;
2763 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2764 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2765 zone->setName("Unit test policy 0");
2766 zone->addNSIPTrigger(Netmask(ns, 128), pol);
648bcbd1 2767 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2768 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2769 g_luaconfs.setState(luaconfsCopy);
2770
2771 vector<DNSRecord> ret;
2772 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2773 BOOST_CHECK_EQUAL(res, -2);
2774 BOOST_CHECK_EQUAL(ret.size(), 0);
2775}
2776
2777BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2778 std::unique_ptr<SyncRes> sr;
895449a5 2779 initSR(sr);
648bcbd1
RG
2780
2781 primeHints();
2782
2783 const DNSName target("rpz.powerdns.com.");
2784 const ComboAddress ns("192.0.2.1:53");
2785 const DNSName nsName("ns1.powerdns.com.");
2786
0bd2e252 2787 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
2788
2789 if (isRootServer(ip)) {
8455425c 2790 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2791 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2792 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2793 return 1;
2794 } else if (ip == ns) {
2795
2796 setLWResult(res, 0, true, false, true);
2797 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2798 return 1;
2799 }
2800
2801 return 0;
2802 });
2803
2804 DNSFilterEngine::Policy pol;
2805 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2806 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2807 zone->setName("Unit test policy 0");
2808 zone->addNSTrigger(nsName, pol);
648bcbd1 2809 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2810 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2811 g_luaconfs.setState(luaconfsCopy);
2812
2813 vector<DNSRecord> ret;
2814 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2815 BOOST_CHECK_EQUAL(res, -2);
2816 BOOST_CHECK_EQUAL(ret.size(), 0);
2817}
2818
2819BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2820 std::unique_ptr<SyncRes> sr;
895449a5 2821 initSR(sr);
648bcbd1
RG
2822
2823 primeHints();
2824
2825 const DNSName target("rpz.powerdns.com.");
2826 const ComboAddress ns("192.0.2.1:53");
2827 const DNSName nsName("ns1.powerdns.com.");
2828
0bd2e252 2829 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
2830
2831 if (isRootServer(ip)) {
8455425c 2832 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2833 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2834 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2835 return 1;
2836 } else if (ip == ns) {
2837
2838 setLWResult(res, 0, true, false, true);
2839 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2840 return 1;
2841 }
2842
2843 return 0;
2844 });
2845
2846 DNSFilterEngine::Policy pol;
2847 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2848 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2849 zone->setName("Unit test policy 0");
2850 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2851 zone->addNSTrigger(nsName, pol);
648bcbd1 2852 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2853 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2854 g_luaconfs.setState(luaconfsCopy);
2855
2856 /* RPZ is disabled for this query, we should not be blocked */
2857 sr->setWantsRPZ(false);
2858
2859 vector<DNSRecord> ret;
2860 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2861 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2862 BOOST_CHECK_EQUAL(ret.size(), 1);
2863}
2864
3e59ff53
RG
2865BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2866 std::unique_ptr<SyncRes> sr;
895449a5 2867 initSR(sr);
3e59ff53
RG
2868
2869 primeHints();
2870
2871 const DNSName target("powerdns.com.");
2872 const ComboAddress ns("192.0.2.1:53");
2873 const ComboAddress forwardedNS("192.0.2.42:53");
2874
2875 SyncRes::AuthDomain ad;
2876 ad.d_rdForward = false;
2877 ad.d_servers.push_back(forwardedNS);
a712cb56 2878 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2879
0bd2e252 2880 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
2881
2882 if (ip == forwardedNS) {
6dfff36f
RG
2883 BOOST_CHECK_EQUAL(sendRDQuery, false);
2884
3e59ff53
RG
2885 setLWResult(res, 0, true, false, true);
2886 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2887 return 1;
2888 }
2889
2890 return 0;
2891 });
2892
2893 /* simulate a no-RD query */
2894 sr->setCacheOnly();
2895
2896 vector<DNSRecord> ret;
2897 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2898 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2899 BOOST_CHECK_EQUAL(ret.size(), 1);
2900}
2901
2902BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
2903 std::unique_ptr<SyncRes> sr;
895449a5 2904 initSR(sr);
3e59ff53
RG
2905
2906 primeHints();
2907
2908 const DNSName target("powerdns.com.");
2909 const ComboAddress ns("192.0.2.1:53");
2910 const ComboAddress forwardedNS("192.0.2.42:53");
2911
ad797d94 2912 size_t queriesCount = 0;
3e59ff53 2913 SyncRes::AuthDomain ad;
ad797d94 2914 ad.d_rdForward = true;
3e59ff53 2915 ad.d_servers.push_back(forwardedNS);
a712cb56 2916 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2917
0bd2e252 2918 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
2919
2920 queriesCount++;
3e59ff53
RG
2921
2922 if (ip == forwardedNS) {
ad797d94 2923 BOOST_CHECK_EQUAL(sendRDQuery, true);
6dfff36f 2924
ad797d94
RG
2925 /* set AA=0, we are a recursor */
2926 setLWResult(res, 0, false, false, true);
3e59ff53
RG
2927 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2928 return 1;
2929 }
2930
2931 return 0;
2932 });
2933
2934 vector<DNSRecord> ret;
2935 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2936 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53 2937 BOOST_CHECK_EQUAL(ret.size(), 1);
ad797d94
RG
2938 BOOST_CHECK_EQUAL(queriesCount, 1);
2939
2940 /* now make sure we can resolve from the cache (see #6340
2941 where the entries were added to the cache but not retrieved,
2942 because the recursor doesn't set the AA bit and we require
2943 it. We fixed it by not requiring the AA bit for forward-recurse
2944 answers. */
2945 ret.clear();
2946 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2947 BOOST_CHECK_EQUAL(res, RCode::NoError);
2948 BOOST_CHECK_EQUAL(ret.size(), 1);
2949 BOOST_CHECK_EQUAL(queriesCount, 1);
3e59ff53
RG
2950}
2951
2952BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
2953 std::unique_ptr<SyncRes> sr;
895449a5 2954 initSR(sr);
3e59ff53
RG
2955
2956 primeHints();
2957
2958 const DNSName target("powerdns.com.");
2959 const ComboAddress ns("192.0.2.1:53");
2960 const ComboAddress forwardedNS("192.0.2.42:53");
2961
2962 SyncRes::AuthDomain ad;
2963 ad.d_rdForward = true;
2964 ad.d_servers.push_back(forwardedNS);
a712cb56 2965 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2966
0bd2e252 2967 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
2968
2969 if (ip == forwardedNS) {
6dfff36f
RG
2970 BOOST_CHECK_EQUAL(sendRDQuery, false);
2971
3e59ff53
RG
2972 setLWResult(res, 0, true, false, true);
2973 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2974 return 1;
2975 }
2976
2977 return 0;
2978 });
2979
2980 /* simulate a no-RD query */
2981 sr->setCacheOnly();
2982
2983 vector<DNSRecord> ret;
2984 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2985 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2986 BOOST_CHECK_EQUAL(ret.size(), 1);
2987}
2988
2989BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
2990 std::unique_ptr<SyncRes> sr;
895449a5 2991 initSR(sr);
3e59ff53
RG
2992
2993 primeHints();
2994
2995 const DNSName target("powerdns.com.");
2996 const ComboAddress ns("192.0.2.1:53");
2997 const ComboAddress forwardedNS("192.0.2.42:53");
2998
2999 SyncRes::AuthDomain ad;
3000 ad.d_rdForward = true;
3001 ad.d_servers.push_back(forwardedNS);
a712cb56 3002 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 3003
0bd2e252 3004 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
3005
3006 if (ip == forwardedNS) {
6dfff36f
RG
3007 BOOST_CHECK_EQUAL(sendRDQuery, true);
3008
3e59ff53
RG
3009 setLWResult(res, 0, true, false, true);
3010 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3011 return 1;
3012 }
3013
3014 return 0;
3015 });
3016
3017 vector<DNSRecord> ret;
3018 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3019 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
3020 BOOST_CHECK_EQUAL(ret.size(), 1);
3021}
3022
e1636f82 3023BOOST_AUTO_TEST_CASE(test_auth_zone_oob) {
f79a4e30 3024 std::unique_ptr<SyncRes> sr;
e1636f82 3025 initSR(sr, true);
f79a4e30
RG
3026
3027 primeHints();
3028
3029 size_t queriesCount = 0;
3030 const DNSName target("test.xx.");
3031 const ComboAddress targetAddr("127.0.0.1");
f79a4e30
RG
3032 const DNSName authZone("test.xx");
3033
3034 SyncRes::AuthDomain ad;
3035 DNSRecord dr;
f79a4e30
RG
3036
3037 dr.d_place = DNSResourceRecord::ANSWER;
e1636f82 3038 dr.d_name = target;
f79a4e30
RG
3039 dr.d_type = QType::A;
3040 dr.d_ttl = 1800;
e1636f82 3041 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
f79a4e30
RG
3042 ad.d_records.insert(dr);
3043
a712cb56 3044 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
f79a4e30 3045
0bd2e252 3046 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
3047 queriesCount++;
3048 return 0;
3049 });
3050
3051 vector<DNSRecord> ret;
3052 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3053 BOOST_CHECK_EQUAL(res, 0);
3054 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3055 BOOST_CHECK(ret[0].d_type == QType::A);
3056 BOOST_CHECK_EQUAL(queriesCount, 0);
3057 BOOST_CHECK(sr->wasOutOfBand());
e1636f82 3058 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
3059
3060 /* a second time, to check that the OOB flag is set when the query cache is used */
3061 ret.clear();
3062 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3063 BOOST_CHECK_EQUAL(res, 0);
3064 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3065 BOOST_CHECK(ret[0].d_type == QType::A);
3066 BOOST_CHECK_EQUAL(queriesCount, 0);
3067 BOOST_CHECK(sr->wasOutOfBand());
e1636f82
RG
3068 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3069
3070 /* a third time, to check that the validation is disabled when the OOB flag is set */
3071 ret.clear();
3072 sr->setDNSSECValidationRequested(true);
3073 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3074 BOOST_CHECK_EQUAL(res, 0);
3075 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3076 BOOST_CHECK(ret[0].d_type == QType::A);
3077 BOOST_CHECK_EQUAL(queriesCount, 0);
3078 BOOST_CHECK(sr->wasOutOfBand());
3079 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3080}
3081
3082BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) {
3083 std::unique_ptr<SyncRes> sr;
3084 initSR(sr, true);
3085
3086 primeHints();
3087
3088 size_t queriesCount = 0;
3089 const DNSName target("cname.test.xx.");
3090 const DNSName targetCname("cname-target.test.xx.");
3091 const ComboAddress targetCnameAddr("127.0.0.1");
3092 const DNSName authZone("test.xx");
3093
3094 SyncRes::AuthDomain ad;
3095 DNSRecord dr;
3096
3097 dr.d_place = DNSResourceRecord::ANSWER;
3098 dr.d_name = target;
3099 dr.d_type = QType::CNAME;
3100 dr.d_ttl = 1800;
3101 dr.d_content = std::make_shared<CNAMERecordContent>(targetCname);
3102 ad.d_records.insert(dr);
3103
3104 dr.d_place = DNSResourceRecord::ANSWER;
3105 dr.d_name = targetCname;
3106 dr.d_type = QType::A;
3107 dr.d_ttl = 1800;
3108 dr.d_content = std::make_shared<ARecordContent>(targetCnameAddr);
3109 ad.d_records.insert(dr);
3110
3111 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
3112
0bd2e252 3113 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
3114 queriesCount++;
3115 return 0;
3116 });
3117
3118 vector<DNSRecord> ret;
3119 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3120 BOOST_CHECK_EQUAL(res, 0);
3121 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3122 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3123 BOOST_CHECK(ret[1].d_type == QType::A);
3124 BOOST_CHECK_EQUAL(queriesCount, 0);
3125 BOOST_CHECK(sr->wasOutOfBand());
3126 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3127
3128 /* a second time, to check that the OOB flag is set when the query cache is used */
3129 ret.clear();
3130 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3131 BOOST_CHECK_EQUAL(res, 0);
3132 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3133 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3134 BOOST_CHECK(ret[1].d_type == QType::A);
3135 BOOST_CHECK_EQUAL(queriesCount, 0);
3136 BOOST_CHECK(sr->wasOutOfBand());
3137 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3138
3139 /* a third time, to check that the validation is disabled when the OOB flag is set */
3140 ret.clear();
3141 sr->setDNSSECValidationRequested(true);
3142 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3143 BOOST_CHECK_EQUAL(res, 0);
3144 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3145 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3146 BOOST_CHECK(ret[1].d_type == QType::A);
3147 BOOST_CHECK_EQUAL(queriesCount, 0);
3148 BOOST_CHECK(sr->wasOutOfBand());
3149 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
3150}
3151
3337c2f7
RG
3152BOOST_AUTO_TEST_CASE(test_auth_zone) {
3153 std::unique_ptr<SyncRes> sr;
895449a5 3154 initSR(sr);
3337c2f7
RG
3155
3156 primeHints();
3157
3158 size_t queriesCount = 0;
3159 const DNSName target("powerdns.com.");
3160 const ComboAddress addr("192.0.2.5");
3161
3162 SyncRes::AuthDomain ad;
3163 ad.d_name = target;
3164 DNSRecord dr;
3165 dr.d_place = DNSResourceRecord::ANSWER;
3166 dr.d_name = target;
3167 dr.d_type = QType::SOA;
3168 dr.d_ttl = 3600;
3169 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3170 ad.d_records.insert(dr);
3171
3172 dr.d_place = DNSResourceRecord::ANSWER;
3173 dr.d_name = target;
3174 dr.d_type = QType::A;
3175 dr.d_ttl = 3600;
3176 dr.d_content = std::make_shared<ARecordContent>(addr);
3177 ad.d_records.insert(dr);
3178
3179 auto map = std::make_shared<SyncRes::domainmap_t>();
3180 (*map)[target] = ad;
3181 SyncRes::setDomainMap(map);
3182
0bd2e252 3183 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
3184
3185 queriesCount++;
3186 setLWResult(res, 0, true, false, true);
3187 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3188 return 1;
3189 });
3190
3191 vector<DNSRecord> ret;
3192 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3193 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3194 BOOST_CHECK_EQUAL(ret.size(), 1);
3195 BOOST_CHECK(ret[0].d_type == QType::A);
3196 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3197 BOOST_CHECK_EQUAL(queriesCount, 0);
3198}
3199
3200BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
3201 std::unique_ptr<SyncRes> sr;
895449a5 3202 initSR(sr);
3337c2f7
RG
3203
3204 primeHints();
3205
3206 size_t queriesCount = 0;
3207 const DNSName target("powerdns.com.");
3208 const DNSName authZone("internal.powerdns.com.");
3209 const ComboAddress addr("192.0.2.5");
3210
3211 SyncRes::AuthDomain ad;
3212 ad.d_name = authZone;
3213 DNSRecord dr;
3214 dr.d_place = DNSResourceRecord::ANSWER;
3215 dr.d_name = authZone;
3216 dr.d_type = QType::SOA;
3217 dr.d_ttl = 3600;
3218 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3219 ad.d_records.insert(dr);
3220
3221 dr.d_place = DNSResourceRecord::ANSWER;
3222 dr.d_name = authZone;
3223 dr.d_type = QType::A;
3224 dr.d_ttl = 3600;
3225 dr.d_content = std::make_shared<ARecordContent>(addr);
3226 ad.d_records.insert(dr);
3227
3228 auto map = std::make_shared<SyncRes::domainmap_t>();
3229 (*map)[authZone] = ad;
3230 SyncRes::setDomainMap(map);
3231
0bd2e252 3232 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
3233
3234 queriesCount++;
3235
3236 if (domain == target) {
3237 setLWResult(res, 0, true, false, true);
3238 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
3239 return 1;
3240 }
3241
3242 return 0;
3243 });
3244
3245 vector<DNSRecord> ret;
3246 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3247 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3248 BOOST_CHECK_EQUAL(ret.size(), 2);
3249 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3250 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
3251 BOOST_CHECK(ret[1].d_type == QType::A);
3252 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3253 BOOST_CHECK_EQUAL(queriesCount, 1);
3254}
3255
3256BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
3257 std::unique_ptr<SyncRes> sr;
895449a5 3258 initSR(sr);
3337c2f7
RG
3259
3260 primeHints();
3261
3262 size_t queriesCount = 0;
3263 const DNSName target("powerdns.com.");
3264 const DNSName externalCNAME("www.open-xchange.com.");
3265 const ComboAddress addr("192.0.2.5");
3266
3267 SyncRes::AuthDomain ad;
3268 ad.d_name = target;
3269 DNSRecord dr;
3270 dr.d_place = DNSResourceRecord::ANSWER;
3271 dr.d_name = target;
3272 dr.d_type = QType::SOA;
3273 dr.d_ttl = 3600;
3274 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3275 ad.d_records.insert(dr);
3276
3277 dr.d_place = DNSResourceRecord::ANSWER;
3278 dr.d_name = target;
3279 dr.d_type = QType::CNAME;
3280 dr.d_ttl = 3600;
3281 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
3282 ad.d_records.insert(dr);
3283
3284 auto map = std::make_shared<SyncRes::domainmap_t>();
3285 (*map)[target] = ad;
3286 SyncRes::setDomainMap(map);
3287
0bd2e252 3288 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
3289
3290 queriesCount++;
3291
3292 if (domain == externalCNAME) {
3293 setLWResult(res, 0, true, false, true);
3294 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
3295 return 1;
3296 }
3297
3298 return 0;
3299 });
3300
3301 vector<DNSRecord> ret;
3302 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3303 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3304 BOOST_CHECK_EQUAL(ret.size(), 2);
3305 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3306 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
3307 BOOST_CHECK(ret[1].d_type == QType::A);
3308 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3309 BOOST_CHECK_EQUAL(queriesCount, 1);
3310}
3311
3312BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
3313 std::unique_ptr<SyncRes> sr;
895449a5 3314 initSR(sr);
3337c2f7
RG
3315
3316 primeHints();
3317
3318 size_t queriesCount = 0;
3319 const DNSName target("nodata.powerdns.com.");
3320 const DNSName authZone("powerdns.com");
3321
3322 SyncRes::AuthDomain ad;
3323 ad.d_name = authZone;
3324 DNSRecord dr;
3325 dr.d_place = DNSResourceRecord::ANSWER;
3326 dr.d_name = target;
3327 dr.d_type = QType::A;
3328 dr.d_ttl = 3600;
3329 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3330 ad.d_records.insert(dr);
3331
3332 dr.d_place = DNSResourceRecord::ANSWER;
3333 dr.d_name = authZone;
3334 dr.d_type = QType::SOA;
3335 dr.d_ttl = 3600;
3336 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3337 ad.d_records.insert(dr);
3338
3339 auto map = std::make_shared<SyncRes::domainmap_t>();
3340 (*map)[authZone] = ad;
3341 SyncRes::setDomainMap(map);
3342
0bd2e252 3343 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
3344
3345 queriesCount++;
3346
3347 return 0;
3348 });
3349
3350 vector<DNSRecord> ret;
3351 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3352 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3353 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3354 BOOST_CHECK(ret[0].d_type == QType::SOA);
3355 BOOST_CHECK_EQUAL(queriesCount, 0);
3356}
3357
3358BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3359 std::unique_ptr<SyncRes> sr;
895449a5 3360 initSR(sr);
3337c2f7
RG
3361
3362 primeHints();
3363
3364 size_t queriesCount = 0;
3365 const DNSName target("nx.powerdns.com.");
3366 const DNSName authZone("powerdns.com");
3367
3368 SyncRes::AuthDomain ad;
3369 ad.d_name = authZone;
3370 DNSRecord dr;
3371 dr.d_place = DNSResourceRecord::ANSWER;
3372 dr.d_name = DNSName("powerdns.com.");
3373 dr.d_type = QType::SOA;
3374 dr.d_ttl = 3600;
3375 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3376 ad.d_records.insert(dr);
3377
3378 auto map = std::make_shared<SyncRes::domainmap_t>();
3379 (*map)[authZone] = ad;
3380 SyncRes::setDomainMap(map);
3381
0bd2e252 3382 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
3383
3384 queriesCount++;
3385
3386 return 0;
3387 });
3388
3389 vector<DNSRecord> ret;
3390 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3391 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3392 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3393 BOOST_CHECK(ret[0].d_type == QType::SOA);
3394 BOOST_CHECK_EQUAL(queriesCount, 0);
3395}
3396
3397BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3398 std::unique_ptr<SyncRes> sr;
e1636f82 3399 initSR(sr, true, false);
3337c2f7
RG
3400
3401 primeHints();
3402
3403 size_t queriesCount = 0;
3404 const DNSName target("www.test.powerdns.com.");
3405 const ComboAddress targetAddr("192.0.2.2");
3406 const DNSName ns("ns1.test.powerdns.com.");
3407 const ComboAddress nsAddr("192.0.2.1");
3408 const DNSName authZone("powerdns.com");
3409
3410 SyncRes::AuthDomain ad;
3411 ad.d_name = authZone;
3412 DNSRecord dr;
3413 dr.d_place = DNSResourceRecord::ANSWER;
3414 dr.d_name = authZone;
3415 dr.d_type = QType::SOA;
3416 dr.d_ttl = 3600;
3417 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3418 ad.d_records.insert(dr);
3419
3420 dr.d_place = DNSResourceRecord::ANSWER;
3421 dr.d_name = DNSName("test.powerdns.com.");
3422 dr.d_type = QType::NS;
3423 dr.d_ttl = 3600;
3424 dr.d_content = std::make_shared<NSRecordContent>(ns);
3425 ad.d_records.insert(dr);
3426
3427 dr.d_place = DNSResourceRecord::ANSWER;
3428 dr.d_name = ns;
3429 dr.d_type = QType::A;
3430 dr.d_ttl = 3600;
3431 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3432 ad.d_records.insert(dr);
3433
3434 auto map = std::make_shared<SyncRes::domainmap_t>();
3435 (*map)[authZone] = ad;
3436 SyncRes::setDomainMap(map);
3437
e1636f82
RG
3438 testkeysset_t keys;
3439 auto luaconfsCopy = g_luaconfs.getCopy();
3440 luaconfsCopy.dsAnchors.clear();
3441 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3442 g_luaconfs.setState(luaconfsCopy);
3443
0bd2e252 3444 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
3445
3446 queriesCount++;
e1636f82
RG
3447 if (type == QType::DS || type == QType::DNSKEY) {
3448 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone);
3449 }
3450
3337c2f7
RG
3451 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3452 setLWResult(res, 0, true, false, true);
3453 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3454 return 1;
3455 }
3456
3457 return 0;
3458 });
3459
e1636f82 3460 sr->setDNSSECValidationRequested(true);
3337c2f7
RG
3461 vector<DNSRecord> ret;
3462 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3463 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3464 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3465 BOOST_CHECK(ret[0].d_type == QType::A);
e1636f82
RG
3466 BOOST_CHECK_EQUAL(queriesCount, 4);
3467 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3337c2f7
RG
3468}
3469
3470BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3471 std::unique_ptr<SyncRes> sr;
895449a5 3472 initSR(sr);
3337c2f7
RG
3473
3474 primeHints();
3475
3476 size_t queriesCount = 0;
3477 const DNSName target("test.powerdns.com.");
3478 const ComboAddress targetAddr("192.0.2.2");
3479 const DNSName ns("ns1.test.powerdns.com.");
3480 const ComboAddress nsAddr("192.0.2.1");
3481 const DNSName authZone("powerdns.com");
3482
3483 SyncRes::AuthDomain ad;
3484 ad.d_name = authZone;
3485 DNSRecord dr;
3486 dr.d_place = DNSResourceRecord::ANSWER;
3487 dr.d_name = authZone;
3488 dr.d_type = QType::SOA;
3489 dr.d_ttl = 3600;
3490 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3491 ad.d_records.insert(dr);
3492
3493 dr.d_place = DNSResourceRecord::ANSWER;
3494 dr.d_name = DNSName("test.powerdns.com.");
3495 dr.d_type = QType::NS;
3496 dr.d_ttl = 3600;
3497 dr.d_content = std::make_shared<NSRecordContent>(ns);
3498 ad.d_records.insert(dr);
3499
3500 dr.d_place = DNSResourceRecord::ANSWER;
3501 dr.d_name = ns;
3502 dr.d_type = QType::A;
3503 dr.d_ttl = 3600;
3504 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3505 ad.d_records.insert(dr);
3506
3507 auto map = std::make_shared<SyncRes::domainmap_t>();
3508 (*map)[authZone] = ad;
3509 SyncRes::setDomainMap(map);
3510
0bd2e252 3511 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
3512
3513 queriesCount++;
3514
3515 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3516 setLWResult(res, 0, true, false, true);
3517 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3518 return 1;
3519 }
3520
3521 return 0;
3522 });
3523
3524 vector<DNSRecord> ret;
3525 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3526 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3527 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3528 BOOST_CHECK(ret[0].d_type == QType::A);
3529 BOOST_CHECK_EQUAL(queriesCount, 1);
3530}
3531
3532BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3533 std::unique_ptr<SyncRes> sr;
895449a5 3534 initSR(sr);
3337c2f7
RG
3535
3536 primeHints();
3537
3538 size_t queriesCount = 0;
3539 const DNSName target("test.powerdns.com.");
3540 const ComboAddress targetAddr("192.0.2.2");
3541 const DNSName authZone("powerdns.com");
3542
3543 SyncRes::AuthDomain ad;
3544 ad.d_name = authZone;
3545 DNSRecord dr;
3546 dr.d_place = DNSResourceRecord::ANSWER;
3547 dr.d_name = authZone;
3548 dr.d_type = QType::SOA;
3549 dr.d_ttl = 3600;
3550 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3551 ad.d_records.insert(dr);
3552
3553 dr.d_place = DNSResourceRecord::ANSWER;
3554 dr.d_name = DNSName("*.powerdns.com.");
3555 dr.d_type = QType::A;
3556 dr.d_ttl = 3600;
3557 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3558 ad.d_records.insert(dr);
3559
3560 auto map = std::make_shared<SyncRes::domainmap_t>();
3561 (*map)[authZone] = ad;
3562 SyncRes::setDomainMap(map);
3563
0bd2e252 3564 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
3565
3566 queriesCount++;
3567
3568 return 0;
3569 });
3570
3571 vector<DNSRecord> ret;
3572 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3573 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3574 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3575 BOOST_CHECK(ret[0].d_type == QType::A);
3576 BOOST_CHECK_EQUAL(queriesCount, 0);
3577}
3578
3579BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3580 std::unique_ptr<SyncRes> sr;
895449a5 3581 initSR(sr);
3337c2f7
RG
3582
3583 primeHints();
3584
3585 size_t queriesCount = 0;
3586 const DNSName target("test.powerdns.com.");
3587 const ComboAddress targetAddr("192.0.2.2");
3588 const DNSName authZone("powerdns.com");
3589
3590 SyncRes::AuthDomain ad;
3591 ad.d_name = authZone;
3592 DNSRecord dr;
3593 dr.d_place = DNSResourceRecord::ANSWER;
3594 dr.d_name = authZone;
3595 dr.d_type = QType::SOA;
3596 dr.d_ttl = 3600;
3597 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3598 ad.d_records.insert(dr);
3599
3600 dr.d_place = DNSResourceRecord::ANSWER;
3601 dr.d_name = DNSName("*.powerdns.com.");
3602 dr.d_type = QType::A;
3603 dr.d_ttl = 3600;
3604 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3605 ad.d_records.insert(dr);
3606
3607 auto map = std::make_shared<SyncRes::domainmap_t>();
3608 (*map)[authZone] = ad;
3609 SyncRes::setDomainMap(map);
3610
0bd2e252 3611 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
3612
3613 queriesCount++;
3614
3615 return 0;
3616 });
3617
3618 vector<DNSRecord> ret;
3619 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3620 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3621 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3622 BOOST_CHECK(ret[0].d_type == QType::SOA);
3623 BOOST_CHECK_EQUAL(queriesCount, 0);
3624}
3625
3626BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3627 std::unique_ptr<SyncRes> sr;
895449a5 3628 initSR(sr);
3337c2f7
RG
3629
3630 primeHints();
3631
3632 size_t queriesCount = 0;
3633 const DNSName target("powerdns.com.");
3634 const ComboAddress addr("192.0.2.5");
3635
3636 SyncRes::AuthDomain ad;
3637 ad.d_name = target;
3638 DNSRecord dr;
3639 dr.d_place = DNSResourceRecord::ANSWER;
3640 dr.d_name = target;
3641 dr.d_type = QType::SOA;
3642 dr.d_ttl = 3600;
3643 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3644 ad.d_records.insert(dr);
3645
3646 dr.d_place = DNSResourceRecord::ANSWER;
3647 dr.d_name = target;
3648 dr.d_type = QType::A;
3649 dr.d_ttl = 3600;
3650 dr.d_content = std::make_shared<ARecordContent>(addr);
3651 ad.d_records.insert(dr);
3652
3653 auto map = std::make_shared<SyncRes::domainmap_t>();
3654 (*map)[target] = ad;
3655 SyncRes::setDomainMap(map);
3656
0bd2e252 3657 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
3658
3659 queriesCount++;
3660 setLWResult(res, 0, true, false, true);
3661 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3662 return 1;
3663 });
3664
3665 /* simulate a no-RD query */
3666 sr->setCacheOnly();
3667
3668 vector<DNSRecord> ret;
3669 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3670 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3671 BOOST_CHECK_EQUAL(ret.size(), 1);
3672 BOOST_CHECK(ret[0].d_type == QType::A);
3673 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3674 BOOST_CHECK_EQUAL(queriesCount, 0);
3675}
3676
8455425c 3677BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
8455425c
RG
3678 init();
3679
3680 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3681 dcke->create(dcke->getBits());
3682 // cerr<<dcke->convertToISC()<<endl;
3683 DNSSECPrivateKey dpk;
3684 dpk.d_flags = 256;
3685 dpk.setKey(dcke);
3686
3687 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3688 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3689
3690 DNSName qname("powerdns.com.");
3691
179b340d 3692 time_t now = time(nullptr);
8455425c 3693 RRSIGRecordContent rrc;
179b340d
RG
3694 /* this RRSIG is valid for the current second only */
3695 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
8455425c
RG
3696
3697 skeyset_t keyset;
3698 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3699
3700 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3701 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3702
179b340d 3703 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
8455425c
RG
3704}
3705
3706BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3707 std::unique_ptr<SyncRes> sr;
895449a5 3708 initSR(sr, true);
8455425c 3709
0c43f455 3710 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3711
3712 primeHints();
3713 const DNSName target(".");
b7f378d1 3714 testkeysset_t keys;
8455425c
RG
3715
3716 auto luaconfsCopy = g_luaconfs.getCopy();
3717 luaconfsCopy.dsAnchors.clear();
3718 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3719 g_luaconfs.setState(luaconfsCopy);
3720
3721 size_t queriesCount = 0;
3722
0bd2e252 3723 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
3724 queriesCount++;
3725
3726 if (domain == target && type == QType::NS) {
3727
3728 setLWResult(res, 0, true, false, true);
3729 char addr[] = "a.root-servers.net.";
3730 for (char idx = 'a'; idx <= 'm'; idx++) {
3731 addr[0] = idx;
3732 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3733 }
3734
3735 addRRSIG(keys, res->d_records, domain, 300);
3736
3737 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3738 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3739
3740 return 1;
3741 } else if (domain == target && type == QType::DNSKEY) {
3742
3743 setLWResult(res, 0, true, false, true);
3744
3745 addDNSKEY(keys, domain, 300, res->d_records);
3746 addRRSIG(keys, res->d_records, domain, 300);
3747
3748 return 1;
3749 }
3750
3751 return 0;
3752 });
3753
3754 vector<DNSRecord> ret;
3755 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3756 BOOST_CHECK_EQUAL(res, RCode::NoError);
3757 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
3758 /* 13 NS + 1 RRSIG */
3759 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3760 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3761
3762 /* again, to test the cache */
3763 ret.clear();
3764 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3765 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3766 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
3767 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3768 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3769}
3770
3771BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3772 std::unique_ptr<SyncRes> sr;
895449a5 3773 initSR(sr, true);
8455425c 3774
0c43f455 3775 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3776
3777 primeHints();
3778 const DNSName target(".");
b7f378d1
RG
3779 testkeysset_t zskeys;
3780 testkeysset_t kskeys;
8455425c
RG
3781
3782 /* Generate key material for "." */
3783 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3784 dckeZ->create(dckeZ->getBits());
3785 DNSSECPrivateKey ksk;
3786 ksk.d_flags = 257;
3787 ksk.setKey(dckeZ);
b7f378d1
RG
3788 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3789
8455425c
RG
3790 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3791 dckeK->create(dckeK->getBits());
3792 DNSSECPrivateKey zsk;
3793 zsk.d_flags = 256;
3794 zsk.setKey(dckeK);
b7f378d1 3795 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3796
b7f378d1
RG
3797 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3798 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
8455425c
RG
3799
3800 /* Set the root DS */
8455425c
RG
3801 auto luaconfsCopy = g_luaconfs.getCopy();
3802 luaconfsCopy.dsAnchors.clear();
b7f378d1 3803 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
8455425c
RG
3804 g_luaconfs.setState(luaconfsCopy);
3805
3806 size_t queriesCount = 0;
3807
0bd2e252 3808 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
3809 queriesCount++;
3810
3811 if (domain == target && type == QType::NS) {
3812
3813 setLWResult(res, 0, true, false, true);
3814 char addr[] = "a.root-servers.net.";
3815 for (char idx = 'a'; idx <= 'm'; idx++) {
3816 addr[0] = idx;
3817 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3818 }
3819
3820 addRRSIG(zskeys, res->d_records, domain, 300);
3821
3822 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3823 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3824
3825 return 1;
3826 } else if (domain == target && type == QType::DNSKEY) {
3827
3828 setLWResult(res, 0, true, false, true);
3829
3830 addDNSKEY(kskeys, domain, 300, res->d_records);
3831 addDNSKEY(zskeys, domain, 300, res->d_records);
3832 addRRSIG(kskeys, res->d_records, domain, 300);
3833
3834 return 1;
3835 }
3836
3837 return 0;
3838 });
3839
3840 vector<DNSRecord> ret;
3841 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3842 BOOST_CHECK_EQUAL(res, RCode::NoError);
3843 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
3844 /* 13 NS + 1 RRSIG */
3845 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3846 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3847
3848 /* again, to test the cache */
3849 ret.clear();
3850 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3851 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3852 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
3853 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3854 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3855}
3856
3857BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
3858 std::unique_ptr<SyncRes> sr;
895449a5 3859 initSR(sr, true);
8455425c 3860
0c43f455 3861 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3862
3863 primeHints();
3864 const DNSName target(".");
b7f378d1 3865 testkeysset_t keys;
8455425c
RG
3866
3867 auto luaconfsCopy = g_luaconfs.getCopy();
3868 luaconfsCopy.dsAnchors.clear();
3869 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3870 g_luaconfs.setState(luaconfsCopy);
3871
3872 size_t queriesCount = 0;
3873
0bd2e252 3874 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
3875 queriesCount++;
3876
3877 if (domain == target && type == QType::NS) {
3878
3879 setLWResult(res, 0, true, false, true);
3880 char addr[] = "a.root-servers.net.";
3881 for (char idx = 'a'; idx <= 'm'; idx++) {
3882 addr[0] = idx;
3883 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3884 }
3885
3886 addRRSIG(keys, res->d_records, domain, 300);
3887
3888 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3889 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3890
3891 return 1;
3892 } else if (domain == target && type == QType::DNSKEY) {
3893
3894 setLWResult(res, 0, true, false, true);
3895
3896 /* No DNSKEY */
3897
3898 return 1;
3899 }
3900
3901 return 0;
3902 });
3903
3904 vector<DNSRecord> ret;
3905 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3906 BOOST_CHECK_EQUAL(res, RCode::NoError);
3907 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3908 /* 13 NS + 1 RRSIG */
3909 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3910 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3911
3912 /* again, to test the cache */
3913 ret.clear();
3914 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3915 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3916 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3917 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3918 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3919}
3920
3921BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3922 std::unique_ptr<SyncRes> sr;
895449a5 3923 initSR(sr, true);
8455425c 3924
0c43f455 3925 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3926
3927 primeHints();
3928 const DNSName target(".");
b7f378d1
RG
3929 testkeysset_t dskeys;
3930 testkeysset_t keys;
8455425c
RG
3931
3932 /* Generate key material for "." */
3933 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3934 dckeDS->create(dckeDS->getBits());
3935 DNSSECPrivateKey dskey;
3936 dskey.d_flags = 257;
3937 dskey.setKey(dckeDS);
b7f378d1
RG
3938 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3939
8455425c
RG
3940 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3941 dcke->create(dcke->getBits());
3942 DNSSECPrivateKey dpk;
3943 dpk.d_flags = 256;
3944 dpk.setKey(dcke);
b7f378d1 3945 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3946
b7f378d1
RG
3947 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3948 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
8455425c
RG
3949
3950 /* Set the root DS */
8455425c
RG
3951 auto luaconfsCopy = g_luaconfs.getCopy();
3952 luaconfsCopy.dsAnchors.clear();
3953 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3954 g_luaconfs.setState(luaconfsCopy);
3955
3956 size_t queriesCount = 0;
3957
0bd2e252 3958 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
3959 queriesCount++;
3960
3961 if (domain == target && type == QType::NS) {
3962
3963 setLWResult(res, 0, true, false, true);
3964 char addr[] = "a.root-servers.net.";
3965 for (char idx = 'a'; idx <= 'm'; idx++) {
3966 addr[0] = idx;
3967 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3968 }
3969
3970 addRRSIG(keys, res->d_records, domain, 300);
3971
3972 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3973 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3974
3975 return 1;
3976 } else if (domain == target && type == QType::DNSKEY) {
3977
3978 setLWResult(res, 0, true, false, true);
3979
3980 addDNSKEY(keys, domain, 300, res->d_records);
3981 addRRSIG(keys, res->d_records, domain, 300);
3982
3983 return 1;
3984 }
3985
3986 return 0;
3987 });
3988
3989 vector<DNSRecord> ret;
3990 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3991 BOOST_CHECK_EQUAL(res, RCode::NoError);
3992 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3993 /* 13 NS + 1 RRSIG */
3994 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3995 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3996
3997 /* again, to test the cache */
3998 ret.clear();
3999 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4000 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4001 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4002 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4003 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
4004}
4005
4006BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
4007 std::unique_ptr<SyncRes> sr;
895449a5 4008 initSR(sr, true);
8455425c 4009
0c43f455 4010 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4011
4012 primeHints();
4013 const DNSName target(".");
b7f378d1
RG
4014 testkeysset_t keys;
4015 testkeysset_t rrsigkeys;
8455425c
RG
4016
4017 auto luaconfsCopy = g_luaconfs.getCopy();
4018 luaconfsCopy.dsAnchors.clear();
4019 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4020 g_luaconfs.setState(luaconfsCopy);
4021
4022 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4023 dckeRRSIG->create(dckeRRSIG->getBits());
4024 DNSSECPrivateKey rrsigkey;
4025 rrsigkey.d_flags = 257;
4026 rrsigkey.setKey(dckeRRSIG);
b7f378d1
RG
4027 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
4028
4029 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
8455425c
RG
4030
4031 size_t queriesCount = 0;
4032
0bd2e252 4033 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
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(rrsigkeys, 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(rrsigkeys, 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(), Bogus);
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(), Bogus);
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_bogus_no_rrsig) {
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 4089 testkeysset_t keys;
8455425c
RG
4090
4091 auto luaconfsCopy = g_luaconfs.getCopy();
4092 luaconfsCopy.dsAnchors.clear();
4093 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4094 g_luaconfs.setState(luaconfsCopy);
4095
4096 size_t queriesCount = 0;
4097
0bd2e252 4098 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
4099 queriesCount++;
4100
4101 if (domain == target && type == QType::NS) {
4102
4103 setLWResult(res, 0, true, false, true);
4104 char addr[] = "a.root-servers.net.";
4105 for (char idx = 'a'; idx <= 'm'; idx++) {
4106 addr[0] = idx;
4107 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4108 }
4109
4110 /* No RRSIG */
4111
4112 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4113 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4114
4115 return 1;
4116 } else if (domain == target && type == QType::DNSKEY) {
4117
4118 setLWResult(res, 0, true, false, true);
4119
4120 addDNSKEY(keys, domain, 300, res->d_records);
4121 addRRSIG(keys, res->d_records, domain, 300);
4122
4123 return 1;
4124 }
4125
4126 return 0;
4127 });
4128
4129 vector<DNSRecord> ret;
4130 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4131 BOOST_CHECK_EQUAL(res, RCode::NoError);
4132 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
4133 /* 13 NS + 0 RRSIG */
4134 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4135 /* no RRSIG so no query for DNSKEYs */
4136 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4137
4138 /* again, to test the cache */
4139 ret.clear();
4140 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4141 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4142 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4143 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4144 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4145}
4146
4147BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
4148 std::unique_ptr<SyncRes> sr;
895449a5 4149 initSR(sr, true);
8455425c 4150
0c43f455 4151 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4152
4153 primeHints();
4154 const DNSName target(".");
b7f378d1 4155 testkeysset_t keys;
8455425c
RG
4156
4157 /* Generate key material for "." */
4158 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4159 dcke->create(dcke->getBits());
4160 DNSSECPrivateKey dpk;
4161 dpk.d_flags = 256;
4162 dpk.setKey(dcke);
4163 /* Fake algorithm number (private) */
4164 dpk.d_algorithm = 253;
4165
8455425c 4166 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
b7f378d1 4167 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
8455425c
RG
4168 /* Fake algorithm number (private) */
4169 drc.d_algorithm = 253;
4170
b7f378d1 4171 /* Set the root DS */
8455425c
RG
4172 auto luaconfsCopy = g_luaconfs.getCopy();
4173 luaconfsCopy.dsAnchors.clear();
4174 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4175 g_luaconfs.setState(luaconfsCopy);
4176
4177 size_t queriesCount = 0;
4178
0bd2e252 4179 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
4180 queriesCount++;
4181
4182 if (domain == target && type == QType::NS) {
4183
4184 setLWResult(res, 0, true, false, true);
4185 char addr[] = "a.root-servers.net.";
4186 for (char idx = 'a'; idx <= 'm'; idx++) {
4187 addr[0] = idx;
4188 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4189 }
4190
4191 addRRSIG(keys, res->d_records, domain, 300);
4192
4193 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4194 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4195
4196 return 1;
4197 } else if (domain == target && type == QType::DNSKEY) {
4198
4199 setLWResult(res, 0, true, false, true);
4200
4201 addDNSKEY(keys, domain, 300, res->d_records);
4202 addRRSIG(keys, res->d_records, domain, 300);
4203
4204 return 1;
4205 }
4206
4207 return 0;
4208 });
4209
4210 vector<DNSRecord> ret;
4211 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4212 BOOST_CHECK_EQUAL(res, RCode::NoError);
4213 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4214 /* 13 NS + 1 RRSIG */
4215 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4216 /* no supported DS so no query for DNSKEYs */
4217 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4218
4219 /* again, to test the cache */
4220 ret.clear();
4221 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4222 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4223 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4224 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4225 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4226}
4227
4228BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
4229 std::unique_ptr<SyncRes> sr;
895449a5 4230 initSR(sr, true);
8455425c 4231
0c43f455 4232 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4233
4234 primeHints();
4235 const DNSName target(".");
b7f378d1 4236 testkeysset_t keys;
8455425c
RG
4237
4238 /* Generate key material for "." */
4239 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4240 dcke->create(dcke->getBits());
4241 DNSSECPrivateKey dpk;
4242 dpk.d_flags = 256;
4243 dpk.setKey(dcke);
8455425c
RG
4244 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
4245 /* Fake digest number (reserved) */
4246 drc.d_digesttype = 0;
4247
b7f378d1
RG
4248 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
4249
4250 /* Set the root DS */
8455425c
RG
4251 auto luaconfsCopy = g_luaconfs.getCopy();
4252 luaconfsCopy.dsAnchors.clear();
4253 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4254 g_luaconfs.setState(luaconfsCopy);
4255
4256 size_t queriesCount = 0;
4257
0bd2e252 4258 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
4259 queriesCount++;
4260
4261 if (domain == target && type == QType::NS) {
4262
4263 setLWResult(res, 0, true, false, true);
4264 char addr[] = "a.root-servers.net.";
4265 for (char idx = 'a'; idx <= 'm'; idx++) {
4266 addr[0] = idx;
4267 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4268 }
4269
4270 addRRSIG(keys, res->d_records, domain, 300);
4271
4272 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4273 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4274
4275 return 1;
4276 } else if (domain == target && type == QType::DNSKEY) {
4277
4278 setLWResult(res, 0, true, false, true);
4279
4280 addDNSKEY(keys, domain, 300, res->d_records);
4281 addRRSIG(keys, res->d_records, domain, 300);
4282
4283 return 1;
4284 }
4285
4286 return 0;
4287 });
4288
4289 vector<DNSRecord> ret;
4290 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4291 BOOST_CHECK_EQUAL(res, RCode::NoError);
4292 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4293 /* 13 NS + 1 RRSIG */
4294 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4295 /* no supported DS so no query for DNSKEYs */
4296 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4297
4298 /* again, to test the cache */
4299 ret.clear();
4300 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4301 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4302 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4303 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4304 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4305}
4306
3d5ebf10
RG
4307BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
4308 std::unique_ptr<SyncRes> sr;
4309 initSR(sr, true);
4310
0c43f455 4311 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4312
4313 primeHints();
4314 const DNSName target(".");
4315 testkeysset_t keys;
4316
4317 auto luaconfsCopy = g_luaconfs.getCopy();
4318 luaconfsCopy.dsAnchors.clear();
4319 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4320
4321 g_luaconfs.setState(luaconfsCopy);
4322
4323 size_t queriesCount = 0;
4324
0bd2e252 4325 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
4326 queriesCount++;
4327
4328 if (domain == target && type == QType::NS) {
4329
4330 setLWResult(res, 0, true, false, true);
4331 char addr[] = "a.root-servers.net.";
4332 for (char idx = 'a'; idx <= 'm'; idx++) {
4333 addr[0] = idx;
4334 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4335 }
4336
4337 addRRSIG(keys, res->d_records, domain, 300, true);
4338
4339 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4340 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4341
4342 return 1;
4343 } else if (domain == target && type == QType::DNSKEY) {
4344
4345 setLWResult(res, 0, true, false, true);
4346
4347 addDNSKEY(keys, domain, 300, res->d_records);
4348 addRRSIG(keys, res->d_records, domain, 300);
4349
4350 return 1;
4351 }
4352
4353 return 0;
4354 });
4355
4356 vector<DNSRecord> ret;
4357 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4358 BOOST_CHECK_EQUAL(res, RCode::NoError);
4359 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4360 /* 13 NS + 1 RRSIG */
4361 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4362 BOOST_CHECK_EQUAL(queriesCount, 2);
4363
4364 /* again, to test the cache */
4365 ret.clear();
4366 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4367 BOOST_CHECK_EQUAL(res, RCode::NoError);
4368 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4369 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4370 BOOST_CHECK_EQUAL(queriesCount, 2);
4371}
4372
4373BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
4374 std::unique_ptr<SyncRes> sr;
4375 initSR(sr, true);
4376
0c43f455 4377 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4378
4379 primeHints();
4380 const DNSName target(".");
4381 testkeysset_t keys;
4382
4383 auto luaconfsCopy = g_luaconfs.getCopy();
4384 luaconfsCopy.dsAnchors.clear();
4385 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4386
4387 g_luaconfs.setState(luaconfsCopy);
4388
4389 size_t queriesCount = 0;
4390
0bd2e252 4391 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
4392 queriesCount++;
4393
4394 if (domain == target && type == QType::NS) {
4395
4396 setLWResult(res, 0, true, false, true);
4397 char addr[] = "a.root-servers.net.";
4398 for (char idx = 'a'; idx <= 'm'; idx++) {
4399 addr[0] = idx;
4400 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4401 }
4402
4403 /* FORCE WRONG ALGO */
4404 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4405
4406 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4407 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4408
4409 return 1;
4410 } else if (domain == target && type == QType::DNSKEY) {
4411
4412 setLWResult(res, 0, true, false, true);
4413
4414 addDNSKEY(keys, domain, 300, res->d_records);
4415 addRRSIG(keys, res->d_records, domain, 300);
4416
4417 return 1;
4418 }
4419
4420 return 0;
4421 });
4422
4423 vector<DNSRecord> ret;
4424 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4425 BOOST_CHECK_EQUAL(res, RCode::NoError);
4426 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4427 /* 13 NS + 1 RRSIG */
4428 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4429 BOOST_CHECK_EQUAL(queriesCount, 2);
4430
4431 /* again, to test the cache */
4432 ret.clear();
4433 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4434 BOOST_CHECK_EQUAL(res, RCode::NoError);
4435 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4436 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4437 BOOST_CHECK_EQUAL(queriesCount, 2);
4438}
4439
f100caac
RG
4440BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds) {
4441 std::unique_ptr<SyncRes> sr;
4442 initSR(sr, true);
4443
4444 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4445
4446 primeHints();
4447 const DNSName target("com.");
4448 const ComboAddress targetAddr("192.0.2.42");
4449 testkeysset_t keys;
4450
4451 auto luaconfsCopy = g_luaconfs.getCopy();
4452 luaconfsCopy.dsAnchors.clear();
4453 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4454 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4455
4456 g_luaconfs.setState(luaconfsCopy);
4457
4458 size_t queriesCount = 0;
4459
0bd2e252 4460 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
4461 queriesCount++;
4462
4463 DNSName auth = domain;
4464
4465 if (type == QType::DS || type == QType::DNSKEY) {
4466 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4467 return 0;
4468 }
4469
4470 if (type == QType::DS && domain == target) {
4471 /* remove the last record, which is the DS's RRSIG */
4472 res->d_records.pop_back();
4473 }
4474
4475 return 1;
4476 }
4477
4478 if (isRootServer(ip)) {
4479 setLWResult(res, 0, false, false, true);
4480 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4481 /* Include the DS but omit the RRSIG*/
4482 addDS(DNSName("com."), 300, res->d_records, keys);
4483 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4484 return 1;
4485 }
4486
4487 if (ip == ComboAddress("192.0.2.1:53")) {
4488 setLWResult(res, RCode::NoError, true, false, true);
4489 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4490 addRRSIG(keys, res->d_records, auth, 300);
4491 return 1;
4492 }
4493
4494 return 0;
4495 });
4496
4497 vector<DNSRecord> ret;
4498 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4499 BOOST_CHECK_EQUAL(res, RCode::NoError);
4500 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4501 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4502 BOOST_CHECK_EQUAL(queriesCount, 4);
4503
4504 /* again, to test the cache */
4505 ret.clear();
4506 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4507 BOOST_CHECK_EQUAL(res, RCode::NoError);
4508 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4509 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4510 BOOST_CHECK_EQUAL(queriesCount, 4);
4511
4512 /* now we ask directly for the DS */
4513 ret.clear();
4514 res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4515 BOOST_CHECK_EQUAL(res, RCode::NoError);
4516 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4517 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4518 BOOST_CHECK_EQUAL(queriesCount, 4);
4519}
4520
4521BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds_direct) {
4522 std::unique_ptr<SyncRes> sr;
4523 initSR(sr, true);
4524
4525 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4526
4527 primeHints();
4528 const DNSName target("com.");
4529 testkeysset_t keys;
4530
4531 auto luaconfsCopy = g_luaconfs.getCopy();
4532 luaconfsCopy.dsAnchors.clear();
4533 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4534 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4535
4536 g_luaconfs.setState(luaconfsCopy);
4537
4538 size_t queriesCount = 0;
4539
0bd2e252 4540 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
4541 queriesCount++;
4542
4543 DNSName auth = domain;
4544
4545 if (type == QType::DS || type == QType::DNSKEY) {
4546 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4547 return 0;
4548 }
4549
4550 if (type == QType::DS && domain == target) {
4551 /* remove the last record, which is the DS's RRSIG */
4552 res->d_records.pop_back();
4553 }
4554
4555 return 1;
4556 }
4557
4558 if (isRootServer(ip)) {
4559 setLWResult(res, 0, false, false, true);
4560 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4561 /* Include the DS but omit the RRSIG*/
4562 addDS(DNSName("com."), 300, res->d_records, keys);
4563 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4564 return 1;
4565 }
4566
4567 return 0;
4568 });
4569
4570 vector<DNSRecord> ret;
4571 int res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4572 BOOST_CHECK_EQUAL(res, RCode::NoError);
4573 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4574 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4575 BOOST_CHECK_EQUAL(queriesCount, 1);
4576}
4577
b7f378d1 4578BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
8455425c 4579 std::unique_ptr<SyncRes> sr;
895449a5 4580 initSR(sr, true);
8455425c 4581
0c43f455 4582 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4583
4584 primeHints();
4585 const DNSName target("powerdns.com.");
b7f378d1
RG
4586 const ComboAddress targetAddr("192.0.2.42");
4587 testkeysset_t keys;
8455425c
RG
4588
4589 auto luaconfsCopy = g_luaconfs.getCopy();
4590 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4591 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4592 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4593 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
8455425c
RG
4594
4595 g_luaconfs.setState(luaconfsCopy);
4596
4597 size_t queriesCount = 0;
4598
0bd2e252 4599 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
4600 queriesCount++;
4601
b7f378d1
RG
4602 DNSName auth = domain;
4603 if (domain == target) {
4604 auth = DNSName("powerdns.com.");
4605 }
5374b03b
RG
4606
4607 if (type == QType::DS || type == QType::DNSKEY) {
4608 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8455425c 4609 }
5374b03b
RG
4610
4611 if (isRootServer(ip)) {
4612 setLWResult(res, 0, false, false, true);
4613 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4614 addDS(DNSName("com."), 300, res->d_records, keys);
4615 addRRSIG(keys, res->d_records, DNSName("."), 300);
4616 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8455425c
RG
4617 return 1;
4618 }
5374b03b
RG
4619
4620 if (ip == ComboAddress("192.0.2.1:53")) {
4621 if (domain == DNSName("com.")) {
4622 setLWResult(res, 0, true, false, true);
4623 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4624 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4625 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4626 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4627 }
5374b03b
RG
4628 else {
4629 setLWResult(res, 0, false, false, true);
4630 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4631 addDS(auth, 300, res->d_records, keys);
4632 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4633 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8455425c 4634 }
5374b03b
RG
4635 return 1;
4636 }
4637
4638 if (ip == ComboAddress("192.0.2.2:53")) {
4639 if (type == QType::NS) {
4640 setLWResult(res, 0, true, false, true);
4641 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4642 addRRSIG(keys, res->d_records, auth, 300);
4643 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4644 addRRSIG(keys, res->d_records, auth, 300);
8455425c 4645 }
5374b03b
RG
4646 else {
4647 setLWResult(res, RCode::NoError, true, false, true);
4648 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4649 addRRSIG(keys, res->d_records, auth, 300);
4650 }
4651 return 1;
8455425c
RG
4652 }
4653
4654 return 0;
4655 });
4656
4657 vector<DNSRecord> ret;
4658 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1
RG
4659 BOOST_CHECK_EQUAL(res, RCode::NoError);
4660 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4661 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4662 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4663
4664 /* again, to test the cache */
4665 ret.clear();
4666 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4667 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4668 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1 4669 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4670 BOOST_CHECK_EQUAL(queriesCount, 8);
8455425c
RG
4671}
4672
428f41b7
RG
4673BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4674 std::unique_ptr<SyncRes> sr;
4675 initSR(sr, true);
4676
0c43f455 4677 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4678
4679 primeHints();
4680 const DNSName target("powerdns.com.");
4681 const ComboAddress targetAddr("192.0.2.42");
4682 testkeysset_t keys;
4683
4684 auto luaconfsCopy = g_luaconfs.getCopy();
4685 luaconfsCopy.dsAnchors.clear();
4686 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4687 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4688 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4689 g_luaconfs.setState(luaconfsCopy);
4690
4691 size_t queriesCount = 0;
4692
0bd2e252 4693 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
4694 queriesCount++;
4695
4696 DNSName auth = domain;
4697 if (domain == target) {
4698 auth = DNSName("powerdns.com.");
4699 }
5374b03b
RG
4700
4701 if (type == QType::DS || type == QType::DNSKEY) {
4702 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4703 }
5374b03b
RG
4704
4705 if (isRootServer(ip)) {
4706 setLWResult(res, 0, false, false, true);
4707 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4708 addDS(DNSName("com."), 300, res->d_records, keys);
4709 addRRSIG(keys, res->d_records, DNSName("."), 300);
4710 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4711 return 1;
4712 }
5374b03b
RG
4713
4714 if (ip == ComboAddress("192.0.2.1:53")) {
4715 if (domain == DNSName("com.")) {
4716 setLWResult(res, 0, true, false, true);
4717 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4718 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4719 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4720 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4721 }
5374b03b
RG
4722 else {
4723 setLWResult(res, 0, false, false, true);
4724 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4725 addDS(auth, 300, res->d_records, keys);
4726 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4727 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4728 }
5374b03b
RG
4729 return 1;
4730 }
4731
4732 if (ip == ComboAddress("192.0.2.2:53")) {
4733 if (type == QType::NS) {
4734 setLWResult(res, 0, true, false, true);
4735 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4736 addRRSIG(keys, res->d_records, auth, 300);
4737 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4738 addRRSIG(keys, res->d_records, auth, 300);
4739 }
4740 else {
4741 setLWResult(res, RCode::NoError, true, false, true);
4742 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4743 addRRSIG(keys, res->d_records, auth, 300);
428f41b7 4744 }
5374b03b 4745 return 1;
428f41b7
RG
4746 }
4747
4748 return 0;
4749 });
4750
4751 vector<DNSRecord> ret;
4752 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4753 BOOST_CHECK_EQUAL(res, RCode::NoError);
4754 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4755 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4756 BOOST_CHECK_EQUAL(queriesCount, 8);
4757
4758 /* again, to test the cache */
4759 ret.clear();
4760 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4761 BOOST_CHECK_EQUAL(res, RCode::NoError);
4762 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4763 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4764 BOOST_CHECK_EQUAL(queriesCount, 8);
4765
4766 /* this time we ask for the NS that should be in the cache, to check
4767 the validation status */
4768 ret.clear();
4769 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4770 BOOST_CHECK_EQUAL(res, RCode::NoError);
4771 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4772 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4773 BOOST_CHECK_EQUAL(queriesCount, 9);
428f41b7
RG
4774
4775}
4776
4777BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4778 std::unique_ptr<SyncRes> sr;
4779 initSR(sr, true);
4780
0c43f455 4781 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4782
4783 primeHints();
4784 const DNSName target("powerdns.com.");
4785 const ComboAddress targetAddr("192.0.2.42");
4786 testkeysset_t keys;
4787
4788 auto luaconfsCopy = g_luaconfs.getCopy();
4789 luaconfsCopy.dsAnchors.clear();
4790 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4791 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4792 g_luaconfs.setState(luaconfsCopy);
4793
4794 size_t queriesCount = 0;
4795
0bd2e252 4796 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
4797 queriesCount++;
4798
4799 DNSName auth = domain;
4800 if (domain == target) {
4801 auth = DNSName("powerdns.com.");
4802 }
5374b03b
RG
4803
4804 if (type == QType::DS || type == QType::DNSKEY) {
4805 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4806 }
5374b03b
RG
4807
4808 if (isRootServer(ip)) {
4809 setLWResult(res, 0, false, false, true);
4810 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4811 addDS(DNSName("com."), 300, res->d_records, keys);
4812 addRRSIG(keys, res->d_records, DNSName("."), 300);
4813 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4814 return 1;
4815 }
5374b03b
RG
4816
4817 if (ip == ComboAddress("192.0.2.1:53")) {
4818 if (domain == DNSName("com.")) {
4819 setLWResult(res, 0, true, false, true);
4820 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4821 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4822 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4823 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4824 }
5374b03b
RG
4825 else {
4826 setLWResult(res, 0, false, false, true);
4827 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4828 /* no DS */
4829 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4830 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4831 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4832 }
5374b03b
RG
4833 return 1;
4834 }
4835
4836 if (ip == ComboAddress("192.0.2.2:53")) {
4837 if (type == QType::NS) {
4838 setLWResult(res, 0, true, false, true);
4839 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4840 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4841 }
5374b03b
RG
4842 else {
4843 setLWResult(res, RCode::NoError, true, false, true);
4844 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4845 }
4846 return 1;
428f41b7
RG
4847 }
4848
4849 return 0;
4850 });
4851
4852 vector<DNSRecord> ret;
4853 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4854 BOOST_CHECK_EQUAL(res, RCode::NoError);
4855 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4856 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4857 BOOST_CHECK_EQUAL(queriesCount, 7);
4858
4859 /* again, to test the cache */
4860 ret.clear();
4861 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4862 BOOST_CHECK_EQUAL(res, RCode::NoError);
4863 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4864 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4865 BOOST_CHECK_EQUAL(queriesCount, 7);
4866
4867 /* this time we ask for the NS that should be in the cache, to check
4868 the validation status */
4869 ret.clear();
4870 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4871 BOOST_CHECK_EQUAL(res, RCode::NoError);
4872 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4873 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4874 BOOST_CHECK_EQUAL(queriesCount, 8);
428f41b7
RG
4875}
4876
b7f378d1 4877BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
8455425c 4878 std::unique_ptr<SyncRes> sr;
895449a5 4879 initSR(sr, true);
8455425c 4880
0c43f455 4881 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4882
4883 primeHints();
b7f378d1
RG
4884 const DNSName target("powerdns.com.");
4885 const ComboAddress targetAddr("192.0.2.42");
4886 testkeysset_t keys;
8455425c
RG
4887
4888 auto luaconfsCopy = g_luaconfs.getCopy();
4889 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4890 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4891 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4892 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4893
4894 /* Add a NTA for "powerdns.com" */
4895 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
8455425c 4896
8455425c
RG
4897 g_luaconfs.setState(luaconfsCopy);
4898
4899 size_t queriesCount = 0;
4900
0bd2e252 4901 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
4902 queriesCount++;
4903
b7f378d1
RG
4904 DNSName auth = domain;
4905 if (domain == target) {
4906 auth = DNSName("powerdns.com.");
4907 }
5374b03b
RG
4908
4909 if (type == QType::DS || type == QType::DNSKEY) {
4910 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
b7f378d1 4911 }
5374b03b
RG
4912
4913 if (isRootServer(ip)) {
4914 setLWResult(res, 0, false, false, true);
4915 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4916 addDS(DNSName("com."), 300, res->d_records, keys);
4917 addRRSIG(keys, res->d_records, DNSName("."), 300);
4918 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1
RG
4919 return 1;
4920 }
5374b03b
RG
4921
4922 if (ip == ComboAddress("192.0.2.1:53")) {
4923 if (domain == DNSName("com.")) {
4924 setLWResult(res, 0, true, false, true);
4925 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4926 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4927 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4928 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4929 }
5374b03b
RG
4930 else {
4931 setLWResult(res, 0, false, false, true);
4932 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4933 addDS(auth, 300, res->d_records, keys);
4934 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4935 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1 4936 }
5374b03b
RG
4937 return 1;
4938 }
4939
4940 if (ip == ComboAddress("192.0.2.2:53")) {
4941 if (type == QType::NS) {
4942 setLWResult(res, 0, true, false, true);
4943 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4944 addRRSIG(keys, res->d_records, auth, 300);
4945 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4946 addRRSIG(keys, res->d_records, auth, 300);
4947 }
4948 else {
4949 setLWResult(res, RCode::NoError, true, false, true);
4950 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4951 addRRSIG(keys, res->d_records, auth, 300);
b7f378d1 4952 }
5374b03b 4953 return 1;
b7f378d1
RG
4954 }
4955
4956 return 0;
4957 });
4958
4959 vector<DNSRecord> ret;
4960 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4961 BOOST_CHECK_EQUAL(res, RCode::NoError);
4962 /* Should be insecure because of the NTA */
4963 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4964 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4965 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4966
4967 /* again, to test the cache */
4968 ret.clear();
4969 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4970 BOOST_CHECK_EQUAL(res, RCode::NoError);
4971 /* Should be insecure because of the NTA */
4972 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4973 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4974 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4975}
4976
4977BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4978 std::unique_ptr<SyncRes> sr;
895449a5 4979 initSR(sr, true);
b7f378d1 4980
0c43f455 4981 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
4982
4983 primeHints();
4984 const DNSName target("powerdns.com.");
4985 const ComboAddress targetAddr("192.0.2.42");
4986 testkeysset_t keys;
4987
4988 auto luaconfsCopy = g_luaconfs.getCopy();
4989 luaconfsCopy.dsAnchors.clear();
4990 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4991 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4992 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4993
4994 /* Add a NTA for "powerdns.com" */
4995 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4996
4997 g_luaconfs.setState(luaconfsCopy);
4998
4999 size_t queriesCount = 0;
5000
0bd2e252 5001 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
5002 queriesCount++;
5003
5004 if (type == QType::DS || type == QType::DNSKEY) {
5005 setLWResult(res, 0, false, false, true);
5006 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5007 return 1;
5008 }
f24465e5 5009 else {
b7f378d1
RG
5010 if (isRootServer(ip)) {
5011 setLWResult(res, 0, false, false, true);
5012 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5013 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5014 return 1;
5015 }
5016 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5017 if (domain == DNSName("com.")) {
5018 setLWResult(res, 0, true, false, true);
5019 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5020 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5021 }
5022 else {
5023 setLWResult(res, 0, false, false, true);
5024 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5025 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5026 }
b7f378d1
RG
5027 return 1;
5028 }
5029 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5030 if (type == QType::NS) {
5031 setLWResult(res, 0, true, false, true);
5032 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5033 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5034 }
5035 else {
5036 setLWResult(res, RCode::NoError, true, false, true);
5037 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
5038 }
b7f378d1
RG
5039 return 1;
5040 }
5041 }
5042
5043 return 0;
5044 });
5045
5046 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
5047 vector<DNSRecord> ret;
5048 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5049 BOOST_CHECK_EQUAL(res, RCode::NoError);
5050 /* Should be insecure because of the NTA */
5051 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5052 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 5053 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
5054
5055 /* again, to test the cache */
5056 ret.clear();
5057 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5058 BOOST_CHECK_EQUAL(res, RCode::NoError);
5059 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5060 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 5061 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
5062}
5063
5064BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
5065 std::unique_ptr<SyncRes> sr;
895449a5 5066 initSR(sr, true);
b7f378d1 5067
0c43f455 5068 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5069
5070 primeHints();
5071 const DNSName target("powerdns.com.");
5072 testkeysset_t keys;
5073
5074 auto luaconfsCopy = g_luaconfs.getCopy();
5075 luaconfsCopy.dsAnchors.clear();
5076 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5077 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5078 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5079
5080 g_luaconfs.setState(luaconfsCopy);
5081
5082 size_t queriesCount = 0;
5083
0bd2e252 5084 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
5085 queriesCount++;
5086
5374b03b
RG
5087 if (type == QType::DS || type == QType::DNSKEY) {
5088 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 5089 }
f24465e5 5090 else {
b7f378d1
RG
5091 if (isRootServer(ip)) {
5092 setLWResult(res, 0, false, false, true);
5093 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5094 addDS(DNSName("com."), 300, res->d_records, keys);
5095 addRRSIG(keys, res->d_records, DNSName("."), 300);
5096 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5097 return 1;
5098 }
5099 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5100 if (domain == DNSName("com.")) {
5101 setLWResult(res, 0, true, false, true);
5102 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5103 addRRSIG(keys, res->d_records, domain, 300);
5104 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5105 addRRSIG(keys, res->d_records, domain, 300);
5106 }
5107 else {
5108 setLWResult(res, 0, false, false, true);
5109 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5110 addDS(domain, 300, res->d_records, keys);
5111 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5112 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5113 }
b7f378d1
RG
5114 return 1;
5115 }
5116 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5117 if (type == QType::NS) {
5118 setLWResult(res, 0, true, false, true);
5119 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5120 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5121 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5122 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5123 }
5124 else {
5125 setLWResult(res, 0, true, false, true);
5126 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5127 addRRSIG(keys, res->d_records, domain, 300);
5128 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
5129 addRRSIG(keys, res->d_records, domain, 300);
5130 }
b7f378d1
RG
5131 return 1;
5132 }
5133 }
5134
5135 return 0;
5136 });
5137
5138 vector<DNSRecord> ret;
5139 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5140 BOOST_CHECK_EQUAL(res, RCode::NoError);
5141 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5142 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5143 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5144
5145 /* again, to test the cache */
5146 ret.clear();
5147 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5148 BOOST_CHECK_EQUAL(res, RCode::NoError);
5149 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5150 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5151 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5152}
5153
5154BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
5155 std::unique_ptr<SyncRes> sr;
895449a5 5156 initSR(sr, true);
b7f378d1 5157
0c43f455 5158 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5159
5160 primeHints();
5161 const DNSName target("nx.powerdns.com.");
5162 testkeysset_t keys;
5163
5164 auto luaconfsCopy = g_luaconfs.getCopy();
5165 luaconfsCopy.dsAnchors.clear();
5166 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5167 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5168 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5169
5170 g_luaconfs.setState(luaconfsCopy);
5171
5172 size_t queriesCount = 0;
5173
0bd2e252 5174 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
5175 queriesCount++;
5176
5177 DNSName auth = domain;
5178 if (domain == target) {
5179 auth = DNSName("powerdns.com.");
5180 }
5374b03b
RG
5181 if (type == QType::DS || type == QType::DNSKEY) {
5182 if (type == QType::DS && domain == target) {
5183 setLWResult(res, RCode::NXDomain, true, false, true);
5184 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5185 addRRSIG(keys, res->d_records, auth, 300);
5186 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5187 addRRSIG(keys, res->d_records, auth, 300);
5188 return 1;
5189 }
5190 else {
5191 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
5192 }
b7f378d1 5193 }
f24465e5 5194 else {
b7f378d1
RG
5195 if (isRootServer(ip)) {
5196 setLWResult(res, 0, false, false, true);
5197 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5198 addDS(DNSName("com."), 300, res->d_records, keys);
5199 addRRSIG(keys, res->d_records, DNSName("."), 300);
5200 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5201 return 1;
5202 }
5203 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5204 if (domain == DNSName("com.")) {
5205 setLWResult(res, 0, true, false, true);
5206 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5207 addRRSIG(keys, res->d_records, domain, 300);
5208 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5209 addRRSIG(keys, res->d_records, domain, 300);
5210 }
5211 else {
5212 setLWResult(res, 0, false, false, true);
5213 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5214 addDS(auth, 300, res->d_records, keys);
5215 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5216 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5217 }
b7f378d1
RG
5218 return 1;
5219 }
5220 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5221 if (type == QType::NS) {
5222 setLWResult(res, 0, true, false, true);
5223 if (domain == DNSName("powerdns.com.")) {
5224 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5225 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5226 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5227 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5228 }
5229 else {
5230 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5231 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5232 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5233 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5234 }
5235 }
5236 else {
5237 setLWResult(res, RCode::NXDomain, true, false, true);
5238 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5239 addRRSIG(keys, res->d_records, auth, 300);
5240 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5241 addRRSIG(keys, res->d_records, auth, 300);
9b061cf5
RG
5242 /* add wildcard denial */
5243 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5244 addRRSIG(keys, res->d_records, auth, 300);
f24465e5 5245 }
b7f378d1
RG
5246 return 1;
5247 }
5248 }
5249
5250 return 0;
5251 });
5252
5253 vector<DNSRecord> ret;
5254 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5255 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5256 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5257 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5258 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5259
5260 /* again, to test the cache */
5261 ret.clear();
5262 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5263 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5264 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5265 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5266 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5267}
5268
2b984251
RG
5269BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
5270 std::unique_ptr<SyncRes> sr;
5271 initSR(sr, true);
5272
0c43f455 5273 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2b984251
RG
5274
5275 primeHints();
5276 const DNSName target("www.powerdns.com.");
5277 testkeysset_t keys;
5278
5279 auto luaconfsCopy = g_luaconfs.getCopy();
5280 luaconfsCopy.dsAnchors.clear();
5281 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5282 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5283 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5284
5285 g_luaconfs.setState(luaconfsCopy);
5286
5287 size_t queriesCount = 0;
5288
0bd2e252 5289 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
5290 queriesCount++;
5291
5374b03b
RG
5292 if (type == QType::DS || type == QType::DNSKEY) {
5293 if (type == QType::DS && domain == target) {
5294 setLWResult(res, RCode::NoError, true, false, true);
5295 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5296 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5297 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5298 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5299 return 1;
5300 }
5301 else {
5302 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5303 }
2b984251 5304 }
f24465e5 5305 else {
2b984251
RG
5306 if (isRootServer(ip)) {
5307 setLWResult(res, 0, false, false, true);
5308 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5309 addDS(DNSName("com."), 300, res->d_records, keys);
5310 addRRSIG(keys, res->d_records, DNSName("."), 300);
5311 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5312 return 1;
5313 }
5314 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5315 if (domain == DNSName("com.")) {
5316 setLWResult(res, 0, true, false, true);
5317 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5318 addRRSIG(keys, res->d_records, domain, 300);
5319 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5320 addRRSIG(keys, res->d_records, domain, 300);
5321 }
5322 else {
5323 setLWResult(res, 0, false, false, true);
5324 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5325 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5326 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5327 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5328 }
2b984251
RG
5329 return 1;
5330 }
5331 else if (ip == ComboAddress("192.0.2.2:53")) {
5332 setLWResult(res, 0, true, false, true);
f24465e5
RG
5333 if (type == QType::NS) {
5334 if (domain == DNSName("powerdns.com.")) {
5335 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5336 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5337 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5338 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5339 }
5340 else {
5341 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5342 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5343 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5344 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5345 }
5346 }
5347 else {
5348 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5349 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
9b061cf5 5350 /* we need to add the proof that this name does not exist, so the wildcard may apply */
f24465e5
RG
5351 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5352 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5353 }
2b984251
RG
5354 return 1;
5355 }
5356 }
5357
5358 return 0;
5359 });
5360
5361 vector<DNSRecord> ret;
5362 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5363 BOOST_CHECK_EQUAL(res, RCode::NoError);
5364 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5365 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5366 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5367
5368 /* again, to test the cache */
5369 ret.clear();
5370 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5371 BOOST_CHECK_EQUAL(res, RCode::NoError);
5372 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5373 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5374 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5375}
5376
9b061cf5
RG
5377BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
5378 std::unique_ptr<SyncRes> sr;
5379 initSR(sr, true);
5380
5381 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5382
5383 primeHints();
5384 const DNSName target("www.com.");
5385 testkeysset_t keys;
5386
5387 auto luaconfsCopy = g_luaconfs.getCopy();
5388 luaconfsCopy.dsAnchors.clear();
5389 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5390 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5391
5392 g_luaconfs.setState(luaconfsCopy);
5393
5394 size_t queriesCount = 0;
5395
0bd2e252 5396 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
5397 queriesCount++;
5398
5399 if (type == QType::DS || type == QType::DNSKEY) {
5400 if (type == QType::DS && domain == target) {
5401 DNSName auth("com.");
5402 setLWResult(res, 0, true, false, true);
5403
5404 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5405 addRRSIG(keys, res->d_records, auth, 300);
5406 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
5407 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
5408 addRRSIG(keys, res->d_records, auth, 300);
5409 return 1;
5410 }
5411 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5412 }
5413 else {
5414 if (isRootServer(ip)) {
5415 setLWResult(res, 0, false, false, true);
5416 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5417 addDS(DNSName("com."), 300, res->d_records, keys);
5418 addRRSIG(keys, res->d_records, DNSName("."), 300);
5419 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5420 return 1;
5421 }
5422 else if (ip == ComboAddress("192.0.2.1:53")) {
5423 setLWResult(res, 0, true, false, true);
5424 /* no data */
5425 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5426 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5427 /* no record for this name */
5428 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
5429 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5430 /* a wildcard matches but has no record for this type */
5431 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5432 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5433 return 1;
5434 }
5435 }
5436
5437 return 0;
5438 });
5439
5440 vector<DNSRecord> ret;
5441 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5442 BOOST_CHECK_EQUAL(res, RCode::NoError);
5443 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5444 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5445 BOOST_CHECK_EQUAL(queriesCount, 6);
5446
5447 /* again, to test the cache */
5448 ret.clear();
5449 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(), 6);
5453 BOOST_CHECK_EQUAL(queriesCount, 6);
5454}
5455
5456BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
5457 std::unique_ptr<SyncRes> sr;
5458 initSR(sr, true);
5459
5460 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5461
5462 primeHints();
5463 const DNSName target("www.com.");
5464 testkeysset_t keys;
5465
5466 auto luaconfsCopy = g_luaconfs.getCopy();
5467 luaconfsCopy.dsAnchors.clear();
5468 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5469 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5470
5471 g_luaconfs.setState(luaconfsCopy);
5472
5473 size_t queriesCount = 0;
5474
0bd2e252 5475 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
5476 queriesCount++;
5477
5478 if (type == QType::DS || type == QType::DNSKEY) {
5479 if (type == QType::DS && domain == target) {
5480 DNSName auth("com.");
5481 setLWResult(res, 0, true, false, true);
5482
5483 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5484 addRRSIG(keys, res->d_records, auth, 300);
5485 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5486 /* first the closest encloser */
5487 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5488 addRRSIG(keys, res->d_records, auth, 300);
5489 /* then the next closer */
5490 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5491 addRRSIG(keys, res->d_records, auth, 300);
5492 /* a wildcard matches but has no record for this type */
5493 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5494 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5495 return 1;
5496 }
5497 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5498 }
5499 else {
5500 if (isRootServer(ip)) {
5501 setLWResult(res, 0, false, false, true);
5502 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5503 addDS(DNSName("com."), 300, res->d_records, keys);
5504 addRRSIG(keys, res->d_records, DNSName("."), 300);
5505 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5506 return 1;
5507 }
5508 else if (ip == ComboAddress("192.0.2.1:53")) {
5509 setLWResult(res, 0, true, false, true);
5510 /* no data */
5511 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5512 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5513 /* no record for this name */
5514 /* first the closest encloser */
5515 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5516 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5517 /* then the next closer */
5518 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5519 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5520 /* a wildcard matches but has no record for this type */
5521 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5522 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5523 return 1;
5524 }
5525 }
5526
5527 return 0;
5528 });
5529
5530 vector<DNSRecord> ret;
5531 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5532 BOOST_CHECK_EQUAL(res, RCode::NoError);
5533 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5534 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5535 BOOST_CHECK_EQUAL(queriesCount, 6);
5536
5537 /* again, to test the cache */
5538 ret.clear();
5539 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5540 BOOST_CHECK_EQUAL(res, RCode::NoError);
5541 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5542 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5543 BOOST_CHECK_EQUAL(queriesCount, 6);
5544}
5545
b7c40613
RG
5546BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5547 std::unique_ptr<SyncRes> sr;
5548 initSR(sr, true);
5549
5550 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5551
5552 primeHints();
5553 const DNSName target("www.com.");
5554 testkeysset_t keys;
5555
5556 auto luaconfsCopy = g_luaconfs.getCopy();
5557 luaconfsCopy.dsAnchors.clear();
5558 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5559 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5560
5561 g_luaconfs.setState(luaconfsCopy);
5562
5563 size_t queriesCount = 0;
5564
0bd2e252 5565 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
5566 queriesCount++;
5567
5568 if (type == QType::DS || type == QType::DNSKEY) {
5569 if (type == QType::DS && domain == target) {
5570 DNSName auth("com.");
5571 setLWResult(res, 0, true, false, true);
5572
5573 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5574 addRRSIG(keys, res->d_records, auth, 300);
5575 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5576 /* first the closest encloser */
5577 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5578 addRRSIG(keys, res->d_records, auth, 300);
5579 /* then the next closer */
5580 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5581 addRRSIG(keys, res->d_records, auth, 300);
5582 /* a wildcard matches but has no record for this type */
5583 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5584 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5585 return 1;
5586 }
5587 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5588 }
5589 else {
5590 if (isRootServer(ip)) {
5591 setLWResult(res, 0, false, false, true);
5592 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5593 addDS(DNSName("com."), 300, res->d_records, keys);
5594 addRRSIG(keys, res->d_records, DNSName("."), 300);
5595 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5596 return 1;
5597 }
5598 else if (ip == ComboAddress("192.0.2.1:53")) {
5599 setLWResult(res, 0, true, false, true);
5600 /* no data */
5601 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5602 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5603 /* no record for this name */
5604 /* first the closest encloser */
5605 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5606 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5607 /* then the next closer */
5608 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5609 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5610 /* a wildcard matches but has no record for this type */
5611 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5612 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5613 return 1;
5614 }
5615 }
5616
5617 return 0;
5618 });
5619
5620 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5621 vector<DNSRecord> ret;
5622 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5623 BOOST_CHECK_EQUAL(res, RCode::NoError);
5624 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5625 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5626 BOOST_CHECK_EQUAL(queriesCount, 6);
5627
5628 /* again, to test the cache */
5629 ret.clear();
5630 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5631 BOOST_CHECK_EQUAL(res, RCode::NoError);
5632 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5633 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5634 BOOST_CHECK_EQUAL(queriesCount, 6);
5635}
5636
9b061cf5
RG
5637BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5638 std::unique_ptr<SyncRes> sr;
5639 initSR(sr, true);
5640
5641 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5642
5643 primeHints();
e4894ce0 5644 const DNSName target("www.sub.powerdns.com.");
9b061cf5
RG
5645 testkeysset_t keys;
5646
5647 auto luaconfsCopy = g_luaconfs.getCopy();
5648 luaconfsCopy.dsAnchors.clear();
5649 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5650 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5651 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5652
5653 g_luaconfs.setState(luaconfsCopy);
5654
5655 size_t queriesCount = 0;
5656
0bd2e252 5657 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
5658 queriesCount++;
5659
5660 if (type == QType::DS || type == QType::DNSKEY) {
e4894ce0 5661 if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) {
9b061cf5
RG
5662 setLWResult(res, RCode::NoError, true, false, true);
5663 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5664 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
e4894ce0
RG
5665 if (domain == DNSName("sub.powerdns.com")) {
5666 addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5667 }
5668 else if (domain == target) {
5669 addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5670 }
9b061cf5
RG
5671 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5672 return 1;
5673 }
5674 else {
5675 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5676 }
5677 }
5678 else {
5679 if (isRootServer(ip)) {
5680 setLWResult(res, 0, false, false, true);
5681 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5682 addDS(DNSName("com."), 300, res->d_records, keys);
5683 addRRSIG(keys, res->d_records, DNSName("."), 300);
5684 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5685 return 1;
5686 }
5687 else if (ip == ComboAddress("192.0.2.1:53")) {
5688 if (domain == DNSName("com.")) {
5689 setLWResult(res, 0, true, false, true);
5690 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5691 addRRSIG(keys, res->d_records, domain, 300);
5692 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5693 addRRSIG(keys, res->d_records, domain, 300);
5694 }
5695 else {
5696 setLWResult(res, 0, false, false, true);
5697 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5698 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5699 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5700 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5701 }
5702 return 1;
5703 }
5704 else if (ip == ComboAddress("192.0.2.2:53")) {
5705 setLWResult(res, 0, true, false, true);
5706 if (type == QType::NS) {
5707 if (domain == DNSName("powerdns.com.")) {
5708 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5709 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5710 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5711 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5712 }
5713 else {
5714 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5715 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5716 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5717 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5718 }
5719 }
5720 else {
5721 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5722 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5723 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5724 /* first the closest encloser */
5725 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5726 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5727 /* then the next closer */
e4894ce0 5728 addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
9b061cf5
RG
5729 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5730 }
5731 return 1;
5732 }
5733 }
5734
5735 return 0;
5736 });
5737
5738 vector<DNSRecord> ret;
5739 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5740 BOOST_CHECK_EQUAL(res, RCode::NoError);
5741 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5742 BOOST_REQUIRE_EQUAL(ret.size(), 6);
e4894ce0 5743 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
5744
5745 /* again, to test the cache */
5746 ret.clear();
5747 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5748 BOOST_CHECK_EQUAL(res, RCode::NoError);
5749 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5750 BOOST_REQUIRE_EQUAL(ret.size(), 6);
e4894ce0 5751 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
5752}
5753
b7c40613
RG
5754BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5755 std::unique_ptr<SyncRes> sr;
5756 initSR(sr, true);
5757
5758 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5759
5760 primeHints();
5761 const DNSName target("www.powerdns.com.");
5762 testkeysset_t keys;
5763
5764 auto luaconfsCopy = g_luaconfs.getCopy();
5765 luaconfsCopy.dsAnchors.clear();
5766 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5767 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5768 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5769
5770 g_luaconfs.setState(luaconfsCopy);
5771
5772 size_t queriesCount = 0;
5773
0bd2e252 5774 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
5775 queriesCount++;
5776
5777 if (type == QType::DS || type == QType::DNSKEY) {
5778 if (type == QType::DS && domain == target) {
5779 setLWResult(res, RCode::NoError, true, false, true);
5780 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5781 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5782 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5783 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5784 return 1;
5785 }
5786 else {
5787 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5788 }
5789 }
5790 else {
5791 if (isRootServer(ip)) {
5792 setLWResult(res, 0, false, false, true);
5793 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5794 addDS(DNSName("com."), 300, res->d_records, keys);
5795 addRRSIG(keys, res->d_records, DNSName("."), 300);
5796 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5797 return 1;
5798 }
5799 else if (ip == ComboAddress("192.0.2.1:53")) {
5800 if (domain == DNSName("com.")) {
5801 setLWResult(res, 0, true, false, true);
5802 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5803 addRRSIG(keys, res->d_records, domain, 300);
5804 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5805 addRRSIG(keys, res->d_records, domain, 300);
5806 }
5807 else {
5808 setLWResult(res, 0, false, false, true);
5809 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5810 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5811 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5812 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5813 }
5814 return 1;
5815 }
5816 else if (ip == ComboAddress("192.0.2.2:53")) {
5817 setLWResult(res, 0, true, false, true);
5818 if (type == QType::NS) {
5819 if (domain == DNSName("powerdns.com.")) {
5820 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5821 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5822 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5823 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5824 }
5825 else {
5826 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5827 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5828 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5829 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5830 }
5831 }
5832 else {
5833 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5834 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5835 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5836 /* first the closest encloser */
5837 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5838 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5839 /* then the next closer */
5840 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5841 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5842 }
5843 return 1;
5844 }
5845 }
5846
5847 return 0;
5848 });
5849
5850 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5851 we should end up Insecure */
5852 vector<DNSRecord> ret;
5853 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5854 BOOST_CHECK_EQUAL(res, RCode::NoError);
5855 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5856 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5857 BOOST_CHECK_EQUAL(queriesCount, 9);
5858
5859 /* again, to test the cache */
5860 ret.clear();
5861 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5862 BOOST_CHECK_EQUAL(res, RCode::NoError);
5863 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5864 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5865 BOOST_CHECK_EQUAL(queriesCount, 9);
5866}
5867
9b061cf5
RG
5868BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5869 std::unique_ptr<SyncRes> sr;
5870 initSR(sr, true);
5871
5872 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5873
5874 primeHints();
5875 const DNSName target("www.powerdns.com.");
5876 testkeysset_t keys;
5877
5878 auto luaconfsCopy = g_luaconfs.getCopy();
5879 luaconfsCopy.dsAnchors.clear();
5880 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5881 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5882 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5883
5884 g_luaconfs.setState(luaconfsCopy);
5885
5886 size_t queriesCount = 0;
5887
0bd2e252 5888 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
5889 queriesCount++;
5890
5891 if (type == QType::DS || type == QType::DNSKEY) {
5892 if (type == QType::DS && domain == target) {
5893 setLWResult(res, RCode::NoError, true, false, true);
5894 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5895 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5896 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5897 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5898 return 1;
5899 }
5900 else {
5901 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5902 }
5903 }
5904 else {
5905 if (isRootServer(ip)) {
5906 setLWResult(res, 0, false, false, true);
5907 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5908 addDS(DNSName("com."), 300, res->d_records, keys);
5909 addRRSIG(keys, res->d_records, DNSName("."), 300);
5910 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5911 return 1;
5912 }
5913 else if (ip == ComboAddress("192.0.2.1:53")) {
5914 if (domain == DNSName("com.")) {
5915 setLWResult(res, 0, true, false, true);
5916 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5917 addRRSIG(keys, res->d_records, domain, 300);
5918 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5919 addRRSIG(keys, res->d_records, domain, 300);
5920 }
5921 else {
5922 setLWResult(res, 0, false, false, true);
5923 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5924 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5925 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5926 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5927 }
5928 return 1;
5929 }
5930 else if (ip == ComboAddress("192.0.2.2:53")) {
5931 setLWResult(res, 0, true, false, true);
5932 if (type == QType::NS) {
5933 if (domain == DNSName("powerdns.com.")) {
5934 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5935 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5936 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5937 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5938 }
5939 else {
5940 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5941 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5942 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5943 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5944 }
5945 }
5946 else {
5947 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5948 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5949 }
5950 return 1;
5951 }
5952 }
5953
5954 return 0;
5955 });
5956
5957 vector<DNSRecord> ret;
5958 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5959 BOOST_CHECK_EQUAL(res, RCode::NoError);
5960 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5961 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5962 BOOST_CHECK_EQUAL(queriesCount, 9);
5963
5964 /* again, to test the cache */
5965 ret.clear();
5966 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5967 BOOST_CHECK_EQUAL(res, RCode::NoError);
5968 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5969 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5970 BOOST_CHECK_EQUAL(queriesCount, 9);
5971}
5972
a53e8fe3
RG
5973BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5974 std::unique_ptr<SyncRes> sr;
5975 initSR(sr, true);
5976
0c43f455 5977 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
5978
5979 primeHints();
5980 const DNSName target("www.powerdns.com.");
5981 testkeysset_t keys;
5982
5983 auto luaconfsCopy = g_luaconfs.getCopy();
5984 luaconfsCopy.dsAnchors.clear();
5985 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5986 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5987 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5988
5989 g_luaconfs.setState(luaconfsCopy);
5990
5991 size_t queriesCount = 0;
5992 size_t dsQueriesCount = 0;
5993
0bd2e252 5994 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
5995 queriesCount++;
5996
5997 if (type == QType::DS) {
5998 DNSName auth(domain);
5999 auth.chopOff();
6000 dsQueriesCount++;
6001
6002 setLWResult(res, 0, true, false, true);
6003 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6004 addRRSIG(keys, res->d_records, auth, 300);
6005 return 1;
6006 }
6007 else if (type == QType::DNSKEY) {
6008 setLWResult(res, 0, true, false, true);
6009 addDNSKEY(keys, domain, 300, res->d_records);
6010 addRRSIG(keys, res->d_records, domain, 300);
6011 return 1;
6012 }
f24465e5 6013 else {
a53e8fe3
RG
6014 if (isRootServer(ip)) {
6015 setLWResult(res, 0, false, false, true);
6016 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6017 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6018 /* No DS on referral, and no denial of the DS either */
6019 return 1;
6020 }
6021 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
6022 if (domain == DNSName("com.")) {
6023 setLWResult(res, 0, true, false, true);
6024 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6025 addRRSIG(keys, res->d_records, domain, 300);
6026 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6027 addRRSIG(keys, res->d_records, domain, 300);
6028 }
6029 else {
6030 setLWResult(res, 0, false, false, true);
6031 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6032 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6033 /* No DS on referral, and no denial of the DS either */
6034 }
a53e8fe3
RG
6035 return 1;
6036 }
6037 else if (ip == ComboAddress("192.0.2.2:53")) {
6038 setLWResult(res, 0, true, false, true);
f24465e5
RG
6039 if (type == QType::NS) {
6040 if (domain == DNSName("powerdns.com.")) {
6041 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6042 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6043 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6044 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6045 }
6046 else {
6047 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6048 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6049 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
6050 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6051 }
6052 }
6053 else {
6054 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6055 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
6056 }
6057
a53e8fe3
RG
6058 return 1;
6059 }
6060 }
6061
6062 return 0;
6063 });
6064
6065 vector<DNSRecord> ret;
6066 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6067 BOOST_CHECK_EQUAL(res, RCode::NoError);
6068 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 6069 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
6070 BOOST_CHECK_EQUAL(queriesCount, 9);
6071 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
6072
6073 /* again, to test the cache */
6074 ret.clear();
6075 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6076 BOOST_CHECK_EQUAL(res, RCode::NoError);
6077 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 6078 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
6079 BOOST_CHECK_EQUAL(queriesCount, 9);
6080 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
6081}
6082
f715542c
RG
6083BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
6084 std::unique_ptr<SyncRes> sr;
6085 initSR(sr, true);
6086
5d7b19c5 6087 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
f715542c
RG
6088
6089 primeHints();
6090 const DNSName target("www.powerdns.com.");
6091 testkeysset_t keys;
6092
6093 auto luaconfsCopy = g_luaconfs.getCopy();
6094 luaconfsCopy.dsAnchors.clear();
6095 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6096 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3cef03e9 6097 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
f715542c
RG
6098 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6099
6100 g_luaconfs.setState(luaconfsCopy);
6101
6102 size_t queriesCount = 0;
6103
0bd2e252 6104 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
6105 queriesCount++;
6106
6107 if (type == QType::DS) {
6108 DNSName auth(domain);
6109 auth.chopOff();
6110
6111 setLWResult(res, 0, true, false, true);
6112 if (domain == target) {
6113 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6114 addRRSIG(keys, res->d_records, target, 300);
6115 }
6116 else {
6117 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6118 addRRSIG(keys, res->d_records, auth, 300);
6119 }
6120 return 1;
6121 }
6122 else if (type == QType::DNSKEY) {
6123 setLWResult(res, 0, true, false, true);
6124 addDNSKEY(keys, domain, 300, res->d_records);
6125 addRRSIG(keys, res->d_records, domain, 300);
6126 return 1;
6127 }
6128 else {
6129 if (isRootServer(ip)) {
6130 setLWResult(res, 0, false, false, true);
6131 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6132 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6133 addDS(DNSName("com."), 300, res->d_records, keys);
6134 addRRSIG(keys, res->d_records, DNSName("."), 300);
6135 return 1;
6136 }
6137 else if (ip == ComboAddress("192.0.2.1:53")) {
6138 if (domain == DNSName("com.")) {
6139 setLWResult(res, 0, true, false, true);
6140 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6141 addRRSIG(keys, res->d_records, domain, 300);
6142 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6143 addRRSIG(keys, res->d_records, domain, 300);
6144 }
6145 else {
6146 setLWResult(res, 0, false, false, true);
6147 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6148 /* no DS */
6149 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6150 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6151 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6152 }
6153 return 1;
6154 }
6155 else if (ip == ComboAddress("192.0.2.2:53")) {
6156 if (type == QType::NS) {
6157 if (domain == DNSName("powerdns.com.")) {
6158 setLWResult(res, RCode::Refused, false, false, true);
6159 }
6160 else {
6161 setLWResult(res, 0, true, false, true);
6162 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6163 addRRSIG(keys, res->d_records, domain, 300);
6164 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6165 addRRSIG(keys, res->d_records, domain, 300);
6166 }
6167 }
6168 else {
6169 setLWResult(res, 0, true, false, true);
6170 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6171 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
6172 }
6173
6174 return 1;
6175 }
6176 }
6177
6178 return 0;
6179 });
6180
6181 vector<DNSRecord> ret;
6182 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6183 BOOST_CHECK_EQUAL(res, RCode::NoError);
6184 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6185 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6186 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6187
6188 /* again, to test the cache */
6189 ret.clear();
6190 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6191 BOOST_CHECK_EQUAL(res, RCode::NoError);
6192 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6193 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6194 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6195}
6196
8d2e7fa1
RG
6197BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) {
6198 /* check that we don't accept a signer below us */
6199 std::unique_ptr<SyncRes> sr;
6200 initSR(sr, true);
6201
6202 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6203
6204 primeHints();
6205 const DNSName target("www.powerdns.com.");
6206 testkeysset_t keys;
6207
6208 auto luaconfsCopy = g_luaconfs.getCopy();
6209 luaconfsCopy.dsAnchors.clear();
6210 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6211 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6212 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6213 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6214 generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6215
6216 g_luaconfs.setState(luaconfsCopy);
6217
6218 size_t queriesCount = 0;
6219
0bd2e252 6220 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
6221 queriesCount++;
6222
6223 if (type == QType::DS) {
6224 DNSName auth(domain);
6225 auth.chopOff();
6226
6227 setLWResult(res, 0, true, false, true);
6228 if (domain == target) {
6229 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6230 addRRSIG(keys, res->d_records, target, 300);
6231 }
6232 else {
6233 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6234 addRRSIG(keys, res->d_records, auth, 300);
6235 }
6236 return 1;
6237 }
6238 else if (type == QType::DNSKEY) {
6239 setLWResult(res, 0, true, false, true);
6240 addDNSKEY(keys, domain, 300, res->d_records);
6241 if (domain == DNSName("www.powerdns.com.")) {
6242 addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
6243 }
6244 else {
6245 addRRSIG(keys, res->d_records, domain, 300);
6246 }
6247 return 1;
6248 }
6249 else {
6250 if (isRootServer(ip)) {
6251 setLWResult(res, 0, false, false, true);
6252 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6253 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6254 addDS(DNSName("com."), 300, res->d_records, keys);
6255 addRRSIG(keys, res->d_records, DNSName("."), 300);
6256 return 1;
6257 }
6258 else if (ip == ComboAddress("192.0.2.1:53")) {
6259 if (domain == DNSName("com.")) {
6260 setLWResult(res, 0, true, false, true);
6261 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6262 addRRSIG(keys, res->d_records, domain, 300);
6263 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6264 addRRSIG(keys, res->d_records, domain, 300);
6265 }
6266 else {
6267 setLWResult(res, 0, false, false, true);
6268 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6269 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6270 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6271 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6272 }
6273 return 1;
6274 }
6275 else if (ip == ComboAddress("192.0.2.2:53")) {
6276 if (type == QType::NS) {
6277 setLWResult(res, 0, true, false, true);
6278 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6279 addRRSIG(keys, res->d_records, domain, 300);
6280 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6281 addRRSIG(keys, res->d_records, domain, 300);
6282 }
6283 else {
6284 setLWResult(res, 0, true, false, true);
6285 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6286 addRRSIG(keys, res->d_records, domain, 300);
6287 }
6288
6289 return 1;
6290 }
6291 }
6292
f715542c
RG
6293 return 0;
6294 });
6295
6296 vector<DNSRecord> ret;
6297 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6298 BOOST_CHECK_EQUAL(res, RCode::NoError);
6299 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6300 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6301 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6302
6303 /* again, to test the cache */
6304 ret.clear();
6305 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6306 BOOST_CHECK_EQUAL(res, RCode::NoError);
6307 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6308 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6309 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6310}
6311
a53e8fe3
RG
6312BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
6313 std::unique_ptr<SyncRes> sr;
f24465e5 6314 initSR(sr, true);
a53e8fe3 6315
0c43f455 6316 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
6317
6318 primeHints();
6319 const DNSName target("www.powerdns.com.");
6320 testkeysset_t keys;
6321
6322 auto luaconfsCopy = g_luaconfs.getCopy();
6323 luaconfsCopy.dsAnchors.clear();
6324 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6325 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6326
6327 g_luaconfs.setState(luaconfsCopy);
6328
6329 size_t queriesCount = 0;
6330 size_t dsQueriesCount = 0;
6331
0bd2e252 6332 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
6333 queriesCount++;
6334
6335 if (type == QType::DS) {
6336 DNSName auth(domain);
6337 auth.chopOff();
6338 dsQueriesCount++;
6339
6340 setLWResult(res, 0, true, false, true);
6341 if (domain == DNSName("com.")) {
6342 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6343 }
6344 else {
f24465e5
RG
6345 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6346 addRRSIG(keys, res->d_records, DNSName("com."), 300);
a53e8fe3
RG
6347 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
6348 }
6349 addRRSIG(keys, res->d_records, auth, 300);
6350 return 1;
6351 }
6352 else if (type == QType::DNSKEY) {
6353 setLWResult(res, 0, true, false, true);
6354 addDNSKEY(keys, domain, 300, res->d_records);
6355 addRRSIG(keys, res->d_records, domain, 300);
6356 return 1;
6357 }
a69867f2 6358 else {
a53e8fe3
RG
6359 if (isRootServer(ip)) {
6360 setLWResult(res, 0, false, false, true);
6361 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6362 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6363 /* No DS on referral, and no denial of the DS either */
6364 return 1;
6365 }
6366 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6367 if (domain == DNSName("com.")) {
6368 setLWResult(res, 0, true, false, true);
6369 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
f24465e5 6370 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 6371 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
f24465e5 6372 addRRSIG(keys, res->d_records, domain, 300);
a69867f2
RG
6373 }
6374 else {
6375 setLWResult(res, 0, false, false, true);
6376 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6377 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6378 /* No DS on referral, and no denial of the DS either */
6379 }
a53e8fe3
RG
6380 return 1;
6381 }
6382 else if (ip == ComboAddress("192.0.2.2:53")) {
6383 setLWResult(res, 0, true, false, true);
f24465e5
RG
6384 if (type == QType::NS) {
6385 if (domain == DNSName("powerdns.com.")) {
6386 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6387 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6388 }
6389 else {
6390 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6391 }
6392 }
6393 else {
6394 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6395 }
a53e8fe3
RG
6396 return 1;
6397 }
6398 }
6399
6400 return 0;
6401 });
6402
6403 vector<DNSRecord> ret;
6404 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6405 BOOST_CHECK_EQUAL(res, RCode::NoError);
6406 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6407 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6408 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6409 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6410
6411 /* again, to test the cache */
6412 ret.clear();
6413 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6414 BOOST_CHECK_EQUAL(res, RCode::NoError);
6415 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6416 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6417 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6418 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6419}
6420
e59c8907 6421BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
b7f378d1 6422 std::unique_ptr<SyncRes> sr;
895449a5 6423 initSR(sr, true);
b7f378d1 6424
0c43f455 6425 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6426
6427 primeHints();
6428 const DNSName target("powerdns.com.");
6429 testkeysset_t keys;
6430
6431 auto luaconfsCopy = g_luaconfs.getCopy();
6432 luaconfsCopy.dsAnchors.clear();
6433 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6434 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6435 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6436
6437 g_luaconfs.setState(luaconfsCopy);
6438
6439 size_t queriesCount = 0;
6440
0bd2e252 6441 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
6442 queriesCount++;
6443
5374b03b
RG
6444 if (type == QType::DS || type == QType::DNSKEY) {
6445 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6446 }
a69867f2 6447 else {
b7f378d1
RG
6448 if (isRootServer(ip)) {
6449 setLWResult(res, 0, false, false, true);
6450 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6451 addDS(DNSName("com."), 300, res->d_records, keys);
6452 addRRSIG(keys, res->d_records, DNSName("."), 300);
6453 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6454 return 1;
6455 }
6456 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6457 if (domain == DNSName("com.")) {
6458 setLWResult(res, 0, true, false, true);
6459 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6460 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6461 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6462 }
6463 else {
6464 setLWResult(res, 0, false, false, true);
6465 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6466 addDS(domain, 300, res->d_records, keys);
6467 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6468 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6469 }
b7f378d1
RG
6470 return 1;
6471 }
6472 else if (ip == ComboAddress("192.0.2.2:53")) {
6473 setLWResult(res, 0, true, false, true);
a69867f2
RG
6474 if (type == QType::NS) {
6475 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6476 addRRSIG(keys, res->d_records, domain, 300);
6477 }
6478 else {
6479 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6480 addRRSIG(keys, res->d_records, domain, 300);
6481 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
6482 /* NO RRSIG for the NSEC record! */
6483 }
b7f378d1
RG
6484 return 1;
6485 }
6486 }
6487
6488 return 0;
6489 });
6490
6491 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
6492 vector<DNSRecord> ret;
6493 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6494 BOOST_CHECK_EQUAL(res, RCode::NoError);
6495 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6496 BOOST_CHECK_EQUAL(ret.size(), 3);
a69867f2 6497 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6498
6499 /* again, to test the cache */
6500 ret.clear();
6501 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6502 BOOST_CHECK_EQUAL(res, RCode::NoError);
6503 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6504 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 6505 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6506}
6507
e59c8907 6508BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
b7f378d1 6509 std::unique_ptr<SyncRes> sr;
895449a5 6510 initSR(sr, true);
b7f378d1 6511
0c43f455 6512 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6513
6514 primeHints();
6515 const DNSName target("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
6524 g_luaconfs.setState(luaconfsCopy);
6525
6526 size_t queriesCount = 0;
6527
0bd2e252 6528 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
6529 queriesCount++;
6530
5374b03b
RG
6531 if (type == QType::DS || type == QType::DNSKEY) {
6532 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6533 }
a69867f2 6534 else {
b7f378d1
RG
6535 if (isRootServer(ip)) {
6536 setLWResult(res, 0, false, false, true);
6537 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6538 addDS(DNSName("com."), 300, res->d_records, keys);
6539 addRRSIG(keys, res->d_records, DNSName("."), 300);
6540 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6541 return 1;
6542 }
6543 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6544 if (domain == DNSName("com.")) {
6545 setLWResult(res, 0, true, false, true);
6546 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6547 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6548 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6549 }
6550 else {
6551 setLWResult(res, 0, false, false, true);
6552 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6553 addDS(domain, 300, res->d_records, keys);
6554 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6555 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6556 }
b7f378d1
RG
6557 return 1;
6558 }
6559 else if (ip == ComboAddress("192.0.2.2:53")) {
6560 setLWResult(res, 0, true, false, true);
a69867f2
RG
6561 if (type == QType::NS) {
6562 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6563 addRRSIG(keys, res->d_records, domain, 300);
6564 }
6565 else {
6566 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6567 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 6568
a69867f2
RG
6569 /* NO NSEC record! */
6570 }
b7f378d1
RG
6571 return 1;
6572 }
6573 }
6574
6575 return 0;
6576 });
6577
6578 /* no NSEC record in a secure zone, should be Bogus! */
6579 vector<DNSRecord> ret;
6580 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6581 BOOST_CHECK_EQUAL(res, RCode::NoError);
6582 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6583 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 6584 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6585
6586 /* again, to test the cache */
6587 ret.clear();
6588 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6589 BOOST_CHECK_EQUAL(res, RCode::NoError);
6590 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6591 BOOST_REQUIRE_EQUAL(ret.size(), 2);
a69867f2 6592 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6593}
6594
6595BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6596 std::unique_ptr<SyncRes> sr;
895449a5 6597 initSR(sr, true);
b7f378d1 6598
0c43f455 6599 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6600
6601 primeHints();
6602 const DNSName target("powerdns.com.");
6603 const ComboAddress targetAddr("192.0.2.42");
6604 testkeysset_t keys;
6605
6606 auto luaconfsCopy = g_luaconfs.getCopy();
6607 luaconfsCopy.dsAnchors.clear();
6608 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6609 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6610
6611 g_luaconfs.setState(luaconfsCopy);
6612
6613 size_t queriesCount = 0;
6614
0bd2e252 6615 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
6616 queriesCount++;
6617
6618 if (type == QType::DS) {
a53e8fe3 6619 if (domain == target) {
b7f378d1 6620 setLWResult(res, 0, false, false, true);
895449a5 6621 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6622 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6623 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6624 return 1;
5374b03b
RG
6625 } else {
6626 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1
RG
6627 }
6628 }
6629 else if (type == QType::DNSKEY) {
6630 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6631 setLWResult(res, 0, true, false, true);
6632 addDNSKEY(keys, domain, 300, res->d_records);
6633 addRRSIG(keys, res->d_records, domain, 300);
6634 return 1;
6635 }
6636 else {
6637 setLWResult(res, 0, false, false, true);
895449a5 6638 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6639 return 1;
6640 }
6641 }
a69867f2 6642 else {
b7f378d1
RG
6643 if (isRootServer(ip)) {
6644 setLWResult(res, 0, false, false, true);
6645 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6646 addDS(DNSName("com."), 300, res->d_records, keys);
6647 addRRSIG(keys, res->d_records, DNSName("."), 300);
6648 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6649 return 1;
6650 }
6651 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6652 if (domain == DNSName("com.")) {
6653 setLWResult(res, 0, true, false, true);
6654 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6655 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6656 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6657 }
6658 else {
6659 setLWResult(res, 0, false, false, true);
6660 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6661 /* no DS */
6662 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6663 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6664 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6665 }
b7f378d1
RG
6666 return 1;
6667 }
6668 else if (ip == ComboAddress("192.0.2.2:53")) {
6669 setLWResult(res, 0, true, false, true);
a69867f2
RG
6670 if (type == QType::NS) {
6671 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6672 }
6673 else {
6674 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6675 }
b7f378d1
RG
6676 return 1;
6677 }
6678 }
6679
6680 return 0;
6681 });
6682
6683 vector<DNSRecord> ret;
6684 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6685 BOOST_CHECK_EQUAL(res, RCode::NoError);
6686 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6687 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6688 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2
RG
6689 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6690 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6691 1 query for A */
6692 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6693
6694 /* again, to test the cache */
6695 ret.clear();
6696 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6697 BOOST_CHECK_EQUAL(res, RCode::NoError);
6698 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6699 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6700 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2 6701 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6702}
6703
3cef03e9
RG
6704
6705BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6706 /*
6707 Direct DS query:
6708 - parent is secure, zone is secure: DS should be secure
6709 */
6710 std::unique_ptr<SyncRes> sr;
6711 initSR(sr, true);
6712
6713 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6714
6715 primeHints();
6716 const DNSName target("powerdns.com.");
6717 testkeysset_t keys;
6718
6719 auto luaconfsCopy = g_luaconfs.getCopy();
6720 luaconfsCopy.dsAnchors.clear();
6721 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6722 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6723 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6724
6725 g_luaconfs.setState(luaconfsCopy);
6726
6727 size_t queriesCount = 0;
6728
0bd2e252 6729 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
6730 queriesCount++;
6731
6732 if (type == QType::DS || type == QType::DNSKEY) {
6733 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6734 }
6735 else {
6736 if (isRootServer(ip)) {
6737 setLWResult(res, 0, false, false, true);
6738 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6739 addDS(DNSName("com."), 300, res->d_records, keys);
6740 addRRSIG(keys, res->d_records, DNSName("."), 300);
6741 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6742 return 1;
6743 }
6744 }
6745
6746 return 0;
6747 });
6748
6749 vector<DNSRecord> ret;
6750 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6751 BOOST_CHECK_EQUAL(res, RCode::NoError);
6752 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6753 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6754 for (const auto& record : ret) {
6755 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6756 }
6757 BOOST_CHECK_EQUAL(queriesCount, 4);
6758
6759 /* again, to test the cache */
6760 ret.clear();
6761 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6762 BOOST_CHECK_EQUAL(res, RCode::NoError);
6763 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6764 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6765 for (const auto& record : ret) {
6766 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6767 }
6768 BOOST_CHECK_EQUAL(queriesCount, 4);
6769}
6770
6771BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6772 /*
6773 Direct DS query:
6774 - parent is secure, zone is insecure: DS denial should be secure
6775 */
6776 std::unique_ptr<SyncRes> sr;
6777 initSR(sr, true);
6778
6779 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6780
6781 primeHints();
6782 const DNSName target("powerdns.com.");
6783 testkeysset_t keys;
6784
6785 auto luaconfsCopy = g_luaconfs.getCopy();
6786 luaconfsCopy.dsAnchors.clear();
6787 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6788 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6789
6790 g_luaconfs.setState(luaconfsCopy);
6791
6792 size_t queriesCount = 0;
6793
0bd2e252 6794 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
6795 queriesCount++;
6796
6797 if (type == QType::DS || type == QType::DNSKEY) {
6798 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6799 }
6800 else {
6801 if (isRootServer(ip)) {
6802 setLWResult(res, 0, false, false, true);
6803 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6804 addDS(DNSName("com."), 300, res->d_records, keys);
6805 addRRSIG(keys, res->d_records, DNSName("."), 300);
6806 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6807 return 1;
6808 }
6809 }
6810
6811 return 0;
6812 });
6813
6814 vector<DNSRecord> ret;
6815 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6816 BOOST_CHECK_EQUAL(res, RCode::NoError);
6817 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6818 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6819 for (const auto& record : ret) {
6820 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6821 }
6822 BOOST_CHECK_EQUAL(queriesCount, 4);
6823
6824 /* again, to test the cache */
6825 ret.clear();
6826 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6827 BOOST_CHECK_EQUAL(res, RCode::NoError);
6828 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6829 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6830 for (const auto& record : ret) {
6831 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6832 }
6833 BOOST_CHECK_EQUAL(queriesCount, 4);
6834}
6835
70b3fe7a
RG
6836BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6837 std::unique_ptr<SyncRes> sr;
a69867f2 6838 initSR(sr, true);
70b3fe7a 6839
0c43f455 6840 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6841
6842 primeHints();
6843 const DNSName target("www.sub.powerdns.com.");
6844 const ComboAddress targetAddr("192.0.2.42");
6845 testkeysset_t keys;
6846
6847 auto luaconfsCopy = g_luaconfs.getCopy();
6848 luaconfsCopy.dsAnchors.clear();
6849 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6850 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6851 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6852
6853 g_luaconfs.setState(luaconfsCopy);
6854
6855 size_t queriesCount = 0;
6856
0bd2e252 6857 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
6858 queriesCount++;
6859
6860 if (type == QType::DS) {
6861 if (domain == DNSName("sub.powerdns.com.")) {
6862 setLWResult(res, 0, false, false, true);
6863 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6864 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6865 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6866 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6867 return 1;
6868 }
6869 else if (domain == DNSName("www.sub.powerdns.com.")) {
6870 setLWResult(res, 0, false, false, true);
6871 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);
6872 return 1;
6873 }
5374b03b
RG
6874 else {
6875 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6876 }
70b3fe7a
RG
6877 }
6878 else if (type == QType::DNSKEY) {
a69867f2 6879 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
70b3fe7a
RG
6880 setLWResult(res, 0, true, false, true);
6881 addDNSKEY(keys, domain, 300, res->d_records);
6882 addRRSIG(keys, res->d_records, domain, 300);
6883 return 1;
6884 }
6885 else {
6886 setLWResult(res, 0, false, false, true);
6887 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6888 return 1;
6889 }
6890 }
88cb0fe0 6891 else {
70b3fe7a
RG
6892 if (isRootServer(ip)) {
6893 setLWResult(res, 0, false, false, true);
6894 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6895 addDS(DNSName("com."), 300, res->d_records, keys);
6896 addRRSIG(keys, res->d_records, DNSName("."), 300);
6897 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6898 return 1;
6899 }
6900 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6901 if (domain == DNSName("com.")) {
6902 setLWResult(res, 0, true, false, true);
6903 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6904 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6905 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6906 }
6907 else {
6908 setLWResult(res, 0, false, false, true);
6909 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6910 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6911 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6912 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6913 }
70b3fe7a
RG
6914 return 1;
6915 }
6916 else if (ip == ComboAddress("192.0.2.2:53")) {
6917 setLWResult(res, 0, true, false, true);
a69867f2
RG
6918 if (type == QType::NS) {
6919 if (domain == DNSName("www.sub.powerdns.com.")) {
6920 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);
6921 }
6922 else if (domain == DNSName("sub.powerdns.com.")) {
6923 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
a69867f2
RG
6924 }
6925 else if (domain == DNSName("powerdns.com.")) {
6926 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6927 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6928 }
6929 } else {
6930 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6931 }
70b3fe7a
RG
6932 return 1;
6933 }
6934 }
6935
6936 return 0;
6937 });
6938
6939 vector<DNSRecord> ret;
6940 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6941 BOOST_CHECK_EQUAL(res, RCode::NoError);
6942 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6943 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6944 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6945 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6946
6947 /* again, to test the cache */
6948 ret.clear();
6949 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6950 BOOST_CHECK_EQUAL(res, RCode::NoError);
6951 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6952 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6953 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6954 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6955}
6956
6957BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6958 std::unique_ptr<SyncRes> sr;
a69867f2 6959 initSR(sr, true);
70b3fe7a 6960
0c43f455 6961 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6962
6963 primeHints();
6964 const DNSName target("www.sub.powerdns.com.");
6965 const ComboAddress targetAddr("192.0.2.42");
6966 testkeysset_t keys;
6967
6968 auto luaconfsCopy = g_luaconfs.getCopy();
6969 luaconfsCopy.dsAnchors.clear();
6970 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6971 /* No key material for .com */
6972 /* But TA for sub.powerdns.com. */
6973 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6974 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6975 g_luaconfs.setState(luaconfsCopy);
6976
6977 size_t queriesCount = 0;
6978
0bd2e252 6979 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
6980 queriesCount++;
6981
6982 if (type == QType::DS) {
88cb0fe0
RG
6983 if (domain == DNSName("www.sub.powerdns.com")) {
6984 setLWResult(res, 0, false, false, true);
6985 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);
6986 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6987 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6988 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6989 }
6990 else {
6991 setLWResult(res, 0, false, false, true);
5374b03b
RG
6992
6993 if (domain == DNSName("com.")) {
6994 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6995 /* no DS */
6996 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6997 addRRSIG(keys, res->d_records, DNSName("."), 300);
6998 }
6999 else {
7000 setLWResult(res, 0, false, false, true);
7001 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7002 }
88cb0fe0 7003 }
70b3fe7a
RG
7004 return 1;
7005 }
7006 else if (type == QType::DNSKEY) {
7007 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
7008 setLWResult(res, 0, true, false, true);
7009 addDNSKEY(keys, domain, 300, res->d_records);
7010 addRRSIG(keys, res->d_records, domain, 300);
7011 return 1;
7012 }
7013 }
88cb0fe0 7014 else {
70b3fe7a
RG
7015 if (isRootServer(ip)) {
7016 setLWResult(res, 0, false, false, true);
7017 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7018 /* no DS */
7019 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
7020 addRRSIG(keys, res->d_records, DNSName("."), 300);
7021 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7022 return 1;
7023 }
7024 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7025 if (domain == DNSName("com.")) {
7026 setLWResult(res, 0, true, false, true);
7027 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
7028 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7029 }
5374b03b 7030 else if (domain.isPartOf(DNSName("powerdns.com."))) {
88cb0fe0
RG
7031 setLWResult(res, 0, false, false, true);
7032 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7033 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7034 }
70b3fe7a
RG
7035 return 1;
7036 }
7037 else if (ip == ComboAddress("192.0.2.2:53")) {
7038 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7039 if (type == QType::NS) {
7040 if (domain == DNSName("www.sub.powerdns.com.")) {
7041 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);
7042 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7043 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
7044 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
7045 }
7046 else if (domain == DNSName("sub.powerdns.com.")) {
7047 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7048 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
7049 }
7050 else if (domain == DNSName("powerdns.com.")) {
7051 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7052 }
7053 }
7054 else if (domain == DNSName("www.sub.powerdns.com.")) {
7055 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7056 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
7057 }
70b3fe7a
RG
7058 return 1;
7059 }
7060 }
7061
7062 return 0;
7063 });
7064
7065 vector<DNSRecord> ret;
7066 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7067 BOOST_CHECK_EQUAL(res, RCode::NoError);
7068 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 7069 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 7070 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7071 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
7072
7073 /* again, to test the cache */
7074 ret.clear();
7075 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7076 BOOST_CHECK_EQUAL(res, RCode::NoError);
7077 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 7078 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 7079 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7080 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
7081}
7082
b7f378d1
RG
7083BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
7084 std::unique_ptr<SyncRes> sr;
895449a5 7085 initSR(sr, true);
b7f378d1 7086
0c43f455 7087 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
7088
7089 primeHints();
7090 const DNSName target("powerdns.com.");
7091 testkeysset_t keys;
7092
7093 auto luaconfsCopy = g_luaconfs.getCopy();
7094 luaconfsCopy.dsAnchors.clear();
7095 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7096 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7097
7098 g_luaconfs.setState(luaconfsCopy);
7099
7100 size_t queriesCount = 0;
7101
0bd2e252 7102 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
7103 queriesCount++;
7104
7105 if (type == QType::DS) {
a53e8fe3 7106 if (domain == target) {
b7f378d1 7107 setLWResult(res, 0, false, false, true);
895449a5 7108 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
7109 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7110 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7111 return 1;
7112 }
5374b03b
RG
7113 else {
7114 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7115 }
b7f378d1
RG
7116 }
7117 else if (type == QType::DNSKEY) {
7118 if (domain == g_rootdnsname || domain == DNSName("com.")) {
7119 setLWResult(res, 0, true, false, true);
7120 addDNSKEY(keys, domain, 300, res->d_records);
7121 addRRSIG(keys, res->d_records, domain, 300);
7122 return 1;
7123 }
7124 else {
7125 setLWResult(res, 0, false, false, true);
895449a5 7126 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
7127 return 1;
7128 }
7129 }
a69867f2 7130 else {
b7f378d1
RG
7131 if (isRootServer(ip)) {
7132 setLWResult(res, 0, false, false, true);
7133 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7134 addDS(DNSName("com."), 300, res->d_records, keys);
7135 addRRSIG(keys, res->d_records, DNSName("."), 300);
7136 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7137 return 1;
7138 }
7139 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7140 if (domain == DNSName("com.")) {
7141 setLWResult(res, 0, true, false, true);
7142 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7143 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7144 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7145 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7146 }
7147 else {
7148 setLWResult(res, 0, false, false, true);
7149 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7150 /* no DS */
7151 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7152 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7153 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7154 }
b7f378d1
RG
7155 return 1;
7156 }
7157 else if (ip == ComboAddress("192.0.2.2:53")) {
a69867f2
RG
7158 if (type == QType::NS) {
7159 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7160 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7161 }
7162 else {
7163 setLWResult(res, 0, true, false, true);
7164 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7165 }
b7f378d1
RG
7166 return 1;
7167 }
7168 }
7169
7170 return 0;
7171 });
7172
7173 vector<DNSRecord> ret;
7174 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7175 BOOST_CHECK_EQUAL(res, RCode::NoError);
7176 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7177 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2
RG
7178 /* 4 NS (com from root, com from com, powerdns.com from com,
7179 powerdns.com from powerdns.com)
7180 2 DNSKEY (. and com., none for powerdns.com because no DS)
7181 1 query for A
7182 */
7183 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7184
7185 /* again, to test the cache */
7186 ret.clear();
7187 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7188 BOOST_CHECK_EQUAL(res, RCode::NoError);
7189 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7190 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2 7191 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7192}
7193
895449a5 7194BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
b7f378d1 7195 std::unique_ptr<SyncRes> sr;
860d5e8e 7196 initSR(sr, true);
b7f378d1 7197
0c43f455 7198 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1 7199
895449a5
RG
7200 primeHints();
7201 const DNSName target("powerdns.com.");
7202 const DNSName targetCName("power-dns.com.");
7203 const ComboAddress targetCNameAddr("192.0.2.42");
7204 testkeysset_t keys;
7205
7206 auto luaconfsCopy = g_luaconfs.getCopy();
7207 luaconfsCopy.dsAnchors.clear();
7208 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7209 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7210 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7211 g_luaconfs.setState(luaconfsCopy);
7212
7213 size_t queriesCount = 0;
7214
0bd2e252 7215 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
7216 queriesCount++;
7217
7218 if (type == QType::DS) {
5374b03b 7219 if (domain == targetCName) {
895449a5
RG
7220 setLWResult(res, 0, false, false, true);
7221 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7222 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7223 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7224 return 1;
7225 }
5374b03b
RG
7226 else {
7227 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7228 }
895449a5
RG
7229 }
7230 else if (type == QType::DNSKEY) {
7231 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7232 setLWResult(res, 0, true, false, true);
7233 addDNSKEY(keys, domain, 300, res->d_records);
7234 addRRSIG(keys, res->d_records, domain, 300);
7235 return 1;
7236 }
7237 else {
7238 setLWResult(res, 0, false, false, true);
7239 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7240 return 1;
7241 }
7242 }
7243 else {
7244 if (isRootServer(ip)) {
7245 setLWResult(res, 0, false, false, true);
7246 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7247 addDS(DNSName("com."), 300, res->d_records, keys);
7248 addRRSIG(keys, res->d_records, DNSName("."), 300);
7249 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7250 return 1;
7251 }
7252 else if (ip == ComboAddress("192.0.2.1:53")) {
7253 setLWResult(res, 0, false, false, true);
a69867f2
RG
7254 if (domain == DNSName("com.")) {
7255 setLWResult(res, 0, true, false, true);
7256 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7257 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7258 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7259 addRRSIG(keys, res->d_records, DNSName("com."), 300);
895449a5 7260 }
a69867f2
RG
7261 else {
7262 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7263 if (domain == DNSName("powerdns.com.")) {
7264 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7265 }
7266 else if (domain == targetCName) {
7267 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7268 }
7269 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7270 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
895449a5 7271 }
a69867f2 7272
895449a5
RG
7273 return 1;
7274 }
7275 else if (ip == ComboAddress("192.0.2.2:53")) {
7276 setLWResult(res, 0, true, false, true);
a69867f2
RG
7277
7278 if (type == QType::NS) {
7279 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7280 if (domain == DNSName("powerdns.com.")) {
7281 addRRSIG(keys, res->d_records, domain, 300);
7282 }
7283 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7284 if (domain == DNSName("powerdns.com.")) {
7285 addRRSIG(keys, res->d_records, domain, 300);
7286 }
895449a5 7287 }
a69867f2
RG
7288 else {
7289 if (domain == DNSName("powerdns.com.")) {
7290 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7291 addRRSIG(keys, res->d_records, domain, 300);
7292 }
7293 else if (domain == targetCName) {
7294 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7295 }
895449a5 7296 }
a69867f2 7297
895449a5
RG
7298 return 1;
7299 }
7300 }
7301
7302 return 0;
7303 });
7304
7305 vector<DNSRecord> ret;
7306 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7307 BOOST_CHECK_EQUAL(res, RCode::NoError);
7308 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7309 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7310 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7311
7312 /* again, to test the cache */
7313 ret.clear();
7314 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7315 BOOST_CHECK_EQUAL(res, RCode::NoError);
7316 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7317 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7318 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7319}
7320
933299e8
RG
7321BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname_glue) {
7322 std::unique_ptr<SyncRes> sr;
f100caac 7323 initSR(sr, true);
933299e8
RG
7324
7325 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7326
7327 primeHints();
7328 const DNSName target("powerdns.com.");
7329 const DNSName targetCName1("cname.sub.powerdns.com.");
7330 const DNSName targetCName2("cname2.sub.powerdns.com.");
7331 const ComboAddress targetCName2Addr("192.0.2.42");
7332 testkeysset_t keys;
7333
7334 auto luaconfsCopy = g_luaconfs.getCopy();
7335 luaconfsCopy.dsAnchors.clear();
7336 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7337 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7338 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7339 g_luaconfs.setState(luaconfsCopy);
7340
7341 size_t queriesCount = 0;
7342
0bd2e252 7343 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
7344 queriesCount++;
7345
7346 if (type == QType::DS || type == QType::DNSKEY) {
7347 if (domain == DNSName("sub.powerdns.com")) {
7348 setLWResult(res, 0, false, false, true);
7349 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7350 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7351 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7352 return 1;
7353 }
7354 else {
7355 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7356 }
7357 }
7358 else {
7359 if (isRootServer(ip)) {
7360 setLWResult(res, 0, false, false, true);
7361 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7362 addDS(DNSName("com."), 300, res->d_records, keys);
7363 addRRSIG(keys, res->d_records, DNSName("."), 300);
7364 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7365 return 1;
7366 }
7367 else if (ip == ComboAddress("192.0.2.1:53")) {
7368 setLWResult(res, 0, false, false, true);
7369 if (domain == DNSName("com.")) {
7370 setLWResult(res, 0, true, false, true);
7371 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7372 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7373 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7374 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7375 }
7376 else {
7377 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7378 if (domain == DNSName("powerdns.com.")) {
7379 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7380 }
7381 else if (domain == DNSName("sub.powerdns.com")) {
7382 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7383 }
7384 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7385 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7386 }
7387
7388 return 1;
7389 }
7390 else if (ip == ComboAddress("192.0.2.2:53")) {
7391 setLWResult(res, 0, true, false, true);
7392
7393 if (type == QType::NS) {
7394 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7395 if (domain == DNSName("powerdns.com.")) {
7396 addRRSIG(keys, res->d_records, domain, 300);
7397 }
7398 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7399 if (domain == DNSName("powerdns.com.")) {
7400 addRRSIG(keys, res->d_records, domain, 300);
7401 }
7402 }
7403 else {
7404 if (domain == DNSName("powerdns.com.")) {
7405 addRecordToLW(res, domain, QType::CNAME, targetCName1.toString());
7406 addRRSIG(keys, res->d_records, domain, 300);
7407 /* add the CNAME target as a glue, with no RRSIG since the sub zone is insecure */
7408 addRecordToLW(res, targetCName1, QType::CNAME, targetCName2.toString());
7409 addRecordToLW(res, targetCName2, QType::A, targetCName2Addr.toString());
7410 }
7411 else if (domain == targetCName1) {
7412 addRecordToLW(res, domain, QType::CNAME, targetCName2.toString());
7413 }
7414 else if (domain == targetCName2) {
7415 addRecordToLW(res, domain, QType::A, targetCName2Addr.toString());
7416 }
7417 }
7418
7419 return 1;
7420 }
7421 }
7422
7423 return 0;
7424 });
7425
7426 vector<DNSRecord> ret;
7427 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7428 BOOST_CHECK_EQUAL(res, RCode::NoError);
7429 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7430 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7431 BOOST_CHECK_EQUAL(queriesCount, 11);
7432
7433 /* again, to test the cache */
7434 ret.clear();
7435 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7436 BOOST_CHECK_EQUAL(res, RCode::NoError);
7437 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7438 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7439 BOOST_CHECK_EQUAL(queriesCount, 11);
7440}
7441
3d5ebf10
RG
7442BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
7443 std::unique_ptr<SyncRes> sr;
7444 initSR(sr, true);
7445
0c43f455 7446 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7447
7448 primeHints();
7449 const DNSName target("power-dns.com.");
7450 const DNSName targetCName("powerdns.com.");
7451 const ComboAddress targetCNameAddr("192.0.2.42");
7452 testkeysset_t keys;
7453
7454 auto luaconfsCopy = g_luaconfs.getCopy();
7455 luaconfsCopy.dsAnchors.clear();
7456 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7457 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7458 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7459 g_luaconfs.setState(luaconfsCopy);
7460
7461 size_t queriesCount = 0;
7462
0bd2e252 7463 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
7464 queriesCount++;
7465
7466 if (type == QType::DS) {
a53e8fe3 7467 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
7468 setLWResult(res, 0, false, false, true);
7469 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7470 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7471 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7472 return 1;
7473 }
5374b03b
RG
7474 else {
7475 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7476 }
3d5ebf10
RG
7477 }
7478 else if (type == QType::DNSKEY) {
7479 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7480 setLWResult(res, 0, true, false, true);
7481 addDNSKEY(keys, domain, 300, res->d_records);
7482 addRRSIG(keys, res->d_records, domain, 300);
7483 return 1;
7484 }
7485 else {
7486 setLWResult(res, 0, false, false, true);
7487 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7488 return 1;
7489 }
7490 }
7491 else {
7492 if (isRootServer(ip)) {
7493 setLWResult(res, 0, false, false, true);
7494 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7495 addDS(DNSName("com."), 300, res->d_records, keys);
7496 addRRSIG(keys, res->d_records, DNSName("."), 300);
7497 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7498 return 1;
7499 }
7500 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7501 if (domain == DNSName("com.")) {
7502 setLWResult(res, 0, true, false, true);
7503 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7504 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7505 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7506 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7507 }
a69867f2
RG
7508 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7509 setLWResult(res, 0, false, false, true);
7510 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7511 if (domain == targetCName) {
7512 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7513 }
7514 else if (domain == target) {
7515 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7516 }
7517 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7518 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7519 }
3d5ebf10
RG
7520 return 1;
7521 }
7522 else if (ip == ComboAddress("192.0.2.2:53")) {
7523 setLWResult(res, 0, true, false, true);
a69867f2
RG
7524 if (type == QType::NS) {
7525 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7526 if (domain == DNSName("powerdns.com.")) {
7527 addRRSIG(keys, res->d_records, domain, 300);
7528 }
7529 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7530 if (domain == DNSName("powerdns.com.")) {
7531 addRRSIG(keys, res->d_records, domain, 300);
7532 }
3d5ebf10 7533 }
a69867f2
RG
7534 else {
7535 if (domain == target) {
7536 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7537 }
7538 else if (domain == targetCName) {
7539 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7540 addRRSIG(keys, res->d_records, domain, 300);
7541 }
3d5ebf10
RG
7542 }
7543 return 1;
7544 }
7545 }
7546
7547 return 0;
7548 });
7549
7550 vector<DNSRecord> ret;
7551 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7552 BOOST_CHECK_EQUAL(res, RCode::NoError);
7553 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7554 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7555 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7556
7557 /* again, to test the cache */
7558 ret.clear();
7559 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7560 BOOST_CHECK_EQUAL(res, RCode::NoError);
7561 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7562 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7563 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7564}
7565
7566BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
7567 std::unique_ptr<SyncRes> sr;
7568 initSR(sr, true);
7569
0c43f455 7570 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7571
7572 primeHints();
7573 const DNSName target("power-dns.com.");
7574 const DNSName targetCName("powerdns.com.");
7575 const ComboAddress targetCNameAddr("192.0.2.42");
7576 testkeysset_t keys;
7577
7578 auto luaconfsCopy = g_luaconfs.getCopy();
7579 luaconfsCopy.dsAnchors.clear();
7580 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7581 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7582 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7583 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7584 g_luaconfs.setState(luaconfsCopy);
7585
7586 size_t queriesCount = 0;
7587
0bd2e252 7588 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
7589 queriesCount++;
7590
5374b03b
RG
7591 if (type == QType::DS || type == QType::DNSKEY) {
7592 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7593 }
7594 else {
7595 if (isRootServer(ip)) {
7596 setLWResult(res, 0, false, false, true);
7597 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7598 addDS(DNSName("com."), 300, res->d_records, keys);
7599 addRRSIG(keys, res->d_records, DNSName("."), 300);
7600 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7601 return 1;
7602 }
7603 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7604 if (domain == DNSName("com.")) {
7605 setLWResult(res, 0, true, false, true);
7606 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7607 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7608 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7609 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7610 }
7611 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7612 setLWResult(res, 0, false, false, true);
7613 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7614 addDS(DNSName(domain), 300, res->d_records, keys);
7615 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7616 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7617 }
3d5ebf10
RG
7618 return 1;
7619 }
7620 else if (ip == ComboAddress("192.0.2.2:53")) {
7621 setLWResult(res, 0, true, false, true);
a69867f2
RG
7622 if (type == QType::NS) {
7623 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7624 addRRSIG(keys, res->d_records, domain, 300);
7625 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7626 addRRSIG(keys, res->d_records, domain, 300);
7627 }
a69867f2
RG
7628 else {
7629 if (domain == target) {
7630 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7631 /* No RRSIG, leading to bogus */
7632 }
7633 else if (domain == targetCName) {
7634 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7635 addRRSIG(keys, res->d_records, domain, 300);
7636 }
7637 }
3d5ebf10
RG
7638 return 1;
7639 }
7640 }
7641
7642 return 0;
7643 });
7644
7645 vector<DNSRecord> ret;
7646 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7647 BOOST_CHECK_EQUAL(res, RCode::NoError);
7648 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7649 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7650 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7651
7652 /* again, to test the cache */
7653 ret.clear();
7654 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7655 BOOST_CHECK_EQUAL(res, RCode::NoError);
7656 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7657 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7658 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7659}
7660
7661BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7662 std::unique_ptr<SyncRes> sr;
7663 initSR(sr, true);
7664
0c43f455 7665 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7666
7667 primeHints();
7668 const DNSName target("power-dns.com.");
7669 const DNSName targetCName("powerdns.com.");
7670 const ComboAddress targetCNameAddr("192.0.2.42");
7671 testkeysset_t keys;
7672
7673 auto luaconfsCopy = g_luaconfs.getCopy();
7674 luaconfsCopy.dsAnchors.clear();
7675 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7676 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7677 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7678 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7679 g_luaconfs.setState(luaconfsCopy);
7680
7681 size_t queriesCount = 0;
7682
0bd2e252 7683 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
7684 queriesCount++;
7685
5374b03b
RG
7686 if (type == QType::DS || type == QType::DNSKEY) {
7687 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7688 }
7689 else {
7690 if (isRootServer(ip)) {
7691 setLWResult(res, 0, false, false, true);
7692 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7693 addDS(DNSName("com."), 300, res->d_records, keys);
7694 addRRSIG(keys, res->d_records, DNSName("."), 300);
7695 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7696 return 1;
7697 }
7698 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7699 if (domain == DNSName("com.")) {
7700 setLWResult(res, 0, true, false, true);
7701 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7702 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7703 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7704 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7705 }
7706 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7707 setLWResult(res, 0, false, false, true);
7708 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7709 addDS(DNSName(domain), 300, res->d_records, keys);
7710 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7711 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7712 }
3d5ebf10
RG
7713 return 1;
7714 }
7715 else if (ip == ComboAddress("192.0.2.2:53")) {
7716 setLWResult(res, 0, true, false, true);
a69867f2
RG
7717 if (type == QType::NS) {
7718 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7719 addRRSIG(keys, res->d_records, domain, 300);
7720 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7721 addRRSIG(keys, res->d_records, domain, 300);
7722 }
a69867f2
RG
7723 else {
7724 if (domain == target) {
7725 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7726 addRRSIG(keys, res->d_records, domain, 300);
7727 }
7728 else if (domain == targetCName) {
7729 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7730 /* No RRSIG, leading to bogus */
7731 }
3d5ebf10
RG
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(), Bogus);
7744 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7745 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
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(), Bogus);
7752 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7753 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7754}
7755
7756BOOST_AUTO_TEST_CASE(test_dnssec_secure_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 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7774 g_luaconfs.setState(luaconfsCopy);
7775
7776 size_t queriesCount = 0;
7777
0bd2e252 7778 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
7779 queriesCount++;
7780
5374b03b
RG
7781 if (type == QType::DS || type == QType::DNSKEY) {
7782 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7783 }
7784 else {
7785 if (isRootServer(ip)) {
7786 setLWResult(res, 0, false, false, true);
7787 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7788 addDS(DNSName("com."), 300, res->d_records, keys);
7789 addRRSIG(keys, res->d_records, DNSName("."), 300);
7790 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7791 return 1;
7792 }
7793 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7794 if (domain == DNSName("com.")) {
7795 setLWResult(res, 0, true, false, true);
7796 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7797 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7798 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7799 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7800 }
7801 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7802 setLWResult(res, 0, false, false, true);
7803 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7804 addDS(DNSName(domain), 300, res->d_records, keys);
7805 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7806 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7807 }
3d5ebf10
RG
7808 return 1;
7809 }
7810 else if (ip == ComboAddress("192.0.2.2:53")) {
7811 setLWResult(res, 0, true, false, true);
a69867f2
RG
7812 if (type == QType::NS) {
7813 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
3d5ebf10 7814 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 7815 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7816 addRRSIG(keys, res->d_records, domain, 300);
7817 }
a69867f2
RG
7818 else {
7819 if (domain == target) {
7820 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7821 addRRSIG(keys, res->d_records, domain, 300);
7822 }
7823 else if (domain == targetCName) {
7824 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7825 addRRSIG(keys, res->d_records, domain, 300);
7826 }
7827 }
3d5ebf10
RG
7828 return 1;
7829 }
7830 }
7831
7832 return 0;
7833 });
7834
7835 vector<DNSRecord> ret;
7836 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7837 BOOST_CHECK_EQUAL(res, RCode::NoError);
7838 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7839 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7840 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7841
7842 /* again, to test the cache */
7843 ret.clear();
7844 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7845 BOOST_CHECK_EQUAL(res, RCode::NoError);
7846 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7847 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7848 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7849}
7850
7851BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7852 std::unique_ptr<SyncRes> sr;
a69867f2 7853 initSR(sr, true);
3d5ebf10 7854
0c43f455 7855 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7856
7857 primeHints();
7858 const DNSName target("powerdns.com.");
7859 const DNSName targetCName("power-dns.com.");
7860 const ComboAddress targetCNameAddr("192.0.2.42");
7861 testkeysset_t keys;
7862
7863 auto luaconfsCopy = g_luaconfs.getCopy();
7864 luaconfsCopy.dsAnchors.clear();
7865 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7866 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7867 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7868 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7869 g_luaconfs.setState(luaconfsCopy);
7870
7871 size_t queriesCount = 0;
7872
0bd2e252 7873 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
7874 queriesCount++;
7875
7876 if (type == QType::DS) {
a53e8fe3 7877 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
7878 setLWResult(res, 0, false, false, true);
7879 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7880 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7881 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7882 return 1;
7883 }
5374b03b
RG
7884 else {
7885 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7886 }
3d5ebf10
RG
7887 }
7888 else if (type == QType::DNSKEY) {
7889 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7890 setLWResult(res, 0, true, false, true);
7891 addDNSKEY(keys, domain, 300, res->d_records);
7892 addRRSIG(keys, res->d_records, domain, 300);
7893 return 1;
7894 }
7895 else {
7896 setLWResult(res, 0, false, false, true);
7897 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7898 return 1;
7899 }
7900 }
7901 else {
7902 if (isRootServer(ip)) {
7903 setLWResult(res, 0, false, false, true);
7904 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7905 addDS(DNSName("com."), 300, res->d_records, keys);
7906 addRRSIG(keys, res->d_records, DNSName("."), 300);
7907 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7908 return 1;
7909 }
7910 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7911 if (domain == DNSName("com.")) {
7912 setLWResult(res, 0, true, false, true);
a69867f2 7913 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0
RG
7914 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7915 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7916 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7917 }
88cb0fe0
RG
7918 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7919 setLWResult(res, 0, false, false, true);
7920 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7921 if (domain == DNSName("powerdns.com.")) {
7922 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7923 }
7924 else if (domain == targetCName) {
7925 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7926 }
7927 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7928 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7929 }
3d5ebf10
RG
7930 return 1;
7931 }
7932 else if (ip == ComboAddress("192.0.2.2:53")) {
7933 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7934 if (type == QType::NS) {
7935 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7936 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7937 }
88cb0fe0
RG
7938 else {
7939 if (domain == DNSName("powerdns.com.")) {
7940 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7941 /* No RRSIG -> Bogus */
7942 }
7943 else if (domain == targetCName) {
7944 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7945 }
3d5ebf10
RG
7946 }
7947 return 1;
7948 }
7949 }
7950
7951 return 0;
7952 });
7953
7954 vector<DNSRecord> ret;
7955 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7956 BOOST_CHECK_EQUAL(res, RCode::NoError);
7957 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7958 /* no RRSIG to show */
7959 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7960 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7961
7962 /* again, to test the cache */
7963 ret.clear();
7964 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7965 BOOST_CHECK_EQUAL(res, RCode::NoError);
7966 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7967 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7968 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7969}
7970
895449a5
RG
7971BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7972 std::unique_ptr<SyncRes> sr;
7973 initSR(sr, true);
7974
0c43f455 7975 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
7976
7977 primeHints();
7978 const DNSName target("powerdns.com.");
7979 const ComboAddress targetAddr("192.0.2.42");
7980 testkeysset_t keys;
7981
7982 auto luaconfsCopy = g_luaconfs.getCopy();
7983 luaconfsCopy.dsAnchors.clear();
7984 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7985 /* No key material for .com */
7986 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7987 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7988 g_luaconfs.setState(luaconfsCopy);
7989
7990 size_t queriesCount = 0;
7991
0bd2e252 7992 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
7993 queriesCount++;
7994
a53e8fe3 7995 if (type == QType::DNSKEY) {
895449a5
RG
7996 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7997 setLWResult(res, 0, true, false, true);
7998 addDNSKEY(keys, domain, 300, res->d_records);
7999 addRRSIG(keys, res->d_records, domain, 300);
8000 return 1;
8001 }
8002 else if (domain == DNSName("com.")) {
8003 setLWResult(res, 0, false, false, true);
8004 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8005 return 1;
8006 }
8007 }
88cb0fe0 8008 else {
895449a5
RG
8009 if (isRootServer(ip)) {
8010 setLWResult(res, 0, false, false, true);
8011 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8012 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
8013 addRRSIG(keys, res->d_records, DNSName("."), 300);
8014 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8015 return 1;
8016 }
8017 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
8018 if (target == domain) {
8019 setLWResult(res, 0, false, false, true);
8020 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8021 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8022 }
8023 else if (domain == DNSName("com.")) {
8024 setLWResult(res, 0, true, false, true);
8025 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
8026 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8027 }
895449a5
RG
8028 return 1;
8029 }
8030 else if (ip == ComboAddress("192.0.2.2:53")) {
8031 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
8032 if (type == QType::NS) {
8033 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8034 }
8035 else {
8036 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8037 }
895449a5
RG
8038 addRRSIG(keys, res->d_records, domain, 300);
8039 return 1;
8040 }
8041 }
8042
8043 return 0;
8044 });
8045
8046 vector<DNSRecord> ret;
8047 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8048 BOOST_CHECK_EQUAL(res, RCode::NoError);
8049 /* should be insecure but we have a TA for powerdns.com. */
8050 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8051 /* We got a RRSIG */
8052 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8053 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8054 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
8055
8056 /* again, to test the cache */
8057 ret.clear();
8058 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8059 BOOST_CHECK_EQUAL(res, RCode::NoError);
8060 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8061 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8062 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8063 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
8064}
8065
8066BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
8067 std::unique_ptr<SyncRes> sr;
8068 initSR(sr, true);
8069
0c43f455 8070 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
8071
8072 primeHints();
8073 const DNSName target("powerdns.com.");
8074 const ComboAddress targetAddr("192.0.2.42");
8075 testkeysset_t keys;
8076
8077 auto luaconfsCopy = g_luaconfs.getCopy();
8078 luaconfsCopy.dsAnchors.clear();
8079 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8080 /* No key material for .com */
8081 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8082 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
8083 g_luaconfs.setState(luaconfsCopy);
8084
8085 size_t queriesCount = 0;
8086
0bd2e252 8087 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
8088 queriesCount++;
8089
a53e8fe3 8090 if (type == QType::DNSKEY) {
895449a5
RG
8091 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
8092 setLWResult(res, 0, true, false, true);
8093 addDNSKEY(keys, domain, 300, res->d_records);
8094 addRRSIG(keys, res->d_records, domain, 300);
8095 return 1;
8096 }
8097 else if (domain == DNSName("com.")) {
8098 setLWResult(res, 0, false, false, true);
8099 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8100 return 1;
8101 }
8102 }
70b3fe7a
RG
8103 else {
8104 if (target.isPartOf(domain) && isRootServer(ip)) {
895449a5
RG
8105 setLWResult(res, 0, false, false, true);
8106 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
8107 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
8108 addRRSIG(keys, res->d_records, DNSName("."), 300);
8109 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8110 return 1;
8111 }
8112 else if (ip == ComboAddress("192.0.2.1:53")) {
70b3fe7a
RG
8113 if (target == domain) {
8114 setLWResult(res, 0, false, false, true);
8115 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
8116 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8117 }
8118 else if (domain == DNSName("com.")) {
8119 setLWResult(res, 0, true, false, true);
8120 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0 8121 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
70b3fe7a 8122 }
895449a5
RG
8123 return 1;
8124 }
70b3fe7a 8125 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
895449a5 8126 setLWResult(res, 0, true, false, true);
70b3fe7a
RG
8127 if (type == QType::NS) {
8128 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8129 }
8130 else {
8131 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8132 }
895449a5
RG
8133 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
8134 return 1;
8135 }
8136 }
8137
8138 return 0;
8139 });
8140
8141 vector<DNSRecord> ret;
8142 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8143 BOOST_CHECK_EQUAL(res, RCode::NoError);
8144 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
8145 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8146 /* No RRSIG */
8147 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8148 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8149 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
8150
8151 /* again, to test the cache */
8152 ret.clear();
8153 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8154 BOOST_CHECK_EQUAL(res, RCode::NoError);
8155 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8156 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8157 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8158 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
8159}
8160
895449a5
RG
8161BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
8162 std::unique_ptr<SyncRes> sr;
8163 initSR(sr, true);
8164
0c43f455 8165 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5 8166
b7f378d1
RG
8167 primeHints();
8168 const DNSName target(".");
8169 testkeysset_t keys;
8170
8171 auto luaconfsCopy = g_luaconfs.getCopy();
8172 luaconfsCopy.dsAnchors.clear();
8173 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8174 /* Add a NTA for "." */
8175 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
8176 g_luaconfs.setState(luaconfsCopy);
8177
8178 size_t queriesCount = 0;
8179
0bd2e252 8180 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
8181 queriesCount++;
8182
8183 if (domain == target && type == QType::NS) {
8184
8185 setLWResult(res, 0, true, false, true);
8186 char addr[] = "a.root-servers.net.";
8187 for (char idx = 'a'; idx <= 'm'; idx++) {
8188 addr[0] = idx;
8455425c
RG
8189 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8190 }
8191
8192 addRRSIG(keys, res->d_records, domain, 300);
8193
8194 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8195 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8196
8197 return 1;
8198 } else if (domain == target && type == QType::DNSKEY) {
8199
8200 setLWResult(res, 0, true, false, true);
8201
8202 /* No DNSKEY */
8203
8204 return 1;
8205 }
8206
8207 return 0;
8208 });
8209
8210 vector<DNSRecord> ret;
8211 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8212 BOOST_CHECK_EQUAL(res, RCode::NoError);
8213 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8214 /* 13 NS + 1 RRSIG */
8215 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8216 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8217
8218 /* again, to test the cache */
8219 ret.clear();
8220 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8221 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8222 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8223 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8224 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8225}
8226
8227BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
8228 std::unique_ptr<SyncRes> sr;
895449a5 8229 initSR(sr, true);
8455425c 8230
0c43f455 8231 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
8232
8233 primeHints();
8234 const DNSName target(".");
b7f378d1 8235 testkeysset_t keys;
8455425c
RG
8236
8237 /* Remove the root DS */
8238 auto luaconfsCopy = g_luaconfs.getCopy();
8239 luaconfsCopy.dsAnchors.clear();
8240 g_luaconfs.setState(luaconfsCopy);
8241
8242 size_t queriesCount = 0;
8243
0bd2e252 8244 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
8245 queriesCount++;
8246
8247 if (domain == target && type == QType::NS) {
8248
8249 setLWResult(res, 0, true, false, true);
8250 char addr[] = "a.root-servers.net.";
8251 for (char idx = 'a'; idx <= 'm'; idx++) {
8252 addr[0] = idx;
8253 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8254 }
8255
8256 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8257 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8258
8259 return 1;
8260 }
8261
8262 return 0;
8263 });
8264
8265 vector<DNSRecord> ret;
8266 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8267 BOOST_CHECK_EQUAL(res, RCode::NoError);
8268 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8269 /* 13 NS + 0 RRSIG */
8270 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8271 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8272
8273 /* again, to test the cache */
8274 ret.clear();
8275 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8276 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8277 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8278 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8279 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8280}
8281
114829cc
RG
8282BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
8283 std::unique_ptr<SyncRes> sr;
8284 initSR(sr, true);
8285
5d7b19c5 8286 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
114829cc
RG
8287
8288 primeHints();
8289 const DNSName target("powerdns.com.");
8290 testkeysset_t keys;
8291
8292 auto luaconfsCopy = g_luaconfs.getCopy();
8293 luaconfsCopy.dsAnchors.clear();
8294 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5374b03b 8295 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
114829cc
RG
8296 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8297 g_luaconfs.setState(luaconfsCopy);
8298
8299 size_t queriesCount = 0;
8300
0bd2e252 8301 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
8302 queriesCount++;
8303
5374b03b
RG
8304 if (type == QType::DS || type == QType::DNSKEY) {
8305 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
114829cc
RG
8306 }
8307 else {
8308
8309 setLWResult(res, 0, true, false, true);
8310 return 1;
8311 }
8312
8313 return 0;
8314 });
8315
8316 vector<DNSRecord> ret;
8317 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8318 BOOST_CHECK_EQUAL(res, RCode::NoError);
8319 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8320 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8321 /* com|NS, powerdns.com|NS, powerdns.com|A */
8322 BOOST_CHECK_EQUAL(queriesCount, 3);
8323
8324 /* again, to test the cache */
8325 ret.clear();
8326 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8327 BOOST_CHECK_EQUAL(res, RCode::NoError);
8328 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8329 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8330 /* we don't store empty results */
5374b03b 8331 BOOST_CHECK_EQUAL(queriesCount, 4);
114829cc
RG
8332}
8333
db04449e
RG
8334BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
8335 init();
8336
8337 testkeysset_t keys;
8338 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8339
8340 vector<DNSRecord> records;
8341
8342 vector<shared_ptr<DNSRecordContent>> recordContents;
8343 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8344
8345 /*
8346 No wrap test case:
8347 a.example.org. -> d.example.org. denies the existence of b.example.org.
8348 */
8349 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8350 recordContents.push_back(records.at(0).d_content);
8351 addRRSIG(keys, records, DNSName("example.org."), 300);
8352 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8353 records.clear();
8354
8355 ContentSigPair pair;
8356 pair.records = recordContents;
8357 pair.signatures = signatureContents;
8358 cspmap_t denialMap;
8359 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8360
9b061cf5
RG
8361 /* add wildcard denial */
8362 recordContents.clear();
8363 signatureContents.clear();
8364 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8365 recordContents.push_back(records.at(0).d_content);
8366 addRRSIG(keys, records, DNSName("example.org."), 300);
8367 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8368 records.clear();
8369
8370 pair.records = recordContents;
8371 pair.signatures = signatureContents;
8372 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
8373
00e3fef4 8374 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8375 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8376
00e3fef4 8377 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8378 /* let's check that d.example.org. is not denied by this proof */
8379 BOOST_CHECK_EQUAL(denialState, NODATA);
8380}
8381
8382BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
8383 init();
8384
8385 testkeysset_t keys;
8386 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8387
8388 vector<DNSRecord> records;
8389
8390 vector<shared_ptr<DNSRecordContent>> recordContents;
8391 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8392
8393 /*
8394 Wrap case 1 test case:
8395 z.example.org. -> b.example.org. denies the existence of a.example.org.
8396 */
8397 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8398 recordContents.push_back(records.at(0).d_content);
8399 addRRSIG(keys, records, DNSName("example.org."), 300);
8400 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8401 records.clear();
8402
8403 ContentSigPair pair;
8404 pair.records = recordContents;
8405 pair.signatures = signatureContents;
8406 cspmap_t denialMap;
8407 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
8408
00e3fef4 8409 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8410 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8411
00e3fef4 8412 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8413 /* let's check that d.example.org. is not denied by this proof */
8414 BOOST_CHECK_EQUAL(denialState, NODATA);
8415}
8416
8417BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
8418 init();
8419
8420 testkeysset_t keys;
8421 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8422
8423 vector<DNSRecord> records;
8424
8425 vector<shared_ptr<DNSRecordContent>> recordContents;
8426 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8427
8428 /*
8429 Wrap case 2 test case:
8430 y.example.org. -> a.example.org. denies the existence of z.example.org.
8431 */
8432 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8433 recordContents.push_back(records.at(0).d_content);
8434 addRRSIG(keys, records, DNSName("example.org."), 300);
8435 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8436 records.clear();
8437
8438 ContentSigPair pair;
8439 pair.records = recordContents;
8440 pair.signatures = signatureContents;
8441 cspmap_t denialMap;
8442 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
8443
00e3fef4 8444 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
db04449e
RG
8445 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8446
00e3fef4 8447 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8448 /* let's check that d.example.org. is not denied by this proof */
8449 BOOST_CHECK_EQUAL(denialState, NODATA);
8450}
8451
8452BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
8453 init();
8454
8455 testkeysset_t keys;
8456 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8457
8458 vector<DNSRecord> records;
8459
8460 vector<shared_ptr<DNSRecordContent>> recordContents;
8461 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8462
8463 /*
8464 Only one NSEC in the whole zone test case:
8465 a.example.org. -> a.example.org. denies the existence of b.example.org.
8466 */
8467 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8468 recordContents.push_back(records.at(0).d_content);
8469 addRRSIG(keys, records, DNSName("example.org."), 300);
8470 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8471 records.clear();
8472
8473 ContentSigPair pair;
8474 pair.records = recordContents;
8475 pair.signatures = signatureContents;
8476 cspmap_t denialMap;
8477 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8478
00e3fef4 8479 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8480 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8481
00e3fef4 8482 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8483 /* let's check that d.example.org. is not denied by this proof */
8484 BOOST_CHECK_EQUAL(denialState, NODATA);
8485}
8486
1efd998a
RG
8487BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
8488 init();
8489
8490 testkeysset_t keys;
8491 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8492
8493 vector<DNSRecord> records;
8494
8495 vector<shared_ptr<DNSRecordContent>> recordContents;
8496 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8497
8498 /*
8499 The RRSIG from "." denies the existence of anything between a. and c.,
8500 including b.
8501 */
8502 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
8503 recordContents.push_back(records.at(0).d_content);
8504 addRRSIG(keys, records, DNSName("."), 300);
8505 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8506 records.clear();
8507
8508 ContentSigPair pair;
8509 pair.records = recordContents;
8510 pair.signatures = signatureContents;
8511 cspmap_t denialMap;
8512 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8513
9b061cf5
RG
8514 /* add wildcard denial */
8515 recordContents.clear();
8516 signatureContents.clear();
8517 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8518 recordContents.push_back(records.at(0).d_content);
8519 addRRSIG(keys, records, DNSName("."), 300);
8520 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8521 records.clear();
8522
8523 pair.records = recordContents;
8524 pair.signatures = signatureContents;
8525 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
8526
00e3fef4 8527 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
1efd998a
RG
8528 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8529}
8530
8531BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
8532 init();
8533
8534 testkeysset_t keys;
8535 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8536
8537 vector<DNSRecord> records;
8538
8539 vector<shared_ptr<DNSRecordContent>> recordContents;
8540 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8541
8542 /*
8543 The RRSIG from "." denies the existence of any type except NS at a.
8544 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8545 signer field that is shorter than the owner name of the NSEC RR) it can't
8546 be used to deny anything except the whole name or a DS.
8547 */
8548 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
8549 recordContents.push_back(records.at(0).d_content);
8550 addRRSIG(keys, records, DNSName("."), 300);
8551 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8552 records.clear();
8553
8554 ContentSigPair pair;
8555 pair.records = recordContents;
8556 pair.signatures = signatureContents;
8557 cspmap_t denialMap;
8558 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8559
8560 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8561 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8562 nonexistence of any RRs below that zone cut, which include all RRs at
8563 that (original) owner name other than DS RRs, and all RRs below that
8564 owner name regardless of type.
8565 */
8566
00e3fef4 8567 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
1efd998a
RG
8568 /* no data means the qname/qtype is not denied, because an ancestor
8569 delegation NSEC can only deny the DS */
8570 BOOST_CHECK_EQUAL(denialState, NODATA);
8571
5b522864
RG
8572 /* it can not be used to deny any RRs below that owner name either */
8573 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false);
8574 BOOST_CHECK_EQUAL(denialState, NODATA);
8575
00e3fef4 8576 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
1efd998a
RG
8577 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8578}
8579
95823c07
RG
8580BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
8581 init();
8582
8583 testkeysset_t keys;
8584 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8585
8586 vector<DNSRecord> records;
8587
8588 vector<shared_ptr<DNSRecordContent>> recordContents;
8589 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8590
8591 /*
8592 * RFC 5155 section 8.9:
8593 * If there is an NSEC3 RR present in the response that matches the
8594 * delegation name, then the validator MUST ensure that the NS bit is
8595 * set and that the DS bit is not set in the Type Bit Maps field of the
8596 * NSEC3 RR.
8597 */
8598 /*
8599 The RRSIG from "." denies the existence of any type at a.
8600 NS should be set if it was proving an insecure delegation, let's check that
8601 we correctly detect that it's not.
8602 */
8603 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
8604 recordContents.push_back(records.at(0).d_content);
8605 addRRSIG(keys, records, DNSName("."), 300);
8606 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8607 records.clear();
8608
8609 ContentSigPair pair;
8610 pair.records = recordContents;
8611 pair.signatures = signatureContents;
8612 cspmap_t denialMap;
8613 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8614
8615 /* Insecure because the NS is not set, so while it does
8616 denies the DS, it can't prove an insecure delegation */
00e3fef4 8617 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8618 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8619}
8620
9b061cf5
RG
8621BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
8622 init();
8623
8624 testkeysset_t keys;
8625 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8626
8627 vector<DNSRecord> records;
8628
8629 vector<shared_ptr<DNSRecordContent>> recordContents;
8630 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8631
8632 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
8633 recordContents.push_back(records.at(0).d_content);
8634 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8635 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8636 records.clear();
8637
8638 ContentSigPair pair;
8639 pair.records = recordContents;
8640 pair.signatures = signatureContents;
8641 cspmap_t denialMap;
8642 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8643
8644 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8645 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
8646 BOOST_CHECK_EQUAL(denialState, NODATA);
8647}
8648
8649BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
8650 init();
8651
8652 testkeysset_t keys;
8653 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8654
8655 vector<DNSRecord> records;
8656
8657 vector<shared_ptr<DNSRecordContent>> recordContents;
8658 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8659
8660 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
8661 recordContents.push_back(records.at(0).d_content);
8662 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8663 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8664
8665 ContentSigPair pair;
8666 pair.records = recordContents;
8667 pair.signatures = signatureContents;
8668 cspmap_t denialMap;
8669 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8670 records.clear();
8671
8672 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8673 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8674 BOOST_CHECK_EQUAL(denialState, NODATA);
8675}
8676
8677BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8678 init();
8679
8680 testkeysset_t keys;
8681 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8682
8683 vector<DNSRecord> records;
8684
8685 vector<shared_ptr<DNSRecordContent>> recordContents;
8686 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8687
8688 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8689 recordContents.push_back(records.at(0).d_content);
8690 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8691 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8692 records.clear();
8693
8694 ContentSigPair pair;
8695 pair.records = recordContents;
8696 pair.signatures = signatureContents;
8697 cspmap_t denialMap;
8698 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8699
8700 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8701 BOOST_CHECK_EQUAL(denialState, NODATA);
8702}
8703
8704BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
8705 init();
8706
8707 testkeysset_t keys;
8708 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8709
8710 vector<DNSRecord> records;
8711
8712 vector<shared_ptr<DNSRecordContent>> recordContents;
8713 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8714
8715 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8716 recordContents.push_back(records.at(0).d_content);
8717 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8718 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8719
8720 ContentSigPair pair;
8721 pair.records = recordContents;
8722 pair.signatures = signatureContents;
8723 cspmap_t denialMap;
8724 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8725
8726 /* Add NSEC3 for the closest encloser */
8727 recordContents.clear();
8728 signatureContents.clear();
8729 records.clear();
8730 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8731 recordContents.push_back(records.at(0).d_content);
8732 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8733 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8734
8735 pair.records = recordContents;
8736 pair.signatures = signatureContents;
8737 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8738
8739 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8740 BOOST_CHECK_EQUAL(denialState, NODATA);
8741}
8742
00e3fef4
RG
8743BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8744 init();
8745
8746 testkeysset_t keys;
8747 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8748
8749 vector<DNSRecord> records;
8750
8751 vector<shared_ptr<DNSRecordContent>> recordContents;
8752 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8753
8754 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8755 recordContents.push_back(records.at(0).d_content);
8756 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8757 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8758 records.clear();
8759
8760 ContentSigPair pair;
8761 pair.records = recordContents;
8762 pair.signatures = signatureContents;
8763 cspmap_t denialMap;
8764 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8765
9b061cf5 8766 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
00e3fef4 8767 it is an ENT */
9b061cf5 8768 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
00e3fef4 8769 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
00be1ff6 8770
9b061cf5
RG
8771 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8772 it could prove a NXDOMAIN if it had an additional wildcard denial */
8773 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8774 BOOST_CHECK_EQUAL(denialState, NODATA);
8775
00be1ff6
RG
8776 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8777 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8778 BOOST_CHECK_EQUAL(denialState, NODATA);
9b061cf5
RG
8779
8780 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8781 recordContents.clear();
8782 signatureContents.clear();
8783 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8784 recordContents.push_back(records.at(0).d_content);
8785 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8786 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8787 records.clear();
8788 pair.records = recordContents;
8789 pair.signatures = signatureContents;
8790 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8791
82566a96 8792 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
9b061cf5 8793 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
00e3fef4
RG
8794}
8795
95823c07
RG
8796BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8797 init();
8798
8799 testkeysset_t keys;
8800 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8801
8802 vector<DNSRecord> records;
8803
8804 vector<shared_ptr<DNSRecordContent>> recordContents;
8805 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8806
8807 /*
8808 The RRSIG from "." denies the existence of any type except NS at a.
8809 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8810 signer field that is shorter than the owner name of the NSEC RR) it can't
8811 be used to deny anything except the whole name or a DS.
8812 */
9b061cf5 8813 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
95823c07
RG
8814 recordContents.push_back(records.at(0).d_content);
8815 addRRSIG(keys, records, DNSName("."), 300);
8816 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8817
8818 ContentSigPair pair;
8819 pair.records = recordContents;
8820 pair.signatures = signatureContents;
8821 cspmap_t denialMap;
8822 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8823 records.clear();
8824
8825 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8826 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8827 nonexistence of any RRs below that zone cut, which include all RRs at
8828 that (original) owner name other than DS RRs, and all RRs below that
8829 owner name regardless of type.
8830 */
8831
00e3fef4 8832 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
95823c07
RG
8833 /* no data means the qname/qtype is not denied, because an ancestor
8834 delegation NSEC3 can only deny the DS */
8835 BOOST_CHECK_EQUAL(denialState, NODATA);
8836
00e3fef4 8837 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
95823c07 8838 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
5b522864
RG
8839
8840 /* it can not be used to deny any RRs below that owner name either */
8841 /* Add NSEC3 for the next closer */
8842 recordContents.clear();
8843 signatureContents.clear();
8844 records.clear();
8845 addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8846 recordContents.push_back(records.at(0).d_content);
8847 addRRSIG(keys, records, DNSName("."), 300);
8848 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8849
8850 pair.records = recordContents;
8851 pair.signatures = signatureContents;
8852 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8853
8854 /* add wildcard denial */
8855 recordContents.clear();
8856 signatureContents.clear();
8857 records.clear();
8858 addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8859 recordContents.push_back(records.at(0).d_content);
8860 addRRSIG(keys, records, DNSName("."), 300);
8861 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8862
8863 pair.records = recordContents;
8864 pair.signatures = signatureContents;
8865 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8866
8867 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true);
8868 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8869}
8870
b7c40613
RG
8871BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8872 init();
8873
8874 testkeysset_t keys;
8875 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8876
8877 vector<DNSRecord> records;
8878
8879 vector<shared_ptr<DNSRecordContent>> recordContents;
8880 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8881
8882 /* adding a NSEC3 with more iterations that we support */
8883 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8884 recordContents.push_back(records.at(0).d_content);
8885 addRRSIG(keys, records, DNSName("."), 300);
8886 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8887
8888 ContentSigPair pair;
8889 pair.records = recordContents;
8890 pair.signatures = signatureContents;
8891 cspmap_t denialMap;
8892 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8893 records.clear();
8894
8895 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8896 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8897 BOOST_CHECK_EQUAL(denialState, INSECURE);
8898}
8899
95823c07
RG
8900BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8901 init();
8902
8903 testkeysset_t keys;
8904 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8905
8906 vector<DNSRecord> records;
8907
8908 vector<shared_ptr<DNSRecordContent>> recordContents;
8909 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8910
8911 /*
8912 * RFC 5155 section 8.9:
8913 * If there is an NSEC3 RR present in the response that matches the
8914 * delegation name, then the validator MUST ensure that the NS bit is
8915 * set and that the DS bit is not set in the Type Bit Maps field of the
8916 * NSEC3 RR.
8917 */
8918 /*
8919 The RRSIG from "." denies the existence of any type at a.
8920 NS should be set if it was proving an insecure delegation, let's check that
8921 we correctly detect that it's not.
8922 */
9b061cf5 8923 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
95823c07
RG
8924 recordContents.push_back(records.at(0).d_content);
8925 addRRSIG(keys, records, DNSName("."), 300);
8926 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8927
8928 ContentSigPair pair;
8929 pair.records = recordContents;
8930 pair.signatures = signatureContents;
8931 cspmap_t denialMap;
8932 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8933 records.clear();
8934
8935 /* Insecure because the NS is not set, so while it does
8936 denies the DS, it can't prove an insecure delegation */
00e3fef4 8937 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8938 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8939}
8940
dbbef467
RG
8941BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8942 std::unique_ptr<SyncRes> sr;
dbbef467
RG
8943 initSR(sr, true);
8944
8945 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8946
8947 primeHints();
8948 const DNSName target("com.");
8949 testkeysset_t keys;
8950
8951 auto luaconfsCopy = g_luaconfs.getCopy();
8952 luaconfsCopy.dsAnchors.clear();
8953 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8954 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8955 g_luaconfs.setState(luaconfsCopy);
8956
8957 size_t queriesCount = 0;
8958
0bd2e252 8959 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) {
dbbef467
RG
8960 queriesCount++;
8961
8962 DNSName auth = domain;
8963 auth.chopOff();
8964
8965 if (type == QType::DS || type == QType::DNSKEY) {
8966 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8967 }
8968 else {
8969 setLWResult(res, RCode::NoError, true, false, true);
8970 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8971 addRRSIG(keys, res->d_records, domain, 300);
8972 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8973 addRRSIG(keys, res->d_records, domain, 1);
8974 return 1;
8975 }
8976
8977 return 0;
8978 });
8979
a66eacd6 8980 const time_t now = sr->getNow().tv_sec;
dbbef467
RG
8981 vector<DNSRecord> ret;
8982 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8983 BOOST_CHECK_EQUAL(res, RCode::NoError);
8984 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8985 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8986 BOOST_CHECK_EQUAL(queriesCount, 4);
8987
8988 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
28364e4b 8989 const NegCache::NegCacheEntry* ne = nullptr;
dbbef467 8990 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
8991 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
8992 BOOST_CHECK_EQUAL(ne->d_ttd, now + 1);
8993 BOOST_CHECK_EQUAL(ne->d_validationState, Secure);
8994 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
8995 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
8996 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
8997 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 1);
dbbef467
RG
8998
8999 /* again, to test the cache */
9000 ret.clear();
9001 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9002 BOOST_CHECK_EQUAL(res, RCode::NoError);
9003 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9004 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9005 BOOST_CHECK_EQUAL(queriesCount, 4);
9006}
9007
9008BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
9009 std::unique_ptr<SyncRes> sr;
dbbef467
RG
9010 initSR(sr, true);
9011
9012 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9013
9014 primeHints();
9015 const DNSName target("com.");
9016 const ComboAddress targetAddr("192.0.2.42");
9017 testkeysset_t keys;
9018
9019 auto luaconfsCopy = g_luaconfs.getCopy();
9020 luaconfsCopy.dsAnchors.clear();
9021 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9022 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9023 g_luaconfs.setState(luaconfsCopy);
9024
9025 size_t queriesCount = 0;
9026
0bd2e252 9027 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) {
dbbef467
RG
9028 queriesCount++;
9029
9030 DNSName auth = domain;
9031 auth.chopOff();
9032
9033 if (type == QType::DS || type == QType::DNSKEY) {
9034 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9035 }
9036 else {
9037 setLWResult(res, RCode::NoError, true, false, true);
9038 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
9039 addRRSIG(keys, res->d_records, domain, 1);
9040 return 1;
9041 }
9042
9043 return 0;
9044 });
9045
a66eacd6 9046 const time_t now = sr->getNow().tv_sec;
dbbef467
RG
9047 vector<DNSRecord> ret;
9048 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9049 BOOST_CHECK_EQUAL(res, RCode::NoError);
9050 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9051 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9052 BOOST_CHECK_EQUAL(queriesCount, 4);
9053
9054 /* check that the entry has not been cached for longer than the RRSIG validity */
9055 const ComboAddress who;
9056 vector<DNSRecord> cached;
9057 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
9058 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
9059 BOOST_REQUIRE_EQUAL(cached.size(), 1);
9060 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
9061 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
9062
9063 /* again, to test the cache */
9064 ret.clear();
9065 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9066 BOOST_CHECK_EQUAL(res, RCode::NoError);
9067 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9068 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9069 BOOST_CHECK_EQUAL(queriesCount, 4);
9070}
9071
f4de85a3
RG
9072BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
9073 /*
9074 Validation is optional, and the first query does not ask for it,
9075 so the answer is cached as Indeterminate.
9076 The second query asks for validation, answer should be marked as
9077 Secure.
9078 */
9079 std::unique_ptr<SyncRes> sr;
9080 initSR(sr, true);
9081
9082 setDNSSECValidation(sr, DNSSECMode::Process);
9083
9084 primeHints();
9085 const DNSName target("com.");
9086 testkeysset_t keys;
9087
9088 auto luaconfsCopy = g_luaconfs.getCopy();
9089 luaconfsCopy.dsAnchors.clear();
9090 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9091 g_luaconfs.setState(luaconfsCopy);
9092
9093 size_t queriesCount = 0;
9094
0bd2e252 9095 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
9096 queriesCount++;
9097
9098 if (type == QType::DS || type == QType::DNSKEY) {
9099 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9100 }
9101 else {
9102 if (domain == target && type == QType::A) {
9103 setLWResult(res, 0, true, false, true);
9104 addRecordToLW(res, target, QType::A, "192.0.2.1");
9105 addRRSIG(keys, res->d_records, DNSName("."), 300);
9106 return 1;
9107 }
9108 }
9109
9110 return 0;
9111 });
9112
9113 vector<DNSRecord> ret;
9114 /* first query does not require validation */
9115 sr->setDNSSECValidationRequested(false);
9116 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9117 BOOST_CHECK_EQUAL(res, RCode::NoError);
9118 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9119 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9120 for (const auto& record : ret) {
9121 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
9122 }
9123 BOOST_CHECK_EQUAL(queriesCount, 1);
9124
9125
9126 ret.clear();
9127 /* second one _does_ require validation */
9128 sr->setDNSSECValidationRequested(true);
9129 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9130 BOOST_CHECK_EQUAL(res, RCode::NoError);
9131 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9132 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9133 for (const auto& record : ret) {
9134 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
9135 }
9136 BOOST_CHECK_EQUAL(queriesCount, 3);
9137}
9138
9139BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
9140 /*
9141 Validation is optional, and the first query does not ask for it,
9142 so the answer is cached as Indeterminate.
9143 The second query asks for validation, answer should be marked as
9144 Insecure.
9145 */
9146 std::unique_ptr<SyncRes> sr;
9147 initSR(sr, true);
9148
9149 setDNSSECValidation(sr, DNSSECMode::Process);
9150
9151 primeHints();
9152 const DNSName target("com.");
9153 testkeysset_t keys;
9154
9155 auto luaconfsCopy = g_luaconfs.getCopy();
9156 luaconfsCopy.dsAnchors.clear();
9157 g_luaconfs.setState(luaconfsCopy);
9158
9159 size_t queriesCount = 0;
9160
0bd2e252 9161 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
9162 queriesCount++;
9163
9164 if (type == QType::DS || type == QType::DNSKEY) {
9165 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9166 }
9167 else {
9168 if (domain == target && type == QType::A) {
9169 setLWResult(res, 0, true, false, true);
9170 addRecordToLW(res, target, QType::A, "192.0.2.1");
9171 return 1;
9172 }
9173 }
9174
9175 return 0;
9176 });
9177
9178 vector<DNSRecord> ret;
9179 /* first query does not require validation */
9180 sr->setDNSSECValidationRequested(false);
9181 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9182 BOOST_CHECK_EQUAL(res, RCode::NoError);
9183 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9184 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9185 for (const auto& record : ret) {
55acb073 9186 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9187 }
9188 BOOST_CHECK_EQUAL(queriesCount, 1);
9189
9190
9191 ret.clear();
9192 /* second one _does_ require validation */
9193 sr->setDNSSECValidationRequested(true);
9194 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9195 BOOST_CHECK_EQUAL(res, RCode::NoError);
9196 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9197 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9198 for (const auto& record : ret) {
55acb073 9199 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9200 }
9201 BOOST_CHECK_EQUAL(queriesCount, 1);
9202}
9203
9204BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
9205 /*
9206 Validation is optional, and the first query does not ask for it,
9207 so the answer is cached as Indeterminate.
9208 The second query asks for validation, answer should be marked as
9209 Bogus.
9210 */
9211 std::unique_ptr<SyncRes> sr;
9212 initSR(sr, true);
9213
9214 setDNSSECValidation(sr, DNSSECMode::Process);
9215
9216 primeHints();
9217 const DNSName target("com.");
9218 testkeysset_t keys;
9219
9220 auto luaconfsCopy = g_luaconfs.getCopy();
9221 luaconfsCopy.dsAnchors.clear();
9222 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9223 g_luaconfs.setState(luaconfsCopy);
9224
9225 size_t queriesCount = 0;
9226
0bd2e252 9227 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
9228 queriesCount++;
9229
9230 if (type == QType::DS || type == QType::DNSKEY) {
9231 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9232 }
9233 else {
9234 if (domain == target && type == QType::A) {
9235 setLWResult(res, 0, true, false, true);
9236 addRecordToLW(res, target, QType::A, "192.0.2.1");
9237 /* no RRSIG */
9238 return 1;
9239 }
9240 }
9241
9242 return 0;
9243 });
9244
9245 vector<DNSRecord> ret;
9246 /* first query does not require validation */
9247 sr->setDNSSECValidationRequested(false);
9248 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9249 BOOST_CHECK_EQUAL(res, RCode::NoError);
9250 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9251 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9252 for (const auto& record : ret) {
55acb073 9253 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9254 }
9255 BOOST_CHECK_EQUAL(queriesCount, 1);
9256
9257
9258 ret.clear();
9259 /* second one _does_ require validation */
9260 sr->setDNSSECValidationRequested(true);
9261 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9262 BOOST_CHECK_EQUAL(res, RCode::NoError);
9263 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9264 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9265 for (const auto& record : ret) {
55acb073 9266 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9267 }
9268 BOOST_CHECK_EQUAL(queriesCount, 3);
9269}
9270
55acb073
RG
9271BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
9272 /*
9273 Validation is optional, and the first query does not ask for it,
9274 so the answer is cached as Indeterminate.
9275 The second query asks for validation, answer should be marked as
9276 Secure.
9277 */
9278 std::unique_ptr<SyncRes> sr;
9279 initSR(sr, true);
9280
9281 setDNSSECValidation(sr, DNSSECMode::Process);
9282
9283 primeHints();
9284 const DNSName target("com.");
9285 const DNSName cnameTarget("cname-com.");
9286 testkeysset_t keys;
9287
9288 auto luaconfsCopy = g_luaconfs.getCopy();
9289 luaconfsCopy.dsAnchors.clear();
9290 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9291 g_luaconfs.setState(luaconfsCopy);
9292
9293 size_t queriesCount = 0;
9294
0bd2e252 9295 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
9296 queriesCount++;
9297
9298 if (type == QType::DS || type == QType::DNSKEY) {
9299 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9300 }
9301 else {
9302 if (domain == target && type == QType::A) {
9303 setLWResult(res, 0, true, false, true);
9304 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9305 addRRSIG(keys, res->d_records, DNSName("."), 300);
9306 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9307 addRRSIG(keys, res->d_records, DNSName("."), 300);
9308 return 1;
9309 } else if (domain == cnameTarget && type == QType::A) {
9310 setLWResult(res, 0, true, false, true);
9311 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9312 addRRSIG(keys, res->d_records, DNSName("."), 300);
9313 return 1;
9314 }
9315 }
9316
9317 return 0;
9318 });
9319
9320 vector<DNSRecord> ret;
9321 /* first query does not require validation */
9322 sr->setDNSSECValidationRequested(false);
9323 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9324 BOOST_CHECK_EQUAL(res, RCode::NoError);
9325 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9326 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9327 for (const auto& record : ret) {
9328 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9329 }
9330 BOOST_CHECK_EQUAL(queriesCount, 2);
9331
9332
9333 ret.clear();
9334 /* second one _does_ require validation */
9335 sr->setDNSSECValidationRequested(true);
9336 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9337 BOOST_CHECK_EQUAL(res, RCode::NoError);
9338 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9339 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9340 for (const auto& record : ret) {
9341 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9342 }
9343 BOOST_CHECK_EQUAL(queriesCount, 5);
9344}
9345
9346BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
9347 /*
9348 Validation is optional, and the first query does not ask for it,
9349 so the answer is cached as Indeterminate.
9350 The second query asks for validation, answer should be marked as
9351 Insecure.
9352 */
9353 std::unique_ptr<SyncRes> sr;
9354 initSR(sr, true);
9355
9356 setDNSSECValidation(sr, DNSSECMode::Process);
9357
9358 primeHints();
9359 const DNSName target("com.");
9360 const DNSName cnameTarget("cname-com.");
9361 testkeysset_t keys;
9362
9363 auto luaconfsCopy = g_luaconfs.getCopy();
9364 luaconfsCopy.dsAnchors.clear();
9365 g_luaconfs.setState(luaconfsCopy);
9366
9367 size_t queriesCount = 0;
9368
0bd2e252 9369 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
9370 queriesCount++;
9371
9372 if (type == QType::DS || type == QType::DNSKEY) {
9373 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9374 }
9375 else {
9376 if (domain == target && type == QType::A) {
9377 setLWResult(res, 0, true, false, true);
9378 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9379 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9380 return 1;
9381 } else if (domain == cnameTarget && type == QType::A) {
9382 setLWResult(res, 0, true, false, true);
9383 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9384 return 1;
9385 }
9386 }
9387
9388 return 0;
9389 });
9390
9391 vector<DNSRecord> ret;
9392 /* first query does not require validation */
9393 sr->setDNSSECValidationRequested(false);
9394 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9395 BOOST_CHECK_EQUAL(res, RCode::NoError);
9396 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9397 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9398 for (const auto& record : ret) {
9399 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9400 }
9401 BOOST_CHECK_EQUAL(queriesCount, 2);
9402
9403
9404 ret.clear();
9405 /* second one _does_ require validation */
9406 sr->setDNSSECValidationRequested(true);
9407 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9408 BOOST_CHECK_EQUAL(res, RCode::NoError);
9409 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9410 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9411 for (const auto& record : ret) {
9412 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9413 }
9414 BOOST_CHECK_EQUAL(queriesCount, 2);
9415}
9416
9417BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
9418 /*
9419 Validation is optional, and the first query does not ask for it,
9420 so the answer is cached as Indeterminate.
9421 The second query asks for validation, answer should be marked as
9422 Bogus.
9423 */
9424 std::unique_ptr<SyncRes> sr;
9425 initSR(sr, true);
9426
9427 setDNSSECValidation(sr, DNSSECMode::Process);
9428
9429 primeHints();
9430 const DNSName target("com.");
9431 const DNSName cnameTarget("cname-com.");
9432 testkeysset_t keys;
9433
9434 auto luaconfsCopy = g_luaconfs.getCopy();
9435 luaconfsCopy.dsAnchors.clear();
9436 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9437 g_luaconfs.setState(luaconfsCopy);
9438
9439 size_t queriesCount = 0;
9440
0bd2e252 9441 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
9442 queriesCount++;
9443
9444 if (type == QType::DS || type == QType::DNSKEY) {
9445 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9446 }
9447 else {
9448 if (domain == target && type == QType::A) {
9449 setLWResult(res, 0, true, false, true);
9450 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9451 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9452 /* no RRSIG */
9453 return 1;
9454 } else if (domain == cnameTarget && type == QType::A) {
9455 setLWResult(res, 0, true, false, true);
9456 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9457 /* no RRSIG */
9458 return 1;
9459 }
9460 }
9461
9462 return 0;
9463 });
9464
9465 vector<DNSRecord> ret;
9466 /* first query does not require validation */
9467 sr->setDNSSECValidationRequested(false);
9468 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9469 BOOST_CHECK_EQUAL(res, RCode::NoError);
9470 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9471 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9472 for (const auto& record : ret) {
9473 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9474 }
9475 BOOST_CHECK_EQUAL(queriesCount, 2);
9476
9477
9478 ret.clear();
9479 /* second one _does_ require validation */
9480 sr->setDNSSECValidationRequested(true);
9481 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9482 BOOST_CHECK_EQUAL(res, RCode::NoError);
9483 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9484 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9485 for (const auto& record : ret) {
9486 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9487 }
9488 BOOST_CHECK_EQUAL(queriesCount, 5);
9489}
9490
405a26bd
RG
9491BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) {
9492 /*
9493 We get a record from a secure zone in the additional section, without
9494 the corresponding RRSIG. The record should not be marked as authoritative
9495 and should be correctly validated.
9496 */
9497 std::unique_ptr<SyncRes> sr;
9498 initSR(sr, true);
9499
9500 setDNSSECValidation(sr, DNSSECMode::Process);
9501
9502 primeHints();
9503 const DNSName target("com.");
9504 const DNSName addTarget("nsX.com.");
9505 testkeysset_t keys;
9506
9507 auto luaconfsCopy = g_luaconfs.getCopy();
9508 luaconfsCopy.dsAnchors.clear();
9509 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9510 g_luaconfs.setState(luaconfsCopy);
9511
9512 size_t queriesCount = 0;
9513
0bd2e252 9514 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
9515 queriesCount++;
9516
9517 if (type == QType::DS || type == QType::DNSKEY) {
9518 if (domain == addTarget) {
9519 DNSName auth(domain);
9520 /* no DS for com, auth will be . */
9521 auth.chopOff();
9522 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false);
9523 }
9524 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9525 }
9526 else {
9527 if (domain == target && type == QType::A) {
9528 setLWResult(res, 0, true, false, true);
9529 addRecordToLW(res, target, QType::A, "192.0.2.1");
9530 addRRSIG(keys, res->d_records, DNSName("."), 300);
9531 addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL);
9532 /* no RRSIG for the additional record */
9533 return 1;
9534 } else if (domain == addTarget && type == QType::A) {
9535 setLWResult(res, 0, true, false, true);
9536 addRecordToLW(res, addTarget, QType::A, "192.0.2.42");
9537 addRRSIG(keys, res->d_records, DNSName("."), 300);
9538 return 1;
9539 }
9540 }
9541
9542 return 0;
9543 });
9544
9545 vector<DNSRecord> ret;
9546 /* first query for target/A, will pick up the additional record as non-auth / unvalidated */
9547 sr->setDNSSECValidationRequested(false);
9548 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9549 BOOST_CHECK_EQUAL(res, RCode::NoError);
9550 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9551 BOOST_CHECK_EQUAL(ret.size(), 2);
9552 for (const auto& record : ret) {
9553 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9554 }
9555 BOOST_CHECK_EQUAL(queriesCount, 1);
9556
9557 ret.clear();
9558 /* ask for the additional record directly, we should not use
9559 the non-auth one and issue a new query, properly validated */
9560 sr->setDNSSECValidationRequested(true);
9561 res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret);
9562 BOOST_CHECK_EQUAL(res, RCode::NoError);
9563 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9564 BOOST_CHECK_EQUAL(ret.size(), 2);
9565 for (const auto& record : ret) {
9566 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9567 }
9568 BOOST_CHECK_EQUAL(queriesCount, 5);
9569}
9570
f4de85a3
RG
9571BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
9572 /*
9573 Validation is optional, and the first query does not ask for it,
9574 so the answer is negatively cached as Indeterminate.
9575 The second query asks for validation, answer should be marked as
9576 Secure.
9577 */
9578 std::unique_ptr<SyncRes> sr;
9579 initSR(sr, true);
9580
9581 setDNSSECValidation(sr, DNSSECMode::Process);
9582
9583 primeHints();
9584 const DNSName target("com.");
9585 testkeysset_t keys;
9586
9587 auto luaconfsCopy = g_luaconfs.getCopy();
9588 luaconfsCopy.dsAnchors.clear();
9589 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9590 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9591 g_luaconfs.setState(luaconfsCopy);
9592
9593 size_t queriesCount = 0;
9594
0bd2e252 9595 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
9596 queriesCount++;
9597
9598 DNSName auth = domain;
9599 auth.chopOff();
9600
9601 if (type == QType::DS || type == QType::DNSKEY) {
9602 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9603 }
9604 else {
9605 setLWResult(res, RCode::NoError, true, false, true);
9606 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9607 addRRSIG(keys, res->d_records, domain, 300);
9608 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
9609 addRRSIG(keys, res->d_records, domain, 1);
9610 return 1;
9611 }
9612
9613 return 0;
9614 });
9615
9616 vector<DNSRecord> ret;
9617 /* first query does not require validation */
9618 sr->setDNSSECValidationRequested(false);
9619 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9620 BOOST_CHECK_EQUAL(res, RCode::NoError);
9621 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9622 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9623 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd 9624 /* check that the entry has not been negatively cached */
28364e4b 9625 const NegCache::NegCacheEntry* ne = nullptr;
b25712fd 9626 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9627 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9628 BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
9629 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9630 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9631 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
9632 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9633
9634 ret.clear();
9635 /* second one _does_ require validation */
9636 sr->setDNSSECValidationRequested(true);
9637 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9638 BOOST_CHECK_EQUAL(res, RCode::NoError);
9639 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9640 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9641 BOOST_CHECK_EQUAL(queriesCount, 4);
b25712fd 9642 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9643 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9644 BOOST_CHECK_EQUAL(ne->d_validationState, Secure);
9645 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9646 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9647 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 1);
9648 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9649}
9650
f5a747bb
RG
9651BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
9652 /*
9653 Validation is optional, and the first query does not ask for it,
9654 so the answer is negatively cached as Indeterminate.
9655 The second query asks for validation, answer should be marked as
9656 Secure.
9657 The difference with test_dnssec_validation_from_negcache_secure is
9658 that have one more level here, so we are going to look for the proof
9659 that the DS does not exist for the last level. Since there is no cut,
9660 we should accept the fact that the NSEC denies DS and NS both.
9661 */
9662 std::unique_ptr<SyncRes> sr;
9663 initSR(sr, true);
9664
9665 setDNSSECValidation(sr, DNSSECMode::Process);
9666
9667 primeHints();
9668 const DNSName target("www.com.");
9669 testkeysset_t keys;
9670
9671 auto luaconfsCopy = g_luaconfs.getCopy();
9672 luaconfsCopy.dsAnchors.clear();
9673 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9674 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9675 g_luaconfs.setState(luaconfsCopy);
9676
9677 size_t queriesCount = 0;
9678
0bd2e252 9679 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
9680 queriesCount++;
9681
9682 if (type == QType::DS || type == QType::DNSKEY) {
9683 if (domain == target) {
9684 /* there is no cut */
9685 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9686 }
9687 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
9688 }
9689
9690 return 0;
9691 });
9692
9693 vector<DNSRecord> ret;
9694 /* first query does not require validation */
9695 sr->setDNSSECValidationRequested(false);
9696 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9697 BOOST_CHECK_EQUAL(res, RCode::NoError);
9698 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9699 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9700 BOOST_CHECK_EQUAL(queriesCount, 1);
9701
9702 ret.clear();
9703 /* second one _does_ require validation */
9704 sr->setDNSSECValidationRequested(true);
9705 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9706 BOOST_CHECK_EQUAL(res, RCode::NoError);
9707 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9708 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9709 BOOST_CHECK_EQUAL(queriesCount, 4);
9710}
9711
f4de85a3
RG
9712BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
9713 /*
9714 Validation is optional, and the first query does not ask for it,
9715 so the answer is negatively cached as Indeterminate.
9716 The second query asks for validation, answer should be marked as
9717 Insecure.
9718 */
9719 std::unique_ptr<SyncRes> sr;
9720 initSR(sr, true);
9721
9722 setDNSSECValidation(sr, DNSSECMode::Process);
9723
9724 primeHints();
9725 const DNSName target("com.");
9726 testkeysset_t keys;
9727
9728 auto luaconfsCopy = g_luaconfs.getCopy();
9729 luaconfsCopy.dsAnchors.clear();
9730 g_luaconfs.setState(luaconfsCopy);
9731
9732 size_t queriesCount = 0;
9733
0bd2e252 9734 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
9735 queriesCount++;
9736
9737 DNSName auth = domain;
9738 auth.chopOff();
9739
9740 if (type == QType::DS || type == QType::DNSKEY) {
9741 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9742 }
9743 else {
9744 setLWResult(res, RCode::NoError, true, false, true);
9745 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9746 return 1;
9747 }
9748
9749 return 0;
9750 });
9751
9752 vector<DNSRecord> ret;
9753 /* first query does not require validation */
9754 sr->setDNSSECValidationRequested(false);
9755 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9756 BOOST_CHECK_EQUAL(res, RCode::NoError);
9757 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9758 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9759 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd 9760 /* check that the entry has not been negatively cached */
28364e4b 9761 const NegCache::NegCacheEntry* ne = nullptr;
b25712fd 9762 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9763 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9764 BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
9765 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9766 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 0);
9767 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
9768 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9769
9770 ret.clear();
9771 /* second one _does_ require validation */
9772 sr->setDNSSECValidationRequested(true);
9773 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9774 BOOST_CHECK_EQUAL(res, RCode::NoError);
9775 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9776 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9777 BOOST_CHECK_EQUAL(queriesCount, 1);
28364e4b
RG
9778 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9779 BOOST_CHECK_EQUAL(ne->d_validationState, Insecure);
9780 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9781 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 0);
9782 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
9783 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9784}
9785
9786BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
9787 /*
9788 Validation is optional, and the first query does not ask for it,
9789 so the answer is negatively cached as Indeterminate.
9790 The second query asks for validation, answer should be marked as
9791 Bogus.
9792 */
9793 std::unique_ptr<SyncRes> sr;
9794 initSR(sr, true);
9795
9796 setDNSSECValidation(sr, DNSSECMode::Process);
9797
9798 primeHints();
9799 const DNSName target("com.");
9800 testkeysset_t keys;
9801
9802 auto luaconfsCopy = g_luaconfs.getCopy();
9803 luaconfsCopy.dsAnchors.clear();
9804 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9805 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9806 g_luaconfs.setState(luaconfsCopy);
9807
9808 size_t queriesCount = 0;
9809
0bd2e252 9810 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
9811 queriesCount++;
9812
9813 DNSName auth = domain;
9814 auth.chopOff();
9815
9816 if (type == QType::DS || type == QType::DNSKEY) {
9817 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9818 }
9819 else {
9820 setLWResult(res, RCode::NoError, true, false, true);
9821 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9822 addRRSIG(keys, res->d_records, domain, 300);
9823 /* no denial */
9824 return 1;
9825 }
9826
9827 return 0;
9828 });
9829
9830 vector<DNSRecord> ret;
9831 /* first query does not require validation */
9832 sr->setDNSSECValidationRequested(false);
9833 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9834 BOOST_CHECK_EQUAL(res, RCode::NoError);
9835 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9836 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9837 BOOST_CHECK_EQUAL(queriesCount, 1);
28364e4b 9838 const NegCache::NegCacheEntry* ne = nullptr;
b25712fd 9839 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
28364e4b
RG
9840 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9841 BOOST_CHECK_EQUAL(ne->d_validationState, Indeterminate);
9842 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9843 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9844 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
9845 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9846
9847 ret.clear();
9848 /* second one _does_ require validation */
9849 sr->setDNSSECValidationRequested(true);
9850 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9851 BOOST_CHECK_EQUAL(res, RCode::NoError);
9852 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9853 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9854 BOOST_CHECK_EQUAL(queriesCount, 4);
28364e4b
RG
9855 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), &ne), true);
9856 BOOST_CHECK_EQUAL(ne->d_validationState, Bogus);
9857 BOOST_CHECK_EQUAL(ne->authoritySOA.records.size(), 1);
9858 BOOST_CHECK_EQUAL(ne->authoritySOA.signatures.size(), 1);
9859 BOOST_CHECK_EQUAL(ne->DNSSECRecords.records.size(), 0);
9860 BOOST_CHECK_EQUAL(ne->DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9861}
9862
429ce1da
PL
9863BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
9864 g_lowercaseOutgoing = true;
9865 std::unique_ptr<SyncRes> sr;
9866 initSR(sr);
9867
9868 primeHints();
9869
9870 vector<DNSName> sentOutQnames;
9871
9872 const DNSName target("WWW.POWERDNS.COM");
9873 const DNSName cname("WWW.PowerDNS.org");
9874
0bd2e252 9875 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
9876
9877 sentOutQnames.push_back(domain);
9878
9879 if (isRootServer(ip)) {
9880 if (domain == target) {
9881 setLWResult(res, 0, false, false, true);
9882 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
9883 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
9884 return 1;
9885 }
9886 if (domain == cname) {
9887 setLWResult(res, 0, false, false, true);
9888 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
9889 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
9890 return 1;
9891 }
9892 } else if (ip == ComboAddress("192.0.2.1:53")) {
9893 if (domain == target) {
9894 setLWResult(res, 0, true, false, false);
9895 addRecordToLW(res, domain, QType::CNAME, cname.toString());
9896 return 1;
9897 }
9898 } else if (ip == ComboAddress("192.0.2.2:53")) {
9899 if (domain == cname) {
9900 setLWResult(res, 0, true, false, false);
9901 addRecordToLW(res, domain, QType::A, "127.0.0.1");
9902 return 1;
9903 }
9904 }
9905 return 0;
9906 });
9907
9908 vector<DNSRecord> ret;
9909 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9910
9911 BOOST_CHECK_EQUAL(res, RCode::NoError);
9912
9913 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9914 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
9915
9916 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
9917 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
9918 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
9919 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
9920 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
9921
9922 g_lowercaseOutgoing = false;
9923}
9924
4d787d30
PL
9925BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
9926 std::unique_ptr<SyncRes> sr;
9927 initSR(sr, true);
9928
9929 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9930
9931 primeHints();
9932 const DNSName target("com.");
9933 testkeysset_t keys, keys2;
9934
9935 auto luaconfsCopy = g_luaconfs.getCopy();
9936 luaconfsCopy.dsAnchors.clear();
9937 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9938 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9939 g_luaconfs.setState(luaconfsCopy);
9940
9941 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9942 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9943 // But add the existing root key otherwise no RRSIG can be created
9944 auto rootkey = keys.find(g_rootdnsname);
9945 keys2.insert(*rootkey);
9946
0bd2e252 9947 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
9948 DNSName auth = domain;
9949 auth.chopOff();
9950 if (type == QType::DS || type == QType::DNSKEY) {
9951 if (domain == target) {
9952 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9953 return 0;
9954 }
9955 }
9956 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9957 }
9958 return 0;
9959 });
9960
9961 dsmap_t ds;
9962 auto state = sr->getDSRecords(target, ds, false, 0, false);
9963 BOOST_CHECK_EQUAL(state, Secure);
9964 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9965 for (const auto& i : ds) {
9966 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9967 }
9968}
9969
9970BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
9971 std::unique_ptr<SyncRes> sr;
9972 initSR(sr, true);
9973
9974 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9975
9976 primeHints();
9977 const DNSName target("com.");
9978 testkeysset_t keys, keys2, keys3;
9979
9980 auto luaconfsCopy = g_luaconfs.getCopy();
9981 luaconfsCopy.dsAnchors.clear();
9982 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9983 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9984 g_luaconfs.setState(luaconfsCopy);
9985
9986 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9987 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9988 // But add the existing root key otherwise no RRSIG can be created
9989 auto rootkey = keys.find(g_rootdnsname);
9990 keys2.insert(*rootkey);
9991
9992 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
9993 // But add the existing root key otherwise no RRSIG can be created
9994 keys3.insert(*rootkey);
9995
0bd2e252 9996 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
9997 DNSName auth = domain;
9998 auth.chopOff();
9999 if (type == QType::DS || type == QType::DNSKEY) {
10000 if (domain == target) {
10001 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10002 return 0;
10003 }
10004 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
10005 return 0;
10006 }
10007 }
10008 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10009 }
10010 return 0;
10011 });
10012
10013 dsmap_t ds;
10014 auto state = sr->getDSRecords(target, ds, false, 0, false);
10015 BOOST_CHECK_EQUAL(state, Secure);
10016 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10017 for (const auto& i : ds) {
10018 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
10019 }
10020}
10021
10022BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
10023 std::unique_ptr<SyncRes> sr;
10024 initSR(sr, true);
10025
10026 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10027
10028 primeHints();
10029 const DNSName target("com.");
10030 testkeysset_t keys, keys2, keys3;
10031
10032 auto luaconfsCopy = g_luaconfs.getCopy();
10033 luaconfsCopy.dsAnchors.clear();
10034 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10035 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10036 g_luaconfs.setState(luaconfsCopy);
10037
10038 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10039 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
10040 // But add the existing root key otherwise no RRSIG can be created
10041 auto rootkey = keys.find(g_rootdnsname);
10042 keys2.insert(*rootkey);
10043
10044 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
10045 // But add the existing root key otherwise no RRSIG can be created
10046 keys3.insert(*rootkey);
10047
0bd2e252 10048 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
10049 DNSName auth = domain;
10050 auth.chopOff();
10051 if (type == QType::DS || type == QType::DNSKEY) {
10052 if (domain == target) {
10053 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10054 return 0;
10055 }
10056 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
10057 return 0;
10058 }
10059 }
10060 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10061 }
10062 return 0;
10063 });
10064
10065 dsmap_t ds;
10066 auto state = sr->getDSRecords(target, ds, false, 0, false);
10067 BOOST_CHECK_EQUAL(state, Secure);
10068 BOOST_REQUIRE_EQUAL(ds.size(), 2);
10069 for (const auto& i : ds) {
10070 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
10071 }
10072}
10073
cdc5d0c0
RG
10074BOOST_AUTO_TEST_CASE(test_cname_plus_authority_auth) {
10075 std::unique_ptr<SyncRes> sr;
10076 initSR(sr);
10077
10078 primeHints();
10079
10080 const DNSName target("cname.powerdns.com.");
10081 const DNSName cnameTarget("cname-target.powerdns.com");
10082 size_t queriesCount = 0;
10083
128efd1d 10084 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) {
cdc5d0c0
RG
10085
10086 queriesCount++;
10087
10088 if (isRootServer(ip)) {
10089 setLWResult(res, 0, false, false, true);
10090 addRecordToLW(res, DNSName("powerdns.com"), QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
10091 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
10092 return 1;
10093 } else if (ip == ComboAddress("192.0.2.1:53")) {
10094
10095 if (domain == target) {
10096 setLWResult(res, 0, true, false, false);
10097 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
10098 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2");
10099 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 42);
10100 addRecordToLW(res, DNSName("add.powerdns.com."), QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 42);
10101 return 1;
10102 }
10103 else if (domain == cnameTarget) {
10104 setLWResult(res, 0, true, false, false);
10105 addRecordToLW(res, domain, QType::A, "192.0.2.2");
10106 }
10107
10108 return 1;
10109 }
10110
10111 return 0;
10112 });
10113
10114 const time_t now = sr->getNow().tv_sec;
10115 vector<DNSRecord> ret;
10116 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
10117 BOOST_CHECK_EQUAL(res, RCode::NoError);
10118 BOOST_REQUIRE_EQUAL(ret.size(), 2);
10119 BOOST_CHECK(ret[0].d_type == QType::CNAME);
10120 BOOST_CHECK_EQUAL(ret[0].d_name, target);
10121 BOOST_CHECK(ret[1].d_type == QType::A);
10122 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
10123
10124 /* check that the NS in authority has been replaced in the cache
10125 with auth=1, but that the part in additional is still not auth */
10126 const ComboAddress who;
10127 vector<DNSRecord> cached;
10128 bool wasAuth = false;
10129
10130 BOOST_REQUIRE_GE(t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth), 1);
10131 BOOST_CHECK_EQUAL(cached.size(), 1);
10132 BOOST_CHECK_EQUAL(wasAuth, true);
10133
10134 cached.clear();
10135 BOOST_REQUIRE_GE(t_RC->get(now, DNSName("add.powerdns.com."), QType(QType::A), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth), 1);
10136 BOOST_CHECK_EQUAL(cached.size(), 1);
10137 BOOST_CHECK_EQUAL(wasAuth, false);
10138}
10139
d6e797b8
RG
10140/*
10141// cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
10142
648bcbd1 10143- check out of band support
d6e797b8 10144
648bcbd1 10145- check preoutquery
d6e797b8 10146
30ee601a
RG
10147*/
10148
10149BOOST_AUTO_TEST_SUITE_END()