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