]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/test-syncres_cc.cc
Merge pull request #6642 from rgacogne/rec41-fix-error-string
[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
3c5901d7 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
42int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res)
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) {
6b4ca097 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);
2b984251 78 t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
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);
2b984251 84 t_RC->replace(time(0), 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 }
2b984251 89 t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
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{
b4c8789a
RG
104 L.setName("test");
105 L.disableSyslog(true);
106
30ee601a 107 if (debug) {
30ee601a 108 L.setLoglevel((Logger::Urgency)(6)); // info and up
30ee601a
RG
109 L.toConsole(Logger::Info);
110 }
b4c8789a
RG
111 else {
112 L.setLoglevel(Logger::None);
113 L.toConsole(Logger::Error);
114 }
30ee601a
RG
115
116 seedRandom("/dev/urandom");
d6e797b8 117 reportAllTypes();
30ee601a 118
f26bf547 119 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
30ee601a 120
30ee601a
RG
121 SyncRes::s_maxqperq = 50;
122 SyncRes::s_maxtotusec = 1000*7000;
123 SyncRes::s_maxdepth = 40;
124 SyncRes::s_maxnegttl = 3600;
125 SyncRes::s_maxcachettl = 86400;
126 SyncRes::s_packetcachettl = 3600;
127 SyncRes::s_packetcacheservfailttl = 60;
128 SyncRes::s_serverdownmaxfails = 64;
129 SyncRes::s_serverdownthrottletime = 60;
130 SyncRes::s_doIPv6 = true;
e9f9b8ec
RG
131 SyncRes::s_ecsipv4limit = 24;
132 SyncRes::s_ecsipv6limit = 56;
f58c8379 133 SyncRes::s_rootNXTrust = true;
d6e797b8 134 SyncRes::s_minimumTTL = 0;
648bcbd1 135 SyncRes::s_serverID = "PowerDNS Unit Tests Server ID";
9065eb05
RG
136 SyncRes::clearEDNSSubnets();
137 SyncRes::clearEDNSDomains();
138 SyncRes::clearDelegationOnly();
139 SyncRes::clearDontQuery();
648bcbd1 140
a712cb56 141 SyncRes::clearNSSpeeds();
6dfff36f 142 BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0);
a712cb56 143 SyncRes::clearEDNSStatuses();
6dfff36f 144 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0);
a712cb56 145 SyncRes::clearThrottle();
6dfff36f 146 BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0);
a712cb56 147 SyncRes::clearFailedServers();
6dfff36f 148 BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0);
a712cb56 149
648bcbd1
RG
150 auto luaconfsCopy = g_luaconfs.getCopy();
151 luaconfsCopy.dfe.clear();
8455425c
RG
152 luaconfsCopy.dsAnchors.clear();
153 for (const auto &dsRecord : rootDSs) {
154 auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
155 luaconfsCopy.dsAnchors[g_rootdnsname].insert(*ds);
156 }
157 luaconfsCopy.negAnchors.clear();
648bcbd1
RG
158 g_luaconfs.setState(luaconfsCopy);
159
8455425c 160 g_dnssecmode = DNSSECMode::Off;
895449a5 161 g_dnssecLOG = debug;
b7c40613 162 g_maxNSEC3Iterations = 2500;
8455425c 163
648bcbd1 164 ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Unit Tests";
30ee601a
RG
165}
166
895449a5 167static void initSR(std::unique_ptr<SyncRes>& sr, bool dnssec=false, bool debug=false, time_t fakeNow=0)
30ee601a
RG
168{
169 struct timeval now;
d6e797b8
RG
170 if (fakeNow > 0) {
171 now.tv_sec = fakeNow;
172 now.tv_usec = 0;
173 }
174 else {
175 Utility::gettimeofday(&now, 0);
176 }
177
895449a5
RG
178 init(debug);
179
30ee601a 180 sr = std::unique_ptr<SyncRes>(new SyncRes(now));
895449a5 181 sr->setDoEDNS0(true);
0c43f455
RG
182 if (dnssec) {
183 sr->setDoDNSSEC(dnssec);
184 }
185
895449a5
RG
186 sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
187
a712cb56
RG
188 SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
189 SyncRes::clearNegCache();
30ee601a
RG
190}
191
0c43f455
RG
192static void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
193{
194 sr->setDNSSECValidationRequested(true);
195 g_dnssecmode = mode;
196}
197
30ee601a
RG
198static void setLWResult(LWResult* res, int rcode, bool aa=false, bool tc=false, bool edns=false)
199{
200 res->d_rcode = rcode;
201 res->d_aabit = aa;
202 res->d_tcbit = tc;
203 res->d_haveEDNS = edns;
204}
205
d6e797b8
RG
206static void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
207{
208 addRecordToList(res->d_records, name, type, content, place, ttl);
30ee601a
RG
209}
210
211static void addRecordToLW(LWResult* res, const std::string& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, uint32_t ttl=60)
212{
213 addRecordToLW(res, DNSName(name), type, content, place, ttl);
214}
215
216static bool isRootServer(const ComboAddress& ip)
217{
8455425c
RG
218 if (ip.isIPv4()) {
219 for (size_t idx = 0; idx < rootIps4Count; idx++) {
220 if (ip.toString() == rootIps4[idx]) {
221 return true;
222 }
30ee601a
RG
223 }
224 }
8455425c
RG
225 else {
226 for (size_t idx = 0; idx < rootIps6Count; idx++) {
227 if (ip.toString() == rootIps6[idx]) {
228 return true;
229 }
30ee601a
RG
230 }
231 }
8455425c 232
30ee601a
RG
233 return false;
234}
235
179b340d 236static 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
237{
238 time_t now = time(nullptr);
239 DNSKEYRecordContent drc = dpk.getDNSKEY();
240 const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
241
242 rrc.d_type = signQType;
243 rrc.d_labels = signQName.countLabels() - signQName.isWildcard();
244 rrc.d_originalttl = signTTL;
179b340d 245 rrc.d_siginception = inception ? *inception : (now - 10);
8455425c
RG
246 rrc.d_sigexpire = now + sigValidity;
247 rrc.d_signer = signer;
248 rrc.d_tag = 0;
249 rrc.d_tag = drc.getTag();
3d5ebf10 250 rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
8455425c
RG
251
252 std::string msg = getMessageForRRSET(signQName, rrc, toSign);
253
254 rrc.d_signature = rc->sign(msg);
255}
256
b7f378d1
RG
257typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent> > testkeysset_t;
258
5374b03b 259static 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
260{
261 if (records.empty()) {
5374b03b 262 return false;
8455425c
RG
263 }
264
265 const auto it = keys.find(signer);
266 if (it == keys.cend()) {
267 throw std::runtime_error("No DNSKEY found for " + signer.toString() + ", unable to compute the requested RRSIG");
268 }
269
270 size_t recordsCount = records.size();
271 const DNSName& name = records[recordsCount-1].d_name;
272 const uint16_t type = records[recordsCount-1].d_type;
273
274 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
275 for (const auto record : records) {
276 if (record.d_name == name && record.d_type == type) {
277 recordcontents.push_back(record.d_content);
278 }
279 }
280
281 RRSIGRecordContent rrc;
82fbd934 282 computeRRSIG(it->second.first, signer, wildcard ? *wildcard : records[recordsCount-1].d_name, records[recordsCount-1].d_type, records[recordsCount-1].d_ttl, sigValidity, rrc, recordcontents, algo);
3d5ebf10
RG
283 if (broken) {
284 rrc.d_signature[0] ^= 42;
285 }
8455425c
RG
286
287 DNSRecord rec;
dbbef467 288 rec.d_type = QType::RRSIG;
8455425c
RG
289 rec.d_place = records[recordsCount-1].d_place;
290 rec.d_name = records[recordsCount-1].d_name;
dbbef467 291 rec.d_ttl = records[recordsCount-1].d_ttl;
8455425c
RG
292
293 rec.d_content = std::make_shared<RRSIGRecordContent>(rrc);
294 records.push_back(rec);
5374b03b
RG
295
296 return true;
8455425c
RG
297}
298
b7f378d1 299static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records)
8455425c
RG
300{
301 const auto it = keys.find(signer);
302 if (it == keys.cend()) {
303 throw std::runtime_error("No DNSKEY found for " + signer.toString());
304 }
305
306 DNSRecord rec;
307 rec.d_place = DNSResourceRecord::ANSWER;
308 rec.d_name = signer;
309 rec.d_type = QType::DNSKEY;
310 rec.d_ttl = ttl;
311
b7f378d1 312 rec.d_content = std::make_shared<DNSKEYRecordContent>(it->second.first.getDNSKEY());
8455425c
RG
313 records.push_back(rec);
314}
315
5374b03b 316static bool addDS(const DNSName& domain, uint32_t ttl, std::vector<DNSRecord>& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY)
8455425c 317{
b7f378d1
RG
318 const auto it = keys.find(domain);
319 if (it == keys.cend()) {
5374b03b 320 return false;
8455425c
RG
321 }
322
b7f378d1
RG
323 DNSRecord rec;
324 rec.d_name = domain;
325 rec.d_type = QType::DS;
a53e8fe3 326 rec.d_place = place;
b7f378d1
RG
327 rec.d_ttl = ttl;
328 rec.d_content = std::make_shared<DSRecordContent>(it->second.second);
8455425c 329
b7f378d1 330 records.push_back(rec);
5374b03b 331 return true;
8455425c
RG
332}
333
334static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
335{
336 NSECRecordContent nrc;
337 nrc.d_next = next;
338 nrc.d_set = types;
339
340 DNSRecord rec;
341 rec.d_name = domain;
342 rec.d_ttl = ttl;
343 rec.d_type = QType::NSEC;
344 rec.d_content = std::make_shared<NSECRecordContent>(nrc);
345 rec.d_place = DNSResourceRecord::AUTHORITY;
346
347 records.push_back(rec);
348}
349
95823c07
RG
350static void addNSEC3RecordToLW(const DNSName& hashedName, const std::string& hashedNext, const std::string& salt, unsigned int iterations, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
351{
352 NSEC3RecordContent nrc;
353 nrc.d_algorithm = 1;
354 nrc.d_flags = 0;
355 nrc.d_iterations = iterations;
356 nrc.d_salt = salt;
357 nrc.d_nexthash = hashedNext;
358 nrc.d_set = types;
359
360 DNSRecord rec;
361 rec.d_name = hashedName;
362 rec.d_ttl = ttl;
363 rec.d_type = QType::NSEC3;
364 rec.d_content = std::make_shared<NSEC3RecordContent>(nrc);
365 rec.d_place = DNSResourceRecord::AUTHORITY;
366
367 records.push_back(rec);
368}
369
b7c40613 370static 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
371{
372 static const std::string salt = "deadbeef";
95823c07
RG
373 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
374
9b061cf5 375 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, next, salt, iterations, types, ttl, records);
95823c07
RG
376}
377
b7c40613 378static 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
379{
380 static const std::string salt = "deadbeef";
95823c07 381 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
95823c07
RG
382 std::string hashedNext(hashed);
383 incrementHash(hashedNext);
384 decrementHash(hashed);
385
9b061cf5 386 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, hashedNext, salt, iterations, types, ttl, records);
95823c07
RG
387}
388
b7f378d1 389static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys)
8455425c
RG
390{
391 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(algo));
b7f378d1 392 dcke->create((algo <= 10) ? 2048 : dcke->getBits());
8455425c
RG
393 DNSSECPrivateKey dpk;
394 dpk.d_flags = 256;
395 dpk.setKey(dcke);
8455425c 396 DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest);
b7f378d1
RG
397 keys[name] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk,ds);
398}
399
400static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map<DNSName,dsmap_t>& dsAnchors)
401{
402 generateKeyMaterial(name, algo, digest, keys);
403 dsAnchors[name].insert(keys[name].second);
8455425c
RG
404}
405
f4de85a3 406static int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut=true)
5374b03b
RG
407{
408 if (type == QType::DS) {
409 auth.chopOff();
410
411 setLWResult(res, 0, true, false, true);
412
413 if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) {
414 addRRSIG(keys, res->d_records, auth, 300);
415 }
416 else {
417 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
418
419 /* if the auth zone is signed, we need to provide a secure denial */
420 const auto it = keys.find(auth);
421 if (it != keys.cend()) {
422 /* sign the SOA */
423 addRRSIG(keys, res->d_records, auth, 300);
424 /* add a NSEC denying the DS */
f4de85a3
RG
425 std::set<uint16_t> types = { QType::NSEC };
426 if (proveCut) {
427 types.insert(QType::NS);
428 }
429
430 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
5374b03b
RG
431 addRRSIG(keys, res->d_records, auth, 300);
432 }
433 }
434
435 return 1;
436 }
437
438 if (type == QType::DNSKEY) {
439 setLWResult(res, 0, true, false, true);
dbbef467
RG
440 addDNSKEY(keys, domain, 300, res->d_records);
441 addRRSIG(keys, res->d_records, domain, 300);
5374b03b
RG
442 return 1;
443 }
444
445 return 0;
446}
447
30ee601a
RG
448/* Real tests */
449
450BOOST_AUTO_TEST_SUITE(syncres_cc)
451
452BOOST_AUTO_TEST_CASE(test_root_primed) {
453 std::unique_ptr<SyncRes> sr;
895449a5 454 initSR(sr);
30ee601a
RG
455
456 primeHints();
895449a5 457
4d2be65d 458 const DNSName target("a.root-servers.net.");
30ee601a 459
4d2be65d 460 /* we are primed, we should be able to resolve A a.root-servers.net. without any query */
30ee601a 461 vector<DNSRecord> ret;
4d2be65d 462 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 463 BOOST_CHECK_EQUAL(res, RCode::NoError);
4d2be65d
RG
464 BOOST_REQUIRE_EQUAL(ret.size(), 1);
465 BOOST_CHECK(ret[0].d_type == QType::A);
466 BOOST_CHECK_EQUAL(ret[0].d_name, target);
467
468 ret.clear();
469 res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1
RG
470 BOOST_CHECK_EQUAL(res, RCode::NoError);
471 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
4d2be65d
RG
472 BOOST_REQUIRE_EQUAL(ret.size(), 1);
473 BOOST_CHECK(ret[0].d_type == QType::AAAA);
474 BOOST_CHECK_EQUAL(ret[0].d_name, target);
4d2be65d
RG
475}
476
477BOOST_AUTO_TEST_CASE(test_root_primed_ns) {
478 std::unique_ptr<SyncRes> sr;
895449a5 479 initSR(sr);
4d2be65d
RG
480
481 primeHints();
482 const DNSName target(".");
483
484 /* we are primed, but we should not be able to NS . without any query
485 because the . NS entry is not stored as authoritative */
486
487 size_t queriesCount = 0;
488
489 sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
490 queriesCount++;
491
492 if (domain == target && type == QType::NS) {
493
494 setLWResult(res, 0, true, false, true);
8455425c 495 char addr[] = "a.root-servers.net.";
4d2be65d 496 for (char idx = 'a'; idx <= 'm'; idx++) {
8455425c
RG
497 addr[0] = idx;
498 addRecordToLW(res, g_rootdnsname, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4d2be65d
RG
499 }
500
501 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
502 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
503
504 return 1;
505 }
506
507 return 0;
508 });
509
510 vector<DNSRecord> ret;
511 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1 512 BOOST_CHECK_EQUAL(res, RCode::NoError);
4d2be65d
RG
513 BOOST_REQUIRE_EQUAL(ret.size(), 13);
514 BOOST_CHECK_EQUAL(queriesCount, 1);
30ee601a
RG
515}
516
517BOOST_AUTO_TEST_CASE(test_root_not_primed) {
518 std::unique_ptr<SyncRes> sr;
895449a5 519 initSR(sr);
30ee601a
RG
520
521 size_t queriesCount = 0;
522
523 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
524 queriesCount++;
525
526 if (domain == g_rootdnsname && type == QType::NS) {
527 setLWResult(res, 0, true, false, true);
528 addRecordToLW(res, g_rootdnsname, QType::NS, "a.root-servers.net.", DNSResourceRecord::ANSWER, 3600);
529 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
530 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
531
532 return 1;
533 }
534
535 return 0;
536 });
537
538 /* we are not primed yet, so SyncRes will have to call primeHints()
539 then call getRootNS(), for which at least one of the root servers needs to answer */
540 vector<DNSRecord> ret;
541 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
b7f378d1 542 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
543 BOOST_CHECK_EQUAL(ret.size(), 1);
544 BOOST_CHECK_EQUAL(queriesCount, 2);
545}
546
547BOOST_AUTO_TEST_CASE(test_root_not_primed_and_no_response) {
548 std::unique_ptr<SyncRes> sr;
895449a5 549 initSR(sr);
30ee601a
RG
550 std::set<ComboAddress> downServers;
551
552 /* we are not primed yet, so SyncRes will have to call primeHints()
553 then call getRootNS(), for which at least one of the root servers needs to answer.
554 None will, so it should ServFail.
555 */
556 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
557
558 downServers.insert(ip);
559 return 0;
560 });
561
562 vector<DNSRecord> ret;
563 int res = sr->beginResolve(DNSName("."), QType(QType::NS), QClass::IN, ret);
f58c8379 564 BOOST_CHECK_EQUAL(res, RCode::ServFail);
30ee601a
RG
565 BOOST_CHECK_EQUAL(ret.size(), 0);
566 BOOST_CHECK(downServers.size() > 0);
567 /* we explicitly refuse to mark the root servers down */
568 for (const auto& server : downServers) {
a712cb56 569 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
30ee601a
RG
570 }
571}
572
573BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) {
574 std::unique_ptr<SyncRes> sr;
895449a5 575 initSR(sr);
30ee601a
RG
576
577 ComboAddress noEDNSServer;
578 size_t queriesWithEDNS = 0;
579 size_t queriesWithoutEDNS = 0;
580
581 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &noEDNSServer](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
582 if (EDNS0Level != 0) {
583 queriesWithEDNS++;
584 noEDNSServer = ip;
585
586 setLWResult(res, RCode::FormErr);
587 return 1;
588 }
589
590 queriesWithoutEDNS++;
591
592 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
593 setLWResult(res, 0, true, false, false);
594 addRecordToLW(res, domain, QType::A, "192.0.2.1");
595 return 1;
596 }
597
598 return 0;
599 });
600
601 primeHints();
602
603 /* fake that the root NS doesn't handle EDNS, check that we fallback */
604 vector<DNSRecord> ret;
605 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 606 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
607 BOOST_CHECK_EQUAL(ret.size(), 1);
608 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
609 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
a712cb56
RG
610 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
611 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS);
30ee601a
RG
612}
613
614BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) {
615 std::unique_ptr<SyncRes> sr;
895449a5 616 initSR(sr);
30ee601a
RG
617
618 size_t queriesWithEDNS = 0;
619 size_t queriesWithoutEDNS = 0;
620
621 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
622 if (EDNS0Level != 0) {
623 queriesWithEDNS++;
624 setLWResult(res, RCode::NotImp);
625 return 1;
626 }
627
628 queriesWithoutEDNS++;
629
630 if (domain == DNSName("powerdns.com") && type == QType::A && !doTCP) {
631 setLWResult(res, 0, true, false, false);
632 addRecordToLW(res, domain, QType::A, "192.0.2.1");
633 return 1;
634 }
635
636 return 0;
637 });
638
639 primeHints();
640
641 /* fake that the NS doesn't handle EDNS, check that we fallback */
642 vector<DNSRecord> ret;
643 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 644 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
645 BOOST_CHECK_EQUAL(ret.size(), 1);
646 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
647 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
648}
649
650BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
651 std::unique_ptr<SyncRes> sr;
895449a5 652 initSR(sr);
30ee601a
RG
653
654 sr->setAsyncCallback([](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
655 if (!doTCP) {
656 setLWResult(res, 0, false, true, false);
657 return 1;
658 }
659 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
660 setLWResult(res, 0, true, false, false);
661 addRecordToLW(res, domain, QType::A, "192.0.2.1");
662 return 1;
663 }
664
665 return 0;
666 });
667
668 primeHints();
669
670 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
671 vector<DNSRecord> ret;
672 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 673 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
674}
675
3337c2f7
RG
676BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
677 std::unique_ptr<SyncRes> sr;
895449a5 678 initSR(sr);
3337c2f7
RG
679
680 size_t tcpQueriesCount = 0;
681
682 sr->setAsyncCallback([&tcpQueriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
683 if (!doTCP) {
684 setLWResult(res, 0, true, true, false);
685 return 1;
686 }
687
688 /* first TCP query is answered with a TC response */
689 tcpQueriesCount++;
690 if (tcpQueriesCount == 1) {
691 setLWResult(res, 0, true, true, false);
692 }
693 else {
694 setLWResult(res, 0, true, false, false);
695 }
696
697 addRecordToLW(res, domain, QType::A, "192.0.2.1");
698 return 1;
699 });
700
701 primeHints();
702
703 vector<DNSRecord> ret;
704 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 705 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
706 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
707}
708
30ee601a
RG
709BOOST_AUTO_TEST_CASE(test_all_nss_down) {
710 std::unique_ptr<SyncRes> sr;
895449a5 711 initSR(sr);
30ee601a
RG
712 std::set<ComboAddress> downServers;
713
714 primeHints();
715
716 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
717
718 if (isRootServer(ip)) {
8455425c 719 setLWResult(res, 0, false, false, true);
30ee601a
RG
720 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
721 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
722 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
723 return 1;
724 }
725 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 726 setLWResult(res, 0, false, false, true);
30ee601a
RG
727 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
728 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
729 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
730 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
731 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
732 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
733 return 1;
734 }
735 else {
736 downServers.insert(ip);
737 return 0;
738 }
739 });
740
ccb07d93
RG
741 DNSName target("powerdns.com.");
742
30ee601a 743 vector<DNSRecord> ret;
ccb07d93 744 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 745 BOOST_CHECK_EQUAL(res, RCode::ServFail);
30ee601a
RG
746 BOOST_CHECK_EQUAL(ret.size(), 0);
747 BOOST_CHECK_EQUAL(downServers.size(), 4);
748
749 for (const auto& server : downServers) {
a712cb56
RG
750 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
751 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
30ee601a
RG
752 }
753}
754
648bcbd1
RG
755BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
756 std::unique_ptr<SyncRes> sr;
895449a5 757 initSR(sr);
648bcbd1
RG
758 std::set<ComboAddress> downServers;
759
760 primeHints();
761
762 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
763
764 if (isRootServer(ip)) {
8455425c 765 setLWResult(res, 0, false, false, true);
648bcbd1
RG
766 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
767 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
768 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
769 return 1;
770 }
771 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 772 setLWResult(res, 0, false, false, true);
648bcbd1
RG
773 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
774 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
775 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
776 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
777 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
778 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
779 return 1;
780 }
781 else {
782 downServers.insert(ip);
b4c8789a 783 return 0;
648bcbd1
RG
784 }
785 });
786
787 /* exact same test than the previous one, except instead of a time out we fake a network error */
788 DNSName target("powerdns.com.");
789
790 vector<DNSRecord> ret;
791 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
792 BOOST_CHECK_EQUAL(res, RCode::ServFail);
793 BOOST_CHECK_EQUAL(ret.size(), 0);
794 BOOST_CHECK_EQUAL(downServers.size(), 4);
795
796 for (const auto& server : downServers) {
a712cb56
RG
797 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
798 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
648bcbd1
RG
799 }
800}
801
b4c8789a
RG
802BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) {
803 std::unique_ptr<SyncRes> sr;
804 initSR(sr);
805
806 primeHints();
807
808 DNSName target("www.powerdns.com.");
809
810 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
811
812 if (isRootServer(ip)) {
813 setLWResult(res, 0, false, false, true);
814 if (domain == target) {
815 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
816 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
817 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
818 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
819 }
820 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
821 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
822 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
823 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
824 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
825 }
826 return 1;
827 }
828 else if (ip == ComboAddress("192.0.2.3:53")) {
829 setLWResult(res, 0, true, false, true);
830 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
831 if (type == QType::A) {
832 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
833 }
834 else if (type == QType::AAAA) {
835 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
836 }
837 }
838 else if (domain == target) {
839 if (type == QType::A) {
840 addRecordToLW(res, domain, QType::A, "192.0.2.1");
841 }
842 else if (type == QType::AAAA) {
843 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
844 }
845 }
846 return 1;
847 }
848 return 0;
849 });
850
851 vector<DNSRecord> ret;
852 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
853 BOOST_CHECK_EQUAL(res, RCode::NoError);
854 BOOST_CHECK_EQUAL(ret.size(), 1);
855}
856
648bcbd1
RG
857BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
858 std::unique_ptr<SyncRes> sr;
895449a5 859 initSR(sr);
648bcbd1
RG
860 std::set<ComboAddress> downServers;
861
862 primeHints();
863
864 sr->setAsyncCallback([&downServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
865
866 if (isRootServer(ip)) {
8455425c 867 setLWResult(res, 0, false, false, true);
648bcbd1
RG
868 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
869 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
870 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
871 return 1;
872 }
873 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 874 setLWResult(res, 0, false, false, true);
648bcbd1
RG
875 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
876 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
877 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
878 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
879 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
880 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
881 return 1;
882 }
883 else {
884 if (downServers.size() < 3) {
885 /* only the last one will answer */
886 downServers.insert(ip);
887 return -2;
888 }
889 else {
890 setLWResult(res, 0, true, false, true);
891 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
892 return 1;
893 }
894 }
895 });
896
897 DNSName target("powerdns.com.");
898
899 vector<DNSRecord> ret;
900 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 901 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
902 BOOST_CHECK_EQUAL(ret.size(), 1);
903 BOOST_CHECK_EQUAL(downServers.size(), 3);
904
905 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
906 for (const auto& server : downServers) {
a712cb56
RG
907 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
908 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
648bcbd1
RG
909 }
910}
911
30ee601a
RG
912BOOST_AUTO_TEST_CASE(test_glued_referral) {
913 std::unique_ptr<SyncRes> sr;
895449a5 914 initSR(sr);
30ee601a
RG
915
916 primeHints();
917
918 const DNSName target("powerdns.com.");
919
920 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
921 /* this will cause issue with qname minimization if we ever implement it */
922 if (domain != target) {
923 return 0;
924 }
925
926 if (isRootServer(ip)) {
8455425c 927 setLWResult(res, 0, false, false, true);
30ee601a
RG
928 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
929 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
930 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
931 return 1;
932 }
933 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 934 setLWResult(res, 0, false, false, true);
30ee601a
RG
935 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
936 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
937 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
938 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
939 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
940 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
941 return 1;
942 }
943 else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) {
944 setLWResult(res, 0, true, false, true);
945 addRecordToLW(res, target, QType::A, "192.0.2.4");
946 return 1;
947 }
948 else {
949 return 0;
950 }
951 });
952
953 vector<DNSRecord> ret;
954 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 955 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 956 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 957 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
958 BOOST_CHECK_EQUAL(ret[0].d_name, target);
959}
960
961BOOST_AUTO_TEST_CASE(test_glueless_referral) {
962 std::unique_ptr<SyncRes> sr;
895449a5 963 initSR(sr);
30ee601a
RG
964
965 primeHints();
966
967 const DNSName target("powerdns.com.");
968
969 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
970
971 if (isRootServer(ip)) {
8455425c 972 setLWResult(res, 0, false, false, true);
30ee601a
RG
973
974 if (domain.isPartOf(DNSName("com."))) {
975 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
976 } else if (domain.isPartOf(DNSName("org."))) {
977 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
978 }
979 else {
980 setLWResult(res, RCode::NXDomain, false, false, true);
981 return 1;
982 }
983
984 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
985 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
986 return 1;
987 }
988 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
989 if (domain == target) {
8455425c 990 setLWResult(res, 0, false, false, true);
30ee601a
RG
991 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
992 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
993 return 1;
994 }
995 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
996 setLWResult(res, 0, true, false, true);
997 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
998 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
999 return 1;
1000 }
1001 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
1002 setLWResult(res, 0, true, false, true);
1003 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
1004 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
1005 return 1;
1006 }
1007
1008 setLWResult(res, RCode::NXDomain, false, false, true);
1009 return 1;
1010 }
1011 else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) {
1012 setLWResult(res, 0, true, false, true);
1013 addRecordToLW(res, target, QType::A, "192.0.2.4");
1014 return 1;
1015 }
1016 else {
1017 return 0;
1018 }
1019 });
1020
1021 vector<DNSRecord> ret;
1022 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1023 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 1024 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 1025 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
1026 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1027}
1028
e9f9b8ec
RG
1029BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
1030 std::unique_ptr<SyncRes> sr;
895449a5 1031 initSR(sr);
e9f9b8ec
RG
1032
1033 primeHints();
1034
1035 const DNSName target("powerdns.com.");
9065eb05 1036 SyncRes::addEDNSDomain(target);
e9f9b8ec
RG
1037
1038 EDNSSubnetOpts incomingECS;
1039 incomingECS.source = Netmask("192.0.2.128/32");
1040 sr->setIncomingECSFound(true);
1041 sr->setIncomingECS(incomingECS);
1042
1043 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1044
1045 BOOST_REQUIRE(srcmask);
1046 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1047 return 0;
1048 });
1049
1050 vector<DNSRecord> ret;
1051 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 1052 BOOST_CHECK_EQUAL(res, RCode::ServFail);
e9f9b8ec
RG
1053}
1054
1055BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
1056 std::unique_ptr<SyncRes> sr;
895449a5 1057 initSR(sr);
e9f9b8ec
RG
1058
1059 primeHints();
1060
1061 const DNSName target("powerdns.com.");
9065eb05 1062 SyncRes::addEDNSSubnet(Netmask("192.0.2.1/32"));
e9f9b8ec
RG
1063
1064 EDNSSubnetOpts incomingECS;
1065 incomingECS.source = Netmask("2001:DB8::FF/128");
1066 sr->setIncomingECSFound(true);
1067 sr->setIncomingECS(incomingECS);
1068
1069 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1070
1071 if (isRootServer(ip)) {
1072 BOOST_REQUIRE(!srcmask);
1073
8455425c 1074 setLWResult(res, 0, false, false, true);
e9f9b8ec
RG
1075 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1076 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1077 return 1;
1078 } else if (ip == ComboAddress("192.0.2.1:53")) {
1079
1080 BOOST_REQUIRE(srcmask);
1081 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1082
1083 setLWResult(res, 0, true, false, false);
1084 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1085 return 1;
1086 }
1087
1088 return 0;
1089 });
1090
1091 vector<DNSRecord> ret;
1092 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1093 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
1094 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1095 BOOST_CHECK(ret[0].d_type == QType::A);
1096 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1097}
1098
1099BOOST_AUTO_TEST_CASE(test_following_cname) {
1100 std::unique_ptr<SyncRes> sr;
895449a5 1101 initSR(sr);
778bcea6
RG
1102
1103 primeHints();
1104
1105 const DNSName target("cname.powerdns.com.");
1106 const DNSName cnameTarget("cname-target.powerdns.com");
1107
1108 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1109
1110 if (isRootServer(ip)) {
8455425c 1111 setLWResult(res, 0, false, false, true);
778bcea6
RG
1112 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1113 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1114 return 1;
1115 } else if (ip == ComboAddress("192.0.2.1:53")) {
1116
1117 if (domain == target) {
1118 setLWResult(res, 0, true, false, false);
1119 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1120 return 1;
1121 }
1122 else if (domain == cnameTarget) {
1123 setLWResult(res, 0, true, false, false);
1124 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1125 }
1126
1127 return 1;
1128 }
1129
1130 return 0;
1131 });
1132
1133 vector<DNSRecord> ret;
1134 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1135 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
1136 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1137 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1138 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1139 BOOST_CHECK(ret[1].d_type == QType::A);
1140 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1141}
1142
9b061cf5
RG
1143BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
1144 std::unique_ptr<SyncRes> sr;
1145 initSR(sr);
1146
1147 primeHints();
1148
1149 const DNSName target("cname.powerdns.com.");
1150 const DNSName cnameTarget("cname-target.powerdns.com");
1151
1152 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1153
1154 if (isRootServer(ip)) {
1155 setLWResult(res, 0, false, false, true);
1156 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1157 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1158 return 1;
1159 } else if (ip == ComboAddress("192.0.2.1:53")) {
1160
1161 if (domain == target) {
1162 setLWResult(res, RCode::NXDomain, true, false, false);
1163 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1164 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1165 } else if (domain == cnameTarget) {
1166 setLWResult(res, RCode::NXDomain, true, false, false);
1167 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1168 return 1;
1169 }
1170
1171 return 1;
1172 }
1173
1174 return 0;
1175 });
1176
1177 vector<DNSRecord> ret;
1178 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1179 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1180 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1181 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1182 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1183 BOOST_CHECK(ret[1].d_type == QType::SOA);
1184
1185 /* a second time, to check the cache */
1186 ret.clear();
1187 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1188 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1189 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1190 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1191 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1192 BOOST_CHECK(ret[1].d_type == QType::SOA);
1193}
1194
4fff116b
RG
1195BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1196 std::unique_ptr<SyncRes> sr;
895449a5 1197 initSR(sr);
4fff116b
RG
1198
1199 primeHints();
1200
1201 /* In this test we directly get the NS server for cname.powerdns.com.,
1202 and we don't know whether it's also authoritative for
1203 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1204 the additional A record for cname-target.powerdns.com. */
1205 const DNSName target("cname.powerdns.com.");
1206 const DNSName cnameTarget("cname-target.powerdns.com");
1207
1208 sr->setAsyncCallback([target, cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1209
1210 if (isRootServer(ip)) {
1211
8455425c 1212 setLWResult(res, 0, false, false, true);
4fff116b
RG
1213
1214 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1215 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1216 return 1;
1217 } else if (ip == ComboAddress("192.0.2.1:53")) {
1218
1219 if (domain == target) {
1220 setLWResult(res, 0, true, false, false);
1221 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1222 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1223 return 1;
1224 } else if (domain == cnameTarget) {
1225 setLWResult(res, 0, true, false, false);
1226 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1227 return 1;
1228 }
1229
1230 return 1;
1231 }
1232
1233 return 0;
1234 });
1235
1236 vector<DNSRecord> ret;
1237 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1238 BOOST_CHECK_EQUAL(res, RCode::NoError);
4fff116b
RG
1239 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1240 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1241 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1242 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1243 BOOST_REQUIRE(ret[1].d_type == QType::A);
1244 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1245 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1246}
1247
778bcea6
RG
1248BOOST_AUTO_TEST_CASE(test_cname_loop) {
1249 std::unique_ptr<SyncRes> sr;
895449a5 1250 initSR(sr);
778bcea6
RG
1251
1252 primeHints();
1253
1254 size_t count = 0;
1255 const DNSName target("cname.powerdns.com.");
1256
1257 sr->setAsyncCallback([target,&count](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1258
1259 count++;
1260
1261 if (isRootServer(ip)) {
778bcea6 1262
8455425c 1263 setLWResult(res, 0, false, false, true);
778bcea6
RG
1264 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1265 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1266 return 1;
1267 } else if (ip == ComboAddress("192.0.2.1:53")) {
1268
1269 if (domain == target) {
1270 setLWResult(res, 0, true, false, false);
1271 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1272 return 1;
1273 }
1274
1275 return 1;
1276 }
1277
1278 return 0;
1279 });
1280
1281 vector<DNSRecord> ret;
1282 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1283 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1284 BOOST_CHECK_GT(ret.size(), 0);
778bcea6 1285 BOOST_CHECK_EQUAL(count, 2);
e9f9b8ec
RG
1286}
1287
4fff116b
RG
1288BOOST_AUTO_TEST_CASE(test_cname_depth) {
1289 std::unique_ptr<SyncRes> sr;
895449a5 1290 initSR(sr);
4fff116b
RG
1291
1292 primeHints();
1293
1294 size_t depth = 0;
1295 const DNSName target("cname.powerdns.com.");
1296
1297 sr->setAsyncCallback([target,&depth](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1298
1299 if (isRootServer(ip)) {
4fff116b 1300
8455425c 1301 setLWResult(res, 0, false, false, true);
4fff116b
RG
1302 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1303 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1304 return 1;
1305 } else if (ip == ComboAddress("192.0.2.1:53")) {
1306
1307 setLWResult(res, 0, true, false, false);
1308 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1309 depth++;
1310 return 1;
1311 }
1312
1313 return 0;
1314 });
1315
1316 vector<DNSRecord> ret;
1317 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1318 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1319 BOOST_CHECK_EQUAL(ret.size(), depth);
4fff116b
RG
1320 /* we have an arbitrary limit at 10 when following a CNAME chain */
1321 BOOST_CHECK_EQUAL(depth, 10 + 2);
1322}
1323
d6e797b8
RG
1324BOOST_AUTO_TEST_CASE(test_time_limit) {
1325 std::unique_ptr<SyncRes> sr;
895449a5 1326 initSR(sr);
d6e797b8
RG
1327
1328 primeHints();
1329
1330 size_t queries = 0;
1331 const DNSName target("cname.powerdns.com.");
1332
1333 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1334
1335 queries++;
1336
1337 if (isRootServer(ip)) {
8455425c 1338 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1339 /* Pretend that this query took 2000 ms */
1340 res->d_usec = 2000;
1341
1342 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1343 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1344 return 1;
1345 } else if (ip == ComboAddress("192.0.2.1:53")) {
1346
1347 setLWResult(res, 0, true, false, false);
1348 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1349 return 1;
1350 }
1351
1352 return 0;
1353 });
1354
1355 /* Set the maximum time to 1 ms */
1356 SyncRes::s_maxtotusec = 1000;
1357
1358 try {
1359 vector<DNSRecord> ret;
1360 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1361 BOOST_CHECK(false);
1362 }
1363 catch(const ImmediateServFailException& e) {
1364 }
1365 BOOST_CHECK_EQUAL(queries, 1);
1366}
1367
1368BOOST_AUTO_TEST_CASE(test_referral_depth) {
1369 std::unique_ptr<SyncRes> sr;
895449a5 1370 initSR(sr);
d6e797b8
RG
1371
1372 primeHints();
1373
1374 size_t queries = 0;
1375 const DNSName target("www.powerdns.com.");
1376
1377 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1378
1379 queries++;
1380
1381 if (isRootServer(ip)) {
8455425c 1382 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1383
1384 if (domain == DNSName("www.powerdns.com.")) {
1385 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1386 }
1387 else if (domain == DNSName("ns.powerdns.com.")) {
1388 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1389 }
1390 else if (domain == DNSName("ns1.powerdns.org.")) {
1391 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1392 }
1393 else if (domain == DNSName("ns2.powerdns.org.")) {
1394 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1395 }
1396 else if (domain == DNSName("ns3.powerdns.org.")) {
1397 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1398 }
1399 else if (domain == DNSName("ns4.powerdns.org.")) {
1400 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1401 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1402 }
1403
1404 return 1;
1405 } else if (ip == ComboAddress("192.0.2.1:53")) {
1406
1407 setLWResult(res, 0, true, false, false);
1408 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1409 return 1;
1410 }
1411
1412 return 0;
1413 });
1414
1415 /* Set the maximum depth low */
1416 SyncRes::s_maxdepth = 10;
1417
1418 try {
1419 vector<DNSRecord> ret;
1420 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1421 BOOST_CHECK(false);
1422 }
1423 catch(const ImmediateServFailException& e) {
1424 }
1425}
1426
1427BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1428 std::unique_ptr<SyncRes> sr;
895449a5 1429 initSR(sr);
d6e797b8
RG
1430
1431 primeHints();
1432
1433 size_t queries = 0;
1434 const DNSName target("cname.powerdns.com.");
1435
1436 sr->setAsyncCallback([target,&queries](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1437
1438 queries++;
1439
1440 if (isRootServer(ip)) {
1441
8455425c 1442 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1443 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1444 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1445 return 1;
1446 } else if (ip == ComboAddress("192.0.2.1:53")) {
1447
1448 setLWResult(res, 0, true, false, false);
1449 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1450 return 1;
1451 }
1452
1453 return 0;
1454 });
1455
1456 /* Set the maximum number of questions very low */
1457 SyncRes::s_maxqperq = 5;
1458
1459 try {
1460 vector<DNSRecord> ret;
1461 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1462 BOOST_CHECK(false);
1463 }
1464 catch(const ImmediateServFailException& e) {
1465 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1466 }
1467}
1468
ccb07d93
RG
1469BOOST_AUTO_TEST_CASE(test_throttled_server) {
1470 std::unique_ptr<SyncRes> sr;
895449a5 1471 initSR(sr);
ccb07d93
RG
1472
1473 primeHints();
1474
1475 const DNSName target("throttled.powerdns.com.");
1476 const ComboAddress ns("192.0.2.1:53");
1477 size_t queriesToNS = 0;
1478
1479 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1480
1481 if (isRootServer(ip)) {
ccb07d93 1482
8455425c 1483 setLWResult(res, 0, false, false, true);
ccb07d93
RG
1484 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1485 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1486 return 1;
1487 } else if (ip == ns) {
1488
1489 queriesToNS++;
1490
1491 setLWResult(res, 0, true, false, false);
1492 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1493
1494 return 1;
1495 }
1496
1497 return 0;
1498 });
1499
1500 /* mark ns as down */
a712cb56 1501 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, 10000);
ccb07d93
RG
1502
1503 vector<DNSRecord> ret;
1504 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1505 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1506 BOOST_CHECK_EQUAL(ret.size(), 0);
1507 /* we should not have sent any queries to ns */
ccb07d93
RG
1508 BOOST_CHECK_EQUAL(queriesToNS, 0);
1509}
1510
1511BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1512 std::unique_ptr<SyncRes> sr;
895449a5 1513 initSR(sr);
ccb07d93
RG
1514
1515 primeHints();
1516
1517 const ComboAddress ns("192.0.2.1:53");
1518
1519 const size_t blocks = 10;
1520 /* mark ns as down for 'blocks' queries */
a712cb56 1521 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, blocks);
ccb07d93
RG
1522
1523 for (size_t idx = 0; idx < blocks; idx++) {
a712cb56 1524 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
ccb07d93
RG
1525 }
1526
1527 /* we have been throttled 'blocks' times, we should not be throttled anymore */
a712cb56 1528 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
ccb07d93
RG
1529}
1530
1531BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1532 std::unique_ptr<SyncRes> sr;
895449a5 1533 initSR(sr);
ccb07d93
RG
1534
1535 primeHints();
1536
1537 const ComboAddress ns("192.0.2.1:53");
1538
1539 const size_t seconds = 1;
1540 /* mark ns as down for 'seconds' seconds */
a712cb56
RG
1541 SyncRes::doThrottle(time(nullptr), ns, seconds, 10000);
1542
1543 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
ccb07d93
RG
1544
1545 sleep(seconds + 1);
1546
1547 /* we should not be throttled anymore */
a712cb56 1548 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
ccb07d93
RG
1549}
1550
f58c8379
RG
1551BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1552 std::unique_ptr<SyncRes> sr;
895449a5 1553 initSR(sr);
f58c8379
RG
1554
1555 primeHints();
1556
1557 const DNSName target("throttled.powerdns.com.");
1558 const ComboAddress ns("192.0.2.1:53");
1559 size_t queriesToNS = 0;
1560
1561 sr->setAsyncCallback([target,ns,&queriesToNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1562
1563 if (isRootServer(ip)) {
1564
8455425c 1565 setLWResult(res, 0, false, false, true);
f58c8379
RG
1566 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1567 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1568 return 1;
1569 } else if (ip == ns) {
1570
1571 queriesToNS++;
1572
1573 setLWResult(res, 0, true, false, false);
1574 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1575
1576 return 1;
1577 }
1578
1579 return 0;
1580 });
1581
1582 /* prevent querying this NS */
9065eb05 1583 SyncRes::addDontQuery(Netmask(ns));
f58c8379
RG
1584
1585 vector<DNSRecord> ret;
1586 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1587 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1588 BOOST_CHECK_EQUAL(ret.size(), 0);
1589 /* we should not have sent any queries to ns */
1590 BOOST_CHECK_EQUAL(queriesToNS, 0);
1591}
1592
1593BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1594 std::unique_ptr<SyncRes> sr;
895449a5 1595 initSR(sr);
f58c8379
RG
1596
1597 primeHints();
1598
1599 const DNSName target1("powerdns.com.");
1600 const DNSName target2("notpowerdns.com.");
1601 const ComboAddress ns("192.0.2.1:53");
1602 size_t queriesCount = 0;
1603
1604 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1605
1606 queriesCount++;
1607
1608 if (isRootServer(ip)) {
1609
1610 if (domain == target1) {
1611 setLWResult(res, RCode::NXDomain, true, false, true);
1612 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1613 }
1614 else {
1615 setLWResult(res, 0, true, false, true);
1616 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1617 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1618 }
1619
1620 return 1;
1621 } else if (ip == ns) {
1622
1623 setLWResult(res, 0, true, false, false);
1624 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1625
1626 return 1;
1627 }
1628
1629 return 0;
1630 });
1631
1632 vector<DNSRecord> ret;
1633 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1634 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1635 BOOST_CHECK_EQUAL(ret.size(), 1);
1636 /* one for target1 and one for the entire TLD */
a712cb56 1637 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1638
1639 ret.clear();
1640 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1641 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1642 BOOST_CHECK_EQUAL(ret.size(), 1);
1643 /* one for target1 and one for the entire TLD */
a712cb56 1644 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1645
1646 /* we should have sent only one query */
1647 BOOST_CHECK_EQUAL(queriesCount, 1);
1648}
1649
898856ca
RG
1650BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1651 std::unique_ptr<SyncRes> sr;
1652 init();
1653 initSR(sr, true, false);
1654
1655 primeHints();
1656
1657 const DNSName target1("powerdns.com.");
1658 const DNSName target2("notpowerdns.com.");
1659 const ComboAddress ns("192.0.2.1:53");
1660 size_t queriesCount = 0;
1661
1662 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1663 We should add target1 to the negcache, but not "com.". */
1664
1665 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1666
1667 queriesCount++;
1668
1669 if (isRootServer(ip)) {
1670
1671 if (domain == target1) {
1672 setLWResult(res, RCode::NXDomain, true, false, true);
1673 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1674 }
1675 else {
1676 setLWResult(res, 0, true, false, true);
1677 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1678 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1679 }
1680
1681 return 1;
1682 } else if (ip == ns) {
1683
1684 setLWResult(res, 0, true, false, false);
1685 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1686
1687 return 1;
1688 }
1689
1690 return 0;
1691 });
1692
1693 vector<DNSRecord> ret;
1694 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1695 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1696 BOOST_CHECK_EQUAL(ret.size(), 1);
1697
1698 /* even with root-nx-trust on and a NX answer from the root,
1699 we should not have cached the entire TLD this time. */
a712cb56 1700 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1701
1702 ret.clear();
1703 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1704 BOOST_CHECK_EQUAL(res, RCode::NoError);
1705 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1706 BOOST_REQUIRE(ret[0].d_type == QType::A);
1707 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1708 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1709
a712cb56 1710 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1711
1712 BOOST_CHECK_EQUAL(queriesCount, 3);
1713}
1714
f58c8379
RG
1715BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1716 std::unique_ptr<SyncRes> sr;
895449a5 1717 initSR(sr);
f58c8379
RG
1718
1719 primeHints();
1720
1721 const DNSName target1("powerdns.com.");
1722 const DNSName target2("notpowerdns.com.");
1723 const ComboAddress ns("192.0.2.1:53");
1724 size_t queriesCount = 0;
1725
1726 sr->setAsyncCallback([target1, target2, ns, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1727
1728 queriesCount++;
1729
1730 if (isRootServer(ip)) {
1731
1732 if (domain == target1) {
1733 setLWResult(res, RCode::NXDomain, true, false, true);
1734 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1735 }
1736 else {
1737 setLWResult(res, 0, true, false, true);
1738 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1739 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1740 }
1741
1742 return 1;
1743 } else if (ip == ns) {
1744
1745 setLWResult(res, 0, true, false, false);
1746 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1747
1748 return 1;
1749 }
1750
1751 return 0;
1752 });
1753
1754 SyncRes::s_rootNXTrust = false;
1755
1756 vector<DNSRecord> ret;
1757 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1758 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1759 BOOST_CHECK_EQUAL(ret.size(), 1);
1760 /* one for target1 */
a712cb56 1761 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1762
1763 ret.clear();
1764 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
b7f378d1 1765 BOOST_CHECK_EQUAL(res, RCode::NoError);
f58c8379
RG
1766 BOOST_CHECK_EQUAL(ret.size(), 1);
1767 /* one for target1 */
a712cb56 1768 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1769
1770 /* we should have sent three queries */
1771 BOOST_CHECK_EQUAL(queriesCount, 3);
1772}
1773
1774BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1775 std::unique_ptr<SyncRes> sr;
895449a5 1776 initSR(sr);
f58c8379
RG
1777
1778 primeHints();
1779
1780 const DNSName target("www.powerdns.com.");
1781 const DNSName cnameTarget("cname.powerdns.com.");
1782
9065eb05 1783 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
f58c8379
RG
1784
1785 EDNSSubnetOpts incomingECS;
1786 incomingECS.source = Netmask("192.0.2.128/32");
1787 sr->setIncomingECSFound(true);
1788 sr->setIncomingECS(incomingECS);
1789
1790 sr->setAsyncCallback([target,cnameTarget](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1791
1792 BOOST_REQUIRE(srcmask);
1793 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1794
1795 if (isRootServer(ip)) {
8455425c 1796 setLWResult(res, 0, false, false, true);
f58c8379
RG
1797 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1798 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1799
1800 return 1;
1801 } else if (ip == ComboAddress("192.0.2.1:53")) {
1802 if (domain == target) {
1803 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
1804 setLWResult(res, RCode::NXDomain, true, false, true);
1805 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1806 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1807 }
1808 else if (domain == cnameTarget) {
1809 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
1810 but we might if we still chase the CNAME. */
1811 setLWResult(res, RCode::NXDomain, true, false, true);
1812 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1813 }
1814
1815 return 1;
1816 }
1817
1818 return 0;
1819 });
1820
1821 vector<DNSRecord> ret;
1822 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1823 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1824 BOOST_CHECK_EQUAL(ret.size(), 2);
1825 /* no negative cache entry because the response was variable */
a712cb56 1826 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
f58c8379
RG
1827}
1828
d6e797b8
RG
1829BOOST_AUTO_TEST_CASE(test_ns_speed) {
1830 std::unique_ptr<SyncRes> sr;
895449a5 1831 initSR(sr);
30ee601a 1832
d6e797b8 1833 primeHints();
30ee601a 1834
d6e797b8 1835 const DNSName target("powerdns.com.");
30ee601a 1836
d6e797b8 1837 std::map<ComboAddress, uint64_t> nsCounts;
30ee601a 1838
d6e797b8 1839 sr->setAsyncCallback([target,&nsCounts](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
30ee601a 1840
d6e797b8 1841 if (isRootServer(ip)) {
8455425c 1842 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1843 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1844 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1845 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
30ee601a 1846
d6e797b8
RG
1847 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1848 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1849 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1850 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
1851 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
1852 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
30ee601a 1853
d6e797b8
RG
1854 return 1;
1855 } else {
1856 nsCounts[ip]++;
30ee601a 1857
d6e797b8
RG
1858 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
1859 BOOST_CHECK_LT(nsCounts.size(), 3);
1860
1861 /* let's time out on pdns-public-ns2.powerdns.com. */
1862 return 0;
1863 }
1864 else if (ip == ComboAddress("192.0.2.1:53")) {
1865 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1866
1867 setLWResult(res, 0, true, false, true);
1868 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1869 return 1;
1870 }
1871
1872 return 0;
1873 }
30ee601a 1874
d6e797b8
RG
1875 return 0;
1876 });
30ee601a 1877
d6e797b8
RG
1878 struct timeval now;
1879 gettimeofday(&now, 0);
30ee601a 1880
d6e797b8
RG
1881 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
1882 then pdns-public-ns1.powerdns.com. on IPv4 */
a712cb56
RG
1883 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
1884 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
1885 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
1886 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
1887 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
1888 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
30ee601a 1889
d6e797b8
RG
1890 vector<DNSRecord> ret;
1891 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1892 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
1893 BOOST_CHECK_EQUAL(ret.size(), 1);
1894 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1895 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
1896 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
1897 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
1898}
30ee601a 1899
d6e797b8
RG
1900BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
1901 std::unique_ptr<SyncRes> sr;
895449a5 1902 initSR(sr);
30ee601a 1903
d6e797b8 1904 primeHints();
30ee601a 1905
d6e797b8 1906 const DNSName target("powerdns.com.");
30ee601a 1907
d6e797b8
RG
1908 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1909
1910 if (isRootServer(ip)) {
8455425c 1911 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1912 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1913
1914 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1915
1916 return 1;
1917 } else if (ip == ComboAddress("192.0.2.1:53")) {
1918 setLWResult(res, 0, true, false, true);
1919 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1920 return 1;
1921 }
1922
1923 return 0;
1924 });
1925
1926 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
934c35b9 1927 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
1928 std::vector<DNSRecord> records;
1929 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1930 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
1931
2b984251 1932 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
1933
1934 vector<DNSRecord> ret;
1935 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1936 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
1937 BOOST_CHECK_EQUAL(ret.size(), 1);
1938}
1939
3337c2f7
RG
1940BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
1941 std::unique_ptr<SyncRes> sr;
895449a5 1942 initSR(sr);
3337c2f7
RG
1943
1944 primeHints();
1945
1946 const DNSName target("powerdns.com.");
1947 size_t queriesCount = 0;
1948
1949 sr->setAsyncCallback([&queriesCount,target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1950
1951 queriesCount++;
1952
1953 if (isRootServer(ip) && domain == target) {
8455425c 1954 setLWResult(res, 0, false, false, true);
3337c2f7
RG
1955 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1956 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1957 return 1;
1958 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
1959 setLWResult(res, 0, true, false, true);
1960 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1961 return 1;
1962 }
1963
1964 return 0;
1965 });
1966
1967 vector<DNSRecord> ret;
1968 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1969 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1970 BOOST_CHECK_EQUAL(ret.size(), 0);
1971 /* one query to get NSs, then A and AAAA for each NS */
1972 BOOST_CHECK_EQUAL(queriesCount, 5);
1973}
1974
d6e797b8
RG
1975BOOST_AUTO_TEST_CASE(test_cache_hit) {
1976 std::unique_ptr<SyncRes> sr;
895449a5 1977 initSR(sr);
d6e797b8
RG
1978
1979 primeHints();
1980
1981 const DNSName target("powerdns.com.");
1982
1983 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
1984
1985 return 0;
1986 });
1987
1988 /* we populate the cache with eveything we need */
934c35b9 1989 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
1990 std::vector<DNSRecord> records;
1991 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1992
1993 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
2b984251 1994 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
1995
1996 vector<DNSRecord> ret;
1997 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1998 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
1999 BOOST_CHECK_EQUAL(ret.size(), 1);
2000}
2001
648bcbd1
RG
2002BOOST_AUTO_TEST_CASE(test_no_rd) {
2003 std::unique_ptr<SyncRes> sr;
895449a5 2004 initSR(sr);
648bcbd1
RG
2005
2006 primeHints();
2007
2008 const DNSName target("powerdns.com.");
2009 size_t queriesCount = 0;
2010
2011 sr->setCacheOnly();
2012
2013 sr->setAsyncCallback([target,&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2014
2015 queriesCount++;
2016 return 0;
2017 });
2018
2019 vector<DNSRecord> ret;
2020 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2021 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2022 BOOST_CHECK_EQUAL(ret.size(), 0);
2023 BOOST_CHECK_EQUAL(queriesCount, 0);
2024}
2025
d6e797b8
RG
2026BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
2027 std::unique_ptr<SyncRes> sr;
895449a5 2028 initSR(sr);
d6e797b8
RG
2029
2030 primeHints();
2031
2032 const DNSName target("cachettl.powerdns.com.");
2033 const ComboAddress ns("192.0.2.1:53");
2034
2035 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2036
2037 if (isRootServer(ip)) {
2038
8455425c 2039 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2040 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2041 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
2042 return 1;
2043 } else if (ip == ns) {
2044
2045 setLWResult(res, 0, true, false, false);
2046 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2047
2048 return 1;
2049 }
2050
2051 return 0;
2052 });
2053
934c35b9 2054 const time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2055 SyncRes::s_minimumTTL = 60;
2056 SyncRes::s_maxcachettl = 3600;
2057
2058 vector<DNSRecord> ret;
2059 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2060 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2061 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2062 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
2063
2064 const ComboAddress who;
2065 vector<DNSRecord> cached;
24bb9b58 2066 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
d6e797b8
RG
2067 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2068 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2069 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
2070
2071 cached.clear();
24bb9b58 2072 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
d6e797b8
RG
2073 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2074 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2075 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
2076}
2077
2078BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
2079 std::unique_ptr<SyncRes> sr;
895449a5 2080 initSR(sr);
d6e797b8
RG
2081
2082 primeHints();
2083
2084 const DNSName target("powerdns.com.");
2085
2086 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2087
2088 if (isRootServer(ip)) {
8455425c 2089 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2090 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2091
2092 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2093
2094 return 1;
2095 } else if (ip == ComboAddress("192.0.2.1:53")) {
2096 setLWResult(res, 0, true, false, true);
2097 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2098 return 1;
2099 }
2100
2101 return 0;
2102 });
2103
2104 /* we populate the cache with entries that expired 60s ago*/
934c35b9 2105 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2106 std::vector<DNSRecord> records;
2107 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2108 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
2109
2b984251 2110 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2111
2112 vector<DNSRecord> ret;
2113 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2114 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2115 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2116 BOOST_REQUIRE(ret[0].d_type == QType::A);
2117 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
2118}
2119
2120BOOST_AUTO_TEST_CASE(test_delegation_only) {
2121 std::unique_ptr<SyncRes> sr;
895449a5 2122 initSR(sr);
d6e797b8
RG
2123
2124 primeHints();
2125
2126 /* Thanks, Verisign */
9065eb05
RG
2127 SyncRes::addDelegationOnly(DNSName("com."));
2128 SyncRes::addDelegationOnly(DNSName("net."));
d6e797b8
RG
2129
2130 const DNSName target("nx-powerdns.com.");
2131
2132 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2133
2134 if (isRootServer(ip)) {
8455425c 2135 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2136 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2137 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2138 return 1;
2139 } else if (ip == ComboAddress("192.0.2.1:53")) {
2140
2141 setLWResult(res, 0, true, false, true);
2142 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2143 return 1;
2144 }
2145
2146 return 0;
2147 });
2148
2149 vector<DNSRecord> ret;
2150 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2151 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2152 BOOST_CHECK_EQUAL(ret.size(), 0);
2153}
2154
2155BOOST_AUTO_TEST_CASE(test_unauth_any) {
2156 std::unique_ptr<SyncRes> sr;
895449a5 2157 initSR(sr);
d6e797b8
RG
2158
2159 primeHints();
2160
2161 const DNSName target("powerdns.com.");
2162
2163 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2164
2165 if (isRootServer(ip)) {
8455425c 2166 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2167 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2168 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2169 return 1;
2170 } else if (ip == ComboAddress("192.0.2.1:53")) {
2171
2172 setLWResult(res, 0, false, false, true);
2173 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2174 return 1;
2175 }
2176
2177 return 0;
2178 });
2179
2180 vector<DNSRecord> ret;
2181 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2182 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2183 BOOST_CHECK_EQUAL(ret.size(), 0);
2184}
2185
2186BOOST_AUTO_TEST_CASE(test_no_data) {
2187 std::unique_ptr<SyncRes> sr;
895449a5 2188 initSR(sr);
d6e797b8
RG
2189
2190 primeHints();
2191
2192 const DNSName target("powerdns.com.");
2193
2194 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2195
2196 setLWResult(res, 0, true, false, true);
2197 return 1;
2198 });
2199
2200 vector<DNSRecord> ret;
2201 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2202 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2203 BOOST_CHECK_EQUAL(ret.size(), 0);
2204}
2205
2206BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2207 std::unique_ptr<SyncRes> sr;
895449a5 2208 initSR(sr);
d6e797b8
RG
2209
2210 primeHints();
2211
2212 const DNSName target("powerdns.com.");
2213
2214 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2215
2216 setLWResult(res, 0, true, false, true);
2217 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2218 addRecordToLW(res, domain, QType::ANY, "0 0");
2219 addRecordToLW(res, domain, QType::OPT, "");
2220 return 1;
2221 });
2222
2223 vector<DNSRecord> ret;
2224 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2225 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2226 BOOST_CHECK_EQUAL(ret.size(), 1);
2227}
2228
2229BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2230 std::unique_ptr<SyncRes> sr;
895449a5 2231 initSR(sr);
d6e797b8
RG
2232
2233 primeHints();
2234
2235 const DNSName target("powerdns.com.");
2236
2237 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2238
2239 setLWResult(res, 0, true, false, true);
2240 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2241 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2242 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2243 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2244 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2245 return 1;
2246 });
2247
2248 vector<DNSRecord> ret;
2249 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2250 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2251 BOOST_CHECK_EQUAL(ret.size(), 1);
2252}
2253
2254BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2255 std::unique_ptr<SyncRes> sr;
895449a5 2256 initSR(sr, true);
d6e797b8
RG
2257
2258 primeHints();
2259
2260 const DNSName target("powerdns.com.");
2261
2262 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2263
2264 setLWResult(res, 0, true, false, true);
2265 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2266 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2267 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2268 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2269 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2270 return 1;
2271 });
2272
2273 vector<DNSRecord> ret;
2274 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2275 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2276 BOOST_CHECK_EQUAL(ret.size(), 4);
2277}
2278
2279BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2280 std::unique_ptr<SyncRes> sr;
895449a5 2281 initSR(sr);
d6e797b8
RG
2282
2283 primeHints();
2284
2285 const DNSName target("powerdns.com.");
2286
2287 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2288
2289 setLWResult(res, RCode::NXDomain, true, false, true);
2290 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2291 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2292 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2293 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2294 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2295 return 1;
2296 });
2297
2298 vector<DNSRecord> ret;
2299 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2300 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2301 BOOST_CHECK_EQUAL(ret.size(), 1);
2302}
2303
2304BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2305 std::unique_ptr<SyncRes> sr;
895449a5 2306 initSR(sr, true);
d6e797b8
RG
2307
2308 primeHints();
2309
2310 const DNSName target("powerdns.com.");
2311
2312 sr->setAsyncCallback([target](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2313
2314 setLWResult(res, RCode::NXDomain, true, false, true);
2315 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2316 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2317 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2318 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2319 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2320 return 1;
2321 });
2322
2323 vector<DNSRecord> ret;
2324 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2325 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2326 BOOST_CHECK_EQUAL(ret.size(), 4);
2327}
2328
648bcbd1
RG
2329BOOST_AUTO_TEST_CASE(test_qclass_none) {
2330 std::unique_ptr<SyncRes> sr;
895449a5 2331 initSR(sr);
648bcbd1
RG
2332
2333 primeHints();
2334
2335 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2336 size_t queriesCount = 0;
2337
2338 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2339
2340 queriesCount++;
2341 return 0;
2342 });
2343
2344 const DNSName target("powerdns.com.");
2345 vector<DNSRecord> ret;
2346 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2347 BOOST_CHECK_EQUAL(res, -1);
2348 BOOST_CHECK_EQUAL(ret.size(), 0);
2349 BOOST_CHECK_EQUAL(queriesCount, 0);
2350}
2351
1f03b691 2352BOOST_AUTO_TEST_CASE(test_special_types) {
648bcbd1 2353 std::unique_ptr<SyncRes> sr;
895449a5 2354 initSR(sr);
648bcbd1
RG
2355
2356 primeHints();
2357
1f03b691 2358 /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
648bcbd1
RG
2359 size_t queriesCount = 0;
2360
2361 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2362
2363 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2364 queriesCount++;
2365 return 0;
2366 });
2367
2368 const DNSName target("powerdns.com.");
2369 vector<DNSRecord> ret;
2370 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2371 BOOST_CHECK_EQUAL(res, -1);
2372 BOOST_CHECK_EQUAL(ret.size(), 0);
2373 BOOST_CHECK_EQUAL(queriesCount, 0);
2374
2375 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2376 BOOST_CHECK_EQUAL(res, -1);
2377 BOOST_CHECK_EQUAL(ret.size(), 0);
2378 BOOST_CHECK_EQUAL(queriesCount, 0);
1f03b691
RG
2379
2380 res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2381 BOOST_CHECK_EQUAL(res, -1);
2382 BOOST_CHECK_EQUAL(ret.size(), 0);
2383 BOOST_CHECK_EQUAL(queriesCount, 0);
2384
2385 res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
648bcbd1
RG
2386 BOOST_CHECK_EQUAL(res, -1);
2387 BOOST_CHECK_EQUAL(ret.size(), 0);
2388 BOOST_CHECK_EQUAL(queriesCount, 0);
2389}
2390
2391BOOST_AUTO_TEST_CASE(test_special_names) {
2392 std::unique_ptr<SyncRes> sr;
895449a5 2393 initSR(sr);
648bcbd1
RG
2394
2395 primeHints();
2396
2397 /* special names should be handled internally */
2398
2399 size_t queriesCount = 0;
2400
2401 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2402
2403 queriesCount++;
2404 return 0;
2405 });
2406
2407 vector<DNSRecord> ret;
2408 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
b7f378d1 2409 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2410 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2411 BOOST_CHECK(ret[0].d_type == QType::PTR);
2412 BOOST_CHECK_EQUAL(queriesCount, 0);
2413
2414 ret.clear();
2415 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2416 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2417 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2418 BOOST_CHECK(ret[0].d_type == QType::PTR);
2419 BOOST_CHECK_EQUAL(queriesCount, 0);
2420
2421 ret.clear();
2422 res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::PTR), QClass::IN, ret);
b7f378d1 2423 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2424 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2425 BOOST_CHECK(ret[0].d_type == QType::PTR);
2426 BOOST_CHECK_EQUAL(queriesCount, 0);
2427
2428 ret.clear();
2429 res = sr->beginResolve(DNSName("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2430 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2431 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2432 BOOST_CHECK(ret[0].d_type == QType::PTR);
2433 BOOST_CHECK_EQUAL(queriesCount, 0);
2434
2435 ret.clear();
2436 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
b7f378d1 2437 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2438 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2439 BOOST_CHECK(ret[0].d_type == QType::A);
2440 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2441 BOOST_CHECK_EQUAL(queriesCount, 0);
2442
2443 ret.clear();
2444 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
b7f378d1 2445 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2446 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2447 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2448 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2449 BOOST_CHECK_EQUAL(queriesCount, 0);
2450
2451 ret.clear();
2452 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2453 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2454 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2455 for (const auto& rec : ret) {
2456 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2457 if (rec.d_type == QType::A) {
2458 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2459 }
2460 else {
2461 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2462 }
2463 }
2464 BOOST_CHECK_EQUAL(queriesCount, 0);
2465
2466 ret.clear();
2467 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2468 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2469 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2470 BOOST_CHECK(ret[0].d_type == QType::TXT);
2471 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2472 BOOST_CHECK_EQUAL(queriesCount, 0);
2473
2474 ret.clear();
2475 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2476 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2477 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2478 BOOST_CHECK(ret[0].d_type == QType::TXT);
2479 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2480 BOOST_CHECK_EQUAL(queriesCount, 0);
2481
2482 ret.clear();
2483 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2484 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2485 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2486 BOOST_CHECK(ret[0].d_type == QType::TXT);
2487 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2488 BOOST_CHECK_EQUAL(queriesCount, 0);
2489
2490 ret.clear();
2491 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2492 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2493 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2494 BOOST_CHECK(ret[0].d_type == QType::TXT);
2495 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2496 BOOST_CHECK_EQUAL(queriesCount, 0);
2497
2498 ret.clear();
2499 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2500 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2501 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2502 BOOST_CHECK(ret[0].d_type == QType::TXT);
2503 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2504 BOOST_CHECK_EQUAL(queriesCount, 0);
2505
2506 ret.clear();
2507 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2508 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2509 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2510 BOOST_CHECK(ret[0].d_type == QType::TXT);
2511 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2512 BOOST_CHECK_EQUAL(queriesCount, 0);
2513}
2514
2515BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2516 std::unique_ptr<SyncRes> sr;
895449a5 2517 initSR(sr);
648bcbd1
RG
2518
2519 primeHints();
2520
2521 const DNSName target("rpz.powerdns.com.");
2522 const ComboAddress ns("192.0.2.1:53");
2523
2524 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2525
2526 if (isRootServer(ip)) {
8455425c 2527 setLWResult(res, false, true, false, true);
648bcbd1
RG
2528 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2529 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2530 return 1;
2531 } else if (ip == ns) {
2532
2533 setLWResult(res, 0, true, false, true);
2534 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2535 return 1;
2536 }
2537
2538 return 0;
2539 });
2540
2541 DNSFilterEngine::Policy pol;
2542 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2543 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2544 zone->setName("Unit test policy 0");
2545 zone->addNSIPTrigger(Netmask(ns, 32), pol);
648bcbd1 2546 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2547 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2548 g_luaconfs.setState(luaconfsCopy);
2549
2550 vector<DNSRecord> ret;
2551 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2552 BOOST_CHECK_EQUAL(res, -2);
2553 BOOST_CHECK_EQUAL(ret.size(), 0);
2554}
2555
2556BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2557 std::unique_ptr<SyncRes> sr;
895449a5 2558 initSR(sr);
648bcbd1
RG
2559
2560 primeHints();
2561
2562 const DNSName target("rpz.powerdns.com.");
2563 const ComboAddress ns("[2001:DB8::42]:53");
2564
2565 sr->setAsyncCallback([target,ns](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2566
2567 if (isRootServer(ip)) {
8455425c 2568 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2569 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2570 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2571 return 1;
2572 } else if (ip == ns) {
2573
2574 setLWResult(res, 0, true, false, true);
2575 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2576 return 1;
2577 }
2578
2579 return 0;
2580 });
2581
2582 DNSFilterEngine::Policy pol;
2583 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2584 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2585 zone->setName("Unit test policy 0");
2586 zone->addNSIPTrigger(Netmask(ns, 128), pol);
648bcbd1 2587 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2588 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2589 g_luaconfs.setState(luaconfsCopy);
2590
2591 vector<DNSRecord> ret;
2592 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2593 BOOST_CHECK_EQUAL(res, -2);
2594 BOOST_CHECK_EQUAL(ret.size(), 0);
2595}
2596
2597BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2598 std::unique_ptr<SyncRes> sr;
895449a5 2599 initSR(sr);
648bcbd1
RG
2600
2601 primeHints();
2602
2603 const DNSName target("rpz.powerdns.com.");
2604 const ComboAddress ns("192.0.2.1:53");
2605 const DNSName nsName("ns1.powerdns.com.");
2606
2607 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2608
2609 if (isRootServer(ip)) {
8455425c 2610 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2611 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2612 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2613 return 1;
2614 } else if (ip == ns) {
2615
2616 setLWResult(res, 0, true, false, true);
2617 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2618 return 1;
2619 }
2620
2621 return 0;
2622 });
2623
2624 DNSFilterEngine::Policy pol;
2625 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2626 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2627 zone->setName("Unit test policy 0");
2628 zone->addNSTrigger(nsName, pol);
648bcbd1 2629 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2630 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2631 g_luaconfs.setState(luaconfsCopy);
2632
2633 vector<DNSRecord> ret;
2634 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2635 BOOST_CHECK_EQUAL(res, -2);
2636 BOOST_CHECK_EQUAL(ret.size(), 0);
2637}
2638
2639BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2640 std::unique_ptr<SyncRes> sr;
895449a5 2641 initSR(sr);
648bcbd1
RG
2642
2643 primeHints();
2644
2645 const DNSName target("rpz.powerdns.com.");
2646 const ComboAddress ns("192.0.2.1:53");
2647 const DNSName nsName("ns1.powerdns.com.");
2648
2649 sr->setAsyncCallback([target,ns,nsName](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2650
2651 if (isRootServer(ip)) {
8455425c 2652 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2653 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2654 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2655 return 1;
2656 } else if (ip == ns) {
2657
2658 setLWResult(res, 0, true, false, true);
2659 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2660 return 1;
2661 }
2662
2663 return 0;
2664 });
2665
2666 DNSFilterEngine::Policy pol;
2667 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2668 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2669 zone->setName("Unit test policy 0");
2670 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2671 zone->addNSTrigger(nsName, pol);
648bcbd1 2672 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2673 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2674 g_luaconfs.setState(luaconfsCopy);
2675
2676 /* RPZ is disabled for this query, we should not be blocked */
2677 sr->setWantsRPZ(false);
2678
2679 vector<DNSRecord> ret;
2680 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2681 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2682 BOOST_CHECK_EQUAL(ret.size(), 1);
2683}
2684
3e59ff53
RG
2685BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2686 std::unique_ptr<SyncRes> sr;
895449a5 2687 initSR(sr);
3e59ff53
RG
2688
2689 primeHints();
2690
2691 const DNSName target("powerdns.com.");
2692 const ComboAddress ns("192.0.2.1:53");
2693 const ComboAddress forwardedNS("192.0.2.42:53");
2694
2695 SyncRes::AuthDomain ad;
2696 ad.d_rdForward = false;
2697 ad.d_servers.push_back(forwardedNS);
a712cb56 2698 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53
RG
2699
2700 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2701
2702 if (ip == forwardedNS) {
6dfff36f
RG
2703 BOOST_CHECK_EQUAL(sendRDQuery, false);
2704
3e59ff53
RG
2705 setLWResult(res, 0, true, false, true);
2706 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2707 return 1;
2708 }
2709
2710 return 0;
2711 });
2712
2713 /* simulate a no-RD query */
2714 sr->setCacheOnly();
2715
2716 vector<DNSRecord> ret;
2717 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2718 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2719 BOOST_CHECK_EQUAL(ret.size(), 1);
2720}
2721
2722BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
2723 std::unique_ptr<SyncRes> sr;
895449a5 2724 initSR(sr);
3e59ff53
RG
2725
2726 primeHints();
2727
2728 const DNSName target("powerdns.com.");
2729 const ComboAddress ns("192.0.2.1:53");
2730 const ComboAddress forwardedNS("192.0.2.42:53");
2731
2732 SyncRes::AuthDomain ad;
2733 ad.d_rdForward = false;
2734 ad.d_servers.push_back(forwardedNS);
a712cb56 2735 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53
RG
2736
2737 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2738
2739 if (ip == forwardedNS) {
6dfff36f
RG
2740 BOOST_CHECK_EQUAL(sendRDQuery, false);
2741
3e59ff53
RG
2742 setLWResult(res, 0, true, false, true);
2743 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2744 return 1;
2745 }
2746
2747 return 0;
2748 });
2749
2750 vector<DNSRecord> ret;
2751 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2752 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2753 BOOST_CHECK_EQUAL(ret.size(), 1);
2754}
2755
2756BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
2757 std::unique_ptr<SyncRes> sr;
895449a5 2758 initSR(sr);
3e59ff53
RG
2759
2760 primeHints();
2761
2762 const DNSName target("powerdns.com.");
2763 const ComboAddress ns("192.0.2.1:53");
2764 const ComboAddress forwardedNS("192.0.2.42:53");
2765
2766 SyncRes::AuthDomain ad;
2767 ad.d_rdForward = true;
2768 ad.d_servers.push_back(forwardedNS);
a712cb56 2769 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53
RG
2770
2771 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2772
2773 if (ip == forwardedNS) {
6dfff36f
RG
2774 BOOST_CHECK_EQUAL(sendRDQuery, false);
2775
3e59ff53
RG
2776 setLWResult(res, 0, true, false, true);
2777 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2778 return 1;
2779 }
2780
2781 return 0;
2782 });
2783
2784 /* simulate a no-RD query */
2785 sr->setCacheOnly();
2786
2787 vector<DNSRecord> ret;
2788 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2789 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2790 BOOST_CHECK_EQUAL(ret.size(), 1);
2791}
2792
2793BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
2794 std::unique_ptr<SyncRes> sr;
895449a5 2795 initSR(sr);
3e59ff53
RG
2796
2797 primeHints();
2798
2799 const DNSName target("powerdns.com.");
2800 const ComboAddress ns("192.0.2.1:53");
2801 const ComboAddress forwardedNS("192.0.2.42:53");
2802
2803 SyncRes::AuthDomain ad;
2804 ad.d_rdForward = true;
2805 ad.d_servers.push_back(forwardedNS);
a712cb56 2806 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53
RG
2807
2808 sr->setAsyncCallback([forwardedNS](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2809
2810 if (ip == forwardedNS) {
6dfff36f
RG
2811 BOOST_CHECK_EQUAL(sendRDQuery, true);
2812
3e59ff53
RG
2813 setLWResult(res, 0, true, false, true);
2814 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2815 return 1;
2816 }
2817
2818 return 0;
2819 });
2820
2821 vector<DNSRecord> ret;
2822 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2823 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2824 BOOST_CHECK_EQUAL(ret.size(), 1);
2825}
2826
e1636f82 2827BOOST_AUTO_TEST_CASE(test_auth_zone_oob) {
f79a4e30 2828 std::unique_ptr<SyncRes> sr;
e1636f82 2829 initSR(sr, true);
f79a4e30
RG
2830
2831 primeHints();
2832
2833 size_t queriesCount = 0;
2834 const DNSName target("test.xx.");
2835 const ComboAddress targetAddr("127.0.0.1");
f79a4e30
RG
2836 const DNSName authZone("test.xx");
2837
2838 SyncRes::AuthDomain ad;
2839 DNSRecord dr;
f79a4e30
RG
2840
2841 dr.d_place = DNSResourceRecord::ANSWER;
e1636f82 2842 dr.d_name = target;
f79a4e30
RG
2843 dr.d_type = QType::A;
2844 dr.d_ttl = 1800;
e1636f82 2845 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
f79a4e30
RG
2846 ad.d_records.insert(dr);
2847
a712cb56 2848 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
f79a4e30 2849
e1636f82 2850 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
f79a4e30
RG
2851 queriesCount++;
2852 return 0;
2853 });
2854
2855 vector<DNSRecord> ret;
2856 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2857 BOOST_CHECK_EQUAL(res, 0);
2858 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2859 BOOST_CHECK(ret[0].d_type == QType::A);
2860 BOOST_CHECK_EQUAL(queriesCount, 0);
2861 BOOST_CHECK(sr->wasOutOfBand());
e1636f82 2862 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
2863
2864 /* a second time, to check that the OOB flag is set when the query cache is used */
2865 ret.clear();
2866 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2867 BOOST_CHECK_EQUAL(res, 0);
2868 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2869 BOOST_CHECK(ret[0].d_type == QType::A);
2870 BOOST_CHECK_EQUAL(queriesCount, 0);
2871 BOOST_CHECK(sr->wasOutOfBand());
e1636f82
RG
2872 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2873
2874 /* a third time, to check that the validation is disabled when the OOB flag is set */
2875 ret.clear();
2876 sr->setDNSSECValidationRequested(true);
2877 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2878 BOOST_CHECK_EQUAL(res, 0);
2879 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2880 BOOST_CHECK(ret[0].d_type == QType::A);
2881 BOOST_CHECK_EQUAL(queriesCount, 0);
2882 BOOST_CHECK(sr->wasOutOfBand());
2883 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2884}
2885
2886BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) {
2887 std::unique_ptr<SyncRes> sr;
2888 initSR(sr, true);
2889
2890 primeHints();
2891
2892 size_t queriesCount = 0;
2893 const DNSName target("cname.test.xx.");
2894 const DNSName targetCname("cname-target.test.xx.");
2895 const ComboAddress targetCnameAddr("127.0.0.1");
2896 const DNSName authZone("test.xx");
2897
2898 SyncRes::AuthDomain ad;
2899 DNSRecord dr;
2900
2901 dr.d_place = DNSResourceRecord::ANSWER;
2902 dr.d_name = target;
2903 dr.d_type = QType::CNAME;
2904 dr.d_ttl = 1800;
2905 dr.d_content = std::make_shared<CNAMERecordContent>(targetCname);
2906 ad.d_records.insert(dr);
2907
2908 dr.d_place = DNSResourceRecord::ANSWER;
2909 dr.d_name = targetCname;
2910 dr.d_type = QType::A;
2911 dr.d_ttl = 1800;
2912 dr.d_content = std::make_shared<ARecordContent>(targetCnameAddr);
2913 ad.d_records.insert(dr);
2914
2915 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2916
2917 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2918 queriesCount++;
2919 return 0;
2920 });
2921
2922 vector<DNSRecord> ret;
2923 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2924 BOOST_CHECK_EQUAL(res, 0);
2925 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2926 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2927 BOOST_CHECK(ret[1].d_type == QType::A);
2928 BOOST_CHECK_EQUAL(queriesCount, 0);
2929 BOOST_CHECK(sr->wasOutOfBand());
2930 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2931
2932 /* a second time, to check that the OOB flag is set when the query cache is used */
2933 ret.clear();
2934 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2935 BOOST_CHECK_EQUAL(res, 0);
2936 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2937 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2938 BOOST_CHECK(ret[1].d_type == QType::A);
2939 BOOST_CHECK_EQUAL(queriesCount, 0);
2940 BOOST_CHECK(sr->wasOutOfBand());
2941 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2942
2943 /* a third time, to check that the validation is disabled when the OOB flag is set */
2944 ret.clear();
2945 sr->setDNSSECValidationRequested(true);
2946 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2947 BOOST_CHECK_EQUAL(res, 0);
2948 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2949 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2950 BOOST_CHECK(ret[1].d_type == QType::A);
2951 BOOST_CHECK_EQUAL(queriesCount, 0);
2952 BOOST_CHECK(sr->wasOutOfBand());
2953 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
2954}
2955
3337c2f7
RG
2956BOOST_AUTO_TEST_CASE(test_auth_zone) {
2957 std::unique_ptr<SyncRes> sr;
895449a5 2958 initSR(sr);
3337c2f7
RG
2959
2960 primeHints();
2961
2962 size_t queriesCount = 0;
2963 const DNSName target("powerdns.com.");
2964 const ComboAddress addr("192.0.2.5");
2965
2966 SyncRes::AuthDomain ad;
2967 ad.d_name = target;
2968 DNSRecord dr;
2969 dr.d_place = DNSResourceRecord::ANSWER;
2970 dr.d_name = target;
2971 dr.d_type = QType::SOA;
2972 dr.d_ttl = 3600;
2973 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2974 ad.d_records.insert(dr);
2975
2976 dr.d_place = DNSResourceRecord::ANSWER;
2977 dr.d_name = target;
2978 dr.d_type = QType::A;
2979 dr.d_ttl = 3600;
2980 dr.d_content = std::make_shared<ARecordContent>(addr);
2981 ad.d_records.insert(dr);
2982
2983 auto map = std::make_shared<SyncRes::domainmap_t>();
2984 (*map)[target] = ad;
2985 SyncRes::setDomainMap(map);
2986
2987 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
2988
2989 queriesCount++;
2990 setLWResult(res, 0, true, false, true);
2991 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2992 return 1;
2993 });
2994
2995 vector<DNSRecord> ret;
2996 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2997 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
2998 BOOST_CHECK_EQUAL(ret.size(), 1);
2999 BOOST_CHECK(ret[0].d_type == QType::A);
3000 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3001 BOOST_CHECK_EQUAL(queriesCount, 0);
3002}
3003
3004BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
3005 std::unique_ptr<SyncRes> sr;
895449a5 3006 initSR(sr);
3337c2f7
RG
3007
3008 primeHints();
3009
3010 size_t queriesCount = 0;
3011 const DNSName target("powerdns.com.");
3012 const DNSName authZone("internal.powerdns.com.");
3013 const ComboAddress addr("192.0.2.5");
3014
3015 SyncRes::AuthDomain ad;
3016 ad.d_name = authZone;
3017 DNSRecord dr;
3018 dr.d_place = DNSResourceRecord::ANSWER;
3019 dr.d_name = authZone;
3020 dr.d_type = QType::SOA;
3021 dr.d_ttl = 3600;
3022 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3023 ad.d_records.insert(dr);
3024
3025 dr.d_place = DNSResourceRecord::ANSWER;
3026 dr.d_name = authZone;
3027 dr.d_type = QType::A;
3028 dr.d_ttl = 3600;
3029 dr.d_content = std::make_shared<ARecordContent>(addr);
3030 ad.d_records.insert(dr);
3031
3032 auto map = std::make_shared<SyncRes::domainmap_t>();
3033 (*map)[authZone] = ad;
3034 SyncRes::setDomainMap(map);
3035
3036 sr->setAsyncCallback([&queriesCount,target,authZone](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3037
3038 queriesCount++;
3039
3040 if (domain == target) {
3041 setLWResult(res, 0, true, false, true);
3042 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
3043 return 1;
3044 }
3045
3046 return 0;
3047 });
3048
3049 vector<DNSRecord> ret;
3050 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3051 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3052 BOOST_CHECK_EQUAL(ret.size(), 2);
3053 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3054 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
3055 BOOST_CHECK(ret[1].d_type == QType::A);
3056 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3057 BOOST_CHECK_EQUAL(queriesCount, 1);
3058}
3059
3060BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
3061 std::unique_ptr<SyncRes> sr;
895449a5 3062 initSR(sr);
3337c2f7
RG
3063
3064 primeHints();
3065
3066 size_t queriesCount = 0;
3067 const DNSName target("powerdns.com.");
3068 const DNSName externalCNAME("www.open-xchange.com.");
3069 const ComboAddress addr("192.0.2.5");
3070
3071 SyncRes::AuthDomain ad;
3072 ad.d_name = target;
3073 DNSRecord dr;
3074 dr.d_place = DNSResourceRecord::ANSWER;
3075 dr.d_name = target;
3076 dr.d_type = QType::SOA;
3077 dr.d_ttl = 3600;
3078 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3079 ad.d_records.insert(dr);
3080
3081 dr.d_place = DNSResourceRecord::ANSWER;
3082 dr.d_name = target;
3083 dr.d_type = QType::CNAME;
3084 dr.d_ttl = 3600;
3085 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
3086 ad.d_records.insert(dr);
3087
3088 auto map = std::make_shared<SyncRes::domainmap_t>();
3089 (*map)[target] = ad;
3090 SyncRes::setDomainMap(map);
3091
3092 sr->setAsyncCallback([&queriesCount,externalCNAME,addr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3093
3094 queriesCount++;
3095
3096 if (domain == externalCNAME) {
3097 setLWResult(res, 0, true, false, true);
3098 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
3099 return 1;
3100 }
3101
3102 return 0;
3103 });
3104
3105 vector<DNSRecord> ret;
3106 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3107 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3108 BOOST_CHECK_EQUAL(ret.size(), 2);
3109 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3110 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
3111 BOOST_CHECK(ret[1].d_type == QType::A);
3112 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3113 BOOST_CHECK_EQUAL(queriesCount, 1);
3114}
3115
3116BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
3117 std::unique_ptr<SyncRes> sr;
895449a5 3118 initSR(sr);
3337c2f7
RG
3119
3120 primeHints();
3121
3122 size_t queriesCount = 0;
3123 const DNSName target("nodata.powerdns.com.");
3124 const DNSName authZone("powerdns.com");
3125
3126 SyncRes::AuthDomain ad;
3127 ad.d_name = authZone;
3128 DNSRecord dr;
3129 dr.d_place = DNSResourceRecord::ANSWER;
3130 dr.d_name = target;
3131 dr.d_type = QType::A;
3132 dr.d_ttl = 3600;
3133 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3134 ad.d_records.insert(dr);
3135
3136 dr.d_place = DNSResourceRecord::ANSWER;
3137 dr.d_name = authZone;
3138 dr.d_type = QType::SOA;
3139 dr.d_ttl = 3600;
3140 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3141 ad.d_records.insert(dr);
3142
3143 auto map = std::make_shared<SyncRes::domainmap_t>();
3144 (*map)[authZone] = ad;
3145 SyncRes::setDomainMap(map);
3146
3147 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3148
3149 queriesCount++;
3150
3151 return 0;
3152 });
3153
3154 vector<DNSRecord> ret;
3155 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3156 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3157 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3158 BOOST_CHECK(ret[0].d_type == QType::SOA);
3159 BOOST_CHECK_EQUAL(queriesCount, 0);
3160}
3161
3162BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3163 std::unique_ptr<SyncRes> sr;
895449a5 3164 initSR(sr);
3337c2f7
RG
3165
3166 primeHints();
3167
3168 size_t queriesCount = 0;
3169 const DNSName target("nx.powerdns.com.");
3170 const DNSName authZone("powerdns.com");
3171
3172 SyncRes::AuthDomain ad;
3173 ad.d_name = authZone;
3174 DNSRecord dr;
3175 dr.d_place = DNSResourceRecord::ANSWER;
3176 dr.d_name = DNSName("powerdns.com.");
3177 dr.d_type = QType::SOA;
3178 dr.d_ttl = 3600;
3179 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3180 ad.d_records.insert(dr);
3181
3182 auto map = std::make_shared<SyncRes::domainmap_t>();
3183 (*map)[authZone] = ad;
3184 SyncRes::setDomainMap(map);
3185
3186 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3187
3188 queriesCount++;
3189
3190 return 0;
3191 });
3192
3193 vector<DNSRecord> ret;
3194 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3195 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3196 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3197 BOOST_CHECK(ret[0].d_type == QType::SOA);
3198 BOOST_CHECK_EQUAL(queriesCount, 0);
3199}
3200
3201BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3202 std::unique_ptr<SyncRes> sr;
e1636f82 3203 initSR(sr, true, false);
3337c2f7
RG
3204
3205 primeHints();
3206
3207 size_t queriesCount = 0;
3208 const DNSName target("www.test.powerdns.com.");
3209 const ComboAddress targetAddr("192.0.2.2");
3210 const DNSName ns("ns1.test.powerdns.com.");
3211 const ComboAddress nsAddr("192.0.2.1");
3212 const DNSName authZone("powerdns.com");
3213
3214 SyncRes::AuthDomain ad;
3215 ad.d_name = authZone;
3216 DNSRecord dr;
3217 dr.d_place = DNSResourceRecord::ANSWER;
3218 dr.d_name = authZone;
3219 dr.d_type = QType::SOA;
3220 dr.d_ttl = 3600;
3221 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3222 ad.d_records.insert(dr);
3223
3224 dr.d_place = DNSResourceRecord::ANSWER;
3225 dr.d_name = DNSName("test.powerdns.com.");
3226 dr.d_type = QType::NS;
3227 dr.d_ttl = 3600;
3228 dr.d_content = std::make_shared<NSRecordContent>(ns);
3229 ad.d_records.insert(dr);
3230
3231 dr.d_place = DNSResourceRecord::ANSWER;
3232 dr.d_name = ns;
3233 dr.d_type = QType::A;
3234 dr.d_ttl = 3600;
3235 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3236 ad.d_records.insert(dr);
3237
3238 auto map = std::make_shared<SyncRes::domainmap_t>();
3239 (*map)[authZone] = ad;
3240 SyncRes::setDomainMap(map);
3241
e1636f82
RG
3242 testkeysset_t keys;
3243 auto luaconfsCopy = g_luaconfs.getCopy();
3244 luaconfsCopy.dsAnchors.clear();
3245 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3246 g_luaconfs.setState(luaconfsCopy);
3247
3248 sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr,authZone,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3337c2f7
RG
3249
3250 queriesCount++;
e1636f82
RG
3251 if (type == QType::DS || type == QType::DNSKEY) {
3252 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone);
3253 }
3254
3337c2f7
RG
3255 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3256 setLWResult(res, 0, true, false, true);
3257 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3258 return 1;
3259 }
3260
3261 return 0;
3262 });
3263
e1636f82 3264 sr->setDNSSECValidationRequested(true);
3337c2f7
RG
3265 vector<DNSRecord> ret;
3266 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3267 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3268 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3269 BOOST_CHECK(ret[0].d_type == QType::A);
e1636f82
RG
3270 BOOST_CHECK_EQUAL(queriesCount, 4);
3271 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3337c2f7
RG
3272}
3273
3274BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3275 std::unique_ptr<SyncRes> sr;
895449a5 3276 initSR(sr);
3337c2f7
RG
3277
3278 primeHints();
3279
3280 size_t queriesCount = 0;
3281 const DNSName target("test.powerdns.com.");
3282 const ComboAddress targetAddr("192.0.2.2");
3283 const DNSName ns("ns1.test.powerdns.com.");
3284 const ComboAddress nsAddr("192.0.2.1");
3285 const DNSName authZone("powerdns.com");
3286
3287 SyncRes::AuthDomain ad;
3288 ad.d_name = authZone;
3289 DNSRecord dr;
3290 dr.d_place = DNSResourceRecord::ANSWER;
3291 dr.d_name = authZone;
3292 dr.d_type = QType::SOA;
3293 dr.d_ttl = 3600;
3294 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3295 ad.d_records.insert(dr);
3296
3297 dr.d_place = DNSResourceRecord::ANSWER;
3298 dr.d_name = DNSName("test.powerdns.com.");
3299 dr.d_type = QType::NS;
3300 dr.d_ttl = 3600;
3301 dr.d_content = std::make_shared<NSRecordContent>(ns);
3302 ad.d_records.insert(dr);
3303
3304 dr.d_place = DNSResourceRecord::ANSWER;
3305 dr.d_name = ns;
3306 dr.d_type = QType::A;
3307 dr.d_ttl = 3600;
3308 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3309 ad.d_records.insert(dr);
3310
3311 auto map = std::make_shared<SyncRes::domainmap_t>();
3312 (*map)[authZone] = ad;
3313 SyncRes::setDomainMap(map);
3314
3315 sr->setAsyncCallback([&queriesCount,nsAddr,target,targetAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3316
3317 queriesCount++;
3318
3319 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3320 setLWResult(res, 0, true, false, true);
3321 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3322 return 1;
3323 }
3324
3325 return 0;
3326 });
3327
3328 vector<DNSRecord> ret;
3329 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3330 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3331 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3332 BOOST_CHECK(ret[0].d_type == QType::A);
3333 BOOST_CHECK_EQUAL(queriesCount, 1);
3334}
3335
3336BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3337 std::unique_ptr<SyncRes> sr;
895449a5 3338 initSR(sr);
3337c2f7
RG
3339
3340 primeHints();
3341
3342 size_t queriesCount = 0;
3343 const DNSName target("test.powerdns.com.");
3344 const ComboAddress targetAddr("192.0.2.2");
3345 const DNSName authZone("powerdns.com");
3346
3347 SyncRes::AuthDomain ad;
3348 ad.d_name = authZone;
3349 DNSRecord dr;
3350 dr.d_place = DNSResourceRecord::ANSWER;
3351 dr.d_name = authZone;
3352 dr.d_type = QType::SOA;
3353 dr.d_ttl = 3600;
3354 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3355 ad.d_records.insert(dr);
3356
3357 dr.d_place = DNSResourceRecord::ANSWER;
3358 dr.d_name = DNSName("*.powerdns.com.");
3359 dr.d_type = QType::A;
3360 dr.d_ttl = 3600;
3361 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3362 ad.d_records.insert(dr);
3363
3364 auto map = std::make_shared<SyncRes::domainmap_t>();
3365 (*map)[authZone] = ad;
3366 SyncRes::setDomainMap(map);
3367
3368 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3369
3370 queriesCount++;
3371
3372 return 0;
3373 });
3374
3375 vector<DNSRecord> ret;
3376 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3377 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3378 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3379 BOOST_CHECK(ret[0].d_type == QType::A);
3380 BOOST_CHECK_EQUAL(queriesCount, 0);
3381}
3382
3383BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3384 std::unique_ptr<SyncRes> sr;
895449a5 3385 initSR(sr);
3337c2f7
RG
3386
3387 primeHints();
3388
3389 size_t queriesCount = 0;
3390 const DNSName target("test.powerdns.com.");
3391 const ComboAddress targetAddr("192.0.2.2");
3392 const DNSName authZone("powerdns.com");
3393
3394 SyncRes::AuthDomain ad;
3395 ad.d_name = authZone;
3396 DNSRecord dr;
3397 dr.d_place = DNSResourceRecord::ANSWER;
3398 dr.d_name = authZone;
3399 dr.d_type = QType::SOA;
3400 dr.d_ttl = 3600;
3401 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3402 ad.d_records.insert(dr);
3403
3404 dr.d_place = DNSResourceRecord::ANSWER;
3405 dr.d_name = DNSName("*.powerdns.com.");
3406 dr.d_type = QType::A;
3407 dr.d_ttl = 3600;
3408 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3409 ad.d_records.insert(dr);
3410
3411 auto map = std::make_shared<SyncRes::domainmap_t>();
3412 (*map)[authZone] = ad;
3413 SyncRes::setDomainMap(map);
3414
3415 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3416
3417 queriesCount++;
3418
3419 return 0;
3420 });
3421
3422 vector<DNSRecord> ret;
3423 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3424 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3425 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3426 BOOST_CHECK(ret[0].d_type == QType::SOA);
3427 BOOST_CHECK_EQUAL(queriesCount, 0);
3428}
3429
3430BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3431 std::unique_ptr<SyncRes> sr;
895449a5 3432 initSR(sr);
3337c2f7
RG
3433
3434 primeHints();
3435
3436 size_t queriesCount = 0;
3437 const DNSName target("powerdns.com.");
3438 const ComboAddress addr("192.0.2.5");
3439
3440 SyncRes::AuthDomain ad;
3441 ad.d_name = target;
3442 DNSRecord dr;
3443 dr.d_place = DNSResourceRecord::ANSWER;
3444 dr.d_name = target;
3445 dr.d_type = QType::SOA;
3446 dr.d_ttl = 3600;
3447 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3448 ad.d_records.insert(dr);
3449
3450 dr.d_place = DNSResourceRecord::ANSWER;
3451 dr.d_name = target;
3452 dr.d_type = QType::A;
3453 dr.d_ttl = 3600;
3454 dr.d_content = std::make_shared<ARecordContent>(addr);
3455 ad.d_records.insert(dr);
3456
3457 auto map = std::make_shared<SyncRes::domainmap_t>();
3458 (*map)[target] = ad;
3459 SyncRes::setDomainMap(map);
3460
3461 sr->setAsyncCallback([&queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3462
3463 queriesCount++;
3464 setLWResult(res, 0, true, false, true);
3465 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3466 return 1;
3467 });
3468
3469 /* simulate a no-RD query */
3470 sr->setCacheOnly();
3471
3472 vector<DNSRecord> ret;
3473 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3474 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3475 BOOST_CHECK_EQUAL(ret.size(), 1);
3476 BOOST_CHECK(ret[0].d_type == QType::A);
3477 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3478 BOOST_CHECK_EQUAL(queriesCount, 0);
3479}
3480
8455425c 3481BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
8455425c
RG
3482 init();
3483
3484 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3485 dcke->create(dcke->getBits());
3486 // cerr<<dcke->convertToISC()<<endl;
3487 DNSSECPrivateKey dpk;
3488 dpk.d_flags = 256;
3489 dpk.setKey(dcke);
3490
3491 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3492 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3493
3494 DNSName qname("powerdns.com.");
3495
179b340d 3496 time_t now = time(nullptr);
8455425c 3497 RRSIGRecordContent rrc;
179b340d
RG
3498 /* this RRSIG is valid for the current second only */
3499 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
8455425c
RG
3500
3501 skeyset_t keyset;
3502 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3503
3504 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3505 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3506
179b340d 3507 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
8455425c
RG
3508}
3509
3510BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3511 std::unique_ptr<SyncRes> sr;
895449a5 3512 initSR(sr, true);
8455425c 3513
0c43f455 3514 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3515
3516 primeHints();
3517 const DNSName target(".");
b7f378d1 3518 testkeysset_t keys;
8455425c
RG
3519
3520 auto luaconfsCopy = g_luaconfs.getCopy();
3521 luaconfsCopy.dsAnchors.clear();
3522 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3523 g_luaconfs.setState(luaconfsCopy);
3524
3525 size_t queriesCount = 0;
3526
3527 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3528 queriesCount++;
3529
3530 if (domain == target && type == QType::NS) {
3531
3532 setLWResult(res, 0, true, false, true);
3533 char addr[] = "a.root-servers.net.";
3534 for (char idx = 'a'; idx <= 'm'; idx++) {
3535 addr[0] = idx;
3536 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3537 }
3538
3539 addRRSIG(keys, res->d_records, domain, 300);
3540
3541 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3542 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3543
3544 return 1;
3545 } else if (domain == target && type == QType::DNSKEY) {
3546
3547 setLWResult(res, 0, true, false, true);
3548
3549 addDNSKEY(keys, domain, 300, res->d_records);
3550 addRRSIG(keys, res->d_records, domain, 300);
3551
3552 return 1;
3553 }
3554
3555 return 0;
3556 });
3557
3558 vector<DNSRecord> ret;
3559 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3560 BOOST_CHECK_EQUAL(res, RCode::NoError);
3561 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
3562 /* 13 NS + 1 RRSIG */
3563 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3564 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3565
3566 /* again, to test the cache */
3567 ret.clear();
3568 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3569 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3570 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
3571 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3572 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3573}
3574
3575BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3576 std::unique_ptr<SyncRes> sr;
895449a5 3577 initSR(sr, true);
8455425c 3578
0c43f455 3579 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3580
3581 primeHints();
3582 const DNSName target(".");
b7f378d1
RG
3583 testkeysset_t zskeys;
3584 testkeysset_t kskeys;
8455425c
RG
3585
3586 /* Generate key material for "." */
3587 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3588 dckeZ->create(dckeZ->getBits());
3589 DNSSECPrivateKey ksk;
3590 ksk.d_flags = 257;
3591 ksk.setKey(dckeZ);
b7f378d1
RG
3592 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3593
8455425c
RG
3594 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3595 dckeK->create(dckeK->getBits());
3596 DNSSECPrivateKey zsk;
3597 zsk.d_flags = 256;
3598 zsk.setKey(dckeK);
b7f378d1 3599 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3600
b7f378d1
RG
3601 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3602 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
8455425c
RG
3603
3604 /* Set the root DS */
8455425c
RG
3605 auto luaconfsCopy = g_luaconfs.getCopy();
3606 luaconfsCopy.dsAnchors.clear();
b7f378d1 3607 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
8455425c
RG
3608 g_luaconfs.setState(luaconfsCopy);
3609
3610 size_t queriesCount = 0;
3611
3612 sr->setAsyncCallback([target,&queriesCount,zskeys,kskeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3613 queriesCount++;
3614
3615 if (domain == target && type == QType::NS) {
3616
3617 setLWResult(res, 0, true, false, true);
3618 char addr[] = "a.root-servers.net.";
3619 for (char idx = 'a'; idx <= 'm'; idx++) {
3620 addr[0] = idx;
3621 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3622 }
3623
3624 addRRSIG(zskeys, res->d_records, domain, 300);
3625
3626 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3627 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3628
3629 return 1;
3630 } else if (domain == target && type == QType::DNSKEY) {
3631
3632 setLWResult(res, 0, true, false, true);
3633
3634 addDNSKEY(kskeys, domain, 300, res->d_records);
3635 addDNSKEY(zskeys, domain, 300, res->d_records);
3636 addRRSIG(kskeys, res->d_records, domain, 300);
3637
3638 return 1;
3639 }
3640
3641 return 0;
3642 });
3643
3644 vector<DNSRecord> ret;
3645 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3646 BOOST_CHECK_EQUAL(res, RCode::NoError);
3647 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
3648 /* 13 NS + 1 RRSIG */
3649 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3650 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3651
3652 /* again, to test the cache */
3653 ret.clear();
3654 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3655 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3656 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
3657 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3658 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3659}
3660
3661BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
3662 std::unique_ptr<SyncRes> sr;
895449a5 3663 initSR(sr, true);
8455425c 3664
0c43f455 3665 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3666
3667 primeHints();
3668 const DNSName target(".");
b7f378d1 3669 testkeysset_t keys;
8455425c
RG
3670
3671 auto luaconfsCopy = g_luaconfs.getCopy();
3672 luaconfsCopy.dsAnchors.clear();
3673 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3674 g_luaconfs.setState(luaconfsCopy);
3675
3676 size_t queriesCount = 0;
3677
3678 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3679 queriesCount++;
3680
3681 if (domain == target && type == QType::NS) {
3682
3683 setLWResult(res, 0, true, false, true);
3684 char addr[] = "a.root-servers.net.";
3685 for (char idx = 'a'; idx <= 'm'; idx++) {
3686 addr[0] = idx;
3687 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3688 }
3689
3690 addRRSIG(keys, res->d_records, domain, 300);
3691
3692 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3693 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3694
3695 return 1;
3696 } else if (domain == target && type == QType::DNSKEY) {
3697
3698 setLWResult(res, 0, true, false, true);
3699
3700 /* No DNSKEY */
3701
3702 return 1;
3703 }
3704
3705 return 0;
3706 });
3707
3708 vector<DNSRecord> ret;
3709 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3710 BOOST_CHECK_EQUAL(res, RCode::NoError);
3711 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3712 /* 13 NS + 1 RRSIG */
3713 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3714 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3715
3716 /* again, to test the cache */
3717 ret.clear();
3718 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3719 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3720 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3721 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3722 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3723}
3724
3725BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3726 std::unique_ptr<SyncRes> sr;
895449a5 3727 initSR(sr, true);
8455425c 3728
0c43f455 3729 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3730
3731 primeHints();
3732 const DNSName target(".");
b7f378d1
RG
3733 testkeysset_t dskeys;
3734 testkeysset_t keys;
8455425c
RG
3735
3736 /* Generate key material for "." */
3737 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3738 dckeDS->create(dckeDS->getBits());
3739 DNSSECPrivateKey dskey;
3740 dskey.d_flags = 257;
3741 dskey.setKey(dckeDS);
b7f378d1
RG
3742 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3743
8455425c
RG
3744 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3745 dcke->create(dcke->getBits());
3746 DNSSECPrivateKey dpk;
3747 dpk.d_flags = 256;
3748 dpk.setKey(dcke);
b7f378d1 3749 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3750
b7f378d1
RG
3751 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3752 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
8455425c
RG
3753
3754 /* Set the root DS */
8455425c
RG
3755 auto luaconfsCopy = g_luaconfs.getCopy();
3756 luaconfsCopy.dsAnchors.clear();
3757 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3758 g_luaconfs.setState(luaconfsCopy);
3759
3760 size_t queriesCount = 0;
3761
3762 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3763 queriesCount++;
3764
3765 if (domain == target && type == QType::NS) {
3766
3767 setLWResult(res, 0, true, false, true);
3768 char addr[] = "a.root-servers.net.";
3769 for (char idx = 'a'; idx <= 'm'; idx++) {
3770 addr[0] = idx;
3771 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3772 }
3773
3774 addRRSIG(keys, res->d_records, domain, 300);
3775
3776 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3777 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3778
3779 return 1;
3780 } else if (domain == target && type == QType::DNSKEY) {
3781
3782 setLWResult(res, 0, true, false, true);
3783
3784 addDNSKEY(keys, domain, 300, res->d_records);
3785 addRRSIG(keys, res->d_records, domain, 300);
3786
3787 return 1;
3788 }
3789
3790 return 0;
3791 });
3792
3793 vector<DNSRecord> ret;
3794 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3795 BOOST_CHECK_EQUAL(res, RCode::NoError);
3796 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3797 /* 13 NS + 1 RRSIG */
3798 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3799 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3800
3801 /* again, to test the cache */
3802 ret.clear();
3803 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3804 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3805 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3806 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3807 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3808}
3809
3810BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
3811 std::unique_ptr<SyncRes> sr;
895449a5 3812 initSR(sr, true);
8455425c 3813
0c43f455 3814 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3815
3816 primeHints();
3817 const DNSName target(".");
b7f378d1
RG
3818 testkeysset_t keys;
3819 testkeysset_t rrsigkeys;
8455425c
RG
3820
3821 auto luaconfsCopy = g_luaconfs.getCopy();
3822 luaconfsCopy.dsAnchors.clear();
3823 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3824 g_luaconfs.setState(luaconfsCopy);
3825
3826 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3827 dckeRRSIG->create(dckeRRSIG->getBits());
3828 DNSSECPrivateKey rrsigkey;
3829 rrsigkey.d_flags = 257;
3830 rrsigkey.setKey(dckeRRSIG);
b7f378d1
RG
3831 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
3832
3833 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
8455425c
RG
3834
3835 size_t queriesCount = 0;
3836
3837 sr->setAsyncCallback([target,&queriesCount,keys,rrsigkeys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3838 queriesCount++;
3839
3840 if (domain == target && type == QType::NS) {
3841
3842 setLWResult(res, 0, true, false, true);
3843 char addr[] = "a.root-servers.net.";
3844 for (char idx = 'a'; idx <= 'm'; idx++) {
3845 addr[0] = idx;
3846 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3847 }
3848
3849 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3850
3851 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3852 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3853
3854 return 1;
3855 } else if (domain == target && type == QType::DNSKEY) {
3856
3857 setLWResult(res, 0, true, false, true);
3858
3859 addDNSKEY(keys, domain, 300, res->d_records);
3860 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3861
3862 return 1;
3863 }
3864
3865 return 0;
3866 });
3867
3868 vector<DNSRecord> ret;
3869 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3870 BOOST_CHECK_EQUAL(res, RCode::NoError);
3871 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3872 /* 13 NS + 1 RRSIG */
3873 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3874 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3875
3876 /* again, to test the cache */
3877 ret.clear();
3878 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3879 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3880 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3881 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3882 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3883}
3884
3885BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
3886 std::unique_ptr<SyncRes> sr;
895449a5 3887 initSR(sr, true);
8455425c 3888
0c43f455 3889 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3890
3891 primeHints();
3892 const DNSName target(".");
b7f378d1 3893 testkeysset_t keys;
8455425c
RG
3894
3895 auto luaconfsCopy = g_luaconfs.getCopy();
3896 luaconfsCopy.dsAnchors.clear();
3897 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3898 g_luaconfs.setState(luaconfsCopy);
3899
3900 size_t queriesCount = 0;
3901
3902 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3903 queriesCount++;
3904
3905 if (domain == target && type == QType::NS) {
3906
3907 setLWResult(res, 0, true, false, true);
3908 char addr[] = "a.root-servers.net.";
3909 for (char idx = 'a'; idx <= 'm'; idx++) {
3910 addr[0] = idx;
3911 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3912 }
3913
3914 /* No RRSIG */
3915
3916 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3917 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3918
3919 return 1;
3920 } else if (domain == target && type == QType::DNSKEY) {
3921
3922 setLWResult(res, 0, true, false, true);
3923
3924 addDNSKEY(keys, domain, 300, res->d_records);
3925 addRRSIG(keys, res->d_records, domain, 300);
3926
3927 return 1;
3928 }
3929
3930 return 0;
3931 });
3932
3933 vector<DNSRecord> ret;
3934 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3935 BOOST_CHECK_EQUAL(res, RCode::NoError);
3936 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3937 /* 13 NS + 0 RRSIG */
3938 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3939 /* no RRSIG so no query for DNSKEYs */
3940 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
3941
3942 /* again, to test the cache */
3943 ret.clear();
3944 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3945 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3946 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3947 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3948 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
3949}
3950
3951BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
3952 std::unique_ptr<SyncRes> sr;
895449a5 3953 initSR(sr, true);
8455425c 3954
0c43f455 3955 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3956
3957 primeHints();
3958 const DNSName target(".");
b7f378d1 3959 testkeysset_t keys;
8455425c
RG
3960
3961 /* Generate key material for "." */
3962 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3963 dcke->create(dcke->getBits());
3964 DNSSECPrivateKey dpk;
3965 dpk.d_flags = 256;
3966 dpk.setKey(dcke);
3967 /* Fake algorithm number (private) */
3968 dpk.d_algorithm = 253;
3969
8455425c 3970 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
b7f378d1 3971 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
8455425c
RG
3972 /* Fake algorithm number (private) */
3973 drc.d_algorithm = 253;
3974
b7f378d1 3975 /* Set the root DS */
8455425c
RG
3976 auto luaconfsCopy = g_luaconfs.getCopy();
3977 luaconfsCopy.dsAnchors.clear();
3978 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3979 g_luaconfs.setState(luaconfsCopy);
3980
3981 size_t queriesCount = 0;
3982
3983 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3984 queriesCount++;
3985
3986 if (domain == target && type == QType::NS) {
3987
3988 setLWResult(res, 0, true, false, true);
3989 char addr[] = "a.root-servers.net.";
3990 for (char idx = 'a'; idx <= 'm'; idx++) {
3991 addr[0] = idx;
3992 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3993 }
3994
3995 addRRSIG(keys, res->d_records, domain, 300);
3996
3997 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3998 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3999
4000 return 1;
4001 } else if (domain == target && type == QType::DNSKEY) {
4002
4003 setLWResult(res, 0, true, false, true);
4004
4005 addDNSKEY(keys, domain, 300, res->d_records);
4006 addRRSIG(keys, res->d_records, domain, 300);
4007
4008 return 1;
4009 }
4010
4011 return 0;
4012 });
4013
4014 vector<DNSRecord> ret;
4015 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4016 BOOST_CHECK_EQUAL(res, RCode::NoError);
4017 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4018 /* 13 NS + 1 RRSIG */
4019 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4020 /* no supported DS so no query for DNSKEYs */
4021 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4022
4023 /* again, to test the cache */
4024 ret.clear();
4025 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4026 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4027 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4028 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4029 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4030}
4031
4032BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
4033 std::unique_ptr<SyncRes> sr;
895449a5 4034 initSR(sr, true);
8455425c 4035
0c43f455 4036 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4037
4038 primeHints();
4039 const DNSName target(".");
b7f378d1 4040 testkeysset_t keys;
8455425c
RG
4041
4042 /* Generate key material for "." */
4043 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4044 dcke->create(dcke->getBits());
4045 DNSSECPrivateKey dpk;
4046 dpk.d_flags = 256;
4047 dpk.setKey(dcke);
8455425c
RG
4048 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
4049 /* Fake digest number (reserved) */
4050 drc.d_digesttype = 0;
4051
b7f378d1
RG
4052 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
4053
4054 /* Set the root DS */
8455425c
RG
4055 auto luaconfsCopy = g_luaconfs.getCopy();
4056 luaconfsCopy.dsAnchors.clear();
4057 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4058 g_luaconfs.setState(luaconfsCopy);
4059
4060 size_t queriesCount = 0;
4061
4062 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4063 queriesCount++;
4064
4065 if (domain == target && type == QType::NS) {
4066
4067 setLWResult(res, 0, true, false, true);
4068 char addr[] = "a.root-servers.net.";
4069 for (char idx = 'a'; idx <= 'm'; idx++) {
4070 addr[0] = idx;
4071 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4072 }
4073
4074 addRRSIG(keys, res->d_records, domain, 300);
4075
4076 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4077 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4078
4079 return 1;
4080 } else if (domain == target && type == QType::DNSKEY) {
4081
4082 setLWResult(res, 0, true, false, true);
4083
4084 addDNSKEY(keys, domain, 300, res->d_records);
4085 addRRSIG(keys, res->d_records, domain, 300);
4086
4087 return 1;
4088 }
4089
4090 return 0;
4091 });
4092
4093 vector<DNSRecord> ret;
4094 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4095 BOOST_CHECK_EQUAL(res, RCode::NoError);
4096 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4097 /* 13 NS + 1 RRSIG */
4098 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4099 /* no supported DS so no query for DNSKEYs */
4100 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4101
4102 /* again, to test the cache */
4103 ret.clear();
4104 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4105 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4106 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4107 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4108 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4109}
4110
3d5ebf10
RG
4111BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
4112 std::unique_ptr<SyncRes> sr;
4113 initSR(sr, true);
4114
0c43f455 4115 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4116
4117 primeHints();
4118 const DNSName target(".");
4119 testkeysset_t keys;
4120
4121 auto luaconfsCopy = g_luaconfs.getCopy();
4122 luaconfsCopy.dsAnchors.clear();
4123 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4124
4125 g_luaconfs.setState(luaconfsCopy);
4126
4127 size_t queriesCount = 0;
4128
4129 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4130 queriesCount++;
4131
4132 if (domain == target && type == QType::NS) {
4133
4134 setLWResult(res, 0, true, false, true);
4135 char addr[] = "a.root-servers.net.";
4136 for (char idx = 'a'; idx <= 'm'; idx++) {
4137 addr[0] = idx;
4138 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4139 }
4140
4141 addRRSIG(keys, res->d_records, domain, 300, true);
4142
4143 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4144 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4145
4146 return 1;
4147 } else if (domain == target && type == QType::DNSKEY) {
4148
4149 setLWResult(res, 0, true, false, true);
4150
4151 addDNSKEY(keys, domain, 300, res->d_records);
4152 addRRSIG(keys, res->d_records, domain, 300);
4153
4154 return 1;
4155 }
4156
4157 return 0;
4158 });
4159
4160 vector<DNSRecord> ret;
4161 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4162 BOOST_CHECK_EQUAL(res, RCode::NoError);
4163 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4164 /* 13 NS + 1 RRSIG */
4165 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4166 BOOST_CHECK_EQUAL(queriesCount, 2);
4167
4168 /* again, to test the cache */
4169 ret.clear();
4170 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4171 BOOST_CHECK_EQUAL(res, RCode::NoError);
4172 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4173 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4174 BOOST_CHECK_EQUAL(queriesCount, 2);
4175}
4176
4177BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
4178 std::unique_ptr<SyncRes> sr;
4179 initSR(sr, true);
4180
0c43f455 4181 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4182
4183 primeHints();
4184 const DNSName target(".");
4185 testkeysset_t keys;
4186
4187 auto luaconfsCopy = g_luaconfs.getCopy();
4188 luaconfsCopy.dsAnchors.clear();
4189 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4190
4191 g_luaconfs.setState(luaconfsCopy);
4192
4193 size_t queriesCount = 0;
4194
4195 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4196 queriesCount++;
4197
4198 if (domain == target && type == QType::NS) {
4199
4200 setLWResult(res, 0, true, false, true);
4201 char addr[] = "a.root-servers.net.";
4202 for (char idx = 'a'; idx <= 'm'; idx++) {
4203 addr[0] = idx;
4204 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4205 }
4206
4207 /* FORCE WRONG ALGO */
4208 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4209
4210 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4211 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4212
4213 return 1;
4214 } else if (domain == target && type == QType::DNSKEY) {
4215
4216 setLWResult(res, 0, true, false, true);
4217
4218 addDNSKEY(keys, domain, 300, res->d_records);
4219 addRRSIG(keys, res->d_records, domain, 300);
4220
4221 return 1;
4222 }
4223
4224 return 0;
4225 });
4226
4227 vector<DNSRecord> ret;
4228 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4229 BOOST_CHECK_EQUAL(res, RCode::NoError);
4230 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4231 /* 13 NS + 1 RRSIG */
4232 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4233 BOOST_CHECK_EQUAL(queriesCount, 2);
4234
4235 /* again, to test the cache */
4236 ret.clear();
4237 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4238 BOOST_CHECK_EQUAL(res, RCode::NoError);
4239 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4240 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4241 BOOST_CHECK_EQUAL(queriesCount, 2);
4242}
4243
cd48a0ff
RG
4244BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds) {
4245 std::unique_ptr<SyncRes> sr;
4246 initSR(sr, true);
4247
4248 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4249
4250 primeHints();
4251 const DNSName target("com.");
4252 const ComboAddress targetAddr("192.0.2.42");
4253 testkeysset_t keys;
4254
4255 auto luaconfsCopy = g_luaconfs.getCopy();
4256 luaconfsCopy.dsAnchors.clear();
4257 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4258 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4259
4260 g_luaconfs.setState(luaconfsCopy);
4261
4262 size_t queriesCount = 0;
4263
4264 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4265 queriesCount++;
4266
4267 DNSName auth = domain;
4268
4269 if (type == QType::DS || type == QType::DNSKEY) {
4270 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4271 return 0;
4272 }
4273
4274 if (type == QType::DS && domain == target) {
4275 /* remove the last record, which is the DS's RRSIG */
4276 res->d_records.pop_back();
4277 }
4278
4279 return 1;
4280 }
4281
4282 if (isRootServer(ip)) {
4283 setLWResult(res, 0, false, false, true);
4284 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4285 /* Include the DS but omit the RRSIG*/
4286 addDS(DNSName("com."), 300, res->d_records, keys);
4287 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4288 return 1;
4289 }
4290
4291 if (ip == ComboAddress("192.0.2.1:53")) {
4292 setLWResult(res, RCode::NoError, true, false, true);
4293 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4294 addRRSIG(keys, res->d_records, auth, 300);
4295 return 1;
4296 }
4297
4298 return 0;
4299 });
4300
4301 vector<DNSRecord> ret;
4302 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4303 BOOST_CHECK_EQUAL(res, RCode::NoError);
4304 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4305 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4306 BOOST_CHECK_EQUAL(queriesCount, 4);
4307
4308 /* again, to test the cache */
4309 ret.clear();
4310 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4311 BOOST_CHECK_EQUAL(res, RCode::NoError);
4312 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4313 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4314 BOOST_CHECK_EQUAL(queriesCount, 4);
4315
4316 /* now we ask directly for the DS */
4317 ret.clear();
4318 res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4319 BOOST_CHECK_EQUAL(res, RCode::NoError);
4320 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4321 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4322 BOOST_CHECK_EQUAL(queriesCount, 4);
4323}
4324
4325BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds_direct) {
4326 std::unique_ptr<SyncRes> sr;
4327 initSR(sr, true);
4328
4329 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4330
4331 primeHints();
4332 const DNSName target("com.");
4333 testkeysset_t keys;
4334
4335 auto luaconfsCopy = g_luaconfs.getCopy();
4336 luaconfsCopy.dsAnchors.clear();
4337 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4338 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4339
4340 g_luaconfs.setState(luaconfsCopy);
4341
4342 size_t queriesCount = 0;
4343
4344 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4345 queriesCount++;
4346
4347 DNSName auth = domain;
4348
4349 if (type == QType::DS || type == QType::DNSKEY) {
4350 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4351 return 0;
4352 }
4353
4354 if (type == QType::DS && domain == target) {
4355 /* remove the last record, which is the DS's RRSIG */
4356 res->d_records.pop_back();
4357 }
4358
4359 return 1;
4360 }
4361
4362 if (isRootServer(ip)) {
4363 setLWResult(res, 0, false, false, true);
4364 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4365 /* Include the DS but omit the RRSIG*/
4366 addDS(DNSName("com."), 300, res->d_records, keys);
4367 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4368 return 1;
4369 }
4370
4371 return 0;
4372 });
4373
4374 vector<DNSRecord> ret;
4375 int res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4376 BOOST_CHECK_EQUAL(res, RCode::NoError);
4377 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4378 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4379 BOOST_CHECK_EQUAL(queriesCount, 1);
4380}
4381
b7f378d1 4382BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
8455425c 4383 std::unique_ptr<SyncRes> sr;
895449a5 4384 initSR(sr, true);
8455425c 4385
0c43f455 4386 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4387
4388 primeHints();
4389 const DNSName target("powerdns.com.");
b7f378d1
RG
4390 const ComboAddress targetAddr("192.0.2.42");
4391 testkeysset_t keys;
8455425c
RG
4392
4393 auto luaconfsCopy = g_luaconfs.getCopy();
4394 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4395 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4396 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4397 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
8455425c
RG
4398
4399 g_luaconfs.setState(luaconfsCopy);
4400
4401 size_t queriesCount = 0;
4402
b7f378d1 4403 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
8455425c
RG
4404 queriesCount++;
4405
b7f378d1
RG
4406 DNSName auth = domain;
4407 if (domain == target) {
4408 auth = DNSName("powerdns.com.");
4409 }
5374b03b
RG
4410
4411 if (type == QType::DS || type == QType::DNSKEY) {
4412 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8455425c 4413 }
5374b03b
RG
4414
4415 if (isRootServer(ip)) {
4416 setLWResult(res, 0, false, false, true);
4417 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4418 addDS(DNSName("com."), 300, res->d_records, keys);
4419 addRRSIG(keys, res->d_records, DNSName("."), 300);
4420 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8455425c
RG
4421 return 1;
4422 }
5374b03b
RG
4423
4424 if (ip == ComboAddress("192.0.2.1:53")) {
4425 if (domain == DNSName("com.")) {
4426 setLWResult(res, 0, true, false, true);
4427 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4428 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4429 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4430 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4431 }
5374b03b
RG
4432 else {
4433 setLWResult(res, 0, false, false, true);
4434 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4435 addDS(auth, 300, res->d_records, keys);
4436 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4437 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8455425c 4438 }
5374b03b
RG
4439 return 1;
4440 }
4441
4442 if (ip == ComboAddress("192.0.2.2:53")) {
4443 if (type == QType::NS) {
4444 setLWResult(res, 0, true, false, true);
4445 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4446 addRRSIG(keys, res->d_records, auth, 300);
4447 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4448 addRRSIG(keys, res->d_records, auth, 300);
8455425c 4449 }
5374b03b
RG
4450 else {
4451 setLWResult(res, RCode::NoError, true, false, true);
4452 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4453 addRRSIG(keys, res->d_records, auth, 300);
4454 }
4455 return 1;
8455425c
RG
4456 }
4457
4458 return 0;
4459 });
4460
4461 vector<DNSRecord> ret;
4462 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1
RG
4463 BOOST_CHECK_EQUAL(res, RCode::NoError);
4464 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4465 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4466 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4467
4468 /* again, to test the cache */
4469 ret.clear();
4470 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4471 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4472 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1 4473 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4474 BOOST_CHECK_EQUAL(queriesCount, 8);
8455425c
RG
4475}
4476
428f41b7
RG
4477BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4478 std::unique_ptr<SyncRes> sr;
4479 initSR(sr, true);
4480
0c43f455 4481 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4482
4483 primeHints();
4484 const DNSName target("powerdns.com.");
4485 const ComboAddress targetAddr("192.0.2.42");
4486 testkeysset_t keys;
4487
4488 auto luaconfsCopy = g_luaconfs.getCopy();
4489 luaconfsCopy.dsAnchors.clear();
4490 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4491 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4492 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4493 g_luaconfs.setState(luaconfsCopy);
4494
4495 size_t queriesCount = 0;
4496
4497 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4498 queriesCount++;
4499
4500 DNSName auth = domain;
4501 if (domain == target) {
4502 auth = DNSName("powerdns.com.");
4503 }
5374b03b
RG
4504
4505 if (type == QType::DS || type == QType::DNSKEY) {
4506 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4507 }
5374b03b
RG
4508
4509 if (isRootServer(ip)) {
4510 setLWResult(res, 0, false, false, true);
4511 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4512 addDS(DNSName("com."), 300, res->d_records, keys);
4513 addRRSIG(keys, res->d_records, DNSName("."), 300);
4514 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4515 return 1;
4516 }
5374b03b
RG
4517
4518 if (ip == ComboAddress("192.0.2.1:53")) {
4519 if (domain == DNSName("com.")) {
4520 setLWResult(res, 0, true, false, true);
4521 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4522 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4523 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4524 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4525 }
5374b03b
RG
4526 else {
4527 setLWResult(res, 0, false, false, true);
4528 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4529 addDS(auth, 300, res->d_records, keys);
4530 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4531 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4532 }
5374b03b
RG
4533 return 1;
4534 }
4535
4536 if (ip == ComboAddress("192.0.2.2:53")) {
4537 if (type == QType::NS) {
4538 setLWResult(res, 0, true, false, true);
4539 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4540 addRRSIG(keys, res->d_records, auth, 300);
4541 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4542 addRRSIG(keys, res->d_records, auth, 300);
4543 }
4544 else {
4545 setLWResult(res, RCode::NoError, true, false, true);
4546 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4547 addRRSIG(keys, res->d_records, auth, 300);
428f41b7 4548 }
5374b03b 4549 return 1;
428f41b7
RG
4550 }
4551
4552 return 0;
4553 });
4554
4555 vector<DNSRecord> ret;
4556 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4557 BOOST_CHECK_EQUAL(res, RCode::NoError);
4558 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4559 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4560 BOOST_CHECK_EQUAL(queriesCount, 8);
4561
4562 /* again, to test the cache */
4563 ret.clear();
4564 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4565 BOOST_CHECK_EQUAL(res, RCode::NoError);
4566 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4567 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4568 BOOST_CHECK_EQUAL(queriesCount, 8);
4569
4570 /* this time we ask for the NS that should be in the cache, to check
4571 the validation status */
4572 ret.clear();
4573 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4574 BOOST_CHECK_EQUAL(res, RCode::NoError);
4575 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4576 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4577 BOOST_CHECK_EQUAL(queriesCount, 9);
428f41b7
RG
4578
4579}
4580
4581BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4582 std::unique_ptr<SyncRes> sr;
4583 initSR(sr, true);
4584
0c43f455 4585 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4586
4587 primeHints();
4588 const DNSName target("powerdns.com.");
4589 const ComboAddress targetAddr("192.0.2.42");
4590 testkeysset_t keys;
4591
4592 auto luaconfsCopy = g_luaconfs.getCopy();
4593 luaconfsCopy.dsAnchors.clear();
4594 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4595 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4596 g_luaconfs.setState(luaconfsCopy);
4597
4598 size_t queriesCount = 0;
4599
4600 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4601 queriesCount++;
4602
4603 DNSName auth = domain;
4604 if (domain == target) {
4605 auth = DNSName("powerdns.com.");
4606 }
5374b03b
RG
4607
4608 if (type == QType::DS || type == QType::DNSKEY) {
4609 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4610 }
5374b03b
RG
4611
4612 if (isRootServer(ip)) {
4613 setLWResult(res, 0, false, false, true);
4614 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4615 addDS(DNSName("com."), 300, res->d_records, keys);
4616 addRRSIG(keys, res->d_records, DNSName("."), 300);
4617 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4618 return 1;
4619 }
5374b03b
RG
4620
4621 if (ip == ComboAddress("192.0.2.1:53")) {
4622 if (domain == DNSName("com.")) {
4623 setLWResult(res, 0, true, false, true);
4624 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4625 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4626 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4627 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4628 }
5374b03b
RG
4629 else {
4630 setLWResult(res, 0, false, false, true);
4631 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4632 /* no DS */
4633 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4634 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4635 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4636 }
5374b03b
RG
4637 return 1;
4638 }
4639
4640 if (ip == ComboAddress("192.0.2.2:53")) {
4641 if (type == QType::NS) {
4642 setLWResult(res, 0, true, false, true);
4643 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4644 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 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 }
4650 return 1;
428f41b7
RG
4651 }
4652
4653 return 0;
4654 });
4655
4656 vector<DNSRecord> ret;
4657 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4658 BOOST_CHECK_EQUAL(res, RCode::NoError);
4659 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4660 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4661 BOOST_CHECK_EQUAL(queriesCount, 7);
4662
4663 /* again, to test the cache */
4664 ret.clear();
4665 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4666 BOOST_CHECK_EQUAL(res, RCode::NoError);
4667 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4668 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4669 BOOST_CHECK_EQUAL(queriesCount, 7);
4670
4671 /* this time we ask for the NS that should be in the cache, to check
4672 the validation status */
4673 ret.clear();
4674 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4675 BOOST_CHECK_EQUAL(res, RCode::NoError);
4676 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4677 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4678 BOOST_CHECK_EQUAL(queriesCount, 8);
428f41b7
RG
4679}
4680
b7f378d1 4681BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
8455425c 4682 std::unique_ptr<SyncRes> sr;
895449a5 4683 initSR(sr, true);
8455425c 4684
0c43f455 4685 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4686
4687 primeHints();
b7f378d1
RG
4688 const DNSName target("powerdns.com.");
4689 const ComboAddress targetAddr("192.0.2.42");
4690 testkeysset_t keys;
8455425c
RG
4691
4692 auto luaconfsCopy = g_luaconfs.getCopy();
4693 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4694 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4695 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4696 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4697
4698 /* Add a NTA for "powerdns.com" */
4699 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
8455425c 4700
8455425c
RG
4701 g_luaconfs.setState(luaconfsCopy);
4702
4703 size_t queriesCount = 0;
4704
b7f378d1 4705 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
8455425c
RG
4706 queriesCount++;
4707
b7f378d1
RG
4708 DNSName auth = domain;
4709 if (domain == target) {
4710 auth = DNSName("powerdns.com.");
4711 }
5374b03b
RG
4712
4713 if (type == QType::DS || type == QType::DNSKEY) {
4714 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
b7f378d1 4715 }
5374b03b
RG
4716
4717 if (isRootServer(ip)) {
4718 setLWResult(res, 0, false, false, true);
4719 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4720 addDS(DNSName("com."), 300, res->d_records, keys);
4721 addRRSIG(keys, res->d_records, DNSName("."), 300);
4722 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1
RG
4723 return 1;
4724 }
5374b03b
RG
4725
4726 if (ip == ComboAddress("192.0.2.1:53")) {
4727 if (domain == DNSName("com.")) {
4728 setLWResult(res, 0, true, false, true);
4729 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4730 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4731 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4732 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4733 }
5374b03b
RG
4734 else {
4735 setLWResult(res, 0, false, false, true);
4736 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4737 addDS(auth, 300, res->d_records, keys);
4738 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4739 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1 4740 }
5374b03b
RG
4741 return 1;
4742 }
4743
4744 if (ip == ComboAddress("192.0.2.2:53")) {
4745 if (type == QType::NS) {
4746 setLWResult(res, 0, true, false, true);
4747 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4748 addRRSIG(keys, res->d_records, auth, 300);
4749 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4750 addRRSIG(keys, res->d_records, auth, 300);
4751 }
4752 else {
4753 setLWResult(res, RCode::NoError, true, false, true);
4754 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4755 addRRSIG(keys, res->d_records, auth, 300);
b7f378d1 4756 }
5374b03b 4757 return 1;
b7f378d1
RG
4758 }
4759
4760 return 0;
4761 });
4762
4763 vector<DNSRecord> ret;
4764 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4765 BOOST_CHECK_EQUAL(res, RCode::NoError);
4766 /* Should be insecure because of the NTA */
4767 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4768 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4769 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4770
4771 /* again, to test the cache */
4772 ret.clear();
4773 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4774 BOOST_CHECK_EQUAL(res, RCode::NoError);
4775 /* Should be insecure because of the NTA */
4776 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4777 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4778 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4779}
4780
4781BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4782 std::unique_ptr<SyncRes> sr;
895449a5 4783 initSR(sr, true);
b7f378d1 4784
0c43f455 4785 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
4786
4787 primeHints();
4788 const DNSName target("powerdns.com.");
4789 const ComboAddress targetAddr("192.0.2.42");
4790 testkeysset_t keys;
4791
4792 auto luaconfsCopy = g_luaconfs.getCopy();
4793 luaconfsCopy.dsAnchors.clear();
4794 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4795 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4796 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4797
4798 /* Add a NTA for "powerdns.com" */
4799 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4800
4801 g_luaconfs.setState(luaconfsCopy);
4802
4803 size_t queriesCount = 0;
4804
4805 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4806 queriesCount++;
4807
4808 if (type == QType::DS || type == QType::DNSKEY) {
4809 setLWResult(res, 0, false, false, true);
4810 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4811 return 1;
4812 }
f24465e5 4813 else {
b7f378d1
RG
4814 if (isRootServer(ip)) {
4815 setLWResult(res, 0, false, false, true);
4816 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4817 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4818 return 1;
4819 }
4820 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
4821 if (domain == DNSName("com.")) {
4822 setLWResult(res, 0, true, false, true);
4823 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4824 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4825 }
4826 else {
4827 setLWResult(res, 0, false, false, true);
4828 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4829 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4830 }
b7f378d1
RG
4831 return 1;
4832 }
4833 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
4834 if (type == QType::NS) {
4835 setLWResult(res, 0, true, false, true);
4836 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4837 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4838 }
4839 else {
4840 setLWResult(res, RCode::NoError, true, false, true);
4841 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4842 }
b7f378d1
RG
4843 return 1;
4844 }
4845 }
4846
4847 return 0;
4848 });
4849
4850 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
4851 vector<DNSRecord> ret;
4852 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4853 BOOST_CHECK_EQUAL(res, RCode::NoError);
4854 /* Should be insecure because of the NTA */
4855 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4856 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4857 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
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);
5374b03b 4865 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
4866}
4867
4868BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
4869 std::unique_ptr<SyncRes> sr;
895449a5 4870 initSR(sr, true);
b7f378d1 4871
0c43f455 4872 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
4873
4874 primeHints();
4875 const DNSName target("powerdns.com.");
4876 testkeysset_t keys;
4877
4878 auto luaconfsCopy = g_luaconfs.getCopy();
4879 luaconfsCopy.dsAnchors.clear();
4880 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4881 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4882 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4883
4884 g_luaconfs.setState(luaconfsCopy);
4885
4886 size_t queriesCount = 0;
4887
4888 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4889 queriesCount++;
4890
5374b03b
RG
4891 if (type == QType::DS || type == QType::DNSKEY) {
4892 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 4893 }
f24465e5 4894 else {
b7f378d1
RG
4895 if (isRootServer(ip)) {
4896 setLWResult(res, 0, false, false, true);
4897 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4898 addDS(DNSName("com."), 300, res->d_records, keys);
4899 addRRSIG(keys, res->d_records, DNSName("."), 300);
4900 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4901 return 1;
4902 }
4903 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
4904 if (domain == DNSName("com.")) {
4905 setLWResult(res, 0, true, false, true);
4906 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4907 addRRSIG(keys, res->d_records, domain, 300);
4908 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4909 addRRSIG(keys, res->d_records, domain, 300);
4910 }
4911 else {
4912 setLWResult(res, 0, false, false, true);
4913 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4914 addDS(domain, 300, res->d_records, keys);
4915 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4916 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4917 }
b7f378d1
RG
4918 return 1;
4919 }
4920 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
4921 if (type == QType::NS) {
4922 setLWResult(res, 0, true, false, true);
4923 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4924 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4925 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4926 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4927 }
4928 else {
4929 setLWResult(res, 0, true, false, true);
4930 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4931 addRRSIG(keys, res->d_records, domain, 300);
4932 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
4933 addRRSIG(keys, res->d_records, domain, 300);
4934 }
b7f378d1
RG
4935 return 1;
4936 }
4937 }
4938
4939 return 0;
4940 });
4941
4942 vector<DNSRecord> ret;
4943 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4944 BOOST_CHECK_EQUAL(res, RCode::NoError);
4945 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4946 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 4947 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4948
4949 /* again, to test the cache */
4950 ret.clear();
4951 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4952 BOOST_CHECK_EQUAL(res, RCode::NoError);
4953 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4954 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 4955 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4956}
4957
4958BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
4959 std::unique_ptr<SyncRes> sr;
895449a5 4960 initSR(sr, true);
b7f378d1 4961
0c43f455 4962 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
4963
4964 primeHints();
4965 const DNSName target("nx.powerdns.com.");
4966 testkeysset_t keys;
4967
4968 auto luaconfsCopy = g_luaconfs.getCopy();
4969 luaconfsCopy.dsAnchors.clear();
4970 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4971 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4972 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4973
4974 g_luaconfs.setState(luaconfsCopy);
4975
4976 size_t queriesCount = 0;
4977
4978 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
4979 queriesCount++;
4980
4981 DNSName auth = domain;
4982 if (domain == target) {
4983 auth = DNSName("powerdns.com.");
4984 }
5374b03b
RG
4985 if (type == QType::DS || type == QType::DNSKEY) {
4986 if (type == QType::DS && domain == target) {
4987 setLWResult(res, RCode::NXDomain, true, false, true);
4988 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4989 addRRSIG(keys, res->d_records, auth, 300);
4990 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4991 addRRSIG(keys, res->d_records, auth, 300);
4992 return 1;
4993 }
4994 else {
4995 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4996 }
b7f378d1 4997 }
f24465e5 4998 else {
b7f378d1
RG
4999 if (isRootServer(ip)) {
5000 setLWResult(res, 0, false, false, true);
5001 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5002 addDS(DNSName("com."), 300, res->d_records, keys);
5003 addRRSIG(keys, res->d_records, DNSName("."), 300);
5004 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5005 return 1;
5006 }
5007 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5008 if (domain == DNSName("com.")) {
5009 setLWResult(res, 0, true, false, true);
5010 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5011 addRRSIG(keys, res->d_records, domain, 300);
5012 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5013 addRRSIG(keys, res->d_records, domain, 300);
5014 }
5015 else {
5016 setLWResult(res, 0, false, false, true);
5017 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5018 addDS(auth, 300, res->d_records, keys);
5019 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5020 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5021 }
b7f378d1
RG
5022 return 1;
5023 }
5024 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5025 if (type == QType::NS) {
5026 setLWResult(res, 0, true, false, true);
5027 if (domain == DNSName("powerdns.com.")) {
5028 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5029 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5030 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5031 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5032 }
5033 else {
5034 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5035 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5036 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5037 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5038 }
5039 }
5040 else {
5041 setLWResult(res, RCode::NXDomain, true, false, true);
5042 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5043 addRRSIG(keys, res->d_records, auth, 300);
5044 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5045 addRRSIG(keys, res->d_records, auth, 300);
9b061cf5
RG
5046 /* add wildcard denial */
5047 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5048 addRRSIG(keys, res->d_records, auth, 300);
f24465e5 5049 }
b7f378d1
RG
5050 return 1;
5051 }
5052 }
5053
5054 return 0;
5055 });
5056
5057 vector<DNSRecord> ret;
5058 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5059 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5060 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5061 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5062 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5063
5064 /* again, to test the cache */
5065 ret.clear();
5066 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5067 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5068 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5069 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5070 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5071}
5072
2b984251
RG
5073BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
5074 std::unique_ptr<SyncRes> sr;
5075 initSR(sr, true);
5076
0c43f455 5077 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2b984251
RG
5078
5079 primeHints();
5080 const DNSName target("www.powerdns.com.");
5081 testkeysset_t keys;
5082
5083 auto luaconfsCopy = g_luaconfs.getCopy();
5084 luaconfsCopy.dsAnchors.clear();
5085 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5086 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5087 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5088
5089 g_luaconfs.setState(luaconfsCopy);
5090
5091 size_t queriesCount = 0;
5092
5093 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
5094 queriesCount++;
5095
5374b03b
RG
5096 if (type == QType::DS || type == QType::DNSKEY) {
5097 if (type == QType::DS && domain == target) {
5098 setLWResult(res, RCode::NoError, true, false, true);
5099 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5100 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5101 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5102 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5103 return 1;
5104 }
5105 else {
5106 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5107 }
2b984251 5108 }
f24465e5 5109 else {
2b984251
RG
5110 if (isRootServer(ip)) {
5111 setLWResult(res, 0, false, false, true);
5112 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5113 addDS(DNSName("com."), 300, res->d_records, keys);
5114 addRRSIG(keys, res->d_records, DNSName("."), 300);
5115 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5116 return 1;
5117 }
5118 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5119 if (domain == DNSName("com.")) {
5120 setLWResult(res, 0, true, false, true);
5121 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5122 addRRSIG(keys, res->d_records, domain, 300);
5123 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5124 addRRSIG(keys, res->d_records, domain, 300);
5125 }
5126 else {
5127 setLWResult(res, 0, false, false, true);
5128 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5129 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5130 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5131 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5132 }
2b984251
RG
5133 return 1;
5134 }
5135 else if (ip == ComboAddress("192.0.2.2:53")) {
5136 setLWResult(res, 0, true, false, true);
f24465e5
RG
5137 if (type == QType::NS) {
5138 if (domain == DNSName("powerdns.com.")) {
5139 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5140 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5141 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5142 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5143 }
5144 else {
5145 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5146 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5147 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5148 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5149 }
5150 }
5151 else {
5152 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5153 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
9b061cf5 5154 /* we need to add the proof that this name does not exist, so the wildcard may apply */
f24465e5
RG
5155 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5156 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5157 }
2b984251
RG
5158 return 1;
5159 }
5160 }
5161
5162 return 0;
5163 });
5164
5165 vector<DNSRecord> ret;
5166 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5167 BOOST_CHECK_EQUAL(res, RCode::NoError);
5168 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5169 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5170 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5171
5172 /* again, to test the cache */
5173 ret.clear();
5174 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5175 BOOST_CHECK_EQUAL(res, RCode::NoError);
5176 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5177 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5178 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5179}
5180
9b061cf5
RG
5181BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
5182 std::unique_ptr<SyncRes> sr;
5183 initSR(sr, true);
5184
5185 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5186
5187 primeHints();
5188 const DNSName target("www.com.");
5189 testkeysset_t keys;
5190
5191 auto luaconfsCopy = g_luaconfs.getCopy();
5192 luaconfsCopy.dsAnchors.clear();
5193 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5194 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5195
5196 g_luaconfs.setState(luaconfsCopy);
5197
5198 size_t queriesCount = 0;
5199
5200 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
5201 queriesCount++;
5202
5203 if (type == QType::DS || type == QType::DNSKEY) {
5204 if (type == QType::DS && domain == target) {
5205 DNSName auth("com.");
5206 setLWResult(res, 0, true, false, true);
5207
5208 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5209 addRRSIG(keys, res->d_records, auth, 300);
5210 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
5211 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
5212 addRRSIG(keys, res->d_records, auth, 300);
5213 return 1;
5214 }
5215 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5216 }
5217 else {
5218 if (isRootServer(ip)) {
5219 setLWResult(res, 0, false, false, true);
5220 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5221 addDS(DNSName("com."), 300, res->d_records, keys);
5222 addRRSIG(keys, res->d_records, DNSName("."), 300);
5223 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5224 return 1;
5225 }
5226 else if (ip == ComboAddress("192.0.2.1:53")) {
5227 setLWResult(res, 0, true, false, true);
5228 /* no data */
5229 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5230 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5231 /* no record for this name */
5232 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
5233 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5234 /* a wildcard matches but has no record for this type */
5235 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5236 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5237 return 1;
5238 }
5239 }
5240
5241 return 0;
5242 });
5243
5244 vector<DNSRecord> ret;
5245 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5246 BOOST_CHECK_EQUAL(res, RCode::NoError);
5247 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5248 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5249 BOOST_CHECK_EQUAL(queriesCount, 6);
5250
5251 /* again, to test the cache */
5252 ret.clear();
5253 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5254 BOOST_CHECK_EQUAL(res, RCode::NoError);
5255 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5256 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5257 BOOST_CHECK_EQUAL(queriesCount, 6);
5258}
5259
5260BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
5261 std::unique_ptr<SyncRes> sr;
5262 initSR(sr, true);
5263
5264 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5265
5266 primeHints();
5267 const DNSName target("www.com.");
5268 testkeysset_t keys;
5269
5270 auto luaconfsCopy = g_luaconfs.getCopy();
5271 luaconfsCopy.dsAnchors.clear();
5272 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5273 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5274
5275 g_luaconfs.setState(luaconfsCopy);
5276
5277 size_t queriesCount = 0;
5278
5279 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
5280 queriesCount++;
5281
5282 if (type == QType::DS || type == QType::DNSKEY) {
5283 if (type == QType::DS && domain == target) {
5284 DNSName auth("com.");
5285 setLWResult(res, 0, true, false, true);
5286
5287 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5288 addRRSIG(keys, res->d_records, auth, 300);
5289 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5290 /* first the closest encloser */
5291 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5292 addRRSIG(keys, res->d_records, auth, 300);
5293 /* then the next closer */
5294 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5295 addRRSIG(keys, res->d_records, auth, 300);
5296 /* a wildcard matches but has no record for this type */
5297 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5298 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5299 return 1;
5300 }
5301 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5302 }
5303 else {
5304 if (isRootServer(ip)) {
5305 setLWResult(res, 0, false, false, true);
5306 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5307 addDS(DNSName("com."), 300, res->d_records, keys);
5308 addRRSIG(keys, res->d_records, DNSName("."), 300);
5309 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5310 return 1;
5311 }
5312 else if (ip == ComboAddress("192.0.2.1:53")) {
5313 setLWResult(res, 0, true, false, true);
5314 /* no data */
5315 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5316 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5317 /* no record for this name */
5318 /* first the closest encloser */
5319 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5320 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5321 /* then the next closer */
5322 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5323 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5324 /* a wildcard matches but has no record for this type */
5325 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5326 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5327 return 1;
5328 }
5329 }
5330
5331 return 0;
5332 });
5333
5334 vector<DNSRecord> ret;
5335 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5336 BOOST_CHECK_EQUAL(res, RCode::NoError);
5337 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5338 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5339 BOOST_CHECK_EQUAL(queriesCount, 6);
5340
5341 /* again, to test the cache */
5342 ret.clear();
5343 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5344 BOOST_CHECK_EQUAL(res, RCode::NoError);
5345 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5346 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5347 BOOST_CHECK_EQUAL(queriesCount, 6);
5348}
5349
b7c40613
RG
5350BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5351 std::unique_ptr<SyncRes> sr;
5352 initSR(sr, true);
5353
5354 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5355
5356 primeHints();
5357 const DNSName target("www.com.");
5358 testkeysset_t keys;
5359
5360 auto luaconfsCopy = g_luaconfs.getCopy();
5361 luaconfsCopy.dsAnchors.clear();
5362 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5363 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5364
5365 g_luaconfs.setState(luaconfsCopy);
5366
5367 size_t queriesCount = 0;
5368
5369 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
5370 queriesCount++;
5371
5372 if (type == QType::DS || type == QType::DNSKEY) {
5373 if (type == QType::DS && domain == target) {
5374 DNSName auth("com.");
5375 setLWResult(res, 0, true, false, true);
5376
5377 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5378 addRRSIG(keys, res->d_records, auth, 300);
5379 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5380 /* first the closest encloser */
5381 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5382 addRRSIG(keys, res->d_records, auth, 300);
5383 /* then the next closer */
5384 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5385 addRRSIG(keys, res->d_records, auth, 300);
5386 /* a wildcard matches but has no record for this type */
5387 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5388 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5389 return 1;
5390 }
5391 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5392 }
5393 else {
5394 if (isRootServer(ip)) {
5395 setLWResult(res, 0, false, false, true);
5396 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5397 addDS(DNSName("com."), 300, res->d_records, keys);
5398 addRRSIG(keys, res->d_records, DNSName("."), 300);
5399 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5400 return 1;
5401 }
5402 else if (ip == ComboAddress("192.0.2.1:53")) {
5403 setLWResult(res, 0, true, false, true);
5404 /* no data */
5405 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5406 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5407 /* no record for this name */
5408 /* first the closest encloser */
5409 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5410 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5411 /* then the next closer */
5412 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5413 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5414 /* a wildcard matches but has no record for this type */
5415 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5416 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5417 return 1;
5418 }
5419 }
5420
5421 return 0;
5422 });
5423
5424 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5425 vector<DNSRecord> ret;
5426 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5427 BOOST_CHECK_EQUAL(res, RCode::NoError);
5428 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5429 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5430 BOOST_CHECK_EQUAL(queriesCount, 6);
5431
5432 /* again, to test the cache */
5433 ret.clear();
5434 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5435 BOOST_CHECK_EQUAL(res, RCode::NoError);
5436 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5437 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5438 BOOST_CHECK_EQUAL(queriesCount, 6);
5439}
5440
9b061cf5
RG
5441BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5442 std::unique_ptr<SyncRes> sr;
5443 initSR(sr, true);
5444
5445 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5446
5447 primeHints();
6bc9ccbb 5448 const DNSName target("www.sub.powerdns.com.");
9b061cf5
RG
5449 testkeysset_t keys;
5450
5451 auto luaconfsCopy = g_luaconfs.getCopy();
5452 luaconfsCopy.dsAnchors.clear();
5453 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5454 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5455 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5456
5457 g_luaconfs.setState(luaconfsCopy);
5458
5459 size_t queriesCount = 0;
5460
5461 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
5462 queriesCount++;
5463
5464 if (type == QType::DS || type == QType::DNSKEY) {
6bc9ccbb 5465 if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) {
9b061cf5
RG
5466 setLWResult(res, RCode::NoError, true, false, true);
5467 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5468 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6bc9ccbb
RG
5469 if (domain == DNSName("sub.powerdns.com")) {
5470 addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5471 }
5472 else if (domain == target) {
5473 addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5474 }
9b061cf5
RG
5475 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5476 return 1;
5477 }
5478 else {
5479 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5480 }
5481 }
5482 else {
5483 if (isRootServer(ip)) {
5484 setLWResult(res, 0, false, false, true);
5485 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5486 addDS(DNSName("com."), 300, res->d_records, keys);
5487 addRRSIG(keys, res->d_records, DNSName("."), 300);
5488 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5489 return 1;
5490 }
5491 else if (ip == ComboAddress("192.0.2.1:53")) {
5492 if (domain == DNSName("com.")) {
5493 setLWResult(res, 0, true, false, true);
5494 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5495 addRRSIG(keys, res->d_records, domain, 300);
5496 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5497 addRRSIG(keys, res->d_records, domain, 300);
5498 }
5499 else {
5500 setLWResult(res, 0, false, false, true);
5501 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5502 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5503 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5504 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5505 }
5506 return 1;
5507 }
5508 else if (ip == ComboAddress("192.0.2.2:53")) {
5509 setLWResult(res, 0, true, false, true);
5510 if (type == QType::NS) {
5511 if (domain == DNSName("powerdns.com.")) {
5512 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5513 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5514 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5515 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5516 }
5517 else {
5518 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5519 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5520 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5521 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5522 }
5523 }
5524 else {
5525 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5526 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5527 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5528 /* first the closest encloser */
5529 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5530 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5531 /* then the next closer */
6bc9ccbb 5532 addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
9b061cf5
RG
5533 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5534 }
5535 return 1;
5536 }
5537 }
5538
5539 return 0;
5540 });
5541
5542 vector<DNSRecord> ret;
5543 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5544 BOOST_CHECK_EQUAL(res, RCode::NoError);
5545 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5546 BOOST_REQUIRE_EQUAL(ret.size(), 6);
6bc9ccbb 5547 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
5548
5549 /* again, to test the cache */
5550 ret.clear();
5551 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5552 BOOST_CHECK_EQUAL(res, RCode::NoError);
5553 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5554 BOOST_REQUIRE_EQUAL(ret.size(), 6);
6bc9ccbb 5555 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
5556}
5557
b7c40613
RG
5558BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5559 std::unique_ptr<SyncRes> sr;
5560 initSR(sr, true);
5561
5562 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5563
5564 primeHints();
5565 const DNSName target("www.powerdns.com.");
5566 testkeysset_t keys;
5567
5568 auto luaconfsCopy = g_luaconfs.getCopy();
5569 luaconfsCopy.dsAnchors.clear();
5570 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5571 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5572 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5573
5574 g_luaconfs.setState(luaconfsCopy);
5575
5576 size_t queriesCount = 0;
5577
5578 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
5579 queriesCount++;
5580
5581 if (type == QType::DS || type == QType::DNSKEY) {
5582 if (type == QType::DS && domain == target) {
5583 setLWResult(res, RCode::NoError, true, false, true);
5584 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5585 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5586 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5587 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5588 return 1;
5589 }
5590 else {
5591 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5592 }
5593 }
5594 else {
5595 if (isRootServer(ip)) {
5596 setLWResult(res, 0, false, false, true);
5597 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5598 addDS(DNSName("com."), 300, res->d_records, keys);
5599 addRRSIG(keys, res->d_records, DNSName("."), 300);
5600 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5601 return 1;
5602 }
5603 else if (ip == ComboAddress("192.0.2.1:53")) {
5604 if (domain == DNSName("com.")) {
5605 setLWResult(res, 0, true, false, true);
5606 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5607 addRRSIG(keys, res->d_records, domain, 300);
5608 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5609 addRRSIG(keys, res->d_records, domain, 300);
5610 }
5611 else {
5612 setLWResult(res, 0, false, false, true);
5613 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5614 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5615 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5616 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5617 }
5618 return 1;
5619 }
5620 else if (ip == ComboAddress("192.0.2.2:53")) {
5621 setLWResult(res, 0, true, false, true);
5622 if (type == QType::NS) {
5623 if (domain == DNSName("powerdns.com.")) {
5624 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5625 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5626 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5627 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5628 }
5629 else {
5630 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5631 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5632 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5633 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5634 }
5635 }
5636 else {
5637 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5638 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5639 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5640 /* first the closest encloser */
5641 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5642 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5643 /* then the next closer */
5644 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5645 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5646 }
5647 return 1;
5648 }
5649 }
5650
5651 return 0;
5652 });
5653
5654 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5655 we should end up Insecure */
5656 vector<DNSRecord> ret;
5657 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5658 BOOST_CHECK_EQUAL(res, RCode::NoError);
5659 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5660 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5661 BOOST_CHECK_EQUAL(queriesCount, 9);
5662
5663 /* again, to test the cache */
5664 ret.clear();
5665 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5666 BOOST_CHECK_EQUAL(res, RCode::NoError);
5667 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5668 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5669 BOOST_CHECK_EQUAL(queriesCount, 9);
5670}
5671
9b061cf5
RG
5672BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5673 std::unique_ptr<SyncRes> sr;
5674 initSR(sr, true);
5675
5676 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5677
5678 primeHints();
5679 const DNSName target("www.powerdns.com.");
5680 testkeysset_t keys;
5681
5682 auto luaconfsCopy = g_luaconfs.getCopy();
5683 luaconfsCopy.dsAnchors.clear();
5684 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5685 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5686 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5687
5688 g_luaconfs.setState(luaconfsCopy);
5689
5690 size_t queriesCount = 0;
5691
5692 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
5693 queriesCount++;
5694
5695 if (type == QType::DS || type == QType::DNSKEY) {
5696 if (type == QType::DS && domain == target) {
5697 setLWResult(res, RCode::NoError, true, false, true);
5698 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5699 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5700 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5701 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5702 return 1;
5703 }
5704 else {
5705 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5706 }
5707 }
5708 else {
5709 if (isRootServer(ip)) {
5710 setLWResult(res, 0, false, false, true);
5711 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5712 addDS(DNSName("com."), 300, res->d_records, keys);
5713 addRRSIG(keys, res->d_records, DNSName("."), 300);
5714 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5715 return 1;
5716 }
5717 else if (ip == ComboAddress("192.0.2.1:53")) {
5718 if (domain == DNSName("com.")) {
5719 setLWResult(res, 0, true, false, true);
5720 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5721 addRRSIG(keys, res->d_records, domain, 300);
5722 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5723 addRRSIG(keys, res->d_records, domain, 300);
5724 }
5725 else {
5726 setLWResult(res, 0, false, false, true);
5727 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5728 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5729 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5730 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5731 }
5732 return 1;
5733 }
5734 else if (ip == ComboAddress("192.0.2.2:53")) {
5735 setLWResult(res, 0, true, false, true);
5736 if (type == QType::NS) {
5737 if (domain == DNSName("powerdns.com.")) {
5738 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5739 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5740 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5741 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5742 }
5743 else {
5744 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5745 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5746 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5747 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5748 }
5749 }
5750 else {
5751 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5752 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5753 }
5754 return 1;
5755 }
5756 }
5757
5758 return 0;
5759 });
5760
5761 vector<DNSRecord> ret;
5762 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5763 BOOST_CHECK_EQUAL(res, RCode::NoError);
5764 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5765 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5766 BOOST_CHECK_EQUAL(queriesCount, 9);
5767
5768 /* again, to test the cache */
5769 ret.clear();
5770 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5771 BOOST_CHECK_EQUAL(res, RCode::NoError);
5772 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5773 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5774 BOOST_CHECK_EQUAL(queriesCount, 9);
5775}
5776
a53e8fe3
RG
5777BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5778 std::unique_ptr<SyncRes> sr;
5779 initSR(sr, true);
5780
0c43f455 5781 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
5782
5783 primeHints();
5784 const DNSName target("www.powerdns.com.");
5785 testkeysset_t keys;
5786
5787 auto luaconfsCopy = g_luaconfs.getCopy();
5788 luaconfsCopy.dsAnchors.clear();
5789 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5790 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5791 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5792
5793 g_luaconfs.setState(luaconfsCopy);
5794
5795 size_t queriesCount = 0;
5796 size_t dsQueriesCount = 0;
5797
5798 sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
5799 queriesCount++;
5800
5801 if (type == QType::DS) {
5802 DNSName auth(domain);
5803 auth.chopOff();
5804 dsQueriesCount++;
5805
5806 setLWResult(res, 0, true, false, true);
5807 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5808 addRRSIG(keys, res->d_records, auth, 300);
5809 return 1;
5810 }
5811 else if (type == QType::DNSKEY) {
5812 setLWResult(res, 0, true, false, true);
5813 addDNSKEY(keys, domain, 300, res->d_records);
5814 addRRSIG(keys, res->d_records, domain, 300);
5815 return 1;
5816 }
f24465e5 5817 else {
a53e8fe3
RG
5818 if (isRootServer(ip)) {
5819 setLWResult(res, 0, false, false, true);
5820 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5821 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5822 /* No DS on referral, and no denial of the DS either */
5823 return 1;
5824 }
5825 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5826 if (domain == DNSName("com.")) {
5827 setLWResult(res, 0, true, false, true);
5828 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5829 addRRSIG(keys, res->d_records, domain, 300);
5830 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5831 addRRSIG(keys, res->d_records, domain, 300);
5832 }
5833 else {
5834 setLWResult(res, 0, false, false, true);
5835 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5836 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5837 /* No DS on referral, and no denial of the DS either */
5838 }
a53e8fe3
RG
5839 return 1;
5840 }
5841 else if (ip == ComboAddress("192.0.2.2:53")) {
5842 setLWResult(res, 0, true, false, true);
f24465e5
RG
5843 if (type == QType::NS) {
5844 if (domain == DNSName("powerdns.com.")) {
5845 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5846 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5847 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5848 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5849 }
5850 else {
5851 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5852 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5853 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5854 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5855 }
5856 }
5857 else {
5858 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5859 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5860 }
5861
a53e8fe3
RG
5862 return 1;
5863 }
5864 }
5865
5866 return 0;
5867 });
5868
5869 vector<DNSRecord> ret;
5870 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5871 BOOST_CHECK_EQUAL(res, RCode::NoError);
5872 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 5873 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
5874 BOOST_CHECK_EQUAL(queriesCount, 9);
5875 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
5876
5877 /* again, to test the cache */
5878 ret.clear();
5879 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5880 BOOST_CHECK_EQUAL(res, RCode::NoError);
5881 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 5882 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
5883 BOOST_CHECK_EQUAL(queriesCount, 9);
5884 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
5885}
5886
f715542c
RG
5887BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
5888 std::unique_ptr<SyncRes> sr;
5889 initSR(sr, true);
5890
5d7b19c5 5891 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
f715542c
RG
5892
5893 primeHints();
5894 const DNSName target("www.powerdns.com.");
5895 testkeysset_t keys;
5896
5897 auto luaconfsCopy = g_luaconfs.getCopy();
5898 luaconfsCopy.dsAnchors.clear();
5899 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5900 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3cef03e9 5901 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
f715542c
RG
5902 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5903
5904 g_luaconfs.setState(luaconfsCopy);
5905
5906 size_t queriesCount = 0;
5907
5908 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
5909 queriesCount++;
5910
5911 if (type == QType::DS) {
5912 DNSName auth(domain);
5913 auth.chopOff();
5914
5915 setLWResult(res, 0, true, false, true);
5916 if (domain == target) {
5917 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5918 addRRSIG(keys, res->d_records, target, 300);
5919 }
5920 else {
5921 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5922 addRRSIG(keys, res->d_records, auth, 300);
5923 }
5924 return 1;
5925 }
5926 else if (type == QType::DNSKEY) {
5927 setLWResult(res, 0, true, false, true);
5928 addDNSKEY(keys, domain, 300, res->d_records);
5929 addRRSIG(keys, res->d_records, domain, 300);
5930 return 1;
5931 }
5932 else {
5933 if (isRootServer(ip)) {
5934 setLWResult(res, 0, false, false, true);
5935 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5936 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5937 addDS(DNSName("com."), 300, res->d_records, keys);
5938 addRRSIG(keys, res->d_records, DNSName("."), 300);
5939 return 1;
5940 }
5941 else if (ip == ComboAddress("192.0.2.1:53")) {
5942 if (domain == DNSName("com.")) {
5943 setLWResult(res, 0, true, false, true);
5944 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5945 addRRSIG(keys, res->d_records, domain, 300);
5946 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5947 addRRSIG(keys, res->d_records, domain, 300);
5948 }
5949 else {
5950 setLWResult(res, 0, false, false, true);
5951 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5952 /* no DS */
5953 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5954 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5955 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5956 }
5957 return 1;
5958 }
5959 else if (ip == ComboAddress("192.0.2.2:53")) {
5960 if (type == QType::NS) {
5961 if (domain == DNSName("powerdns.com.")) {
5962 setLWResult(res, RCode::Refused, false, false, true);
5963 }
5964 else {
5965 setLWResult(res, 0, true, false, true);
5966 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5967 addRRSIG(keys, res->d_records, domain, 300);
5968 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5969 addRRSIG(keys, res->d_records, domain, 300);
5970 }
5971 }
5972 else {
5973 setLWResult(res, 0, true, false, true);
5974 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5975 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
5976 }
5977
5978 return 1;
5979 }
5980 }
5981
5982 return 0;
5983 });
5984
5985 vector<DNSRecord> ret;
5986 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5987 BOOST_CHECK_EQUAL(res, RCode::NoError);
5988 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5989 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 5990 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
5991
5992 /* again, to test the cache */
5993 ret.clear();
5994 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5995 BOOST_CHECK_EQUAL(res, RCode::NoError);
5996 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5997 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 5998 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
5999}
6000
8d2e7fa1
RG
6001BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) {
6002 /* check that we don't accept a signer below us */
6003 std::unique_ptr<SyncRes> sr;
6004 initSR(sr, true);
6005
6006 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6007
6008 primeHints();
6009 const DNSName target("www.powerdns.com.");
6010 testkeysset_t keys;
6011
6012 auto luaconfsCopy = g_luaconfs.getCopy();
6013 luaconfsCopy.dsAnchors.clear();
6014 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6015 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6016 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6017 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6018 generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6019
6020 g_luaconfs.setState(luaconfsCopy);
6021
6022 size_t queriesCount = 0;
6023
6024 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6025 queriesCount++;
6026
6027 if (type == QType::DS) {
6028 DNSName auth(domain);
6029 auth.chopOff();
6030
6031 setLWResult(res, 0, true, false, true);
6032 if (domain == target) {
6033 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6034 addRRSIG(keys, res->d_records, target, 300);
6035 }
6036 else {
6037 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6038 addRRSIG(keys, res->d_records, auth, 300);
6039 }
6040 return 1;
6041 }
6042 else if (type == QType::DNSKEY) {
6043 setLWResult(res, 0, true, false, true);
6044 addDNSKEY(keys, domain, 300, res->d_records);
6045 if (domain == DNSName("www.powerdns.com.")) {
6046 addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
6047 }
6048 else {
6049 addRRSIG(keys, res->d_records, domain, 300);
6050 }
6051 return 1;
6052 }
6053 else {
6054 if (isRootServer(ip)) {
6055 setLWResult(res, 0, false, false, true);
6056 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6057 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6058 addDS(DNSName("com."), 300, res->d_records, keys);
6059 addRRSIG(keys, res->d_records, DNSName("."), 300);
6060 return 1;
6061 }
6062 else if (ip == ComboAddress("192.0.2.1:53")) {
6063 if (domain == DNSName("com.")) {
6064 setLWResult(res, 0, true, false, true);
6065 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6066 addRRSIG(keys, res->d_records, domain, 300);
6067 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6068 addRRSIG(keys, res->d_records, domain, 300);
6069 }
6070 else {
6071 setLWResult(res, 0, false, false, true);
6072 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6073 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6074 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6075 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6076 }
6077 return 1;
6078 }
6079 else if (ip == ComboAddress("192.0.2.2:53")) {
6080 if (type == QType::NS) {
6081 setLWResult(res, 0, true, false, true);
6082 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6083 addRRSIG(keys, res->d_records, domain, 300);
6084 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6085 addRRSIG(keys, res->d_records, domain, 300);
6086 }
6087 else {
6088 setLWResult(res, 0, true, false, true);
6089 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6090 addRRSIG(keys, res->d_records, domain, 300);
6091 }
6092
6093 return 1;
6094 }
6095 }
6096
f715542c
RG
6097 return 0;
6098 });
6099
6100 vector<DNSRecord> ret;
6101 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6102 BOOST_CHECK_EQUAL(res, RCode::NoError);
6103 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6104 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6105 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6106
6107 /* again, to test the cache */
6108 ret.clear();
6109 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6110 BOOST_CHECK_EQUAL(res, RCode::NoError);
6111 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6112 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6113 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6114}
6115
a53e8fe3
RG
6116BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
6117 std::unique_ptr<SyncRes> sr;
f24465e5 6118 initSR(sr, true);
a53e8fe3 6119
0c43f455 6120 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
6121
6122 primeHints();
6123 const DNSName target("www.powerdns.com.");
6124 testkeysset_t keys;
6125
6126 auto luaconfsCopy = g_luaconfs.getCopy();
6127 luaconfsCopy.dsAnchors.clear();
6128 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6129 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6130
6131 g_luaconfs.setState(luaconfsCopy);
6132
6133 size_t queriesCount = 0;
6134 size_t dsQueriesCount = 0;
6135
6136 sr->setAsyncCallback([target,&queriesCount,&dsQueriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6137 queriesCount++;
6138
6139 if (type == QType::DS) {
6140 DNSName auth(domain);
6141 auth.chopOff();
6142 dsQueriesCount++;
6143
6144 setLWResult(res, 0, true, false, true);
6145 if (domain == DNSName("com.")) {
6146 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6147 }
6148 else {
f24465e5
RG
6149 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6150 addRRSIG(keys, res->d_records, DNSName("com."), 300);
a53e8fe3
RG
6151 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
6152 }
6153 addRRSIG(keys, res->d_records, auth, 300);
6154 return 1;
6155 }
6156 else if (type == QType::DNSKEY) {
6157 setLWResult(res, 0, true, false, true);
6158 addDNSKEY(keys, domain, 300, res->d_records);
6159 addRRSIG(keys, res->d_records, domain, 300);
6160 return 1;
6161 }
a69867f2 6162 else {
a53e8fe3
RG
6163 if (isRootServer(ip)) {
6164 setLWResult(res, 0, false, false, true);
6165 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6166 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6167 /* No DS on referral, and no denial of the DS either */
6168 return 1;
6169 }
6170 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6171 if (domain == DNSName("com.")) {
6172 setLWResult(res, 0, true, false, true);
6173 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
f24465e5 6174 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 6175 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
f24465e5 6176 addRRSIG(keys, res->d_records, domain, 300);
a69867f2
RG
6177 }
6178 else {
6179 setLWResult(res, 0, false, false, true);
6180 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6181 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6182 /* No DS on referral, and no denial of the DS either */
6183 }
a53e8fe3
RG
6184 return 1;
6185 }
6186 else if (ip == ComboAddress("192.0.2.2:53")) {
6187 setLWResult(res, 0, true, false, true);
f24465e5
RG
6188 if (type == QType::NS) {
6189 if (domain == DNSName("powerdns.com.")) {
6190 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6191 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6192 }
6193 else {
6194 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6195 }
6196 }
6197 else {
6198 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6199 }
a53e8fe3
RG
6200 return 1;
6201 }
6202 }
6203
6204 return 0;
6205 });
6206
6207 vector<DNSRecord> ret;
6208 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6209 BOOST_CHECK_EQUAL(res, RCode::NoError);
6210 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6211 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6212 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6213 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6214
6215 /* again, to test the cache */
6216 ret.clear();
6217 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6218 BOOST_CHECK_EQUAL(res, RCode::NoError);
6219 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6220 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6221 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6222 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6223}
6224
e59c8907 6225BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
b7f378d1 6226 std::unique_ptr<SyncRes> sr;
895449a5 6227 initSR(sr, true);
b7f378d1 6228
0c43f455 6229 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6230
6231 primeHints();
6232 const DNSName target("powerdns.com.");
6233 testkeysset_t keys;
6234
6235 auto luaconfsCopy = g_luaconfs.getCopy();
6236 luaconfsCopy.dsAnchors.clear();
6237 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6238 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6239 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6240
6241 g_luaconfs.setState(luaconfsCopy);
6242
6243 size_t queriesCount = 0;
6244
6245 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6246 queriesCount++;
6247
5374b03b
RG
6248 if (type == QType::DS || type == QType::DNSKEY) {
6249 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6250 }
a69867f2 6251 else {
b7f378d1
RG
6252 if (isRootServer(ip)) {
6253 setLWResult(res, 0, false, false, true);
6254 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6255 addDS(DNSName("com."), 300, res->d_records, keys);
6256 addRRSIG(keys, res->d_records, DNSName("."), 300);
6257 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6258 return 1;
6259 }
6260 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6261 if (domain == DNSName("com.")) {
6262 setLWResult(res, 0, true, false, true);
6263 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6264 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6265 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6266 }
6267 else {
6268 setLWResult(res, 0, false, false, true);
6269 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6270 addDS(domain, 300, res->d_records, keys);
6271 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6272 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6273 }
b7f378d1
RG
6274 return 1;
6275 }
6276 else if (ip == ComboAddress("192.0.2.2:53")) {
6277 setLWResult(res, 0, true, false, true);
a69867f2
RG
6278 if (type == QType::NS) {
6279 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6280 addRRSIG(keys, res->d_records, domain, 300);
6281 }
6282 else {
6283 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6284 addRRSIG(keys, res->d_records, domain, 300);
6285 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
6286 /* NO RRSIG for the NSEC record! */
6287 }
b7f378d1
RG
6288 return 1;
6289 }
6290 }
6291
6292 return 0;
6293 });
6294
6295 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
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_CHECK_EQUAL(ret.size(), 3);
a69867f2 6301 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
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(), 3);
a69867f2 6309 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6310}
6311
e59c8907 6312BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
b7f378d1 6313 std::unique_ptr<SyncRes> sr;
895449a5 6314 initSR(sr, true);
b7f378d1 6315
0c43f455 6316 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6317
6318 primeHints();
6319 const DNSName target("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 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6327
6328 g_luaconfs.setState(luaconfsCopy);
6329
6330 size_t queriesCount = 0;
6331
6332 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6333 queriesCount++;
6334
5374b03b
RG
6335 if (type == QType::DS || type == QType::DNSKEY) {
6336 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6337 }
a69867f2 6338 else {
b7f378d1
RG
6339 if (isRootServer(ip)) {
6340 setLWResult(res, 0, false, false, true);
6341 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6342 addDS(DNSName("com."), 300, res->d_records, keys);
6343 addRRSIG(keys, res->d_records, DNSName("."), 300);
6344 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6345 return 1;
6346 }
6347 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6348 if (domain == DNSName("com.")) {
6349 setLWResult(res, 0, true, false, true);
6350 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6351 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6352 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6353 }
6354 else {
6355 setLWResult(res, 0, false, false, true);
6356 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6357 addDS(domain, 300, res->d_records, keys);
6358 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6359 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6360 }
b7f378d1
RG
6361 return 1;
6362 }
6363 else if (ip == ComboAddress("192.0.2.2:53")) {
6364 setLWResult(res, 0, true, false, true);
a69867f2
RG
6365 if (type == QType::NS) {
6366 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6367 addRRSIG(keys, res->d_records, domain, 300);
6368 }
6369 else {
6370 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6371 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 6372
a69867f2
RG
6373 /* NO NSEC record! */
6374 }
b7f378d1
RG
6375 return 1;
6376 }
6377 }
6378
6379 return 0;
6380 });
6381
6382 /* no NSEC record in a secure zone, should be Bogus! */
6383 vector<DNSRecord> ret;
6384 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6385 BOOST_CHECK_EQUAL(res, RCode::NoError);
6386 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6387 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 6388 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6389
6390 /* again, to test the cache */
6391 ret.clear();
6392 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6393 BOOST_CHECK_EQUAL(res, RCode::NoError);
6394 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6395 BOOST_REQUIRE_EQUAL(ret.size(), 2);
a69867f2 6396 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6397}
6398
6399BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6400 std::unique_ptr<SyncRes> sr;
895449a5 6401 initSR(sr, true);
b7f378d1 6402
0c43f455 6403 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6404
6405 primeHints();
6406 const DNSName target("powerdns.com.");
6407 const ComboAddress targetAddr("192.0.2.42");
6408 testkeysset_t keys;
6409
6410 auto luaconfsCopy = g_luaconfs.getCopy();
6411 luaconfsCopy.dsAnchors.clear();
6412 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6413 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6414
6415 g_luaconfs.setState(luaconfsCopy);
6416
6417 size_t queriesCount = 0;
6418
6419 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6420 queriesCount++;
6421
6422 if (type == QType::DS) {
a53e8fe3 6423 if (domain == target) {
b7f378d1 6424 setLWResult(res, 0, false, false, true);
895449a5 6425 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6426 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6427 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6428 return 1;
5374b03b
RG
6429 } else {
6430 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1
RG
6431 }
6432 }
6433 else if (type == QType::DNSKEY) {
6434 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6435 setLWResult(res, 0, true, false, true);
6436 addDNSKEY(keys, domain, 300, res->d_records);
6437 addRRSIG(keys, res->d_records, domain, 300);
6438 return 1;
6439 }
6440 else {
6441 setLWResult(res, 0, false, false, true);
895449a5 6442 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6443 return 1;
6444 }
6445 }
a69867f2 6446 else {
b7f378d1
RG
6447 if (isRootServer(ip)) {
6448 setLWResult(res, 0, false, false, true);
6449 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6450 addDS(DNSName("com."), 300, res->d_records, keys);
6451 addRRSIG(keys, res->d_records, DNSName("."), 300);
6452 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6453 return 1;
6454 }
6455 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6456 if (domain == DNSName("com.")) {
6457 setLWResult(res, 0, true, false, true);
6458 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6459 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6460 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6461 }
6462 else {
6463 setLWResult(res, 0, false, false, true);
6464 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6465 /* no DS */
6466 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
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 }
6477 else {
6478 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6479 }
b7f378d1
RG
6480 return 1;
6481 }
6482 }
6483
6484 return 0;
6485 });
6486
6487 vector<DNSRecord> ret;
6488 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6489 BOOST_CHECK_EQUAL(res, RCode::NoError);
6490 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6491 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6492 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2
RG
6493 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6494 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6495 1 query for A */
6496 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6497
6498 /* again, to test the cache */
6499 ret.clear();
6500 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6501 BOOST_CHECK_EQUAL(res, RCode::NoError);
6502 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6503 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6504 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2 6505 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6506}
6507
3cef03e9
RG
6508
6509BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6510 /*
6511 Direct DS query:
6512 - parent is secure, zone is secure: DS should be secure
6513 */
6514 std::unique_ptr<SyncRes> sr;
6515 initSR(sr, true);
6516
6517 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6518
6519 primeHints();
6520 const DNSName target("powerdns.com.");
6521 testkeysset_t keys;
6522
6523 auto luaconfsCopy = g_luaconfs.getCopy();
6524 luaconfsCopy.dsAnchors.clear();
6525 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6526 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6527 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6528
6529 g_luaconfs.setState(luaconfsCopy);
6530
6531 size_t queriesCount = 0;
6532
6533 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6534 queriesCount++;
6535
6536 if (type == QType::DS || type == QType::DNSKEY) {
6537 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6538 }
6539 else {
6540 if (isRootServer(ip)) {
6541 setLWResult(res, 0, false, false, true);
6542 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6543 addDS(DNSName("com."), 300, res->d_records, keys);
6544 addRRSIG(keys, res->d_records, DNSName("."), 300);
6545 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6546 return 1;
6547 }
6548 }
6549
6550 return 0;
6551 });
6552
6553 vector<DNSRecord> ret;
6554 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6555 BOOST_CHECK_EQUAL(res, RCode::NoError);
6556 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6557 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6558 for (const auto& record : ret) {
6559 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6560 }
6561 BOOST_CHECK_EQUAL(queriesCount, 4);
6562
6563 /* again, to test the cache */
6564 ret.clear();
6565 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6566 BOOST_CHECK_EQUAL(res, RCode::NoError);
6567 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6568 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6569 for (const auto& record : ret) {
6570 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6571 }
6572 BOOST_CHECK_EQUAL(queriesCount, 4);
6573}
6574
6575BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6576 /*
6577 Direct DS query:
6578 - parent is secure, zone is insecure: DS denial should be secure
6579 */
6580 std::unique_ptr<SyncRes> sr;
6581 initSR(sr, true);
6582
6583 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6584
6585 primeHints();
6586 const DNSName target("powerdns.com.");
6587 testkeysset_t keys;
6588
6589 auto luaconfsCopy = g_luaconfs.getCopy();
6590 luaconfsCopy.dsAnchors.clear();
6591 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6592 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6593
6594 g_luaconfs.setState(luaconfsCopy);
6595
6596 size_t queriesCount = 0;
6597
6598 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6599 queriesCount++;
6600
6601 if (type == QType::DS || type == QType::DNSKEY) {
6602 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6603 }
6604 else {
6605 if (isRootServer(ip)) {
6606 setLWResult(res, 0, false, false, true);
6607 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6608 addDS(DNSName("com."), 300, res->d_records, keys);
6609 addRRSIG(keys, res->d_records, DNSName("."), 300);
6610 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6611 return 1;
6612 }
6613 }
6614
6615 return 0;
6616 });
6617
6618 vector<DNSRecord> ret;
6619 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6620 BOOST_CHECK_EQUAL(res, RCode::NoError);
6621 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6622 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6623 for (const auto& record : ret) {
6624 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6625 }
6626 BOOST_CHECK_EQUAL(queriesCount, 4);
6627
6628 /* again, to test the cache */
6629 ret.clear();
6630 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6631 BOOST_CHECK_EQUAL(res, RCode::NoError);
6632 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6633 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6634 for (const auto& record : ret) {
6635 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6636 }
6637 BOOST_CHECK_EQUAL(queriesCount, 4);
6638}
6639
70b3fe7a
RG
6640BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6641 std::unique_ptr<SyncRes> sr;
a69867f2 6642 initSR(sr, true);
70b3fe7a 6643
0c43f455 6644 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6645
6646 primeHints();
6647 const DNSName target("www.sub.powerdns.com.");
6648 const ComboAddress targetAddr("192.0.2.42");
6649 testkeysset_t keys;
6650
6651 auto luaconfsCopy = g_luaconfs.getCopy();
6652 luaconfsCopy.dsAnchors.clear();
6653 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6654 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6655 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6656
6657 g_luaconfs.setState(luaconfsCopy);
6658
6659 size_t queriesCount = 0;
6660
6661 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6662 queriesCount++;
6663
6664 if (type == QType::DS) {
6665 if (domain == DNSName("sub.powerdns.com.")) {
6666 setLWResult(res, 0, false, false, true);
6667 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6668 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6669 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6670 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6671 return 1;
6672 }
6673 else if (domain == DNSName("www.sub.powerdns.com.")) {
6674 setLWResult(res, 0, false, false, true);
6675 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);
6676 return 1;
6677 }
5374b03b
RG
6678 else {
6679 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6680 }
70b3fe7a
RG
6681 }
6682 else if (type == QType::DNSKEY) {
a69867f2 6683 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
70b3fe7a
RG
6684 setLWResult(res, 0, true, false, true);
6685 addDNSKEY(keys, domain, 300, res->d_records);
6686 addRRSIG(keys, res->d_records, domain, 300);
6687 return 1;
6688 }
6689 else {
6690 setLWResult(res, 0, false, false, true);
6691 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6692 return 1;
6693 }
6694 }
88cb0fe0 6695 else {
70b3fe7a
RG
6696 if (isRootServer(ip)) {
6697 setLWResult(res, 0, false, false, true);
6698 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6699 addDS(DNSName("com."), 300, res->d_records, keys);
6700 addRRSIG(keys, res->d_records, DNSName("."), 300);
6701 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6702 return 1;
6703 }
6704 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6705 if (domain == DNSName("com.")) {
6706 setLWResult(res, 0, true, false, true);
6707 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6708 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6709 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6710 }
6711 else {
6712 setLWResult(res, 0, false, false, true);
6713 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6714 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6715 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6716 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6717 }
70b3fe7a
RG
6718 return 1;
6719 }
6720 else if (ip == ComboAddress("192.0.2.2:53")) {
6721 setLWResult(res, 0, true, false, true);
a69867f2
RG
6722 if (type == QType::NS) {
6723 if (domain == DNSName("www.sub.powerdns.com.")) {
6724 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);
6725 }
6726 else if (domain == DNSName("sub.powerdns.com.")) {
6727 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
a69867f2
RG
6728 }
6729 else if (domain == DNSName("powerdns.com.")) {
6730 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6731 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6732 }
6733 } else {
6734 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6735 }
70b3fe7a
RG
6736 return 1;
6737 }
6738 }
6739
6740 return 0;
6741 });
6742
6743 vector<DNSRecord> ret;
6744 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6745 BOOST_CHECK_EQUAL(res, RCode::NoError);
6746 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6747 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6748 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6749 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6750
6751 /* again, to test the cache */
6752 ret.clear();
6753 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6754 BOOST_CHECK_EQUAL(res, RCode::NoError);
6755 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6756 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6757 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6758 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6759}
6760
6761BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6762 std::unique_ptr<SyncRes> sr;
a69867f2 6763 initSR(sr, true);
70b3fe7a 6764
0c43f455 6765 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6766
6767 primeHints();
6768 const DNSName target("www.sub.powerdns.com.");
6769 const ComboAddress targetAddr("192.0.2.42");
6770 testkeysset_t keys;
6771
6772 auto luaconfsCopy = g_luaconfs.getCopy();
6773 luaconfsCopy.dsAnchors.clear();
6774 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6775 /* No key material for .com */
6776 /* But TA for sub.powerdns.com. */
6777 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6778 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6779 g_luaconfs.setState(luaconfsCopy);
6780
6781 size_t queriesCount = 0;
6782
6783 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6784 queriesCount++;
6785
6786 if (type == QType::DS) {
88cb0fe0
RG
6787 if (domain == DNSName("www.sub.powerdns.com")) {
6788 setLWResult(res, 0, false, false, true);
6789 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);
6790 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6791 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6792 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6793 }
6794 else {
6795 setLWResult(res, 0, false, false, true);
5374b03b
RG
6796
6797 if (domain == DNSName("com.")) {
6798 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6799 /* no DS */
6800 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6801 addRRSIG(keys, res->d_records, DNSName("."), 300);
6802 }
6803 else {
6804 setLWResult(res, 0, false, false, true);
6805 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6806 }
88cb0fe0 6807 }
70b3fe7a
RG
6808 return 1;
6809 }
6810 else if (type == QType::DNSKEY) {
6811 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
6812 setLWResult(res, 0, true, false, true);
6813 addDNSKEY(keys, domain, 300, res->d_records);
6814 addRRSIG(keys, res->d_records, domain, 300);
6815 return 1;
6816 }
6817 }
88cb0fe0 6818 else {
70b3fe7a
RG
6819 if (isRootServer(ip)) {
6820 setLWResult(res, 0, false, false, true);
6821 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6822 /* no DS */
6823 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6824 addRRSIG(keys, res->d_records, DNSName("."), 300);
6825 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6826 return 1;
6827 }
6828 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
6829 if (domain == DNSName("com.")) {
6830 setLWResult(res, 0, true, false, true);
6831 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6832 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6833 }
5374b03b 6834 else if (domain.isPartOf(DNSName("powerdns.com."))) {
88cb0fe0
RG
6835 setLWResult(res, 0, false, false, true);
6836 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6837 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6838 }
70b3fe7a
RG
6839 return 1;
6840 }
6841 else if (ip == ComboAddress("192.0.2.2:53")) {
6842 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
6843 if (type == QType::NS) {
6844 if (domain == DNSName("www.sub.powerdns.com.")) {
6845 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);
6846 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6847 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6848 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6849 }
6850 else if (domain == DNSName("sub.powerdns.com.")) {
6851 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6852 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6853 }
6854 else if (domain == DNSName("powerdns.com.")) {
6855 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6856 }
6857 }
6858 else if (domain == DNSName("www.sub.powerdns.com.")) {
6859 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6860 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6861 }
70b3fe7a
RG
6862 return 1;
6863 }
6864 }
6865
6866 return 0;
6867 });
6868
6869 vector<DNSRecord> ret;
6870 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6871 BOOST_CHECK_EQUAL(res, RCode::NoError);
6872 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 6873 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 6874 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6875 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
6876
6877 /* again, to test the cache */
6878 ret.clear();
6879 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6880 BOOST_CHECK_EQUAL(res, RCode::NoError);
6881 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 6882 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 6883 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6884 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
6885}
6886
b7f378d1
RG
6887BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
6888 std::unique_ptr<SyncRes> sr;
895449a5 6889 initSR(sr, true);
b7f378d1 6890
0c43f455 6891 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6892
6893 primeHints();
6894 const DNSName target("powerdns.com.");
6895 testkeysset_t keys;
6896
6897 auto luaconfsCopy = g_luaconfs.getCopy();
6898 luaconfsCopy.dsAnchors.clear();
6899 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6900 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6901
6902 g_luaconfs.setState(luaconfsCopy);
6903
6904 size_t queriesCount = 0;
6905
6906 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6907 queriesCount++;
6908
6909 if (type == QType::DS) {
a53e8fe3 6910 if (domain == target) {
b7f378d1 6911 setLWResult(res, 0, false, false, true);
895449a5 6912 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6913 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6914 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6915 return 1;
6916 }
5374b03b
RG
6917 else {
6918 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6919 }
b7f378d1
RG
6920 }
6921 else if (type == QType::DNSKEY) {
6922 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6923 setLWResult(res, 0, true, false, true);
6924 addDNSKEY(keys, domain, 300, res->d_records);
6925 addRRSIG(keys, res->d_records, domain, 300);
6926 return 1;
6927 }
6928 else {
6929 setLWResult(res, 0, false, false, true);
895449a5 6930 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6931 return 1;
6932 }
6933 }
a69867f2 6934 else {
b7f378d1
RG
6935 if (isRootServer(ip)) {
6936 setLWResult(res, 0, false, false, true);
6937 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6938 addDS(DNSName("com."), 300, res->d_records, keys);
6939 addRRSIG(keys, res->d_records, DNSName("."), 300);
6940 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6941 return 1;
6942 }
6943 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6944 if (domain == DNSName("com.")) {
6945 setLWResult(res, 0, true, false, true);
6946 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6947 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6948 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6949 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6950 }
6951 else {
6952 setLWResult(res, 0, false, false, true);
6953 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6954 /* no DS */
6955 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6956 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6957 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6958 }
b7f378d1
RG
6959 return 1;
6960 }
6961 else if (ip == ComboAddress("192.0.2.2:53")) {
a69867f2
RG
6962 if (type == QType::NS) {
6963 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6964 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6965 }
6966 else {
6967 setLWResult(res, 0, true, false, true);
6968 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6969 }
b7f378d1
RG
6970 return 1;
6971 }
6972 }
6973
6974 return 0;
6975 });
6976
6977 vector<DNSRecord> ret;
6978 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6979 BOOST_CHECK_EQUAL(res, RCode::NoError);
6980 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6981 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2
RG
6982 /* 4 NS (com from root, com from com, powerdns.com from com,
6983 powerdns.com from powerdns.com)
6984 2 DNSKEY (. and com., none for powerdns.com because no DS)
6985 1 query for A
6986 */
6987 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6988
6989 /* again, to test the cache */
6990 ret.clear();
6991 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6992 BOOST_CHECK_EQUAL(res, RCode::NoError);
6993 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6994 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2 6995 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6996}
6997
895449a5 6998BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
b7f378d1 6999 std::unique_ptr<SyncRes> sr;
860d5e8e 7000 initSR(sr, true);
b7f378d1 7001
0c43f455 7002 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1 7003
895449a5
RG
7004 primeHints();
7005 const DNSName target("powerdns.com.");
7006 const DNSName targetCName("power-dns.com.");
7007 const ComboAddress targetCNameAddr("192.0.2.42");
7008 testkeysset_t keys;
7009
7010 auto luaconfsCopy = g_luaconfs.getCopy();
7011 luaconfsCopy.dsAnchors.clear();
7012 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7013 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7014 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7015 g_luaconfs.setState(luaconfsCopy);
7016
7017 size_t queriesCount = 0;
7018
7019 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7020 queriesCount++;
7021
7022 if (type == QType::DS) {
5374b03b 7023 if (domain == targetCName) {
895449a5
RG
7024 setLWResult(res, 0, false, false, true);
7025 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7026 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7027 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7028 return 1;
7029 }
5374b03b
RG
7030 else {
7031 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7032 }
895449a5
RG
7033 }
7034 else if (type == QType::DNSKEY) {
7035 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7036 setLWResult(res, 0, true, false, true);
7037 addDNSKEY(keys, domain, 300, res->d_records);
7038 addRRSIG(keys, res->d_records, domain, 300);
7039 return 1;
7040 }
7041 else {
7042 setLWResult(res, 0, false, false, true);
7043 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7044 return 1;
7045 }
7046 }
7047 else {
7048 if (isRootServer(ip)) {
7049 setLWResult(res, 0, false, false, true);
7050 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7051 addDS(DNSName("com."), 300, res->d_records, keys);
7052 addRRSIG(keys, res->d_records, DNSName("."), 300);
7053 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7054 return 1;
7055 }
7056 else if (ip == ComboAddress("192.0.2.1:53")) {
7057 setLWResult(res, 0, false, false, true);
a69867f2
RG
7058 if (domain == DNSName("com.")) {
7059 setLWResult(res, 0, true, false, true);
7060 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7061 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7062 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7063 addRRSIG(keys, res->d_records, DNSName("com."), 300);
895449a5 7064 }
a69867f2
RG
7065 else {
7066 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7067 if (domain == DNSName("powerdns.com.")) {
7068 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7069 }
7070 else if (domain == targetCName) {
7071 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7072 }
7073 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7074 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
895449a5 7075 }
a69867f2 7076
895449a5
RG
7077 return 1;
7078 }
7079 else if (ip == ComboAddress("192.0.2.2:53")) {
7080 setLWResult(res, 0, true, false, true);
a69867f2
RG
7081
7082 if (type == QType::NS) {
7083 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7084 if (domain == DNSName("powerdns.com.")) {
7085 addRRSIG(keys, res->d_records, domain, 300);
7086 }
7087 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7088 if (domain == DNSName("powerdns.com.")) {
7089 addRRSIG(keys, res->d_records, domain, 300);
7090 }
895449a5 7091 }
a69867f2
RG
7092 else {
7093 if (domain == DNSName("powerdns.com.")) {
7094 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7095 addRRSIG(keys, res->d_records, domain, 300);
7096 }
7097 else if (domain == targetCName) {
7098 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7099 }
895449a5 7100 }
a69867f2 7101
895449a5
RG
7102 return 1;
7103 }
7104 }
7105
7106 return 0;
7107 });
7108
7109 vector<DNSRecord> ret;
7110 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7111 BOOST_CHECK_EQUAL(res, RCode::NoError);
7112 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7113 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7114 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7115
7116 /* again, to test the cache */
7117 ret.clear();
7118 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7119 BOOST_CHECK_EQUAL(res, RCode::NoError);
7120 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7121 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7122 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7123}
7124
8783a0ac
RG
7125BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname_glue) {
7126 std::unique_ptr<SyncRes> sr;
cd48a0ff 7127 initSR(sr, true);
8783a0ac
RG
7128
7129 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7130
7131 primeHints();
7132 const DNSName target("powerdns.com.");
7133 const DNSName targetCName1("cname.sub.powerdns.com.");
7134 const DNSName targetCName2("cname2.sub.powerdns.com.");
7135 const ComboAddress targetCName2Addr("192.0.2.42");
7136 testkeysset_t keys;
7137
7138 auto luaconfsCopy = g_luaconfs.getCopy();
7139 luaconfsCopy.dsAnchors.clear();
7140 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7141 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7142 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7143 g_luaconfs.setState(luaconfsCopy);
7144
7145 size_t queriesCount = 0;
7146
7147 sr->setAsyncCallback([target,targetCName1,targetCName2,targetCName2Addr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7148 queriesCount++;
7149
7150 if (type == QType::DS || type == QType::DNSKEY) {
7151 if (domain == DNSName("sub.powerdns.com")) {
7152 setLWResult(res, 0, false, false, true);
7153 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7154 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7155 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7156 return 1;
7157 }
7158 else {
7159 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7160 }
7161 }
7162 else {
7163 if (isRootServer(ip)) {
7164 setLWResult(res, 0, false, false, true);
7165 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7166 addDS(DNSName("com."), 300, res->d_records, keys);
7167 addRRSIG(keys, res->d_records, DNSName("."), 300);
7168 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7169 return 1;
7170 }
7171 else if (ip == ComboAddress("192.0.2.1:53")) {
7172 setLWResult(res, 0, false, false, true);
7173 if (domain == DNSName("com.")) {
7174 setLWResult(res, 0, true, false, true);
7175 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7176 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7177 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7178 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7179 }
7180 else {
7181 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7182 if (domain == DNSName("powerdns.com.")) {
7183 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7184 }
7185 else if (domain == DNSName("sub.powerdns.com")) {
7186 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7187 }
7188 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7189 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7190 }
7191
7192 return 1;
7193 }
7194 else if (ip == ComboAddress("192.0.2.2:53")) {
7195 setLWResult(res, 0, true, false, true);
7196
7197 if (type == QType::NS) {
7198 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7199 if (domain == DNSName("powerdns.com.")) {
7200 addRRSIG(keys, res->d_records, domain, 300);
7201 }
7202 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7203 if (domain == DNSName("powerdns.com.")) {
7204 addRRSIG(keys, res->d_records, domain, 300);
7205 }
7206 }
7207 else {
7208 if (domain == DNSName("powerdns.com.")) {
7209 addRecordToLW(res, domain, QType::CNAME, targetCName1.toString());
7210 addRRSIG(keys, res->d_records, domain, 300);
7211 /* add the CNAME target as a glue, with no RRSIG since the sub zone is insecure */
7212 addRecordToLW(res, targetCName1, QType::CNAME, targetCName2.toString());
7213 addRecordToLW(res, targetCName2, QType::A, targetCName2Addr.toString());
7214 }
7215 else if (domain == targetCName1) {
7216 addRecordToLW(res, domain, QType::CNAME, targetCName2.toString());
7217 }
7218 else if (domain == targetCName2) {
7219 addRecordToLW(res, domain, QType::A, targetCName2Addr.toString());
7220 }
7221 }
7222
7223 return 1;
7224 }
7225 }
7226
7227 return 0;
7228 });
7229
7230 vector<DNSRecord> ret;
7231 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7232 BOOST_CHECK_EQUAL(res, RCode::NoError);
7233 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7234 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7235 BOOST_CHECK_EQUAL(queriesCount, 11);
7236
7237 /* again, to test the cache */
7238 ret.clear();
7239 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7240 BOOST_CHECK_EQUAL(res, RCode::NoError);
7241 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7242 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7243 BOOST_CHECK_EQUAL(queriesCount, 11);
7244}
7245
3d5ebf10
RG
7246BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
7247 std::unique_ptr<SyncRes> sr;
7248 initSR(sr, true);
7249
0c43f455 7250 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7251
7252 primeHints();
7253 const DNSName target("power-dns.com.");
7254 const DNSName targetCName("powerdns.com.");
7255 const ComboAddress targetCNameAddr("192.0.2.42");
7256 testkeysset_t keys;
7257
7258 auto luaconfsCopy = g_luaconfs.getCopy();
7259 luaconfsCopy.dsAnchors.clear();
7260 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7261 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7262 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7263 g_luaconfs.setState(luaconfsCopy);
7264
7265 size_t queriesCount = 0;
7266
7267 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7268 queriesCount++;
7269
7270 if (type == QType::DS) {
a53e8fe3 7271 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
7272 setLWResult(res, 0, false, false, true);
7273 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7274 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7275 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7276 return 1;
7277 }
5374b03b
RG
7278 else {
7279 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7280 }
3d5ebf10
RG
7281 }
7282 else if (type == QType::DNSKEY) {
7283 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7284 setLWResult(res, 0, true, false, true);
7285 addDNSKEY(keys, domain, 300, res->d_records);
7286 addRRSIG(keys, res->d_records, domain, 300);
7287 return 1;
7288 }
7289 else {
7290 setLWResult(res, 0, false, false, true);
7291 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7292 return 1;
7293 }
7294 }
7295 else {
7296 if (isRootServer(ip)) {
7297 setLWResult(res, 0, false, false, true);
7298 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7299 addDS(DNSName("com."), 300, res->d_records, keys);
7300 addRRSIG(keys, res->d_records, DNSName("."), 300);
7301 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7302 return 1;
7303 }
7304 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7305 if (domain == DNSName("com.")) {
7306 setLWResult(res, 0, true, false, true);
7307 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7308 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7309 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7310 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7311 }
a69867f2
RG
7312 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7313 setLWResult(res, 0, false, false, true);
7314 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7315 if (domain == targetCName) {
7316 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7317 }
7318 else if (domain == target) {
7319 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7320 }
7321 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7322 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7323 }
3d5ebf10
RG
7324 return 1;
7325 }
7326 else if (ip == ComboAddress("192.0.2.2:53")) {
7327 setLWResult(res, 0, true, false, true);
a69867f2
RG
7328 if (type == QType::NS) {
7329 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7330 if (domain == DNSName("powerdns.com.")) {
7331 addRRSIG(keys, res->d_records, domain, 300);
7332 }
7333 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7334 if (domain == DNSName("powerdns.com.")) {
7335 addRRSIG(keys, res->d_records, domain, 300);
7336 }
3d5ebf10 7337 }
a69867f2
RG
7338 else {
7339 if (domain == target) {
7340 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7341 }
7342 else if (domain == targetCName) {
7343 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7344 addRRSIG(keys, res->d_records, domain, 300);
7345 }
3d5ebf10
RG
7346 }
7347 return 1;
7348 }
7349 }
7350
7351 return 0;
7352 });
7353
7354 vector<DNSRecord> ret;
7355 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7356 BOOST_CHECK_EQUAL(res, RCode::NoError);
7357 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7358 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7359 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7360
7361 /* again, to test the cache */
7362 ret.clear();
7363 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7364 BOOST_CHECK_EQUAL(res, RCode::NoError);
7365 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7366 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7367 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7368}
7369
7370BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
7371 std::unique_ptr<SyncRes> sr;
7372 initSR(sr, true);
7373
0c43f455 7374 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7375
7376 primeHints();
7377 const DNSName target("power-dns.com.");
7378 const DNSName targetCName("powerdns.com.");
7379 const ComboAddress targetCNameAddr("192.0.2.42");
7380 testkeysset_t keys;
7381
7382 auto luaconfsCopy = g_luaconfs.getCopy();
7383 luaconfsCopy.dsAnchors.clear();
7384 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7385 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7386 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7387 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7388 g_luaconfs.setState(luaconfsCopy);
7389
7390 size_t queriesCount = 0;
7391
7392 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7393 queriesCount++;
7394
5374b03b
RG
7395 if (type == QType::DS || type == QType::DNSKEY) {
7396 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7397 }
7398 else {
7399 if (isRootServer(ip)) {
7400 setLWResult(res, 0, false, false, true);
7401 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7402 addDS(DNSName("com."), 300, res->d_records, keys);
7403 addRRSIG(keys, res->d_records, DNSName("."), 300);
7404 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7405 return 1;
7406 }
7407 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7408 if (domain == DNSName("com.")) {
7409 setLWResult(res, 0, true, false, true);
7410 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7411 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7412 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7413 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7414 }
7415 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7416 setLWResult(res, 0, false, false, true);
7417 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7418 addDS(DNSName(domain), 300, res->d_records, keys);
7419 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7420 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7421 }
3d5ebf10
RG
7422 return 1;
7423 }
7424 else if (ip == ComboAddress("192.0.2.2:53")) {
7425 setLWResult(res, 0, true, false, true);
a69867f2
RG
7426 if (type == QType::NS) {
7427 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7428 addRRSIG(keys, res->d_records, domain, 300);
7429 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7430 addRRSIG(keys, res->d_records, domain, 300);
7431 }
a69867f2
RG
7432 else {
7433 if (domain == target) {
7434 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7435 /* No RRSIG, leading to bogus */
7436 }
7437 else if (domain == targetCName) {
7438 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7439 addRRSIG(keys, res->d_records, domain, 300);
7440 }
7441 }
3d5ebf10
RG
7442 return 1;
7443 }
7444 }
7445
7446 return 0;
7447 });
7448
7449 vector<DNSRecord> ret;
7450 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7451 BOOST_CHECK_EQUAL(res, RCode::NoError);
7452 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7453 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7454 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7455
7456 /* again, to test the cache */
7457 ret.clear();
7458 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7459 BOOST_CHECK_EQUAL(res, RCode::NoError);
7460 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7461 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7462 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7463}
7464
7465BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7466 std::unique_ptr<SyncRes> sr;
7467 initSR(sr, true);
7468
0c43f455 7469 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7470
7471 primeHints();
7472 const DNSName target("power-dns.com.");
7473 const DNSName targetCName("powerdns.com.");
7474 const ComboAddress targetCNameAddr("192.0.2.42");
7475 testkeysset_t keys;
7476
7477 auto luaconfsCopy = g_luaconfs.getCopy();
7478 luaconfsCopy.dsAnchors.clear();
7479 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7480 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7481 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7482 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7483 g_luaconfs.setState(luaconfsCopy);
7484
7485 size_t queriesCount = 0;
7486
7487 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7488 queriesCount++;
7489
5374b03b
RG
7490 if (type == QType::DS || type == QType::DNSKEY) {
7491 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7492 }
7493 else {
7494 if (isRootServer(ip)) {
7495 setLWResult(res, 0, false, false, true);
7496 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7497 addDS(DNSName("com."), 300, res->d_records, keys);
7498 addRRSIG(keys, res->d_records, DNSName("."), 300);
7499 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7500 return 1;
7501 }
7502 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7503 if (domain == DNSName("com.")) {
7504 setLWResult(res, 0, true, false, true);
7505 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7506 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7507 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7508 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7509 }
7510 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7511 setLWResult(res, 0, false, false, true);
7512 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7513 addDS(DNSName(domain), 300, res->d_records, keys);
7514 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7515 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7516 }
3d5ebf10
RG
7517 return 1;
7518 }
7519 else if (ip == ComboAddress("192.0.2.2:53")) {
7520 setLWResult(res, 0, true, false, true);
a69867f2
RG
7521 if (type == QType::NS) {
7522 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7523 addRRSIG(keys, res->d_records, domain, 300);
7524 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7525 addRRSIG(keys, res->d_records, domain, 300);
7526 }
a69867f2
RG
7527 else {
7528 if (domain == target) {
7529 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7530 addRRSIG(keys, res->d_records, domain, 300);
7531 }
7532 else if (domain == targetCName) {
7533 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7534 /* No RRSIG, leading to bogus */
7535 }
3d5ebf10
RG
7536 }
7537 return 1;
7538 }
7539 }
7540
7541 return 0;
7542 });
7543
7544 vector<DNSRecord> ret;
7545 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7546 BOOST_CHECK_EQUAL(res, RCode::NoError);
7547 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7548 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7549 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7550
7551 /* again, to test the cache */
7552 ret.clear();
7553 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7554 BOOST_CHECK_EQUAL(res, RCode::NoError);
7555 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7556 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7557 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7558}
7559
7560BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
7561 std::unique_ptr<SyncRes> sr;
7562 initSR(sr, true);
7563
0c43f455 7564 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7565
7566 primeHints();
7567 const DNSName target("power-dns.com.");
7568 const DNSName targetCName("powerdns.com.");
7569 const ComboAddress targetCNameAddr("192.0.2.42");
7570 testkeysset_t keys;
7571
7572 auto luaconfsCopy = g_luaconfs.getCopy();
7573 luaconfsCopy.dsAnchors.clear();
7574 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7575 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7576 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7577 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7578 g_luaconfs.setState(luaconfsCopy);
7579
7580 size_t queriesCount = 0;
7581
7582 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7583 queriesCount++;
7584
5374b03b
RG
7585 if (type == QType::DS || type == QType::DNSKEY) {
7586 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7587 }
7588 else {
7589 if (isRootServer(ip)) {
7590 setLWResult(res, 0, false, false, true);
7591 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7592 addDS(DNSName("com."), 300, res->d_records, keys);
7593 addRRSIG(keys, res->d_records, DNSName("."), 300);
7594 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7595 return 1;
7596 }
7597 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7598 if (domain == DNSName("com.")) {
7599 setLWResult(res, 0, true, false, true);
7600 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7601 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7602 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7603 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7604 }
7605 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7606 setLWResult(res, 0, false, false, true);
7607 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7608 addDS(DNSName(domain), 300, res->d_records, keys);
7609 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7610 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7611 }
3d5ebf10
RG
7612 return 1;
7613 }
7614 else if (ip == ComboAddress("192.0.2.2:53")) {
7615 setLWResult(res, 0, true, false, true);
a69867f2
RG
7616 if (type == QType::NS) {
7617 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
3d5ebf10 7618 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 7619 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7620 addRRSIG(keys, res->d_records, domain, 300);
7621 }
a69867f2
RG
7622 else {
7623 if (domain == target) {
7624 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7625 addRRSIG(keys, res->d_records, domain, 300);
7626 }
7627 else if (domain == targetCName) {
7628 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7629 addRRSIG(keys, res->d_records, domain, 300);
7630 }
7631 }
3d5ebf10
RG
7632 return 1;
7633 }
7634 }
7635
7636 return 0;
7637 });
7638
7639 vector<DNSRecord> ret;
7640 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7641 BOOST_CHECK_EQUAL(res, RCode::NoError);
7642 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7643 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7644 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7645
7646 /* again, to test the cache */
7647 ret.clear();
7648 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7649 BOOST_CHECK_EQUAL(res, RCode::NoError);
7650 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7651 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7652 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7653}
7654
7655BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7656 std::unique_ptr<SyncRes> sr;
a69867f2 7657 initSR(sr, true);
3d5ebf10 7658
0c43f455 7659 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7660
7661 primeHints();
7662 const DNSName target("powerdns.com.");
7663 const DNSName targetCName("power-dns.com.");
7664 const ComboAddress targetCNameAddr("192.0.2.42");
7665 testkeysset_t keys;
7666
7667 auto luaconfsCopy = g_luaconfs.getCopy();
7668 luaconfsCopy.dsAnchors.clear();
7669 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7670 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7671 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7672 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7673 g_luaconfs.setState(luaconfsCopy);
7674
7675 size_t queriesCount = 0;
7676
7677 sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7678 queriesCount++;
7679
7680 if (type == QType::DS) {
a53e8fe3 7681 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
7682 setLWResult(res, 0, false, false, true);
7683 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7684 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7685 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7686 return 1;
7687 }
5374b03b
RG
7688 else {
7689 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7690 }
3d5ebf10
RG
7691 }
7692 else if (type == QType::DNSKEY) {
7693 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7694 setLWResult(res, 0, true, false, true);
7695 addDNSKEY(keys, domain, 300, res->d_records);
7696 addRRSIG(keys, res->d_records, domain, 300);
7697 return 1;
7698 }
7699 else {
7700 setLWResult(res, 0, false, false, true);
7701 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7702 return 1;
7703 }
7704 }
7705 else {
7706 if (isRootServer(ip)) {
7707 setLWResult(res, 0, false, false, true);
7708 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7709 addDS(DNSName("com."), 300, res->d_records, keys);
7710 addRRSIG(keys, res->d_records, DNSName("."), 300);
7711 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7712 return 1;
7713 }
7714 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7715 if (domain == DNSName("com.")) {
7716 setLWResult(res, 0, true, false, true);
a69867f2 7717 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0
RG
7718 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7719 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7720 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7721 }
88cb0fe0
RG
7722 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7723 setLWResult(res, 0, false, false, true);
7724 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7725 if (domain == DNSName("powerdns.com.")) {
7726 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7727 }
7728 else if (domain == targetCName) {
7729 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7730 }
7731 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7732 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7733 }
3d5ebf10
RG
7734 return 1;
7735 }
7736 else if (ip == ComboAddress("192.0.2.2:53")) {
7737 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7738 if (type == QType::NS) {
7739 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7740 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7741 }
88cb0fe0
RG
7742 else {
7743 if (domain == DNSName("powerdns.com.")) {
7744 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7745 /* No RRSIG -> Bogus */
7746 }
7747 else if (domain == targetCName) {
7748 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7749 }
3d5ebf10
RG
7750 }
7751 return 1;
7752 }
7753 }
7754
7755 return 0;
7756 });
7757
7758 vector<DNSRecord> ret;
7759 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7760 BOOST_CHECK_EQUAL(res, RCode::NoError);
7761 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7762 /* no RRSIG to show */
7763 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7764 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7765
7766 /* again, to test the cache */
7767 ret.clear();
7768 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7769 BOOST_CHECK_EQUAL(res, RCode::NoError);
7770 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7771 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7772 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7773}
7774
895449a5
RG
7775BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7776 std::unique_ptr<SyncRes> sr;
7777 initSR(sr, true);
7778
0c43f455 7779 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
7780
7781 primeHints();
7782 const DNSName target("powerdns.com.");
7783 const ComboAddress targetAddr("192.0.2.42");
7784 testkeysset_t keys;
7785
7786 auto luaconfsCopy = g_luaconfs.getCopy();
7787 luaconfsCopy.dsAnchors.clear();
7788 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7789 /* No key material for .com */
7790 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7791 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7792 g_luaconfs.setState(luaconfsCopy);
7793
7794 size_t queriesCount = 0;
7795
7796 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7797 queriesCount++;
7798
a53e8fe3 7799 if (type == QType::DNSKEY) {
895449a5
RG
7800 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7801 setLWResult(res, 0, true, false, true);
7802 addDNSKEY(keys, domain, 300, res->d_records);
7803 addRRSIG(keys, res->d_records, domain, 300);
7804 return 1;
7805 }
7806 else if (domain == DNSName("com.")) {
7807 setLWResult(res, 0, false, false, true);
7808 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7809 return 1;
7810 }
7811 }
88cb0fe0 7812 else {
895449a5
RG
7813 if (isRootServer(ip)) {
7814 setLWResult(res, 0, false, false, true);
7815 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7816 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7817 addRRSIG(keys, res->d_records, DNSName("."), 300);
7818 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7819 return 1;
7820 }
7821 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7822 if (target == domain) {
7823 setLWResult(res, 0, false, false, true);
7824 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7825 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7826 }
7827 else if (domain == DNSName("com.")) {
7828 setLWResult(res, 0, true, false, true);
7829 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7830 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7831 }
895449a5
RG
7832 return 1;
7833 }
7834 else if (ip == ComboAddress("192.0.2.2:53")) {
7835 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7836 if (type == QType::NS) {
7837 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7838 }
7839 else {
7840 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7841 }
895449a5
RG
7842 addRRSIG(keys, res->d_records, domain, 300);
7843 return 1;
7844 }
7845 }
7846
7847 return 0;
7848 });
7849
7850 vector<DNSRecord> ret;
7851 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7852 BOOST_CHECK_EQUAL(res, RCode::NoError);
7853 /* should be insecure but we have a TA for powerdns.com. */
7854 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7855 /* We got a RRSIG */
7856 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7857 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7858 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
7859
7860 /* again, to test the cache */
7861 ret.clear();
7862 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7863 BOOST_CHECK_EQUAL(res, RCode::NoError);
7864 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7865 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7866 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7867 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
7868}
7869
7870BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
7871 std::unique_ptr<SyncRes> sr;
7872 initSR(sr, true);
7873
0c43f455 7874 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
7875
7876 primeHints();
7877 const DNSName target("powerdns.com.");
7878 const ComboAddress targetAddr("192.0.2.42");
7879 testkeysset_t keys;
7880
7881 auto luaconfsCopy = g_luaconfs.getCopy();
7882 luaconfsCopy.dsAnchors.clear();
7883 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7884 /* No key material for .com */
7885 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7886 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7887 g_luaconfs.setState(luaconfsCopy);
7888
7889 size_t queriesCount = 0;
7890
7891 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7892 queriesCount++;
7893
a53e8fe3 7894 if (type == QType::DNSKEY) {
895449a5
RG
7895 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7896 setLWResult(res, 0, true, false, true);
7897 addDNSKEY(keys, domain, 300, res->d_records);
7898 addRRSIG(keys, res->d_records, domain, 300);
7899 return 1;
7900 }
7901 else if (domain == DNSName("com.")) {
7902 setLWResult(res, 0, false, false, true);
7903 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7904 return 1;
7905 }
7906 }
70b3fe7a
RG
7907 else {
7908 if (target.isPartOf(domain) && isRootServer(ip)) {
895449a5
RG
7909 setLWResult(res, 0, false, false, true);
7910 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7911 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7912 addRRSIG(keys, res->d_records, DNSName("."), 300);
7913 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7914 return 1;
7915 }
7916 else if (ip == ComboAddress("192.0.2.1:53")) {
70b3fe7a
RG
7917 if (target == domain) {
7918 setLWResult(res, 0, false, false, true);
7919 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7920 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7921 }
7922 else if (domain == DNSName("com.")) {
7923 setLWResult(res, 0, true, false, true);
7924 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0 7925 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
70b3fe7a 7926 }
895449a5
RG
7927 return 1;
7928 }
70b3fe7a 7929 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
895449a5 7930 setLWResult(res, 0, true, false, true);
70b3fe7a
RG
7931 if (type == QType::NS) {
7932 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7933 }
7934 else {
7935 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7936 }
895449a5
RG
7937 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
7938 return 1;
7939 }
7940 }
7941
7942 return 0;
7943 });
7944
7945 vector<DNSRecord> ret;
7946 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7947 BOOST_CHECK_EQUAL(res, RCode::NoError);
7948 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
7949 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7950 /* No RRSIG */
7951 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7952 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7953 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
7954
7955 /* again, to test the cache */
7956 ret.clear();
7957 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7958 BOOST_CHECK_EQUAL(res, RCode::NoError);
7959 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7960 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7961 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7962 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
7963}
7964
895449a5
RG
7965BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
7966 std::unique_ptr<SyncRes> sr;
7967 initSR(sr, true);
7968
0c43f455 7969 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5 7970
b7f378d1
RG
7971 primeHints();
7972 const DNSName target(".");
7973 testkeysset_t keys;
7974
7975 auto luaconfsCopy = g_luaconfs.getCopy();
7976 luaconfsCopy.dsAnchors.clear();
7977 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7978 /* Add a NTA for "." */
7979 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
7980 g_luaconfs.setState(luaconfsCopy);
7981
7982 size_t queriesCount = 0;
7983
7984 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
7985 queriesCount++;
7986
7987 if (domain == target && type == QType::NS) {
7988
7989 setLWResult(res, 0, true, false, true);
7990 char addr[] = "a.root-servers.net.";
7991 for (char idx = 'a'; idx <= 'm'; idx++) {
7992 addr[0] = idx;
8455425c
RG
7993 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7994 }
7995
7996 addRRSIG(keys, res->d_records, domain, 300);
7997
7998 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7999 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8000
8001 return 1;
8002 } else if (domain == target && type == QType::DNSKEY) {
8003
8004 setLWResult(res, 0, true, false, true);
8005
8006 /* No DNSKEY */
8007
8008 return 1;
8009 }
8010
8011 return 0;
8012 });
8013
8014 vector<DNSRecord> ret;
8015 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8016 BOOST_CHECK_EQUAL(res, RCode::NoError);
8017 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8018 /* 13 NS + 1 RRSIG */
8019 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8020 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8021
8022 /* again, to test the cache */
8023 ret.clear();
8024 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8025 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8026 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8027 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8028 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8029}
8030
8031BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
8032 std::unique_ptr<SyncRes> sr;
895449a5 8033 initSR(sr, true);
8455425c 8034
0c43f455 8035 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
8036
8037 primeHints();
8038 const DNSName target(".");
b7f378d1 8039 testkeysset_t keys;
8455425c
RG
8040
8041 /* Remove the root DS */
8042 auto luaconfsCopy = g_luaconfs.getCopy();
8043 luaconfsCopy.dsAnchors.clear();
8044 g_luaconfs.setState(luaconfsCopy);
8045
8046 size_t queriesCount = 0;
8047
8048 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
8049 queriesCount++;
8050
8051 if (domain == target && type == QType::NS) {
8052
8053 setLWResult(res, 0, true, false, true);
8054 char addr[] = "a.root-servers.net.";
8055 for (char idx = 'a'; idx <= 'm'; idx++) {
8056 addr[0] = idx;
8057 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8058 }
8059
8060 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8061 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8062
8063 return 1;
8064 }
8065
8066 return 0;
8067 });
8068
8069 vector<DNSRecord> ret;
8070 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8071 BOOST_CHECK_EQUAL(res, RCode::NoError);
8072 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8073 /* 13 NS + 0 RRSIG */
8074 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8075 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8076
8077 /* again, to test the cache */
8078 ret.clear();
8079 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8080 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8081 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8082 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8083 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8084}
8085
114829cc
RG
8086BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
8087 std::unique_ptr<SyncRes> sr;
8088 initSR(sr, true);
8089
5d7b19c5 8090 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
114829cc
RG
8091
8092 primeHints();
8093 const DNSName target("powerdns.com.");
8094 testkeysset_t keys;
8095
8096 auto luaconfsCopy = g_luaconfs.getCopy();
8097 luaconfsCopy.dsAnchors.clear();
8098 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5374b03b 8099 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
114829cc
RG
8100 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8101 g_luaconfs.setState(luaconfsCopy);
8102
8103 size_t queriesCount = 0;
8104
8105 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
8106 queriesCount++;
8107
5374b03b
RG
8108 if (type == QType::DS || type == QType::DNSKEY) {
8109 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
114829cc
RG
8110 }
8111 else {
8112
8113 setLWResult(res, 0, true, false, true);
8114 return 1;
8115 }
8116
8117 return 0;
8118 });
8119
8120 vector<DNSRecord> ret;
8121 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8122 BOOST_CHECK_EQUAL(res, RCode::NoError);
8123 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8124 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8125 /* com|NS, powerdns.com|NS, powerdns.com|A */
8126 BOOST_CHECK_EQUAL(queriesCount, 3);
8127
8128 /* again, to test the cache */
8129 ret.clear();
8130 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8131 BOOST_CHECK_EQUAL(res, RCode::NoError);
8132 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8133 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8134 /* we don't store empty results */
5374b03b 8135 BOOST_CHECK_EQUAL(queriesCount, 4);
114829cc
RG
8136}
8137
db04449e
RG
8138BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
8139 init();
8140
8141 testkeysset_t keys;
8142 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8143
8144 vector<DNSRecord> records;
8145
8146 vector<shared_ptr<DNSRecordContent>> recordContents;
8147 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8148
8149 /*
8150 No wrap test case:
8151 a.example.org. -> d.example.org. denies the existence of b.example.org.
8152 */
8153 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8154 recordContents.push_back(records.at(0).d_content);
8155 addRRSIG(keys, records, DNSName("example.org."), 300);
8156 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8157 records.clear();
8158
8159 ContentSigPair pair;
8160 pair.records = recordContents;
8161 pair.signatures = signatureContents;
8162 cspmap_t denialMap;
8163 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8164
9b061cf5
RG
8165 /* add wildcard denial */
8166 recordContents.clear();
8167 signatureContents.clear();
8168 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8169 recordContents.push_back(records.at(0).d_content);
8170 addRRSIG(keys, records, DNSName("example.org."), 300);
8171 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8172 records.clear();
8173
8174 pair.records = recordContents;
8175 pair.signatures = signatureContents;
8176 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
8177
00e3fef4 8178 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8179 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8180
00e3fef4 8181 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8182 /* let's check that d.example.org. is not denied by this proof */
8183 BOOST_CHECK_EQUAL(denialState, NODATA);
8184}
8185
8186BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
8187 init();
8188
8189 testkeysset_t keys;
8190 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8191
8192 vector<DNSRecord> records;
8193
8194 vector<shared_ptr<DNSRecordContent>> recordContents;
8195 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8196
8197 /*
8198 Wrap case 1 test case:
8199 z.example.org. -> b.example.org. denies the existence of a.example.org.
8200 */
8201 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8202 recordContents.push_back(records.at(0).d_content);
8203 addRRSIG(keys, records, DNSName("example.org."), 300);
8204 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8205 records.clear();
8206
8207 ContentSigPair pair;
8208 pair.records = recordContents;
8209 pair.signatures = signatureContents;
8210 cspmap_t denialMap;
8211 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
8212
00e3fef4 8213 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8214 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8215
00e3fef4 8216 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8217 /* let's check that d.example.org. is not denied by this proof */
8218 BOOST_CHECK_EQUAL(denialState, NODATA);
8219}
8220
8221BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
8222 init();
8223
8224 testkeysset_t keys;
8225 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8226
8227 vector<DNSRecord> records;
8228
8229 vector<shared_ptr<DNSRecordContent>> recordContents;
8230 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8231
8232 /*
8233 Wrap case 2 test case:
8234 y.example.org. -> a.example.org. denies the existence of z.example.org.
8235 */
8236 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8237 recordContents.push_back(records.at(0).d_content);
8238 addRRSIG(keys, records, DNSName("example.org."), 300);
8239 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8240 records.clear();
8241
8242 ContentSigPair pair;
8243 pair.records = recordContents;
8244 pair.signatures = signatureContents;
8245 cspmap_t denialMap;
8246 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
8247
00e3fef4 8248 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
db04449e
RG
8249 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8250
00e3fef4 8251 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8252 /* let's check that d.example.org. is not denied by this proof */
8253 BOOST_CHECK_EQUAL(denialState, NODATA);
8254}
8255
8256BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
8257 init();
8258
8259 testkeysset_t keys;
8260 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8261
8262 vector<DNSRecord> records;
8263
8264 vector<shared_ptr<DNSRecordContent>> recordContents;
8265 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8266
8267 /*
8268 Only one NSEC in the whole zone test case:
8269 a.example.org. -> a.example.org. denies the existence of b.example.org.
8270 */
8271 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8272 recordContents.push_back(records.at(0).d_content);
8273 addRRSIG(keys, records, DNSName("example.org."), 300);
8274 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8275 records.clear();
8276
8277 ContentSigPair pair;
8278 pair.records = recordContents;
8279 pair.signatures = signatureContents;
8280 cspmap_t denialMap;
8281 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8282
00e3fef4 8283 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8284 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8285
00e3fef4 8286 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8287 /* let's check that d.example.org. is not denied by this proof */
8288 BOOST_CHECK_EQUAL(denialState, NODATA);
8289}
8290
1efd998a
RG
8291BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
8292 init();
8293
8294 testkeysset_t keys;
8295 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8296
8297 vector<DNSRecord> records;
8298
8299 vector<shared_ptr<DNSRecordContent>> recordContents;
8300 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8301
8302 /*
8303 The RRSIG from "." denies the existence of anything between a. and c.,
8304 including b.
8305 */
8306 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
8307 recordContents.push_back(records.at(0).d_content);
8308 addRRSIG(keys, records, DNSName("."), 300);
8309 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8310 records.clear();
8311
8312 ContentSigPair pair;
8313 pair.records = recordContents;
8314 pair.signatures = signatureContents;
8315 cspmap_t denialMap;
8316 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8317
9b061cf5
RG
8318 /* add wildcard denial */
8319 recordContents.clear();
8320 signatureContents.clear();
8321 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8322 recordContents.push_back(records.at(0).d_content);
8323 addRRSIG(keys, records, DNSName("."), 300);
8324 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8325 records.clear();
8326
8327 pair.records = recordContents;
8328 pair.signatures = signatureContents;
8329 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
8330
00e3fef4 8331 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
1efd998a
RG
8332 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8333}
8334
8335BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
8336 init();
8337
8338 testkeysset_t keys;
8339 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8340
8341 vector<DNSRecord> records;
8342
8343 vector<shared_ptr<DNSRecordContent>> recordContents;
8344 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8345
8346 /*
8347 The RRSIG from "." denies the existence of any type except NS at a.
8348 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8349 signer field that is shorter than the owner name of the NSEC RR) it can't
8350 be used to deny anything except the whole name or a DS.
8351 */
8352 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
8353 recordContents.push_back(records.at(0).d_content);
8354 addRRSIG(keys, records, DNSName("."), 300);
8355 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8356 records.clear();
8357
8358 ContentSigPair pair;
8359 pair.records = recordContents;
8360 pair.signatures = signatureContents;
8361 cspmap_t denialMap;
8362 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8363
8364 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8365 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8366 nonexistence of any RRs below that zone cut, which include all RRs at
8367 that (original) owner name other than DS RRs, and all RRs below that
8368 owner name regardless of type.
8369 */
8370
00e3fef4 8371 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
1efd998a
RG
8372 /* no data means the qname/qtype is not denied, because an ancestor
8373 delegation NSEC can only deny the DS */
8374 BOOST_CHECK_EQUAL(denialState, NODATA);
8375
b93be4a0
RG
8376 /* it can not be used to deny any RRs below that owner name either */
8377 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false);
8378 BOOST_CHECK_EQUAL(denialState, NODATA);
8379
00e3fef4 8380 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
1efd998a
RG
8381 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8382}
8383
95823c07
RG
8384BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
8385 init();
8386
8387 testkeysset_t keys;
8388 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8389
8390 vector<DNSRecord> records;
8391
8392 vector<shared_ptr<DNSRecordContent>> recordContents;
8393 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8394
8395 /*
8396 * RFC 5155 section 8.9:
8397 * If there is an NSEC3 RR present in the response that matches the
8398 * delegation name, then the validator MUST ensure that the NS bit is
8399 * set and that the DS bit is not set in the Type Bit Maps field of the
8400 * NSEC3 RR.
8401 */
8402 /*
8403 The RRSIG from "." denies the existence of any type at a.
8404 NS should be set if it was proving an insecure delegation, let's check that
8405 we correctly detect that it's not.
8406 */
8407 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
8408 recordContents.push_back(records.at(0).d_content);
8409 addRRSIG(keys, records, DNSName("."), 300);
8410 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8411 records.clear();
8412
8413 ContentSigPair pair;
8414 pair.records = recordContents;
8415 pair.signatures = signatureContents;
8416 cspmap_t denialMap;
8417 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8418
8419 /* Insecure because the NS is not set, so while it does
8420 denies the DS, it can't prove an insecure delegation */
00e3fef4 8421 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8422 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8423}
8424
9b061cf5
RG
8425BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
8426 init();
8427
8428 testkeysset_t keys;
8429 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8430
8431 vector<DNSRecord> records;
8432
8433 vector<shared_ptr<DNSRecordContent>> recordContents;
8434 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8435
8436 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
8437 recordContents.push_back(records.at(0).d_content);
8438 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8439 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8440 records.clear();
8441
8442 ContentSigPair pair;
8443 pair.records = recordContents;
8444 pair.signatures = signatureContents;
8445 cspmap_t denialMap;
8446 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8447
8448 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8449 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
8450 BOOST_CHECK_EQUAL(denialState, NODATA);
8451}
8452
8453BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
8454 init();
8455
8456 testkeysset_t keys;
8457 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8458
8459 vector<DNSRecord> records;
8460
8461 vector<shared_ptr<DNSRecordContent>> recordContents;
8462 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8463
8464 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
8465 recordContents.push_back(records.at(0).d_content);
8466 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8467 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8468
8469 ContentSigPair pair;
8470 pair.records = recordContents;
8471 pair.signatures = signatureContents;
8472 cspmap_t denialMap;
8473 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8474 records.clear();
8475
8476 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8477 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8478 BOOST_CHECK_EQUAL(denialState, NODATA);
8479}
8480
8481BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8482 init();
8483
8484 testkeysset_t keys;
8485 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8486
8487 vector<DNSRecord> records;
8488
8489 vector<shared_ptr<DNSRecordContent>> recordContents;
8490 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8491
8492 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8493 recordContents.push_back(records.at(0).d_content);
8494 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8495 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8496 records.clear();
8497
8498 ContentSigPair pair;
8499 pair.records = recordContents;
8500 pair.signatures = signatureContents;
8501 cspmap_t denialMap;
8502 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8503
8504 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8505 BOOST_CHECK_EQUAL(denialState, NODATA);
8506}
8507
8508BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
8509 init();
8510
8511 testkeysset_t keys;
8512 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8513
8514 vector<DNSRecord> records;
8515
8516 vector<shared_ptr<DNSRecordContent>> recordContents;
8517 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8518
8519 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8520 recordContents.push_back(records.at(0).d_content);
8521 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8522 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8523
8524 ContentSigPair pair;
8525 pair.records = recordContents;
8526 pair.signatures = signatureContents;
8527 cspmap_t denialMap;
8528 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8529
8530 /* Add NSEC3 for the closest encloser */
8531 recordContents.clear();
8532 signatureContents.clear();
8533 records.clear();
8534 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8535 recordContents.push_back(records.at(0).d_content);
8536 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8537 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8538
8539 pair.records = recordContents;
8540 pair.signatures = signatureContents;
8541 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8542
8543 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8544 BOOST_CHECK_EQUAL(denialState, NODATA);
8545}
8546
00e3fef4
RG
8547BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8548 init();
8549
8550 testkeysset_t keys;
8551 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8552
8553 vector<DNSRecord> records;
8554
8555 vector<shared_ptr<DNSRecordContent>> recordContents;
8556 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8557
8558 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8559 recordContents.push_back(records.at(0).d_content);
8560 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8561 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8562 records.clear();
8563
8564 ContentSigPair pair;
8565 pair.records = recordContents;
8566 pair.signatures = signatureContents;
8567 cspmap_t denialMap;
8568 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8569
9b061cf5 8570 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
00e3fef4 8571 it is an ENT */
9b061cf5 8572 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
00e3fef4 8573 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
00be1ff6 8574
9b061cf5
RG
8575 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8576 it could prove a NXDOMAIN if it had an additional wildcard denial */
8577 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8578 BOOST_CHECK_EQUAL(denialState, NODATA);
8579
00be1ff6
RG
8580 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8581 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8582 BOOST_CHECK_EQUAL(denialState, NODATA);
9b061cf5
RG
8583
8584 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8585 recordContents.clear();
8586 signatureContents.clear();
8587 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8588 recordContents.push_back(records.at(0).d_content);
8589 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8590 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8591 records.clear();
8592 pair.records = recordContents;
8593 pair.signatures = signatureContents;
8594 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8595
82566a96 8596 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
9b061cf5 8597 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
00e3fef4
RG
8598}
8599
95823c07
RG
8600BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8601 init();
8602
8603 testkeysset_t keys;
8604 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8605
8606 vector<DNSRecord> records;
8607
8608 vector<shared_ptr<DNSRecordContent>> recordContents;
8609 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8610
8611 /*
8612 The RRSIG from "." denies the existence of any type except NS at a.
8613 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8614 signer field that is shorter than the owner name of the NSEC RR) it can't
8615 be used to deny anything except the whole name or a DS.
8616 */
9b061cf5 8617 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
95823c07
RG
8618 recordContents.push_back(records.at(0).d_content);
8619 addRRSIG(keys, records, DNSName("."), 300);
8620 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8621
8622 ContentSigPair pair;
8623 pair.records = recordContents;
8624 pair.signatures = signatureContents;
8625 cspmap_t denialMap;
8626 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8627 records.clear();
8628
8629 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8630 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8631 nonexistence of any RRs below that zone cut, which include all RRs at
8632 that (original) owner name other than DS RRs, and all RRs below that
8633 owner name regardless of type.
8634 */
8635
00e3fef4 8636 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
95823c07
RG
8637 /* no data means the qname/qtype is not denied, because an ancestor
8638 delegation NSEC3 can only deny the DS */
8639 BOOST_CHECK_EQUAL(denialState, NODATA);
8640
00e3fef4 8641 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
95823c07 8642 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
b93be4a0
RG
8643
8644 /* it can not be used to deny any RRs below that owner name either */
8645 /* Add NSEC3 for the next closer */
8646 recordContents.clear();
8647 signatureContents.clear();
8648 records.clear();
8649 addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8650 recordContents.push_back(records.at(0).d_content);
8651 addRRSIG(keys, records, DNSName("."), 300);
8652 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8653
8654 pair.records = recordContents;
8655 pair.signatures = signatureContents;
8656 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8657
8658 /* add wildcard denial */
8659 recordContents.clear();
8660 signatureContents.clear();
8661 records.clear();
8662 addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8663 recordContents.push_back(records.at(0).d_content);
8664 addRRSIG(keys, records, DNSName("."), 300);
8665 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8666
8667 pair.records = recordContents;
8668 pair.signatures = signatureContents;
8669 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8670
8671 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true);
8672 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8673}
8674
b7c40613
RG
8675BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8676 init();
8677
8678 testkeysset_t keys;
8679 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8680
8681 vector<DNSRecord> records;
8682
8683 vector<shared_ptr<DNSRecordContent>> recordContents;
8684 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8685
8686 /* adding a NSEC3 with more iterations that we support */
8687 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8688 recordContents.push_back(records.at(0).d_content);
8689 addRRSIG(keys, records, DNSName("."), 300);
8690 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8691
8692 ContentSigPair pair;
8693 pair.records = recordContents;
8694 pair.signatures = signatureContents;
8695 cspmap_t denialMap;
8696 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8697 records.clear();
8698
8699 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8700 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8701 BOOST_CHECK_EQUAL(denialState, INSECURE);
8702}
8703
95823c07
RG
8704BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8705 init();
8706
8707 testkeysset_t keys;
8708 generateKeyMaterial(DNSName("."), 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 /*
8716 * RFC 5155 section 8.9:
8717 * If there is an NSEC3 RR present in the response that matches the
8718 * delegation name, then the validator MUST ensure that the NS bit is
8719 * set and that the DS bit is not set in the Type Bit Maps field of the
8720 * NSEC3 RR.
8721 */
8722 /*
8723 The RRSIG from "." denies the existence of any type at a.
8724 NS should be set if it was proving an insecure delegation, let's check that
8725 we correctly detect that it's not.
8726 */
9b061cf5 8727 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
95823c07
RG
8728 recordContents.push_back(records.at(0).d_content);
8729 addRRSIG(keys, records, DNSName("."), 300);
8730 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8731
8732 ContentSigPair pair;
8733 pair.records = recordContents;
8734 pair.signatures = signatureContents;
8735 cspmap_t denialMap;
8736 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8737 records.clear();
8738
8739 /* Insecure because the NS is not set, so while it does
8740 denies the DS, it can't prove an insecure delegation */
00e3fef4 8741 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8742 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8743}
8744
dbbef467
RG
8745BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8746 std::unique_ptr<SyncRes> sr;
dbbef467
RG
8747 initSR(sr, true);
8748
8749 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8750
8751 primeHints();
8752 const DNSName target("com.");
8753 testkeysset_t keys;
8754
8755 auto luaconfsCopy = g_luaconfs.getCopy();
8756 luaconfsCopy.dsAnchors.clear();
8757 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8758 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8759 g_luaconfs.setState(luaconfsCopy);
8760
8761 size_t queriesCount = 0;
8762
8763 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
8764 queriesCount++;
8765
8766 DNSName auth = domain;
8767 auth.chopOff();
8768
8769 if (type == QType::DS || type == QType::DNSKEY) {
8770 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8771 }
8772 else {
8773 setLWResult(res, RCode::NoError, true, false, true);
8774 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8775 addRRSIG(keys, res->d_records, domain, 300);
8776 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8777 addRRSIG(keys, res->d_records, domain, 1);
8778 return 1;
8779 }
8780
8781 return 0;
8782 });
8783
934c35b9 8784 const time_t now = sr->getNow().tv_sec;
dbbef467
RG
8785 vector<DNSRecord> ret;
8786 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8787 BOOST_CHECK_EQUAL(res, RCode::NoError);
8788 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8789 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8790 BOOST_CHECK_EQUAL(queriesCount, 4);
8791
8792 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
8793 NegCache::NegCacheEntry ne;
8794 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8795 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8796 BOOST_CHECK_EQUAL(ne.d_ttd, now + 1);
b25712fd 8797 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
dbbef467
RG
8798 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8799 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8800 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8801 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
8802
8803 /* again, to test the cache */
8804 ret.clear();
8805 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8806 BOOST_CHECK_EQUAL(res, RCode::NoError);
8807 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8808 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8809 BOOST_CHECK_EQUAL(queriesCount, 4);
8810}
8811
8812BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
8813 std::unique_ptr<SyncRes> sr;
dbbef467
RG
8814 initSR(sr, true);
8815
8816 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8817
8818 primeHints();
8819 const DNSName target("com.");
8820 const ComboAddress targetAddr("192.0.2.42");
8821 testkeysset_t keys;
8822
8823 auto luaconfsCopy = g_luaconfs.getCopy();
8824 luaconfsCopy.dsAnchors.clear();
8825 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8826 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8827 g_luaconfs.setState(luaconfsCopy);
8828
8829 size_t queriesCount = 0;
8830
8831 sr->setAsyncCallback([target,targetAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
8832 queriesCount++;
8833
8834 DNSName auth = domain;
8835 auth.chopOff();
8836
8837 if (type == QType::DS || type == QType::DNSKEY) {
8838 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8839 }
8840 else {
8841 setLWResult(res, RCode::NoError, true, false, true);
8842 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8843 addRRSIG(keys, res->d_records, domain, 1);
8844 return 1;
8845 }
8846
8847 return 0;
8848 });
8849
934c35b9 8850 const time_t now = sr->getNow().tv_sec;
dbbef467
RG
8851 vector<DNSRecord> ret;
8852 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8853 BOOST_CHECK_EQUAL(res, RCode::NoError);
8854 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8855 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8856 BOOST_CHECK_EQUAL(queriesCount, 4);
8857
8858 /* check that the entry has not been cached for longer than the RRSIG validity */
8859 const ComboAddress who;
8860 vector<DNSRecord> cached;
8861 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
8862 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
8863 BOOST_REQUIRE_EQUAL(cached.size(), 1);
8864 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
8865 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
8866
8867 /* again, to test the cache */
8868 ret.clear();
8869 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8870 BOOST_CHECK_EQUAL(res, RCode::NoError);
8871 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8872 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8873 BOOST_CHECK_EQUAL(queriesCount, 4);
8874}
8875
f4de85a3
RG
8876BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
8877 /*
8878 Validation is optional, and the first query does not ask for it,
8879 so the answer is cached as Indeterminate.
8880 The second query asks for validation, answer should be marked as
8881 Secure.
8882 */
8883 std::unique_ptr<SyncRes> sr;
8884 initSR(sr, true);
8885
8886 setDNSSECValidation(sr, DNSSECMode::Process);
8887
8888 primeHints();
8889 const DNSName target("com.");
8890 testkeysset_t keys;
8891
8892 auto luaconfsCopy = g_luaconfs.getCopy();
8893 luaconfsCopy.dsAnchors.clear();
8894 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8895 g_luaconfs.setState(luaconfsCopy);
8896
8897 size_t queriesCount = 0;
8898
8899 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
8900 queriesCount++;
8901
8902 if (type == QType::DS || type == QType::DNSKEY) {
8903 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8904 }
8905 else {
8906 if (domain == target && type == QType::A) {
8907 setLWResult(res, 0, true, false, true);
8908 addRecordToLW(res, target, QType::A, "192.0.2.1");
8909 addRRSIG(keys, res->d_records, DNSName("."), 300);
8910 return 1;
8911 }
8912 }
8913
8914 return 0;
8915 });
8916
8917 vector<DNSRecord> ret;
8918 /* first query does not require validation */
8919 sr->setDNSSECValidationRequested(false);
8920 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8921 BOOST_CHECK_EQUAL(res, RCode::NoError);
8922 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8923 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8924 for (const auto& record : ret) {
8925 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8926 }
8927 BOOST_CHECK_EQUAL(queriesCount, 1);
8928
8929
8930 ret.clear();
8931 /* second one _does_ require validation */
8932 sr->setDNSSECValidationRequested(true);
8933 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8934 BOOST_CHECK_EQUAL(res, RCode::NoError);
8935 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8936 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8937 for (const auto& record : ret) {
8938 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8939 }
8940 BOOST_CHECK_EQUAL(queriesCount, 3);
8941}
8942
8943BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
8944 /*
8945 Validation is optional, and the first query does not ask for it,
8946 so the answer is cached as Indeterminate.
8947 The second query asks for validation, answer should be marked as
8948 Insecure.
8949 */
8950 std::unique_ptr<SyncRes> sr;
8951 initSR(sr, true);
8952
8953 setDNSSECValidation(sr, DNSSECMode::Process);
8954
8955 primeHints();
8956 const DNSName target("com.");
8957 testkeysset_t keys;
8958
8959 auto luaconfsCopy = g_luaconfs.getCopy();
8960 luaconfsCopy.dsAnchors.clear();
8961 g_luaconfs.setState(luaconfsCopy);
8962
8963 size_t queriesCount = 0;
8964
8965 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
8966 queriesCount++;
8967
8968 if (type == QType::DS || type == QType::DNSKEY) {
8969 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8970 }
8971 else {
8972 if (domain == target && type == QType::A) {
8973 setLWResult(res, 0, true, false, true);
8974 addRecordToLW(res, target, QType::A, "192.0.2.1");
8975 return 1;
8976 }
8977 }
8978
8979 return 0;
8980 });
8981
8982 vector<DNSRecord> ret;
8983 /* first query does not require validation */
8984 sr->setDNSSECValidationRequested(false);
8985 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8986 BOOST_CHECK_EQUAL(res, RCode::NoError);
8987 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8988 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8989 for (const auto& record : ret) {
55acb073 8990 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
8991 }
8992 BOOST_CHECK_EQUAL(queriesCount, 1);
8993
8994
8995 ret.clear();
8996 /* second one _does_ require validation */
8997 sr->setDNSSECValidationRequested(true);
8998 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8999 BOOST_CHECK_EQUAL(res, RCode::NoError);
9000 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9001 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9002 for (const auto& record : ret) {
55acb073 9003 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9004 }
9005 BOOST_CHECK_EQUAL(queriesCount, 1);
9006}
9007
9008BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
9009 /*
9010 Validation is optional, and the first query does not ask for it,
9011 so the answer is cached as Indeterminate.
9012 The second query asks for validation, answer should be marked as
9013 Bogus.
9014 */
9015 std::unique_ptr<SyncRes> sr;
9016 initSR(sr, true);
9017
9018 setDNSSECValidation(sr, DNSSECMode::Process);
9019
9020 primeHints();
9021 const DNSName target("com.");
9022 testkeysset_t keys;
9023
9024 auto luaconfsCopy = g_luaconfs.getCopy();
9025 luaconfsCopy.dsAnchors.clear();
9026 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9027 g_luaconfs.setState(luaconfsCopy);
9028
9029 size_t queriesCount = 0;
9030
9031 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9032 queriesCount++;
9033
9034 if (type == QType::DS || type == QType::DNSKEY) {
9035 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9036 }
9037 else {
9038 if (domain == target && type == QType::A) {
9039 setLWResult(res, 0, true, false, true);
9040 addRecordToLW(res, target, QType::A, "192.0.2.1");
9041 /* no RRSIG */
9042 return 1;
9043 }
9044 }
9045
9046 return 0;
9047 });
9048
9049 vector<DNSRecord> ret;
9050 /* first query does not require validation */
9051 sr->setDNSSECValidationRequested(false);
9052 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9053 BOOST_CHECK_EQUAL(res, RCode::NoError);
9054 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9055 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9056 for (const auto& record : ret) {
55acb073 9057 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9058 }
9059 BOOST_CHECK_EQUAL(queriesCount, 1);
9060
9061
9062 ret.clear();
9063 /* second one _does_ require validation */
9064 sr->setDNSSECValidationRequested(true);
9065 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9066 BOOST_CHECK_EQUAL(res, RCode::NoError);
9067 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9068 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9069 for (const auto& record : ret) {
55acb073 9070 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9071 }
9072 BOOST_CHECK_EQUAL(queriesCount, 3);
9073}
9074
55acb073
RG
9075BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
9076 /*
9077 Validation is optional, and the first query does not ask for it,
9078 so the answer is cached as Indeterminate.
9079 The second query asks for validation, answer should be marked as
9080 Secure.
9081 */
9082 std::unique_ptr<SyncRes> sr;
9083 initSR(sr, true);
9084
9085 setDNSSECValidation(sr, DNSSECMode::Process);
9086
9087 primeHints();
9088 const DNSName target("com.");
9089 const DNSName cnameTarget("cname-com.");
9090 testkeysset_t keys;
9091
9092 auto luaconfsCopy = g_luaconfs.getCopy();
9093 luaconfsCopy.dsAnchors.clear();
9094 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9095 g_luaconfs.setState(luaconfsCopy);
9096
9097 size_t queriesCount = 0;
9098
9099 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9100 queriesCount++;
9101
9102 if (type == QType::DS || type == QType::DNSKEY) {
9103 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9104 }
9105 else {
9106 if (domain == target && type == QType::A) {
9107 setLWResult(res, 0, true, false, true);
9108 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9109 addRRSIG(keys, res->d_records, DNSName("."), 300);
9110 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9111 addRRSIG(keys, res->d_records, DNSName("."), 300);
9112 return 1;
9113 } else if (domain == cnameTarget && type == QType::A) {
9114 setLWResult(res, 0, true, false, true);
9115 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9116 addRRSIG(keys, res->d_records, DNSName("."), 300);
9117 return 1;
9118 }
9119 }
9120
9121 return 0;
9122 });
9123
9124 vector<DNSRecord> ret;
9125 /* first query does not require validation */
9126 sr->setDNSSECValidationRequested(false);
9127 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9128 BOOST_CHECK_EQUAL(res, RCode::NoError);
9129 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9130 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9131 for (const auto& record : ret) {
9132 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9133 }
9134 BOOST_CHECK_EQUAL(queriesCount, 2);
9135
9136
9137 ret.clear();
9138 /* second one _does_ require validation */
9139 sr->setDNSSECValidationRequested(true);
9140 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9141 BOOST_CHECK_EQUAL(res, RCode::NoError);
9142 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9143 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9144 for (const auto& record : ret) {
9145 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9146 }
9147 BOOST_CHECK_EQUAL(queriesCount, 5);
9148}
9149
9150BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
9151 /*
9152 Validation is optional, and the first query does not ask for it,
9153 so the answer is cached as Indeterminate.
9154 The second query asks for validation, answer should be marked as
9155 Insecure.
9156 */
9157 std::unique_ptr<SyncRes> sr;
9158 initSR(sr, true);
9159
9160 setDNSSECValidation(sr, DNSSECMode::Process);
9161
9162 primeHints();
9163 const DNSName target("com.");
9164 const DNSName cnameTarget("cname-com.");
9165 testkeysset_t keys;
9166
9167 auto luaconfsCopy = g_luaconfs.getCopy();
9168 luaconfsCopy.dsAnchors.clear();
9169 g_luaconfs.setState(luaconfsCopy);
9170
9171 size_t queriesCount = 0;
9172
9173 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9174 queriesCount++;
9175
9176 if (type == QType::DS || type == QType::DNSKEY) {
9177 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9178 }
9179 else {
9180 if (domain == target && type == QType::A) {
9181 setLWResult(res, 0, true, false, true);
9182 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9183 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9184 return 1;
9185 } else if (domain == cnameTarget && type == QType::A) {
9186 setLWResult(res, 0, true, false, true);
9187 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9188 return 1;
9189 }
9190 }
9191
9192 return 0;
9193 });
9194
9195 vector<DNSRecord> ret;
9196 /* first query does not require validation */
9197 sr->setDNSSECValidationRequested(false);
9198 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9199 BOOST_CHECK_EQUAL(res, RCode::NoError);
9200 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9201 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9202 for (const auto& record : ret) {
9203 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9204 }
9205 BOOST_CHECK_EQUAL(queriesCount, 2);
9206
9207
9208 ret.clear();
9209 /* second one _does_ require validation */
9210 sr->setDNSSECValidationRequested(true);
9211 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9212 BOOST_CHECK_EQUAL(res, RCode::NoError);
9213 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9214 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9215 for (const auto& record : ret) {
9216 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9217 }
9218 BOOST_CHECK_EQUAL(queriesCount, 2);
9219}
9220
9221BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
9222 /*
9223 Validation is optional, and the first query does not ask for it,
9224 so the answer is cached as Indeterminate.
9225 The second query asks for validation, answer should be marked as
9226 Bogus.
9227 */
9228 std::unique_ptr<SyncRes> sr;
9229 initSR(sr, true);
9230
9231 setDNSSECValidation(sr, DNSSECMode::Process);
9232
9233 primeHints();
9234 const DNSName target("com.");
9235 const DNSName cnameTarget("cname-com.");
9236 testkeysset_t keys;
9237
9238 auto luaconfsCopy = g_luaconfs.getCopy();
9239 luaconfsCopy.dsAnchors.clear();
9240 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9241 g_luaconfs.setState(luaconfsCopy);
9242
9243 size_t queriesCount = 0;
9244
9245 sr->setAsyncCallback([target,cnameTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9246 queriesCount++;
9247
9248 if (type == QType::DS || type == QType::DNSKEY) {
9249 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9250 }
9251 else {
9252 if (domain == target && type == QType::A) {
9253 setLWResult(res, 0, true, false, true);
9254 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9255 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9256 /* no RRSIG */
9257 return 1;
9258 } else if (domain == cnameTarget && type == QType::A) {
9259 setLWResult(res, 0, true, false, true);
9260 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9261 /* no RRSIG */
9262 return 1;
9263 }
9264 }
9265
9266 return 0;
9267 });
9268
9269 vector<DNSRecord> ret;
9270 /* first query does not require validation */
9271 sr->setDNSSECValidationRequested(false);
9272 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9273 BOOST_CHECK_EQUAL(res, RCode::NoError);
9274 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9275 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9276 for (const auto& record : ret) {
9277 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9278 }
9279 BOOST_CHECK_EQUAL(queriesCount, 2);
9280
9281
9282 ret.clear();
9283 /* second one _does_ require validation */
9284 sr->setDNSSECValidationRequested(true);
9285 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9286 BOOST_CHECK_EQUAL(res, RCode::NoError);
9287 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9288 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9289 for (const auto& record : ret) {
9290 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9291 }
9292 BOOST_CHECK_EQUAL(queriesCount, 5);
9293}
9294
405a26bd
RG
9295BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) {
9296 /*
9297 We get a record from a secure zone in the additional section, without
9298 the corresponding RRSIG. The record should not be marked as authoritative
9299 and should be correctly validated.
9300 */
9301 std::unique_ptr<SyncRes> sr;
9302 initSR(sr, true);
9303
9304 setDNSSECValidation(sr, DNSSECMode::Process);
9305
9306 primeHints();
9307 const DNSName target("com.");
9308 const DNSName addTarget("nsX.com.");
9309 testkeysset_t keys;
9310
9311 auto luaconfsCopy = g_luaconfs.getCopy();
9312 luaconfsCopy.dsAnchors.clear();
9313 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9314 g_luaconfs.setState(luaconfsCopy);
9315
9316 size_t queriesCount = 0;
9317
9318 sr->setAsyncCallback([target,addTarget,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9319 queriesCount++;
9320
9321 if (type == QType::DS || type == QType::DNSKEY) {
9322 if (domain == addTarget) {
9323 DNSName auth(domain);
9324 /* no DS for com, auth will be . */
9325 auth.chopOff();
9326 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false);
9327 }
9328 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9329 }
9330 else {
9331 if (domain == target && type == QType::A) {
9332 setLWResult(res, 0, true, false, true);
9333 addRecordToLW(res, target, QType::A, "192.0.2.1");
9334 addRRSIG(keys, res->d_records, DNSName("."), 300);
9335 addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL);
9336 /* no RRSIG for the additional record */
9337 return 1;
9338 } else if (domain == addTarget && type == QType::A) {
9339 setLWResult(res, 0, true, false, true);
9340 addRecordToLW(res, addTarget, QType::A, "192.0.2.42");
9341 addRRSIG(keys, res->d_records, DNSName("."), 300);
9342 return 1;
9343 }
9344 }
9345
9346 return 0;
9347 });
9348
9349 vector<DNSRecord> ret;
9350 /* first query for target/A, will pick up the additional record as non-auth / unvalidated */
9351 sr->setDNSSECValidationRequested(false);
9352 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9353 BOOST_CHECK_EQUAL(res, RCode::NoError);
9354 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9355 BOOST_CHECK_EQUAL(ret.size(), 2);
9356 for (const auto& record : ret) {
9357 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9358 }
9359 BOOST_CHECK_EQUAL(queriesCount, 1);
9360
9361 ret.clear();
9362 /* ask for the additional record directly, we should not use
9363 the non-auth one and issue a new query, properly validated */
9364 sr->setDNSSECValidationRequested(true);
9365 res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret);
9366 BOOST_CHECK_EQUAL(res, RCode::NoError);
9367 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9368 BOOST_CHECK_EQUAL(ret.size(), 2);
9369 for (const auto& record : ret) {
9370 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9371 }
9372 BOOST_CHECK_EQUAL(queriesCount, 5);
9373}
9374
f4de85a3
RG
9375BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
9376 /*
9377 Validation is optional, and the first query does not ask for it,
9378 so the answer is negatively cached as Indeterminate.
9379 The second query asks for validation, answer should be marked as
9380 Secure.
9381 */
9382 std::unique_ptr<SyncRes> sr;
9383 initSR(sr, true);
9384
9385 setDNSSECValidation(sr, DNSSECMode::Process);
9386
9387 primeHints();
9388 const DNSName target("com.");
9389 testkeysset_t keys;
9390
9391 auto luaconfsCopy = g_luaconfs.getCopy();
9392 luaconfsCopy.dsAnchors.clear();
9393 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9394 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9395 g_luaconfs.setState(luaconfsCopy);
9396
9397 size_t queriesCount = 0;
9398
9399 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9400 queriesCount++;
9401
9402 DNSName auth = domain;
9403 auth.chopOff();
9404
9405 if (type == QType::DS || type == QType::DNSKEY) {
9406 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9407 }
9408 else {
9409 setLWResult(res, RCode::NoError, true, false, true);
9410 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9411 addRRSIG(keys, res->d_records, domain, 300);
9412 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
9413 addRRSIG(keys, res->d_records, domain, 1);
9414 return 1;
9415 }
9416
9417 return 0;
9418 });
9419
9420 vector<DNSRecord> ret;
9421 /* first query does not require validation */
9422 sr->setDNSSECValidationRequested(false);
9423 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9424 BOOST_CHECK_EQUAL(res, RCode::NoError);
9425 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9426 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9427 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9428 /* check that the entry has not been negatively cached */
9429 NegCache::NegCacheEntry ne;
9430 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9431 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9432 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9433 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9434 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9435 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9436 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9437
9438 ret.clear();
9439 /* second one _does_ require validation */
9440 sr->setDNSSECValidationRequested(true);
9441 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9442 BOOST_CHECK_EQUAL(res, RCode::NoError);
9443 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9444 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9445 BOOST_CHECK_EQUAL(queriesCount, 4);
b25712fd
RG
9446 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9447 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9448 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
9449 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9450 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9451 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9452 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9453}
9454
f5a747bb
RG
9455BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
9456 /*
9457 Validation is optional, and the first query does not ask for it,
9458 so the answer is negatively cached as Indeterminate.
9459 The second query asks for validation, answer should be marked as
9460 Secure.
9461 The difference with test_dnssec_validation_from_negcache_secure is
9462 that have one more level here, so we are going to look for the proof
9463 that the DS does not exist for the last level. Since there is no cut,
9464 we should accept the fact that the NSEC denies DS and NS both.
9465 */
9466 std::unique_ptr<SyncRes> sr;
9467 initSR(sr, true);
9468
9469 setDNSSECValidation(sr, DNSSECMode::Process);
9470
9471 primeHints();
9472 const DNSName target("www.com.");
9473 testkeysset_t keys;
9474
9475 auto luaconfsCopy = g_luaconfs.getCopy();
9476 luaconfsCopy.dsAnchors.clear();
9477 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9478 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9479 g_luaconfs.setState(luaconfsCopy);
9480
9481 size_t queriesCount = 0;
9482
9483 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9484 queriesCount++;
9485
9486 if (type == QType::DS || type == QType::DNSKEY) {
9487 if (domain == target) {
9488 /* there is no cut */
9489 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9490 }
9491 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
9492 }
9493
9494 return 0;
9495 });
9496
9497 vector<DNSRecord> ret;
9498 /* first query does not require validation */
9499 sr->setDNSSECValidationRequested(false);
9500 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9501 BOOST_CHECK_EQUAL(res, RCode::NoError);
9502 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9503 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9504 BOOST_CHECK_EQUAL(queriesCount, 1);
9505
9506 ret.clear();
9507 /* second one _does_ require validation */
9508 sr->setDNSSECValidationRequested(true);
9509 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9510 BOOST_CHECK_EQUAL(res, RCode::NoError);
9511 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9512 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9513 BOOST_CHECK_EQUAL(queriesCount, 4);
9514}
9515
f4de85a3
RG
9516BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
9517 /*
9518 Validation is optional, and the first query does not ask for it,
9519 so the answer is negatively cached as Indeterminate.
9520 The second query asks for validation, answer should be marked as
9521 Insecure.
9522 */
9523 std::unique_ptr<SyncRes> sr;
9524 initSR(sr, true);
9525
9526 setDNSSECValidation(sr, DNSSECMode::Process);
9527
9528 primeHints();
9529 const DNSName target("com.");
9530 testkeysset_t keys;
9531
9532 auto luaconfsCopy = g_luaconfs.getCopy();
9533 luaconfsCopy.dsAnchors.clear();
9534 g_luaconfs.setState(luaconfsCopy);
9535
9536 size_t queriesCount = 0;
9537
9538 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9539 queriesCount++;
9540
9541 DNSName auth = domain;
9542 auth.chopOff();
9543
9544 if (type == QType::DS || type == QType::DNSKEY) {
9545 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9546 }
9547 else {
9548 setLWResult(res, RCode::NoError, true, false, true);
9549 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9550 return 1;
9551 }
9552
9553 return 0;
9554 });
9555
9556 vector<DNSRecord> ret;
9557 /* first query does not require validation */
9558 sr->setDNSSECValidationRequested(false);
9559 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9560 BOOST_CHECK_EQUAL(res, RCode::NoError);
9561 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9562 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9563 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9564 /* check that the entry has not been negatively cached */
9565 NegCache::NegCacheEntry ne;
9566 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9567 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9568 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9569 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9570 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9571 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9572 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9573
9574 ret.clear();
9575 /* second one _does_ require validation */
9576 sr->setDNSSECValidationRequested(true);
9577 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9578 BOOST_CHECK_EQUAL(res, RCode::NoError);
9579 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9580 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9581 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9582 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9583 BOOST_CHECK_EQUAL(ne.d_validationState, Insecure);
9584 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9585 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9586 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9587 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9588}
9589
9590BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
9591 /*
9592 Validation is optional, and the first query does not ask for it,
9593 so the answer is negatively cached as Indeterminate.
9594 The second query asks for validation, answer should be marked as
9595 Bogus.
9596 */
9597 std::unique_ptr<SyncRes> sr;
9598 initSR(sr, true);
9599
9600 setDNSSECValidation(sr, DNSSECMode::Process);
9601
9602 primeHints();
9603 const DNSName target("com.");
9604 testkeysset_t keys;
9605
9606 auto luaconfsCopy = g_luaconfs.getCopy();
9607 luaconfsCopy.dsAnchors.clear();
9608 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9609 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9610 g_luaconfs.setState(luaconfsCopy);
9611
9612 size_t queriesCount = 0;
9613
9614 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9615 queriesCount++;
9616
9617 DNSName auth = domain;
9618 auth.chopOff();
9619
9620 if (type == QType::DS || type == QType::DNSKEY) {
9621 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9622 }
9623 else {
9624 setLWResult(res, RCode::NoError, true, false, true);
9625 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9626 addRRSIG(keys, res->d_records, domain, 300);
9627 /* no denial */
9628 return 1;
9629 }
9630
9631 return 0;
9632 });
9633
9634 vector<DNSRecord> ret;
9635 /* first query does not require validation */
9636 sr->setDNSSECValidationRequested(false);
9637 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9638 BOOST_CHECK_EQUAL(res, RCode::NoError);
9639 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9640 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9641 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9642 NegCache::NegCacheEntry ne;
9643 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9644 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9645 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9646 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9647 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9648 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9649 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9650
9651 ret.clear();
9652 /* second one _does_ require validation */
9653 sr->setDNSSECValidationRequested(true);
9654 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9655 BOOST_CHECK_EQUAL(res, RCode::NoError);
9656 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9657 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9658 BOOST_CHECK_EQUAL(queriesCount, 4);
b25712fd
RG
9659 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9660 BOOST_CHECK_EQUAL(ne.d_validationState, Bogus);
9661 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9662 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9663 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9664 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9665}
9666
429ce1da
PL
9667BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
9668 g_lowercaseOutgoing = true;
9669 std::unique_ptr<SyncRes> sr;
9670 initSR(sr);
9671
9672 primeHints();
9673
9674 vector<DNSName> sentOutQnames;
9675
9676 const DNSName target("WWW.POWERDNS.COM");
9677 const DNSName cname("WWW.PowerDNS.org");
9678
9679 sr->setAsyncCallback([target, cname, &sentOutQnames](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9680
9681 sentOutQnames.push_back(domain);
9682
9683 if (isRootServer(ip)) {
9684 if (domain == target) {
9685 setLWResult(res, 0, false, false, true);
9686 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
9687 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
9688 return 1;
9689 }
9690 if (domain == cname) {
9691 setLWResult(res, 0, false, false, true);
9692 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
9693 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
9694 return 1;
9695 }
9696 } else if (ip == ComboAddress("192.0.2.1:53")) {
9697 if (domain == target) {
9698 setLWResult(res, 0, true, false, false);
9699 addRecordToLW(res, domain, QType::CNAME, cname.toString());
9700 return 1;
9701 }
9702 } else if (ip == ComboAddress("192.0.2.2:53")) {
9703 if (domain == cname) {
9704 setLWResult(res, 0, true, false, false);
9705 addRecordToLW(res, domain, QType::A, "127.0.0.1");
9706 return 1;
9707 }
9708 }
9709 return 0;
9710 });
9711
9712 vector<DNSRecord> ret;
9713 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9714
9715 BOOST_CHECK_EQUAL(res, RCode::NoError);
9716
9717 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9718 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
9719
9720 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
9721 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
9722 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
9723 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
9724 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
9725
9726 g_lowercaseOutgoing = false;
9727}
9728
4d787d30
PL
9729BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
9730 std::unique_ptr<SyncRes> sr;
9731 initSR(sr, true);
9732
9733 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9734
9735 primeHints();
9736 const DNSName target("com.");
9737 testkeysset_t keys, keys2;
9738
9739 auto luaconfsCopy = g_luaconfs.getCopy();
9740 luaconfsCopy.dsAnchors.clear();
9741 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9742 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9743 g_luaconfs.setState(luaconfsCopy);
9744
9745 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9746 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9747 // But add the existing root key otherwise no RRSIG can be created
9748 auto rootkey = keys.find(g_rootdnsname);
9749 keys2.insert(*rootkey);
9750
9751 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9752 DNSName auth = domain;
9753 auth.chopOff();
9754 if (type == QType::DS || type == QType::DNSKEY) {
9755 if (domain == target) {
9756 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9757 return 0;
9758 }
9759 }
9760 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9761 }
9762 return 0;
9763 });
9764
9765 dsmap_t ds;
9766 auto state = sr->getDSRecords(target, ds, false, 0, false);
9767 BOOST_CHECK_EQUAL(state, Secure);
9768 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9769 for (const auto& i : ds) {
9770 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9771 }
9772}
9773
9774BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
9775 std::unique_ptr<SyncRes> sr;
9776 initSR(sr, true);
9777
9778 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9779
9780 primeHints();
9781 const DNSName target("com.");
9782 testkeysset_t keys, keys2, keys3;
9783
9784 auto luaconfsCopy = g_luaconfs.getCopy();
9785 luaconfsCopy.dsAnchors.clear();
9786 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9787 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9788 g_luaconfs.setState(luaconfsCopy);
9789
9790 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9791 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9792 // But add the existing root key otherwise no RRSIG can be created
9793 auto rootkey = keys.find(g_rootdnsname);
9794 keys2.insert(*rootkey);
9795
9796 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
9797 // But add the existing root key otherwise no RRSIG can be created
9798 keys3.insert(*rootkey);
9799
9800 sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9801 DNSName auth = domain;
9802 auth.chopOff();
9803 if (type == QType::DS || type == QType::DNSKEY) {
9804 if (domain == target) {
9805 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9806 return 0;
9807 }
9808 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9809 return 0;
9810 }
9811 }
9812 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9813 }
9814 return 0;
9815 });
9816
9817 dsmap_t ds;
9818 auto state = sr->getDSRecords(target, ds, false, 0, false);
9819 BOOST_CHECK_EQUAL(state, Secure);
9820 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9821 for (const auto& i : ds) {
9822 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9823 }
9824}
9825
9826BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
9827 std::unique_ptr<SyncRes> sr;
9828 initSR(sr, true);
9829
9830 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9831
9832 primeHints();
9833 const DNSName target("com.");
9834 testkeysset_t keys, keys2, keys3;
9835
9836 auto luaconfsCopy = g_luaconfs.getCopy();
9837 luaconfsCopy.dsAnchors.clear();
9838 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9839 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9840 g_luaconfs.setState(luaconfsCopy);
9841
9842 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9843 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
9844 // But add the existing root key otherwise no RRSIG can be created
9845 auto rootkey = keys.find(g_rootdnsname);
9846 keys2.insert(*rootkey);
9847
9848 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
9849 // But add the existing root key otherwise no RRSIG can be created
9850 keys3.insert(*rootkey);
9851
9852 sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9853 DNSName auth = domain;
9854 auth.chopOff();
9855 if (type == QType::DS || type == QType::DNSKEY) {
9856 if (domain == target) {
9857 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9858 return 0;
9859 }
9860 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9861 return 0;
9862 }
9863 }
9864 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9865 }
9866 return 0;
9867 });
9868
9869 dsmap_t ds;
9870 auto state = sr->getDSRecords(target, ds, false, 0, false);
9871 BOOST_CHECK_EQUAL(state, Secure);
9872 BOOST_REQUIRE_EQUAL(ds.size(), 2);
9873 for (const auto& i : ds) {
9874 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9875 }
9876}
9877
77cb3d33 9878#ifdef HAVE_BOTAN
4d787d30
PL
9879BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) {
9880 std::unique_ptr<SyncRes> sr;
9881 initSR(sr, true);
9882
9883 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9884
9885 primeHints();
9886 const DNSName target("com.");
9887 testkeysset_t keys, keys2;
9888
9889 auto luaconfsCopy = g_luaconfs.getCopy();
9890 luaconfsCopy.dsAnchors.clear();
9891 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9892 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys);
9893 g_luaconfs.setState(luaconfsCopy);
9894
9895 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9896 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9897 // But add the existing root key otherwise no RRSIG can be created
9898 auto rootkey = keys.find(g_rootdnsname);
9899 keys2.insert(*rootkey);
9900
9901 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9902 DNSName auth = domain;
9903 auth.chopOff();
9904 if (type == QType::DS || type == QType::DNSKEY) {
9905 if (domain == target) {
9906 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9907 return 0;
9908 }
9909 }
9910 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9911 }
9912 return 0;
9913 });
9914
9915 dsmap_t ds;
9916 auto state = sr->getDSRecords(target, ds, false, 0, false);
9917 BOOST_CHECK_EQUAL(state, Secure);
9918 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9919 for (const auto& i : ds) {
9920 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9921 }
9922}
9923
9924BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) {
9925 std::unique_ptr<SyncRes> sr;
9926 initSR(sr, true);
9927
9928 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9929
9930 primeHints();
9931 const DNSName target("com.");
9932 testkeysset_t keys, keys2;
9933
9934 auto luaconfsCopy = g_luaconfs.getCopy();
9935 luaconfsCopy.dsAnchors.clear();
9936 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9937 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9938 g_luaconfs.setState(luaconfsCopy);
9939
9940 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9941 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9942 // But add the existing root key otherwise no RRSIG can be created
9943 auto rootkey = keys.find(g_rootdnsname);
9944 keys2.insert(*rootkey);
9945
9946 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9947 DNSName auth = domain;
9948 auth.chopOff();
9949 if (type == QType::DS || type == QType::DNSKEY) {
9950 if (domain == target) {
9951 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9952 return 0;
9953 }
9954 }
9955 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9956 }
9957 return 0;
9958 });
9959
9960 dsmap_t ds;
9961 auto state = sr->getDSRecords(target, ds, false, 0, false);
9962 BOOST_CHECK_EQUAL(state, Secure);
9963 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9964 for (const auto& i : ds) {
9965 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9966 }
9967}
9968
9969BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) {
9970 std::unique_ptr<SyncRes> sr;
9971 initSR(sr, true);
9972
9973 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9974
9975 primeHints();
9976 const DNSName target("com.");
9977 testkeysset_t keys, keys2;
9978
9979 auto luaconfsCopy = g_luaconfs.getCopy();
9980 luaconfsCopy.dsAnchors.clear();
9981 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9982 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys);
9983 g_luaconfs.setState(luaconfsCopy);
9984
9985 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9986 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9987 // But add the existing root key otherwise no RRSIG can be created
9988 auto rootkey = keys.find(g_rootdnsname);
9989 keys2.insert(*rootkey);
9990
9991 sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
9992 DNSName auth = domain;
9993 auth.chopOff();
9994 if (type == QType::DS || type == QType::DNSKEY) {
9995 if (domain == target) {
9996 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9997 return 0;
9998 }
9999 }
10000 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10001 }
10002 return 0;
10003 });
10004
10005 dsmap_t ds;
10006 auto state = sr->getDSRecords(target, ds, false, 0, false);
10007 BOOST_CHECK_EQUAL(state, Secure);
10008 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10009 for (const auto& i : ds) {
10010 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST);
10011 }
10012}
10013#endif // HAVE_BOTAN110
10014
d6e797b8
RG
10015/*
10016// cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
10017
648bcbd1 10018- check out of band support
d6e797b8 10019
648bcbd1 10020- check preoutquery
d6e797b8 10021
30ee601a
RG
10022*/
10023
10024BOOST_AUTO_TEST_SUITE_END()