]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/test-syncres_cc.cc
Merge pull request #5916 from pieterlexis/rm-wiki
[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
37bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret)
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) {
69 static char templ[40];
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 */
1927 time_t now = time(nullptr);
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 */
1989 time_t now = time(nullptr);
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
2010ac95 2054 const time_t now = time(nullptr);
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*/
2105 time_t now = time(nullptr);
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
f79a4e30
RG
2827BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_oob) {
2828 std::unique_ptr<SyncRes> sr;
2829 init();
2830 initSR(sr, true, false);
2831
2832 primeHints();
2833
2834 size_t queriesCount = 0;
2835 const DNSName target("test.xx.");
2836 const ComboAddress targetAddr("127.0.0.1");
2837 const DNSName ns("localhost.");
2838 const ComboAddress nsAddr("127.0.0.1");
2839 const DNSName authZone("test.xx");
2840
2841 SyncRes::AuthDomain ad;
2842 DNSRecord dr;
2843 dr.d_place = DNSResourceRecord::ANSWER;
2844 dr.d_name = authZone;
2845 dr.d_type = QType::NS;
2846 dr.d_ttl = 1800;
2847 dr.d_content = std::make_shared<NSRecordContent>("localhost.");
2848 ad.d_records.insert(dr);
2849
2850 dr.d_place = DNSResourceRecord::ANSWER;
2851 dr.d_name = authZone;
2852 dr.d_type = QType::A;
2853 dr.d_ttl = 1800;
2854 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
2855 ad.d_records.insert(dr);
2856
a712cb56 2857 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
f79a4e30
RG
2858
2859 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) {
2860 queriesCount++;
2861 return 0;
2862 });
2863
2864 vector<DNSRecord> ret;
2865 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2866 BOOST_CHECK_EQUAL(res, 0);
2867 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2868 BOOST_CHECK(ret[0].d_type == QType::A);
2869 BOOST_CHECK_EQUAL(queriesCount, 0);
2870 BOOST_CHECK(sr->wasOutOfBand());
2871
2872 /* a second time, to check that the OOB flag is set when the query cache is used */
2873 ret.clear();
2874 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2875 BOOST_CHECK_EQUAL(res, 0);
2876 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2877 BOOST_CHECK(ret[0].d_type == QType::A);
2878 BOOST_CHECK_EQUAL(queriesCount, 0);
2879 BOOST_CHECK(sr->wasOutOfBand());
2880}
2881
3337c2f7
RG
2882BOOST_AUTO_TEST_CASE(test_auth_zone) {
2883 std::unique_ptr<SyncRes> sr;
895449a5 2884 initSR(sr);
3337c2f7
RG
2885
2886 primeHints();
2887
2888 size_t queriesCount = 0;
2889 const DNSName target("powerdns.com.");
2890 const ComboAddress addr("192.0.2.5");
2891
2892 SyncRes::AuthDomain ad;
2893 ad.d_name = target;
2894 DNSRecord dr;
2895 dr.d_place = DNSResourceRecord::ANSWER;
2896 dr.d_name = target;
2897 dr.d_type = QType::SOA;
2898 dr.d_ttl = 3600;
2899 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2900 ad.d_records.insert(dr);
2901
2902 dr.d_place = DNSResourceRecord::ANSWER;
2903 dr.d_name = target;
2904 dr.d_type = QType::A;
2905 dr.d_ttl = 3600;
2906 dr.d_content = std::make_shared<ARecordContent>(addr);
2907 ad.d_records.insert(dr);
2908
2909 auto map = std::make_shared<SyncRes::domainmap_t>();
2910 (*map)[target] = ad;
2911 SyncRes::setDomainMap(map);
2912
2913 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) {
2914
2915 queriesCount++;
2916 setLWResult(res, 0, true, false, true);
2917 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2918 return 1;
2919 });
2920
2921 vector<DNSRecord> ret;
2922 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2923 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
2924 BOOST_CHECK_EQUAL(ret.size(), 1);
2925 BOOST_CHECK(ret[0].d_type == QType::A);
2926 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
2927 BOOST_CHECK_EQUAL(queriesCount, 0);
2928}
2929
2930BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
2931 std::unique_ptr<SyncRes> sr;
895449a5 2932 initSR(sr);
3337c2f7
RG
2933
2934 primeHints();
2935
2936 size_t queriesCount = 0;
2937 const DNSName target("powerdns.com.");
2938 const DNSName authZone("internal.powerdns.com.");
2939 const ComboAddress addr("192.0.2.5");
2940
2941 SyncRes::AuthDomain ad;
2942 ad.d_name = authZone;
2943 DNSRecord dr;
2944 dr.d_place = DNSResourceRecord::ANSWER;
2945 dr.d_name = authZone;
2946 dr.d_type = QType::SOA;
2947 dr.d_ttl = 3600;
2948 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
2949 ad.d_records.insert(dr);
2950
2951 dr.d_place = DNSResourceRecord::ANSWER;
2952 dr.d_name = authZone;
2953 dr.d_type = QType::A;
2954 dr.d_ttl = 3600;
2955 dr.d_content = std::make_shared<ARecordContent>(addr);
2956 ad.d_records.insert(dr);
2957
2958 auto map = std::make_shared<SyncRes::domainmap_t>();
2959 (*map)[authZone] = ad;
2960 SyncRes::setDomainMap(map);
2961
2962 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) {
2963
2964 queriesCount++;
2965
2966 if (domain == target) {
2967 setLWResult(res, 0, true, false, true);
2968 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
2969 return 1;
2970 }
2971
2972 return 0;
2973 });
2974
2975 vector<DNSRecord> ret;
2976 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2977 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
2978 BOOST_CHECK_EQUAL(ret.size(), 2);
2979 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2980 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
2981 BOOST_CHECK(ret[1].d_type == QType::A);
2982 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
2983 BOOST_CHECK_EQUAL(queriesCount, 1);
2984}
2985
2986BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
2987 std::unique_ptr<SyncRes> sr;
895449a5 2988 initSR(sr);
3337c2f7
RG
2989
2990 primeHints();
2991
2992 size_t queriesCount = 0;
2993 const DNSName target("powerdns.com.");
2994 const DNSName externalCNAME("www.open-xchange.com.");
2995 const ComboAddress addr("192.0.2.5");
2996
2997 SyncRes::AuthDomain ad;
2998 ad.d_name = target;
2999 DNSRecord dr;
3000 dr.d_place = DNSResourceRecord::ANSWER;
3001 dr.d_name = target;
3002 dr.d_type = QType::SOA;
3003 dr.d_ttl = 3600;
3004 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3005 ad.d_records.insert(dr);
3006
3007 dr.d_place = DNSResourceRecord::ANSWER;
3008 dr.d_name = target;
3009 dr.d_type = QType::CNAME;
3010 dr.d_ttl = 3600;
3011 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
3012 ad.d_records.insert(dr);
3013
3014 auto map = std::make_shared<SyncRes::domainmap_t>();
3015 (*map)[target] = ad;
3016 SyncRes::setDomainMap(map);
3017
3018 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) {
3019
3020 queriesCount++;
3021
3022 if (domain == externalCNAME) {
3023 setLWResult(res, 0, true, false, true);
3024 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
3025 return 1;
3026 }
3027
3028 return 0;
3029 });
3030
3031 vector<DNSRecord> ret;
3032 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3033 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3034 BOOST_CHECK_EQUAL(ret.size(), 2);
3035 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3036 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
3037 BOOST_CHECK(ret[1].d_type == QType::A);
3038 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3039 BOOST_CHECK_EQUAL(queriesCount, 1);
3040}
3041
3042BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
3043 std::unique_ptr<SyncRes> sr;
895449a5 3044 initSR(sr);
3337c2f7
RG
3045
3046 primeHints();
3047
3048 size_t queriesCount = 0;
3049 const DNSName target("nodata.powerdns.com.");
3050 const DNSName authZone("powerdns.com");
3051
3052 SyncRes::AuthDomain ad;
3053 ad.d_name = authZone;
3054 DNSRecord dr;
3055 dr.d_place = DNSResourceRecord::ANSWER;
3056 dr.d_name = target;
3057 dr.d_type = QType::A;
3058 dr.d_ttl = 3600;
3059 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3060 ad.d_records.insert(dr);
3061
3062 dr.d_place = DNSResourceRecord::ANSWER;
3063 dr.d_name = authZone;
3064 dr.d_type = QType::SOA;
3065 dr.d_ttl = 3600;
3066 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3067 ad.d_records.insert(dr);
3068
3069 auto map = std::make_shared<SyncRes::domainmap_t>();
3070 (*map)[authZone] = ad;
3071 SyncRes::setDomainMap(map);
3072
3073 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) {
3074
3075 queriesCount++;
3076
3077 return 0;
3078 });
3079
3080 vector<DNSRecord> ret;
3081 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3082 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3083 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3084 BOOST_CHECK(ret[0].d_type == QType::SOA);
3085 BOOST_CHECK_EQUAL(queriesCount, 0);
3086}
3087
3088BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3089 std::unique_ptr<SyncRes> sr;
895449a5 3090 initSR(sr);
3337c2f7
RG
3091
3092 primeHints();
3093
3094 size_t queriesCount = 0;
3095 const DNSName target("nx.powerdns.com.");
3096 const DNSName authZone("powerdns.com");
3097
3098 SyncRes::AuthDomain ad;
3099 ad.d_name = authZone;
3100 DNSRecord dr;
3101 dr.d_place = DNSResourceRecord::ANSWER;
3102 dr.d_name = DNSName("powerdns.com.");
3103 dr.d_type = QType::SOA;
3104 dr.d_ttl = 3600;
3105 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3106 ad.d_records.insert(dr);
3107
3108 auto map = std::make_shared<SyncRes::domainmap_t>();
3109 (*map)[authZone] = ad;
3110 SyncRes::setDomainMap(map);
3111
3112 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) {
3113
3114 queriesCount++;
3115
3116 return 0;
3117 });
3118
3119 vector<DNSRecord> ret;
3120 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3121 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3122 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3123 BOOST_CHECK(ret[0].d_type == QType::SOA);
3124 BOOST_CHECK_EQUAL(queriesCount, 0);
3125}
3126
3127BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3128 std::unique_ptr<SyncRes> sr;
895449a5 3129 initSR(sr);
3337c2f7
RG
3130
3131 primeHints();
3132
3133 size_t queriesCount = 0;
3134 const DNSName target("www.test.powerdns.com.");
3135 const ComboAddress targetAddr("192.0.2.2");
3136 const DNSName ns("ns1.test.powerdns.com.");
3137 const ComboAddress nsAddr("192.0.2.1");
3138 const DNSName authZone("powerdns.com");
3139
3140 SyncRes::AuthDomain ad;
3141 ad.d_name = authZone;
3142 DNSRecord dr;
3143 dr.d_place = DNSResourceRecord::ANSWER;
3144 dr.d_name = authZone;
3145 dr.d_type = QType::SOA;
3146 dr.d_ttl = 3600;
3147 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3148 ad.d_records.insert(dr);
3149
3150 dr.d_place = DNSResourceRecord::ANSWER;
3151 dr.d_name = DNSName("test.powerdns.com.");
3152 dr.d_type = QType::NS;
3153 dr.d_ttl = 3600;
3154 dr.d_content = std::make_shared<NSRecordContent>(ns);
3155 ad.d_records.insert(dr);
3156
3157 dr.d_place = DNSResourceRecord::ANSWER;
3158 dr.d_name = ns;
3159 dr.d_type = QType::A;
3160 dr.d_ttl = 3600;
3161 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3162 ad.d_records.insert(dr);
3163
3164 auto map = std::make_shared<SyncRes::domainmap_t>();
3165 (*map)[authZone] = ad;
3166 SyncRes::setDomainMap(map);
3167
3168 sr->setAsyncCallback([&queriesCount,target,targetAddr,nsAddr](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
3169
3170 queriesCount++;
3171 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3172 setLWResult(res, 0, true, false, true);
3173 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3174 return 1;
3175 }
3176
3177 return 0;
3178 });
3179
3180 vector<DNSRecord> ret;
3181 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3182 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3183 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3184 BOOST_CHECK(ret[0].d_type == QType::A);
3185 BOOST_CHECK_EQUAL(queriesCount, 1);
3186}
3187
3188BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3189 std::unique_ptr<SyncRes> sr;
895449a5 3190 initSR(sr);
3337c2f7
RG
3191
3192 primeHints();
3193
3194 size_t queriesCount = 0;
3195 const DNSName target("test.powerdns.com.");
3196 const ComboAddress targetAddr("192.0.2.2");
3197 const DNSName ns("ns1.test.powerdns.com.");
3198 const ComboAddress nsAddr("192.0.2.1");
3199 const DNSName authZone("powerdns.com");
3200
3201 SyncRes::AuthDomain ad;
3202 ad.d_name = authZone;
3203 DNSRecord dr;
3204 dr.d_place = DNSResourceRecord::ANSWER;
3205 dr.d_name = authZone;
3206 dr.d_type = QType::SOA;
3207 dr.d_ttl = 3600;
3208 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3209 ad.d_records.insert(dr);
3210
3211 dr.d_place = DNSResourceRecord::ANSWER;
3212 dr.d_name = DNSName("test.powerdns.com.");
3213 dr.d_type = QType::NS;
3214 dr.d_ttl = 3600;
3215 dr.d_content = std::make_shared<NSRecordContent>(ns);
3216 ad.d_records.insert(dr);
3217
3218 dr.d_place = DNSResourceRecord::ANSWER;
3219 dr.d_name = ns;
3220 dr.d_type = QType::A;
3221 dr.d_ttl = 3600;
3222 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3223 ad.d_records.insert(dr);
3224
3225 auto map = std::make_shared<SyncRes::domainmap_t>();
3226 (*map)[authZone] = ad;
3227 SyncRes::setDomainMap(map);
3228
3229 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) {
3230
3231 queriesCount++;
3232
3233 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3234 setLWResult(res, 0, true, false, true);
3235 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3236 return 1;
3237 }
3238
3239 return 0;
3240 });
3241
3242 vector<DNSRecord> ret;
3243 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3244 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3245 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3246 BOOST_CHECK(ret[0].d_type == QType::A);
3247 BOOST_CHECK_EQUAL(queriesCount, 1);
3248}
3249
3250BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3251 std::unique_ptr<SyncRes> sr;
895449a5 3252 initSR(sr);
3337c2f7
RG
3253
3254 primeHints();
3255
3256 size_t queriesCount = 0;
3257 const DNSName target("test.powerdns.com.");
3258 const ComboAddress targetAddr("192.0.2.2");
3259 const DNSName authZone("powerdns.com");
3260
3261 SyncRes::AuthDomain ad;
3262 ad.d_name = authZone;
3263 DNSRecord dr;
3264 dr.d_place = DNSResourceRecord::ANSWER;
3265 dr.d_name = authZone;
3266 dr.d_type = QType::SOA;
3267 dr.d_ttl = 3600;
3268 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3269 ad.d_records.insert(dr);
3270
3271 dr.d_place = DNSResourceRecord::ANSWER;
3272 dr.d_name = DNSName("*.powerdns.com.");
3273 dr.d_type = QType::A;
3274 dr.d_ttl = 3600;
3275 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3276 ad.d_records.insert(dr);
3277
3278 auto map = std::make_shared<SyncRes::domainmap_t>();
3279 (*map)[authZone] = ad;
3280 SyncRes::setDomainMap(map);
3281
3282 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) {
3283
3284 queriesCount++;
3285
3286 return 0;
3287 });
3288
3289 vector<DNSRecord> ret;
3290 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3291 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3292 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3293 BOOST_CHECK(ret[0].d_type == QType::A);
3294 BOOST_CHECK_EQUAL(queriesCount, 0);
3295}
3296
3297BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3298 std::unique_ptr<SyncRes> sr;
895449a5 3299 initSR(sr);
3337c2f7
RG
3300
3301 primeHints();
3302
3303 size_t queriesCount = 0;
3304 const DNSName target("test.powerdns.com.");
3305 const ComboAddress targetAddr("192.0.2.2");
3306 const DNSName authZone("powerdns.com");
3307
3308 SyncRes::AuthDomain ad;
3309 ad.d_name = authZone;
3310 DNSRecord dr;
3311 dr.d_place = DNSResourceRecord::ANSWER;
3312 dr.d_name = authZone;
3313 dr.d_type = QType::SOA;
3314 dr.d_ttl = 3600;
3315 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3316 ad.d_records.insert(dr);
3317
3318 dr.d_place = DNSResourceRecord::ANSWER;
3319 dr.d_name = DNSName("*.powerdns.com.");
3320 dr.d_type = QType::A;
3321 dr.d_ttl = 3600;
3322 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3323 ad.d_records.insert(dr);
3324
3325 auto map = std::make_shared<SyncRes::domainmap_t>();
3326 (*map)[authZone] = ad;
3327 SyncRes::setDomainMap(map);
3328
3329 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) {
3330
3331 queriesCount++;
3332
3333 return 0;
3334 });
3335
3336 vector<DNSRecord> ret;
3337 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3338 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3339 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3340 BOOST_CHECK(ret[0].d_type == QType::SOA);
3341 BOOST_CHECK_EQUAL(queriesCount, 0);
3342}
3343
3344BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3345 std::unique_ptr<SyncRes> sr;
895449a5 3346 initSR(sr);
3337c2f7
RG
3347
3348 primeHints();
3349
3350 size_t queriesCount = 0;
3351 const DNSName target("powerdns.com.");
3352 const ComboAddress addr("192.0.2.5");
3353
3354 SyncRes::AuthDomain ad;
3355 ad.d_name = target;
3356 DNSRecord dr;
3357 dr.d_place = DNSResourceRecord::ANSWER;
3358 dr.d_name = target;
3359 dr.d_type = QType::SOA;
3360 dr.d_ttl = 3600;
3361 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3362 ad.d_records.insert(dr);
3363
3364 dr.d_place = DNSResourceRecord::ANSWER;
3365 dr.d_name = target;
3366 dr.d_type = QType::A;
3367 dr.d_ttl = 3600;
3368 dr.d_content = std::make_shared<ARecordContent>(addr);
3369 ad.d_records.insert(dr);
3370
3371 auto map = std::make_shared<SyncRes::domainmap_t>();
3372 (*map)[target] = ad;
3373 SyncRes::setDomainMap(map);
3374
3375 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) {
3376
3377 queriesCount++;
3378 setLWResult(res, 0, true, false, true);
3379 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3380 return 1;
3381 });
3382
3383 /* simulate a no-RD query */
3384 sr->setCacheOnly();
3385
3386 vector<DNSRecord> ret;
3387 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3388 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3389 BOOST_CHECK_EQUAL(ret.size(), 1);
3390 BOOST_CHECK(ret[0].d_type == QType::A);
3391 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3392 BOOST_CHECK_EQUAL(queriesCount, 0);
3393}
3394
8455425c 3395BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
8455425c
RG
3396 init();
3397
3398 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3399 dcke->create(dcke->getBits());
3400 // cerr<<dcke->convertToISC()<<endl;
3401 DNSSECPrivateKey dpk;
3402 dpk.d_flags = 256;
3403 dpk.setKey(dcke);
3404
3405 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3406 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3407
3408 DNSName qname("powerdns.com.");
3409
179b340d 3410 time_t now = time(nullptr);
8455425c 3411 RRSIGRecordContent rrc;
179b340d
RG
3412 /* this RRSIG is valid for the current second only */
3413 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
8455425c
RG
3414
3415 skeyset_t keyset;
3416 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3417
3418 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3419 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3420
179b340d 3421 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
8455425c
RG
3422}
3423
3424BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3425 std::unique_ptr<SyncRes> sr;
895449a5 3426 initSR(sr, true);
8455425c 3427
0c43f455 3428 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3429
3430 primeHints();
3431 const DNSName target(".");
b7f378d1 3432 testkeysset_t keys;
8455425c
RG
3433
3434 auto luaconfsCopy = g_luaconfs.getCopy();
3435 luaconfsCopy.dsAnchors.clear();
3436 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3437 g_luaconfs.setState(luaconfsCopy);
3438
3439 size_t queriesCount = 0;
3440
3441 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) {
3442 queriesCount++;
3443
3444 if (domain == target && type == QType::NS) {
3445
3446 setLWResult(res, 0, true, false, true);
3447 char addr[] = "a.root-servers.net.";
3448 for (char idx = 'a'; idx <= 'm'; idx++) {
3449 addr[0] = idx;
3450 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3451 }
3452
3453 addRRSIG(keys, res->d_records, domain, 300);
3454
3455 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3456 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3457
3458 return 1;
3459 } else if (domain == target && type == QType::DNSKEY) {
3460
3461 setLWResult(res, 0, true, false, true);
3462
3463 addDNSKEY(keys, domain, 300, res->d_records);
3464 addRRSIG(keys, res->d_records, domain, 300);
3465
3466 return 1;
3467 }
3468
3469 return 0;
3470 });
3471
3472 vector<DNSRecord> ret;
3473 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3474 BOOST_CHECK_EQUAL(res, RCode::NoError);
3475 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
3476 /* 13 NS + 1 RRSIG */
3477 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3478 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3479
3480 /* again, to test the cache */
3481 ret.clear();
3482 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3483 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3484 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
3485 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3486 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3487}
3488
3489BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3490 std::unique_ptr<SyncRes> sr;
895449a5 3491 initSR(sr, true);
8455425c 3492
0c43f455 3493 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3494
3495 primeHints();
3496 const DNSName target(".");
b7f378d1
RG
3497 testkeysset_t zskeys;
3498 testkeysset_t kskeys;
8455425c
RG
3499
3500 /* Generate key material for "." */
3501 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3502 dckeZ->create(dckeZ->getBits());
3503 DNSSECPrivateKey ksk;
3504 ksk.d_flags = 257;
3505 ksk.setKey(dckeZ);
b7f378d1
RG
3506 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3507
8455425c
RG
3508 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3509 dckeK->create(dckeK->getBits());
3510 DNSSECPrivateKey zsk;
3511 zsk.d_flags = 256;
3512 zsk.setKey(dckeK);
b7f378d1 3513 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3514
b7f378d1
RG
3515 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3516 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
8455425c
RG
3517
3518 /* Set the root DS */
8455425c
RG
3519 auto luaconfsCopy = g_luaconfs.getCopy();
3520 luaconfsCopy.dsAnchors.clear();
b7f378d1 3521 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
8455425c
RG
3522 g_luaconfs.setState(luaconfsCopy);
3523
3524 size_t queriesCount = 0;
3525
3526 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) {
3527 queriesCount++;
3528
3529 if (domain == target && type == QType::NS) {
3530
3531 setLWResult(res, 0, true, false, true);
3532 char addr[] = "a.root-servers.net.";
3533 for (char idx = 'a'; idx <= 'm'; idx++) {
3534 addr[0] = idx;
3535 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3536 }
3537
3538 addRRSIG(zskeys, res->d_records, domain, 300);
3539
3540 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3541 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3542
3543 return 1;
3544 } else if (domain == target && type == QType::DNSKEY) {
3545
3546 setLWResult(res, 0, true, false, true);
3547
3548 addDNSKEY(kskeys, domain, 300, res->d_records);
3549 addDNSKEY(zskeys, domain, 300, res->d_records);
3550 addRRSIG(kskeys, 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_bogus_no_dnskey) {
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 3583 testkeysset_t keys;
8455425c
RG
3584
3585 auto luaconfsCopy = g_luaconfs.getCopy();
3586 luaconfsCopy.dsAnchors.clear();
3587 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3588 g_luaconfs.setState(luaconfsCopy);
3589
3590 size_t queriesCount = 0;
3591
3592 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) {
3593 queriesCount++;
3594
3595 if (domain == target && type == QType::NS) {
3596
3597 setLWResult(res, 0, true, false, true);
3598 char addr[] = "a.root-servers.net.";
3599 for (char idx = 'a'; idx <= 'm'; idx++) {
3600 addr[0] = idx;
3601 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3602 }
3603
3604 addRRSIG(keys, res->d_records, domain, 300);
3605
3606 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3607 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3608
3609 return 1;
3610 } else if (domain == target && type == QType::DNSKEY) {
3611
3612 setLWResult(res, 0, true, false, true);
3613
3614 /* No DNSKEY */
3615
3616 return 1;
3617 }
3618
3619 return 0;
3620 });
3621
3622 vector<DNSRecord> ret;
3623 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3624 BOOST_CHECK_EQUAL(res, RCode::NoError);
3625 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3626 /* 13 NS + 1 RRSIG */
3627 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3628 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3629
3630 /* again, to test the cache */
3631 ret.clear();
3632 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3633 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3634 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3635 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3636 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3637}
3638
3639BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3640 std::unique_ptr<SyncRes> sr;
895449a5 3641 initSR(sr, true);
8455425c 3642
0c43f455 3643 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3644
3645 primeHints();
3646 const DNSName target(".");
b7f378d1
RG
3647 testkeysset_t dskeys;
3648 testkeysset_t keys;
8455425c
RG
3649
3650 /* Generate key material for "." */
3651 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3652 dckeDS->create(dckeDS->getBits());
3653 DNSSECPrivateKey dskey;
3654 dskey.d_flags = 257;
3655 dskey.setKey(dckeDS);
b7f378d1
RG
3656 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3657
8455425c
RG
3658 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3659 dcke->create(dcke->getBits());
3660 DNSSECPrivateKey dpk;
3661 dpk.d_flags = 256;
3662 dpk.setKey(dcke);
b7f378d1 3663 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3664
b7f378d1
RG
3665 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3666 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
8455425c
RG
3667
3668 /* Set the root DS */
8455425c
RG
3669 auto luaconfsCopy = g_luaconfs.getCopy();
3670 luaconfsCopy.dsAnchors.clear();
3671 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3672 g_luaconfs.setState(luaconfsCopy);
3673
3674 size_t queriesCount = 0;
3675
3676 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) {
3677 queriesCount++;
3678
3679 if (domain == target && type == QType::NS) {
3680
3681 setLWResult(res, 0, true, false, true);
3682 char addr[] = "a.root-servers.net.";
3683 for (char idx = 'a'; idx <= 'm'; idx++) {
3684 addr[0] = idx;
3685 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3686 }
3687
3688 addRRSIG(keys, res->d_records, domain, 300);
3689
3690 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3691 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3692
3693 return 1;
3694 } else if (domain == target && type == QType::DNSKEY) {
3695
3696 setLWResult(res, 0, true, false, true);
3697
3698 addDNSKEY(keys, domain, 300, res->d_records);
3699 addRRSIG(keys, res->d_records, domain, 300);
3700
3701 return 1;
3702 }
3703
3704 return 0;
3705 });
3706
3707 vector<DNSRecord> ret;
3708 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3709 BOOST_CHECK_EQUAL(res, RCode::NoError);
3710 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3711 /* 13 NS + 1 RRSIG */
3712 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3713 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3714
3715 /* again, to test the cache */
3716 ret.clear();
3717 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3718 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3719 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3720 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3721 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3722}
3723
3724BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
3725 std::unique_ptr<SyncRes> sr;
895449a5 3726 initSR(sr, true);
8455425c 3727
0c43f455 3728 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3729
3730 primeHints();
3731 const DNSName target(".");
b7f378d1
RG
3732 testkeysset_t keys;
3733 testkeysset_t rrsigkeys;
8455425c
RG
3734
3735 auto luaconfsCopy = g_luaconfs.getCopy();
3736 luaconfsCopy.dsAnchors.clear();
3737 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3738 g_luaconfs.setState(luaconfsCopy);
3739
3740 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3741 dckeRRSIG->create(dckeRRSIG->getBits());
3742 DNSSECPrivateKey rrsigkey;
3743 rrsigkey.d_flags = 257;
3744 rrsigkey.setKey(dckeRRSIG);
b7f378d1
RG
3745 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
3746
3747 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
8455425c
RG
3748
3749 size_t queriesCount = 0;
3750
3751 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) {
3752 queriesCount++;
3753
3754 if (domain == target && type == QType::NS) {
3755
3756 setLWResult(res, 0, true, false, true);
3757 char addr[] = "a.root-servers.net.";
3758 for (char idx = 'a'; idx <= 'm'; idx++) {
3759 addr[0] = idx;
3760 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3761 }
3762
3763 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3764
3765 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3766 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3767
3768 return 1;
3769 } else if (domain == target && type == QType::DNSKEY) {
3770
3771 setLWResult(res, 0, true, false, true);
3772
3773 addDNSKEY(keys, domain, 300, res->d_records);
3774 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3775
3776 return 1;
3777 }
3778
3779 return 0;
3780 });
3781
3782 vector<DNSRecord> ret;
3783 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3784 BOOST_CHECK_EQUAL(res, RCode::NoError);
3785 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3786 /* 13 NS + 1 RRSIG */
3787 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3788 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3789
3790 /* again, to test the cache */
3791 ret.clear();
3792 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3793 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3794 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3795 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3796 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3797}
3798
3799BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
3800 std::unique_ptr<SyncRes> sr;
895449a5 3801 initSR(sr, true);
8455425c 3802
0c43f455 3803 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3804
3805 primeHints();
3806 const DNSName target(".");
b7f378d1 3807 testkeysset_t keys;
8455425c
RG
3808
3809 auto luaconfsCopy = g_luaconfs.getCopy();
3810 luaconfsCopy.dsAnchors.clear();
3811 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3812 g_luaconfs.setState(luaconfsCopy);
3813
3814 size_t queriesCount = 0;
3815
3816 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) {
3817 queriesCount++;
3818
3819 if (domain == target && type == QType::NS) {
3820
3821 setLWResult(res, 0, true, false, true);
3822 char addr[] = "a.root-servers.net.";
3823 for (char idx = 'a'; idx <= 'm'; idx++) {
3824 addr[0] = idx;
3825 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3826 }
3827
3828 /* No RRSIG */
3829
3830 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3831 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3832
3833 return 1;
3834 } else if (domain == target && type == QType::DNSKEY) {
3835
3836 setLWResult(res, 0, true, false, true);
3837
3838 addDNSKEY(keys, domain, 300, res->d_records);
3839 addRRSIG(keys, res->d_records, domain, 300);
3840
3841 return 1;
3842 }
3843
3844 return 0;
3845 });
3846
3847 vector<DNSRecord> ret;
3848 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3849 BOOST_CHECK_EQUAL(res, RCode::NoError);
3850 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3851 /* 13 NS + 0 RRSIG */
3852 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3853 /* no RRSIG so no query for DNSKEYs */
3854 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
3855
3856 /* again, to test the cache */
3857 ret.clear();
3858 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3859 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3860 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3861 BOOST_REQUIRE_EQUAL(ret.size(), 13);
3862 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
3863}
3864
3865BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
3866 std::unique_ptr<SyncRes> sr;
895449a5 3867 initSR(sr, true);
8455425c 3868
0c43f455 3869 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3870
3871 primeHints();
3872 const DNSName target(".");
b7f378d1 3873 testkeysset_t keys;
8455425c
RG
3874
3875 /* Generate key material for "." */
3876 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3877 dcke->create(dcke->getBits());
3878 DNSSECPrivateKey dpk;
3879 dpk.d_flags = 256;
3880 dpk.setKey(dcke);
3881 /* Fake algorithm number (private) */
3882 dpk.d_algorithm = 253;
3883
8455425c 3884 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
b7f378d1 3885 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
8455425c
RG
3886 /* Fake algorithm number (private) */
3887 drc.d_algorithm = 253;
3888
b7f378d1 3889 /* Set the root DS */
8455425c
RG
3890 auto luaconfsCopy = g_luaconfs.getCopy();
3891 luaconfsCopy.dsAnchors.clear();
3892 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3893 g_luaconfs.setState(luaconfsCopy);
3894
3895 size_t queriesCount = 0;
3896
3897 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) {
3898 queriesCount++;
3899
3900 if (domain == target && type == QType::NS) {
3901
3902 setLWResult(res, 0, true, false, true);
3903 char addr[] = "a.root-servers.net.";
3904 for (char idx = 'a'; idx <= 'm'; idx++) {
3905 addr[0] = idx;
3906 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3907 }
3908
3909 addRRSIG(keys, res->d_records, domain, 300);
3910
3911 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3912 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3913
3914 return 1;
3915 } else if (domain == target && type == QType::DNSKEY) {
3916
3917 setLWResult(res, 0, true, false, true);
3918
3919 addDNSKEY(keys, domain, 300, res->d_records);
3920 addRRSIG(keys, res->d_records, domain, 300);
3921
3922 return 1;
3923 }
3924
3925 return 0;
3926 });
3927
3928 vector<DNSRecord> ret;
3929 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3930 BOOST_CHECK_EQUAL(res, RCode::NoError);
3931 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
3932 /* 13 NS + 1 RRSIG */
3933 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3934 /* no supported DS so no query for DNSKEYs */
3935 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
3936
3937 /* again, to test the cache */
3938 ret.clear();
3939 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3940 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3941 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
3942 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3943 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
3944}
3945
3946BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
3947 std::unique_ptr<SyncRes> sr;
895449a5 3948 initSR(sr, true);
8455425c 3949
0c43f455 3950 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3951
3952 primeHints();
3953 const DNSName target(".");
b7f378d1 3954 testkeysset_t keys;
8455425c
RG
3955
3956 /* Generate key material for "." */
3957 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3958 dcke->create(dcke->getBits());
3959 DNSSECPrivateKey dpk;
3960 dpk.d_flags = 256;
3961 dpk.setKey(dcke);
8455425c
RG
3962 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
3963 /* Fake digest number (reserved) */
3964 drc.d_digesttype = 0;
3965
b7f378d1
RG
3966 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
3967
3968 /* Set the root DS */
8455425c
RG
3969 auto luaconfsCopy = g_luaconfs.getCopy();
3970 luaconfsCopy.dsAnchors.clear();
3971 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3972 g_luaconfs.setState(luaconfsCopy);
3973
3974 size_t queriesCount = 0;
3975
3976 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) {
3977 queriesCount++;
3978
3979 if (domain == target && type == QType::NS) {
3980
3981 setLWResult(res, 0, true, false, true);
3982 char addr[] = "a.root-servers.net.";
3983 for (char idx = 'a'; idx <= 'm'; idx++) {
3984 addr[0] = idx;
3985 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3986 }
3987
3988 addRRSIG(keys, res->d_records, domain, 300);
3989
3990 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3991 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3992
3993 return 1;
3994 } else if (domain == target && type == QType::DNSKEY) {
3995
3996 setLWResult(res, 0, true, false, true);
3997
3998 addDNSKEY(keys, domain, 300, res->d_records);
3999 addRRSIG(keys, res->d_records, domain, 300);
4000
4001 return 1;
4002 }
4003
4004 return 0;
4005 });
4006
4007 vector<DNSRecord> ret;
4008 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4009 BOOST_CHECK_EQUAL(res, RCode::NoError);
4010 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4011 /* 13 NS + 1 RRSIG */
4012 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4013 /* no supported DS so no query for DNSKEYs */
4014 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4015
4016 /* again, to test the cache */
4017 ret.clear();
4018 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4019 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4020 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4021 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4022 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4023}
4024
3d5ebf10
RG
4025BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
4026 std::unique_ptr<SyncRes> sr;
4027 initSR(sr, true);
4028
0c43f455 4029 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4030
4031 primeHints();
4032 const DNSName target(".");
4033 testkeysset_t keys;
4034
4035 auto luaconfsCopy = g_luaconfs.getCopy();
4036 luaconfsCopy.dsAnchors.clear();
4037 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4038
4039 g_luaconfs.setState(luaconfsCopy);
4040
4041 size_t queriesCount = 0;
4042
4043 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) {
4044 queriesCount++;
4045
4046 if (domain == target && type == QType::NS) {
4047
4048 setLWResult(res, 0, true, false, true);
4049 char addr[] = "a.root-servers.net.";
4050 for (char idx = 'a'; idx <= 'm'; idx++) {
4051 addr[0] = idx;
4052 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4053 }
4054
4055 addRRSIG(keys, res->d_records, domain, 300, true);
4056
4057 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4058 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4059
4060 return 1;
4061 } else if (domain == target && type == QType::DNSKEY) {
4062
4063 setLWResult(res, 0, true, false, true);
4064
4065 addDNSKEY(keys, domain, 300, res->d_records);
4066 addRRSIG(keys, res->d_records, domain, 300);
4067
4068 return 1;
4069 }
4070
4071 return 0;
4072 });
4073
4074 vector<DNSRecord> ret;
4075 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4076 BOOST_CHECK_EQUAL(res, RCode::NoError);
4077 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4078 /* 13 NS + 1 RRSIG */
4079 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4080 BOOST_CHECK_EQUAL(queriesCount, 2);
4081
4082 /* again, to test the cache */
4083 ret.clear();
4084 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4085 BOOST_CHECK_EQUAL(res, RCode::NoError);
4086 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4087 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4088 BOOST_CHECK_EQUAL(queriesCount, 2);
4089}
4090
4091BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
4092 std::unique_ptr<SyncRes> sr;
4093 initSR(sr, true);
4094
0c43f455 4095 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4096
4097 primeHints();
4098 const DNSName target(".");
4099 testkeysset_t keys;
4100
4101 auto luaconfsCopy = g_luaconfs.getCopy();
4102 luaconfsCopy.dsAnchors.clear();
4103 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4104
4105 g_luaconfs.setState(luaconfsCopy);
4106
4107 size_t queriesCount = 0;
4108
4109 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) {
4110 queriesCount++;
4111
4112 if (domain == target && type == QType::NS) {
4113
4114 setLWResult(res, 0, true, false, true);
4115 char addr[] = "a.root-servers.net.";
4116 for (char idx = 'a'; idx <= 'm'; idx++) {
4117 addr[0] = idx;
4118 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4119 }
4120
4121 /* FORCE WRONG ALGO */
4122 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4123
4124 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4125 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4126
4127 return 1;
4128 } else if (domain == target && type == QType::DNSKEY) {
4129
4130 setLWResult(res, 0, true, false, true);
4131
4132 addDNSKEY(keys, domain, 300, res->d_records);
4133 addRRSIG(keys, res->d_records, domain, 300);
4134
4135 return 1;
4136 }
4137
4138 return 0;
4139 });
4140
4141 vector<DNSRecord> ret;
4142 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4143 BOOST_CHECK_EQUAL(res, RCode::NoError);
4144 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4145 /* 13 NS + 1 RRSIG */
4146 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4147 BOOST_CHECK_EQUAL(queriesCount, 2);
4148
4149 /* again, to test the cache */
4150 ret.clear();
4151 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4152 BOOST_CHECK_EQUAL(res, RCode::NoError);
4153 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4154 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4155 BOOST_CHECK_EQUAL(queriesCount, 2);
4156}
4157
b7f378d1 4158BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
8455425c 4159 std::unique_ptr<SyncRes> sr;
895449a5 4160 initSR(sr, true);
8455425c 4161
0c43f455 4162 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4163
4164 primeHints();
4165 const DNSName target("powerdns.com.");
b7f378d1
RG
4166 const ComboAddress targetAddr("192.0.2.42");
4167 testkeysset_t keys;
8455425c
RG
4168
4169 auto luaconfsCopy = g_luaconfs.getCopy();
4170 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4171 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4172 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4173 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
8455425c
RG
4174
4175 g_luaconfs.setState(luaconfsCopy);
4176
4177 size_t queriesCount = 0;
4178
b7f378d1 4179 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
4180 queriesCount++;
4181
b7f378d1
RG
4182 DNSName auth = domain;
4183 if (domain == target) {
4184 auth = DNSName("powerdns.com.");
4185 }
5374b03b
RG
4186
4187 if (type == QType::DS || type == QType::DNSKEY) {
4188 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8455425c 4189 }
5374b03b
RG
4190
4191 if (isRootServer(ip)) {
4192 setLWResult(res, 0, false, false, true);
4193 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4194 addDS(DNSName("com."), 300, res->d_records, keys);
4195 addRRSIG(keys, res->d_records, DNSName("."), 300);
4196 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8455425c
RG
4197 return 1;
4198 }
5374b03b
RG
4199
4200 if (ip == ComboAddress("192.0.2.1:53")) {
4201 if (domain == DNSName("com.")) {
4202 setLWResult(res, 0, true, false, true);
4203 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4204 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4205 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4206 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4207 }
5374b03b
RG
4208 else {
4209 setLWResult(res, 0, false, false, true);
4210 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4211 addDS(auth, 300, res->d_records, keys);
4212 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4213 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8455425c 4214 }
5374b03b
RG
4215 return 1;
4216 }
4217
4218 if (ip == ComboAddress("192.0.2.2:53")) {
4219 if (type == QType::NS) {
4220 setLWResult(res, 0, true, false, true);
4221 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4222 addRRSIG(keys, res->d_records, auth, 300);
4223 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4224 addRRSIG(keys, res->d_records, auth, 300);
8455425c 4225 }
5374b03b
RG
4226 else {
4227 setLWResult(res, RCode::NoError, true, false, true);
4228 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4229 addRRSIG(keys, res->d_records, auth, 300);
4230 }
4231 return 1;
8455425c
RG
4232 }
4233
4234 return 0;
4235 });
4236
4237 vector<DNSRecord> ret;
4238 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1
RG
4239 BOOST_CHECK_EQUAL(res, RCode::NoError);
4240 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4241 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4242 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4243
4244 /* again, to test the cache */
4245 ret.clear();
4246 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4247 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4248 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1 4249 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4250 BOOST_CHECK_EQUAL(queriesCount, 8);
8455425c
RG
4251}
4252
428f41b7
RG
4253BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4254 std::unique_ptr<SyncRes> sr;
4255 initSR(sr, true);
4256
0c43f455 4257 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4258
4259 primeHints();
4260 const DNSName target("powerdns.com.");
4261 const ComboAddress targetAddr("192.0.2.42");
4262 testkeysset_t keys;
4263
4264 auto luaconfsCopy = g_luaconfs.getCopy();
4265 luaconfsCopy.dsAnchors.clear();
4266 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4267 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4268 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4269 g_luaconfs.setState(luaconfsCopy);
4270
4271 size_t queriesCount = 0;
4272
4273 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) {
4274 queriesCount++;
4275
4276 DNSName auth = domain;
4277 if (domain == target) {
4278 auth = DNSName("powerdns.com.");
4279 }
5374b03b
RG
4280
4281 if (type == QType::DS || type == QType::DNSKEY) {
4282 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4283 }
5374b03b
RG
4284
4285 if (isRootServer(ip)) {
4286 setLWResult(res, 0, false, false, true);
4287 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4288 addDS(DNSName("com."), 300, res->d_records, keys);
4289 addRRSIG(keys, res->d_records, DNSName("."), 300);
4290 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4291 return 1;
4292 }
5374b03b
RG
4293
4294 if (ip == ComboAddress("192.0.2.1:53")) {
4295 if (domain == DNSName("com.")) {
4296 setLWResult(res, 0, true, false, true);
4297 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4298 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4299 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4300 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4301 }
5374b03b
RG
4302 else {
4303 setLWResult(res, 0, false, false, true);
4304 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4305 addDS(auth, 300, res->d_records, keys);
4306 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4307 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4308 }
5374b03b
RG
4309 return 1;
4310 }
4311
4312 if (ip == ComboAddress("192.0.2.2:53")) {
4313 if (type == QType::NS) {
4314 setLWResult(res, 0, true, false, true);
4315 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4316 addRRSIG(keys, res->d_records, auth, 300);
4317 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4318 addRRSIG(keys, res->d_records, auth, 300);
4319 }
4320 else {
4321 setLWResult(res, RCode::NoError, true, false, true);
4322 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4323 addRRSIG(keys, res->d_records, auth, 300);
428f41b7 4324 }
5374b03b 4325 return 1;
428f41b7
RG
4326 }
4327
4328 return 0;
4329 });
4330
4331 vector<DNSRecord> ret;
4332 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4333 BOOST_CHECK_EQUAL(res, RCode::NoError);
4334 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4335 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4336 BOOST_CHECK_EQUAL(queriesCount, 8);
4337
4338 /* again, to test the cache */
4339 ret.clear();
4340 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4341 BOOST_CHECK_EQUAL(res, RCode::NoError);
4342 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4343 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4344 BOOST_CHECK_EQUAL(queriesCount, 8);
4345
4346 /* this time we ask for the NS that should be in the cache, to check
4347 the validation status */
4348 ret.clear();
4349 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4350 BOOST_CHECK_EQUAL(res, RCode::NoError);
4351 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4352 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4353 BOOST_CHECK_EQUAL(queriesCount, 9);
428f41b7
RG
4354
4355}
4356
4357BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4358 std::unique_ptr<SyncRes> sr;
4359 initSR(sr, true);
4360
0c43f455 4361 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4362
4363 primeHints();
4364 const DNSName target("powerdns.com.");
4365 const ComboAddress targetAddr("192.0.2.42");
4366 testkeysset_t keys;
4367
4368 auto luaconfsCopy = g_luaconfs.getCopy();
4369 luaconfsCopy.dsAnchors.clear();
4370 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4371 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4372 g_luaconfs.setState(luaconfsCopy);
4373
4374 size_t queriesCount = 0;
4375
4376 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) {
4377 queriesCount++;
4378
4379 DNSName auth = domain;
4380 if (domain == target) {
4381 auth = DNSName("powerdns.com.");
4382 }
5374b03b
RG
4383
4384 if (type == QType::DS || type == QType::DNSKEY) {
4385 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4386 }
5374b03b
RG
4387
4388 if (isRootServer(ip)) {
4389 setLWResult(res, 0, false, false, true);
4390 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4391 addDS(DNSName("com."), 300, res->d_records, keys);
4392 addRRSIG(keys, res->d_records, DNSName("."), 300);
4393 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4394 return 1;
4395 }
5374b03b
RG
4396
4397 if (ip == ComboAddress("192.0.2.1:53")) {
4398 if (domain == DNSName("com.")) {
4399 setLWResult(res, 0, true, false, true);
4400 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4401 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4402 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4403 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4404 }
5374b03b
RG
4405 else {
4406 setLWResult(res, 0, false, false, true);
4407 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4408 /* no DS */
4409 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4410 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4411 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4412 }
5374b03b
RG
4413 return 1;
4414 }
4415
4416 if (ip == ComboAddress("192.0.2.2:53")) {
4417 if (type == QType::NS) {
4418 setLWResult(res, 0, true, false, true);
4419 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4420 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4421 }
5374b03b
RG
4422 else {
4423 setLWResult(res, RCode::NoError, true, false, true);
4424 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4425 }
4426 return 1;
428f41b7
RG
4427 }
4428
4429 return 0;
4430 });
4431
4432 vector<DNSRecord> ret;
4433 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4434 BOOST_CHECK_EQUAL(res, RCode::NoError);
4435 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4436 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4437 BOOST_CHECK_EQUAL(queriesCount, 7);
4438
4439 /* again, to test the cache */
4440 ret.clear();
4441 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4442 BOOST_CHECK_EQUAL(res, RCode::NoError);
4443 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4444 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4445 BOOST_CHECK_EQUAL(queriesCount, 7);
4446
4447 /* this time we ask for the NS that should be in the cache, to check
4448 the validation status */
4449 ret.clear();
4450 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4451 BOOST_CHECK_EQUAL(res, RCode::NoError);
4452 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4453 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4454 BOOST_CHECK_EQUAL(queriesCount, 8);
428f41b7
RG
4455}
4456
b7f378d1 4457BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
8455425c 4458 std::unique_ptr<SyncRes> sr;
895449a5 4459 initSR(sr, true);
8455425c 4460
0c43f455 4461 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4462
4463 primeHints();
b7f378d1
RG
4464 const DNSName target("powerdns.com.");
4465 const ComboAddress targetAddr("192.0.2.42");
4466 testkeysset_t keys;
8455425c
RG
4467
4468 auto luaconfsCopy = g_luaconfs.getCopy();
4469 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4470 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4471 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4472 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4473
4474 /* Add a NTA for "powerdns.com" */
4475 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
8455425c 4476
8455425c
RG
4477 g_luaconfs.setState(luaconfsCopy);
4478
4479 size_t queriesCount = 0;
4480
b7f378d1 4481 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
4482 queriesCount++;
4483
b7f378d1
RG
4484 DNSName auth = domain;
4485 if (domain == target) {
4486 auth = DNSName("powerdns.com.");
4487 }
5374b03b
RG
4488
4489 if (type == QType::DS || type == QType::DNSKEY) {
4490 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
b7f378d1 4491 }
5374b03b
RG
4492
4493 if (isRootServer(ip)) {
4494 setLWResult(res, 0, false, false, true);
4495 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4496 addDS(DNSName("com."), 300, res->d_records, keys);
4497 addRRSIG(keys, res->d_records, DNSName("."), 300);
4498 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1
RG
4499 return 1;
4500 }
5374b03b
RG
4501
4502 if (ip == ComboAddress("192.0.2.1:53")) {
4503 if (domain == DNSName("com.")) {
4504 setLWResult(res, 0, true, false, true);
4505 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4506 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4507 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4508 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4509 }
5374b03b
RG
4510 else {
4511 setLWResult(res, 0, false, false, true);
4512 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4513 addDS(auth, 300, res->d_records, keys);
4514 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4515 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1 4516 }
5374b03b
RG
4517 return 1;
4518 }
4519
4520 if (ip == ComboAddress("192.0.2.2:53")) {
4521 if (type == QType::NS) {
4522 setLWResult(res, 0, true, false, true);
4523 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4524 addRRSIG(keys, res->d_records, auth, 300);
4525 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4526 addRRSIG(keys, res->d_records, auth, 300);
4527 }
4528 else {
4529 setLWResult(res, RCode::NoError, true, false, true);
4530 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4531 addRRSIG(keys, res->d_records, auth, 300);
b7f378d1 4532 }
5374b03b 4533 return 1;
b7f378d1
RG
4534 }
4535
4536 return 0;
4537 });
4538
4539 vector<DNSRecord> ret;
4540 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4541 BOOST_CHECK_EQUAL(res, RCode::NoError);
4542 /* Should be insecure because of the NTA */
4543 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4544 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4545 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4546
4547 /* again, to test the cache */
4548 ret.clear();
4549 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4550 BOOST_CHECK_EQUAL(res, RCode::NoError);
4551 /* Should be insecure because of the NTA */
4552 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4553 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4554 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4555}
4556
4557BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4558 std::unique_ptr<SyncRes> sr;
895449a5 4559 initSR(sr, true);
b7f378d1 4560
0c43f455 4561 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
4562
4563 primeHints();
4564 const DNSName target("powerdns.com.");
4565 const ComboAddress targetAddr("192.0.2.42");
4566 testkeysset_t keys;
4567
4568 auto luaconfsCopy = g_luaconfs.getCopy();
4569 luaconfsCopy.dsAnchors.clear();
4570 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4571 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4572 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4573
4574 /* Add a NTA for "powerdns.com" */
4575 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4576
4577 g_luaconfs.setState(luaconfsCopy);
4578
4579 size_t queriesCount = 0;
4580
4581 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) {
4582 queriesCount++;
4583
4584 if (type == QType::DS || type == QType::DNSKEY) {
4585 setLWResult(res, 0, false, false, true);
4586 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4587 return 1;
4588 }
f24465e5 4589 else {
b7f378d1
RG
4590 if (isRootServer(ip)) {
4591 setLWResult(res, 0, false, false, true);
4592 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4593 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4594 return 1;
4595 }
4596 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
4597 if (domain == DNSName("com.")) {
4598 setLWResult(res, 0, true, false, true);
4599 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4600 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4601 }
4602 else {
4603 setLWResult(res, 0, false, false, true);
4604 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4605 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4606 }
b7f378d1
RG
4607 return 1;
4608 }
4609 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
4610 if (type == QType::NS) {
4611 setLWResult(res, 0, true, false, true);
4612 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4613 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4614 }
4615 else {
4616 setLWResult(res, RCode::NoError, true, false, true);
4617 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4618 }
b7f378d1
RG
4619 return 1;
4620 }
4621 }
4622
4623 return 0;
4624 });
4625
4626 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
4627 vector<DNSRecord> ret;
4628 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4629 BOOST_CHECK_EQUAL(res, RCode::NoError);
4630 /* Should be insecure because of the NTA */
4631 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4632 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4633 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
4634
4635 /* again, to test the cache */
4636 ret.clear();
4637 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4638 BOOST_CHECK_EQUAL(res, RCode::NoError);
4639 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4640 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4641 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
4642}
4643
4644BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
4645 std::unique_ptr<SyncRes> sr;
895449a5 4646 initSR(sr, true);
b7f378d1 4647
0c43f455 4648 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
4649
4650 primeHints();
4651 const DNSName target("powerdns.com.");
4652 testkeysset_t keys;
4653
4654 auto luaconfsCopy = g_luaconfs.getCopy();
4655 luaconfsCopy.dsAnchors.clear();
4656 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4657 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4658 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4659
4660 g_luaconfs.setState(luaconfsCopy);
4661
4662 size_t queriesCount = 0;
4663
4664 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) {
4665 queriesCount++;
4666
5374b03b
RG
4667 if (type == QType::DS || type == QType::DNSKEY) {
4668 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 4669 }
f24465e5 4670 else {
b7f378d1
RG
4671 if (isRootServer(ip)) {
4672 setLWResult(res, 0, false, false, true);
4673 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4674 addDS(DNSName("com."), 300, res->d_records, keys);
4675 addRRSIG(keys, res->d_records, DNSName("."), 300);
4676 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4677 return 1;
4678 }
4679 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
4680 if (domain == DNSName("com.")) {
4681 setLWResult(res, 0, true, false, true);
4682 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4683 addRRSIG(keys, res->d_records, domain, 300);
4684 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4685 addRRSIG(keys, res->d_records, domain, 300);
4686 }
4687 else {
4688 setLWResult(res, 0, false, false, true);
4689 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4690 addDS(domain, 300, res->d_records, keys);
4691 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4692 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4693 }
b7f378d1
RG
4694 return 1;
4695 }
4696 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
4697 if (type == QType::NS) {
4698 setLWResult(res, 0, true, false, true);
4699 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4700 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4701 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4702 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4703 }
4704 else {
4705 setLWResult(res, 0, true, false, true);
4706 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4707 addRRSIG(keys, res->d_records, domain, 300);
4708 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
4709 addRRSIG(keys, res->d_records, domain, 300);
4710 }
b7f378d1
RG
4711 return 1;
4712 }
4713 }
4714
4715 return 0;
4716 });
4717
4718 vector<DNSRecord> ret;
4719 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4720 BOOST_CHECK_EQUAL(res, RCode::NoError);
4721 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4722 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 4723 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4724
4725 /* again, to test the cache */
4726 ret.clear();
4727 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4728 BOOST_CHECK_EQUAL(res, RCode::NoError);
4729 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4730 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 4731 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4732}
4733
4734BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
4735 std::unique_ptr<SyncRes> sr;
895449a5 4736 initSR(sr, true);
b7f378d1 4737
0c43f455 4738 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
4739
4740 primeHints();
4741 const DNSName target("nx.powerdns.com.");
4742 testkeysset_t keys;
4743
4744 auto luaconfsCopy = g_luaconfs.getCopy();
4745 luaconfsCopy.dsAnchors.clear();
4746 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4747 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4748 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4749
4750 g_luaconfs.setState(luaconfsCopy);
4751
4752 size_t queriesCount = 0;
4753
4754 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) {
4755 queriesCount++;
4756
4757 DNSName auth = domain;
4758 if (domain == target) {
4759 auth = DNSName("powerdns.com.");
4760 }
5374b03b
RG
4761 if (type == QType::DS || type == QType::DNSKEY) {
4762 if (type == QType::DS && domain == target) {
4763 setLWResult(res, RCode::NXDomain, true, false, true);
4764 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4765 addRRSIG(keys, res->d_records, auth, 300);
4766 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4767 addRRSIG(keys, res->d_records, auth, 300);
4768 return 1;
4769 }
4770 else {
4771 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
4772 }
b7f378d1 4773 }
f24465e5 4774 else {
b7f378d1
RG
4775 if (isRootServer(ip)) {
4776 setLWResult(res, 0, false, false, true);
4777 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4778 addDS(DNSName("com."), 300, res->d_records, keys);
4779 addRRSIG(keys, res->d_records, DNSName("."), 300);
4780 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4781 return 1;
4782 }
4783 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
4784 if (domain == DNSName("com.")) {
4785 setLWResult(res, 0, true, false, true);
4786 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4787 addRRSIG(keys, res->d_records, domain, 300);
4788 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4789 addRRSIG(keys, res->d_records, domain, 300);
4790 }
4791 else {
4792 setLWResult(res, 0, false, false, true);
4793 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4794 addDS(auth, 300, res->d_records, keys);
4795 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4796 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4797 }
b7f378d1
RG
4798 return 1;
4799 }
4800 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
4801 if (type == QType::NS) {
4802 setLWResult(res, 0, true, false, true);
4803 if (domain == DNSName("powerdns.com.")) {
4804 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4805 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4806 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4807 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4808 }
4809 else {
4810 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4811 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4812 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4813 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4814 }
4815 }
4816 else {
4817 setLWResult(res, RCode::NXDomain, true, false, true);
4818 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4819 addRRSIG(keys, res->d_records, auth, 300);
4820 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4821 addRRSIG(keys, res->d_records, auth, 300);
9b061cf5
RG
4822 /* add wildcard denial */
4823 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
4824 addRRSIG(keys, res->d_records, auth, 300);
f24465e5 4825 }
b7f378d1
RG
4826 return 1;
4827 }
4828 }
4829
4830 return 0;
4831 });
4832
4833 vector<DNSRecord> ret;
4834 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4835 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
4836 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 4837 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 4838 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
4839
4840 /* again, to test the cache */
4841 ret.clear();
4842 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4843 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
4844 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 4845 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 4846 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
4847}
4848
2b984251
RG
4849BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
4850 std::unique_ptr<SyncRes> sr;
4851 initSR(sr, true);
4852
0c43f455 4853 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2b984251
RG
4854
4855 primeHints();
4856 const DNSName target("www.powerdns.com.");
4857 testkeysset_t keys;
4858
4859 auto luaconfsCopy = g_luaconfs.getCopy();
4860 luaconfsCopy.dsAnchors.clear();
4861 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4862 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4863 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4864
4865 g_luaconfs.setState(luaconfsCopy);
4866
4867 size_t queriesCount = 0;
4868
4869 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) {
4870 queriesCount++;
4871
5374b03b
RG
4872 if (type == QType::DS || type == QType::DNSKEY) {
4873 if (type == QType::DS && domain == target) {
4874 setLWResult(res, RCode::NoError, true, false, true);
4875 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4876 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
4877 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4878 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4879 return 1;
4880 }
4881 else {
4882 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4883 }
2b984251 4884 }
f24465e5 4885 else {
2b984251
RG
4886 if (isRootServer(ip)) {
4887 setLWResult(res, 0, false, false, true);
4888 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4889 addDS(DNSName("com."), 300, res->d_records, keys);
4890 addRRSIG(keys, res->d_records, DNSName("."), 300);
4891 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4892 return 1;
4893 }
4894 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
4895 if (domain == DNSName("com.")) {
4896 setLWResult(res, 0, true, false, true);
4897 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4898 addRRSIG(keys, res->d_records, domain, 300);
4899 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4900 addRRSIG(keys, res->d_records, domain, 300);
4901 }
4902 else {
4903 setLWResult(res, 0, false, false, true);
4904 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4905 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
4906 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4907 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4908 }
2b984251
RG
4909 return 1;
4910 }
4911 else if (ip == ComboAddress("192.0.2.2:53")) {
4912 setLWResult(res, 0, true, false, true);
f24465e5
RG
4913 if (type == QType::NS) {
4914 if (domain == DNSName("powerdns.com.")) {
4915 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4916 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4917 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4918 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4919 }
4920 else {
4921 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4922 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4923 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4924 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4925 }
4926 }
4927 else {
4928 addRecordToLW(res, domain, QType::A, "192.0.2.42");
4929 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
9b061cf5 4930 /* we need to add the proof that this name does not exist, so the wildcard may apply */
f24465e5
RG
4931 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
4932 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4933 }
2b984251
RG
4934 return 1;
4935 }
4936 }
4937
4938 return 0;
4939 });
4940
4941 vector<DNSRecord> ret;
4942 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4943 BOOST_CHECK_EQUAL(res, RCode::NoError);
4944 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4945 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 4946 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
4947
4948 /* again, to test the cache */
4949 ret.clear();
4950 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4951 BOOST_CHECK_EQUAL(res, RCode::NoError);
4952 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4953 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 4954 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
4955}
4956
9b061cf5
RG
4957BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
4958 std::unique_ptr<SyncRes> sr;
4959 initSR(sr, true);
4960
4961 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4962
4963 primeHints();
4964 const DNSName target("www.com.");
4965 testkeysset_t keys;
4966
4967 auto luaconfsCopy = g_luaconfs.getCopy();
4968 luaconfsCopy.dsAnchors.clear();
4969 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4970 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4971
4972 g_luaconfs.setState(luaconfsCopy);
4973
4974 size_t queriesCount = 0;
4975
4976 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) {
4977 queriesCount++;
4978
4979 if (type == QType::DS || type == QType::DNSKEY) {
4980 if (type == QType::DS && domain == target) {
4981 DNSName auth("com.");
4982 setLWResult(res, 0, true, false, true);
4983
4984 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
4985 addRRSIG(keys, res->d_records, auth, 300);
4986 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
4987 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
4988 addRRSIG(keys, res->d_records, auth, 300);
4989 return 1;
4990 }
4991 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
4992 }
4993 else {
4994 if (isRootServer(ip)) {
4995 setLWResult(res, 0, false, false, true);
4996 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4997 addDS(DNSName("com."), 300, res->d_records, keys);
4998 addRRSIG(keys, res->d_records, DNSName("."), 300);
4999 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5000 return 1;
5001 }
5002 else if (ip == ComboAddress("192.0.2.1:53")) {
5003 setLWResult(res, 0, true, false, true);
5004 /* no data */
5005 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5006 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5007 /* no record for this name */
5008 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
5009 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5010 /* a wildcard matches but has no record for this type */
5011 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5012 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5013 return 1;
5014 }
5015 }
5016
5017 return 0;
5018 });
5019
5020 vector<DNSRecord> ret;
5021 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5022 BOOST_CHECK_EQUAL(res, RCode::NoError);
5023 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5024 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5025 BOOST_CHECK_EQUAL(queriesCount, 6);
5026
5027 /* again, to test the cache */
5028 ret.clear();
5029 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5030 BOOST_CHECK_EQUAL(res, RCode::NoError);
5031 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5032 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5033 BOOST_CHECK_EQUAL(queriesCount, 6);
5034}
5035
5036BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
5037 std::unique_ptr<SyncRes> sr;
5038 initSR(sr, true);
5039
5040 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5041
5042 primeHints();
5043 const DNSName target("www.com.");
5044 testkeysset_t keys;
5045
5046 auto luaconfsCopy = g_luaconfs.getCopy();
5047 luaconfsCopy.dsAnchors.clear();
5048 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5049 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5050
5051 g_luaconfs.setState(luaconfsCopy);
5052
5053 size_t queriesCount = 0;
5054
5055 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) {
5056 queriesCount++;
5057
5058 if (type == QType::DS || type == QType::DNSKEY) {
5059 if (type == QType::DS && domain == target) {
5060 DNSName auth("com.");
5061 setLWResult(res, 0, true, false, true);
5062
5063 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5064 addRRSIG(keys, res->d_records, auth, 300);
5065 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5066 /* first the closest encloser */
5067 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5068 addRRSIG(keys, res->d_records, auth, 300);
5069 /* then the next closer */
5070 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5071 addRRSIG(keys, res->d_records, auth, 300);
5072 /* a wildcard matches but has no record for this type */
5073 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5074 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5075 return 1;
5076 }
5077 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5078 }
5079 else {
5080 if (isRootServer(ip)) {
5081 setLWResult(res, 0, false, false, true);
5082 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5083 addDS(DNSName("com."), 300, res->d_records, keys);
5084 addRRSIG(keys, res->d_records, DNSName("."), 300);
5085 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5086 return 1;
5087 }
5088 else if (ip == ComboAddress("192.0.2.1:53")) {
5089 setLWResult(res, 0, true, false, true);
5090 /* no data */
5091 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5092 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5093 /* no record for this name */
5094 /* first the closest encloser */
5095 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5096 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5097 /* then the next closer */
5098 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5099 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5100 /* a wildcard matches but has no record for this type */
5101 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5102 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5103 return 1;
5104 }
5105 }
5106
5107 return 0;
5108 });
5109
5110 vector<DNSRecord> ret;
5111 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5112 BOOST_CHECK_EQUAL(res, RCode::NoError);
5113 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5114 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5115 BOOST_CHECK_EQUAL(queriesCount, 6);
5116
5117 /* again, to test the cache */
5118 ret.clear();
5119 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5120 BOOST_CHECK_EQUAL(res, RCode::NoError);
5121 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5122 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5123 BOOST_CHECK_EQUAL(queriesCount, 6);
5124}
5125
b7c40613
RG
5126BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5127 std::unique_ptr<SyncRes> sr;
5128 initSR(sr, true);
5129
5130 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5131
5132 primeHints();
5133 const DNSName target("www.com.");
5134 testkeysset_t keys;
5135
5136 auto luaconfsCopy = g_luaconfs.getCopy();
5137 luaconfsCopy.dsAnchors.clear();
5138 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5139 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5140
5141 g_luaconfs.setState(luaconfsCopy);
5142
5143 size_t queriesCount = 0;
5144
5145 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) {
5146 queriesCount++;
5147
5148 if (type == QType::DS || type == QType::DNSKEY) {
5149 if (type == QType::DS && domain == target) {
5150 DNSName auth("com.");
5151 setLWResult(res, 0, true, false, true);
5152
5153 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5154 addRRSIG(keys, res->d_records, auth, 300);
5155 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5156 /* first the closest encloser */
5157 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5158 addRRSIG(keys, res->d_records, auth, 300);
5159 /* then the next closer */
5160 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5161 addRRSIG(keys, res->d_records, auth, 300);
5162 /* a wildcard matches but has no record for this type */
5163 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5164 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5165 return 1;
5166 }
5167 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5168 }
5169 else {
5170 if (isRootServer(ip)) {
5171 setLWResult(res, 0, false, false, true);
5172 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5173 addDS(DNSName("com."), 300, res->d_records, keys);
5174 addRRSIG(keys, res->d_records, DNSName("."), 300);
5175 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5176 return 1;
5177 }
5178 else if (ip == ComboAddress("192.0.2.1:53")) {
5179 setLWResult(res, 0, true, false, true);
5180 /* no data */
5181 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5182 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5183 /* no record for this name */
5184 /* first the closest encloser */
5185 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5186 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5187 /* then the next closer */
5188 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5189 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5190 /* a wildcard matches but has no record for this type */
5191 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5192 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5193 return 1;
5194 }
5195 }
5196
5197 return 0;
5198 });
5199
5200 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5201 vector<DNSRecord> ret;
5202 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5203 BOOST_CHECK_EQUAL(res, RCode::NoError);
5204 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5205 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5206 BOOST_CHECK_EQUAL(queriesCount, 6);
5207
5208 /* again, to test the cache */
5209 ret.clear();
5210 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5211 BOOST_CHECK_EQUAL(res, RCode::NoError);
5212 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5213 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5214 BOOST_CHECK_EQUAL(queriesCount, 6);
5215}
5216
9b061cf5
RG
5217BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5218 std::unique_ptr<SyncRes> sr;
5219 initSR(sr, true);
5220
5221 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5222
5223 primeHints();
5224 const DNSName target("www.powerdns.com.");
5225 testkeysset_t keys;
5226
5227 auto luaconfsCopy = g_luaconfs.getCopy();
5228 luaconfsCopy.dsAnchors.clear();
5229 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5230 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5231 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5232
5233 g_luaconfs.setState(luaconfsCopy);
5234
5235 size_t queriesCount = 0;
5236
5237 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) {
5238 queriesCount++;
5239
5240 if (type == QType::DS || type == QType::DNSKEY) {
5241 if (type == QType::DS && domain == target) {
5242 setLWResult(res, RCode::NoError, true, false, true);
5243 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5244 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5245 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5246 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5247 return 1;
5248 }
5249 else {
5250 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5251 }
5252 }
5253 else {
5254 if (isRootServer(ip)) {
5255 setLWResult(res, 0, false, false, true);
5256 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5257 addDS(DNSName("com."), 300, res->d_records, keys);
5258 addRRSIG(keys, res->d_records, DNSName("."), 300);
5259 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5260 return 1;
5261 }
5262 else if (ip == ComboAddress("192.0.2.1:53")) {
5263 if (domain == DNSName("com.")) {
5264 setLWResult(res, 0, true, false, true);
5265 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5266 addRRSIG(keys, res->d_records, domain, 300);
5267 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5268 addRRSIG(keys, res->d_records, domain, 300);
5269 }
5270 else {
5271 setLWResult(res, 0, false, false, true);
5272 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5273 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5274 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5275 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5276 }
5277 return 1;
5278 }
5279 else if (ip == ComboAddress("192.0.2.2:53")) {
5280 setLWResult(res, 0, true, false, true);
5281 if (type == QType::NS) {
5282 if (domain == DNSName("powerdns.com.")) {
5283 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5284 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5285 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5286 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5287 }
5288 else {
5289 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5290 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5291 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5292 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5293 }
5294 }
5295 else {
5296 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5297 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5298 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5299 /* first the closest encloser */
5300 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5301 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5302 /* then the next closer */
5303 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5304 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5305 }
5306 return 1;
5307 }
5308 }
5309
5310 return 0;
5311 });
5312
5313 vector<DNSRecord> ret;
5314 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5315 BOOST_CHECK_EQUAL(res, RCode::NoError);
5316 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5317 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5318 BOOST_CHECK_EQUAL(queriesCount, 9);
5319
5320 /* again, to test the cache */
5321 ret.clear();
5322 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5323 BOOST_CHECK_EQUAL(res, RCode::NoError);
5324 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5325 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5326 BOOST_CHECK_EQUAL(queriesCount, 9);
5327}
5328
b7c40613
RG
5329BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5330 std::unique_ptr<SyncRes> sr;
5331 initSR(sr, true);
5332
5333 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5334
5335 primeHints();
5336 const DNSName target("www.powerdns.com.");
5337 testkeysset_t keys;
5338
5339 auto luaconfsCopy = g_luaconfs.getCopy();
5340 luaconfsCopy.dsAnchors.clear();
5341 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5342 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5343 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5344
5345 g_luaconfs.setState(luaconfsCopy);
5346
5347 size_t queriesCount = 0;
5348
5349 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) {
5350 queriesCount++;
5351
5352 if (type == QType::DS || type == QType::DNSKEY) {
5353 if (type == QType::DS && domain == target) {
5354 setLWResult(res, RCode::NoError, true, false, true);
5355 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5356 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5357 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5358 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5359 return 1;
5360 }
5361 else {
5362 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5363 }
5364 }
5365 else {
5366 if (isRootServer(ip)) {
5367 setLWResult(res, 0, false, false, true);
5368 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5369 addDS(DNSName("com."), 300, res->d_records, keys);
5370 addRRSIG(keys, res->d_records, DNSName("."), 300);
5371 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5372 return 1;
5373 }
5374 else if (ip == ComboAddress("192.0.2.1:53")) {
5375 if (domain == DNSName("com.")) {
5376 setLWResult(res, 0, true, false, true);
5377 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5378 addRRSIG(keys, res->d_records, domain, 300);
5379 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5380 addRRSIG(keys, res->d_records, domain, 300);
5381 }
5382 else {
5383 setLWResult(res, 0, false, false, true);
5384 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5385 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5386 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5387 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5388 }
5389 return 1;
5390 }
5391 else if (ip == ComboAddress("192.0.2.2:53")) {
5392 setLWResult(res, 0, true, false, true);
5393 if (type == QType::NS) {
5394 if (domain == DNSName("powerdns.com.")) {
5395 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5396 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5397 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5398 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5399 }
5400 else {
5401 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5402 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5403 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5404 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5405 }
5406 }
5407 else {
5408 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5409 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5410 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5411 /* first the closest encloser */
5412 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5413 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5414 /* then the next closer */
5415 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5416 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5417 }
5418 return 1;
5419 }
5420 }
5421
5422 return 0;
5423 });
5424
5425 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5426 we should end up Insecure */
5427 vector<DNSRecord> ret;
5428 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5429 BOOST_CHECK_EQUAL(res, RCode::NoError);
5430 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5431 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5432 BOOST_CHECK_EQUAL(queriesCount, 9);
5433
5434 /* again, to test the cache */
5435 ret.clear();
5436 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5437 BOOST_CHECK_EQUAL(res, RCode::NoError);
5438 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5439 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5440 BOOST_CHECK_EQUAL(queriesCount, 9);
5441}
5442
9b061cf5
RG
5443BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5444 std::unique_ptr<SyncRes> sr;
5445 initSR(sr, true);
5446
5447 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5448
5449 primeHints();
5450 const DNSName target("www.powerdns.com.");
5451 testkeysset_t keys;
5452
5453 auto luaconfsCopy = g_luaconfs.getCopy();
5454 luaconfsCopy.dsAnchors.clear();
5455 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5456 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5457 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5458
5459 g_luaconfs.setState(luaconfsCopy);
5460
5461 size_t queriesCount = 0;
5462
5463 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) {
5464 queriesCount++;
5465
5466 if (type == QType::DS || type == QType::DNSKEY) {
5467 if (type == QType::DS && domain == target) {
5468 setLWResult(res, RCode::NoError, true, false, true);
5469 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5470 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5471 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5472 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5473 return 1;
5474 }
5475 else {
5476 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5477 }
5478 }
5479 else {
5480 if (isRootServer(ip)) {
5481 setLWResult(res, 0, false, false, true);
5482 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5483 addDS(DNSName("com."), 300, res->d_records, keys);
5484 addRRSIG(keys, res->d_records, DNSName("."), 300);
5485 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5486 return 1;
5487 }
5488 else if (ip == ComboAddress("192.0.2.1:53")) {
5489 if (domain == DNSName("com.")) {
5490 setLWResult(res, 0, true, false, true);
5491 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5492 addRRSIG(keys, res->d_records, domain, 300);
5493 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5494 addRRSIG(keys, res->d_records, domain, 300);
5495 }
5496 else {
5497 setLWResult(res, 0, false, false, true);
5498 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5499 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5500 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5501 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5502 }
5503 return 1;
5504 }
5505 else if (ip == ComboAddress("192.0.2.2:53")) {
5506 setLWResult(res, 0, true, false, true);
5507 if (type == QType::NS) {
5508 if (domain == DNSName("powerdns.com.")) {
5509 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5510 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5511 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5512 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5513 }
5514 else {
5515 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5516 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5517 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5518 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5519 }
5520 }
5521 else {
5522 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5523 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5524 }
5525 return 1;
5526 }
5527 }
5528
5529 return 0;
5530 });
5531
5532 vector<DNSRecord> ret;
5533 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5534 BOOST_CHECK_EQUAL(res, RCode::NoError);
5535 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5536 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5537 BOOST_CHECK_EQUAL(queriesCount, 9);
5538
5539 /* again, to test the cache */
5540 ret.clear();
5541 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5542 BOOST_CHECK_EQUAL(res, RCode::NoError);
5543 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5544 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5545 BOOST_CHECK_EQUAL(queriesCount, 9);
5546}
5547
a53e8fe3
RG
5548BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5549 std::unique_ptr<SyncRes> sr;
5550 initSR(sr, true);
5551
0c43f455 5552 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
5553
5554 primeHints();
5555 const DNSName target("www.powerdns.com.");
5556 testkeysset_t keys;
5557
5558 auto luaconfsCopy = g_luaconfs.getCopy();
5559 luaconfsCopy.dsAnchors.clear();
5560 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5561 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5562 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5563
5564 g_luaconfs.setState(luaconfsCopy);
5565
5566 size_t queriesCount = 0;
5567 size_t dsQueriesCount = 0;
5568
5569 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) {
5570 queriesCount++;
5571
5572 if (type == QType::DS) {
5573 DNSName auth(domain);
5574 auth.chopOff();
5575 dsQueriesCount++;
5576
5577 setLWResult(res, 0, true, false, true);
5578 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5579 addRRSIG(keys, res->d_records, auth, 300);
5580 return 1;
5581 }
5582 else if (type == QType::DNSKEY) {
5583 setLWResult(res, 0, true, false, true);
5584 addDNSKEY(keys, domain, 300, res->d_records);
5585 addRRSIG(keys, res->d_records, domain, 300);
5586 return 1;
5587 }
f24465e5 5588 else {
a53e8fe3
RG
5589 if (isRootServer(ip)) {
5590 setLWResult(res, 0, false, false, true);
5591 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5592 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5593 /* No DS on referral, and no denial of the DS either */
5594 return 1;
5595 }
5596 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5597 if (domain == DNSName("com.")) {
5598 setLWResult(res, 0, true, false, true);
5599 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5600 addRRSIG(keys, res->d_records, domain, 300);
5601 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5602 addRRSIG(keys, res->d_records, domain, 300);
5603 }
5604 else {
5605 setLWResult(res, 0, false, false, true);
5606 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5607 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5608 /* No DS on referral, and no denial of the DS either */
5609 }
a53e8fe3
RG
5610 return 1;
5611 }
5612 else if (ip == ComboAddress("192.0.2.2:53")) {
5613 setLWResult(res, 0, true, false, true);
f24465e5
RG
5614 if (type == QType::NS) {
5615 if (domain == DNSName("powerdns.com.")) {
5616 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5617 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5618 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5619 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5620 }
5621 else {
5622 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5623 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5624 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5625 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5626 }
5627 }
5628 else {
5629 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5630 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5631 }
5632
a53e8fe3
RG
5633 return 1;
5634 }
5635 }
5636
5637 return 0;
5638 });
5639
5640 vector<DNSRecord> ret;
5641 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5642 BOOST_CHECK_EQUAL(res, RCode::NoError);
5643 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 5644 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
5645 BOOST_CHECK_EQUAL(queriesCount, 9);
5646 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
5647
5648 /* again, to test the cache */
5649 ret.clear();
5650 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5651 BOOST_CHECK_EQUAL(res, RCode::NoError);
5652 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 5653 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
5654 BOOST_CHECK_EQUAL(queriesCount, 9);
5655 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
5656}
5657
f715542c
RG
5658BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
5659 std::unique_ptr<SyncRes> sr;
5660 initSR(sr, true);
5661
5d7b19c5 5662 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
f715542c
RG
5663
5664 primeHints();
5665 const DNSName target("www.powerdns.com.");
5666 testkeysset_t keys;
5667
5668 auto luaconfsCopy = g_luaconfs.getCopy();
5669 luaconfsCopy.dsAnchors.clear();
5670 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5671 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3cef03e9 5672 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
f715542c
RG
5673 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5674
5675 g_luaconfs.setState(luaconfsCopy);
5676
5677 size_t queriesCount = 0;
5678
5679 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) {
5680 queriesCount++;
5681
5682 if (type == QType::DS) {
5683 DNSName auth(domain);
5684 auth.chopOff();
5685
5686 setLWResult(res, 0, true, false, true);
5687 if (domain == target) {
5688 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5689 addRRSIG(keys, res->d_records, target, 300);
5690 }
5691 else {
5692 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5693 addRRSIG(keys, res->d_records, auth, 300);
5694 }
5695 return 1;
5696 }
5697 else if (type == QType::DNSKEY) {
5698 setLWResult(res, 0, true, false, true);
5699 addDNSKEY(keys, domain, 300, res->d_records);
5700 addRRSIG(keys, res->d_records, domain, 300);
5701 return 1;
5702 }
5703 else {
5704 if (isRootServer(ip)) {
5705 setLWResult(res, 0, false, false, true);
5706 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5707 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5708 addDS(DNSName("com."), 300, res->d_records, keys);
5709 addRRSIG(keys, res->d_records, DNSName("."), 300);
5710 return 1;
5711 }
5712 else if (ip == ComboAddress("192.0.2.1:53")) {
5713 if (domain == DNSName("com.")) {
5714 setLWResult(res, 0, true, false, true);
5715 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5716 addRRSIG(keys, res->d_records, domain, 300);
5717 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5718 addRRSIG(keys, res->d_records, domain, 300);
5719 }
5720 else {
5721 setLWResult(res, 0, false, false, true);
5722 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5723 /* no DS */
5724 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
5725 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5726 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5727 }
5728 return 1;
5729 }
5730 else if (ip == ComboAddress("192.0.2.2:53")) {
5731 if (type == QType::NS) {
5732 if (domain == DNSName("powerdns.com.")) {
5733 setLWResult(res, RCode::Refused, false, false, true);
5734 }
5735 else {
5736 setLWResult(res, 0, true, false, true);
5737 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5738 addRRSIG(keys, res->d_records, domain, 300);
5739 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5740 addRRSIG(keys, res->d_records, domain, 300);
5741 }
5742 }
5743 else {
5744 setLWResult(res, 0, true, false, true);
5745 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5746 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
5747 }
5748
5749 return 1;
5750 }
5751 }
5752
5753 return 0;
5754 });
5755
5756 vector<DNSRecord> ret;
5757 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5758 BOOST_CHECK_EQUAL(res, RCode::NoError);
5759 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5760 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 5761 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
5762
5763 /* again, to test the cache */
5764 ret.clear();
5765 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5766 BOOST_CHECK_EQUAL(res, RCode::NoError);
5767 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5768 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 5769 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
5770}
5771
a53e8fe3
RG
5772BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
5773 std::unique_ptr<SyncRes> sr;
f24465e5 5774 initSR(sr, true);
a53e8fe3 5775
0c43f455 5776 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
5777
5778 primeHints();
5779 const DNSName target("www.powerdns.com.");
5780 testkeysset_t keys;
5781
5782 auto luaconfsCopy = g_luaconfs.getCopy();
5783 luaconfsCopy.dsAnchors.clear();
5784 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5785 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5786
5787 g_luaconfs.setState(luaconfsCopy);
5788
5789 size_t queriesCount = 0;
5790 size_t dsQueriesCount = 0;
5791
5792 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) {
5793 queriesCount++;
5794
5795 if (type == QType::DS) {
5796 DNSName auth(domain);
5797 auth.chopOff();
5798 dsQueriesCount++;
5799
5800 setLWResult(res, 0, true, false, true);
5801 if (domain == DNSName("com.")) {
5802 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5803 }
5804 else {
f24465e5
RG
5805 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5806 addRRSIG(keys, res->d_records, DNSName("com."), 300);
a53e8fe3
RG
5807 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
5808 }
5809 addRRSIG(keys, res->d_records, auth, 300);
5810 return 1;
5811 }
5812 else if (type == QType::DNSKEY) {
5813 setLWResult(res, 0, true, false, true);
5814 addDNSKEY(keys, domain, 300, res->d_records);
5815 addRRSIG(keys, res->d_records, domain, 300);
5816 return 1;
5817 }
a69867f2 5818 else {
a53e8fe3
RG
5819 if (isRootServer(ip)) {
5820 setLWResult(res, 0, false, false, true);
5821 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5822 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5823 /* No DS on referral, and no denial of the DS either */
5824 return 1;
5825 }
5826 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
5827 if (domain == DNSName("com.")) {
5828 setLWResult(res, 0, true, false, true);
5829 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
f24465e5 5830 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 5831 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
f24465e5 5832 addRRSIG(keys, res->d_records, domain, 300);
a69867f2
RG
5833 }
5834 else {
5835 setLWResult(res, 0, false, false, true);
5836 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5837 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5838 /* No DS on referral, and no denial of the DS either */
5839 }
a53e8fe3
RG
5840 return 1;
5841 }
5842 else if (ip == ComboAddress("192.0.2.2:53")) {
5843 setLWResult(res, 0, true, false, true);
f24465e5
RG
5844 if (type == QType::NS) {
5845 if (domain == DNSName("powerdns.com.")) {
5846 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5847 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5848 }
5849 else {
5850 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5851 }
5852 }
5853 else {
5854 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5855 }
a53e8fe3
RG
5856 return 1;
5857 }
5858 }
5859
5860 return 0;
5861 });
5862
5863 vector<DNSRecord> ret;
5864 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5865 BOOST_CHECK_EQUAL(res, RCode::NoError);
5866 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5867 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 5868 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
5869 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
5870
5871 /* again, to test the cache */
5872 ret.clear();
5873 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5874 BOOST_CHECK_EQUAL(res, RCode::NoError);
5875 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5876 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 5877 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
5878 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
5879}
5880
e59c8907 5881BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
b7f378d1 5882 std::unique_ptr<SyncRes> sr;
895449a5 5883 initSR(sr, true);
b7f378d1 5884
0c43f455 5885 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5886
5887 primeHints();
5888 const DNSName target("powerdns.com.");
5889 testkeysset_t keys;
5890
5891 auto luaconfsCopy = g_luaconfs.getCopy();
5892 luaconfsCopy.dsAnchors.clear();
5893 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5894 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5895 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5896
5897 g_luaconfs.setState(luaconfsCopy);
5898
5899 size_t queriesCount = 0;
5900
5901 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) {
5902 queriesCount++;
5903
5374b03b
RG
5904 if (type == QType::DS || type == QType::DNSKEY) {
5905 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 5906 }
a69867f2 5907 else {
b7f378d1
RG
5908 if (isRootServer(ip)) {
5909 setLWResult(res, 0, false, false, true);
5910 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5911 addDS(DNSName("com."), 300, res->d_records, keys);
5912 addRRSIG(keys, res->d_records, DNSName("."), 300);
5913 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5914 return 1;
5915 }
5916 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
5917 if (domain == DNSName("com.")) {
5918 setLWResult(res, 0, true, false, true);
5919 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
5920 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5921 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5922 }
5923 else {
5924 setLWResult(res, 0, false, false, true);
5925 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5926 addDS(domain, 300, res->d_records, keys);
5927 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5928 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5929 }
b7f378d1
RG
5930 return 1;
5931 }
5932 else if (ip == ComboAddress("192.0.2.2:53")) {
5933 setLWResult(res, 0, true, false, true);
a69867f2
RG
5934 if (type == QType::NS) {
5935 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5936 addRRSIG(keys, res->d_records, domain, 300);
5937 }
5938 else {
5939 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5940 addRRSIG(keys, res->d_records, domain, 300);
5941 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
5942 /* NO RRSIG for the NSEC record! */
5943 }
b7f378d1
RG
5944 return 1;
5945 }
5946 }
5947
5948 return 0;
5949 });
5950
5951 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
5952 vector<DNSRecord> ret;
5953 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5954 BOOST_CHECK_EQUAL(res, RCode::NoError);
5955 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5956 BOOST_CHECK_EQUAL(ret.size(), 3);
a69867f2 5957 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5958
5959 /* again, to test the cache */
5960 ret.clear();
5961 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5962 BOOST_CHECK_EQUAL(res, RCode::NoError);
5963 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5964 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 5965 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5966}
5967
e59c8907 5968BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
b7f378d1 5969 std::unique_ptr<SyncRes> sr;
895449a5 5970 initSR(sr, true);
b7f378d1 5971
0c43f455 5972 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5973
5974 primeHints();
5975 const DNSName target("powerdns.com.");
5976 testkeysset_t keys;
5977
5978 auto luaconfsCopy = g_luaconfs.getCopy();
5979 luaconfsCopy.dsAnchors.clear();
5980 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5981 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5982 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5983
5984 g_luaconfs.setState(luaconfsCopy);
5985
5986 size_t queriesCount = 0;
5987
5988 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) {
5989 queriesCount++;
5990
5374b03b
RG
5991 if (type == QType::DS || type == QType::DNSKEY) {
5992 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 5993 }
a69867f2 5994 else {
b7f378d1
RG
5995 if (isRootServer(ip)) {
5996 setLWResult(res, 0, false, false, true);
5997 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5998 addDS(DNSName("com."), 300, res->d_records, keys);
5999 addRRSIG(keys, res->d_records, DNSName("."), 300);
6000 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6001 return 1;
6002 }
6003 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6004 if (domain == DNSName("com.")) {
6005 setLWResult(res, 0, true, false, true);
6006 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6007 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6008 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6009 }
6010 else {
6011 setLWResult(res, 0, false, false, true);
6012 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6013 addDS(domain, 300, res->d_records, keys);
6014 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6015 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6016 }
b7f378d1
RG
6017 return 1;
6018 }
6019 else if (ip == ComboAddress("192.0.2.2:53")) {
6020 setLWResult(res, 0, true, false, true);
a69867f2
RG
6021 if (type == QType::NS) {
6022 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6023 addRRSIG(keys, res->d_records, domain, 300);
6024 }
6025 else {
6026 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6027 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 6028
a69867f2
RG
6029 /* NO NSEC record! */
6030 }
b7f378d1
RG
6031 return 1;
6032 }
6033 }
6034
6035 return 0;
6036 });
6037
6038 /* no NSEC record in a secure zone, should be Bogus! */
6039 vector<DNSRecord> ret;
6040 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6041 BOOST_CHECK_EQUAL(res, RCode::NoError);
6042 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6043 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 6044 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6045
6046 /* again, to test the cache */
6047 ret.clear();
6048 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6049 BOOST_CHECK_EQUAL(res, RCode::NoError);
6050 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6051 BOOST_REQUIRE_EQUAL(ret.size(), 2);
a69867f2 6052 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6053}
6054
6055BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6056 std::unique_ptr<SyncRes> sr;
895449a5 6057 initSR(sr, true);
b7f378d1 6058
0c43f455 6059 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6060
6061 primeHints();
6062 const DNSName target("powerdns.com.");
6063 const ComboAddress targetAddr("192.0.2.42");
6064 testkeysset_t keys;
6065
6066 auto luaconfsCopy = g_luaconfs.getCopy();
6067 luaconfsCopy.dsAnchors.clear();
6068 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6069 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6070
6071 g_luaconfs.setState(luaconfsCopy);
6072
6073 size_t queriesCount = 0;
6074
6075 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) {
6076 queriesCount++;
6077
6078 if (type == QType::DS) {
a53e8fe3 6079 if (domain == target) {
b7f378d1 6080 setLWResult(res, 0, false, false, true);
895449a5 6081 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6082 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6083 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6084 return 1;
5374b03b
RG
6085 } else {
6086 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1
RG
6087 }
6088 }
6089 else if (type == QType::DNSKEY) {
6090 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6091 setLWResult(res, 0, true, false, true);
6092 addDNSKEY(keys, domain, 300, res->d_records);
6093 addRRSIG(keys, res->d_records, domain, 300);
6094 return 1;
6095 }
6096 else {
6097 setLWResult(res, 0, false, false, true);
895449a5 6098 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6099 return 1;
6100 }
6101 }
a69867f2 6102 else {
b7f378d1
RG
6103 if (isRootServer(ip)) {
6104 setLWResult(res, 0, false, false, true);
6105 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6106 addDS(DNSName("com."), 300, res->d_records, keys);
6107 addRRSIG(keys, res->d_records, DNSName("."), 300);
6108 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6109 return 1;
6110 }
6111 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6112 if (domain == DNSName("com.")) {
6113 setLWResult(res, 0, true, false, true);
6114 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6115 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6116 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6117 }
6118 else {
6119 setLWResult(res, 0, false, false, true);
6120 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6121 /* no DS */
6122 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6123 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6124 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6125 }
b7f378d1
RG
6126 return 1;
6127 }
6128 else if (ip == ComboAddress("192.0.2.2:53")) {
6129 setLWResult(res, 0, true, false, true);
a69867f2
RG
6130 if (type == QType::NS) {
6131 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6132 }
6133 else {
6134 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6135 }
b7f378d1
RG
6136 return 1;
6137 }
6138 }
6139
6140 return 0;
6141 });
6142
6143 vector<DNSRecord> ret;
6144 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6145 BOOST_CHECK_EQUAL(res, RCode::NoError);
6146 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6147 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6148 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2
RG
6149 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6150 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6151 1 query for A */
6152 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6153
6154 /* again, to test the cache */
6155 ret.clear();
6156 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6157 BOOST_CHECK_EQUAL(res, RCode::NoError);
6158 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6159 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6160 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2 6161 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6162}
6163
3cef03e9
RG
6164
6165BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6166 /*
6167 Direct DS query:
6168 - parent is secure, zone is secure: DS should be secure
6169 */
6170 std::unique_ptr<SyncRes> sr;
6171 initSR(sr, true);
6172
6173 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6174
6175 primeHints();
6176 const DNSName target("powerdns.com.");
6177 testkeysset_t keys;
6178
6179 auto luaconfsCopy = g_luaconfs.getCopy();
6180 luaconfsCopy.dsAnchors.clear();
6181 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6182 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6183 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6184
6185 g_luaconfs.setState(luaconfsCopy);
6186
6187 size_t queriesCount = 0;
6188
6189 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) {
6190 queriesCount++;
6191
6192 if (type == QType::DS || type == QType::DNSKEY) {
6193 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6194 }
6195 else {
6196 if (isRootServer(ip)) {
6197 setLWResult(res, 0, false, false, true);
6198 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6199 addDS(DNSName("com."), 300, res->d_records, keys);
6200 addRRSIG(keys, res->d_records, DNSName("."), 300);
6201 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6202 return 1;
6203 }
6204 }
6205
6206 return 0;
6207 });
6208
6209 vector<DNSRecord> ret;
6210 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6211 BOOST_CHECK_EQUAL(res, RCode::NoError);
6212 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6213 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6214 for (const auto& record : ret) {
6215 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6216 }
6217 BOOST_CHECK_EQUAL(queriesCount, 4);
6218
6219 /* again, to test the cache */
6220 ret.clear();
6221 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6222 BOOST_CHECK_EQUAL(res, RCode::NoError);
6223 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6224 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6225 for (const auto& record : ret) {
6226 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6227 }
6228 BOOST_CHECK_EQUAL(queriesCount, 4);
6229}
6230
6231BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6232 /*
6233 Direct DS query:
6234 - parent is secure, zone is insecure: DS denial should be secure
6235 */
6236 std::unique_ptr<SyncRes> sr;
6237 initSR(sr, true);
6238
6239 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6240
6241 primeHints();
6242 const DNSName target("powerdns.com.");
6243 testkeysset_t keys;
6244
6245 auto luaconfsCopy = g_luaconfs.getCopy();
6246 luaconfsCopy.dsAnchors.clear();
6247 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6248 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6249
6250 g_luaconfs.setState(luaconfsCopy);
6251
6252 size_t queriesCount = 0;
6253
6254 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) {
6255 queriesCount++;
6256
6257 if (type == QType::DS || type == QType::DNSKEY) {
6258 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6259 }
6260 else {
6261 if (isRootServer(ip)) {
6262 setLWResult(res, 0, false, false, true);
6263 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6264 addDS(DNSName("com."), 300, res->d_records, keys);
6265 addRRSIG(keys, res->d_records, DNSName("."), 300);
6266 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6267 return 1;
6268 }
6269 }
6270
6271 return 0;
6272 });
6273
6274 vector<DNSRecord> ret;
6275 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6276 BOOST_CHECK_EQUAL(res, RCode::NoError);
6277 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6278 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6279 for (const auto& record : ret) {
6280 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6281 }
6282 BOOST_CHECK_EQUAL(queriesCount, 4);
6283
6284 /* again, to test the cache */
6285 ret.clear();
6286 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6287 BOOST_CHECK_EQUAL(res, RCode::NoError);
6288 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6289 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6290 for (const auto& record : ret) {
6291 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6292 }
6293 BOOST_CHECK_EQUAL(queriesCount, 4);
6294}
6295
70b3fe7a
RG
6296BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6297 std::unique_ptr<SyncRes> sr;
a69867f2 6298 initSR(sr, true);
70b3fe7a 6299
0c43f455 6300 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6301
6302 primeHints();
6303 const DNSName target("www.sub.powerdns.com.");
6304 const ComboAddress targetAddr("192.0.2.42");
6305 testkeysset_t keys;
6306
6307 auto luaconfsCopy = g_luaconfs.getCopy();
6308 luaconfsCopy.dsAnchors.clear();
6309 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6310 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6311 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6312
6313 g_luaconfs.setState(luaconfsCopy);
6314
6315 size_t queriesCount = 0;
6316
6317 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) {
6318 queriesCount++;
6319
6320 if (type == QType::DS) {
6321 if (domain == DNSName("sub.powerdns.com.")) {
6322 setLWResult(res, 0, false, false, true);
6323 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6324 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6325 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6326 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6327 return 1;
6328 }
6329 else if (domain == DNSName("www.sub.powerdns.com.")) {
6330 setLWResult(res, 0, false, false, true);
6331 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);
6332 return 1;
6333 }
5374b03b
RG
6334 else {
6335 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6336 }
70b3fe7a
RG
6337 }
6338 else if (type == QType::DNSKEY) {
a69867f2 6339 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
70b3fe7a
RG
6340 setLWResult(res, 0, true, false, true);
6341 addDNSKEY(keys, domain, 300, res->d_records);
6342 addRRSIG(keys, res->d_records, domain, 300);
6343 return 1;
6344 }
6345 else {
6346 setLWResult(res, 0, false, false, true);
6347 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6348 return 1;
6349 }
6350 }
88cb0fe0 6351 else {
70b3fe7a
RG
6352 if (isRootServer(ip)) {
6353 setLWResult(res, 0, false, false, true);
6354 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6355 addDS(DNSName("com."), 300, res->d_records, keys);
6356 addRRSIG(keys, res->d_records, DNSName("."), 300);
6357 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6358 return 1;
6359 }
6360 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6361 if (domain == DNSName("com.")) {
6362 setLWResult(res, 0, true, false, true);
6363 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6364 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6365 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6366 }
6367 else {
6368 setLWResult(res, 0, false, false, true);
6369 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6370 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6371 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6372 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6373 }
70b3fe7a
RG
6374 return 1;
6375 }
6376 else if (ip == ComboAddress("192.0.2.2:53")) {
6377 setLWResult(res, 0, true, false, true);
a69867f2
RG
6378 if (type == QType::NS) {
6379 if (domain == DNSName("www.sub.powerdns.com.")) {
6380 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);
6381 }
6382 else if (domain == DNSName("sub.powerdns.com.")) {
6383 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
a69867f2
RG
6384 }
6385 else if (domain == DNSName("powerdns.com.")) {
6386 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6387 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6388 }
6389 } else {
6390 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6391 }
70b3fe7a
RG
6392 return 1;
6393 }
6394 }
6395
6396 return 0;
6397 });
6398
6399 vector<DNSRecord> ret;
6400 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6401 BOOST_CHECK_EQUAL(res, RCode::NoError);
6402 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6403 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6404 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6405 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6406
6407 /* again, to test the cache */
6408 ret.clear();
6409 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6410 BOOST_CHECK_EQUAL(res, RCode::NoError);
6411 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6412 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6413 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6414 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6415}
6416
6417BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6418 std::unique_ptr<SyncRes> sr;
a69867f2 6419 initSR(sr, true);
70b3fe7a 6420
0c43f455 6421 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6422
6423 primeHints();
6424 const DNSName target("www.sub.powerdns.com.");
6425 const ComboAddress targetAddr("192.0.2.42");
6426 testkeysset_t keys;
6427
6428 auto luaconfsCopy = g_luaconfs.getCopy();
6429 luaconfsCopy.dsAnchors.clear();
6430 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6431 /* No key material for .com */
6432 /* But TA for sub.powerdns.com. */
6433 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6434 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6435 g_luaconfs.setState(luaconfsCopy);
6436
6437 size_t queriesCount = 0;
6438
6439 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) {
6440 queriesCount++;
6441
6442 if (type == QType::DS) {
88cb0fe0
RG
6443 if (domain == DNSName("www.sub.powerdns.com")) {
6444 setLWResult(res, 0, false, false, true);
6445 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);
6446 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6447 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6448 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6449 }
6450 else {
6451 setLWResult(res, 0, false, false, true);
5374b03b
RG
6452
6453 if (domain == DNSName("com.")) {
6454 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6455 /* no DS */
6456 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6457 addRRSIG(keys, res->d_records, DNSName("."), 300);
6458 }
6459 else {
6460 setLWResult(res, 0, false, false, true);
6461 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6462 }
88cb0fe0 6463 }
70b3fe7a
RG
6464 return 1;
6465 }
6466 else if (type == QType::DNSKEY) {
6467 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
6468 setLWResult(res, 0, true, false, true);
6469 addDNSKEY(keys, domain, 300, res->d_records);
6470 addRRSIG(keys, res->d_records, domain, 300);
6471 return 1;
6472 }
6473 }
88cb0fe0 6474 else {
70b3fe7a
RG
6475 if (isRootServer(ip)) {
6476 setLWResult(res, 0, false, false, true);
6477 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6478 /* no DS */
6479 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6480 addRRSIG(keys, res->d_records, DNSName("."), 300);
6481 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6482 return 1;
6483 }
6484 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
6485 if (domain == DNSName("com.")) {
6486 setLWResult(res, 0, true, false, true);
6487 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6488 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6489 }
5374b03b 6490 else if (domain.isPartOf(DNSName("powerdns.com."))) {
88cb0fe0
RG
6491 setLWResult(res, 0, false, false, true);
6492 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6493 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6494 }
70b3fe7a
RG
6495 return 1;
6496 }
6497 else if (ip == ComboAddress("192.0.2.2:53")) {
6498 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
6499 if (type == QType::NS) {
6500 if (domain == DNSName("www.sub.powerdns.com.")) {
6501 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);
6502 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6503 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6504 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6505 }
6506 else if (domain == DNSName("sub.powerdns.com.")) {
6507 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6508 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6509 }
6510 else if (domain == DNSName("powerdns.com.")) {
6511 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6512 }
6513 }
6514 else if (domain == DNSName("www.sub.powerdns.com.")) {
6515 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6516 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6517 }
70b3fe7a
RG
6518 return 1;
6519 }
6520 }
6521
6522 return 0;
6523 });
6524
6525 vector<DNSRecord> ret;
6526 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6527 BOOST_CHECK_EQUAL(res, RCode::NoError);
6528 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 6529 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 6530 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6531 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
6532
6533 /* again, to test the cache */
6534 ret.clear();
6535 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6536 BOOST_CHECK_EQUAL(res, RCode::NoError);
6537 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 6538 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 6539 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6540 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
6541}
6542
b7f378d1
RG
6543BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
6544 std::unique_ptr<SyncRes> sr;
895449a5 6545 initSR(sr, true);
b7f378d1 6546
0c43f455 6547 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6548
6549 primeHints();
6550 const DNSName target("powerdns.com.");
6551 testkeysset_t keys;
6552
6553 auto luaconfsCopy = g_luaconfs.getCopy();
6554 luaconfsCopy.dsAnchors.clear();
6555 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6556 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6557
6558 g_luaconfs.setState(luaconfsCopy);
6559
6560 size_t queriesCount = 0;
6561
6562 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
6563 queriesCount++;
6564
6565 if (type == QType::DS) {
a53e8fe3 6566 if (domain == target) {
b7f378d1 6567 setLWResult(res, 0, false, false, true);
895449a5 6568 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6569 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6570 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6571 return 1;
6572 }
5374b03b
RG
6573 else {
6574 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6575 }
b7f378d1
RG
6576 }
6577 else if (type == QType::DNSKEY) {
6578 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6579 setLWResult(res, 0, true, false, true);
6580 addDNSKEY(keys, domain, 300, res->d_records);
6581 addRRSIG(keys, res->d_records, domain, 300);
6582 return 1;
6583 }
6584 else {
6585 setLWResult(res, 0, false, false, true);
895449a5 6586 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6587 return 1;
6588 }
6589 }
a69867f2 6590 else {
b7f378d1
RG
6591 if (isRootServer(ip)) {
6592 setLWResult(res, 0, false, false, true);
6593 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6594 addDS(DNSName("com."), 300, res->d_records, keys);
6595 addRRSIG(keys, res->d_records, DNSName("."), 300);
6596 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6597 return 1;
6598 }
6599 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6600 if (domain == DNSName("com.")) {
6601 setLWResult(res, 0, true, false, true);
6602 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6603 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6604 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6605 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6606 }
6607 else {
6608 setLWResult(res, 0, false, false, true);
6609 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6610 /* no DS */
6611 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6612 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6613 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6614 }
b7f378d1
RG
6615 return 1;
6616 }
6617 else if (ip == ComboAddress("192.0.2.2:53")) {
a69867f2
RG
6618 if (type == QType::NS) {
6619 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6620 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6621 }
6622 else {
6623 setLWResult(res, 0, true, false, true);
6624 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6625 }
b7f378d1
RG
6626 return 1;
6627 }
6628 }
6629
6630 return 0;
6631 });
6632
6633 vector<DNSRecord> ret;
6634 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6635 BOOST_CHECK_EQUAL(res, RCode::NoError);
6636 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6637 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2
RG
6638 /* 4 NS (com from root, com from com, powerdns.com from com,
6639 powerdns.com from powerdns.com)
6640 2 DNSKEY (. and com., none for powerdns.com because no DS)
6641 1 query for A
6642 */
6643 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6644
6645 /* again, to test the cache */
6646 ret.clear();
6647 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6648 BOOST_CHECK_EQUAL(res, RCode::NoError);
6649 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6650 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2 6651 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6652}
6653
895449a5 6654BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
b7f378d1 6655 std::unique_ptr<SyncRes> sr;
860d5e8e 6656 initSR(sr, true);
b7f378d1 6657
0c43f455 6658 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1 6659
895449a5
RG
6660 primeHints();
6661 const DNSName target("powerdns.com.");
6662 const DNSName targetCName("power-dns.com.");
6663 const ComboAddress targetCNameAddr("192.0.2.42");
6664 testkeysset_t keys;
6665
6666 auto luaconfsCopy = g_luaconfs.getCopy();
6667 luaconfsCopy.dsAnchors.clear();
6668 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6669 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6670 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6671 g_luaconfs.setState(luaconfsCopy);
6672
6673 size_t queriesCount = 0;
6674
6675 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) {
6676 queriesCount++;
6677
6678 if (type == QType::DS) {
5374b03b 6679 if (domain == targetCName) {
895449a5
RG
6680 setLWResult(res, 0, false, false, true);
6681 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6682 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6683 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6684 return 1;
6685 }
5374b03b
RG
6686 else {
6687 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6688 }
895449a5
RG
6689 }
6690 else if (type == QType::DNSKEY) {
6691 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6692 setLWResult(res, 0, true, false, true);
6693 addDNSKEY(keys, domain, 300, res->d_records);
6694 addRRSIG(keys, res->d_records, domain, 300);
6695 return 1;
6696 }
6697 else {
6698 setLWResult(res, 0, false, false, true);
6699 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6700 return 1;
6701 }
6702 }
6703 else {
6704 if (isRootServer(ip)) {
6705 setLWResult(res, 0, false, false, true);
6706 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6707 addDS(DNSName("com."), 300, res->d_records, keys);
6708 addRRSIG(keys, res->d_records, DNSName("."), 300);
6709 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6710 return 1;
6711 }
6712 else if (ip == ComboAddress("192.0.2.1:53")) {
6713 setLWResult(res, 0, false, false, true);
a69867f2
RG
6714 if (domain == DNSName("com.")) {
6715 setLWResult(res, 0, true, false, true);
6716 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6717 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6718 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6719 addRRSIG(keys, res->d_records, DNSName("com."), 300);
895449a5 6720 }
a69867f2
RG
6721 else {
6722 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6723 if (domain == DNSName("powerdns.com.")) {
6724 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6725 }
6726 else if (domain == targetCName) {
6727 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6728 }
6729 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6730 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
895449a5 6731 }
a69867f2 6732
895449a5
RG
6733 return 1;
6734 }
6735 else if (ip == ComboAddress("192.0.2.2:53")) {
6736 setLWResult(res, 0, true, false, true);
a69867f2
RG
6737
6738 if (type == QType::NS) {
6739 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6740 if (domain == DNSName("powerdns.com.")) {
6741 addRRSIG(keys, res->d_records, domain, 300);
6742 }
6743 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6744 if (domain == DNSName("powerdns.com.")) {
6745 addRRSIG(keys, res->d_records, domain, 300);
6746 }
895449a5 6747 }
a69867f2
RG
6748 else {
6749 if (domain == DNSName("powerdns.com.")) {
6750 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6751 addRRSIG(keys, res->d_records, domain, 300);
6752 }
6753 else if (domain == targetCName) {
6754 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6755 }
895449a5 6756 }
a69867f2 6757
895449a5
RG
6758 return 1;
6759 }
6760 }
6761
6762 return 0;
6763 });
6764
6765 vector<DNSRecord> ret;
6766 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6767 BOOST_CHECK_EQUAL(res, RCode::NoError);
6768 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6769 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 6770 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
6771
6772 /* again, to test the cache */
6773 ret.clear();
6774 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6775 BOOST_CHECK_EQUAL(res, RCode::NoError);
6776 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6777 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 6778 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
6779}
6780
3d5ebf10
RG
6781BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
6782 std::unique_ptr<SyncRes> sr;
6783 initSR(sr, true);
6784
0c43f455 6785 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
6786
6787 primeHints();
6788 const DNSName target("power-dns.com.");
6789 const DNSName targetCName("powerdns.com.");
6790 const ComboAddress targetCNameAddr("192.0.2.42");
6791 testkeysset_t keys;
6792
6793 auto luaconfsCopy = g_luaconfs.getCopy();
6794 luaconfsCopy.dsAnchors.clear();
6795 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6796 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6797 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6798 g_luaconfs.setState(luaconfsCopy);
6799
6800 size_t queriesCount = 0;
6801
6802 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) {
6803 queriesCount++;
6804
6805 if (type == QType::DS) {
a53e8fe3 6806 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
6807 setLWResult(res, 0, false, false, true);
6808 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6809 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6810 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6811 return 1;
6812 }
5374b03b
RG
6813 else {
6814 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6815 }
3d5ebf10
RG
6816 }
6817 else if (type == QType::DNSKEY) {
6818 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
6819 setLWResult(res, 0, true, false, true);
6820 addDNSKEY(keys, domain, 300, res->d_records);
6821 addRRSIG(keys, res->d_records, domain, 300);
6822 return 1;
6823 }
6824 else {
6825 setLWResult(res, 0, false, false, true);
6826 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6827 return 1;
6828 }
6829 }
6830 else {
6831 if (isRootServer(ip)) {
6832 setLWResult(res, 0, false, false, true);
6833 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6834 addDS(DNSName("com."), 300, res->d_records, keys);
6835 addRRSIG(keys, res->d_records, DNSName("."), 300);
6836 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6837 return 1;
6838 }
6839 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6840 if (domain == DNSName("com.")) {
6841 setLWResult(res, 0, true, false, true);
6842 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6843 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6844 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6845 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 6846 }
a69867f2
RG
6847 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
6848 setLWResult(res, 0, false, false, true);
6849 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6850 if (domain == targetCName) {
6851 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6852 }
6853 else if (domain == target) {
6854 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
6855 }
6856 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6857 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 6858 }
3d5ebf10
RG
6859 return 1;
6860 }
6861 else if (ip == ComboAddress("192.0.2.2:53")) {
6862 setLWResult(res, 0, true, false, true);
a69867f2
RG
6863 if (type == QType::NS) {
6864 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6865 if (domain == DNSName("powerdns.com.")) {
6866 addRRSIG(keys, res->d_records, domain, 300);
6867 }
6868 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6869 if (domain == DNSName("powerdns.com.")) {
6870 addRRSIG(keys, res->d_records, domain, 300);
6871 }
3d5ebf10 6872 }
a69867f2
RG
6873 else {
6874 if (domain == target) {
6875 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6876 }
6877 else if (domain == targetCName) {
6878 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6879 addRRSIG(keys, res->d_records, domain, 300);
6880 }
3d5ebf10
RG
6881 }
6882 return 1;
6883 }
6884 }
6885
6886 return 0;
6887 });
6888
6889 vector<DNSRecord> ret;
6890 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6891 BOOST_CHECK_EQUAL(res, RCode::NoError);
6892 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6893 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 6894 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
6895
6896 /* again, to test the cache */
6897 ret.clear();
6898 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6899 BOOST_CHECK_EQUAL(res, RCode::NoError);
6900 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6901 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 6902 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
6903}
6904
6905BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
6906 std::unique_ptr<SyncRes> sr;
6907 initSR(sr, true);
6908
0c43f455 6909 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
6910
6911 primeHints();
6912 const DNSName target("power-dns.com.");
6913 const DNSName targetCName("powerdns.com.");
6914 const ComboAddress targetCNameAddr("192.0.2.42");
6915 testkeysset_t keys;
6916
6917 auto luaconfsCopy = g_luaconfs.getCopy();
6918 luaconfsCopy.dsAnchors.clear();
6919 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6920 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6921 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6922 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6923 g_luaconfs.setState(luaconfsCopy);
6924
6925 size_t queriesCount = 0;
6926
6927 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) {
6928 queriesCount++;
6929
5374b03b
RG
6930 if (type == QType::DS || type == QType::DNSKEY) {
6931 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
6932 }
6933 else {
6934 if (isRootServer(ip)) {
6935 setLWResult(res, 0, false, false, true);
6936 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6937 addDS(DNSName("com."), 300, res->d_records, keys);
6938 addRRSIG(keys, res->d_records, DNSName("."), 300);
6939 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6940 return 1;
6941 }
6942 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6943 if (domain == DNSName("com.")) {
6944 setLWResult(res, 0, true, false, true);
6945 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6946 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6947 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6948 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6949 }
6950 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
6951 setLWResult(res, 0, false, false, true);
6952 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6953 addDS(DNSName(domain), 300, res->d_records, keys);
6954 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6955 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6956 }
3d5ebf10
RG
6957 return 1;
6958 }
6959 else if (ip == ComboAddress("192.0.2.2:53")) {
6960 setLWResult(res, 0, true, false, true);
a69867f2
RG
6961 if (type == QType::NS) {
6962 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6963 addRRSIG(keys, res->d_records, domain, 300);
6964 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
6965 addRRSIG(keys, res->d_records, domain, 300);
6966 }
a69867f2
RG
6967 else {
6968 if (domain == target) {
6969 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
6970 /* No RRSIG, leading to bogus */
6971 }
6972 else if (domain == targetCName) {
6973 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
6974 addRRSIG(keys, res->d_records, domain, 300);
6975 }
6976 }
3d5ebf10
RG
6977 return 1;
6978 }
6979 }
6980
6981 return 0;
6982 });
6983
6984 vector<DNSRecord> ret;
6985 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6986 BOOST_CHECK_EQUAL(res, RCode::NoError);
6987 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6988 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 6989 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
6990
6991 /* again, to test the cache */
6992 ret.clear();
6993 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6994 BOOST_CHECK_EQUAL(res, RCode::NoError);
6995 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6996 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 6997 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
6998}
6999
7000BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7001 std::unique_ptr<SyncRes> sr;
7002 initSR(sr, true);
7003
0c43f455 7004 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7005
7006 primeHints();
7007 const DNSName target("power-dns.com.");
7008 const DNSName targetCName("powerdns.com.");
7009 const ComboAddress targetCNameAddr("192.0.2.42");
7010 testkeysset_t keys;
7011
7012 auto luaconfsCopy = g_luaconfs.getCopy();
7013 luaconfsCopy.dsAnchors.clear();
7014 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7015 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7016 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7017 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7018 g_luaconfs.setState(luaconfsCopy);
7019
7020 size_t queriesCount = 0;
7021
7022 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) {
7023 queriesCount++;
7024
5374b03b
RG
7025 if (type == QType::DS || type == QType::DNSKEY) {
7026 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7027 }
7028 else {
7029 if (isRootServer(ip)) {
7030 setLWResult(res, 0, false, false, true);
7031 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7032 addDS(DNSName("com."), 300, res->d_records, keys);
7033 addRRSIG(keys, res->d_records, DNSName("."), 300);
7034 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7035 return 1;
7036 }
7037 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7038 if (domain == DNSName("com.")) {
7039 setLWResult(res, 0, true, false, true);
7040 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7041 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7042 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7043 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7044 }
7045 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7046 setLWResult(res, 0, false, false, true);
7047 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7048 addDS(DNSName(domain), 300, res->d_records, keys);
7049 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7050 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7051 }
3d5ebf10
RG
7052 return 1;
7053 }
7054 else if (ip == ComboAddress("192.0.2.2:53")) {
7055 setLWResult(res, 0, true, false, true);
a69867f2
RG
7056 if (type == QType::NS) {
7057 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7058 addRRSIG(keys, res->d_records, domain, 300);
7059 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7060 addRRSIG(keys, res->d_records, domain, 300);
7061 }
a69867f2
RG
7062 else {
7063 if (domain == target) {
7064 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7065 addRRSIG(keys, res->d_records, domain, 300);
7066 }
7067 else if (domain == targetCName) {
7068 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7069 /* No RRSIG, leading to bogus */
7070 }
3d5ebf10
RG
7071 }
7072 return 1;
7073 }
7074 }
7075
7076 return 0;
7077 });
7078
7079 vector<DNSRecord> ret;
7080 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7081 BOOST_CHECK_EQUAL(res, RCode::NoError);
7082 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7083 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7084 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7085
7086 /* again, to test the cache */
7087 ret.clear();
7088 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7089 BOOST_CHECK_EQUAL(res, RCode::NoError);
7090 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7091 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7092 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7093}
7094
7095BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
7096 std::unique_ptr<SyncRes> sr;
7097 initSR(sr, true);
7098
0c43f455 7099 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7100
7101 primeHints();
7102 const DNSName target("power-dns.com.");
7103 const DNSName targetCName("powerdns.com.");
7104 const ComboAddress targetCNameAddr("192.0.2.42");
7105 testkeysset_t keys;
7106
7107 auto luaconfsCopy = g_luaconfs.getCopy();
7108 luaconfsCopy.dsAnchors.clear();
7109 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7110 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7111 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7112 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7113 g_luaconfs.setState(luaconfsCopy);
7114
7115 size_t queriesCount = 0;
7116
7117 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) {
7118 queriesCount++;
7119
5374b03b
RG
7120 if (type == QType::DS || type == QType::DNSKEY) {
7121 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7122 }
7123 else {
7124 if (isRootServer(ip)) {
7125 setLWResult(res, 0, false, false, true);
7126 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7127 addDS(DNSName("com."), 300, res->d_records, keys);
7128 addRRSIG(keys, res->d_records, DNSName("."), 300);
7129 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7130 return 1;
7131 }
7132 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7133 if (domain == DNSName("com.")) {
7134 setLWResult(res, 0, true, false, true);
7135 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7136 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7137 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7138 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7139 }
7140 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7141 setLWResult(res, 0, false, false, true);
7142 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7143 addDS(DNSName(domain), 300, res->d_records, keys);
7144 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7145 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7146 }
3d5ebf10
RG
7147 return 1;
7148 }
7149 else if (ip == ComboAddress("192.0.2.2:53")) {
7150 setLWResult(res, 0, true, false, true);
a69867f2
RG
7151 if (type == QType::NS) {
7152 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
3d5ebf10 7153 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 7154 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7155 addRRSIG(keys, res->d_records, domain, 300);
7156 }
a69867f2
RG
7157 else {
7158 if (domain == target) {
7159 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7160 addRRSIG(keys, res->d_records, domain, 300);
7161 }
7162 else if (domain == targetCName) {
7163 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7164 addRRSIG(keys, res->d_records, domain, 300);
7165 }
7166 }
3d5ebf10
RG
7167 return 1;
7168 }
7169 }
7170
7171 return 0;
7172 });
7173
7174 vector<DNSRecord> ret;
7175 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7176 BOOST_CHECK_EQUAL(res, RCode::NoError);
7177 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7178 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7179 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7180
7181 /* again, to test the cache */
7182 ret.clear();
7183 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7184 BOOST_CHECK_EQUAL(res, RCode::NoError);
7185 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7186 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7187 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7188}
7189
7190BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7191 std::unique_ptr<SyncRes> sr;
a69867f2 7192 initSR(sr, true);
3d5ebf10 7193
0c43f455 7194 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7195
7196 primeHints();
7197 const DNSName target("powerdns.com.");
7198 const DNSName targetCName("power-dns.com.");
7199 const ComboAddress targetCNameAddr("192.0.2.42");
7200 testkeysset_t keys;
7201
7202 auto luaconfsCopy = g_luaconfs.getCopy();
7203 luaconfsCopy.dsAnchors.clear();
7204 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7205 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7206 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7207 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7208 g_luaconfs.setState(luaconfsCopy);
7209
7210 size_t queriesCount = 0;
7211
7212 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) {
7213 queriesCount++;
7214
7215 if (type == QType::DS) {
a53e8fe3 7216 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
7217 setLWResult(res, 0, false, false, true);
7218 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7219 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7220 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7221 return 1;
7222 }
5374b03b
RG
7223 else {
7224 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7225 }
3d5ebf10
RG
7226 }
7227 else if (type == QType::DNSKEY) {
7228 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7229 setLWResult(res, 0, true, false, true);
7230 addDNSKEY(keys, domain, 300, res->d_records);
7231 addRRSIG(keys, res->d_records, domain, 300);
7232 return 1;
7233 }
7234 else {
7235 setLWResult(res, 0, false, false, true);
7236 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7237 return 1;
7238 }
7239 }
7240 else {
7241 if (isRootServer(ip)) {
7242 setLWResult(res, 0, false, false, true);
7243 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7244 addDS(DNSName("com."), 300, res->d_records, keys);
7245 addRRSIG(keys, res->d_records, DNSName("."), 300);
7246 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7247 return 1;
7248 }
7249 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7250 if (domain == DNSName("com.")) {
7251 setLWResult(res, 0, true, false, true);
a69867f2 7252 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0
RG
7253 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7254 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7255 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7256 }
88cb0fe0
RG
7257 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7258 setLWResult(res, 0, false, false, true);
7259 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7260 if (domain == DNSName("powerdns.com.")) {
7261 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7262 }
7263 else if (domain == targetCName) {
7264 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7265 }
7266 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7267 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7268 }
3d5ebf10
RG
7269 return 1;
7270 }
7271 else if (ip == ComboAddress("192.0.2.2:53")) {
7272 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7273 if (type == QType::NS) {
7274 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7275 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7276 }
88cb0fe0
RG
7277 else {
7278 if (domain == DNSName("powerdns.com.")) {
7279 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7280 /* No RRSIG -> Bogus */
7281 }
7282 else if (domain == targetCName) {
7283 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7284 }
3d5ebf10
RG
7285 }
7286 return 1;
7287 }
7288 }
7289
7290 return 0;
7291 });
7292
7293 vector<DNSRecord> ret;
7294 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7295 BOOST_CHECK_EQUAL(res, RCode::NoError);
7296 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7297 /* no RRSIG to show */
7298 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7299 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7300
7301 /* again, to test the cache */
7302 ret.clear();
7303 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7304 BOOST_CHECK_EQUAL(res, RCode::NoError);
7305 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7306 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7307 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7308}
7309
895449a5
RG
7310BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7311 std::unique_ptr<SyncRes> sr;
7312 initSR(sr, true);
7313
0c43f455 7314 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
7315
7316 primeHints();
7317 const DNSName target("powerdns.com.");
7318 const ComboAddress targetAddr("192.0.2.42");
7319 testkeysset_t keys;
7320
7321 auto luaconfsCopy = g_luaconfs.getCopy();
7322 luaconfsCopy.dsAnchors.clear();
7323 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7324 /* No key material for .com */
7325 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7326 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7327 g_luaconfs.setState(luaconfsCopy);
7328
7329 size_t queriesCount = 0;
7330
7331 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) {
7332 queriesCount++;
7333
a53e8fe3 7334 if (type == QType::DNSKEY) {
895449a5
RG
7335 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7336 setLWResult(res, 0, true, false, true);
7337 addDNSKEY(keys, domain, 300, res->d_records);
7338 addRRSIG(keys, res->d_records, domain, 300);
7339 return 1;
7340 }
7341 else if (domain == DNSName("com.")) {
7342 setLWResult(res, 0, false, false, true);
7343 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7344 return 1;
7345 }
7346 }
88cb0fe0 7347 else {
895449a5
RG
7348 if (isRootServer(ip)) {
7349 setLWResult(res, 0, false, false, true);
7350 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7351 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7352 addRRSIG(keys, res->d_records, DNSName("."), 300);
7353 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7354 return 1;
7355 }
7356 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7357 if (target == domain) {
7358 setLWResult(res, 0, false, false, true);
7359 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7360 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7361 }
7362 else if (domain == DNSName("com.")) {
7363 setLWResult(res, 0, true, false, true);
7364 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7365 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7366 }
895449a5
RG
7367 return 1;
7368 }
7369 else if (ip == ComboAddress("192.0.2.2:53")) {
7370 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7371 if (type == QType::NS) {
7372 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7373 }
7374 else {
7375 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7376 }
895449a5
RG
7377 addRRSIG(keys, res->d_records, domain, 300);
7378 return 1;
7379 }
7380 }
7381
7382 return 0;
7383 });
7384
7385 vector<DNSRecord> ret;
7386 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7387 BOOST_CHECK_EQUAL(res, RCode::NoError);
7388 /* should be insecure but we have a TA for powerdns.com. */
7389 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7390 /* We got a RRSIG */
7391 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7392 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7393 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
7394
7395 /* again, to test the cache */
7396 ret.clear();
7397 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7398 BOOST_CHECK_EQUAL(res, RCode::NoError);
7399 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7400 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7401 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7402 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
7403}
7404
7405BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
7406 std::unique_ptr<SyncRes> sr;
7407 initSR(sr, true);
7408
0c43f455 7409 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
7410
7411 primeHints();
7412 const DNSName target("powerdns.com.");
7413 const ComboAddress targetAddr("192.0.2.42");
7414 testkeysset_t keys;
7415
7416 auto luaconfsCopy = g_luaconfs.getCopy();
7417 luaconfsCopy.dsAnchors.clear();
7418 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7419 /* No key material for .com */
7420 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7421 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7422 g_luaconfs.setState(luaconfsCopy);
7423
7424 size_t queriesCount = 0;
7425
7426 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) {
7427 queriesCount++;
7428
a53e8fe3 7429 if (type == QType::DNSKEY) {
895449a5
RG
7430 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7431 setLWResult(res, 0, true, false, true);
7432 addDNSKEY(keys, domain, 300, res->d_records);
7433 addRRSIG(keys, res->d_records, domain, 300);
7434 return 1;
7435 }
7436 else if (domain == DNSName("com.")) {
7437 setLWResult(res, 0, false, false, true);
7438 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7439 return 1;
7440 }
7441 }
70b3fe7a
RG
7442 else {
7443 if (target.isPartOf(domain) && isRootServer(ip)) {
895449a5
RG
7444 setLWResult(res, 0, false, false, true);
7445 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7446 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7447 addRRSIG(keys, res->d_records, DNSName("."), 300);
7448 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7449 return 1;
7450 }
7451 else if (ip == ComboAddress("192.0.2.1:53")) {
70b3fe7a
RG
7452 if (target == domain) {
7453 setLWResult(res, 0, false, false, true);
7454 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7455 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7456 }
7457 else if (domain == DNSName("com.")) {
7458 setLWResult(res, 0, true, false, true);
7459 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0 7460 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
70b3fe7a 7461 }
895449a5
RG
7462 return 1;
7463 }
70b3fe7a 7464 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
895449a5 7465 setLWResult(res, 0, true, false, true);
70b3fe7a
RG
7466 if (type == QType::NS) {
7467 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7468 }
7469 else {
7470 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7471 }
895449a5
RG
7472 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
7473 return 1;
7474 }
7475 }
7476
7477 return 0;
7478 });
7479
7480 vector<DNSRecord> ret;
7481 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7482 BOOST_CHECK_EQUAL(res, RCode::NoError);
7483 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
7484 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7485 /* No RRSIG */
7486 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7487 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7488 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
7489
7490 /* again, to test the cache */
7491 ret.clear();
7492 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7493 BOOST_CHECK_EQUAL(res, RCode::NoError);
7494 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7495 BOOST_REQUIRE_EQUAL(ret.size(), 1);
7496 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7497 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
7498}
7499
895449a5
RG
7500BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
7501 std::unique_ptr<SyncRes> sr;
7502 initSR(sr, true);
7503
0c43f455 7504 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5 7505
b7f378d1
RG
7506 primeHints();
7507 const DNSName target(".");
7508 testkeysset_t keys;
7509
7510 auto luaconfsCopy = g_luaconfs.getCopy();
7511 luaconfsCopy.dsAnchors.clear();
7512 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7513 /* Add a NTA for "." */
7514 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
7515 g_luaconfs.setState(luaconfsCopy);
7516
7517 size_t queriesCount = 0;
7518
7519 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) {
7520 queriesCount++;
7521
7522 if (domain == target && type == QType::NS) {
7523
7524 setLWResult(res, 0, true, false, true);
7525 char addr[] = "a.root-servers.net.";
7526 for (char idx = 'a'; idx <= 'm'; idx++) {
7527 addr[0] = idx;
8455425c
RG
7528 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7529 }
7530
7531 addRRSIG(keys, res->d_records, domain, 300);
7532
7533 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7534 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
7535
7536 return 1;
7537 } else if (domain == target && type == QType::DNSKEY) {
7538
7539 setLWResult(res, 0, true, false, true);
7540
7541 /* No DNSKEY */
7542
7543 return 1;
7544 }
7545
7546 return 0;
7547 });
7548
7549 vector<DNSRecord> ret;
7550 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
7551 BOOST_CHECK_EQUAL(res, RCode::NoError);
7552 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
7553 /* 13 NS + 1 RRSIG */
7554 BOOST_REQUIRE_EQUAL(ret.size(), 14);
7555 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
7556
7557 /* again, to test the cache */
7558 ret.clear();
7559 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7560 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 7561 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
7562 BOOST_REQUIRE_EQUAL(ret.size(), 14);
7563 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
7564}
7565
7566BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
7567 std::unique_ptr<SyncRes> sr;
895449a5 7568 initSR(sr, true);
8455425c 7569
0c43f455 7570 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
7571
7572 primeHints();
7573 const DNSName target(".");
b7f378d1 7574 testkeysset_t keys;
8455425c
RG
7575
7576 /* Remove the root DS */
7577 auto luaconfsCopy = g_luaconfs.getCopy();
7578 luaconfsCopy.dsAnchors.clear();
7579 g_luaconfs.setState(luaconfsCopy);
7580
7581 size_t queriesCount = 0;
7582
7583 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) {
7584 queriesCount++;
7585
7586 if (domain == target && type == QType::NS) {
7587
7588 setLWResult(res, 0, true, false, true);
7589 char addr[] = "a.root-servers.net.";
7590 for (char idx = 'a'; idx <= 'm'; idx++) {
7591 addr[0] = idx;
7592 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
7593 }
7594
7595 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
7596 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
7597
7598 return 1;
7599 }
7600
7601 return 0;
7602 });
7603
7604 vector<DNSRecord> ret;
7605 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
7606 BOOST_CHECK_EQUAL(res, RCode::NoError);
7607 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
7608 /* 13 NS + 0 RRSIG */
7609 BOOST_REQUIRE_EQUAL(ret.size(), 13);
7610 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
7611
7612 /* again, to test the cache */
7613 ret.clear();
7614 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
7615 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 7616 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
7617 BOOST_REQUIRE_EQUAL(ret.size(), 13);
7618 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
7619}
7620
114829cc
RG
7621BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
7622 std::unique_ptr<SyncRes> sr;
7623 initSR(sr, true);
7624
5d7b19c5 7625 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
114829cc
RG
7626
7627 primeHints();
7628 const DNSName target("powerdns.com.");
7629 testkeysset_t keys;
7630
7631 auto luaconfsCopy = g_luaconfs.getCopy();
7632 luaconfsCopy.dsAnchors.clear();
7633 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5374b03b 7634 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
114829cc
RG
7635 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7636 g_luaconfs.setState(luaconfsCopy);
7637
7638 size_t queriesCount = 0;
7639
7640 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) {
7641 queriesCount++;
7642
5374b03b
RG
7643 if (type == QType::DS || type == QType::DNSKEY) {
7644 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
114829cc
RG
7645 }
7646 else {
7647
7648 setLWResult(res, 0, true, false, true);
7649 return 1;
7650 }
7651
7652 return 0;
7653 });
7654
7655 vector<DNSRecord> ret;
7656 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7657 BOOST_CHECK_EQUAL(res, RCode::NoError);
7658 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7659 BOOST_REQUIRE_EQUAL(ret.size(), 0);
7660 /* com|NS, powerdns.com|NS, powerdns.com|A */
7661 BOOST_CHECK_EQUAL(queriesCount, 3);
7662
7663 /* again, to test the cache */
7664 ret.clear();
7665 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7666 BOOST_CHECK_EQUAL(res, RCode::NoError);
7667 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7668 BOOST_REQUIRE_EQUAL(ret.size(), 0);
7669 /* we don't store empty results */
5374b03b 7670 BOOST_CHECK_EQUAL(queriesCount, 4);
114829cc
RG
7671}
7672
db04449e
RG
7673BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
7674 init();
7675
7676 testkeysset_t keys;
7677 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7678
7679 vector<DNSRecord> records;
7680
7681 vector<shared_ptr<DNSRecordContent>> recordContents;
7682 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7683
7684 /*
7685 No wrap test case:
7686 a.example.org. -> d.example.org. denies the existence of b.example.org.
7687 */
7688 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7689 recordContents.push_back(records.at(0).d_content);
7690 addRRSIG(keys, records, DNSName("example.org."), 300);
7691 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7692 records.clear();
7693
7694 ContentSigPair pair;
7695 pair.records = recordContents;
7696 pair.signatures = signatureContents;
7697 cspmap_t denialMap;
7698 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
7699
9b061cf5
RG
7700 /* add wildcard denial */
7701 recordContents.clear();
7702 signatureContents.clear();
7703 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7704 recordContents.push_back(records.at(0).d_content);
7705 addRRSIG(keys, records, DNSName("example.org."), 300);
7706 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7707 records.clear();
7708
7709 pair.records = recordContents;
7710 pair.signatures = signatureContents;
7711 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
7712
00e3fef4 7713 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
7714 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7715
00e3fef4 7716 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
7717 /* let's check that d.example.org. is not denied by this proof */
7718 BOOST_CHECK_EQUAL(denialState, NODATA);
7719}
7720
7721BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
7722 init();
7723
7724 testkeysset_t keys;
7725 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7726
7727 vector<DNSRecord> records;
7728
7729 vector<shared_ptr<DNSRecordContent>> recordContents;
7730 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7731
7732 /*
7733 Wrap case 1 test case:
7734 z.example.org. -> b.example.org. denies the existence of a.example.org.
7735 */
7736 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7737 recordContents.push_back(records.at(0).d_content);
7738 addRRSIG(keys, records, DNSName("example.org."), 300);
7739 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7740 records.clear();
7741
7742 ContentSigPair pair;
7743 pair.records = recordContents;
7744 pair.signatures = signatureContents;
7745 cspmap_t denialMap;
7746 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
7747
00e3fef4 7748 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
7749 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7750
00e3fef4 7751 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
7752 /* let's check that d.example.org. is not denied by this proof */
7753 BOOST_CHECK_EQUAL(denialState, NODATA);
7754}
7755
7756BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
7757 init();
7758
7759 testkeysset_t keys;
7760 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7761
7762 vector<DNSRecord> records;
7763
7764 vector<shared_ptr<DNSRecordContent>> recordContents;
7765 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7766
7767 /*
7768 Wrap case 2 test case:
7769 y.example.org. -> a.example.org. denies the existence of z.example.org.
7770 */
7771 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7772 recordContents.push_back(records.at(0).d_content);
7773 addRRSIG(keys, records, DNSName("example.org."), 300);
7774 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7775 records.clear();
7776
7777 ContentSigPair pair;
7778 pair.records = recordContents;
7779 pair.signatures = signatureContents;
7780 cspmap_t denialMap;
7781 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
7782
00e3fef4 7783 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
db04449e
RG
7784 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7785
00e3fef4 7786 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
7787 /* let's check that d.example.org. is not denied by this proof */
7788 BOOST_CHECK_EQUAL(denialState, NODATA);
7789}
7790
7791BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
7792 init();
7793
7794 testkeysset_t keys;
7795 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7796
7797 vector<DNSRecord> records;
7798
7799 vector<shared_ptr<DNSRecordContent>> recordContents;
7800 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7801
7802 /*
7803 Only one NSEC in the whole zone test case:
7804 a.example.org. -> a.example.org. denies the existence of b.example.org.
7805 */
7806 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7807 recordContents.push_back(records.at(0).d_content);
7808 addRRSIG(keys, records, DNSName("example.org."), 300);
7809 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7810 records.clear();
7811
7812 ContentSigPair pair;
7813 pair.records = recordContents;
7814 pair.signatures = signatureContents;
7815 cspmap_t denialMap;
7816 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
7817
00e3fef4 7818 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
7819 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7820
00e3fef4 7821 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
7822 /* let's check that d.example.org. is not denied by this proof */
7823 BOOST_CHECK_EQUAL(denialState, NODATA);
7824}
7825
1efd998a
RG
7826BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
7827 init();
7828
7829 testkeysset_t keys;
7830 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7831
7832 vector<DNSRecord> records;
7833
7834 vector<shared_ptr<DNSRecordContent>> recordContents;
7835 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7836
7837 /*
7838 The RRSIG from "." denies the existence of anything between a. and c.,
7839 including b.
7840 */
7841 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
7842 recordContents.push_back(records.at(0).d_content);
7843 addRRSIG(keys, records, DNSName("."), 300);
7844 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7845 records.clear();
7846
7847 ContentSigPair pair;
7848 pair.records = recordContents;
7849 pair.signatures = signatureContents;
7850 cspmap_t denialMap;
7851 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
7852
9b061cf5
RG
7853 /* add wildcard denial */
7854 recordContents.clear();
7855 signatureContents.clear();
7856 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
7857 recordContents.push_back(records.at(0).d_content);
7858 addRRSIG(keys, records, DNSName("."), 300);
7859 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7860 records.clear();
7861
7862 pair.records = recordContents;
7863 pair.signatures = signatureContents;
7864 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
7865
00e3fef4 7866 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
1efd998a
RG
7867 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
7868}
7869
7870BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
7871 init();
7872
7873 testkeysset_t keys;
7874 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7875
7876 vector<DNSRecord> records;
7877
7878 vector<shared_ptr<DNSRecordContent>> recordContents;
7879 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7880
7881 /*
7882 The RRSIG from "." denies the existence of any type except NS at a.
7883 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
7884 signer field that is shorter than the owner name of the NSEC RR) it can't
7885 be used to deny anything except the whole name or a DS.
7886 */
7887 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
7888 recordContents.push_back(records.at(0).d_content);
7889 addRRSIG(keys, records, DNSName("."), 300);
7890 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7891 records.clear();
7892
7893 ContentSigPair pair;
7894 pair.records = recordContents;
7895 pair.signatures = signatureContents;
7896 cspmap_t denialMap;
7897 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
7898
7899 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
7900 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
7901 nonexistence of any RRs below that zone cut, which include all RRs at
7902 that (original) owner name other than DS RRs, and all RRs below that
7903 owner name regardless of type.
7904 */
7905
00e3fef4 7906 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
1efd998a
RG
7907 /* no data means the qname/qtype is not denied, because an ancestor
7908 delegation NSEC can only deny the DS */
7909 BOOST_CHECK_EQUAL(denialState, NODATA);
7910
00e3fef4 7911 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
1efd998a
RG
7912 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
7913}
7914
95823c07
RG
7915BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
7916 init();
7917
7918 testkeysset_t keys;
7919 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7920
7921 vector<DNSRecord> records;
7922
7923 vector<shared_ptr<DNSRecordContent>> recordContents;
7924 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7925
7926 /*
7927 * RFC 5155 section 8.9:
7928 * If there is an NSEC3 RR present in the response that matches the
7929 * delegation name, then the validator MUST ensure that the NS bit is
7930 * set and that the DS bit is not set in the Type Bit Maps field of the
7931 * NSEC3 RR.
7932 */
7933 /*
7934 The RRSIG from "." denies the existence of any type at a.
7935 NS should be set if it was proving an insecure delegation, let's check that
7936 we correctly detect that it's not.
7937 */
7938 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
7939 recordContents.push_back(records.at(0).d_content);
7940 addRRSIG(keys, records, DNSName("."), 300);
7941 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7942 records.clear();
7943
7944 ContentSigPair pair;
7945 pair.records = recordContents;
7946 pair.signatures = signatureContents;
7947 cspmap_t denialMap;
7948 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
7949
7950 /* Insecure because the NS is not set, so while it does
7951 denies the DS, it can't prove an insecure delegation */
00e3fef4 7952 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 7953 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
7954}
7955
9b061cf5
RG
7956BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
7957 init();
7958
7959 testkeysset_t keys;
7960 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7961
7962 vector<DNSRecord> records;
7963
7964 vector<shared_ptr<DNSRecordContent>> recordContents;
7965 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7966
7967 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
7968 recordContents.push_back(records.at(0).d_content);
7969 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
7970 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7971 records.clear();
7972
7973 ContentSigPair pair;
7974 pair.records = recordContents;
7975 pair.signatures = signatureContents;
7976 cspmap_t denialMap;
7977 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
7978
7979 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
7980 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
7981 BOOST_CHECK_EQUAL(denialState, NODATA);
7982}
7983
7984BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
7985 init();
7986
7987 testkeysset_t keys;
7988 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7989
7990 vector<DNSRecord> records;
7991
7992 vector<shared_ptr<DNSRecordContent>> recordContents;
7993 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
7994
7995 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
7996 recordContents.push_back(records.at(0).d_content);
7997 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
7998 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
7999
8000 ContentSigPair pair;
8001 pair.records = recordContents;
8002 pair.signatures = signatureContents;
8003 cspmap_t denialMap;
8004 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8005 records.clear();
8006
8007 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8008 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8009 BOOST_CHECK_EQUAL(denialState, NODATA);
8010}
8011
8012BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8013 init();
8014
8015 testkeysset_t keys;
8016 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8017
8018 vector<DNSRecord> records;
8019
8020 vector<shared_ptr<DNSRecordContent>> recordContents;
8021 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8022
8023 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8024 recordContents.push_back(records.at(0).d_content);
8025 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8026 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8027 records.clear();
8028
8029 ContentSigPair pair;
8030 pair.records = recordContents;
8031 pair.signatures = signatureContents;
8032 cspmap_t denialMap;
8033 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8034
8035 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8036 BOOST_CHECK_EQUAL(denialState, NODATA);
8037}
8038
8039BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
8040 init();
8041
8042 testkeysset_t keys;
8043 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8044
8045 vector<DNSRecord> records;
8046
8047 vector<shared_ptr<DNSRecordContent>> recordContents;
8048 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8049
8050 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8051 recordContents.push_back(records.at(0).d_content);
8052 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8053 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8054
8055 ContentSigPair pair;
8056 pair.records = recordContents;
8057 pair.signatures = signatureContents;
8058 cspmap_t denialMap;
8059 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8060
8061 /* Add NSEC3 for the closest encloser */
8062 recordContents.clear();
8063 signatureContents.clear();
8064 records.clear();
8065 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8066 recordContents.push_back(records.at(0).d_content);
8067 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8068 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8069
8070 pair.records = recordContents;
8071 pair.signatures = signatureContents;
8072 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8073
8074 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8075 BOOST_CHECK_EQUAL(denialState, NODATA);
8076}
8077
00e3fef4
RG
8078BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8079 init();
8080
8081 testkeysset_t keys;
8082 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8083
8084 vector<DNSRecord> records;
8085
8086 vector<shared_ptr<DNSRecordContent>> recordContents;
8087 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8088
8089 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8090 recordContents.push_back(records.at(0).d_content);
8091 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8092 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8093 records.clear();
8094
8095 ContentSigPair pair;
8096 pair.records = recordContents;
8097 pair.signatures = signatureContents;
8098 cspmap_t denialMap;
8099 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8100
9b061cf5 8101 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
00e3fef4 8102 it is an ENT */
9b061cf5 8103 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
00e3fef4 8104 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
00be1ff6 8105
9b061cf5
RG
8106 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8107 it could prove a NXDOMAIN if it had an additional wildcard denial */
8108 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8109 BOOST_CHECK_EQUAL(denialState, NODATA);
8110
00be1ff6
RG
8111 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8112 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8113 BOOST_CHECK_EQUAL(denialState, NODATA);
9b061cf5
RG
8114
8115 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8116 recordContents.clear();
8117 signatureContents.clear();
8118 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8119 recordContents.push_back(records.at(0).d_content);
8120 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8121 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8122 records.clear();
8123 pair.records = recordContents;
8124 pair.signatures = signatureContents;
8125 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8126
82566a96 8127 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
9b061cf5 8128 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
00e3fef4
RG
8129}
8130
95823c07
RG
8131BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8132 init();
8133
8134 testkeysset_t keys;
8135 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8136
8137 vector<DNSRecord> records;
8138
8139 vector<shared_ptr<DNSRecordContent>> recordContents;
8140 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8141
8142 /*
8143 The RRSIG from "." denies the existence of any type except NS at a.
8144 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8145 signer field that is shorter than the owner name of the NSEC RR) it can't
8146 be used to deny anything except the whole name or a DS.
8147 */
9b061cf5 8148 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
95823c07
RG
8149 recordContents.push_back(records.at(0).d_content);
8150 addRRSIG(keys, records, DNSName("."), 300);
8151 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8152
8153 ContentSigPair pair;
8154 pair.records = recordContents;
8155 pair.signatures = signatureContents;
8156 cspmap_t denialMap;
8157 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8158 records.clear();
8159
8160 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8161 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8162 nonexistence of any RRs below that zone cut, which include all RRs at
8163 that (original) owner name other than DS RRs, and all RRs below that
8164 owner name regardless of type.
8165 */
8166
00e3fef4 8167 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
95823c07
RG
8168 /* no data means the qname/qtype is not denied, because an ancestor
8169 delegation NSEC3 can only deny the DS */
8170 BOOST_CHECK_EQUAL(denialState, NODATA);
8171
00e3fef4 8172 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
95823c07
RG
8173 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8174}
8175
b7c40613
RG
8176BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8177 init();
8178
8179 testkeysset_t keys;
8180 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8181
8182 vector<DNSRecord> records;
8183
8184 vector<shared_ptr<DNSRecordContent>> recordContents;
8185 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8186
8187 /* adding a NSEC3 with more iterations that we support */
8188 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8189 recordContents.push_back(records.at(0).d_content);
8190 addRRSIG(keys, records, DNSName("."), 300);
8191 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8192
8193 ContentSigPair pair;
8194 pair.records = recordContents;
8195 pair.signatures = signatureContents;
8196 cspmap_t denialMap;
8197 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8198 records.clear();
8199
8200 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8201 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8202 BOOST_CHECK_EQUAL(denialState, INSECURE);
8203}
8204
95823c07
RG
8205BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8206 init();
8207
8208 testkeysset_t keys;
8209 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8210
8211 vector<DNSRecord> records;
8212
8213 vector<shared_ptr<DNSRecordContent>> recordContents;
8214 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8215
8216 /*
8217 * RFC 5155 section 8.9:
8218 * If there is an NSEC3 RR present in the response that matches the
8219 * delegation name, then the validator MUST ensure that the NS bit is
8220 * set and that the DS bit is not set in the Type Bit Maps field of the
8221 * NSEC3 RR.
8222 */
8223 /*
8224 The RRSIG from "." denies the existence of any type at a.
8225 NS should be set if it was proving an insecure delegation, let's check that
8226 we correctly detect that it's not.
8227 */
9b061cf5 8228 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
95823c07
RG
8229 recordContents.push_back(records.at(0).d_content);
8230 addRRSIG(keys, records, DNSName("."), 300);
8231 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8232
8233 ContentSigPair pair;
8234 pair.records = recordContents;
8235 pair.signatures = signatureContents;
8236 cspmap_t denialMap;
8237 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8238 records.clear();
8239
8240 /* Insecure because the NS is not set, so while it does
8241 denies the DS, it can't prove an insecure delegation */
00e3fef4 8242 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8243 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8244}
8245
dbbef467
RG
8246BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8247 std::unique_ptr<SyncRes> sr;
dbbef467
RG
8248 initSR(sr, true);
8249
8250 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8251
8252 primeHints();
8253 const DNSName target("com.");
8254 testkeysset_t keys;
8255
8256 auto luaconfsCopy = g_luaconfs.getCopy();
8257 luaconfsCopy.dsAnchors.clear();
8258 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8259 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8260 g_luaconfs.setState(luaconfsCopy);
8261
8262 size_t queriesCount = 0;
8263
8264 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) {
8265 queriesCount++;
8266
8267 DNSName auth = domain;
8268 auth.chopOff();
8269
8270 if (type == QType::DS || type == QType::DNSKEY) {
8271 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8272 }
8273 else {
8274 setLWResult(res, RCode::NoError, true, false, true);
8275 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8276 addRRSIG(keys, res->d_records, domain, 300);
8277 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8278 addRRSIG(keys, res->d_records, domain, 1);
8279 return 1;
8280 }
8281
8282 return 0;
8283 });
8284
2010ac95 8285 const time_t now = time(nullptr);
dbbef467
RG
8286 vector<DNSRecord> ret;
8287 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8288 BOOST_CHECK_EQUAL(res, RCode::NoError);
8289 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8290 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8291 BOOST_CHECK_EQUAL(queriesCount, 4);
8292
8293 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
8294 NegCache::NegCacheEntry ne;
8295 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8296 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8297 BOOST_CHECK_EQUAL(ne.d_ttd, now + 1);
b25712fd 8298 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
dbbef467
RG
8299 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8300 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8301 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8302 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
8303
8304 /* again, to test the cache */
8305 ret.clear();
8306 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8307 BOOST_CHECK_EQUAL(res, RCode::NoError);
8308 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8309 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8310 BOOST_CHECK_EQUAL(queriesCount, 4);
8311}
8312
8313BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
8314 std::unique_ptr<SyncRes> sr;
dbbef467
RG
8315 initSR(sr, true);
8316
8317 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8318
8319 primeHints();
8320 const DNSName target("com.");
8321 const ComboAddress targetAddr("192.0.2.42");
8322 testkeysset_t keys;
8323
8324 auto luaconfsCopy = g_luaconfs.getCopy();
8325 luaconfsCopy.dsAnchors.clear();
8326 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8327 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8328 g_luaconfs.setState(luaconfsCopy);
8329
8330 size_t queriesCount = 0;
8331
8332 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) {
8333 queriesCount++;
8334
8335 DNSName auth = domain;
8336 auth.chopOff();
8337
8338 if (type == QType::DS || type == QType::DNSKEY) {
8339 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8340 }
8341 else {
8342 setLWResult(res, RCode::NoError, true, false, true);
8343 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8344 addRRSIG(keys, res->d_records, domain, 1);
8345 return 1;
8346 }
8347
8348 return 0;
8349 });
8350
2010ac95 8351 const time_t now = time(nullptr);
dbbef467
RG
8352 vector<DNSRecord> ret;
8353 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8354 BOOST_CHECK_EQUAL(res, RCode::NoError);
8355 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8356 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8357 BOOST_CHECK_EQUAL(queriesCount, 4);
8358
8359 /* check that the entry has not been cached for longer than the RRSIG validity */
8360 const ComboAddress who;
8361 vector<DNSRecord> cached;
8362 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
8363 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
8364 BOOST_REQUIRE_EQUAL(cached.size(), 1);
8365 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
8366 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
8367
8368 /* again, to test the cache */
8369 ret.clear();
8370 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8371 BOOST_CHECK_EQUAL(res, RCode::NoError);
8372 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8373 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8374 BOOST_CHECK_EQUAL(queriesCount, 4);
8375}
8376
f4de85a3
RG
8377BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
8378 /*
8379 Validation is optional, and the first query does not ask for it,
8380 so the answer is cached as Indeterminate.
8381 The second query asks for validation, answer should be marked as
8382 Secure.
8383 */
8384 std::unique_ptr<SyncRes> sr;
8385 initSR(sr, true);
8386
8387 setDNSSECValidation(sr, DNSSECMode::Process);
8388
8389 primeHints();
8390 const DNSName target("com.");
8391 testkeysset_t keys;
8392
8393 auto luaconfsCopy = g_luaconfs.getCopy();
8394 luaconfsCopy.dsAnchors.clear();
8395 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8396 g_luaconfs.setState(luaconfsCopy);
8397
8398 size_t queriesCount = 0;
8399
8400 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) {
8401 queriesCount++;
8402
8403 if (type == QType::DS || type == QType::DNSKEY) {
8404 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8405 }
8406 else {
8407 if (domain == target && type == QType::A) {
8408 setLWResult(res, 0, true, false, true);
8409 addRecordToLW(res, target, QType::A, "192.0.2.1");
8410 addRRSIG(keys, res->d_records, DNSName("."), 300);
8411 return 1;
8412 }
8413 }
8414
8415 return 0;
8416 });
8417
8418 vector<DNSRecord> ret;
8419 /* first query does not require validation */
8420 sr->setDNSSECValidationRequested(false);
8421 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8422 BOOST_CHECK_EQUAL(res, RCode::NoError);
8423 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8424 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8425 for (const auto& record : ret) {
8426 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8427 }
8428 BOOST_CHECK_EQUAL(queriesCount, 1);
8429
8430
8431 ret.clear();
8432 /* second one _does_ require validation */
8433 sr->setDNSSECValidationRequested(true);
8434 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8435 BOOST_CHECK_EQUAL(res, RCode::NoError);
8436 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8437 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8438 for (const auto& record : ret) {
8439 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8440 }
8441 BOOST_CHECK_EQUAL(queriesCount, 3);
8442}
8443
8444BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
8445 /*
8446 Validation is optional, and the first query does not ask for it,
8447 so the answer is cached as Indeterminate.
8448 The second query asks for validation, answer should be marked as
8449 Insecure.
8450 */
8451 std::unique_ptr<SyncRes> sr;
8452 initSR(sr, true);
8453
8454 setDNSSECValidation(sr, DNSSECMode::Process);
8455
8456 primeHints();
8457 const DNSName target("com.");
8458 testkeysset_t keys;
8459
8460 auto luaconfsCopy = g_luaconfs.getCopy();
8461 luaconfsCopy.dsAnchors.clear();
8462 g_luaconfs.setState(luaconfsCopy);
8463
8464 size_t queriesCount = 0;
8465
8466 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) {
8467 queriesCount++;
8468
8469 if (type == QType::DS || type == QType::DNSKEY) {
8470 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8471 }
8472 else {
8473 if (domain == target && type == QType::A) {
8474 setLWResult(res, 0, true, false, true);
8475 addRecordToLW(res, target, QType::A, "192.0.2.1");
8476 return 1;
8477 }
8478 }
8479
8480 return 0;
8481 });
8482
8483 vector<DNSRecord> ret;
8484 /* first query does not require validation */
8485 sr->setDNSSECValidationRequested(false);
8486 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8487 BOOST_CHECK_EQUAL(res, RCode::NoError);
8488 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8489 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8490 for (const auto& record : ret) {
55acb073 8491 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
8492 }
8493 BOOST_CHECK_EQUAL(queriesCount, 1);
8494
8495
8496 ret.clear();
8497 /* second one _does_ require validation */
8498 sr->setDNSSECValidationRequested(true);
8499 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8500 BOOST_CHECK_EQUAL(res, RCode::NoError);
8501 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8502 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8503 for (const auto& record : ret) {
55acb073 8504 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
8505 }
8506 BOOST_CHECK_EQUAL(queriesCount, 1);
8507}
8508
8509BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
8510 /*
8511 Validation is optional, and the first query does not ask for it,
8512 so the answer is cached as Indeterminate.
8513 The second query asks for validation, answer should be marked as
8514 Bogus.
8515 */
8516 std::unique_ptr<SyncRes> sr;
8517 initSR(sr, true);
8518
8519 setDNSSECValidation(sr, DNSSECMode::Process);
8520
8521 primeHints();
8522 const DNSName target("com.");
8523 testkeysset_t keys;
8524
8525 auto luaconfsCopy = g_luaconfs.getCopy();
8526 luaconfsCopy.dsAnchors.clear();
8527 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8528 g_luaconfs.setState(luaconfsCopy);
8529
8530 size_t queriesCount = 0;
8531
8532 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) {
8533 queriesCount++;
8534
8535 if (type == QType::DS || type == QType::DNSKEY) {
8536 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8537 }
8538 else {
8539 if (domain == target && type == QType::A) {
8540 setLWResult(res, 0, true, false, true);
8541 addRecordToLW(res, target, QType::A, "192.0.2.1");
8542 /* no RRSIG */
8543 return 1;
8544 }
8545 }
8546
8547 return 0;
8548 });
8549
8550 vector<DNSRecord> ret;
8551 /* first query does not require validation */
8552 sr->setDNSSECValidationRequested(false);
8553 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8554 BOOST_CHECK_EQUAL(res, RCode::NoError);
8555 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8556 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8557 for (const auto& record : ret) {
55acb073 8558 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
8559 }
8560 BOOST_CHECK_EQUAL(queriesCount, 1);
8561
8562
8563 ret.clear();
8564 /* second one _does_ require validation */
8565 sr->setDNSSECValidationRequested(true);
8566 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8567 BOOST_CHECK_EQUAL(res, RCode::NoError);
8568 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8569 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8570 for (const auto& record : ret) {
55acb073 8571 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
8572 }
8573 BOOST_CHECK_EQUAL(queriesCount, 3);
8574}
8575
55acb073
RG
8576BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
8577 /*
8578 Validation is optional, and the first query does not ask for it,
8579 so the answer is cached as Indeterminate.
8580 The second query asks for validation, answer should be marked as
8581 Secure.
8582 */
8583 std::unique_ptr<SyncRes> sr;
8584 initSR(sr, true);
8585
8586 setDNSSECValidation(sr, DNSSECMode::Process);
8587
8588 primeHints();
8589 const DNSName target("com.");
8590 const DNSName cnameTarget("cname-com.");
8591 testkeysset_t keys;
8592
8593 auto luaconfsCopy = g_luaconfs.getCopy();
8594 luaconfsCopy.dsAnchors.clear();
8595 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8596 g_luaconfs.setState(luaconfsCopy);
8597
8598 size_t queriesCount = 0;
8599
8600 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) {
8601 queriesCount++;
8602
8603 if (type == QType::DS || type == QType::DNSKEY) {
8604 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8605 }
8606 else {
8607 if (domain == target && type == QType::A) {
8608 setLWResult(res, 0, true, false, true);
8609 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
8610 addRRSIG(keys, res->d_records, DNSName("."), 300);
8611 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8612 addRRSIG(keys, res->d_records, DNSName("."), 300);
8613 return 1;
8614 } else if (domain == cnameTarget && type == QType::A) {
8615 setLWResult(res, 0, true, false, true);
8616 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8617 addRRSIG(keys, res->d_records, DNSName("."), 300);
8618 return 1;
8619 }
8620 }
8621
8622 return 0;
8623 });
8624
8625 vector<DNSRecord> ret;
8626 /* first query does not require validation */
8627 sr->setDNSSECValidationRequested(false);
8628 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8629 BOOST_CHECK_EQUAL(res, RCode::NoError);
8630 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8631 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8632 for (const auto& record : ret) {
8633 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
8634 }
8635 BOOST_CHECK_EQUAL(queriesCount, 2);
8636
8637
8638 ret.clear();
8639 /* second one _does_ require validation */
8640 sr->setDNSSECValidationRequested(true);
8641 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8642 BOOST_CHECK_EQUAL(res, RCode::NoError);
8643 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8644 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8645 for (const auto& record : ret) {
8646 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
8647 }
8648 BOOST_CHECK_EQUAL(queriesCount, 5);
8649}
8650
8651BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
8652 /*
8653 Validation is optional, and the first query does not ask for it,
8654 so the answer is cached as Indeterminate.
8655 The second query asks for validation, answer should be marked as
8656 Insecure.
8657 */
8658 std::unique_ptr<SyncRes> sr;
8659 initSR(sr, true);
8660
8661 setDNSSECValidation(sr, DNSSECMode::Process);
8662
8663 primeHints();
8664 const DNSName target("com.");
8665 const DNSName cnameTarget("cname-com.");
8666 testkeysset_t keys;
8667
8668 auto luaconfsCopy = g_luaconfs.getCopy();
8669 luaconfsCopy.dsAnchors.clear();
8670 g_luaconfs.setState(luaconfsCopy);
8671
8672 size_t queriesCount = 0;
8673
8674 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) {
8675 queriesCount++;
8676
8677 if (type == QType::DS || type == QType::DNSKEY) {
8678 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8679 }
8680 else {
8681 if (domain == target && type == QType::A) {
8682 setLWResult(res, 0, true, false, true);
8683 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
8684 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8685 return 1;
8686 } else if (domain == cnameTarget && type == QType::A) {
8687 setLWResult(res, 0, true, false, true);
8688 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8689 return 1;
8690 }
8691 }
8692
8693 return 0;
8694 });
8695
8696 vector<DNSRecord> ret;
8697 /* first query does not require validation */
8698 sr->setDNSSECValidationRequested(false);
8699 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8700 BOOST_CHECK_EQUAL(res, RCode::NoError);
8701 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8702 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8703 for (const auto& record : ret) {
8704 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8705 }
8706 BOOST_CHECK_EQUAL(queriesCount, 2);
8707
8708
8709 ret.clear();
8710 /* second one _does_ require validation */
8711 sr->setDNSSECValidationRequested(true);
8712 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8713 BOOST_CHECK_EQUAL(res, RCode::NoError);
8714 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8715 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8716 for (const auto& record : ret) {
8717 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8718 }
8719 BOOST_CHECK_EQUAL(queriesCount, 2);
8720}
8721
8722BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
8723 /*
8724 Validation is optional, and the first query does not ask for it,
8725 so the answer is cached as Indeterminate.
8726 The second query asks for validation, answer should be marked as
8727 Bogus.
8728 */
8729 std::unique_ptr<SyncRes> sr;
8730 initSR(sr, true);
8731
8732 setDNSSECValidation(sr, DNSSECMode::Process);
8733
8734 primeHints();
8735 const DNSName target("com.");
8736 const DNSName cnameTarget("cname-com.");
8737 testkeysset_t keys;
8738
8739 auto luaconfsCopy = g_luaconfs.getCopy();
8740 luaconfsCopy.dsAnchors.clear();
8741 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8742 g_luaconfs.setState(luaconfsCopy);
8743
8744 size_t queriesCount = 0;
8745
8746 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) {
8747 queriesCount++;
8748
8749 if (type == QType::DS || type == QType::DNSKEY) {
8750 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8751 }
8752 else {
8753 if (domain == target && type == QType::A) {
8754 setLWResult(res, 0, true, false, true);
8755 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
8756 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8757 /* no RRSIG */
8758 return 1;
8759 } else if (domain == cnameTarget && type == QType::A) {
8760 setLWResult(res, 0, true, false, true);
8761 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
8762 /* no RRSIG */
8763 return 1;
8764 }
8765 }
8766
8767 return 0;
8768 });
8769
8770 vector<DNSRecord> ret;
8771 /* first query does not require validation */
8772 sr->setDNSSECValidationRequested(false);
8773 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8774 BOOST_CHECK_EQUAL(res, RCode::NoError);
8775 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8776 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8777 for (const auto& record : ret) {
8778 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8779 }
8780 BOOST_CHECK_EQUAL(queriesCount, 2);
8781
8782
8783 ret.clear();
8784 /* second one _does_ require validation */
8785 sr->setDNSSECValidationRequested(true);
8786 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8787 BOOST_CHECK_EQUAL(res, RCode::NoError);
8788 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8789 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8790 for (const auto& record : ret) {
8791 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
8792 }
8793 BOOST_CHECK_EQUAL(queriesCount, 5);
8794}
8795
f4de85a3
RG
8796BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
8797 /*
8798 Validation is optional, and the first query does not ask for it,
8799 so the answer is negatively cached as Indeterminate.
8800 The second query asks for validation, answer should be marked as
8801 Secure.
8802 */
8803 std::unique_ptr<SyncRes> sr;
8804 initSR(sr, true);
8805
8806 setDNSSECValidation(sr, DNSSECMode::Process);
8807
8808 primeHints();
8809 const DNSName target("com.");
8810 testkeysset_t keys;
8811
8812 auto luaconfsCopy = g_luaconfs.getCopy();
8813 luaconfsCopy.dsAnchors.clear();
8814 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8815 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8816 g_luaconfs.setState(luaconfsCopy);
8817
8818 size_t queriesCount = 0;
8819
8820 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) {
8821 queriesCount++;
8822
8823 DNSName auth = domain;
8824 auth.chopOff();
8825
8826 if (type == QType::DS || type == QType::DNSKEY) {
8827 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8828 }
8829 else {
8830 setLWResult(res, RCode::NoError, true, false, true);
8831 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8832 addRRSIG(keys, res->d_records, domain, 300);
8833 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8834 addRRSIG(keys, res->d_records, domain, 1);
8835 return 1;
8836 }
8837
8838 return 0;
8839 });
8840
8841 vector<DNSRecord> ret;
8842 /* first query does not require validation */
8843 sr->setDNSSECValidationRequested(false);
8844 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8845 BOOST_CHECK_EQUAL(res, RCode::NoError);
8846 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8847 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8848 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
8849 /* check that the entry has not been negatively cached */
8850 NegCache::NegCacheEntry ne;
8851 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8852 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8853 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
8854 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8855 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8856 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8857 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
8858
8859 ret.clear();
8860 /* second one _does_ require validation */
8861 sr->setDNSSECValidationRequested(true);
8862 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8863 BOOST_CHECK_EQUAL(res, RCode::NoError);
8864 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8865 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8866 BOOST_CHECK_EQUAL(queriesCount, 4);
b25712fd
RG
8867 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8868 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8869 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
8870 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8871 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8872 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8873 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
8874}
8875
f5a747bb
RG
8876BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
8877 /*
8878 Validation is optional, and the first query does not ask for it,
8879 so the answer is negatively cached as Indeterminate.
8880 The second query asks for validation, answer should be marked as
8881 Secure.
8882 The difference with test_dnssec_validation_from_negcache_secure is
8883 that have one more level here, so we are going to look for the proof
8884 that the DS does not exist for the last level. Since there is no cut,
8885 we should accept the fact that the NSEC denies DS and NS both.
8886 */
8887 std::unique_ptr<SyncRes> sr;
8888 initSR(sr, true);
8889
8890 setDNSSECValidation(sr, DNSSECMode::Process);
8891
8892 primeHints();
8893 const DNSName target("www.com.");
8894 testkeysset_t keys;
8895
8896 auto luaconfsCopy = g_luaconfs.getCopy();
8897 luaconfsCopy.dsAnchors.clear();
8898 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8899 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8900 g_luaconfs.setState(luaconfsCopy);
8901
8902 size_t queriesCount = 0;
8903
8904 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) {
8905 queriesCount++;
8906
8907 if (type == QType::DS || type == QType::DNSKEY) {
8908 if (domain == target) {
8909 /* there is no cut */
8910 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8911 }
8912 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
8913 }
8914
8915 return 0;
8916 });
8917
8918 vector<DNSRecord> ret;
8919 /* first query does not require validation */
8920 sr->setDNSSECValidationRequested(false);
8921 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
8922 BOOST_CHECK_EQUAL(res, RCode::NoError);
8923 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8924 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8925 BOOST_CHECK_EQUAL(queriesCount, 1);
8926
8927 ret.clear();
8928 /* second one _does_ require validation */
8929 sr->setDNSSECValidationRequested(true);
8930 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
8931 BOOST_CHECK_EQUAL(res, RCode::NoError);
8932 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8933 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8934 BOOST_CHECK_EQUAL(queriesCount, 4);
8935}
8936
f4de85a3
RG
8937BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
8938 /*
8939 Validation is optional, and the first query does not ask for it,
8940 so the answer is negatively cached as Indeterminate.
8941 The second query asks for validation, answer should be marked as
8942 Insecure.
8943 */
8944 std::unique_ptr<SyncRes> sr;
8945 initSR(sr, true);
8946
8947 setDNSSECValidation(sr, DNSSECMode::Process);
8948
8949 primeHints();
8950 const DNSName target("com.");
8951 testkeysset_t keys;
8952
8953 auto luaconfsCopy = g_luaconfs.getCopy();
8954 luaconfsCopy.dsAnchors.clear();
8955 g_luaconfs.setState(luaconfsCopy);
8956
8957 size_t queriesCount = 0;
8958
8959 sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res) {
8960 queriesCount++;
8961
8962 DNSName auth = domain;
8963 auth.chopOff();
8964
8965 if (type == QType::DS || type == QType::DNSKEY) {
8966 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8967 }
8968 else {
8969 setLWResult(res, RCode::NoError, true, false, true);
8970 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8971 return 1;
8972 }
8973
8974 return 0;
8975 });
8976
8977 vector<DNSRecord> ret;
8978 /* first query does not require validation */
8979 sr->setDNSSECValidationRequested(false);
8980 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8981 BOOST_CHECK_EQUAL(res, RCode::NoError);
8982 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8983 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8984 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
8985 /* check that the entry has not been negatively cached */
8986 NegCache::NegCacheEntry ne;
8987 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8988 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8989 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
8990 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8991 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
8992 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
8993 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
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 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9003 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9004 BOOST_CHECK_EQUAL(ne.d_validationState, Insecure);
9005 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9006 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9007 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9008 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9009}
9010
9011BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
9012 /*
9013 Validation is optional, and the first query does not ask for it,
9014 so the answer is negatively cached as Indeterminate.
9015 The second query asks for validation, answer should be marked as
9016 Bogus.
9017 */
9018 std::unique_ptr<SyncRes> sr;
9019 initSR(sr, true);
9020
9021 setDNSSECValidation(sr, DNSSECMode::Process);
9022
9023 primeHints();
9024 const DNSName target("com.");
9025 testkeysset_t keys;
9026
9027 auto luaconfsCopy = g_luaconfs.getCopy();
9028 luaconfsCopy.dsAnchors.clear();
9029 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9030 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9031 g_luaconfs.setState(luaconfsCopy);
9032
9033 size_t queriesCount = 0;
9034
9035 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) {
9036 queriesCount++;
9037
9038 DNSName auth = domain;
9039 auth.chopOff();
9040
9041 if (type == QType::DS || type == QType::DNSKEY) {
9042 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9043 }
9044 else {
9045 setLWResult(res, RCode::NoError, true, false, true);
9046 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9047 addRRSIG(keys, res->d_records, domain, 300);
9048 /* no denial */
9049 return 1;
9050 }
9051
9052 return 0;
9053 });
9054
9055 vector<DNSRecord> ret;
9056 /* first query does not require validation */
9057 sr->setDNSSECValidationRequested(false);
9058 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9059 BOOST_CHECK_EQUAL(res, RCode::NoError);
9060 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9061 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9062 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9063 NegCache::NegCacheEntry ne;
9064 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9065 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9066 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9067 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9068 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9069 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9070 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9071
9072 ret.clear();
9073 /* second one _does_ require validation */
9074 sr->setDNSSECValidationRequested(true);
9075 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9076 BOOST_CHECK_EQUAL(res, RCode::NoError);
9077 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9078 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9079 BOOST_CHECK_EQUAL(queriesCount, 4);
b25712fd
RG
9080 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9081 BOOST_CHECK_EQUAL(ne.d_validationState, Bogus);
9082 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9083 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9084 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9085 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9086}
9087
429ce1da
PL
9088BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
9089 g_lowercaseOutgoing = true;
9090 std::unique_ptr<SyncRes> sr;
9091 initSR(sr);
9092
9093 primeHints();
9094
9095 vector<DNSName> sentOutQnames;
9096
9097 const DNSName target("WWW.POWERDNS.COM");
9098 const DNSName cname("WWW.PowerDNS.org");
9099
9100 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) {
9101
9102 sentOutQnames.push_back(domain);
9103
9104 if (isRootServer(ip)) {
9105 if (domain == target) {
9106 setLWResult(res, 0, false, false, true);
9107 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
9108 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
9109 return 1;
9110 }
9111 if (domain == cname) {
9112 setLWResult(res, 0, false, false, true);
9113 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
9114 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
9115 return 1;
9116 }
9117 } else if (ip == ComboAddress("192.0.2.1:53")) {
9118 if (domain == target) {
9119 setLWResult(res, 0, true, false, false);
9120 addRecordToLW(res, domain, QType::CNAME, cname.toString());
9121 return 1;
9122 }
9123 } else if (ip == ComboAddress("192.0.2.2:53")) {
9124 if (domain == cname) {
9125 setLWResult(res, 0, true, false, false);
9126 addRecordToLW(res, domain, QType::A, "127.0.0.1");
9127 return 1;
9128 }
9129 }
9130 return 0;
9131 });
9132
9133 vector<DNSRecord> ret;
9134 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9135
9136 BOOST_CHECK_EQUAL(res, RCode::NoError);
9137
9138 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9139 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
9140
9141 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
9142 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
9143 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
9144 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
9145 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
9146
9147 g_lowercaseOutgoing = false;
9148}
9149
4d787d30
PL
9150BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
9151 std::unique_ptr<SyncRes> sr;
9152 initSR(sr, true);
9153
9154 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9155
9156 primeHints();
9157 const DNSName target("com.");
9158 testkeysset_t keys, keys2;
9159
9160 auto luaconfsCopy = g_luaconfs.getCopy();
9161 luaconfsCopy.dsAnchors.clear();
9162 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9163 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9164 g_luaconfs.setState(luaconfsCopy);
9165
9166 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9167 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9168 // But add the existing root key otherwise no RRSIG can be created
9169 auto rootkey = keys.find(g_rootdnsname);
9170 keys2.insert(*rootkey);
9171
9172 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) {
9173 DNSName auth = domain;
9174 auth.chopOff();
9175 if (type == QType::DS || type == QType::DNSKEY) {
9176 if (domain == target) {
9177 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9178 return 0;
9179 }
9180 }
9181 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9182 }
9183 return 0;
9184 });
9185
9186 dsmap_t ds;
9187 auto state = sr->getDSRecords(target, ds, false, 0, false);
9188 BOOST_CHECK_EQUAL(state, Secure);
9189 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9190 for (const auto& i : ds) {
9191 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9192 }
9193}
9194
9195BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
9196 std::unique_ptr<SyncRes> sr;
9197 initSR(sr, true);
9198
9199 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9200
9201 primeHints();
9202 const DNSName target("com.");
9203 testkeysset_t keys, keys2, keys3;
9204
9205 auto luaconfsCopy = g_luaconfs.getCopy();
9206 luaconfsCopy.dsAnchors.clear();
9207 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9208 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9209 g_luaconfs.setState(luaconfsCopy);
9210
9211 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9212 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9213 // But add the existing root key otherwise no RRSIG can be created
9214 auto rootkey = keys.find(g_rootdnsname);
9215 keys2.insert(*rootkey);
9216
9217 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
9218 // But add the existing root key otherwise no RRSIG can be created
9219 keys3.insert(*rootkey);
9220
9221 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) {
9222 DNSName auth = domain;
9223 auth.chopOff();
9224 if (type == QType::DS || type == QType::DNSKEY) {
9225 if (domain == target) {
9226 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9227 return 0;
9228 }
9229 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9230 return 0;
9231 }
9232 }
9233 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9234 }
9235 return 0;
9236 });
9237
9238 dsmap_t ds;
9239 auto state = sr->getDSRecords(target, ds, false, 0, false);
9240 BOOST_CHECK_EQUAL(state, Secure);
9241 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9242 for (const auto& i : ds) {
9243 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9244 }
9245}
9246
9247BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
9248 std::unique_ptr<SyncRes> sr;
9249 initSR(sr, true);
9250
9251 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9252
9253 primeHints();
9254 const DNSName target("com.");
9255 testkeysset_t keys, keys2, keys3;
9256
9257 auto luaconfsCopy = g_luaconfs.getCopy();
9258 luaconfsCopy.dsAnchors.clear();
9259 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9260 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9261 g_luaconfs.setState(luaconfsCopy);
9262
9263 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9264 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
9265 // But add the existing root key otherwise no RRSIG can be created
9266 auto rootkey = keys.find(g_rootdnsname);
9267 keys2.insert(*rootkey);
9268
9269 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
9270 // But add the existing root key otherwise no RRSIG can be created
9271 keys3.insert(*rootkey);
9272
9273 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) {
9274 DNSName auth = domain;
9275 auth.chopOff();
9276 if (type == QType::DS || type == QType::DNSKEY) {
9277 if (domain == target) {
9278 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9279 return 0;
9280 }
9281 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9282 return 0;
9283 }
9284 }
9285 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9286 }
9287 return 0;
9288 });
9289
9290 dsmap_t ds;
9291 auto state = sr->getDSRecords(target, ds, false, 0, false);
9292 BOOST_CHECK_EQUAL(state, Secure);
9293 BOOST_REQUIRE_EQUAL(ds.size(), 2);
9294 for (const auto& i : ds) {
9295 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9296 }
9297}
9298
77cb3d33 9299#ifdef HAVE_BOTAN
4d787d30
PL
9300BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) {
9301 std::unique_ptr<SyncRes> sr;
9302 initSR(sr, true);
9303
9304 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9305
9306 primeHints();
9307 const DNSName target("com.");
9308 testkeysset_t keys, keys2;
9309
9310 auto luaconfsCopy = g_luaconfs.getCopy();
9311 luaconfsCopy.dsAnchors.clear();
9312 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9313 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys);
9314 g_luaconfs.setState(luaconfsCopy);
9315
9316 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9317 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9318 // But add the existing root key otherwise no RRSIG can be created
9319 auto rootkey = keys.find(g_rootdnsname);
9320 keys2.insert(*rootkey);
9321
9322 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) {
9323 DNSName auth = domain;
9324 auth.chopOff();
9325 if (type == QType::DS || type == QType::DNSKEY) {
9326 if (domain == target) {
9327 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9328 return 0;
9329 }
9330 }
9331 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9332 }
9333 return 0;
9334 });
9335
9336 dsmap_t ds;
9337 auto state = sr->getDSRecords(target, ds, false, 0, false);
9338 BOOST_CHECK_EQUAL(state, Secure);
9339 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9340 for (const auto& i : ds) {
9341 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9342 }
9343}
9344
9345BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) {
9346 std::unique_ptr<SyncRes> sr;
9347 initSR(sr, true);
9348
9349 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9350
9351 primeHints();
9352 const DNSName target("com.");
9353 testkeysset_t keys, keys2;
9354
9355 auto luaconfsCopy = g_luaconfs.getCopy();
9356 luaconfsCopy.dsAnchors.clear();
9357 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9358 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9359 g_luaconfs.setState(luaconfsCopy);
9360
9361 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9362 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9363 // But add the existing root key otherwise no RRSIG can be created
9364 auto rootkey = keys.find(g_rootdnsname);
9365 keys2.insert(*rootkey);
9366
9367 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) {
9368 DNSName auth = domain;
9369 auth.chopOff();
9370 if (type == QType::DS || type == QType::DNSKEY) {
9371 if (domain == target) {
9372 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9373 return 0;
9374 }
9375 }
9376 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9377 }
9378 return 0;
9379 });
9380
9381 dsmap_t ds;
9382 auto state = sr->getDSRecords(target, ds, false, 0, false);
9383 BOOST_CHECK_EQUAL(state, Secure);
9384 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9385 for (const auto& i : ds) {
9386 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9387 }
9388}
9389
9390BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) {
9391 std::unique_ptr<SyncRes> sr;
9392 initSR(sr, true);
9393
9394 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9395
9396 primeHints();
9397 const DNSName target("com.");
9398 testkeysset_t keys, keys2;
9399
9400 auto luaconfsCopy = g_luaconfs.getCopy();
9401 luaconfsCopy.dsAnchors.clear();
9402 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9403 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys);
9404 g_luaconfs.setState(luaconfsCopy);
9405
9406 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9407 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9408 // But add the existing root key otherwise no RRSIG can be created
9409 auto rootkey = keys.find(g_rootdnsname);
9410 keys2.insert(*rootkey);
9411
9412 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) {
9413 DNSName auth = domain;
9414 auth.chopOff();
9415 if (type == QType::DS || type == QType::DNSKEY) {
9416 if (domain == target) {
9417 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9418 return 0;
9419 }
9420 }
9421 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9422 }
9423 return 0;
9424 });
9425
9426 dsmap_t ds;
9427 auto state = sr->getDSRecords(target, ds, false, 0, false);
9428 BOOST_CHECK_EQUAL(state, Secure);
9429 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9430 for (const auto& i : ds) {
9431 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST);
9432 }
9433}
9434#endif // HAVE_BOTAN110
9435
d6e797b8
RG
9436/*
9437// cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
9438
648bcbd1 9439- check out of band support
d6e797b8 9440
648bcbd1 9441- check preoutquery
d6e797b8 9442
30ee601a
RG
9443*/
9444
9445BOOST_AUTO_TEST_SUITE_END()