]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursordist/test-syncres_cc.cc
rec: Revert 'Keep the EDNS status of a server on FormErr with EDNS'
[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
eb5dfa69 5#include "syncres.hh"
30ee601a 6#include "arguments.hh"
95823c07 7#include "base32.hh"
8455425c
RG
8#include "dnssecinfra.hh"
9#include "dnsseckeeper.hh"
30ee601a
RG
10#include "lua-recursor4.hh"
11#include "namespaces.hh"
12#include "rec-lua-conf.hh"
13#include "root-dnssec.hh"
e503653f 14#include "test-common.hh"
6dfff36f 15#include "utility.hh"
30ee601a
RG
16#include "validate-recursor.hh"
17
30ee601a
RG
18RecursorStats g_stats;
19GlobalStateHolder<LuaConfigItems> g_luaconfs;
f26bf547 20thread_local std::unique_ptr<MemRecursorCache> t_RC{nullptr};
30ee601a 21unsigned int g_numThreads = 1;
c1c29961 22bool g_lowercaseOutgoing = false;
30ee601a
RG
23
24/* Fake some required functions we didn't want the trouble to
25 link with */
26ArgvMap &arg()
27{
28 static ArgvMap theArg;
29 return theArg;
30}
31
32int getMTaskerTID()
33{
34 return 0;
35}
36
3c5901d7 37bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
30ee601a
RG
38{
39 return false;
40}
41
18d5b679 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, bool* chained)
30ee601a
RG
43{
44 return 0;
45}
46
47/* primeHints() is only here for now because it
48 was way too much trouble to link with the real one.
49 We should fix this, empty functions are one thing, but this is
50 bad.
51*/
52
53#include "root-addresses.hh"
54
55void primeHints(void)
56{
57 vector<DNSRecord> nsset;
58 if(!t_RC)
f26bf547 59 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
30ee601a
RG
60
61 DNSRecord arr, aaaarr, nsrr;
62 nsrr.d_name=g_rootdnsname;
63 arr.d_type=QType::A;
64 aaaarr.d_type=QType::AAAA;
65 nsrr.d_type=QType::NS;
66 arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(nullptr)+3600000;
67
68 for(char c='a';c<='m';++c) {
6b4ca097 69 char templ[40];
30ee601a
RG
70 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
71 templ[sizeof(templ)-1] = '\0';
72 *templ=c;
73 aaaarr.d_name=arr.d_name=DNSName(templ);
74 nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
75 arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
76 vector<DNSRecord> aset;
77 aset.push_back(arr);
2b984251 78 t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
30ee601a
RG
79 if (rootIps6[c-'a'] != NULL) {
80 aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
81
82 vector<DNSRecord> aaaaset;
83 aaaaset.push_back(aaaarr);
2b984251 84 t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
30ee601a
RG
85 }
86
87 nsset.push_back(nsrr);
88 }
2b984251 89 t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
30ee601a
RG
90}
91
92LuaConfigItems::LuaConfigItems()
93{
94 for (const auto &dsRecord : rootDSs) {
6fb72eaa 95 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
30ee601a
RG
96 dsAnchors[g_rootdnsname].insert(*ds);
97 }
98}
99
100/* Some helpers functions */
101
102static void init(bool debug=false)
103{
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) {
6fb72eaa 154 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
8455425c
RG
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
18d5b679 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, bool* chained) {
4d2be65d
RG
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
18d5b679 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, bool* chained) {
30ee601a
RG
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 */
18d5b679 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, bool* chained) {
30ee601a
RG
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
18d5b679 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, bool* chained) {
30ee601a
RG
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
18d5b679 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, bool* chained) {
30ee601a
RG
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
a2372789
RG
650BOOST_AUTO_TEST_CASE(test_edns_formerr_but_edns_enabled) {
651 std::unique_ptr<SyncRes> sr;
652 initSR(sr);
653
654 /* in this test, the auth answers with FormErr to an EDNS-enabled
ea82c854
RG
655 query, but the response does contain EDNS so we might consider
656 that the server knows a bit about EDNS. It turns out that we can't
657 because there are too many awful servers out there.
a2372789
RG
658 */
659 size_t queriesWithEDNS = 0;
660 size_t queriesWithoutEDNS = 0;
661 std::set<ComboAddress> usedServers;
662
663 sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &usedServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
664
665 if (EDNS0Level > 0) {
666 queriesWithEDNS++;
667 }
668 else {
669 queriesWithoutEDNS++;
670 }
671 usedServers.insert(ip);
672
ea82c854 673 if (type == QType::A) {
a2372789 674 if (EDNS0Level > 0) {
ea82c854 675 setLWResult(res, RCode::FormErr);
a2372789
RG
676 res->d_haveEDNS = true;
677 }
ea82c854
RG
678 else {
679 setLWResult(res, 0, true, false, false);
680 addRecordToLW(res, domain, QType::A, "192.0.2.1");
681 }
a2372789
RG
682 return 1;
683 }
684
685 return 0;
686 });
687
688 primeHints();
689
690 vector<DNSRecord> ret;
ea82c854
RG
691 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
692 BOOST_CHECK_EQUAL(res, RCode::NoError);
693 BOOST_CHECK_EQUAL(ret.size(), 1);
694 BOOST_CHECK_EQUAL(queriesWithEDNS, 1);
695 BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1);
696 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 1);
697 BOOST_CHECK_EQUAL(usedServers.size(), 1);
a2372789 698 for (const auto& server : usedServers) {
ea82c854 699 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::NOEDNS);
a2372789
RG
700 }
701}
702
30ee601a
RG
703BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) {
704 std::unique_ptr<SyncRes> sr;
895449a5 705 initSR(sr);
30ee601a 706
18d5b679 707 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, bool* chained) {
30ee601a
RG
708 if (!doTCP) {
709 setLWResult(res, 0, false, true, false);
710 return 1;
711 }
712 if (domain == DNSName("powerdns.com") && type == QType::A && doTCP) {
713 setLWResult(res, 0, true, false, false);
714 addRecordToLW(res, domain, QType::A, "192.0.2.1");
715 return 1;
716 }
717
718 return 0;
719 });
720
721 primeHints();
722
723 /* fake that the NS truncates every request over UDP, we should fallback to TCP */
724 vector<DNSRecord> ret;
725 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 726 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a
RG
727}
728
3337c2f7
RG
729BOOST_AUTO_TEST_CASE(test_tc_over_tcp) {
730 std::unique_ptr<SyncRes> sr;
895449a5 731 initSR(sr);
3337c2f7
RG
732
733 size_t tcpQueriesCount = 0;
734
18d5b679 735 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, bool* chained) {
3337c2f7
RG
736 if (!doTCP) {
737 setLWResult(res, 0, true, true, false);
738 return 1;
739 }
740
741 /* first TCP query is answered with a TC response */
742 tcpQueriesCount++;
743 if (tcpQueriesCount == 1) {
744 setLWResult(res, 0, true, true, false);
745 }
746 else {
747 setLWResult(res, 0, true, false, false);
748 }
749
750 addRecordToLW(res, domain, QType::A, "192.0.2.1");
751 return 1;
752 });
753
754 primeHints();
755
756 vector<DNSRecord> ret;
757 int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::A), QClass::IN, ret);
b7f378d1 758 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
759 BOOST_CHECK_EQUAL(tcpQueriesCount, 2);
760}
761
30ee601a
RG
762BOOST_AUTO_TEST_CASE(test_all_nss_down) {
763 std::unique_ptr<SyncRes> sr;
895449a5 764 initSR(sr);
30ee601a
RG
765 std::set<ComboAddress> downServers;
766
767 primeHints();
768
18d5b679 769 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, bool* chained) {
30ee601a
RG
770
771 if (isRootServer(ip)) {
8455425c 772 setLWResult(res, 0, false, false, true);
30ee601a
RG
773 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
774 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
775 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
776 return 1;
777 }
778 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 779 setLWResult(res, 0, false, false, true);
30ee601a
RG
780 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
781 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
782 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
783 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
784 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
785 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
786 return 1;
787 }
788 else {
789 downServers.insert(ip);
790 return 0;
791 }
792 });
793
ccb07d93
RG
794 DNSName target("powerdns.com.");
795
30ee601a 796 vector<DNSRecord> ret;
ccb07d93 797 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 798 BOOST_CHECK_EQUAL(res, RCode::ServFail);
30ee601a
RG
799 BOOST_CHECK_EQUAL(ret.size(), 0);
800 BOOST_CHECK_EQUAL(downServers.size(), 4);
801
802 for (const auto& server : downServers) {
a712cb56
RG
803 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
804 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
30ee601a
RG
805 }
806}
807
648bcbd1
RG
808BOOST_AUTO_TEST_CASE(test_all_nss_network_error) {
809 std::unique_ptr<SyncRes> sr;
895449a5 810 initSR(sr);
648bcbd1
RG
811 std::set<ComboAddress> downServers;
812
813 primeHints();
814
18d5b679 815 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, bool* chained) {
648bcbd1
RG
816
817 if (isRootServer(ip)) {
8455425c 818 setLWResult(res, 0, false, false, true);
648bcbd1
RG
819 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
820 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
821 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
822 return 1;
823 }
824 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 825 setLWResult(res, 0, false, false, true);
648bcbd1
RG
826 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
827 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
828 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
829 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
830 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
831 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
832 return 1;
833 }
834 else {
835 downServers.insert(ip);
b4c8789a 836 return 0;
648bcbd1
RG
837 }
838 });
839
840 /* exact same test than the previous one, except instead of a time out we fake a network error */
841 DNSName target("powerdns.com.");
842
843 vector<DNSRecord> ret;
844 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
845 BOOST_CHECK_EQUAL(res, RCode::ServFail);
846 BOOST_CHECK_EQUAL(ret.size(), 0);
847 BOOST_CHECK_EQUAL(downServers.size(), 4);
848
849 for (const auto& server : downServers) {
a712cb56
RG
850 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 1);
851 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), server, target, QType::A));
648bcbd1
RG
852 }
853}
854
b4c8789a
RG
855BOOST_AUTO_TEST_CASE(test_only_one_ns_up_resolving_itself_with_glue) {
856 std::unique_ptr<SyncRes> sr;
857 initSR(sr);
858
859 primeHints();
860
861 DNSName target("www.powerdns.com.");
862
18d5b679 863 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, bool* chained) {
b4c8789a
RG
864
865 if (isRootServer(ip)) {
866 setLWResult(res, 0, false, false, true);
867 if (domain == target) {
868 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
869 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
870 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
871 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
872 }
873 else if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
874 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns2.powerdns.net.", DNSResourceRecord::AUTHORITY, 172800);
875 addRecordToLW(res, "powerdns.net.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
876 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
877 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
878 }
879 return 1;
880 }
881 else if (ip == ComboAddress("192.0.2.3:53")) {
882 setLWResult(res, 0, true, false, true);
883 if (domain == DNSName("pdns-public-ns2.powerdns.net.")) {
884 if (type == QType::A) {
885 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::A, "192.0.2.3");
886 }
887 else if (type == QType::AAAA) {
888 addRecordToLW(res, "pdns-public-ns2.powerdns.net.", QType::AAAA, "2001:DB8::3");
889 }
890 }
891 else if (domain == target) {
892 if (type == QType::A) {
893 addRecordToLW(res, domain, QType::A, "192.0.2.1");
894 }
895 else if (type == QType::AAAA) {
896 addRecordToLW(res, domain, QType::AAAA, "2001:DB8::1");
897 }
898 }
899 return 1;
900 }
901 return 0;
902 });
903
904 vector<DNSRecord> ret;
905 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
906 BOOST_CHECK_EQUAL(res, RCode::NoError);
907 BOOST_CHECK_EQUAL(ret.size(), 1);
908}
909
648bcbd1
RG
910BOOST_AUTO_TEST_CASE(test_os_limit_errors) {
911 std::unique_ptr<SyncRes> sr;
895449a5 912 initSR(sr);
648bcbd1
RG
913 std::set<ComboAddress> downServers;
914
915 primeHints();
916
18d5b679 917 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, bool* chained) {
648bcbd1
RG
918
919 if (isRootServer(ip)) {
8455425c 920 setLWResult(res, 0, false, false, true);
648bcbd1
RG
921 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
922 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
923 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
924 return 1;
925 }
926 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 927 setLWResult(res, 0, false, false, true);
648bcbd1
RG
928 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
929 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
930 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
931 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
932 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
933 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
934 return 1;
935 }
936 else {
937 if (downServers.size() < 3) {
938 /* only the last one will answer */
939 downServers.insert(ip);
940 return -2;
941 }
942 else {
943 setLWResult(res, 0, true, false, true);
944 addRecordToLW(res, "powerdns.com.", QType::A, "192.0.2.42");
945 return 1;
946 }
947 }
948 });
949
950 DNSName target("powerdns.com.");
951
952 vector<DNSRecord> ret;
953 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 954 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
955 BOOST_CHECK_EQUAL(ret.size(), 1);
956 BOOST_CHECK_EQUAL(downServers.size(), 3);
957
958 /* Error is reported as "OS limit error" (-2) so the servers should _NOT_ be marked down */
959 for (const auto& server : downServers) {
a712cb56
RG
960 BOOST_CHECK_EQUAL(SyncRes::getServerFailsCount(server), 0);
961 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), server, target, QType::A));
648bcbd1
RG
962 }
963}
964
30ee601a
RG
965BOOST_AUTO_TEST_CASE(test_glued_referral) {
966 std::unique_ptr<SyncRes> sr;
895449a5 967 initSR(sr);
30ee601a
RG
968
969 primeHints();
970
971 const DNSName target("powerdns.com.");
972
18d5b679 973 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, bool* chained) {
30ee601a
RG
974 /* this will cause issue with qname minimization if we ever implement it */
975 if (domain != target) {
976 return 0;
977 }
978
979 if (isRootServer(ip)) {
8455425c 980 setLWResult(res, 0, false, false, true);
30ee601a
RG
981 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
982 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
983 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
984 return 1;
985 }
986 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
8455425c 987 setLWResult(res, 0, false, false, true);
30ee601a
RG
988 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
989 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
990 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800);
991 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800);
992 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800);
993 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800);
994 return 1;
995 }
996 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")) {
997 setLWResult(res, 0, true, false, true);
998 addRecordToLW(res, target, QType::A, "192.0.2.4");
999 return 1;
1000 }
1001 else {
1002 return 0;
1003 }
1004 });
1005
1006 vector<DNSRecord> ret;
1007 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1008 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 1009 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 1010 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
1011 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1012}
1013
1014BOOST_AUTO_TEST_CASE(test_glueless_referral) {
1015 std::unique_ptr<SyncRes> sr;
895449a5 1016 initSR(sr);
30ee601a
RG
1017
1018 primeHints();
1019
1020 const DNSName target("powerdns.com.");
1021
18d5b679 1022 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, bool* chained) {
30ee601a
RG
1023
1024 if (isRootServer(ip)) {
8455425c 1025 setLWResult(res, 0, false, false, true);
30ee601a
RG
1026
1027 if (domain.isPartOf(DNSName("com."))) {
1028 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1029 } else if (domain.isPartOf(DNSName("org."))) {
1030 addRecordToLW(res, "org.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1031 }
1032 else {
1033 setLWResult(res, RCode::NXDomain, false, false, true);
1034 return 1;
1035 }
1036
1037 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1038 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1039 return 1;
1040 }
1041 else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) {
1042 if (domain == target) {
8455425c 1043 setLWResult(res, 0, false, false, true);
30ee601a
RG
1044 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1045 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1046 return 1;
1047 }
1048 else if (domain == DNSName("pdns-public-ns1.powerdns.org.")) {
1049 setLWResult(res, 0, true, false, true);
1050 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2");
1051 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::AAAA, "2001:DB8::2");
1052 return 1;
1053 }
1054 else if (domain == DNSName("pdns-public-ns2.powerdns.org.")) {
1055 setLWResult(res, 0, true, false, true);
1056 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::A, "192.0.2.3");
1057 addRecordToLW(res, "pdns-public-ns2.powerdns.org.", QType::AAAA, "2001:DB8::3");
1058 return 1;
1059 }
1060
1061 setLWResult(res, RCode::NXDomain, false, false, true);
1062 return 1;
1063 }
1064 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")) {
1065 setLWResult(res, 0, true, false, true);
1066 addRecordToLW(res, target, QType::A, "192.0.2.4");
1067 return 1;
1068 }
1069 else {
1070 return 0;
1071 }
1072 });
1073
1074 vector<DNSRecord> ret;
1075 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1076 BOOST_CHECK_EQUAL(res, RCode::NoError);
30ee601a 1077 BOOST_REQUIRE_EQUAL(ret.size(), 1);
e9f9b8ec 1078 BOOST_CHECK(ret[0].d_type == QType::A);
30ee601a
RG
1079 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1080}
1081
e9f9b8ec
RG
1082BOOST_AUTO_TEST_CASE(test_edns_submask_by_domain) {
1083 std::unique_ptr<SyncRes> sr;
895449a5 1084 initSR(sr);
e9f9b8ec
RG
1085
1086 primeHints();
1087
1088 const DNSName target("powerdns.com.");
9065eb05 1089 SyncRes::addEDNSDomain(target);
e9f9b8ec
RG
1090
1091 EDNSSubnetOpts incomingECS;
1092 incomingECS.source = Netmask("192.0.2.128/32");
1093 sr->setIncomingECSFound(true);
1094 sr->setIncomingECS(incomingECS);
1095
18d5b679 1096 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, bool* chained) {
e9f9b8ec
RG
1097
1098 BOOST_REQUIRE(srcmask);
1099 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1100 return 0;
1101 });
1102
1103 vector<DNSRecord> ret;
1104 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379 1105 BOOST_CHECK_EQUAL(res, RCode::ServFail);
e9f9b8ec
RG
1106}
1107
1108BOOST_AUTO_TEST_CASE(test_edns_submask_by_addr) {
1109 std::unique_ptr<SyncRes> sr;
895449a5 1110 initSR(sr);
e9f9b8ec
RG
1111
1112 primeHints();
1113
1114 const DNSName target("powerdns.com.");
9065eb05 1115 SyncRes::addEDNSSubnet(Netmask("192.0.2.1/32"));
e9f9b8ec
RG
1116
1117 EDNSSubnetOpts incomingECS;
1118 incomingECS.source = Netmask("2001:DB8::FF/128");
1119 sr->setIncomingECSFound(true);
1120 sr->setIncomingECS(incomingECS);
1121
18d5b679 1122 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, bool* chained) {
e9f9b8ec
RG
1123
1124 if (isRootServer(ip)) {
1125 BOOST_REQUIRE(!srcmask);
1126
8455425c 1127 setLWResult(res, 0, false, false, true);
e9f9b8ec
RG
1128 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1129 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1130 return 1;
1131 } else if (ip == ComboAddress("192.0.2.1:53")) {
1132
1133 BOOST_REQUIRE(srcmask);
1134 BOOST_CHECK_EQUAL(srcmask->toString(), "2001:db8::/56");
1135
1136 setLWResult(res, 0, true, false, false);
1137 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1138 return 1;
1139 }
1140
1141 return 0;
1142 });
1143
1144 vector<DNSRecord> ret;
1145 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1146 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
1147 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1148 BOOST_CHECK(ret[0].d_type == QType::A);
1149 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1150}
1151
1152BOOST_AUTO_TEST_CASE(test_following_cname) {
1153 std::unique_ptr<SyncRes> sr;
895449a5 1154 initSR(sr);
778bcea6
RG
1155
1156 primeHints();
1157
1158 const DNSName target("cname.powerdns.com.");
1159 const DNSName cnameTarget("cname-target.powerdns.com");
1160
18d5b679 1161 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, bool* chained) {
778bcea6
RG
1162
1163 if (isRootServer(ip)) {
8455425c 1164 setLWResult(res, 0, false, false, true);
778bcea6
RG
1165 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1166 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1167 return 1;
1168 } else if (ip == ComboAddress("192.0.2.1:53")) {
1169
1170 if (domain == target) {
1171 setLWResult(res, 0, true, false, false);
1172 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1173 return 1;
1174 }
1175 else if (domain == cnameTarget) {
1176 setLWResult(res, 0, true, false, false);
1177 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1178 }
1179
1180 return 1;
1181 }
1182
1183 return 0;
1184 });
1185
1186 vector<DNSRecord> ret;
1187 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1188 BOOST_CHECK_EQUAL(res, RCode::NoError);
778bcea6
RG
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::A);
1193 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1194}
1195
9b061cf5
RG
1196BOOST_AUTO_TEST_CASE(test_cname_nxdomain) {
1197 std::unique_ptr<SyncRes> sr;
1198 initSR(sr);
1199
1200 primeHints();
1201
1202 const DNSName target("cname.powerdns.com.");
1203 const DNSName cnameTarget("cname-target.powerdns.com");
1204
18d5b679 1205 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, bool* chained) {
9b061cf5
RG
1206
1207 if (isRootServer(ip)) {
1208 setLWResult(res, 0, false, false, true);
1209 addRecordToLW(res, "powerdns.com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1210 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1211 return 1;
1212 } else if (ip == ComboAddress("192.0.2.1:53")) {
1213
1214 if (domain == target) {
1215 setLWResult(res, RCode::NXDomain, true, false, false);
1216 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1217 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1218 } else if (domain == cnameTarget) {
1219 setLWResult(res, RCode::NXDomain, true, false, false);
1220 addRecordToLW(res, "powerdns.com.", QType::SOA, "a.powerdns.com. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1221 return 1;
1222 }
1223
1224 return 1;
1225 }
1226
1227 return 0;
1228 });
1229
1230 vector<DNSRecord> ret;
1231 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1232 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1233 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1234 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1235 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1236 BOOST_CHECK(ret[1].d_type == QType::SOA);
1237
1238 /* a second time, to check the cache */
1239 ret.clear();
1240 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1241 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1242 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1243 BOOST_CHECK(ret[0].d_type == QType::CNAME);
1244 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1245 BOOST_CHECK(ret[1].d_type == QType::SOA);
1246}
1247
4fff116b
RG
1248BOOST_AUTO_TEST_CASE(test_included_poisonous_cname) {
1249 std::unique_ptr<SyncRes> sr;
895449a5 1250 initSR(sr);
4fff116b
RG
1251
1252 primeHints();
1253
1254 /* In this test we directly get the NS server for cname.powerdns.com.,
1255 and we don't know whether it's also authoritative for
1256 cname-target.powerdns.com or powerdns.com, so we shouldn't accept
1257 the additional A record for cname-target.powerdns.com. */
1258 const DNSName target("cname.powerdns.com.");
1259 const DNSName cnameTarget("cname-target.powerdns.com");
1260
18d5b679 1261 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, bool* chained) {
4fff116b
RG
1262
1263 if (isRootServer(ip)) {
1264
8455425c 1265 setLWResult(res, 0, false, false, true);
4fff116b
RG
1266
1267 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1268 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1269 return 1;
1270 } else if (ip == ComboAddress("192.0.2.1:53")) {
1271
1272 if (domain == target) {
1273 setLWResult(res, 0, true, false, false);
1274 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1275 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL);
1276 return 1;
1277 } else if (domain == cnameTarget) {
1278 setLWResult(res, 0, true, false, false);
1279 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.3");
1280 return 1;
1281 }
1282
1283 return 1;
1284 }
1285
1286 return 0;
1287 });
1288
1289 vector<DNSRecord> ret;
1290 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1291 BOOST_CHECK_EQUAL(res, RCode::NoError);
4fff116b
RG
1292 BOOST_REQUIRE_EQUAL(ret.size(), 2);
1293 BOOST_REQUIRE(ret[0].d_type == QType::CNAME);
1294 BOOST_CHECK_EQUAL(ret[0].d_name, target);
1295 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget(), cnameTarget);
1296 BOOST_REQUIRE(ret[1].d_type == QType::A);
1297 BOOST_CHECK_EQUAL(ret[1].d_name, cnameTarget);
1298 BOOST_CHECK(getRR<ARecordContent>(ret[1])->getCA() == ComboAddress("192.0.2.3"));
1299}
1300
778bcea6
RG
1301BOOST_AUTO_TEST_CASE(test_cname_loop) {
1302 std::unique_ptr<SyncRes> sr;
895449a5 1303 initSR(sr);
778bcea6
RG
1304
1305 primeHints();
1306
1307 size_t count = 0;
1308 const DNSName target("cname.powerdns.com.");
1309
18d5b679 1310 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, bool* chained) {
778bcea6
RG
1311
1312 count++;
1313
1314 if (isRootServer(ip)) {
778bcea6 1315
8455425c 1316 setLWResult(res, 0, false, false, true);
778bcea6
RG
1317 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1318 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1319 return 1;
1320 } else if (ip == ComboAddress("192.0.2.1:53")) {
1321
1322 if (domain == target) {
1323 setLWResult(res, 0, true, false, false);
1324 addRecordToLW(res, domain, QType::CNAME, domain.toString());
1325 return 1;
1326 }
1327
1328 return 1;
1329 }
1330
1331 return 0;
1332 });
1333
1334 vector<DNSRecord> ret;
1335 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1336 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1337 BOOST_CHECK_GT(ret.size(), 0);
778bcea6 1338 BOOST_CHECK_EQUAL(count, 2);
e9f9b8ec
RG
1339}
1340
4fff116b
RG
1341BOOST_AUTO_TEST_CASE(test_cname_depth) {
1342 std::unique_ptr<SyncRes> sr;
895449a5 1343 initSR(sr);
4fff116b
RG
1344
1345 primeHints();
1346
1347 size_t depth = 0;
1348 const DNSName target("cname.powerdns.com.");
1349
18d5b679 1350 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, bool* chained) {
4fff116b
RG
1351
1352 if (isRootServer(ip)) {
4fff116b 1353
8455425c 1354 setLWResult(res, 0, false, false, true);
4fff116b
RG
1355 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1356 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1357 return 1;
1358 } else if (ip == ComboAddress("192.0.2.1:53")) {
1359
1360 setLWResult(res, 0, true, false, false);
1361 addRecordToLW(res, domain, QType::CNAME, std::to_string(depth) + "-cname.powerdns.com");
1362 depth++;
1363 return 1;
1364 }
1365
1366 return 0;
1367 });
1368
1369 vector<DNSRecord> ret;
1370 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1371 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1372 BOOST_CHECK_EQUAL(ret.size(), depth);
4fff116b
RG
1373 /* we have an arbitrary limit at 10 when following a CNAME chain */
1374 BOOST_CHECK_EQUAL(depth, 10 + 2);
1375}
1376
d6e797b8
RG
1377BOOST_AUTO_TEST_CASE(test_time_limit) {
1378 std::unique_ptr<SyncRes> sr;
895449a5 1379 initSR(sr);
d6e797b8
RG
1380
1381 primeHints();
1382
1383 size_t queries = 0;
1384 const DNSName target("cname.powerdns.com.");
1385
18d5b679 1386 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, bool* chained) {
d6e797b8
RG
1387
1388 queries++;
1389
1390 if (isRootServer(ip)) {
8455425c 1391 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1392 /* Pretend that this query took 2000 ms */
1393 res->d_usec = 2000;
1394
1395 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1396 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1397 return 1;
1398 } else if (ip == ComboAddress("192.0.2.1:53")) {
1399
1400 setLWResult(res, 0, true, false, false);
1401 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1402 return 1;
1403 }
1404
1405 return 0;
1406 });
1407
1408 /* Set the maximum time to 1 ms */
1409 SyncRes::s_maxtotusec = 1000;
1410
1411 try {
1412 vector<DNSRecord> ret;
1413 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1414 BOOST_CHECK(false);
1415 }
1416 catch(const ImmediateServFailException& e) {
1417 }
1418 BOOST_CHECK_EQUAL(queries, 1);
1419}
1420
1421BOOST_AUTO_TEST_CASE(test_referral_depth) {
1422 std::unique_ptr<SyncRes> sr;
895449a5 1423 initSR(sr);
d6e797b8
RG
1424
1425 primeHints();
1426
1427 size_t queries = 0;
1428 const DNSName target("www.powerdns.com.");
1429
18d5b679 1430 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, bool* chained) {
d6e797b8
RG
1431
1432 queries++;
1433
1434 if (isRootServer(ip)) {
8455425c 1435 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1436
1437 if (domain == DNSName("www.powerdns.com.")) {
1438 addRecordToLW(res, domain, QType::NS, "ns.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1439 }
1440 else if (domain == DNSName("ns.powerdns.com.")) {
1441 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1442 }
1443 else if (domain == DNSName("ns1.powerdns.org.")) {
1444 addRecordToLW(res, domain, QType::NS, "ns2.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1445 }
1446 else if (domain == DNSName("ns2.powerdns.org.")) {
1447 addRecordToLW(res, domain, QType::NS, "ns3.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1448 }
1449 else if (domain == DNSName("ns3.powerdns.org.")) {
1450 addRecordToLW(res, domain, QType::NS, "ns4.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1451 }
1452 else if (domain == DNSName("ns4.powerdns.org.")) {
1453 addRecordToLW(res, domain, QType::NS, "ns5.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
1454 addRecordToLW(res, domain, QType::A, "192.0.2.1", DNSResourceRecord::AUTHORITY, 172800);
1455 }
1456
1457 return 1;
1458 } else if (ip == ComboAddress("192.0.2.1:53")) {
1459
1460 setLWResult(res, 0, true, false, false);
1461 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1462 return 1;
1463 }
1464
1465 return 0;
1466 });
1467
1468 /* Set the maximum depth low */
1469 SyncRes::s_maxdepth = 10;
1470
1471 try {
1472 vector<DNSRecord> ret;
1473 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1474 BOOST_CHECK(false);
1475 }
1476 catch(const ImmediateServFailException& e) {
1477 }
1478}
1479
1480BOOST_AUTO_TEST_CASE(test_cname_qperq) {
1481 std::unique_ptr<SyncRes> sr;
895449a5 1482 initSR(sr);
d6e797b8
RG
1483
1484 primeHints();
1485
1486 size_t queries = 0;
1487 const DNSName target("cname.powerdns.com.");
1488
18d5b679 1489 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, bool* chained) {
d6e797b8
RG
1490
1491 queries++;
1492
1493 if (isRootServer(ip)) {
1494
8455425c 1495 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1496 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1497 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1498 return 1;
1499 } else if (ip == ComboAddress("192.0.2.1:53")) {
1500
1501 setLWResult(res, 0, true, false, false);
1502 addRecordToLW(res, domain, QType::CNAME, std::to_string(queries) + "-cname.powerdns.com");
1503 return 1;
1504 }
1505
1506 return 0;
1507 });
1508
1509 /* Set the maximum number of questions very low */
1510 SyncRes::s_maxqperq = 5;
1511
1512 try {
1513 vector<DNSRecord> ret;
1514 sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1515 BOOST_CHECK(false);
1516 }
1517 catch(const ImmediateServFailException& e) {
1518 BOOST_CHECK_EQUAL(queries, SyncRes::s_maxqperq);
1519 }
1520}
1521
ccb07d93
RG
1522BOOST_AUTO_TEST_CASE(test_throttled_server) {
1523 std::unique_ptr<SyncRes> sr;
895449a5 1524 initSR(sr);
ccb07d93
RG
1525
1526 primeHints();
1527
1528 const DNSName target("throttled.powerdns.com.");
1529 const ComboAddress ns("192.0.2.1:53");
1530 size_t queriesToNS = 0;
1531
18d5b679 1532 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, bool* chained) {
ccb07d93
RG
1533
1534 if (isRootServer(ip)) {
ccb07d93 1535
8455425c 1536 setLWResult(res, 0, false, false, true);
ccb07d93
RG
1537 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1538 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1539 return 1;
1540 } else if (ip == ns) {
1541
1542 queriesToNS++;
1543
1544 setLWResult(res, 0, true, false, false);
1545 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1546
1547 return 1;
1548 }
1549
1550 return 0;
1551 });
1552
1553 /* mark ns as down */
a712cb56 1554 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, 10000);
ccb07d93
RG
1555
1556 vector<DNSRecord> ret;
1557 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
f58c8379
RG
1558 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1559 BOOST_CHECK_EQUAL(ret.size(), 0);
1560 /* we should not have sent any queries to ns */
ccb07d93
RG
1561 BOOST_CHECK_EQUAL(queriesToNS, 0);
1562}
1563
1564BOOST_AUTO_TEST_CASE(test_throttled_server_count) {
1565 std::unique_ptr<SyncRes> sr;
895449a5 1566 initSR(sr);
ccb07d93
RG
1567
1568 primeHints();
1569
1570 const ComboAddress ns("192.0.2.1:53");
1571
1572 const size_t blocks = 10;
1573 /* mark ns as down for 'blocks' queries */
a712cb56 1574 SyncRes::doThrottle(time(nullptr), ns, SyncRes::s_serverdownthrottletime, blocks);
ccb07d93
RG
1575
1576 for (size_t idx = 0; idx < blocks; idx++) {
a712cb56 1577 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
ccb07d93
RG
1578 }
1579
1580 /* we have been throttled 'blocks' times, we should not be throttled anymore */
a712cb56 1581 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
ccb07d93
RG
1582}
1583
1584BOOST_AUTO_TEST_CASE(test_throttled_server_time) {
1585 std::unique_ptr<SyncRes> sr;
895449a5 1586 initSR(sr);
ccb07d93
RG
1587
1588 primeHints();
1589
1590 const ComboAddress ns("192.0.2.1:53");
1591
1592 const size_t seconds = 1;
1593 /* mark ns as down for 'seconds' seconds */
a712cb56
RG
1594 SyncRes::doThrottle(time(nullptr), ns, seconds, 10000);
1595
1596 BOOST_CHECK(SyncRes::isThrottled(time(nullptr), ns));
ccb07d93
RG
1597
1598 sleep(seconds + 1);
1599
1600 /* we should not be throttled anymore */
a712cb56 1601 BOOST_CHECK(!SyncRes::isThrottled(time(nullptr), ns));
ccb07d93
RG
1602}
1603
f58c8379
RG
1604BOOST_AUTO_TEST_CASE(test_dont_query_server) {
1605 std::unique_ptr<SyncRes> sr;
895449a5 1606 initSR(sr);
f58c8379
RG
1607
1608 primeHints();
1609
1610 const DNSName target("throttled.powerdns.com.");
1611 const ComboAddress ns("192.0.2.1:53");
1612 size_t queriesToNS = 0;
1613
18d5b679 1614 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, bool* chained) {
f58c8379
RG
1615
1616 if (isRootServer(ip)) {
1617
8455425c 1618 setLWResult(res, 0, false, false, true);
f58c8379
RG
1619 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1620 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1621 return 1;
1622 } else if (ip == ns) {
1623
1624 queriesToNS++;
1625
1626 setLWResult(res, 0, true, false, false);
1627 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1628
1629 return 1;
1630 }
1631
1632 return 0;
1633 });
1634
1635 /* prevent querying this NS */
9065eb05 1636 SyncRes::addDontQuery(Netmask(ns));
f58c8379
RG
1637
1638 vector<DNSRecord> ret;
1639 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1640 BOOST_CHECK_EQUAL(res, RCode::ServFail);
1641 BOOST_CHECK_EQUAL(ret.size(), 0);
1642 /* we should not have sent any queries to ns */
1643 BOOST_CHECK_EQUAL(queriesToNS, 0);
1644}
1645
1646BOOST_AUTO_TEST_CASE(test_root_nx_trust) {
1647 std::unique_ptr<SyncRes> sr;
895449a5 1648 initSR(sr);
f58c8379
RG
1649
1650 primeHints();
1651
1652 const DNSName target1("powerdns.com.");
1653 const DNSName target2("notpowerdns.com.");
1654 const ComboAddress ns("192.0.2.1:53");
1655 size_t queriesCount = 0;
1656
18d5b679 1657 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, bool* chained) {
f58c8379
RG
1658
1659 queriesCount++;
1660
1661 if (isRootServer(ip)) {
1662
1663 if (domain == target1) {
1664 setLWResult(res, RCode::NXDomain, true, false, true);
1665 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1666 }
1667 else {
1668 setLWResult(res, 0, true, false, true);
1669 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1670 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1671 }
1672
1673 return 1;
1674 } else if (ip == ns) {
1675
1676 setLWResult(res, 0, true, false, false);
1677 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1678
1679 return 1;
1680 }
1681
1682 return 0;
1683 });
1684
1685 vector<DNSRecord> ret;
1686 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1687 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1688 BOOST_CHECK_EQUAL(ret.size(), 1);
1689 /* one for target1 and one for the entire TLD */
a712cb56 1690 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1691
1692 ret.clear();
1693 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1694 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1695 BOOST_CHECK_EQUAL(ret.size(), 1);
1696 /* one for target1 and one for the entire TLD */
a712cb56 1697 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2);
f58c8379
RG
1698
1699 /* we should have sent only one query */
1700 BOOST_CHECK_EQUAL(queriesCount, 1);
1701}
1702
898856ca
RG
1703BOOST_AUTO_TEST_CASE(test_root_nx_trust_specific) {
1704 std::unique_ptr<SyncRes> sr;
1705 init();
1706 initSR(sr, true, false);
1707
1708 primeHints();
1709
1710 const DNSName target1("powerdns.com.");
1711 const DNSName target2("notpowerdns.com.");
1712 const ComboAddress ns("192.0.2.1:53");
1713 size_t queriesCount = 0;
1714
1715 /* This time the root denies target1 with a "com." SOA instead of a "." one.
1716 We should add target1 to the negcache, but not "com.". */
1717
18d5b679 1718 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, bool* chained) {
898856ca
RG
1719
1720 queriesCount++;
1721
1722 if (isRootServer(ip)) {
1723
1724 if (domain == target1) {
1725 setLWResult(res, RCode::NXDomain, true, false, true);
1726 addRecordToLW(res, "com.", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1727 }
1728 else {
1729 setLWResult(res, 0, true, false, true);
1730 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1731 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1732 }
1733
1734 return 1;
1735 } else if (ip == ns) {
1736
1737 setLWResult(res, 0, true, false, false);
1738 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1739
1740 return 1;
1741 }
1742
1743 return 0;
1744 });
1745
1746 vector<DNSRecord> ret;
1747 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1748 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1749 BOOST_CHECK_EQUAL(ret.size(), 1);
1750
1751 /* even with root-nx-trust on and a NX answer from the root,
1752 we should not have cached the entire TLD this time. */
a712cb56 1753 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1754
1755 ret.clear();
1756 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
1757 BOOST_CHECK_EQUAL(res, RCode::NoError);
1758 BOOST_REQUIRE_EQUAL(ret.size(), 1);
1759 BOOST_REQUIRE(ret[0].d_type == QType::A);
1760 BOOST_CHECK_EQUAL(ret[0].d_name, target2);
1761 BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
1762
a712cb56 1763 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
898856ca
RG
1764
1765 BOOST_CHECK_EQUAL(queriesCount, 3);
1766}
1767
f58c8379
RG
1768BOOST_AUTO_TEST_CASE(test_root_nx_dont_trust) {
1769 std::unique_ptr<SyncRes> sr;
895449a5 1770 initSR(sr);
f58c8379
RG
1771
1772 primeHints();
1773
1774 const DNSName target1("powerdns.com.");
1775 const DNSName target2("notpowerdns.com.");
1776 const ComboAddress ns("192.0.2.1:53");
1777 size_t queriesCount = 0;
1778
18d5b679 1779 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, bool* chained) {
f58c8379
RG
1780
1781 queriesCount++;
1782
1783 if (isRootServer(ip)) {
1784
1785 if (domain == target1) {
1786 setLWResult(res, RCode::NXDomain, true, false, true);
1787 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
1788 }
1789 else {
1790 setLWResult(res, 0, true, false, true);
1791 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
1792 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
1793 }
1794
1795 return 1;
1796 } else if (ip == ns) {
1797
1798 setLWResult(res, 0, true, false, false);
1799 addRecordToLW(res, domain, QType::A, "192.0.2.2");
1800
1801 return 1;
1802 }
1803
1804 return 0;
1805 });
1806
1807 SyncRes::s_rootNXTrust = false;
1808
1809 vector<DNSRecord> ret;
1810 int res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
1811 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1812 BOOST_CHECK_EQUAL(ret.size(), 1);
1813 /* one for target1 */
a712cb56 1814 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1815
1816 ret.clear();
1817 res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
b7f378d1 1818 BOOST_CHECK_EQUAL(res, RCode::NoError);
f58c8379
RG
1819 BOOST_CHECK_EQUAL(ret.size(), 1);
1820 /* one for target1 */
a712cb56 1821 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1);
f58c8379
RG
1822
1823 /* we should have sent three queries */
1824 BOOST_CHECK_EQUAL(queriesCount, 3);
1825}
1826
1827BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response) {
1828 std::unique_ptr<SyncRes> sr;
895449a5 1829 initSR(sr);
f58c8379
RG
1830
1831 primeHints();
1832
1833 const DNSName target("www.powerdns.com.");
1834 const DNSName cnameTarget("cname.powerdns.com.");
1835
9065eb05 1836 SyncRes::addEDNSDomain(DNSName("powerdns.com."));
f58c8379
RG
1837
1838 EDNSSubnetOpts incomingECS;
1839 incomingECS.source = Netmask("192.0.2.128/32");
1840 sr->setIncomingECSFound(true);
1841 sr->setIncomingECS(incomingECS);
1842
18d5b679 1843 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, bool* chained) {
f58c8379
RG
1844
1845 BOOST_REQUIRE(srcmask);
1846 BOOST_CHECK_EQUAL(srcmask->toString(), "192.0.2.0/24");
1847
1848 if (isRootServer(ip)) {
8455425c 1849 setLWResult(res, 0, false, false, true);
f58c8379
RG
1850 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1851 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1852
1853 return 1;
1854 } else if (ip == ComboAddress("192.0.2.1:53")) {
1855 if (domain == target) {
1856 /* Type 2 NXDOMAIN (rfc2308 section-2.1) */
1857 setLWResult(res, RCode::NXDomain, true, false, true);
1858 addRecordToLW(res, domain, QType::CNAME, cnameTarget.toString());
1859 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1860 }
1861 else if (domain == cnameTarget) {
1862 /* we shouldn't get there since the Type NXDOMAIN should have been enough,
1863 but we might if we still chase the CNAME. */
1864 setLWResult(res, RCode::NXDomain, true, false, true);
1865 addRecordToLW(res, "powerdns.com", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
1866 }
1867
1868 return 1;
1869 }
1870
1871 return 0;
1872 });
1873
1874 vector<DNSRecord> ret;
1875 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
1876 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
1877 BOOST_CHECK_EQUAL(ret.size(), 2);
1878 /* no negative cache entry because the response was variable */
a712cb56 1879 BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0);
f58c8379
RG
1880}
1881
d6e797b8
RG
1882BOOST_AUTO_TEST_CASE(test_ns_speed) {
1883 std::unique_ptr<SyncRes> sr;
895449a5 1884 initSR(sr);
30ee601a 1885
d6e797b8 1886 primeHints();
30ee601a 1887
d6e797b8 1888 const DNSName target("powerdns.com.");
30ee601a 1889
d6e797b8 1890 std::map<ComboAddress, uint64_t> nsCounts;
30ee601a 1891
18d5b679 1892 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, bool* chained) {
30ee601a 1893
d6e797b8 1894 if (isRootServer(ip)) {
8455425c 1895 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1896 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1897 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1898 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
30ee601a 1899
d6e797b8
RG
1900 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1901 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600);
1902 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
1903 addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 3600);
1904 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 3600);
1905 addRecordToLW(res, "pdns-public-ns3.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 3600);
30ee601a 1906
d6e797b8
RG
1907 return 1;
1908 } else {
1909 nsCounts[ip]++;
30ee601a 1910
d6e797b8
RG
1911 if (ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("192.0.2.2:53")) {
1912 BOOST_CHECK_LT(nsCounts.size(), 3);
1913
1914 /* let's time out on pdns-public-ns2.powerdns.com. */
1915 return 0;
1916 }
1917 else if (ip == ComboAddress("192.0.2.1:53")) {
1918 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1919
1920 setLWResult(res, 0, true, false, true);
1921 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1922 return 1;
1923 }
1924
1925 return 0;
1926 }
30ee601a 1927
d6e797b8
RG
1928 return 0;
1929 });
30ee601a 1930
d6e797b8
RG
1931 struct timeval now;
1932 gettimeofday(&now, 0);
30ee601a 1933
d6e797b8
RG
1934 /* make pdns-public-ns2.powerdns.com. the fastest NS, with its IPv6 address faster than the IPV4 one,
1935 then pdns-public-ns1.powerdns.com. on IPv4 */
a712cb56
RG
1936 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("192.0.2.1:53"), 100, &now);
1937 SyncRes::submitNSSpeed(DNSName("pdns-public-ns1.powerdns.com."), ComboAddress("[2001:DB8::1]:53"), 10000, &now);
1938 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("192.0.2.2:53"), 10, &now);
1939 SyncRes::submitNSSpeed(DNSName("pdns-public-ns2.powerdns.com."), ComboAddress("[2001:DB8::2]:53"), 1, &now);
1940 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("192.0.2.3:53"), 10000, &now);
1941 SyncRes::submitNSSpeed(DNSName("pdns-public-ns3.powerdns.com."), ComboAddress("[2001:DB8::3]:53"), 10000, &now);
30ee601a 1942
d6e797b8
RG
1943 vector<DNSRecord> ret;
1944 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1945 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
1946 BOOST_CHECK_EQUAL(ret.size(), 1);
1947 BOOST_CHECK_EQUAL(nsCounts.size(), 3);
1948 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.1:53")], 1);
1949 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("192.0.2.2:53")], 1);
1950 BOOST_CHECK_EQUAL(nsCounts[ComboAddress("[2001:DB8::2]:53")], 1);
1951}
30ee601a 1952
d6e797b8
RG
1953BOOST_AUTO_TEST_CASE(test_flawed_nsset) {
1954 std::unique_ptr<SyncRes> sr;
895449a5 1955 initSR(sr);
30ee601a 1956
d6e797b8 1957 primeHints();
30ee601a 1958
d6e797b8 1959 const DNSName target("powerdns.com.");
30ee601a 1960
18d5b679 1961 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, bool* chained) {
d6e797b8
RG
1962
1963 if (isRootServer(ip)) {
8455425c 1964 setLWResult(res, 0, false, false, true);
d6e797b8
RG
1965 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
1966
1967 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
1968
1969 return 1;
1970 } else if (ip == ComboAddress("192.0.2.1:53")) {
1971 setLWResult(res, 0, true, false, true);
1972 addRecordToLW(res, domain, QType::A, "192.0.2.254");
1973 return 1;
1974 }
1975
1976 return 0;
1977 });
1978
1979 /* we populate the cache with a flawed NSset, i.e. there is a NS entry but no corresponding glue */
934c35b9 1980 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
1981 std::vector<DNSRecord> records;
1982 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
1983 addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
1984
2b984251 1985 t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
1986
1987 vector<DNSRecord> ret;
1988 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 1989 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
1990 BOOST_CHECK_EQUAL(ret.size(), 1);
1991}
1992
3337c2f7
RG
1993BOOST_AUTO_TEST_CASE(test_completely_flawed_nsset) {
1994 std::unique_ptr<SyncRes> sr;
895449a5 1995 initSR(sr);
3337c2f7
RG
1996
1997 primeHints();
1998
1999 const DNSName target("powerdns.com.");
2000 size_t queriesCount = 0;
2001
18d5b679 2002 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, bool* chained) {
3337c2f7
RG
2003
2004 queriesCount++;
2005
2006 if (isRootServer(ip) && domain == target) {
8455425c 2007 setLWResult(res, 0, false, false, true);
3337c2f7
RG
2008 addRecordToLW(res, domain, QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2009 addRecordToLW(res, domain, QType::NS, "pdns-public-ns3.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2010 return 1;
2011 } else if (domain == DNSName("pdns-public-ns2.powerdns.com.") || domain == DNSName("pdns-public-ns3.powerdns.com.")){
2012 setLWResult(res, 0, true, false, true);
2013 addRecordToLW(res, ".", QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
2014 return 1;
2015 }
2016
2017 return 0;
2018 });
2019
2020 vector<DNSRecord> ret;
2021 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2022 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2023 BOOST_CHECK_EQUAL(ret.size(), 0);
2024 /* one query to get NSs, then A and AAAA for each NS */
2025 BOOST_CHECK_EQUAL(queriesCount, 5);
2026}
2027
d6e797b8
RG
2028BOOST_AUTO_TEST_CASE(test_cache_hit) {
2029 std::unique_ptr<SyncRes> sr;
895449a5 2030 initSR(sr);
d6e797b8
RG
2031
2032 primeHints();
2033
2034 const DNSName target("powerdns.com.");
2035
18d5b679 2036 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, bool* chained) {
d6e797b8
RG
2037
2038 return 0;
2039 });
2040
2041 /* we populate the cache with eveything we need */
934c35b9 2042 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2043 std::vector<DNSRecord> records;
2044 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2045
2046 addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
2b984251 2047 t_RC->replace(now, target , QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2048
2049 vector<DNSRecord> ret;
2050 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2051 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2052 BOOST_CHECK_EQUAL(ret.size(), 1);
2053}
2054
648bcbd1
RG
2055BOOST_AUTO_TEST_CASE(test_no_rd) {
2056 std::unique_ptr<SyncRes> sr;
895449a5 2057 initSR(sr);
648bcbd1
RG
2058
2059 primeHints();
2060
2061 const DNSName target("powerdns.com.");
2062 size_t queriesCount = 0;
2063
2064 sr->setCacheOnly();
2065
18d5b679 2066 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, bool* chained) {
648bcbd1
RG
2067
2068 queriesCount++;
2069 return 0;
2070 });
2071
2072 vector<DNSRecord> ret;
2073 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2074 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2075 BOOST_CHECK_EQUAL(ret.size(), 0);
2076 BOOST_CHECK_EQUAL(queriesCount, 0);
2077}
2078
d6e797b8
RG
2079BOOST_AUTO_TEST_CASE(test_cache_min_max_ttl) {
2080 std::unique_ptr<SyncRes> sr;
895449a5 2081 initSR(sr);
d6e797b8
RG
2082
2083 primeHints();
2084
2085 const DNSName target("cachettl.powerdns.com.");
2086 const ComboAddress ns("192.0.2.1:53");
2087
18d5b679 2088 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, bool* chained) {
d6e797b8
RG
2089
2090 if (isRootServer(ip)) {
2091
8455425c 2092 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2093 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2094 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 7200);
2095 return 1;
2096 } else if (ip == ns) {
2097
2098 setLWResult(res, 0, true, false, false);
2099 addRecordToLW(res, domain, QType::A, "192.0.2.2", DNSResourceRecord::ANSWER, 10);
2100
2101 return 1;
2102 }
2103
2104 return 0;
2105 });
2106
934c35b9 2107 const time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2108 SyncRes::s_minimumTTL = 60;
2109 SyncRes::s_maxcachettl = 3600;
2110
2111 vector<DNSRecord> ret;
2112 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2113 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2114 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2115 BOOST_CHECK_EQUAL(ret[0].d_ttl, SyncRes::s_minimumTTL);
2116
2117 const ComboAddress who;
2118 vector<DNSRecord> cached;
24bb9b58 2119 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
d6e797b8
RG
2120 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2121 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2122 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
2123
2124 cached.clear();
24bb9b58 2125 BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
d6e797b8
RG
2126 BOOST_REQUIRE_EQUAL(cached.size(), 1);
2127 BOOST_REQUIRE_GT(cached[0].d_ttl, now);
2128 BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
2129}
2130
2131BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) {
2132 std::unique_ptr<SyncRes> sr;
895449a5 2133 initSR(sr);
d6e797b8
RG
2134
2135 primeHints();
2136
2137 const DNSName target("powerdns.com.");
2138
18d5b679 2139 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, bool* chained) {
d6e797b8
RG
2140
2141 if (isRootServer(ip)) {
8455425c 2142 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2143 addRecordToLW(res, domain, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
2144
2145 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2146
2147 return 1;
2148 } else if (ip == ComboAddress("192.0.2.1:53")) {
2149 setLWResult(res, 0, true, false, true);
2150 addRecordToLW(res, domain, QType::A, "192.0.2.2");
2151 return 1;
2152 }
2153
2154 return 0;
2155 });
2156
2157 /* we populate the cache with entries that expired 60s ago*/
934c35b9 2158 time_t now = sr->getNow().tv_sec;
d6e797b8
RG
2159 std::vector<DNSRecord> records;
2160 std::vector<shared_ptr<RRSIGRecordContent> > sigs;
2161 addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
2162
2b984251 2163 t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
d6e797b8
RG
2164
2165 vector<DNSRecord> ret;
2166 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2167 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2168 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2169 BOOST_REQUIRE(ret[0].d_type == QType::A);
2170 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toStringWithPort(), ComboAddress("192.0.2.2").toStringWithPort());
2171}
2172
2173BOOST_AUTO_TEST_CASE(test_delegation_only) {
2174 std::unique_ptr<SyncRes> sr;
895449a5 2175 initSR(sr);
d6e797b8
RG
2176
2177 primeHints();
2178
2179 /* Thanks, Verisign */
9065eb05
RG
2180 SyncRes::addDelegationOnly(DNSName("com."));
2181 SyncRes::addDelegationOnly(DNSName("net."));
d6e797b8
RG
2182
2183 const DNSName target("nx-powerdns.com.");
2184
18d5b679 2185 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, bool* chained) {
d6e797b8
RG
2186
2187 if (isRootServer(ip)) {
8455425c 2188 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2189 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2190 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2191 return 1;
2192 } else if (ip == ComboAddress("192.0.2.1:53")) {
2193
2194 setLWResult(res, 0, true, false, true);
2195 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2196 return 1;
2197 }
2198
2199 return 0;
2200 });
2201
2202 vector<DNSRecord> ret;
2203 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2204 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2205 BOOST_CHECK_EQUAL(ret.size(), 0);
2206}
2207
2208BOOST_AUTO_TEST_CASE(test_unauth_any) {
2209 std::unique_ptr<SyncRes> sr;
895449a5 2210 initSR(sr);
d6e797b8
RG
2211
2212 primeHints();
2213
2214 const DNSName target("powerdns.com.");
2215
18d5b679 2216 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, bool* chained) {
d6e797b8
RG
2217
2218 if (isRootServer(ip)) {
8455425c 2219 setLWResult(res, 0, false, false, true);
d6e797b8
RG
2220 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2221 addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
2222 return 1;
2223 } else if (ip == ComboAddress("192.0.2.1:53")) {
2224
2225 setLWResult(res, 0, false, false, true);
2226 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2227 return 1;
2228 }
2229
2230 return 0;
2231 });
2232
2233 vector<DNSRecord> ret;
2234 int res = sr->beginResolve(target, QType(QType::ANY), QClass::IN, ret);
2235 BOOST_CHECK_EQUAL(res, RCode::ServFail);
2236 BOOST_CHECK_EQUAL(ret.size(), 0);
2237}
2238
2239BOOST_AUTO_TEST_CASE(test_no_data) {
2240 std::unique_ptr<SyncRes> sr;
895449a5 2241 initSR(sr);
d6e797b8
RG
2242
2243 primeHints();
2244
2245 const DNSName target("powerdns.com.");
2246
18d5b679 2247 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, bool* chained) {
d6e797b8
RG
2248
2249 setLWResult(res, 0, true, false, true);
2250 return 1;
2251 });
2252
2253 vector<DNSRecord> ret;
2254 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2255 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2256 BOOST_CHECK_EQUAL(ret.size(), 0);
2257}
2258
2259BOOST_AUTO_TEST_CASE(test_skip_opt_any) {
2260 std::unique_ptr<SyncRes> sr;
895449a5 2261 initSR(sr);
d6e797b8
RG
2262
2263 primeHints();
2264
2265 const DNSName target("powerdns.com.");
2266
18d5b679 2267 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, bool* chained) {
d6e797b8
RG
2268
2269 setLWResult(res, 0, true, false, true);
2270 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2271 addRecordToLW(res, domain, QType::ANY, "0 0");
2272 addRecordToLW(res, domain, QType::OPT, "");
2273 return 1;
2274 });
2275
2276 vector<DNSRecord> ret;
2277 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2278 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2279 BOOST_CHECK_EQUAL(ret.size(), 1);
2280}
2281
2282BOOST_AUTO_TEST_CASE(test_nodata_nsec_nodnssec) {
2283 std::unique_ptr<SyncRes> sr;
895449a5 2284 initSR(sr);
d6e797b8
RG
2285
2286 primeHints();
2287
2288 const DNSName target("powerdns.com.");
2289
18d5b679 2290 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, bool* chained) {
d6e797b8
RG
2291
2292 setLWResult(res, 0, true, false, true);
2293 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2294 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2295 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2296 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2297 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2298 return 1;
2299 });
2300
2301 vector<DNSRecord> ret;
2302 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2303 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2304 BOOST_CHECK_EQUAL(ret.size(), 1);
2305}
2306
2307BOOST_AUTO_TEST_CASE(test_nodata_nsec_dnssec) {
2308 std::unique_ptr<SyncRes> sr;
895449a5 2309 initSR(sr, true);
d6e797b8
RG
2310
2311 primeHints();
2312
2313 const DNSName target("powerdns.com.");
2314
18d5b679 2315 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, bool* chained) {
d6e797b8
RG
2316
2317 setLWResult(res, 0, true, false, true);
2318 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2319 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2320 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2321 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2322 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2323 return 1;
2324 });
2325
2326 vector<DNSRecord> ret;
2327 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2328 BOOST_CHECK_EQUAL(res, RCode::NoError);
d6e797b8
RG
2329 BOOST_CHECK_EQUAL(ret.size(), 4);
2330}
2331
2332BOOST_AUTO_TEST_CASE(test_nx_nsec_nodnssec) {
2333 std::unique_ptr<SyncRes> sr;
895449a5 2334 initSR(sr);
d6e797b8
RG
2335
2336 primeHints();
2337
2338 const DNSName target("powerdns.com.");
2339
18d5b679 2340 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, bool* chained) {
d6e797b8
RG
2341
2342 setLWResult(res, RCode::NXDomain, true, false, true);
2343 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2344 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2345 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2346 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2347 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2348 return 1;
2349 });
2350
2351 vector<DNSRecord> ret;
2352 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2353 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2354 BOOST_CHECK_EQUAL(ret.size(), 1);
2355}
2356
2357BOOST_AUTO_TEST_CASE(test_nx_nsec_dnssec) {
2358 std::unique_ptr<SyncRes> sr;
895449a5 2359 initSR(sr, true);
d6e797b8
RG
2360
2361 primeHints();
2362
2363 const DNSName target("powerdns.com.");
2364
18d5b679 2365 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, bool* chained) {
d6e797b8
RG
2366
2367 setLWResult(res, RCode::NXDomain, true, false, true);
2368 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
2369 /* the NSEC and RRSIG contents are complete garbage, please ignore them */
2370 addRecordToLW(res, domain, QType::NSEC, "deadbeef", DNSResourceRecord::AUTHORITY);
2b984251 2371 addRecordToLW(res, domain, QType::RRSIG, "NSEC 5 2 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
d6e797b8
RG
2372 addRecordToLW(res, domain, QType::RRSIG, "SOA 5 3 600 2100010100000000 2100010100000000 24567 dummy data", DNSResourceRecord::AUTHORITY);
2373 return 1;
2374 });
2375
2376 vector<DNSRecord> ret;
2377 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2378 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
2379 BOOST_CHECK_EQUAL(ret.size(), 4);
2380}
2381
648bcbd1
RG
2382BOOST_AUTO_TEST_CASE(test_qclass_none) {
2383 std::unique_ptr<SyncRes> sr;
895449a5 2384 initSR(sr);
648bcbd1
RG
2385
2386 primeHints();
2387
2388 /* apart from special names and QClass::ANY, anything else than QClass::IN should be rejected right away */
2389 size_t queriesCount = 0;
2390
18d5b679 2391 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, bool* chained) {
648bcbd1
RG
2392
2393 queriesCount++;
2394 return 0;
2395 });
2396
2397 const DNSName target("powerdns.com.");
2398 vector<DNSRecord> ret;
2399 int res = sr->beginResolve(target, QType(QType::A), QClass::NONE, ret);
2400 BOOST_CHECK_EQUAL(res, -1);
2401 BOOST_CHECK_EQUAL(ret.size(), 0);
2402 BOOST_CHECK_EQUAL(queriesCount, 0);
2403}
2404
1f03b691 2405BOOST_AUTO_TEST_CASE(test_special_types) {
648bcbd1 2406 std::unique_ptr<SyncRes> sr;
895449a5 2407 initSR(sr);
648bcbd1
RG
2408
2409 primeHints();
2410
1f03b691 2411 /* {A,I}XFR, RRSIG and NSEC3 should be rejected right away */
648bcbd1
RG
2412 size_t queriesCount = 0;
2413
18d5b679 2414 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, bool* chained) {
648bcbd1
RG
2415
2416 cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
2417 queriesCount++;
2418 return 0;
2419 });
2420
2421 const DNSName target("powerdns.com.");
2422 vector<DNSRecord> ret;
2423 int res = sr->beginResolve(target, QType(QType::AXFR), QClass::IN, ret);
2424 BOOST_CHECK_EQUAL(res, -1);
2425 BOOST_CHECK_EQUAL(ret.size(), 0);
2426 BOOST_CHECK_EQUAL(queriesCount, 0);
2427
2428 res = sr->beginResolve(target, QType(QType::IXFR), QClass::IN, ret);
2429 BOOST_CHECK_EQUAL(res, -1);
2430 BOOST_CHECK_EQUAL(ret.size(), 0);
2431 BOOST_CHECK_EQUAL(queriesCount, 0);
1f03b691
RG
2432
2433 res = sr->beginResolve(target, QType(QType::RRSIG), QClass::IN, ret);
2434 BOOST_CHECK_EQUAL(res, -1);
2435 BOOST_CHECK_EQUAL(ret.size(), 0);
2436 BOOST_CHECK_EQUAL(queriesCount, 0);
2437
2438 res = sr->beginResolve(target, QType(QType::NSEC3), QClass::IN, ret);
648bcbd1
RG
2439 BOOST_CHECK_EQUAL(res, -1);
2440 BOOST_CHECK_EQUAL(ret.size(), 0);
2441 BOOST_CHECK_EQUAL(queriesCount, 0);
2442}
2443
2444BOOST_AUTO_TEST_CASE(test_special_names) {
2445 std::unique_ptr<SyncRes> sr;
895449a5 2446 initSR(sr);
648bcbd1
RG
2447
2448 primeHints();
2449
2450 /* special names should be handled internally */
2451
2452 size_t queriesCount = 0;
2453
18d5b679 2454 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, bool* chained) {
648bcbd1
RG
2455
2456 queriesCount++;
2457 return 0;
2458 });
2459
2460 vector<DNSRecord> ret;
2461 int res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::PTR), QClass::IN, ret);
b7f378d1 2462 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2463 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2464 BOOST_CHECK(ret[0].d_type == QType::PTR);
2465 BOOST_CHECK_EQUAL(queriesCount, 0);
2466
2467 ret.clear();
2468 res = sr->beginResolve(DNSName("1.0.0.127.in-addr.arpa."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2469 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2470 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2471 BOOST_CHECK(ret[0].d_type == QType::PTR);
2472 BOOST_CHECK_EQUAL(queriesCount, 0);
2473
2474 ret.clear();
2475 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 2476 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2477 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2478 BOOST_CHECK(ret[0].d_type == QType::PTR);
2479 BOOST_CHECK_EQUAL(queriesCount, 0);
2480
2481 ret.clear();
2482 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 2483 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2484 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2485 BOOST_CHECK(ret[0].d_type == QType::PTR);
2486 BOOST_CHECK_EQUAL(queriesCount, 0);
2487
2488 ret.clear();
2489 res = sr->beginResolve(DNSName("localhost."), QType(QType::A), QClass::IN, ret);
b7f378d1 2490 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2491 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2492 BOOST_CHECK(ret[0].d_type == QType::A);
2493 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), "127.0.0.1");
2494 BOOST_CHECK_EQUAL(queriesCount, 0);
2495
2496 ret.clear();
2497 res = sr->beginResolve(DNSName("localhost."), QType(QType::AAAA), QClass::IN, ret);
b7f378d1 2498 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2499 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2500 BOOST_CHECK(ret[0].d_type == QType::AAAA);
2501 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(ret[0])->getCA().toString(), "::1");
2502 BOOST_CHECK_EQUAL(queriesCount, 0);
2503
2504 ret.clear();
2505 res = sr->beginResolve(DNSName("localhost."), QType(QType::ANY), QClass::IN, ret);
b7f378d1 2506 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2507 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2508 for (const auto& rec : ret) {
2509 BOOST_REQUIRE((rec.d_type == QType::A) || rec.d_type == QType::AAAA);
2510 if (rec.d_type == QType::A) {
2511 BOOST_CHECK_EQUAL(getRR<ARecordContent>(rec)->getCA().toString(), "127.0.0.1");
2512 }
2513 else {
2514 BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(rec)->getCA().toString(), "::1");
2515 }
2516 }
2517 BOOST_CHECK_EQUAL(queriesCount, 0);
2518
2519 ret.clear();
2520 res = sr->beginResolve(DNSName("version.bind."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2521 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2522 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2523 BOOST_CHECK(ret[0].d_type == QType::TXT);
2524 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2525 BOOST_CHECK_EQUAL(queriesCount, 0);
2526
2527 ret.clear();
2528 res = sr->beginResolve(DNSName("version.bind."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2529 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2530 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2531 BOOST_CHECK(ret[0].d_type == QType::TXT);
2532 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2533 BOOST_CHECK_EQUAL(queriesCount, 0);
2534
2535 ret.clear();
2536 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2537 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2538 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2539 BOOST_CHECK(ret[0].d_type == QType::TXT);
2540 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2541 BOOST_CHECK_EQUAL(queriesCount, 0);
2542
2543 ret.clear();
2544 res = sr->beginResolve(DNSName("version.pdns."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2545 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2546 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2547 BOOST_CHECK(ret[0].d_type == QType::TXT);
2548 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests\"");
2549 BOOST_CHECK_EQUAL(queriesCount, 0);
2550
2551 ret.clear();
2552 res = sr->beginResolve(DNSName("id.server."), QType(QType::TXT), QClass::CHAOS, ret);
b7f378d1 2553 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2554 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2555 BOOST_CHECK(ret[0].d_type == QType::TXT);
2556 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2557 BOOST_CHECK_EQUAL(queriesCount, 0);
2558
2559 ret.clear();
2560 res = sr->beginResolve(DNSName("id.server."), QType(QType::ANY), QClass::CHAOS, ret);
b7f378d1 2561 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2562 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2563 BOOST_CHECK(ret[0].d_type == QType::TXT);
2564 BOOST_CHECK_EQUAL(getRR<TXTRecordContent>(ret[0])->d_text, "\"PowerDNS Unit Tests Server ID\"");
2565 BOOST_CHECK_EQUAL(queriesCount, 0);
2566}
2567
2568BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
2569 std::unique_ptr<SyncRes> sr;
895449a5 2570 initSR(sr);
648bcbd1
RG
2571
2572 primeHints();
2573
2574 const DNSName target("rpz.powerdns.com.");
2575 const ComboAddress ns("192.0.2.1:53");
2576
18d5b679 2577 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, bool* chained) {
648bcbd1
RG
2578
2579 if (isRootServer(ip)) {
8455425c 2580 setLWResult(res, false, true, false, true);
648bcbd1
RG
2581 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2582 addRecordToLW(res, "a.gtld-servers.net.", QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2583 return 1;
2584 } else if (ip == ns) {
2585
2586 setLWResult(res, 0, true, false, true);
2587 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2588 return 1;
2589 }
2590
2591 return 0;
2592 });
2593
2594 DNSFilterEngine::Policy pol;
2595 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2596 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2597 zone->setName("Unit test policy 0");
2598 zone->addNSIPTrigger(Netmask(ns, 32), pol);
648bcbd1 2599 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2600 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2601 g_luaconfs.setState(luaconfsCopy);
2602
2603 vector<DNSRecord> ret;
2604 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2605 BOOST_CHECK_EQUAL(res, -2);
2606 BOOST_CHECK_EQUAL(ret.size(), 0);
2607}
2608
2609BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
2610 std::unique_ptr<SyncRes> sr;
895449a5 2611 initSR(sr);
648bcbd1
RG
2612
2613 primeHints();
2614
2615 const DNSName target("rpz.powerdns.com.");
2616 const ComboAddress ns("[2001:DB8::42]:53");
2617
18d5b679 2618 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, bool* chained) {
648bcbd1
RG
2619
2620 if (isRootServer(ip)) {
8455425c 2621 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2622 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800);
2623 addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2624 return 1;
2625 } else if (ip == ns) {
2626
2627 setLWResult(res, 0, true, false, true);
2628 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2629 return 1;
2630 }
2631
2632 return 0;
2633 });
2634
2635 DNSFilterEngine::Policy pol;
2636 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2637 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2638 zone->setName("Unit test policy 0");
2639 zone->addNSIPTrigger(Netmask(ns, 128), pol);
648bcbd1 2640 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2641 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2642 g_luaconfs.setState(luaconfsCopy);
2643
2644 vector<DNSRecord> ret;
2645 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2646 BOOST_CHECK_EQUAL(res, -2);
2647 BOOST_CHECK_EQUAL(ret.size(), 0);
2648}
2649
2650BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
2651 std::unique_ptr<SyncRes> sr;
895449a5 2652 initSR(sr);
648bcbd1
RG
2653
2654 primeHints();
2655
2656 const DNSName target("rpz.powerdns.com.");
2657 const ComboAddress ns("192.0.2.1:53");
2658 const DNSName nsName("ns1.powerdns.com.");
2659
18d5b679 2660 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, bool* chained) {
648bcbd1
RG
2661
2662 if (isRootServer(ip)) {
8455425c 2663 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2664 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2665 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2666 return 1;
2667 } else if (ip == ns) {
2668
2669 setLWResult(res, 0, true, false, true);
2670 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2671 return 1;
2672 }
2673
2674 return 0;
2675 });
2676
2677 DNSFilterEngine::Policy pol;
2678 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2679 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2680 zone->setName("Unit test policy 0");
2681 zone->addNSTrigger(nsName, pol);
648bcbd1 2682 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2683 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2684 g_luaconfs.setState(luaconfsCopy);
2685
2686 vector<DNSRecord> ret;
2687 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2688 BOOST_CHECK_EQUAL(res, -2);
2689 BOOST_CHECK_EQUAL(ret.size(), 0);
2690}
2691
2692BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
2693 std::unique_ptr<SyncRes> sr;
895449a5 2694 initSR(sr);
648bcbd1
RG
2695
2696 primeHints();
2697
2698 const DNSName target("rpz.powerdns.com.");
2699 const ComboAddress ns("192.0.2.1:53");
2700 const DNSName nsName("ns1.powerdns.com.");
2701
18d5b679 2702 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, bool* chained) {
648bcbd1
RG
2703
2704 if (isRootServer(ip)) {
8455425c 2705 setLWResult(res, 0, false, false, true);
648bcbd1
RG
2706 addRecordToLW(res, domain, QType::NS, nsName.toString(), DNSResourceRecord::AUTHORITY, 172800);
2707 addRecordToLW(res, nsName, QType::A, ns.toString(), DNSResourceRecord::ADDITIONAL, 3600);
2708 return 1;
2709 } else if (ip == ns) {
2710
2711 setLWResult(res, 0, true, false, true);
2712 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2713 return 1;
2714 }
2715
2716 return 0;
2717 });
2718
2719 DNSFilterEngine::Policy pol;
2720 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
6b972d59
RG
2721 std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
2722 zone->setName("Unit test policy 0");
2723 zone->addNSIPTrigger(Netmask(ns, 128), pol);
2724 zone->addNSTrigger(nsName, pol);
648bcbd1 2725 auto luaconfsCopy = g_luaconfs.getCopy();
6b972d59 2726 luaconfsCopy.dfe.addZone(zone);
648bcbd1
RG
2727 g_luaconfs.setState(luaconfsCopy);
2728
2729 /* RPZ is disabled for this query, we should not be blocked */
2730 sr->setWantsRPZ(false);
2731
2732 vector<DNSRecord> ret;
2733 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2734 BOOST_CHECK_EQUAL(res, RCode::NoError);
648bcbd1
RG
2735 BOOST_CHECK_EQUAL(ret.size(), 1);
2736}
2737
3e59ff53
RG
2738BOOST_AUTO_TEST_CASE(test_forward_zone_nord) {
2739 std::unique_ptr<SyncRes> sr;
895449a5 2740 initSR(sr);
3e59ff53
RG
2741
2742 primeHints();
2743
2744 const DNSName target("powerdns.com.");
2745 const ComboAddress ns("192.0.2.1:53");
2746 const ComboAddress forwardedNS("192.0.2.42:53");
2747
2748 SyncRes::AuthDomain ad;
2749 ad.d_rdForward = false;
2750 ad.d_servers.push_back(forwardedNS);
a712cb56 2751 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2752
18d5b679 2753 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, bool* chained) {
3e59ff53
RG
2754
2755 if (ip == forwardedNS) {
6dfff36f
RG
2756 BOOST_CHECK_EQUAL(sendRDQuery, false);
2757
3e59ff53
RG
2758 setLWResult(res, 0, true, false, true);
2759 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2760 return 1;
2761 }
2762
2763 return 0;
2764 });
2765
2766 /* simulate a no-RD query */
2767 sr->setCacheOnly();
2768
2769 vector<DNSRecord> ret;
2770 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2771 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2772 BOOST_CHECK_EQUAL(ret.size(), 1);
2773}
2774
2775BOOST_AUTO_TEST_CASE(test_forward_zone_rd) {
2776 std::unique_ptr<SyncRes> sr;
895449a5 2777 initSR(sr);
3e59ff53
RG
2778
2779 primeHints();
2780
2781 const DNSName target("powerdns.com.");
2782 const ComboAddress ns("192.0.2.1:53");
2783 const ComboAddress forwardedNS("192.0.2.42:53");
2784
f24f20ef 2785 size_t queriesCount = 0;
3e59ff53 2786 SyncRes::AuthDomain ad;
f24f20ef 2787 ad.d_rdForward = true;
3e59ff53 2788 ad.d_servers.push_back(forwardedNS);
a712cb56 2789 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2790
f24f20ef
RG
2791 sr->setAsyncCallback([forwardedNS, &queriesCount](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
2792
2793 queriesCount++;
3e59ff53
RG
2794
2795 if (ip == forwardedNS) {
f24f20ef 2796 BOOST_CHECK_EQUAL(sendRDQuery, true);
6dfff36f 2797
f24f20ef
RG
2798 /* set AA=0, we are a recursor */
2799 setLWResult(res, 0, false, false, true);
3e59ff53
RG
2800 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2801 return 1;
2802 }
2803
2804 return 0;
2805 });
2806
2807 vector<DNSRecord> ret;
2808 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2809 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53 2810 BOOST_CHECK_EQUAL(ret.size(), 1);
f24f20ef
RG
2811 BOOST_CHECK_EQUAL(queriesCount, 1);
2812
2813 /* now make sure we can resolve from the cache (see #6340
2814 where the entries were added to the cache but not retrieved,
2815 because the recursor doesn't set the AA bit and we require
2816 it. We fixed it by not requiring the AA bit for forward-recurse
2817 answers. */
2818 ret.clear();
2819 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2820 BOOST_CHECK_EQUAL(res, RCode::NoError);
2821 BOOST_CHECK_EQUAL(ret.size(), 1);
2822 BOOST_CHECK_EQUAL(queriesCount, 1);
3e59ff53
RG
2823}
2824
2825BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_nord) {
2826 std::unique_ptr<SyncRes> sr;
895449a5 2827 initSR(sr);
3e59ff53
RG
2828
2829 primeHints();
2830
2831 const DNSName target("powerdns.com.");
2832 const ComboAddress ns("192.0.2.1:53");
2833 const ComboAddress forwardedNS("192.0.2.42:53");
2834
2835 SyncRes::AuthDomain ad;
2836 ad.d_rdForward = true;
2837 ad.d_servers.push_back(forwardedNS);
a712cb56 2838 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2839
18d5b679 2840 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, bool* chained) {
3e59ff53
RG
2841
2842 if (ip == forwardedNS) {
6dfff36f
RG
2843 BOOST_CHECK_EQUAL(sendRDQuery, false);
2844
3e59ff53
RG
2845 setLWResult(res, 0, true, false, true);
2846 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2847 return 1;
2848 }
2849
2850 return 0;
2851 });
2852
2853 /* simulate a no-RD query */
2854 sr->setCacheOnly();
2855
2856 vector<DNSRecord> ret;
2857 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2858 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2859 BOOST_CHECK_EQUAL(ret.size(), 1);
2860}
2861
2862BOOST_AUTO_TEST_CASE(test_forward_zone_recurse_rd) {
2863 std::unique_ptr<SyncRes> sr;
895449a5 2864 initSR(sr);
3e59ff53
RG
2865
2866 primeHints();
2867
2868 const DNSName target("powerdns.com.");
2869 const ComboAddress ns("192.0.2.1:53");
2870 const ComboAddress forwardedNS("192.0.2.42:53");
2871
2872 SyncRes::AuthDomain ad;
2873 ad.d_rdForward = true;
2874 ad.d_servers.push_back(forwardedNS);
a712cb56 2875 (*SyncRes::t_sstorage.domainmap)[target] = ad;
3e59ff53 2876
18d5b679 2877 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, bool* chained) {
3e59ff53
RG
2878
2879 if (ip == forwardedNS) {
6dfff36f
RG
2880 BOOST_CHECK_EQUAL(sendRDQuery, true);
2881
3e59ff53
RG
2882 setLWResult(res, 0, true, false, true);
2883 addRecordToLW(res, domain, QType::A, "192.0.2.42");
2884 return 1;
2885 }
2886
2887 return 0;
2888 });
2889
2890 vector<DNSRecord> ret;
2891 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 2892 BOOST_CHECK_EQUAL(res, RCode::NoError);
3e59ff53
RG
2893 BOOST_CHECK_EQUAL(ret.size(), 1);
2894}
2895
e1636f82 2896BOOST_AUTO_TEST_CASE(test_auth_zone_oob) {
f79a4e30 2897 std::unique_ptr<SyncRes> sr;
e1636f82 2898 initSR(sr, true);
f79a4e30
RG
2899
2900 primeHints();
2901
2902 size_t queriesCount = 0;
2903 const DNSName target("test.xx.");
2904 const ComboAddress targetAddr("127.0.0.1");
f79a4e30
RG
2905 const DNSName authZone("test.xx");
2906
2907 SyncRes::AuthDomain ad;
2908 DNSRecord dr;
f79a4e30
RG
2909
2910 dr.d_place = DNSResourceRecord::ANSWER;
e1636f82 2911 dr.d_name = target;
f79a4e30
RG
2912 dr.d_type = QType::A;
2913 dr.d_ttl = 1800;
e1636f82 2914 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
f79a4e30
RG
2915 ad.d_records.insert(dr);
2916
a712cb56 2917 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
f79a4e30 2918
18d5b679 2919 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, bool* chained) {
f79a4e30
RG
2920 queriesCount++;
2921 return 0;
2922 });
2923
2924 vector<DNSRecord> ret;
2925 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2926 BOOST_CHECK_EQUAL(res, 0);
2927 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2928 BOOST_CHECK(ret[0].d_type == QType::A);
2929 BOOST_CHECK_EQUAL(queriesCount, 0);
2930 BOOST_CHECK(sr->wasOutOfBand());
e1636f82 2931 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
2932
2933 /* a second time, to check that the OOB flag is set when the query cache is used */
2934 ret.clear();
2935 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2936 BOOST_CHECK_EQUAL(res, 0);
2937 BOOST_REQUIRE_EQUAL(ret.size(), 1);
2938 BOOST_CHECK(ret[0].d_type == QType::A);
2939 BOOST_CHECK_EQUAL(queriesCount, 0);
2940 BOOST_CHECK(sr->wasOutOfBand());
e1636f82
RG
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(), 1);
2949 BOOST_CHECK(ret[0].d_type == QType::A);
2950 BOOST_CHECK_EQUAL(queriesCount, 0);
2951 BOOST_CHECK(sr->wasOutOfBand());
2952 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
2953}
2954
2955BOOST_AUTO_TEST_CASE(test_auth_zone_oob_cname) {
2956 std::unique_ptr<SyncRes> sr;
2957 initSR(sr, true);
2958
2959 primeHints();
2960
2961 size_t queriesCount = 0;
2962 const DNSName target("cname.test.xx.");
2963 const DNSName targetCname("cname-target.test.xx.");
2964 const ComboAddress targetCnameAddr("127.0.0.1");
2965 const DNSName authZone("test.xx");
2966
2967 SyncRes::AuthDomain ad;
2968 DNSRecord dr;
2969
2970 dr.d_place = DNSResourceRecord::ANSWER;
2971 dr.d_name = target;
2972 dr.d_type = QType::CNAME;
2973 dr.d_ttl = 1800;
2974 dr.d_content = std::make_shared<CNAMERecordContent>(targetCname);
2975 ad.d_records.insert(dr);
2976
2977 dr.d_place = DNSResourceRecord::ANSWER;
2978 dr.d_name = targetCname;
2979 dr.d_type = QType::A;
2980 dr.d_ttl = 1800;
2981 dr.d_content = std::make_shared<ARecordContent>(targetCnameAddr);
2982 ad.d_records.insert(dr);
2983
2984 (*SyncRes::t_sstorage.domainmap)[authZone] = ad;
2985
18d5b679 2986 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, bool* chained) {
e1636f82
RG
2987 queriesCount++;
2988 return 0;
2989 });
2990
2991 vector<DNSRecord> ret;
2992 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
2993 BOOST_CHECK_EQUAL(res, 0);
2994 BOOST_REQUIRE_EQUAL(ret.size(), 2);
2995 BOOST_CHECK(ret[0].d_type == QType::CNAME);
2996 BOOST_CHECK(ret[1].d_type == QType::A);
2997 BOOST_CHECK_EQUAL(queriesCount, 0);
2998 BOOST_CHECK(sr->wasOutOfBand());
2999 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3000
3001 /* a second time, to check that the OOB flag is set when the query cache is used */
3002 ret.clear();
3003 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3004 BOOST_CHECK_EQUAL(res, 0);
3005 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3006 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3007 BOOST_CHECK(ret[1].d_type == QType::A);
3008 BOOST_CHECK_EQUAL(queriesCount, 0);
3009 BOOST_CHECK(sr->wasOutOfBand());
3010 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3011
3012 /* a third time, to check that the validation is disabled when the OOB flag is set */
3013 ret.clear();
3014 sr->setDNSSECValidationRequested(true);
3015 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3016 BOOST_CHECK_EQUAL(res, 0);
3017 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3018 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3019 BOOST_CHECK(ret[1].d_type == QType::A);
3020 BOOST_CHECK_EQUAL(queriesCount, 0);
3021 BOOST_CHECK(sr->wasOutOfBand());
3022 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
f79a4e30
RG
3023}
3024
3337c2f7
RG
3025BOOST_AUTO_TEST_CASE(test_auth_zone) {
3026 std::unique_ptr<SyncRes> sr;
895449a5 3027 initSR(sr);
3337c2f7
RG
3028
3029 primeHints();
3030
3031 size_t queriesCount = 0;
3032 const DNSName target("powerdns.com.");
3033 const ComboAddress addr("192.0.2.5");
3034
3035 SyncRes::AuthDomain ad;
3036 ad.d_name = target;
3037 DNSRecord dr;
3038 dr.d_place = DNSResourceRecord::ANSWER;
3039 dr.d_name = target;
3040 dr.d_type = QType::SOA;
3041 dr.d_ttl = 3600;
3042 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3043 ad.d_records.insert(dr);
3044
3045 dr.d_place = DNSResourceRecord::ANSWER;
3046 dr.d_name = target;
3047 dr.d_type = QType::A;
3048 dr.d_ttl = 3600;
3049 dr.d_content = std::make_shared<ARecordContent>(addr);
3050 ad.d_records.insert(dr);
3051
3052 auto map = std::make_shared<SyncRes::domainmap_t>();
3053 (*map)[target] = ad;
3054 SyncRes::setDomainMap(map);
3055
18d5b679 3056 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, bool* chained) {
3337c2f7
RG
3057
3058 queriesCount++;
3059 setLWResult(res, 0, true, false, true);
3060 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3061 return 1;
3062 });
3063
3064 vector<DNSRecord> ret;
3065 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3066 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3067 BOOST_CHECK_EQUAL(ret.size(), 1);
3068 BOOST_CHECK(ret[0].d_type == QType::A);
3069 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3070 BOOST_CHECK_EQUAL(queriesCount, 0);
3071}
3072
3073BOOST_AUTO_TEST_CASE(test_auth_zone_cname_lead_to_oob) {
3074 std::unique_ptr<SyncRes> sr;
895449a5 3075 initSR(sr);
3337c2f7
RG
3076
3077 primeHints();
3078
3079 size_t queriesCount = 0;
3080 const DNSName target("powerdns.com.");
3081 const DNSName authZone("internal.powerdns.com.");
3082 const ComboAddress addr("192.0.2.5");
3083
3084 SyncRes::AuthDomain ad;
3085 ad.d_name = authZone;
3086 DNSRecord dr;
3087 dr.d_place = DNSResourceRecord::ANSWER;
3088 dr.d_name = authZone;
3089 dr.d_type = QType::SOA;
3090 dr.d_ttl = 3600;
3091 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3092 ad.d_records.insert(dr);
3093
3094 dr.d_place = DNSResourceRecord::ANSWER;
3095 dr.d_name = authZone;
3096 dr.d_type = QType::A;
3097 dr.d_ttl = 3600;
3098 dr.d_content = std::make_shared<ARecordContent>(addr);
3099 ad.d_records.insert(dr);
3100
3101 auto map = std::make_shared<SyncRes::domainmap_t>();
3102 (*map)[authZone] = ad;
3103 SyncRes::setDomainMap(map);
3104
18d5b679 3105 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, bool* chained) {
3337c2f7
RG
3106
3107 queriesCount++;
3108
3109 if (domain == target) {
3110 setLWResult(res, 0, true, false, true);
3111 addRecordToLW(res, target, QType::CNAME, authZone.toString(), DNSResourceRecord::ANSWER, 3600);
3112 return 1;
3113 }
3114
3115 return 0;
3116 });
3117
3118 vector<DNSRecord> ret;
3119 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3120 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3121 BOOST_CHECK_EQUAL(ret.size(), 2);
3122 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3123 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), authZone.toString());
3124 BOOST_CHECK(ret[1].d_type == QType::A);
3125 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3126 BOOST_CHECK_EQUAL(queriesCount, 1);
3127}
3128
3129BOOST_AUTO_TEST_CASE(test_auth_zone_oob_lead_to_outgoing_queryb) {
3130 std::unique_ptr<SyncRes> sr;
895449a5 3131 initSR(sr);
3337c2f7
RG
3132
3133 primeHints();
3134
3135 size_t queriesCount = 0;
3136 const DNSName target("powerdns.com.");
3137 const DNSName externalCNAME("www.open-xchange.com.");
3138 const ComboAddress addr("192.0.2.5");
3139
3140 SyncRes::AuthDomain ad;
3141 ad.d_name = target;
3142 DNSRecord dr;
3143 dr.d_place = DNSResourceRecord::ANSWER;
3144 dr.d_name = target;
3145 dr.d_type = QType::SOA;
3146 dr.d_ttl = 3600;
3147 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3148 ad.d_records.insert(dr);
3149
3150 dr.d_place = DNSResourceRecord::ANSWER;
3151 dr.d_name = target;
3152 dr.d_type = QType::CNAME;
3153 dr.d_ttl = 3600;
3154 dr.d_content = std::make_shared<CNAMERecordContent>(externalCNAME);
3155 ad.d_records.insert(dr);
3156
3157 auto map = std::make_shared<SyncRes::domainmap_t>();
3158 (*map)[target] = ad;
3159 SyncRes::setDomainMap(map);
3160
18d5b679 3161 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, bool* chained) {
3337c2f7
RG
3162
3163 queriesCount++;
3164
3165 if (domain == externalCNAME) {
3166 setLWResult(res, 0, true, false, true);
3167 addRecordToLW(res, externalCNAME, QType::A, addr.toString(), DNSResourceRecord::ANSWER, 3600);
3168 return 1;
3169 }
3170
3171 return 0;
3172 });
3173
3174 vector<DNSRecord> ret;
3175 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3176 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3177 BOOST_CHECK_EQUAL(ret.size(), 2);
3178 BOOST_CHECK(ret[0].d_type == QType::CNAME);
3179 BOOST_CHECK_EQUAL(getRR<CNAMERecordContent>(ret[0])->getTarget().toString(), externalCNAME.toString());
3180 BOOST_CHECK(ret[1].d_type == QType::A);
3181 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[1])->getCA().toString(), addr.toString());
3182 BOOST_CHECK_EQUAL(queriesCount, 1);
3183}
3184
3185BOOST_AUTO_TEST_CASE(test_auth_zone_nodata) {
3186 std::unique_ptr<SyncRes> sr;
895449a5 3187 initSR(sr);
3337c2f7
RG
3188
3189 primeHints();
3190
3191 size_t queriesCount = 0;
3192 const DNSName target("nodata.powerdns.com.");
3193 const DNSName authZone("powerdns.com");
3194
3195 SyncRes::AuthDomain ad;
3196 ad.d_name = authZone;
3197 DNSRecord dr;
3198 dr.d_place = DNSResourceRecord::ANSWER;
3199 dr.d_name = target;
3200 dr.d_type = QType::A;
3201 dr.d_ttl = 3600;
3202 dr.d_content = std::make_shared<ARecordContent>(ComboAddress("192.0.2.1"));
3203 ad.d_records.insert(dr);
3204
3205 dr.d_place = DNSResourceRecord::ANSWER;
3206 dr.d_name = authZone;
3207 dr.d_type = QType::SOA;
3208 dr.d_ttl = 3600;
3209 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3210 ad.d_records.insert(dr);
3211
3212 auto map = std::make_shared<SyncRes::domainmap_t>();
3213 (*map)[authZone] = ad;
3214 SyncRes::setDomainMap(map);
3215
18d5b679 3216 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, bool* chained) {
3337c2f7
RG
3217
3218 queriesCount++;
3219
3220 return 0;
3221 });
3222
3223 vector<DNSRecord> ret;
3224 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3225 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3226 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3227 BOOST_CHECK(ret[0].d_type == QType::SOA);
3228 BOOST_CHECK_EQUAL(queriesCount, 0);
3229}
3230
3231BOOST_AUTO_TEST_CASE(test_auth_zone_nx) {
3232 std::unique_ptr<SyncRes> sr;
895449a5 3233 initSR(sr);
3337c2f7
RG
3234
3235 primeHints();
3236
3237 size_t queriesCount = 0;
3238 const DNSName target("nx.powerdns.com.");
3239 const DNSName authZone("powerdns.com");
3240
3241 SyncRes::AuthDomain ad;
3242 ad.d_name = authZone;
3243 DNSRecord dr;
3244 dr.d_place = DNSResourceRecord::ANSWER;
3245 dr.d_name = DNSName("powerdns.com.");
3246 dr.d_type = QType::SOA;
3247 dr.d_ttl = 3600;
3248 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3249 ad.d_records.insert(dr);
3250
3251 auto map = std::make_shared<SyncRes::domainmap_t>();
3252 (*map)[authZone] = ad;
3253 SyncRes::setDomainMap(map);
3254
18d5b679 3255 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, bool* chained) {
3337c2f7
RG
3256
3257 queriesCount++;
3258
3259 return 0;
3260 });
3261
3262 vector<DNSRecord> ret;
3263 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
3264 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
3265 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3266 BOOST_CHECK(ret[0].d_type == QType::SOA);
3267 BOOST_CHECK_EQUAL(queriesCount, 0);
3268}
3269
3270BOOST_AUTO_TEST_CASE(test_auth_zone_delegation) {
3271 std::unique_ptr<SyncRes> sr;
e1636f82 3272 initSR(sr, true, false);
3337c2f7
RG
3273
3274 primeHints();
3275
3276 size_t queriesCount = 0;
3277 const DNSName target("www.test.powerdns.com.");
3278 const ComboAddress targetAddr("192.0.2.2");
3279 const DNSName ns("ns1.test.powerdns.com.");
3280 const ComboAddress nsAddr("192.0.2.1");
3281 const DNSName authZone("powerdns.com");
3282
3283 SyncRes::AuthDomain ad;
3284 ad.d_name = authZone;
3285 DNSRecord dr;
3286 dr.d_place = DNSResourceRecord::ANSWER;
3287 dr.d_name = authZone;
3288 dr.d_type = QType::SOA;
3289 dr.d_ttl = 3600;
3290 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3291 ad.d_records.insert(dr);
3292
3293 dr.d_place = DNSResourceRecord::ANSWER;
3294 dr.d_name = DNSName("test.powerdns.com.");
3295 dr.d_type = QType::NS;
3296 dr.d_ttl = 3600;
3297 dr.d_content = std::make_shared<NSRecordContent>(ns);
3298 ad.d_records.insert(dr);
3299
3300 dr.d_place = DNSResourceRecord::ANSWER;
3301 dr.d_name = ns;
3302 dr.d_type = QType::A;
3303 dr.d_ttl = 3600;
3304 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3305 ad.d_records.insert(dr);
3306
3307 auto map = std::make_shared<SyncRes::domainmap_t>();
3308 (*map)[authZone] = ad;
3309 SyncRes::setDomainMap(map);
3310
e1636f82
RG
3311 testkeysset_t keys;
3312 auto luaconfsCopy = g_luaconfs.getCopy();
3313 luaconfsCopy.dsAnchors.clear();
3314 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
3315 g_luaconfs.setState(luaconfsCopy);
3316
18d5b679 3317 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, bool* chained) {
3337c2f7
RG
3318
3319 queriesCount++;
e1636f82
RG
3320 if (type == QType::DS || type == QType::DNSKEY) {
3321 return genericDSAndDNSKEYHandler(res, domain, DNSName("."), type, keys, domain == authZone);
3322 }
3323
3337c2f7
RG
3324 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3325 setLWResult(res, 0, true, false, true);
3326 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3327 return 1;
3328 }
3329
3330 return 0;
3331 });
3332
e1636f82 3333 sr->setDNSSECValidationRequested(true);
3337c2f7
RG
3334 vector<DNSRecord> ret;
3335 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3336 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3337 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3338 BOOST_CHECK(ret[0].d_type == QType::A);
e1636f82
RG
3339 BOOST_CHECK_EQUAL(queriesCount, 4);
3340 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
3337c2f7
RG
3341}
3342
3343BOOST_AUTO_TEST_CASE(test_auth_zone_delegation_point) {
3344 std::unique_ptr<SyncRes> sr;
895449a5 3345 initSR(sr);
3337c2f7
RG
3346
3347 primeHints();
3348
3349 size_t queriesCount = 0;
3350 const DNSName target("test.powerdns.com.");
3351 const ComboAddress targetAddr("192.0.2.2");
3352 const DNSName ns("ns1.test.powerdns.com.");
3353 const ComboAddress nsAddr("192.0.2.1");
3354 const DNSName authZone("powerdns.com");
3355
3356 SyncRes::AuthDomain ad;
3357 ad.d_name = authZone;
3358 DNSRecord dr;
3359 dr.d_place = DNSResourceRecord::ANSWER;
3360 dr.d_name = authZone;
3361 dr.d_type = QType::SOA;
3362 dr.d_ttl = 3600;
3363 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3364 ad.d_records.insert(dr);
3365
3366 dr.d_place = DNSResourceRecord::ANSWER;
3367 dr.d_name = DNSName("test.powerdns.com.");
3368 dr.d_type = QType::NS;
3369 dr.d_ttl = 3600;
3370 dr.d_content = std::make_shared<NSRecordContent>(ns);
3371 ad.d_records.insert(dr);
3372
3373 dr.d_place = DNSResourceRecord::ANSWER;
3374 dr.d_name = ns;
3375 dr.d_type = QType::A;
3376 dr.d_ttl = 3600;
3377 dr.d_content = std::make_shared<ARecordContent>(nsAddr);
3378 ad.d_records.insert(dr);
3379
3380 auto map = std::make_shared<SyncRes::domainmap_t>();
3381 (*map)[authZone] = ad;
3382 SyncRes::setDomainMap(map);
3383
18d5b679 3384 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, bool* chained) {
3337c2f7
RG
3385
3386 queriesCount++;
3387
3388 if (ip == ComboAddress(nsAddr.toString(), 53) && domain == target) {
3389 setLWResult(res, 0, true, false, true);
3390 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
3391 return 1;
3392 }
3393
3394 return 0;
3395 });
3396
3397 vector<DNSRecord> ret;
3398 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3399 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3400 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3401 BOOST_CHECK(ret[0].d_type == QType::A);
3402 BOOST_CHECK_EQUAL(queriesCount, 1);
3403}
3404
3405BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard) {
3406 std::unique_ptr<SyncRes> sr;
895449a5 3407 initSR(sr);
3337c2f7
RG
3408
3409 primeHints();
3410
3411 size_t queriesCount = 0;
3412 const DNSName target("test.powerdns.com.");
3413 const ComboAddress targetAddr("192.0.2.2");
3414 const DNSName authZone("powerdns.com");
3415
3416 SyncRes::AuthDomain ad;
3417 ad.d_name = authZone;
3418 DNSRecord dr;
3419 dr.d_place = DNSResourceRecord::ANSWER;
3420 dr.d_name = authZone;
3421 dr.d_type = QType::SOA;
3422 dr.d_ttl = 3600;
3423 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3424 ad.d_records.insert(dr);
3425
3426 dr.d_place = DNSResourceRecord::ANSWER;
3427 dr.d_name = DNSName("*.powerdns.com.");
3428 dr.d_type = QType::A;
3429 dr.d_ttl = 3600;
3430 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3431 ad.d_records.insert(dr);
3432
3433 auto map = std::make_shared<SyncRes::domainmap_t>();
3434 (*map)[authZone] = ad;
3435 SyncRes::setDomainMap(map);
3436
18d5b679 3437 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, bool* chained) {
3337c2f7
RG
3438
3439 queriesCount++;
3440
3441 return 0;
3442 });
3443
3444 vector<DNSRecord> ret;
3445 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3446 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3447 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3448 BOOST_CHECK(ret[0].d_type == QType::A);
3449 BOOST_CHECK_EQUAL(queriesCount, 0);
3450}
3451
3452BOOST_AUTO_TEST_CASE(test_auth_zone_wildcard_nodata) {
3453 std::unique_ptr<SyncRes> sr;
895449a5 3454 initSR(sr);
3337c2f7
RG
3455
3456 primeHints();
3457
3458 size_t queriesCount = 0;
3459 const DNSName target("test.powerdns.com.");
3460 const ComboAddress targetAddr("192.0.2.2");
3461 const DNSName authZone("powerdns.com");
3462
3463 SyncRes::AuthDomain ad;
3464 ad.d_name = authZone;
3465 DNSRecord dr;
3466 dr.d_place = DNSResourceRecord::ANSWER;
3467 dr.d_name = authZone;
3468 dr.d_type = QType::SOA;
3469 dr.d_ttl = 3600;
3470 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3471 ad.d_records.insert(dr);
3472
3473 dr.d_place = DNSResourceRecord::ANSWER;
3474 dr.d_name = DNSName("*.powerdns.com.");
3475 dr.d_type = QType::A;
3476 dr.d_ttl = 3600;
3477 dr.d_content = std::make_shared<ARecordContent>(targetAddr);
3478 ad.d_records.insert(dr);
3479
3480 auto map = std::make_shared<SyncRes::domainmap_t>();
3481 (*map)[authZone] = ad;
3482 SyncRes::setDomainMap(map);
3483
18d5b679 3484 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, bool* chained) {
3337c2f7
RG
3485
3486 queriesCount++;
3487
3488 return 0;
3489 });
3490
3491 vector<DNSRecord> ret;
3492 int res = sr->beginResolve(target, QType(QType::AAAA), QClass::IN, ret);
b7f378d1 3493 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3494 BOOST_REQUIRE_EQUAL(ret.size(), 1);
3495 BOOST_CHECK(ret[0].d_type == QType::SOA);
3496 BOOST_CHECK_EQUAL(queriesCount, 0);
3497}
3498
3499BOOST_AUTO_TEST_CASE(test_auth_zone_cache_only) {
3500 std::unique_ptr<SyncRes> sr;
895449a5 3501 initSR(sr);
3337c2f7
RG
3502
3503 primeHints();
3504
3505 size_t queriesCount = 0;
3506 const DNSName target("powerdns.com.");
3507 const ComboAddress addr("192.0.2.5");
3508
3509 SyncRes::AuthDomain ad;
3510 ad.d_name = target;
3511 DNSRecord dr;
3512 dr.d_place = DNSResourceRecord::ANSWER;
3513 dr.d_name = target;
3514 dr.d_type = QType::SOA;
3515 dr.d_ttl = 3600;
3516 dr.d_content = std::make_shared<SOARecordContent>("pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600");
3517 ad.d_records.insert(dr);
3518
3519 dr.d_place = DNSResourceRecord::ANSWER;
3520 dr.d_name = target;
3521 dr.d_type = QType::A;
3522 dr.d_ttl = 3600;
3523 dr.d_content = std::make_shared<ARecordContent>(addr);
3524 ad.d_records.insert(dr);
3525
3526 auto map = std::make_shared<SyncRes::domainmap_t>();
3527 (*map)[target] = ad;
3528 SyncRes::setDomainMap(map);
3529
18d5b679 3530 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, bool* chained) {
3337c2f7
RG
3531
3532 queriesCount++;
3533 setLWResult(res, 0, true, false, true);
3534 addRecordToLW(res, domain, QType::A, "192.0.2.42");
3535 return 1;
3536 });
3537
3538 /* simulate a no-RD query */
3539 sr->setCacheOnly();
3540
3541 vector<DNSRecord> ret;
3542 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1 3543 BOOST_CHECK_EQUAL(res, RCode::NoError);
3337c2f7
RG
3544 BOOST_CHECK_EQUAL(ret.size(), 1);
3545 BOOST_CHECK(ret[0].d_type == QType::A);
3546 BOOST_CHECK_EQUAL(getRR<ARecordContent>(ret[0])->getCA().toString(), addr.toString());
3547 BOOST_CHECK_EQUAL(queriesCount, 0);
3548}
3549
8455425c 3550BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) {
8455425c
RG
3551 init();
3552
3553 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3554 dcke->create(dcke->getBits());
3555 // cerr<<dcke->convertToISC()<<endl;
3556 DNSSECPrivateKey dpk;
3557 dpk.d_flags = 256;
3558 dpk.setKey(dcke);
3559
3560 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
3561 recordcontents.push_back(getRecordContent(QType::A, "192.0.2.1"));
3562
3563 DNSName qname("powerdns.com.");
3564
179b340d 3565 time_t now = time(nullptr);
8455425c 3566 RRSIGRecordContent rrc;
179b340d
RG
3567 /* this RRSIG is valid for the current second only */
3568 computeRRSIG(dpk, qname, qname, QType::A, 600, 0, rrc, recordcontents, boost::none, now);
8455425c
RG
3569
3570 skeyset_t keyset;
3571 keyset.insert(std::make_shared<DNSKEYRecordContent>(dpk.getDNSKEY()));
3572
3573 std::vector<std::shared_ptr<RRSIGRecordContent> > sigs;
3574 sigs.push_back(std::make_shared<RRSIGRecordContent>(rrc));
3575
179b340d 3576 BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset));
8455425c
RG
3577}
3578
3579BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) {
3580 std::unique_ptr<SyncRes> sr;
895449a5 3581 initSR(sr, true);
8455425c 3582
0c43f455 3583 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3584
3585 primeHints();
3586 const DNSName target(".");
b7f378d1 3587 testkeysset_t keys;
8455425c
RG
3588
3589 auto luaconfsCopy = g_luaconfs.getCopy();
3590 luaconfsCopy.dsAnchors.clear();
3591 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3592 g_luaconfs.setState(luaconfsCopy);
3593
3594 size_t queriesCount = 0;
3595
18d5b679 3596 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, bool* chained) {
8455425c
RG
3597 queriesCount++;
3598
3599 if (domain == target && type == QType::NS) {
3600
3601 setLWResult(res, 0, true, false, true);
3602 char addr[] = "a.root-servers.net.";
3603 for (char idx = 'a'; idx <= 'm'; idx++) {
3604 addr[0] = idx;
3605 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3606 }
3607
3608 addRRSIG(keys, res->d_records, domain, 300);
3609
3610 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3611 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3612
3613 return 1;
3614 } else if (domain == target && type == QType::DNSKEY) {
3615
3616 setLWResult(res, 0, true, false, true);
3617
3618 addDNSKEY(keys, domain, 300, res->d_records);
3619 addRRSIG(keys, res->d_records, domain, 300);
3620
3621 return 1;
3622 }
3623
3624 return 0;
3625 });
3626
3627 vector<DNSRecord> ret;
3628 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3629 BOOST_CHECK_EQUAL(res, RCode::NoError);
3630 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
3631 /* 13 NS + 1 RRSIG */
3632 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3633 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3634
3635 /* again, to test the cache */
3636 ret.clear();
3637 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3638 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3639 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
3640 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3641 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3642}
3643
3644BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_ksk_zsk) {
3645 std::unique_ptr<SyncRes> sr;
895449a5 3646 initSR(sr, true);
8455425c 3647
0c43f455 3648 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3649
3650 primeHints();
3651 const DNSName target(".");
b7f378d1
RG
3652 testkeysset_t zskeys;
3653 testkeysset_t kskeys;
8455425c
RG
3654
3655 /* Generate key material for "." */
3656 auto dckeZ = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3657 dckeZ->create(dckeZ->getBits());
3658 DNSSECPrivateKey ksk;
3659 ksk.d_flags = 257;
3660 ksk.setKey(dckeZ);
b7f378d1
RG
3661 DSRecordContent kskds = makeDSFromDNSKey(target, ksk.getDNSKEY(), DNSSECKeeper::SHA256);
3662
8455425c
RG
3663 auto dckeK = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3664 dckeK->create(dckeK->getBits());
3665 DNSSECPrivateKey zsk;
3666 zsk.d_flags = 256;
3667 zsk.setKey(dckeK);
b7f378d1 3668 DSRecordContent zskds = makeDSFromDNSKey(target, zsk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3669
b7f378d1
RG
3670 kskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(ksk, kskds);
3671 zskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(zsk, zskds);
8455425c
RG
3672
3673 /* Set the root DS */
8455425c
RG
3674 auto luaconfsCopy = g_luaconfs.getCopy();
3675 luaconfsCopy.dsAnchors.clear();
b7f378d1 3676 luaconfsCopy.dsAnchors[g_rootdnsname].insert(kskds);
8455425c
RG
3677 g_luaconfs.setState(luaconfsCopy);
3678
3679 size_t queriesCount = 0;
3680
18d5b679 3681 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, bool* chained) {
8455425c
RG
3682 queriesCount++;
3683
3684 if (domain == target && type == QType::NS) {
3685
3686 setLWResult(res, 0, true, false, true);
3687 char addr[] = "a.root-servers.net.";
3688 for (char idx = 'a'; idx <= 'm'; idx++) {
3689 addr[0] = idx;
3690 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3691 }
3692
3693 addRRSIG(zskeys, res->d_records, domain, 300);
3694
3695 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3696 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3697
3698 return 1;
3699 } else if (domain == target && type == QType::DNSKEY) {
3700
3701 setLWResult(res, 0, true, false, true);
3702
3703 addDNSKEY(kskeys, domain, 300, res->d_records);
3704 addDNSKEY(zskeys, domain, 300, res->d_records);
3705 addRRSIG(kskeys, res->d_records, domain, 300);
3706
3707 return 1;
3708 }
3709
3710 return 0;
3711 });
3712
3713 vector<DNSRecord> ret;
3714 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3715 BOOST_CHECK_EQUAL(res, RCode::NoError);
3716 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8455425c
RG
3717 /* 13 NS + 1 RRSIG */
3718 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3719 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3720
3721 /* again, to test the cache */
3722 ret.clear();
3723 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3724 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3725 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1
RG
3726 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3727 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3728}
3729
3730BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_dnskey) {
3731 std::unique_ptr<SyncRes> sr;
895449a5 3732 initSR(sr, true);
8455425c 3733
0c43f455 3734 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3735
3736 primeHints();
3737 const DNSName target(".");
b7f378d1 3738 testkeysset_t keys;
8455425c
RG
3739
3740 auto luaconfsCopy = g_luaconfs.getCopy();
3741 luaconfsCopy.dsAnchors.clear();
3742 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3743 g_luaconfs.setState(luaconfsCopy);
3744
3745 size_t queriesCount = 0;
3746
18d5b679 3747 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, bool* chained) {
8455425c
RG
3748 queriesCount++;
3749
3750 if (domain == target && type == QType::NS) {
3751
3752 setLWResult(res, 0, true, false, true);
3753 char addr[] = "a.root-servers.net.";
3754 for (char idx = 'a'; idx <= 'm'; idx++) {
3755 addr[0] = idx;
3756 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3757 }
3758
3759 addRRSIG(keys, res->d_records, domain, 300);
3760
3761 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3762 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3763
3764 return 1;
3765 } else if (domain == target && type == QType::DNSKEY) {
3766
3767 setLWResult(res, 0, true, false, true);
3768
3769 /* No DNSKEY */
3770
3771 return 1;
3772 }
3773
3774 return 0;
3775 });
3776
3777 vector<DNSRecord> ret;
3778 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3779 BOOST_CHECK_EQUAL(res, RCode::NoError);
3780 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3781 /* 13 NS + 1 RRSIG */
3782 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3783 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3784
3785 /* again, to test the cache */
3786 ret.clear();
3787 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3788 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3789 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3790 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3791 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3792}
3793
3794BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds) {
3795 std::unique_ptr<SyncRes> sr;
895449a5 3796 initSR(sr, true);
8455425c 3797
0c43f455 3798 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3799
3800 primeHints();
3801 const DNSName target(".");
b7f378d1
RG
3802 testkeysset_t dskeys;
3803 testkeysset_t keys;
8455425c
RG
3804
3805 /* Generate key material for "." */
3806 auto dckeDS = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3807 dckeDS->create(dckeDS->getBits());
3808 DNSSECPrivateKey dskey;
3809 dskey.d_flags = 257;
3810 dskey.setKey(dckeDS);
b7f378d1
RG
3811 DSRecordContent drc = makeDSFromDNSKey(target, dskey.getDNSKEY(), DNSSECKeeper::SHA256);
3812
8455425c
RG
3813 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3814 dcke->create(dcke->getBits());
3815 DNSSECPrivateKey dpk;
3816 dpk.d_flags = 256;
3817 dpk.setKey(dcke);
b7f378d1 3818 DSRecordContent uselessdrc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
8455425c 3819
b7f378d1
RG
3820 dskeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dskey, drc);
3821 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, uselessdrc);
8455425c
RG
3822
3823 /* Set the root DS */
8455425c
RG
3824 auto luaconfsCopy = g_luaconfs.getCopy();
3825 luaconfsCopy.dsAnchors.clear();
3826 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
3827 g_luaconfs.setState(luaconfsCopy);
3828
3829 size_t queriesCount = 0;
3830
18d5b679 3831 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, bool* chained) {
8455425c
RG
3832 queriesCount++;
3833
3834 if (domain == target && type == QType::NS) {
3835
3836 setLWResult(res, 0, true, false, true);
3837 char addr[] = "a.root-servers.net.";
3838 for (char idx = 'a'; idx <= 'm'; idx++) {
3839 addr[0] = idx;
3840 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3841 }
3842
3843 addRRSIG(keys, res->d_records, domain, 300);
3844
3845 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3846 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3847
3848 return 1;
3849 } else if (domain == target && type == QType::DNSKEY) {
3850
3851 setLWResult(res, 0, true, false, true);
3852
3853 addDNSKEY(keys, domain, 300, res->d_records);
3854 addRRSIG(keys, res->d_records, domain, 300);
3855
3856 return 1;
3857 }
3858
3859 return 0;
3860 });
3861
3862 vector<DNSRecord> ret;
3863 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3864 BOOST_CHECK_EQUAL(res, RCode::NoError);
3865 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3866 /* 13 NS + 1 RRSIG */
3867 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3868 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3869
3870 /* again, to test the cache */
3871 ret.clear();
3872 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3873 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3874 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3875 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3876 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3877}
3878
3879BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey) {
3880 std::unique_ptr<SyncRes> sr;
895449a5 3881 initSR(sr, true);
8455425c 3882
0c43f455 3883 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3884
3885 primeHints();
3886 const DNSName target(".");
b7f378d1
RG
3887 testkeysset_t keys;
3888 testkeysset_t rrsigkeys;
8455425c
RG
3889
3890 auto luaconfsCopy = g_luaconfs.getCopy();
3891 luaconfsCopy.dsAnchors.clear();
3892 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3893 g_luaconfs.setState(luaconfsCopy);
3894
3895 auto dckeRRSIG = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
3896 dckeRRSIG->create(dckeRRSIG->getBits());
3897 DNSSECPrivateKey rrsigkey;
3898 rrsigkey.d_flags = 257;
3899 rrsigkey.setKey(dckeRRSIG);
b7f378d1
RG
3900 DSRecordContent rrsigds = makeDSFromDNSKey(target, rrsigkey.getDNSKEY(), DNSSECKeeper::SHA256);
3901
3902 rrsigkeys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(rrsigkey, rrsigds);
8455425c
RG
3903
3904 size_t queriesCount = 0;
3905
18d5b679 3906 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, bool* chained) {
8455425c
RG
3907 queriesCount++;
3908
3909 if (domain == target && type == QType::NS) {
3910
3911 setLWResult(res, 0, true, false, true);
3912 char addr[] = "a.root-servers.net.";
3913 for (char idx = 'a'; idx <= 'm'; idx++) {
3914 addr[0] = idx;
3915 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3916 }
3917
3918 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3919
3920 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3921 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3922
3923 return 1;
3924 } else if (domain == target && type == QType::DNSKEY) {
3925
3926 setLWResult(res, 0, true, false, true);
3927
3928 addDNSKEY(keys, domain, 300, res->d_records);
3929 addRRSIG(rrsigkeys, res->d_records, domain, 300);
3930
3931 return 1;
3932 }
3933
3934 return 0;
3935 });
3936
3937 vector<DNSRecord> ret;
3938 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
3939 BOOST_CHECK_EQUAL(res, RCode::NoError);
3940 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
3941 /* 13 NS + 1 RRSIG */
3942 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3943 BOOST_CHECK_EQUAL(queriesCount, 2);
b7f378d1
RG
3944
3945 /* again, to test the cache */
3946 ret.clear();
3947 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
3948 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 3949 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
3950 BOOST_REQUIRE_EQUAL(ret.size(), 14);
3951 BOOST_CHECK_EQUAL(queriesCount, 2);
8455425c
RG
3952}
3953
3954BOOST_AUTO_TEST_CASE(test_dnssec_bogus_no_rrsig) {
3955 std::unique_ptr<SyncRes> sr;
895449a5 3956 initSR(sr, true);
8455425c 3957
0c43f455 3958 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
3959
3960 primeHints();
3961 const DNSName target(".");
b7f378d1 3962 testkeysset_t keys;
8455425c
RG
3963
3964 auto luaconfsCopy = g_luaconfs.getCopy();
3965 luaconfsCopy.dsAnchors.clear();
3966 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
3967 g_luaconfs.setState(luaconfsCopy);
3968
3969 size_t queriesCount = 0;
3970
18d5b679 3971 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, bool* chained) {
8455425c
RG
3972 queriesCount++;
3973
3974 if (domain == target && type == QType::NS) {
3975
3976 setLWResult(res, 0, true, false, true);
3977 char addr[] = "a.root-servers.net.";
3978 for (char idx = 'a'; idx <= 'm'; idx++) {
3979 addr[0] = idx;
3980 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
3981 }
3982
3983 /* No RRSIG */
3984
3985 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
3986 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
3987
3988 return 1;
3989 } else if (domain == target && type == QType::DNSKEY) {
3990
3991 setLWResult(res, 0, true, false, true);
3992
3993 addDNSKEY(keys, domain, 300, res->d_records);
3994 addRRSIG(keys, res->d_records, domain, 300);
3995
3996 return 1;
3997 }
3998
3999 return 0;
4000 });
4001
4002 vector<DNSRecord> ret;
4003 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4004 BOOST_CHECK_EQUAL(res, RCode::NoError);
4005 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8455425c
RG
4006 /* 13 NS + 0 RRSIG */
4007 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4008 /* no RRSIG so no query for DNSKEYs */
4009 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4010
4011 /* again, to test the cache */
4012 ret.clear();
4013 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4014 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4015 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
b7f378d1
RG
4016 BOOST_REQUIRE_EQUAL(ret.size(), 13);
4017 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4018}
4019
4020BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_algorithm) {
4021 std::unique_ptr<SyncRes> sr;
895449a5 4022 initSR(sr, true);
8455425c 4023
0c43f455 4024 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4025
4026 primeHints();
4027 const DNSName target(".");
b7f378d1 4028 testkeysset_t keys;
8455425c
RG
4029
4030 /* Generate key material for "." */
4031 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4032 dcke->create(dcke->getBits());
4033 DNSSECPrivateKey dpk;
4034 dpk.d_flags = 256;
4035 dpk.setKey(dcke);
4036 /* Fake algorithm number (private) */
4037 dpk.d_algorithm = 253;
4038
8455425c 4039 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
b7f378d1 4040 keys[target] = std::pair<DNSSECPrivateKey,DSRecordContent>(dpk, drc);
8455425c
RG
4041 /* Fake algorithm number (private) */
4042 drc.d_algorithm = 253;
4043
b7f378d1 4044 /* Set the root DS */
8455425c
RG
4045 auto luaconfsCopy = g_luaconfs.getCopy();
4046 luaconfsCopy.dsAnchors.clear();
4047 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4048 g_luaconfs.setState(luaconfsCopy);
4049
4050 size_t queriesCount = 0;
4051
18d5b679 4052 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, bool* chained) {
8455425c
RG
4053 queriesCount++;
4054
4055 if (domain == target && type == QType::NS) {
4056
4057 setLWResult(res, 0, true, false, true);
4058 char addr[] = "a.root-servers.net.";
4059 for (char idx = 'a'; idx <= 'm'; idx++) {
4060 addr[0] = idx;
4061 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4062 }
4063
4064 addRRSIG(keys, res->d_records, domain, 300);
4065
4066 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4067 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4068
4069 return 1;
4070 } else if (domain == target && type == QType::DNSKEY) {
4071
4072 setLWResult(res, 0, true, false, true);
4073
4074 addDNSKEY(keys, domain, 300, res->d_records);
4075 addRRSIG(keys, res->d_records, domain, 300);
4076
4077 return 1;
4078 }
4079
4080 return 0;
4081 });
4082
4083 vector<DNSRecord> ret;
4084 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4085 BOOST_CHECK_EQUAL(res, RCode::NoError);
4086 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4087 /* 13 NS + 1 RRSIG */
4088 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4089 /* no supported DS so no query for DNSKEYs */
4090 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4091
4092 /* again, to test the cache */
4093 ret.clear();
4094 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4095 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4096 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4097 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4098 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4099}
4100
4101BOOST_AUTO_TEST_CASE(test_dnssec_insecure_unknown_ds_digest) {
4102 std::unique_ptr<SyncRes> sr;
895449a5 4103 initSR(sr, true);
8455425c 4104
0c43f455 4105 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4106
4107 primeHints();
4108 const DNSName target(".");
b7f378d1 4109 testkeysset_t keys;
8455425c
RG
4110
4111 /* Generate key material for "." */
4112 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(DNSSECKeeper::ECDSA256));
4113 dcke->create(dcke->getBits());
4114 DNSSECPrivateKey dpk;
4115 dpk.d_flags = 256;
4116 dpk.setKey(dcke);
8455425c
RG
4117 DSRecordContent drc = makeDSFromDNSKey(target, dpk.getDNSKEY(), DNSSECKeeper::SHA256);
4118 /* Fake digest number (reserved) */
4119 drc.d_digesttype = 0;
4120
b7f378d1
RG
4121 keys[target] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, drc);
4122
4123 /* Set the root DS */
8455425c
RG
4124 auto luaconfsCopy = g_luaconfs.getCopy();
4125 luaconfsCopy.dsAnchors.clear();
4126 luaconfsCopy.dsAnchors[g_rootdnsname].insert(drc);
4127 g_luaconfs.setState(luaconfsCopy);
4128
4129 size_t queriesCount = 0;
4130
18d5b679 4131 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, bool* chained) {
8455425c
RG
4132 queriesCount++;
4133
4134 if (domain == target && type == QType::NS) {
4135
4136 setLWResult(res, 0, true, false, true);
4137 char addr[] = "a.root-servers.net.";
4138 for (char idx = 'a'; idx <= 'm'; idx++) {
4139 addr[0] = idx;
4140 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4141 }
4142
4143 addRRSIG(keys, res->d_records, domain, 300);
4144
4145 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4146 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4147
4148 return 1;
4149 } else if (domain == target && type == QType::DNSKEY) {
4150
4151 setLWResult(res, 0, true, false, true);
4152
4153 addDNSKEY(keys, domain, 300, res->d_records);
4154 addRRSIG(keys, res->d_records, domain, 300);
4155
4156 return 1;
4157 }
4158
4159 return 0;
4160 });
4161
4162 vector<DNSRecord> ret;
4163 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
4164 BOOST_CHECK_EQUAL(res, RCode::NoError);
4165 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
4166 /* 13 NS + 1 RRSIG */
4167 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4168 /* no supported DS so no query for DNSKEYs */
4169 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
4170
4171 /* again, to test the cache */
4172 ret.clear();
4173 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4174 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4175 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
4176 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4177 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
4178}
4179
3d5ebf10
RG
4180BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_sig) {
4181 std::unique_ptr<SyncRes> sr;
4182 initSR(sr, true);
4183
0c43f455 4184 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4185
4186 primeHints();
4187 const DNSName target(".");
4188 testkeysset_t keys;
4189
4190 auto luaconfsCopy = g_luaconfs.getCopy();
4191 luaconfsCopy.dsAnchors.clear();
4192 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4193
4194 g_luaconfs.setState(luaconfsCopy);
4195
4196 size_t queriesCount = 0;
4197
18d5b679 4198 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, bool* chained) {
3d5ebf10
RG
4199 queriesCount++;
4200
4201 if (domain == target && type == QType::NS) {
4202
4203 setLWResult(res, 0, true, false, true);
4204 char addr[] = "a.root-servers.net.";
4205 for (char idx = 'a'; idx <= 'm'; idx++) {
4206 addr[0] = idx;
4207 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4208 }
4209
4210 addRRSIG(keys, res->d_records, domain, 300, true);
4211
4212 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4213 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4214
4215 return 1;
4216 } else if (domain == target && type == QType::DNSKEY) {
4217
4218 setLWResult(res, 0, true, false, true);
4219
4220 addDNSKEY(keys, domain, 300, res->d_records);
4221 addRRSIG(keys, res->d_records, domain, 300);
4222
4223 return 1;
4224 }
4225
4226 return 0;
4227 });
4228
4229 vector<DNSRecord> ret;
4230 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4231 BOOST_CHECK_EQUAL(res, RCode::NoError);
4232 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4233 /* 13 NS + 1 RRSIG */
4234 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4235 BOOST_CHECK_EQUAL(queriesCount, 2);
4236
4237 /* again, to test the cache */
4238 ret.clear();
4239 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4240 BOOST_CHECK_EQUAL(res, RCode::NoError);
4241 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4242 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4243 BOOST_CHECK_EQUAL(queriesCount, 2);
4244}
4245
4246BOOST_AUTO_TEST_CASE(test_dnssec_bogus_bad_algo) {
4247 std::unique_ptr<SyncRes> sr;
4248 initSR(sr, true);
4249
0c43f455 4250 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
4251
4252 primeHints();
4253 const DNSName target(".");
4254 testkeysset_t keys;
4255
4256 auto luaconfsCopy = g_luaconfs.getCopy();
4257 luaconfsCopy.dsAnchors.clear();
4258 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4259
4260 g_luaconfs.setState(luaconfsCopy);
4261
4262 size_t queriesCount = 0;
4263
18d5b679 4264 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, bool* chained) {
3d5ebf10
RG
4265 queriesCount++;
4266
4267 if (domain == target && type == QType::NS) {
4268
4269 setLWResult(res, 0, true, false, true);
4270 char addr[] = "a.root-servers.net.";
4271 for (char idx = 'a'; idx <= 'm'; idx++) {
4272 addr[0] = idx;
4273 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
4274 }
4275
4276 /* FORCE WRONG ALGO */
4277 addRRSIG(keys, res->d_records, domain, 300, false, DNSSECKeeper::RSASHA256);
4278
4279 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
4280 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
4281
4282 return 1;
4283 } else if (domain == target && type == QType::DNSKEY) {
4284
4285 setLWResult(res, 0, true, false, true);
4286
4287 addDNSKEY(keys, domain, 300, res->d_records);
4288 addRRSIG(keys, res->d_records, domain, 300);
4289
4290 return 1;
4291 }
4292
4293 return 0;
4294 });
4295
4296 vector<DNSRecord> ret;
4297 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4298 BOOST_CHECK_EQUAL(res, RCode::NoError);
4299 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4300 /* 13 NS + 1 RRSIG */
4301 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4302 BOOST_CHECK_EQUAL(queriesCount, 2);
4303
4304 /* again, to test the cache */
4305 ret.clear();
4306 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4307 BOOST_CHECK_EQUAL(res, RCode::NoError);
4308 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4309 BOOST_REQUIRE_EQUAL(ret.size(), 14);
4310 BOOST_CHECK_EQUAL(queriesCount, 2);
4311}
4312
cd48a0ff
RG
4313BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds) {
4314 std::unique_ptr<SyncRes> sr;
4315 initSR(sr, true);
4316
4317 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4318
4319 primeHints();
4320 const DNSName target("com.");
4321 const ComboAddress targetAddr("192.0.2.42");
4322 testkeysset_t keys;
4323
4324 auto luaconfsCopy = g_luaconfs.getCopy();
4325 luaconfsCopy.dsAnchors.clear();
4326 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4327 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4328
4329 g_luaconfs.setState(luaconfsCopy);
4330
4331 size_t queriesCount = 0;
4332
18d5b679 4333 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, bool* chained) {
cd48a0ff
RG
4334 queriesCount++;
4335
4336 DNSName auth = domain;
4337
4338 if (type == QType::DS || type == QType::DNSKEY) {
4339 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4340 return 0;
4341 }
4342
4343 if (type == QType::DS && domain == target) {
4344 /* remove the last record, which is the DS's RRSIG */
4345 res->d_records.pop_back();
4346 }
4347
4348 return 1;
4349 }
4350
4351 if (isRootServer(ip)) {
4352 setLWResult(res, 0, false, false, true);
4353 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4354 /* Include the DS but omit the RRSIG*/
4355 addDS(DNSName("com."), 300, res->d_records, keys);
4356 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4357 return 1;
4358 }
4359
4360 if (ip == ComboAddress("192.0.2.1:53")) {
4361 setLWResult(res, RCode::NoError, true, false, true);
4362 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4363 addRRSIG(keys, res->d_records, auth, 300);
4364 return 1;
4365 }
4366
4367 return 0;
4368 });
4369
4370 vector<DNSRecord> ret;
4371 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4372 BOOST_CHECK_EQUAL(res, RCode::NoError);
4373 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4374 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4375 BOOST_CHECK_EQUAL(queriesCount, 4);
4376
4377 /* again, to test the cache */
4378 ret.clear();
4379 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4380 BOOST_CHECK_EQUAL(res, RCode::NoError);
4381 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4382 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4383 BOOST_CHECK_EQUAL(queriesCount, 4);
4384
4385 /* now we ask directly for the DS */
4386 ret.clear();
4387 res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4388 BOOST_CHECK_EQUAL(res, RCode::NoError);
4389 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4390 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4391 BOOST_CHECK_EQUAL(queriesCount, 4);
4392}
4393
4394BOOST_AUTO_TEST_CASE(test_dnssec_bogus_unsigned_ds_direct) {
4395 std::unique_ptr<SyncRes> sr;
4396 initSR(sr, true);
4397
4398 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
4399
4400 primeHints();
4401 const DNSName target("com.");
4402 testkeysset_t keys;
4403
4404 auto luaconfsCopy = g_luaconfs.getCopy();
4405 luaconfsCopy.dsAnchors.clear();
4406 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4407 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4408
4409 g_luaconfs.setState(luaconfsCopy);
4410
4411 size_t queriesCount = 0;
4412
18d5b679 4413 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, bool* chained) {
cd48a0ff
RG
4414 queriesCount++;
4415
4416 DNSName auth = domain;
4417
4418 if (type == QType::DS || type == QType::DNSKEY) {
4419 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys) == 0) {
4420 return 0;
4421 }
4422
4423 if (type == QType::DS && domain == target) {
4424 /* remove the last record, which is the DS's RRSIG */
4425 res->d_records.pop_back();
4426 }
4427
4428 return 1;
4429 }
4430
4431 if (isRootServer(ip)) {
4432 setLWResult(res, 0, false, false, true);
4433 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4434 /* Include the DS but omit the RRSIG*/
4435 addDS(DNSName("com."), 300, res->d_records, keys);
4436 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4437 return 1;
4438 }
4439
4440 return 0;
4441 });
4442
4443 vector<DNSRecord> ret;
4444 int res = sr->beginResolve(DNSName("com."), QType(QType::DS), QClass::IN, ret);
4445 BOOST_CHECK_EQUAL(res, RCode::NoError);
4446 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
4447 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4448 BOOST_CHECK_EQUAL(queriesCount, 1);
4449}
4450
b7f378d1 4451BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) {
8455425c 4452 std::unique_ptr<SyncRes> sr;
895449a5 4453 initSR(sr, true);
8455425c 4454
0c43f455 4455 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4456
4457 primeHints();
4458 const DNSName target("powerdns.com.");
b7f378d1
RG
4459 const ComboAddress targetAddr("192.0.2.42");
4460 testkeysset_t keys;
8455425c
RG
4461
4462 auto luaconfsCopy = g_luaconfs.getCopy();
4463 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4464 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::RSASHA512, DNSSECKeeper::SHA384, keys, luaconfsCopy.dsAnchors);
4465 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4466 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA384, DNSSECKeeper::SHA384, keys);
8455425c
RG
4467
4468 g_luaconfs.setState(luaconfsCopy);
4469
4470 size_t queriesCount = 0;
4471
18d5b679 4472 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, bool* chained) {
8455425c
RG
4473 queriesCount++;
4474
b7f378d1
RG
4475 DNSName auth = domain;
4476 if (domain == target) {
4477 auth = DNSName("powerdns.com.");
4478 }
5374b03b
RG
4479
4480 if (type == QType::DS || type == QType::DNSKEY) {
4481 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8455425c 4482 }
5374b03b
RG
4483
4484 if (isRootServer(ip)) {
4485 setLWResult(res, 0, false, false, true);
4486 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4487 addDS(DNSName("com."), 300, res->d_records, keys);
4488 addRRSIG(keys, res->d_records, DNSName("."), 300);
4489 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
8455425c
RG
4490 return 1;
4491 }
5374b03b
RG
4492
4493 if (ip == ComboAddress("192.0.2.1:53")) {
4494 if (domain == DNSName("com.")) {
4495 setLWResult(res, 0, true, false, true);
4496 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4497 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4498 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4499 addRRSIG(keys, res->d_records, domain, 300);
8455425c 4500 }
5374b03b
RG
4501 else {
4502 setLWResult(res, 0, false, false, true);
4503 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4504 addDS(auth, 300, res->d_records, keys);
4505 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4506 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
8455425c 4507 }
5374b03b
RG
4508 return 1;
4509 }
4510
4511 if (ip == ComboAddress("192.0.2.2:53")) {
4512 if (type == QType::NS) {
4513 setLWResult(res, 0, true, false, true);
4514 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4515 addRRSIG(keys, res->d_records, auth, 300);
4516 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4517 addRRSIG(keys, res->d_records, auth, 300);
8455425c 4518 }
5374b03b
RG
4519 else {
4520 setLWResult(res, RCode::NoError, true, false, true);
4521 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4522 addRRSIG(keys, res->d_records, auth, 300);
4523 }
4524 return 1;
8455425c
RG
4525 }
4526
4527 return 0;
4528 });
4529
4530 vector<DNSRecord> ret;
4531 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
b7f378d1
RG
4532 BOOST_CHECK_EQUAL(res, RCode::NoError);
4533 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4534 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4535 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
4536
4537 /* again, to test the cache */
4538 ret.clear();
4539 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4540 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 4541 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
b7f378d1 4542 BOOST_REQUIRE_EQUAL(ret.size(), 2);
f24465e5 4543 BOOST_CHECK_EQUAL(queriesCount, 8);
8455425c
RG
4544}
4545
428f41b7
RG
4546BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) {
4547 std::unique_ptr<SyncRes> sr;
4548 initSR(sr, true);
4549
0c43f455 4550 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4551
4552 primeHints();
4553 const DNSName target("powerdns.com.");
4554 const ComboAddress targetAddr("192.0.2.42");
4555 testkeysset_t keys;
4556
4557 auto luaconfsCopy = g_luaconfs.getCopy();
4558 luaconfsCopy.dsAnchors.clear();
4559 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4560 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4561 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4562 g_luaconfs.setState(luaconfsCopy);
4563
4564 size_t queriesCount = 0;
4565
18d5b679 4566 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, bool* chained) {
428f41b7
RG
4567 queriesCount++;
4568
4569 DNSName auth = domain;
4570 if (domain == target) {
4571 auth = DNSName("powerdns.com.");
4572 }
5374b03b
RG
4573
4574 if (type == QType::DS || type == QType::DNSKEY) {
4575 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4576 }
5374b03b
RG
4577
4578 if (isRootServer(ip)) {
4579 setLWResult(res, 0, false, false, true);
4580 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4581 addDS(DNSName("com."), 300, res->d_records, keys);
4582 addRRSIG(keys, res->d_records, DNSName("."), 300);
4583 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4584 return 1;
4585 }
5374b03b
RG
4586
4587 if (ip == ComboAddress("192.0.2.1:53")) {
4588 if (domain == DNSName("com.")) {
4589 setLWResult(res, 0, true, false, true);
4590 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4591 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4592 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4593 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4594 }
5374b03b
RG
4595 else {
4596 setLWResult(res, 0, false, false, true);
4597 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4598 addDS(auth, 300, res->d_records, keys);
4599 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4600 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4601 }
5374b03b
RG
4602 return 1;
4603 }
4604
4605 if (ip == ComboAddress("192.0.2.2:53")) {
4606 if (type == QType::NS) {
4607 setLWResult(res, 0, true, false, true);
4608 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4609 addRRSIG(keys, res->d_records, auth, 300);
4610 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4611 addRRSIG(keys, res->d_records, auth, 300);
4612 }
4613 else {
4614 setLWResult(res, RCode::NoError, true, false, true);
4615 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4616 addRRSIG(keys, res->d_records, auth, 300);
428f41b7 4617 }
5374b03b 4618 return 1;
428f41b7
RG
4619 }
4620
4621 return 0;
4622 });
4623
4624 vector<DNSRecord> ret;
4625 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4626 BOOST_CHECK_EQUAL(res, RCode::NoError);
4627 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4628 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4629 BOOST_CHECK_EQUAL(queriesCount, 8);
4630
4631 /* again, to test the cache */
4632 ret.clear();
4633 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4634 BOOST_CHECK_EQUAL(res, RCode::NoError);
4635 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4636 BOOST_REQUIRE_EQUAL(ret.size(), 2);
4637 BOOST_CHECK_EQUAL(queriesCount, 8);
4638
4639 /* this time we ask for the NS that should be in the cache, to check
4640 the validation status */
4641 ret.clear();
4642 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4643 BOOST_CHECK_EQUAL(res, RCode::NoError);
4644 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
4645 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4646 BOOST_CHECK_EQUAL(queriesCount, 9);
428f41b7
RG
4647
4648}
4649
4650BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) {
4651 std::unique_ptr<SyncRes> sr;
4652 initSR(sr, true);
4653
0c43f455 4654 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
428f41b7
RG
4655
4656 primeHints();
4657 const DNSName target("powerdns.com.");
4658 const ComboAddress targetAddr("192.0.2.42");
4659 testkeysset_t keys;
4660
4661 auto luaconfsCopy = g_luaconfs.getCopy();
4662 luaconfsCopy.dsAnchors.clear();
4663 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4664 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4665 g_luaconfs.setState(luaconfsCopy);
4666
4667 size_t queriesCount = 0;
4668
18d5b679 4669 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, bool* chained) {
428f41b7
RG
4670 queriesCount++;
4671
4672 DNSName auth = domain;
4673 if (domain == target) {
4674 auth = DNSName("powerdns.com.");
4675 }
5374b03b
RG
4676
4677 if (type == QType::DS || type == QType::DNSKEY) {
4678 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
428f41b7 4679 }
5374b03b
RG
4680
4681 if (isRootServer(ip)) {
4682 setLWResult(res, 0, false, false, true);
4683 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4684 addDS(DNSName("com."), 300, res->d_records, keys);
4685 addRRSIG(keys, res->d_records, DNSName("."), 300);
4686 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7
RG
4687 return 1;
4688 }
5374b03b
RG
4689
4690 if (ip == ComboAddress("192.0.2.1:53")) {
4691 if (domain == DNSName("com.")) {
4692 setLWResult(res, 0, true, false, true);
4693 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4694 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4695 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4696 addRRSIG(keys, res->d_records, domain, 300);
428f41b7 4697 }
5374b03b
RG
4698 else {
4699 setLWResult(res, 0, false, false, true);
4700 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4701 /* no DS */
4702 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
4703 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4704 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4705 }
5374b03b
RG
4706 return 1;
4707 }
4708
4709 if (ip == ComboAddress("192.0.2.2:53")) {
4710 if (type == QType::NS) {
4711 setLWResult(res, 0, true, false, true);
4712 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4713 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
428f41b7 4714 }
5374b03b
RG
4715 else {
4716 setLWResult(res, RCode::NoError, true, false, true);
4717 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4718 }
4719 return 1;
428f41b7
RG
4720 }
4721
4722 return 0;
4723 });
4724
4725 vector<DNSRecord> ret;
4726 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4727 BOOST_CHECK_EQUAL(res, RCode::NoError);
4728 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4729 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4730 BOOST_CHECK_EQUAL(queriesCount, 7);
4731
4732 /* again, to test the cache */
4733 ret.clear();
4734 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4735 BOOST_CHECK_EQUAL(res, RCode::NoError);
4736 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4737 BOOST_REQUIRE_EQUAL(ret.size(), 1);
4738 BOOST_CHECK_EQUAL(queriesCount, 7);
4739
4740 /* this time we ask for the NS that should be in the cache, to check
4741 the validation status */
4742 ret.clear();
4743 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
4744 BOOST_CHECK_EQUAL(res, RCode::NoError);
4745 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4746 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4747 BOOST_CHECK_EQUAL(queriesCount, 8);
428f41b7
RG
4748}
4749
b7f378d1 4750BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) {
8455425c 4751 std::unique_ptr<SyncRes> sr;
895449a5 4752 initSR(sr, true);
8455425c 4753
0c43f455 4754 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
4755
4756 primeHints();
b7f378d1
RG
4757 const DNSName target("powerdns.com.");
4758 const ComboAddress targetAddr("192.0.2.42");
4759 testkeysset_t keys;
8455425c
RG
4760
4761 auto luaconfsCopy = g_luaconfs.getCopy();
4762 luaconfsCopy.dsAnchors.clear();
b7f378d1
RG
4763 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4764 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4765 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4766
4767 /* Add a NTA for "powerdns.com" */
4768 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
8455425c 4769
8455425c
RG
4770 g_luaconfs.setState(luaconfsCopy);
4771
4772 size_t queriesCount = 0;
4773
18d5b679 4774 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, bool* chained) {
8455425c
RG
4775 queriesCount++;
4776
b7f378d1
RG
4777 DNSName auth = domain;
4778 if (domain == target) {
4779 auth = DNSName("powerdns.com.");
4780 }
5374b03b
RG
4781
4782 if (type == QType::DS || type == QType::DNSKEY) {
4783 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
b7f378d1 4784 }
5374b03b
RG
4785
4786 if (isRootServer(ip)) {
4787 setLWResult(res, 0, false, false, true);
4788 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4789 addDS(DNSName("com."), 300, res->d_records, keys);
4790 addRRSIG(keys, res->d_records, DNSName("."), 300);
4791 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1
RG
4792 return 1;
4793 }
5374b03b
RG
4794
4795 if (ip == ComboAddress("192.0.2.1:53")) {
4796 if (domain == DNSName("com.")) {
4797 setLWResult(res, 0, true, false, true);
4798 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4799 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4800 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5374b03b 4801 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 4802 }
5374b03b
RG
4803 else {
4804 setLWResult(res, 0, false, false, true);
4805 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4806 addDS(auth, 300, res->d_records, keys);
4807 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4808 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
b7f378d1 4809 }
5374b03b
RG
4810 return 1;
4811 }
4812
4813 if (ip == ComboAddress("192.0.2.2:53")) {
4814 if (type == QType::NS) {
4815 setLWResult(res, 0, true, false, true);
4816 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4817 addRRSIG(keys, res->d_records, auth, 300);
4818 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4819 addRRSIG(keys, res->d_records, auth, 300);
4820 }
4821 else {
4822 setLWResult(res, RCode::NoError, true, false, true);
4823 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4824 addRRSIG(keys, res->d_records, auth, 300);
b7f378d1 4825 }
5374b03b 4826 return 1;
b7f378d1
RG
4827 }
4828
4829 return 0;
4830 });
4831
4832 vector<DNSRecord> ret;
4833 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4834 BOOST_CHECK_EQUAL(res, RCode::NoError);
4835 /* Should be insecure because of the NTA */
4836 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4837 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4838 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4839
4840 /* again, to test the cache */
4841 ret.clear();
4842 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4843 BOOST_CHECK_EQUAL(res, RCode::NoError);
4844 /* Should be insecure because of the NTA */
4845 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4846 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b 4847 BOOST_CHECK_EQUAL(queriesCount, 5);
b7f378d1
RG
4848}
4849
4850BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) {
4851 std::unique_ptr<SyncRes> sr;
895449a5 4852 initSR(sr, true);
b7f378d1 4853
0c43f455 4854 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
4855
4856 primeHints();
4857 const DNSName target("powerdns.com.");
4858 const ComboAddress targetAddr("192.0.2.42");
4859 testkeysset_t keys;
4860
4861 auto luaconfsCopy = g_luaconfs.getCopy();
4862 luaconfsCopy.dsAnchors.clear();
4863 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4864 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4865 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4866
4867 /* Add a NTA for "powerdns.com" */
4868 luaconfsCopy.negAnchors[target] = "NTA for PowerDNS.com";
4869
4870 g_luaconfs.setState(luaconfsCopy);
4871
4872 size_t queriesCount = 0;
4873
18d5b679 4874 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, bool* chained) {
b7f378d1
RG
4875 queriesCount++;
4876
4877 if (type == QType::DS || type == QType::DNSKEY) {
4878 setLWResult(res, 0, false, false, true);
4879 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
4880 return 1;
4881 }
f24465e5 4882 else {
b7f378d1
RG
4883 if (isRootServer(ip)) {
4884 setLWResult(res, 0, false, false, true);
4885 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4886 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4887 return 1;
4888 }
4889 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
4890 if (domain == DNSName("com.")) {
4891 setLWResult(res, 0, true, false, true);
4892 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4893 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4894 }
4895 else {
4896 setLWResult(res, 0, false, false, true);
4897 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4898 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4899 }
b7f378d1
RG
4900 return 1;
4901 }
4902 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
4903 if (type == QType::NS) {
4904 setLWResult(res, 0, true, false, true);
4905 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4906 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4907 }
4908 else {
4909 setLWResult(res, RCode::NoError, true, false, true);
4910 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
4911 }
b7f378d1
RG
4912 return 1;
4913 }
4914 }
4915
4916 return 0;
4917 });
4918
4919 /* There is TA for root but no DS/DNSKEY/RRSIG, should be Bogus, but.. */
4920 vector<DNSRecord> ret;
4921 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4922 BOOST_CHECK_EQUAL(res, RCode::NoError);
4923 /* Should be insecure because of the NTA */
4924 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4925 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4926 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
4927
4928 /* again, to test the cache */
4929 ret.clear();
4930 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
4931 BOOST_CHECK_EQUAL(res, RCode::NoError);
4932 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
4933 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 4934 BOOST_CHECK_EQUAL(queriesCount, 4);
b7f378d1
RG
4935}
4936
4937BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) {
4938 std::unique_ptr<SyncRes> sr;
895449a5 4939 initSR(sr, true);
b7f378d1 4940
0c43f455 4941 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
4942
4943 primeHints();
4944 const DNSName target("powerdns.com.");
4945 testkeysset_t keys;
4946
4947 auto luaconfsCopy = g_luaconfs.getCopy();
4948 luaconfsCopy.dsAnchors.clear();
4949 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
4950 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4951 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
4952
4953 g_luaconfs.setState(luaconfsCopy);
4954
4955 size_t queriesCount = 0;
4956
18d5b679 4957 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, bool* chained) {
b7f378d1
RG
4958 queriesCount++;
4959
5374b03b
RG
4960 if (type == QType::DS || type == QType::DNSKEY) {
4961 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 4962 }
f24465e5 4963 else {
b7f378d1
RG
4964 if (isRootServer(ip)) {
4965 setLWResult(res, 0, false, false, true);
4966 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
4967 addDS(DNSName("com."), 300, res->d_records, keys);
4968 addRRSIG(keys, res->d_records, DNSName("."), 300);
4969 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4970 return 1;
4971 }
4972 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
4973 if (domain == DNSName("com.")) {
4974 setLWResult(res, 0, true, false, true);
4975 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
4976 addRRSIG(keys, res->d_records, domain, 300);
4977 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
4978 addRRSIG(keys, res->d_records, domain, 300);
4979 }
4980 else {
4981 setLWResult(res, 0, false, false, true);
4982 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
4983 addDS(domain, 300, res->d_records, keys);
4984 addRRSIG(keys, res->d_records, DNSName("com."), 300);
4985 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4986 }
b7f378d1
RG
4987 return 1;
4988 }
4989 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
4990 if (type == QType::NS) {
4991 setLWResult(res, 0, true, false, true);
4992 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
4993 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4994 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
4995 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
4996 }
4997 else {
4998 setLWResult(res, 0, true, false, true);
4999 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5000 addRRSIG(keys, res->d_records, domain, 300);
5001 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
5002 addRRSIG(keys, res->d_records, domain, 300);
5003 }
b7f378d1
RG
5004 return 1;
5005 }
5006 }
5007
5008 return 0;
5009 });
5010
5011 vector<DNSRecord> ret;
5012 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5013 BOOST_CHECK_EQUAL(res, RCode::NoError);
5014 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5015 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5016 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5017
5018 /* again, to test the cache */
5019 ret.clear();
5020 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5021 BOOST_CHECK_EQUAL(res, RCode::NoError);
5022 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5023 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5024 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
5025}
5026
5027BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) {
5028 std::unique_ptr<SyncRes> sr;
895449a5 5029 initSR(sr, true);
b7f378d1 5030
0c43f455 5031 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
5032
5033 primeHints();
5034 const DNSName target("nx.powerdns.com.");
5035 testkeysset_t keys;
5036
5037 auto luaconfsCopy = g_luaconfs.getCopy();
5038 luaconfsCopy.dsAnchors.clear();
5039 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5040 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5041 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5042
5043 g_luaconfs.setState(luaconfsCopy);
5044
5045 size_t queriesCount = 0;
5046
18d5b679 5047 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, bool* chained) {
b7f378d1
RG
5048 queriesCount++;
5049
5050 DNSName auth = domain;
5051 if (domain == target) {
5052 auth = DNSName("powerdns.com.");
5053 }
5374b03b
RG
5054 if (type == QType::DS || type == QType::DNSKEY) {
5055 if (type == QType::DS && domain == target) {
5056 setLWResult(res, RCode::NXDomain, true, false, true);
5057 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5058 addRRSIG(keys, res->d_records, auth, 300);
5059 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5060 addRRSIG(keys, res->d_records, auth, 300);
5061 return 1;
5062 }
5063 else {
5064 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
5065 }
b7f378d1 5066 }
f24465e5 5067 else {
b7f378d1
RG
5068 if (isRootServer(ip)) {
5069 setLWResult(res, 0, false, false, true);
5070 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5071 addDS(DNSName("com."), 300, res->d_records, keys);
5072 addRRSIG(keys, res->d_records, DNSName("."), 300);
5073 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5074 return 1;
5075 }
5076 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5077 if (domain == DNSName("com.")) {
5078 setLWResult(res, 0, true, false, true);
5079 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5080 addRRSIG(keys, res->d_records, domain, 300);
5081 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5082 addRRSIG(keys, res->d_records, domain, 300);
5083 }
5084 else {
5085 setLWResult(res, 0, false, false, true);
5086 addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5087 addDS(auth, 300, res->d_records, keys);
5088 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5089 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5090 }
b7f378d1
RG
5091 return 1;
5092 }
5093 else if (ip == ComboAddress("192.0.2.2:53")) {
f24465e5
RG
5094 if (type == QType::NS) {
5095 setLWResult(res, 0, true, false, true);
5096 if (domain == DNSName("powerdns.com.")) {
5097 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5098 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5099 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5100 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5101 }
5102 else {
5103 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5104 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5105 addNSECRecordToLW(DNSName("nx.powerdns.com."), DNSName("nz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5106 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5107 }
5108 }
5109 else {
5110 setLWResult(res, RCode::NXDomain, true, false, true);
5111 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5112 addRRSIG(keys, res->d_records, auth, 300);
5113 addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5114 addRRSIG(keys, res->d_records, auth, 300);
9b061cf5
RG
5115 /* add wildcard denial */
5116 addNSECRecordToLW(DNSName("powerdns.com."), DNSName("a.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5117 addRRSIG(keys, res->d_records, auth, 300);
f24465e5 5118 }
b7f378d1
RG
5119 return 1;
5120 }
5121 }
5122
5123 return 0;
5124 });
5125
5126 vector<DNSRecord> ret;
5127 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5128 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5129 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5130 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5131 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5132
5133 /* again, to test the cache */
5134 ret.clear();
5135 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5136 BOOST_CHECK_EQUAL(res, RCode::NXDomain);
5137 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9b061cf5 5138 BOOST_REQUIRE_EQUAL(ret.size(), 6);
f24465e5 5139 BOOST_CHECK_EQUAL(queriesCount, 9);
b7f378d1
RG
5140}
5141
2b984251
RG
5142BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) {
5143 std::unique_ptr<SyncRes> sr;
5144 initSR(sr, true);
5145
0c43f455 5146 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
2b984251
RG
5147
5148 primeHints();
5149 const DNSName target("www.powerdns.com.");
5150 testkeysset_t keys;
5151
5152 auto luaconfsCopy = g_luaconfs.getCopy();
5153 luaconfsCopy.dsAnchors.clear();
5154 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5155 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5156 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5157
5158 g_luaconfs.setState(luaconfsCopy);
5159
5160 size_t queriesCount = 0;
5161
18d5b679 5162 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, bool* chained) {
2b984251
RG
5163 queriesCount++;
5164
5374b03b
RG
5165 if (type == QType::DS || type == QType::DNSKEY) {
5166 if (type == QType::DS && domain == target) {
5167 setLWResult(res, RCode::NoError, true, false, true);
5168 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5169 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5170 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5171 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5172 return 1;
5173 }
5174 else {
5175 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5176 }
2b984251 5177 }
f24465e5 5178 else {
2b984251
RG
5179 if (isRootServer(ip)) {
5180 setLWResult(res, 0, false, false, true);
5181 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5182 addDS(DNSName("com."), 300, res->d_records, keys);
5183 addRRSIG(keys, res->d_records, DNSName("."), 300);
5184 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5185 return 1;
5186 }
5187 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5188 if (domain == DNSName("com.")) {
5189 setLWResult(res, 0, true, false, true);
5190 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5191 addRRSIG(keys, res->d_records, domain, 300);
5192 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5193 addRRSIG(keys, res->d_records, domain, 300);
5194 }
5195 else {
5196 setLWResult(res, 0, false, false, true);
5197 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5198 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5199 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5200 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5201 }
2b984251
RG
5202 return 1;
5203 }
5204 else if (ip == ComboAddress("192.0.2.2:53")) {
5205 setLWResult(res, 0, true, false, true);
f24465e5
RG
5206 if (type == QType::NS) {
5207 if (domain == DNSName("powerdns.com.")) {
5208 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5209 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5210 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5211 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5212 }
5213 else {
5214 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5215 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5216 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5217 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5218 }
5219 }
5220 else {
5221 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5222 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
9b061cf5 5223 /* we need to add the proof that this name does not exist, so the wildcard may apply */
f24465e5
RG
5224 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5225 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5226 }
2b984251
RG
5227 return 1;
5228 }
5229 }
5230
5231 return 0;
5232 });
5233
5234 vector<DNSRecord> ret;
5235 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5236 BOOST_CHECK_EQUAL(res, RCode::NoError);
5237 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5238 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5239 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5240
5241 /* again, to test the cache */
5242 ret.clear();
5243 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5244 BOOST_CHECK_EQUAL(res, RCode::NoError);
5245 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5246 BOOST_REQUIRE_EQUAL(ret.size(), 4);
f24465e5 5247 BOOST_CHECK_EQUAL(queriesCount, 9);
2b984251
RG
5248}
5249
9b061cf5
RG
5250BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_nodata_nowildcard) {
5251 std::unique_ptr<SyncRes> sr;
5252 initSR(sr, true);
5253
5254 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5255
5256 primeHints();
5257 const DNSName target("www.com.");
5258 testkeysset_t keys;
5259
5260 auto luaconfsCopy = g_luaconfs.getCopy();
5261 luaconfsCopy.dsAnchors.clear();
5262 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5263 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5264
5265 g_luaconfs.setState(luaconfsCopy);
5266
5267 size_t queriesCount = 0;
5268
18d5b679 5269 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, bool* chained) {
9b061cf5
RG
5270 queriesCount++;
5271
5272 if (type == QType::DS || type == QType::DNSKEY) {
5273 if (type == QType::DS && domain == target) {
5274 DNSName auth("com.");
5275 setLWResult(res, 0, true, false, true);
5276
5277 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5278 addRRSIG(keys, res->d_records, auth, 300);
5279 /* add a NSEC denying the DS AND the existence of a cut (no NS) */
5280 addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NSEC }, 600, res->d_records);
5281 addRRSIG(keys, res->d_records, auth, 300);
5282 return 1;
5283 }
5284 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5285 }
5286 else {
5287 if (isRootServer(ip)) {
5288 setLWResult(res, 0, false, false, true);
5289 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5290 addDS(DNSName("com."), 300, res->d_records, keys);
5291 addRRSIG(keys, res->d_records, DNSName("."), 300);
5292 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5293 return 1;
5294 }
5295 else if (ip == ComboAddress("192.0.2.1:53")) {
5296 setLWResult(res, 0, true, false, true);
5297 /* no data */
5298 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5299 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5300 /* no record for this name */
5301 addNSECRecordToLW(DNSName("wwv.com."), DNSName("wwx.com."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
5302 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5303 /* a wildcard matches but has no record for this type */
5304 addNSECRecordToLW(DNSName("*.com."), DNSName("com."), { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5305 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5306 return 1;
5307 }
5308 }
5309
5310 return 0;
5311 });
5312
5313 vector<DNSRecord> ret;
5314 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5315 BOOST_CHECK_EQUAL(res, RCode::NoError);
5316 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5317 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5318 BOOST_CHECK_EQUAL(queriesCount, 6);
5319
5320 /* again, to test the cache */
5321 ret.clear();
5322 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5323 BOOST_CHECK_EQUAL(res, RCode::NoError);
5324 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5325 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5326 BOOST_CHECK_EQUAL(queriesCount, 6);
5327}
5328
5329BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard) {
5330 std::unique_ptr<SyncRes> sr;
5331 initSR(sr, true);
5332
5333 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5334
5335 primeHints();
5336 const DNSName target("www.com.");
5337 testkeysset_t keys;
5338
5339 auto luaconfsCopy = g_luaconfs.getCopy();
5340 luaconfsCopy.dsAnchors.clear();
5341 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5342 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5343
5344 g_luaconfs.setState(luaconfsCopy);
5345
5346 size_t queriesCount = 0;
5347
18d5b679 5348 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, bool* chained) {
9b061cf5
RG
5349 queriesCount++;
5350
5351 if (type == QType::DS || type == QType::DNSKEY) {
5352 if (type == QType::DS && domain == target) {
5353 DNSName auth("com.");
5354 setLWResult(res, 0, true, false, true);
5355
5356 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5357 addRRSIG(keys, res->d_records, auth, 300);
5358 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5359 /* first the closest encloser */
5360 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5361 addRRSIG(keys, res->d_records, auth, 300);
5362 /* then the next closer */
5363 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5364 addRRSIG(keys, res->d_records, auth, 300);
5365 /* a wildcard matches but has no record for this type */
5366 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5367 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5368 return 1;
5369 }
5370 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5371 }
5372 else {
5373 if (isRootServer(ip)) {
5374 setLWResult(res, 0, false, false, true);
5375 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5376 addDS(DNSName("com."), 300, res->d_records, keys);
5377 addRRSIG(keys, res->d_records, DNSName("."), 300);
5378 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5379 return 1;
5380 }
5381 else if (ip == ComboAddress("192.0.2.1:53")) {
5382 setLWResult(res, 0, true, false, true);
5383 /* no data */
5384 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5385 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5386 /* no record for this name */
5387 /* first the closest encloser */
5388 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5389 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5390 /* then the next closer */
5391 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records);
5392 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5393 /* a wildcard matches but has no record for this type */
5394 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5395 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5396 return 1;
5397 }
5398 }
5399
5400 return 0;
5401 });
5402
5403 vector<DNSRecord> ret;
5404 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5405 BOOST_CHECK_EQUAL(res, RCode::NoError);
5406 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5407 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5408 BOOST_CHECK_EQUAL(queriesCount, 6);
5409
5410 /* again, to test the cache */
5411 ret.clear();
5412 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5413 BOOST_CHECK_EQUAL(res, RCode::NoError);
5414 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5415 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5416 BOOST_CHECK_EQUAL(queriesCount, 6);
5417}
5418
b7c40613
RG
5419BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_nodata_nowildcard_too_many_iterations) {
5420 std::unique_ptr<SyncRes> sr;
5421 initSR(sr, true);
5422
5423 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5424
5425 primeHints();
5426 const DNSName target("www.com.");
5427 testkeysset_t keys;
5428
5429 auto luaconfsCopy = g_luaconfs.getCopy();
5430 luaconfsCopy.dsAnchors.clear();
5431 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5432 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5433
5434 g_luaconfs.setState(luaconfsCopy);
5435
5436 size_t queriesCount = 0;
5437
18d5b679 5438 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, bool* chained) {
b7c40613
RG
5439 queriesCount++;
5440
5441 if (type == QType::DS || type == QType::DNSKEY) {
5442 if (type == QType::DS && domain == target) {
5443 DNSName auth("com.");
5444 setLWResult(res, 0, true, false, true);
5445
5446 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5447 addRRSIG(keys, res->d_records, auth, 300);
5448 /* add a NSEC3 denying the DS AND the existence of a cut (no NS) */
5449 /* first the closest encloser */
5450 addNSEC3UnhashedRecordToLW(DNSName("com."), auth, "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5451 addRRSIG(keys, res->d_records, auth, 300);
5452 /* then the next closer */
5453 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5454 addRRSIG(keys, res->d_records, auth, 300);
5455 /* a wildcard matches but has no record for this type */
5456 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5457 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5458 return 1;
5459 }
5460 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5461 }
5462 else {
5463 if (isRootServer(ip)) {
5464 setLWResult(res, 0, false, false, true);
5465 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5466 addDS(DNSName("com."), 300, res->d_records, keys);
5467 addRRSIG(keys, res->d_records, DNSName("."), 300);
5468 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5469 return 1;
5470 }
5471 else if (ip == ComboAddress("192.0.2.1:53")) {
5472 setLWResult(res, 0, true, false, true);
5473 /* no data */
5474 addRecordToLW(res, DNSName("com."), QType::SOA, "com. com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5475 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5476 /* no record for this name */
5477 /* first the closest encloser */
5478 addNSEC3UnhashedRecordToLW(DNSName("com."), DNSName("com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5479 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5480 /* then the next closer */
5481 addNSEC3NarrowRecordToLW(domain, DNSName("com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5482 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5483 /* a wildcard matches but has no record for this type */
5484 addNSEC3UnhashedRecordToLW(DNSName("*.com."), DNSName("com."), "whatever", { QType::AAAA, QType::NSEC, QType::RRSIG }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5485 addRRSIG(keys, res->d_records, DNSName("com"), 300, false, boost::none, DNSName("*.com"));
5486 return 1;
5487 }
5488 }
5489
5490 return 0;
5491 });
5492
5493 /* we are generating NSEC3 with more iterations than we allow, so we should go Insecure */
5494 vector<DNSRecord> ret;
5495 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5496 BOOST_CHECK_EQUAL(res, RCode::NoError);
5497 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5498 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5499 BOOST_CHECK_EQUAL(queriesCount, 6);
5500
5501 /* again, to test the cache */
5502 ret.clear();
5503 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5504 BOOST_CHECK_EQUAL(res, RCode::NoError);
5505 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5506 BOOST_REQUIRE_EQUAL(ret.size(), 8);
5507 BOOST_CHECK_EQUAL(queriesCount, 6);
5508}
5509
9b061cf5
RG
5510BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard) {
5511 std::unique_ptr<SyncRes> sr;
5512 initSR(sr, true);
5513
5514 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5515
5516 primeHints();
6bc9ccbb 5517 const DNSName target("www.sub.powerdns.com.");
9b061cf5
RG
5518 testkeysset_t keys;
5519
5520 auto luaconfsCopy = g_luaconfs.getCopy();
5521 luaconfsCopy.dsAnchors.clear();
5522 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5523 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5524 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5525
5526 g_luaconfs.setState(luaconfsCopy);
5527
5528 size_t queriesCount = 0;
5529
18d5b679 5530 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, bool* chained) {
9b061cf5
RG
5531 queriesCount++;
5532
5533 if (type == QType::DS || type == QType::DNSKEY) {
6bc9ccbb 5534 if (type == QType::DS && domain.isPartOf(DNSName("sub.powerdns.com"))) {
9b061cf5
RG
5535 setLWResult(res, RCode::NoError, true, false, true);
5536 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5537 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6bc9ccbb
RG
5538 if (domain == DNSName("sub.powerdns.com")) {
5539 addNSECRecordToLW(DNSName("sub.powerdns.com."), DNSName("sud.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5540 }
5541 else if (domain == target) {
5542 addNSECRecordToLW(DNSName("www.sub.powerdns.com."), DNSName("wwz.sub.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5543 }
9b061cf5
RG
5544 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5545 return 1;
5546 }
5547 else {
5548 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5549 }
5550 }
5551 else {
5552 if (isRootServer(ip)) {
5553 setLWResult(res, 0, false, false, true);
5554 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5555 addDS(DNSName("com."), 300, res->d_records, keys);
5556 addRRSIG(keys, res->d_records, DNSName("."), 300);
5557 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5558 return 1;
5559 }
5560 else if (ip == ComboAddress("192.0.2.1:53")) {
5561 if (domain == DNSName("com.")) {
5562 setLWResult(res, 0, true, false, true);
5563 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5564 addRRSIG(keys, res->d_records, domain, 300);
5565 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5566 addRRSIG(keys, res->d_records, domain, 300);
5567 }
5568 else {
5569 setLWResult(res, 0, false, false, true);
5570 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5571 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5572 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5573 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5574 }
5575 return 1;
5576 }
5577 else if (ip == ComboAddress("192.0.2.2:53")) {
5578 setLWResult(res, 0, true, false, true);
5579 if (type == QType::NS) {
5580 if (domain == DNSName("powerdns.com.")) {
5581 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5582 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5583 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5584 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5585 }
5586 else {
5587 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5588 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5589 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5590 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5591 }
5592 }
5593 else {
5594 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5595 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5596 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5597 /* first the closest encloser */
5598 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5599 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5600 /* then the next closer */
6bc9ccbb 5601 addNSEC3NarrowRecordToLW(DNSName("sub.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
9b061cf5
RG
5602 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5603 }
5604 return 1;
5605 }
5606 }
5607
5608 return 0;
5609 });
5610
5611 vector<DNSRecord> ret;
5612 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5613 BOOST_CHECK_EQUAL(res, RCode::NoError);
5614 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5615 BOOST_REQUIRE_EQUAL(ret.size(), 6);
6bc9ccbb 5616 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
5617
5618 /* again, to test the cache */
5619 ret.clear();
5620 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5621 BOOST_CHECK_EQUAL(res, RCode::NoError);
5622 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
5623 BOOST_REQUIRE_EQUAL(ret.size(), 6);
6bc9ccbb 5624 BOOST_CHECK_EQUAL(queriesCount, 10);
9b061cf5
RG
5625}
5626
b7c40613
RG
5627BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec3_wildcard_too_many_iterations) {
5628 std::unique_ptr<SyncRes> sr;
5629 initSR(sr, true);
5630
5631 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5632
5633 primeHints();
5634 const DNSName target("www.powerdns.com.");
5635 testkeysset_t keys;
5636
5637 auto luaconfsCopy = g_luaconfs.getCopy();
5638 luaconfsCopy.dsAnchors.clear();
5639 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5640 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5641 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5642
5643 g_luaconfs.setState(luaconfsCopy);
5644
5645 size_t queriesCount = 0;
5646
18d5b679 5647 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, bool* chained) {
b7c40613
RG
5648 queriesCount++;
5649
5650 if (type == QType::DS || type == QType::DNSKEY) {
5651 if (type == QType::DS && domain == target) {
5652 setLWResult(res, RCode::NoError, true, false, true);
5653 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5654 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5655 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5656 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5657 return 1;
5658 }
5659 else {
5660 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5661 }
5662 }
5663 else {
5664 if (isRootServer(ip)) {
5665 setLWResult(res, 0, false, false, true);
5666 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5667 addDS(DNSName("com."), 300, res->d_records, keys);
5668 addRRSIG(keys, res->d_records, DNSName("."), 300);
5669 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5670 return 1;
5671 }
5672 else if (ip == ComboAddress("192.0.2.1:53")) {
5673 if (domain == DNSName("com.")) {
5674 setLWResult(res, 0, true, false, true);
5675 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5676 addRRSIG(keys, res->d_records, domain, 300);
5677 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5678 addRRSIG(keys, res->d_records, domain, 300);
5679 }
5680 else {
5681 setLWResult(res, 0, false, false, true);
5682 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5683 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5684 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5685 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5686 }
5687 return 1;
5688 }
5689 else if (ip == ComboAddress("192.0.2.2:53")) {
5690 setLWResult(res, 0, true, false, true);
5691 if (type == QType::NS) {
5692 if (domain == DNSName("powerdns.com.")) {
5693 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5694 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5695 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5696 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5697 }
5698 else {
5699 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5700 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5701 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5702 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5703 }
5704 }
5705 else {
5706 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5707 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5708 /* we need to add the proof that this name does not exist, so the wildcard may apply */
5709 /* first the closest encloser */
5710 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records);
5711 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5712 /* then the next closer */
5713 addNSEC3NarrowRecordToLW(DNSName("www.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, res->d_records, g_maxNSEC3Iterations + 100);
5714 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5715 }
5716 return 1;
5717 }
5718 }
5719
5720 return 0;
5721 });
5722
5723 /* the NSEC3 providing the denial of existence proof for the next closer has too many iterations,
5724 we should end up Insecure */
5725 vector<DNSRecord> ret;
5726 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5727 BOOST_CHECK_EQUAL(res, RCode::NoError);
5728 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5729 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5730 BOOST_CHECK_EQUAL(queriesCount, 9);
5731
5732 /* again, to test the cache */
5733 ret.clear();
5734 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5735 BOOST_CHECK_EQUAL(res, RCode::NoError);
5736 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
5737 BOOST_REQUIRE_EQUAL(ret.size(), 6);
5738 BOOST_CHECK_EQUAL(queriesCount, 9);
5739}
5740
9b061cf5
RG
5741BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard_missing) {
5742 std::unique_ptr<SyncRes> sr;
5743 initSR(sr, true);
5744
5745 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
5746
5747 primeHints();
5748 const DNSName target("www.powerdns.com.");
5749 testkeysset_t keys;
5750
5751 auto luaconfsCopy = g_luaconfs.getCopy();
5752 luaconfsCopy.dsAnchors.clear();
5753 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5754 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5755 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5756
5757 g_luaconfs.setState(luaconfsCopy);
5758
5759 size_t queriesCount = 0;
5760
18d5b679 5761 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, bool* chained) {
9b061cf5
RG
5762 queriesCount++;
5763
5764 if (type == QType::DS || type == QType::DNSKEY) {
5765 if (type == QType::DS && domain == target) {
5766 setLWResult(res, RCode::NoError, true, false, true);
5767 addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5768 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
5769 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5770 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5771 return 1;
5772 }
5773 else {
5774 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
5775 }
5776 }
5777 else {
5778 if (isRootServer(ip)) {
5779 setLWResult(res, 0, false, false, true);
5780 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5781 addDS(DNSName("com."), 300, res->d_records, keys);
5782 addRRSIG(keys, res->d_records, DNSName("."), 300);
5783 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5784 return 1;
5785 }
5786 else if (ip == ComboAddress("192.0.2.1:53")) {
5787 if (domain == DNSName("com.")) {
5788 setLWResult(res, 0, true, false, true);
5789 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5790 addRRSIG(keys, res->d_records, domain, 300);
5791 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5792 addRRSIG(keys, res->d_records, domain, 300);
5793 }
5794 else {
5795 setLWResult(res, 0, false, false, true);
5796 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5797 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
5798 addRRSIG(keys, res->d_records, DNSName("com."), 300);
5799 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5800 }
5801 return 1;
5802 }
5803 else if (ip == ComboAddress("192.0.2.2:53")) {
5804 setLWResult(res, 0, true, false, true);
5805 if (type == QType::NS) {
5806 if (domain == DNSName("powerdns.com.")) {
5807 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5808 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5809 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5810 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5811 }
5812 else {
5813 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5814 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5815 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5816 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5817 }
5818 }
5819 else {
5820 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5821 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300, false, boost::none, DNSName("*.powerdns.com"));
5822 }
5823 return 1;
5824 }
5825 }
5826
5827 return 0;
5828 });
5829
5830 vector<DNSRecord> ret;
5831 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5832 BOOST_CHECK_EQUAL(res, RCode::NoError);
5833 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5834 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5835 BOOST_CHECK_EQUAL(queriesCount, 9);
5836
5837 /* again, to test the cache */
5838 ret.clear();
5839 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5840 BOOST_CHECK_EQUAL(res, RCode::NoError);
5841 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
5842 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5843 BOOST_CHECK_EQUAL(queriesCount, 9);
5844}
5845
a53e8fe3
RG
5846BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) {
5847 std::unique_ptr<SyncRes> sr;
5848 initSR(sr, true);
5849
0c43f455 5850 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
5851
5852 primeHints();
5853 const DNSName target("www.powerdns.com.");
5854 testkeysset_t keys;
5855
5856 auto luaconfsCopy = g_luaconfs.getCopy();
5857 luaconfsCopy.dsAnchors.clear();
5858 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5859 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5860 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5861
5862 g_luaconfs.setState(luaconfsCopy);
5863
5864 size_t queriesCount = 0;
5865 size_t dsQueriesCount = 0;
5866
18d5b679 5867 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, bool* chained) {
a53e8fe3
RG
5868 queriesCount++;
5869
5870 if (type == QType::DS) {
5871 DNSName auth(domain);
5872 auth.chopOff();
5873 dsQueriesCount++;
5874
5875 setLWResult(res, 0, true, false, true);
5876 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5877 addRRSIG(keys, res->d_records, auth, 300);
5878 return 1;
5879 }
5880 else if (type == QType::DNSKEY) {
5881 setLWResult(res, 0, true, false, true);
5882 addDNSKEY(keys, domain, 300, res->d_records);
5883 addRRSIG(keys, res->d_records, domain, 300);
5884 return 1;
5885 }
f24465e5 5886 else {
a53e8fe3
RG
5887 if (isRootServer(ip)) {
5888 setLWResult(res, 0, false, false, true);
5889 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
5890 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5891 /* No DS on referral, and no denial of the DS either */
5892 return 1;
5893 }
5894 else if (ip == ComboAddress("192.0.2.1:53")) {
f24465e5
RG
5895 if (domain == DNSName("com.")) {
5896 setLWResult(res, 0, true, false, true);
5897 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
5898 addRRSIG(keys, res->d_records, domain, 300);
5899 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
5900 addRRSIG(keys, res->d_records, domain, 300);
5901 }
5902 else {
5903 setLWResult(res, 0, false, false, true);
5904 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
5905 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5906 /* No DS on referral, and no denial of the DS either */
5907 }
a53e8fe3
RG
5908 return 1;
5909 }
5910 else if (ip == ComboAddress("192.0.2.2:53")) {
5911 setLWResult(res, 0, true, false, true);
f24465e5
RG
5912 if (type == QType::NS) {
5913 if (domain == DNSName("powerdns.com.")) {
5914 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
5915 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5916 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
5917 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5918 }
5919 else {
5920 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
5921 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5922 addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records);
5923 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5924 }
5925 }
5926 else {
5927 addRecordToLW(res, domain, QType::A, "192.0.2.42");
5928 addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300);
5929 }
5930
a53e8fe3
RG
5931 return 1;
5932 }
5933 }
5934
5935 return 0;
5936 });
5937
5938 vector<DNSRecord> ret;
5939 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5940 BOOST_CHECK_EQUAL(res, RCode::NoError);
5941 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 5942 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
5943 BOOST_CHECK_EQUAL(queriesCount, 9);
5944 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
5945
5946 /* again, to test the cache */
5947 ret.clear();
5948 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
5949 BOOST_CHECK_EQUAL(res, RCode::NoError);
5950 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
f24465e5 5951 BOOST_REQUIRE_EQUAL(ret.size(), 2);
5374b03b
RG
5952 BOOST_CHECK_EQUAL(queriesCount, 9);
5953 BOOST_CHECK_EQUAL(dsQueriesCount, 3);
a53e8fe3
RG
5954}
5955
f715542c
RG
5956BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) {
5957 std::unique_ptr<SyncRes> sr;
5958 initSR(sr, true);
5959
5d7b19c5 5960 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
f715542c
RG
5961
5962 primeHints();
5963 const DNSName target("www.powerdns.com.");
5964 testkeysset_t keys;
5965
5966 auto luaconfsCopy = g_luaconfs.getCopy();
5967 luaconfsCopy.dsAnchors.clear();
5968 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5969 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
3cef03e9 5970 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
f715542c
RG
5971 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
5972
5973 g_luaconfs.setState(luaconfsCopy);
5974
5975 size_t queriesCount = 0;
5976
18d5b679 5977 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, bool* chained) {
f715542c
RG
5978 queriesCount++;
5979
5980 if (type == QType::DS) {
5981 DNSName auth(domain);
5982 auth.chopOff();
5983
5984 setLWResult(res, 0, true, false, true);
5985 if (domain == target) {
5986 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
5987 addRRSIG(keys, res->d_records, target, 300);
5988 }
5989 else {
5990 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
5991 addRRSIG(keys, res->d_records, auth, 300);
5992 }
5993 return 1;
5994 }
5995 else if (type == QType::DNSKEY) {
5996 setLWResult(res, 0, true, false, true);
5997 addDNSKEY(keys, domain, 300, res->d_records);
5998 addRRSIG(keys, res->d_records, domain, 300);
5999 return 1;
6000 }
6001 else {
6002 if (isRootServer(ip)) {
6003 setLWResult(res, 0, false, false, true);
6004 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6005 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6006 addDS(DNSName("com."), 300, res->d_records, keys);
6007 addRRSIG(keys, res->d_records, DNSName("."), 300);
6008 return 1;
6009 }
6010 else if (ip == ComboAddress("192.0.2.1:53")) {
6011 if (domain == DNSName("com.")) {
6012 setLWResult(res, 0, true, false, true);
6013 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6014 addRRSIG(keys, res->d_records, domain, 300);
6015 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6016 addRRSIG(keys, res->d_records, domain, 300);
6017 }
6018 else {
6019 setLWResult(res, 0, false, false, true);
6020 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6021 /* no DS */
6022 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6023 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6024 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6025 }
6026 return 1;
6027 }
6028 else if (ip == ComboAddress("192.0.2.2:53")) {
6029 if (type == QType::NS) {
6030 if (domain == DNSName("powerdns.com.")) {
6031 setLWResult(res, RCode::Refused, false, false, true);
6032 }
6033 else {
6034 setLWResult(res, 0, true, false, true);
6035 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6036 addRRSIG(keys, res->d_records, domain, 300);
6037 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6038 addRRSIG(keys, res->d_records, domain, 300);
6039 }
6040 }
6041 else {
6042 setLWResult(res, 0, true, false, true);
6043 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6044 addRRSIG(keys, res->d_records, DNSName("www.powerdns.com"), 300);
6045 }
6046
6047 return 1;
6048 }
6049 }
6050
6051 return 0;
6052 });
6053
6054 vector<DNSRecord> ret;
6055 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6056 BOOST_CHECK_EQUAL(res, RCode::NoError);
6057 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6058 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6059 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6060
6061 /* again, to test the cache */
6062 ret.clear();
6063 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6064 BOOST_CHECK_EQUAL(res, RCode::NoError);
6065 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6066 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6067 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6068}
6069
8d2e7fa1
RG
6070BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) {
6071 /* check that we don't accept a signer below us */
6072 std::unique_ptr<SyncRes> sr;
6073 initSR(sr, true);
6074
6075 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6076
6077 primeHints();
6078 const DNSName target("www.powerdns.com.");
6079 testkeysset_t keys;
6080
6081 auto luaconfsCopy = g_luaconfs.getCopy();
6082 luaconfsCopy.dsAnchors.clear();
6083 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6084 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6085 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6086 generateKeyMaterial(DNSName("www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6087 generateKeyMaterial(DNSName("sub.www.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6088
6089 g_luaconfs.setState(luaconfsCopy);
6090
6091 size_t queriesCount = 0;
6092
18d5b679 6093 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, bool* chained) {
8d2e7fa1
RG
6094 queriesCount++;
6095
6096 if (type == QType::DS) {
6097 DNSName auth(domain);
6098 auth.chopOff();
6099
6100 setLWResult(res, 0, true, false, true);
6101 if (domain == target) {
6102 addRecordToLW(res, domain, QType::SOA, "ns1.powerdns.com. blah. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
6103 addRRSIG(keys, res->d_records, target, 300);
6104 }
6105 else {
6106 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6107 addRRSIG(keys, res->d_records, auth, 300);
6108 }
6109 return 1;
6110 }
6111 else if (type == QType::DNSKEY) {
6112 setLWResult(res, 0, true, false, true);
6113 addDNSKEY(keys, domain, 300, res->d_records);
6114 if (domain == DNSName("www.powerdns.com.")) {
6115 addRRSIG(keys, res->d_records, DNSName("sub.www.powerdns.com."), 300);
6116 }
6117 else {
6118 addRRSIG(keys, res->d_records, domain, 300);
6119 }
6120 return 1;
6121 }
6122 else {
6123 if (isRootServer(ip)) {
6124 setLWResult(res, 0, false, false, true);
6125 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6126 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6127 addDS(DNSName("com."), 300, res->d_records, keys);
6128 addRRSIG(keys, res->d_records, DNSName("."), 300);
6129 return 1;
6130 }
6131 else if (ip == ComboAddress("192.0.2.1:53")) {
6132 if (domain == DNSName("com.")) {
6133 setLWResult(res, 0, true, false, true);
6134 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
6135 addRRSIG(keys, res->d_records, domain, 300);
6136 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6137 addRRSIG(keys, res->d_records, domain, 300);
6138 }
6139 else {
6140 setLWResult(res, 0, false, false, true);
6141 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6142 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6143 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6144 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6145 }
6146 return 1;
6147 }
6148 else if (ip == ComboAddress("192.0.2.2:53")) {
6149 if (type == QType::NS) {
6150 setLWResult(res, 0, true, false, true);
6151 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6152 addRRSIG(keys, res->d_records, domain, 300);
6153 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6154 addRRSIG(keys, res->d_records, domain, 300);
6155 }
6156 else {
6157 setLWResult(res, 0, true, false, true);
6158 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6159 addRRSIG(keys, res->d_records, domain, 300);
6160 }
6161
6162 return 1;
6163 }
6164 }
6165
f715542c
RG
6166 return 0;
6167 });
6168
6169 vector<DNSRecord> ret;
6170 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6171 BOOST_CHECK_EQUAL(res, RCode::NoError);
6172 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6173 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6174 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6175
6176 /* again, to test the cache */
6177 ret.clear();
6178 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6179 BOOST_CHECK_EQUAL(res, RCode::NoError);
6180 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6181 BOOST_REQUIRE_EQUAL(ret.size(), 2);
3cef03e9 6182 BOOST_CHECK_EQUAL(queriesCount, 9);
f715542c
RG
6183}
6184
a53e8fe3
RG
6185BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) {
6186 std::unique_ptr<SyncRes> sr;
f24465e5 6187 initSR(sr, true);
a53e8fe3 6188
0c43f455 6189 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
a53e8fe3
RG
6190
6191 primeHints();
6192 const DNSName target("www.powerdns.com.");
6193 testkeysset_t keys;
6194
6195 auto luaconfsCopy = g_luaconfs.getCopy();
6196 luaconfsCopy.dsAnchors.clear();
6197 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6198 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6199
6200 g_luaconfs.setState(luaconfsCopy);
6201
6202 size_t queriesCount = 0;
6203 size_t dsQueriesCount = 0;
6204
18d5b679 6205 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, bool* chained) {
a53e8fe3
RG
6206 queriesCount++;
6207
6208 if (type == QType::DS) {
6209 DNSName auth(domain);
6210 auth.chopOff();
6211 dsQueriesCount++;
6212
6213 setLWResult(res, 0, true, false, true);
6214 if (domain == DNSName("com.")) {
6215 addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER);
6216 }
6217 else {
f24465e5
RG
6218 addRecordToLW(res, "com.", QType::SOA, "a.gtld-servers.com. hostmastercom. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6219 addRRSIG(keys, res->d_records, DNSName("com."), 300);
a53e8fe3
RG
6220 addNSECRecordToLW(domain, DNSName("powerdnt.com."), { QType::NS }, 600, res->d_records);
6221 }
6222 addRRSIG(keys, res->d_records, auth, 300);
6223 return 1;
6224 }
6225 else if (type == QType::DNSKEY) {
6226 setLWResult(res, 0, true, false, true);
6227 addDNSKEY(keys, domain, 300, res->d_records);
6228 addRRSIG(keys, res->d_records, domain, 300);
6229 return 1;
6230 }
a69867f2 6231 else {
a53e8fe3
RG
6232 if (isRootServer(ip)) {
6233 setLWResult(res, 0, false, false, true);
6234 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6235 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6236 /* No DS on referral, and no denial of the DS either */
6237 return 1;
6238 }
6239 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6240 if (domain == DNSName("com.")) {
6241 setLWResult(res, 0, true, false, true);
6242 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
f24465e5 6243 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 6244 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
f24465e5 6245 addRRSIG(keys, res->d_records, domain, 300);
a69867f2
RG
6246 }
6247 else {
6248 setLWResult(res, 0, false, false, true);
6249 addRecordToLW(res, "powerdns.com.", QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6250 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6251 /* No DS on referral, and no denial of the DS either */
6252 }
a53e8fe3
RG
6253 return 1;
6254 }
6255 else if (ip == ComboAddress("192.0.2.2:53")) {
6256 setLWResult(res, 0, true, false, true);
f24465e5
RG
6257 if (type == QType::NS) {
6258 if (domain == DNSName("powerdns.com.")) {
6259 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6260 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6261 }
6262 else {
6263 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6264 }
6265 }
6266 else {
6267 addRecordToLW(res, domain, QType::A, "192.0.2.42");
6268 }
a53e8fe3
RG
6269 return 1;
6270 }
6271 }
6272
6273 return 0;
6274 });
6275
6276 vector<DNSRecord> ret;
6277 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6278 BOOST_CHECK_EQUAL(res, RCode::NoError);
6279 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6280 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6281 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6282 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6283
6284 /* again, to test the cache */
6285 ret.clear();
6286 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6287 BOOST_CHECK_EQUAL(res, RCode::NoError);
6288 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6289 BOOST_REQUIRE_EQUAL(ret.size(), 1);
5374b03b 6290 BOOST_CHECK_EQUAL(queriesCount, 7);
a53e8fe3
RG
6291 BOOST_CHECK_EQUAL(dsQueriesCount, 2);
6292}
6293
e59c8907 6294BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) {
b7f378d1 6295 std::unique_ptr<SyncRes> sr;
895449a5 6296 initSR(sr, true);
b7f378d1 6297
0c43f455 6298 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6299
6300 primeHints();
6301 const DNSName target("powerdns.com.");
6302 testkeysset_t keys;
6303
6304 auto luaconfsCopy = g_luaconfs.getCopy();
6305 luaconfsCopy.dsAnchors.clear();
6306 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6307 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6308 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6309
6310 g_luaconfs.setState(luaconfsCopy);
6311
6312 size_t queriesCount = 0;
6313
18d5b679 6314 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, bool* chained) {
b7f378d1
RG
6315 queriesCount++;
6316
5374b03b
RG
6317 if (type == QType::DS || type == QType::DNSKEY) {
6318 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6319 }
a69867f2 6320 else {
b7f378d1
RG
6321 if (isRootServer(ip)) {
6322 setLWResult(res, 0, false, false, true);
6323 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6324 addDS(DNSName("com."), 300, res->d_records, keys);
6325 addRRSIG(keys, res->d_records, DNSName("."), 300);
6326 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6327 return 1;
6328 }
6329 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6330 if (domain == DNSName("com.")) {
6331 setLWResult(res, 0, true, false, true);
6332 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6333 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6334 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6335 }
6336 else {
6337 setLWResult(res, 0, false, false, true);
6338 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6339 addDS(domain, 300, res->d_records, keys);
6340 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6341 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6342 }
b7f378d1
RG
6343 return 1;
6344 }
6345 else if (ip == ComboAddress("192.0.2.2:53")) {
6346 setLWResult(res, 0, true, false, true);
a69867f2
RG
6347 if (type == QType::NS) {
6348 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6349 addRRSIG(keys, res->d_records, domain, 300);
6350 }
6351 else {
6352 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6353 addRRSIG(keys, res->d_records, domain, 300);
6354 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS, QType::DNSKEY }, 600, res->d_records);
6355 /* NO RRSIG for the NSEC record! */
6356 }
b7f378d1
RG
6357 return 1;
6358 }
6359 }
6360
6361 return 0;
6362 });
6363
6364 /* NSEC record without the corresponding RRSIG in a secure zone, should be Bogus! */
6365 vector<DNSRecord> ret;
6366 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6367 BOOST_CHECK_EQUAL(res, RCode::NoError);
6368 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6369 BOOST_CHECK_EQUAL(ret.size(), 3);
a69867f2 6370 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6371
6372 /* again, to test the cache */
6373 ret.clear();
6374 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6375 BOOST_CHECK_EQUAL(res, RCode::NoError);
6376 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6377 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 6378 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6379}
6380
e59c8907 6381BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) {
b7f378d1 6382 std::unique_ptr<SyncRes> sr;
895449a5 6383 initSR(sr, true);
b7f378d1 6384
0c43f455 6385 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6386
6387 primeHints();
6388 const DNSName target("powerdns.com.");
6389 testkeysset_t keys;
6390
6391 auto luaconfsCopy = g_luaconfs.getCopy();
6392 luaconfsCopy.dsAnchors.clear();
6393 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6394 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6395 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6396
6397 g_luaconfs.setState(luaconfsCopy);
6398
6399 size_t queriesCount = 0;
6400
18d5b679 6401 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, bool* chained) {
b7f378d1
RG
6402 queriesCount++;
6403
5374b03b
RG
6404 if (type == QType::DS || type == QType::DNSKEY) {
6405 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1 6406 }
a69867f2 6407 else {
b7f378d1
RG
6408 if (isRootServer(ip)) {
6409 setLWResult(res, 0, false, false, true);
6410 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6411 addDS(DNSName("com."), 300, res->d_records, keys);
6412 addRRSIG(keys, res->d_records, DNSName("."), 300);
6413 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6414 return 1;
6415 }
6416 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6417 if (domain == DNSName("com.")) {
6418 setLWResult(res, 0, true, false, true);
6419 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6420 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6421 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6422 }
6423 else {
6424 setLWResult(res, 0, false, false, true);
6425 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6426 addDS(domain, 300, res->d_records, keys);
6427 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6428 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6429 }
b7f378d1
RG
6430 return 1;
6431 }
6432 else if (ip == ComboAddress("192.0.2.2:53")) {
6433 setLWResult(res, 0, true, false, true);
a69867f2
RG
6434 if (type == QType::NS) {
6435 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6436 addRRSIG(keys, res->d_records, domain, 300);
6437 }
6438 else {
6439 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6440 addRRSIG(keys, res->d_records, domain, 300);
b7f378d1 6441
a69867f2
RG
6442 /* NO NSEC record! */
6443 }
b7f378d1
RG
6444 return 1;
6445 }
6446 }
6447
6448 return 0;
6449 });
6450
6451 /* no NSEC record in a secure zone, should be Bogus! */
6452 vector<DNSRecord> ret;
6453 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6454 BOOST_CHECK_EQUAL(res, RCode::NoError);
6455 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6456 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 6457 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6458
6459 /* again, to test the cache */
6460 ret.clear();
6461 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6462 BOOST_CHECK_EQUAL(res, RCode::NoError);
6463 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
6464 BOOST_REQUIRE_EQUAL(ret.size(), 2);
a69867f2 6465 BOOST_CHECK_EQUAL(queriesCount, 8);
b7f378d1
RG
6466}
6467
6468BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) {
6469 std::unique_ptr<SyncRes> sr;
895449a5 6470 initSR(sr, true);
b7f378d1 6471
0c43f455 6472 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6473
6474 primeHints();
6475 const DNSName target("powerdns.com.");
6476 const ComboAddress targetAddr("192.0.2.42");
6477 testkeysset_t keys;
6478
6479 auto luaconfsCopy = g_luaconfs.getCopy();
6480 luaconfsCopy.dsAnchors.clear();
6481 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6482 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6483
6484 g_luaconfs.setState(luaconfsCopy);
6485
6486 size_t queriesCount = 0;
6487
18d5b679 6488 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, bool* chained) {
b7f378d1
RG
6489 queriesCount++;
6490
6491 if (type == QType::DS) {
a53e8fe3 6492 if (domain == target) {
b7f378d1 6493 setLWResult(res, 0, false, false, true);
895449a5 6494 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6495 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6496 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6497 return 1;
5374b03b
RG
6498 } else {
6499 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
b7f378d1
RG
6500 }
6501 }
6502 else if (type == QType::DNSKEY) {
6503 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6504 setLWResult(res, 0, true, false, true);
6505 addDNSKEY(keys, domain, 300, res->d_records);
6506 addRRSIG(keys, res->d_records, domain, 300);
6507 return 1;
6508 }
6509 else {
6510 setLWResult(res, 0, false, false, true);
895449a5 6511 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6512 return 1;
6513 }
6514 }
a69867f2 6515 else {
b7f378d1
RG
6516 if (isRootServer(ip)) {
6517 setLWResult(res, 0, false, false, true);
6518 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6519 addDS(DNSName("com."), 300, res->d_records, keys);
6520 addRRSIG(keys, res->d_records, DNSName("."), 300);
6521 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6522 return 1;
6523 }
6524 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6525 if (domain == DNSName("com.")) {
6526 setLWResult(res, 0, true, false, true);
6527 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6528 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6529 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6530 }
6531 else {
6532 setLWResult(res, 0, false, false, true);
6533 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6534 /* no DS */
6535 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6536 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6537 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6538 }
b7f378d1
RG
6539 return 1;
6540 }
6541 else if (ip == ComboAddress("192.0.2.2:53")) {
6542 setLWResult(res, 0, true, false, true);
a69867f2
RG
6543 if (type == QType::NS) {
6544 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6545 }
6546 else {
6547 addRecordToLW(res, domain, QType::A, targetAddr.toString());
6548 }
b7f378d1
RG
6549 return 1;
6550 }
6551 }
6552
6553 return 0;
6554 });
6555
6556 vector<DNSRecord> ret;
6557 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6558 BOOST_CHECK_EQUAL(res, RCode::NoError);
6559 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6560 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6561 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2
RG
6562 /* 4 NS: com at ., com at com, powerdns.com at com, powerdns.com at powerdns.com
6563 4 DNSKEY: ., com (not for powerdns.com because DS denial in referral)
6564 1 query for A */
6565 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6566
6567 /* again, to test the cache */
6568 ret.clear();
6569 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6570 BOOST_CHECK_EQUAL(res, RCode::NoError);
6571 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6572 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6573 BOOST_CHECK(ret[0].d_type == QType::A);
a69867f2 6574 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
6575}
6576
3cef03e9
RG
6577
6578BOOST_AUTO_TEST_CASE(test_dnssec_secure_direct_ds) {
6579 /*
6580 Direct DS query:
6581 - parent is secure, zone is secure: DS should be secure
6582 */
6583 std::unique_ptr<SyncRes> sr;
6584 initSR(sr, true);
6585
6586 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6587
6588 primeHints();
6589 const DNSName target("powerdns.com.");
6590 testkeysset_t keys;
6591
6592 auto luaconfsCopy = g_luaconfs.getCopy();
6593 luaconfsCopy.dsAnchors.clear();
6594 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6595 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6596 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6597
6598 g_luaconfs.setState(luaconfsCopy);
6599
6600 size_t queriesCount = 0;
6601
18d5b679 6602 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, bool* chained) {
3cef03e9
RG
6603 queriesCount++;
6604
6605 if (type == QType::DS || type == QType::DNSKEY) {
6606 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6607 }
6608 else {
6609 if (isRootServer(ip)) {
6610 setLWResult(res, 0, false, false, true);
6611 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6612 addDS(DNSName("com."), 300, res->d_records, keys);
6613 addRRSIG(keys, res->d_records, DNSName("."), 300);
6614 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6615 return 1;
6616 }
6617 }
6618
6619 return 0;
6620 });
6621
6622 vector<DNSRecord> ret;
6623 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6624 BOOST_CHECK_EQUAL(res, RCode::NoError);
6625 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6626 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6627 for (const auto& record : ret) {
6628 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6629 }
6630 BOOST_CHECK_EQUAL(queriesCount, 4);
6631
6632 /* again, to test the cache */
6633 ret.clear();
6634 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6635 BOOST_CHECK_EQUAL(res, RCode::NoError);
6636 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6637 BOOST_REQUIRE_EQUAL(ret.size(), 2);
6638 for (const auto& record : ret) {
6639 BOOST_CHECK(record.d_type == QType::DS || record.d_type == QType::RRSIG);
6640 }
6641 BOOST_CHECK_EQUAL(queriesCount, 4);
6642}
6643
6644BOOST_AUTO_TEST_CASE(test_dnssec_insecure_direct_ds) {
6645 /*
6646 Direct DS query:
6647 - parent is secure, zone is insecure: DS denial should be secure
6648 */
6649 std::unique_ptr<SyncRes> sr;
6650 initSR(sr, true);
6651
6652 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
6653
6654 primeHints();
6655 const DNSName target("powerdns.com.");
6656 testkeysset_t keys;
6657
6658 auto luaconfsCopy = g_luaconfs.getCopy();
6659 luaconfsCopy.dsAnchors.clear();
6660 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6661 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6662
6663 g_luaconfs.setState(luaconfsCopy);
6664
6665 size_t queriesCount = 0;
6666
18d5b679 6667 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, bool* chained) {
3cef03e9
RG
6668 queriesCount++;
6669
6670 if (type == QType::DS || type == QType::DNSKEY) {
6671 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6672 }
6673 else {
6674 if (isRootServer(ip)) {
6675 setLWResult(res, 0, false, false, true);
6676 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6677 addDS(DNSName("com."), 300, res->d_records, keys);
6678 addRRSIG(keys, res->d_records, DNSName("."), 300);
6679 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6680 return 1;
6681 }
6682 }
6683
6684 return 0;
6685 });
6686
6687 vector<DNSRecord> ret;
6688 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6689 BOOST_CHECK_EQUAL(res, RCode::NoError);
6690 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6691 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6692 for (const auto& record : ret) {
6693 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6694 }
6695 BOOST_CHECK_EQUAL(queriesCount, 4);
6696
6697 /* again, to test the cache */
6698 ret.clear();
6699 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
6700 BOOST_CHECK_EQUAL(res, RCode::NoError);
6701 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
6702 BOOST_REQUIRE_EQUAL(ret.size(), 4);
6703 for (const auto& record : ret) {
6704 BOOST_CHECK(record.d_type == QType::SOA || record.d_type == QType::NSEC || record.d_type == QType::RRSIG);
6705 }
6706 BOOST_CHECK_EQUAL(queriesCount, 4);
6707}
6708
70b3fe7a
RG
6709BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) {
6710 std::unique_ptr<SyncRes> sr;
a69867f2 6711 initSR(sr, true);
70b3fe7a 6712
0c43f455 6713 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6714
6715 primeHints();
6716 const DNSName target("www.sub.powerdns.com.");
6717 const ComboAddress targetAddr("192.0.2.42");
6718 testkeysset_t keys;
6719
6720 auto luaconfsCopy = g_luaconfs.getCopy();
6721 luaconfsCopy.dsAnchors.clear();
6722 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6723 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6724 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6725
6726 g_luaconfs.setState(luaconfsCopy);
6727
6728 size_t queriesCount = 0;
6729
18d5b679 6730 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, bool* chained) {
70b3fe7a
RG
6731 queriesCount++;
6732
6733 if (type == QType::DS) {
6734 if (domain == DNSName("sub.powerdns.com.")) {
6735 setLWResult(res, 0, false, false, true);
6736 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6737 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6738 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6739 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6740 return 1;
6741 }
6742 else if (domain == DNSName("www.sub.powerdns.com.")) {
6743 setLWResult(res, 0, false, false, true);
6744 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);
6745 return 1;
6746 }
5374b03b
RG
6747 else {
6748 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6749 }
70b3fe7a
RG
6750 }
6751 else if (type == QType::DNSKEY) {
a69867f2 6752 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
70b3fe7a
RG
6753 setLWResult(res, 0, true, false, true);
6754 addDNSKEY(keys, domain, 300, res->d_records);
6755 addRRSIG(keys, res->d_records, domain, 300);
6756 return 1;
6757 }
6758 else {
6759 setLWResult(res, 0, false, false, true);
6760 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6761 return 1;
6762 }
6763 }
88cb0fe0 6764 else {
70b3fe7a
RG
6765 if (isRootServer(ip)) {
6766 setLWResult(res, 0, false, false, true);
6767 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6768 addDS(DNSName("com."), 300, res->d_records, keys);
6769 addRRSIG(keys, res->d_records, DNSName("."), 300);
6770 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6771 return 1;
6772 }
6773 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
6774 if (domain == DNSName("com.")) {
6775 setLWResult(res, 0, true, false, true);
6776 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6777 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6778 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6779 }
6780 else {
6781 setLWResult(res, 0, false, false, true);
6782 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6783 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
6784 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6785 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6786 }
70b3fe7a
RG
6787 return 1;
6788 }
6789 else if (ip == ComboAddress("192.0.2.2:53")) {
6790 setLWResult(res, 0, true, false, true);
a69867f2
RG
6791 if (type == QType::NS) {
6792 if (domain == DNSName("www.sub.powerdns.com.")) {
6793 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);
6794 }
6795 else if (domain == DNSName("sub.powerdns.com.")) {
6796 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
a69867f2
RG
6797 }
6798 else if (domain == DNSName("powerdns.com.")) {
6799 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6800 addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300);
6801 }
6802 } else {
6803 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6804 }
70b3fe7a
RG
6805 return 1;
6806 }
6807 }
6808
6809 return 0;
6810 });
6811
6812 vector<DNSRecord> ret;
6813 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6814 BOOST_CHECK_EQUAL(res, RCode::NoError);
6815 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6816 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6817 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6818 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6819
6820 /* again, to test the cache */
6821 ret.clear();
6822 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6823 BOOST_CHECK_EQUAL(res, RCode::NoError);
6824 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
6825 BOOST_REQUIRE_EQUAL(ret.size(), 1);
6826 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6827 BOOST_CHECK_EQUAL(queriesCount, 9);
70b3fe7a
RG
6828}
6829
6830BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) {
6831 std::unique_ptr<SyncRes> sr;
a69867f2 6832 initSR(sr, true);
70b3fe7a 6833
0c43f455 6834 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
70b3fe7a
RG
6835
6836 primeHints();
6837 const DNSName target("www.sub.powerdns.com.");
6838 const ComboAddress targetAddr("192.0.2.42");
6839 testkeysset_t keys;
6840
6841 auto luaconfsCopy = g_luaconfs.getCopy();
6842 luaconfsCopy.dsAnchors.clear();
6843 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6844 /* No key material for .com */
6845 /* But TA for sub.powerdns.com. */
6846 generateKeyMaterial(DNSName("sub.powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6847 luaconfsCopy.dsAnchors[DNSName("sub.powerdns.com.")].insert(keys[DNSName("sub.powerdns.com.")].second);
6848 g_luaconfs.setState(luaconfsCopy);
6849
6850 size_t queriesCount = 0;
6851
18d5b679 6852 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, bool* chained) {
70b3fe7a
RG
6853 queriesCount++;
6854
6855 if (type == QType::DS) {
88cb0fe0
RG
6856 if (domain == DNSName("www.sub.powerdns.com")) {
6857 setLWResult(res, 0, false, false, true);
6858 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);
6859 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6860 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6861 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6862 }
6863 else {
6864 setLWResult(res, 0, false, false, true);
5374b03b
RG
6865
6866 if (domain == DNSName("com.")) {
6867 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6868 /* no DS */
6869 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6870 addRRSIG(keys, res->d_records, DNSName("."), 300);
6871 }
6872 else {
6873 setLWResult(res, 0, false, false, true);
6874 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
6875 }
88cb0fe0 6876 }
70b3fe7a
RG
6877 return 1;
6878 }
6879 else if (type == QType::DNSKEY) {
6880 if (domain == g_rootdnsname || domain == DNSName("sub.powerdns.com.")) {
6881 setLWResult(res, 0, true, false, true);
6882 addDNSKEY(keys, domain, 300, res->d_records);
6883 addRRSIG(keys, res->d_records, domain, 300);
6884 return 1;
6885 }
6886 }
88cb0fe0 6887 else {
70b3fe7a
RG
6888 if (isRootServer(ip)) {
6889 setLWResult(res, 0, false, false, true);
6890 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
6891 /* no DS */
6892 addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records);
6893 addRRSIG(keys, res->d_records, DNSName("."), 300);
6894 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6895 return 1;
6896 }
6897 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
6898 if (domain == DNSName("com.")) {
6899 setLWResult(res, 0, true, false, true);
6900 addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com.");
6901 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
6902 }
5374b03b 6903 else if (domain.isPartOf(DNSName("powerdns.com."))) {
88cb0fe0
RG
6904 setLWResult(res, 0, false, false, true);
6905 addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
6906 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
6907 }
70b3fe7a
RG
6908 return 1;
6909 }
6910 else if (ip == ComboAddress("192.0.2.2:53")) {
6911 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
6912 if (type == QType::NS) {
6913 if (domain == DNSName("www.sub.powerdns.com.")) {
6914 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);
6915 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6916 addNSECRecordToLW(DNSName("www.sub.powerdns.com"), DNSName("vww.sub.powerdns.com."), { QType::A }, 600, res->d_records);
6917 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com"), 300);
6918 }
6919 else if (domain == DNSName("sub.powerdns.com.")) {
6920 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6921 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6922 }
6923 else if (domain == DNSName("powerdns.com.")) {
6924 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
6925 }
6926 }
6927 else if (domain == DNSName("www.sub.powerdns.com.")) {
6928 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
6929 addRRSIG(keys, res->d_records, DNSName("sub.powerdns.com."), 300);
6930 }
70b3fe7a
RG
6931 return 1;
6932 }
6933 }
6934
6935 return 0;
6936 });
6937
6938 vector<DNSRecord> ret;
6939 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6940 BOOST_CHECK_EQUAL(res, RCode::NoError);
6941 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 6942 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 6943 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6944 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
6945
6946 /* again, to test the cache */
6947 ret.clear();
6948 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
6949 BOOST_CHECK_EQUAL(res, RCode::NoError);
6950 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
88cb0fe0 6951 BOOST_REQUIRE_EQUAL(ret.size(), 2);
70b3fe7a 6952 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 6953 BOOST_CHECK_EQUAL(queriesCount, 7);
70b3fe7a
RG
6954}
6955
b7f378d1
RG
6956BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) {
6957 std::unique_ptr<SyncRes> sr;
895449a5 6958 initSR(sr, true);
b7f378d1 6959
0c43f455 6960 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1
RG
6961
6962 primeHints();
6963 const DNSName target("powerdns.com.");
6964 testkeysset_t keys;
6965
6966 auto luaconfsCopy = g_luaconfs.getCopy();
6967 luaconfsCopy.dsAnchors.clear();
6968 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
6969 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
6970
6971 g_luaconfs.setState(luaconfsCopy);
6972
6973 size_t queriesCount = 0;
6974
18d5b679 6975 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, bool* chained) {
b7f378d1
RG
6976 queriesCount++;
6977
6978 if (type == QType::DS) {
a53e8fe3 6979 if (domain == target) {
b7f378d1 6980 setLWResult(res, 0, false, false, true);
895449a5 6981 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
6982 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
6983 addRRSIG(keys, res->d_records, DNSName("com."), 300);
6984 return 1;
6985 }
5374b03b
RG
6986 else {
6987 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
6988 }
b7f378d1
RG
6989 }
6990 else if (type == QType::DNSKEY) {
6991 if (domain == g_rootdnsname || domain == DNSName("com.")) {
6992 setLWResult(res, 0, true, false, true);
6993 addDNSKEY(keys, domain, 300, res->d_records);
6994 addRRSIG(keys, res->d_records, domain, 300);
6995 return 1;
6996 }
6997 else {
6998 setLWResult(res, 0, false, false, true);
895449a5 6999 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
b7f378d1
RG
7000 return 1;
7001 }
7002 }
a69867f2 7003 else {
b7f378d1
RG
7004 if (isRootServer(ip)) {
7005 setLWResult(res, 0, false, false, true);
7006 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7007 addDS(DNSName("com."), 300, res->d_records, keys);
7008 addRRSIG(keys, res->d_records, DNSName("."), 300);
7009 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7010 return 1;
7011 }
7012 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7013 if (domain == DNSName("com.")) {
7014 setLWResult(res, 0, true, false, true);
7015 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7016 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7017 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7018 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7019 }
7020 else {
7021 setLWResult(res, 0, false, false, true);
7022 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7023 /* no DS */
7024 addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records);
7025 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7026 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7027 }
b7f378d1
RG
7028 return 1;
7029 }
7030 else if (ip == ComboAddress("192.0.2.2:53")) {
a69867f2
RG
7031 if (type == QType::NS) {
7032 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7033 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7034 }
7035 else {
7036 setLWResult(res, 0, true, false, true);
7037 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7038 }
b7f378d1
RG
7039 return 1;
7040 }
7041 }
7042
7043 return 0;
7044 });
7045
7046 vector<DNSRecord> ret;
7047 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7048 BOOST_CHECK_EQUAL(res, RCode::NoError);
7049 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7050 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2
RG
7051 /* 4 NS (com from root, com from com, powerdns.com from com,
7052 powerdns.com from powerdns.com)
7053 2 DNSKEY (. and com., none for powerdns.com because no DS)
7054 1 query for A
7055 */
7056 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7057
7058 /* again, to test the cache */
7059 ret.clear();
7060 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7061 BOOST_CHECK_EQUAL(res, RCode::NoError);
7062 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7063 BOOST_REQUIRE_EQUAL(ret.size(), 1);
a69867f2 7064 BOOST_CHECK_EQUAL(queriesCount, 7);
b7f378d1
RG
7065}
7066
895449a5 7067BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) {
b7f378d1 7068 std::unique_ptr<SyncRes> sr;
860d5e8e 7069 initSR(sr, true);
b7f378d1 7070
0c43f455 7071 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
b7f378d1 7072
895449a5
RG
7073 primeHints();
7074 const DNSName target("powerdns.com.");
7075 const DNSName targetCName("power-dns.com.");
7076 const ComboAddress targetCNameAddr("192.0.2.42");
7077 testkeysset_t keys;
7078
7079 auto luaconfsCopy = g_luaconfs.getCopy();
7080 luaconfsCopy.dsAnchors.clear();
7081 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7082 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7083 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7084 g_luaconfs.setState(luaconfsCopy);
7085
7086 size_t queriesCount = 0;
7087
18d5b679 7088 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, bool* chained) {
895449a5
RG
7089 queriesCount++;
7090
7091 if (type == QType::DS) {
5374b03b 7092 if (domain == targetCName) {
895449a5
RG
7093 setLWResult(res, 0, false, false, true);
7094 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7095 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7096 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7097 return 1;
7098 }
5374b03b
RG
7099 else {
7100 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7101 }
895449a5
RG
7102 }
7103 else if (type == QType::DNSKEY) {
7104 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7105 setLWResult(res, 0, true, false, true);
7106 addDNSKEY(keys, domain, 300, res->d_records);
7107 addRRSIG(keys, res->d_records, domain, 300);
7108 return 1;
7109 }
7110 else {
7111 setLWResult(res, 0, false, false, true);
7112 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7113 return 1;
7114 }
7115 }
7116 else {
7117 if (isRootServer(ip)) {
7118 setLWResult(res, 0, false, false, true);
7119 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7120 addDS(DNSName("com."), 300, res->d_records, keys);
7121 addRRSIG(keys, res->d_records, DNSName("."), 300);
7122 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7123 return 1;
7124 }
7125 else if (ip == ComboAddress("192.0.2.1:53")) {
7126 setLWResult(res, 0, false, false, true);
a69867f2
RG
7127 if (domain == DNSName("com.")) {
7128 setLWResult(res, 0, true, false, true);
7129 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7130 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7131 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7132 addRRSIG(keys, res->d_records, DNSName("com."), 300);
895449a5 7133 }
a69867f2
RG
7134 else {
7135 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7136 if (domain == DNSName("powerdns.com.")) {
7137 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7138 }
7139 else if (domain == targetCName) {
7140 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7141 }
7142 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7143 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
895449a5 7144 }
a69867f2 7145
895449a5
RG
7146 return 1;
7147 }
7148 else if (ip == ComboAddress("192.0.2.2:53")) {
7149 setLWResult(res, 0, true, false, true);
a69867f2
RG
7150
7151 if (type == QType::NS) {
7152 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7153 if (domain == DNSName("powerdns.com.")) {
7154 addRRSIG(keys, res->d_records, domain, 300);
7155 }
7156 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7157 if (domain == DNSName("powerdns.com.")) {
7158 addRRSIG(keys, res->d_records, domain, 300);
7159 }
895449a5 7160 }
a69867f2
RG
7161 else {
7162 if (domain == DNSName("powerdns.com.")) {
7163 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7164 addRRSIG(keys, res->d_records, domain, 300);
7165 }
7166 else if (domain == targetCName) {
7167 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7168 }
895449a5 7169 }
a69867f2 7170
895449a5
RG
7171 return 1;
7172 }
7173 }
7174
7175 return 0;
7176 });
7177
7178 vector<DNSRecord> ret;
7179 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7180 BOOST_CHECK_EQUAL(res, RCode::NoError);
7181 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7182 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7183 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7184
7185 /* again, to test the cache */
7186 ret.clear();
7187 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7188 BOOST_CHECK_EQUAL(res, RCode::NoError);
7189 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7190 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7191 BOOST_CHECK_EQUAL(queriesCount, 11);
895449a5
RG
7192}
7193
8783a0ac
RG
7194BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname_glue) {
7195 std::unique_ptr<SyncRes> sr;
cd48a0ff 7196 initSR(sr, true);
8783a0ac
RG
7197
7198 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
7199
7200 primeHints();
7201 const DNSName target("powerdns.com.");
7202 const DNSName targetCName1("cname.sub.powerdns.com.");
7203 const DNSName targetCName2("cname2.sub.powerdns.com.");
7204 const ComboAddress targetCName2Addr("192.0.2.42");
7205 testkeysset_t keys;
7206
7207 auto luaconfsCopy = g_luaconfs.getCopy();
7208 luaconfsCopy.dsAnchors.clear();
7209 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7210 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7211 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7212 g_luaconfs.setState(luaconfsCopy);
7213
7214 size_t queriesCount = 0;
7215
18d5b679 7216 sr->setAsyncCallback([target,targetCName1,targetCName2,targetCName2Addr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> outgoingLogger, LWResult* res, bool* chained) {
8783a0ac
RG
7217 queriesCount++;
7218
7219 if (type == QType::DS || type == QType::DNSKEY) {
7220 if (domain == DNSName("sub.powerdns.com")) {
7221 setLWResult(res, 0, false, false, true);
7222 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7223 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7224 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7225 return 1;
7226 }
7227 else {
7228 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7229 }
7230 }
7231 else {
7232 if (isRootServer(ip)) {
7233 setLWResult(res, 0, false, false, true);
7234 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7235 addDS(DNSName("com."), 300, res->d_records, keys);
7236 addRRSIG(keys, res->d_records, DNSName("."), 300);
7237 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7238 return 1;
7239 }
7240 else if (ip == ComboAddress("192.0.2.1:53")) {
7241 setLWResult(res, 0, false, false, true);
7242 if (domain == DNSName("com.")) {
7243 setLWResult(res, 0, true, false, true);
7244 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7245 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7246 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7247 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7248 }
7249 else {
7250 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7251 if (domain == DNSName("powerdns.com.")) {
7252 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7253 }
7254 else if (domain == DNSName("sub.powerdns.com")) {
7255 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7256 }
7257 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7258 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7259 }
7260
7261 return 1;
7262 }
7263 else if (ip == ComboAddress("192.0.2.2:53")) {
7264 setLWResult(res, 0, true, false, true);
7265
7266 if (type == QType::NS) {
7267 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7268 if (domain == DNSName("powerdns.com.")) {
7269 addRRSIG(keys, res->d_records, domain, 300);
7270 }
7271 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7272 if (domain == DNSName("powerdns.com.")) {
7273 addRRSIG(keys, res->d_records, domain, 300);
7274 }
7275 }
7276 else {
7277 if (domain == DNSName("powerdns.com.")) {
7278 addRecordToLW(res, domain, QType::CNAME, targetCName1.toString());
7279 addRRSIG(keys, res->d_records, domain, 300);
7280 /* add the CNAME target as a glue, with no RRSIG since the sub zone is insecure */
7281 addRecordToLW(res, targetCName1, QType::CNAME, targetCName2.toString());
7282 addRecordToLW(res, targetCName2, QType::A, targetCName2Addr.toString());
7283 }
7284 else if (domain == targetCName1) {
7285 addRecordToLW(res, domain, QType::CNAME, targetCName2.toString());
7286 }
7287 else if (domain == targetCName2) {
7288 addRecordToLW(res, domain, QType::A, targetCName2Addr.toString());
7289 }
7290 }
7291
7292 return 1;
7293 }
7294 }
7295
7296 return 0;
7297 });
7298
7299 vector<DNSRecord> ret;
7300 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7301 BOOST_CHECK_EQUAL(res, RCode::NoError);
7302 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7303 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7304 BOOST_CHECK_EQUAL(queriesCount, 11);
7305
7306 /* again, to test the cache */
7307 ret.clear();
7308 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7309 BOOST_CHECK_EQUAL(res, RCode::NoError);
7310 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7311 BOOST_REQUIRE_EQUAL(ret.size(), 4);
7312 BOOST_CHECK_EQUAL(queriesCount, 11);
7313}
7314
3d5ebf10
RG
7315BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) {
7316 std::unique_ptr<SyncRes> sr;
7317 initSR(sr, true);
7318
0c43f455 7319 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7320
7321 primeHints();
7322 const DNSName target("power-dns.com.");
7323 const DNSName targetCName("powerdns.com.");
7324 const ComboAddress targetCNameAddr("192.0.2.42");
7325 testkeysset_t keys;
7326
7327 auto luaconfsCopy = g_luaconfs.getCopy();
7328 luaconfsCopy.dsAnchors.clear();
7329 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7330 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7331 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7332 g_luaconfs.setState(luaconfsCopy);
7333
7334 size_t queriesCount = 0;
7335
18d5b679 7336 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, bool* chained) {
3d5ebf10
RG
7337 queriesCount++;
7338
7339 if (type == QType::DS) {
a53e8fe3 7340 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
7341 setLWResult(res, 0, false, false, true);
7342 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7343 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7344 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7345 return 1;
7346 }
5374b03b
RG
7347 else {
7348 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7349 }
3d5ebf10
RG
7350 }
7351 else if (type == QType::DNSKEY) {
7352 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7353 setLWResult(res, 0, true, false, true);
7354 addDNSKEY(keys, domain, 300, res->d_records);
7355 addRRSIG(keys, res->d_records, domain, 300);
7356 return 1;
7357 }
7358 else {
7359 setLWResult(res, 0, false, false, true);
7360 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7361 return 1;
7362 }
7363 }
7364 else {
7365 if (isRootServer(ip)) {
7366 setLWResult(res, 0, false, false, true);
7367 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7368 addDS(DNSName("com."), 300, res->d_records, keys);
7369 addRRSIG(keys, res->d_records, DNSName("."), 300);
7370 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7371 return 1;
7372 }
7373 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7374 if (domain == DNSName("com.")) {
7375 setLWResult(res, 0, true, false, true);
7376 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7377 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7378 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7379 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7380 }
a69867f2
RG
7381 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7382 setLWResult(res, 0, false, false, true);
7383 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7384 if (domain == targetCName) {
7385 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7386 }
7387 else if (domain == target) {
7388 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7389 }
7390 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7391 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7392 }
3d5ebf10
RG
7393 return 1;
7394 }
7395 else if (ip == ComboAddress("192.0.2.2:53")) {
7396 setLWResult(res, 0, true, false, true);
a69867f2
RG
7397 if (type == QType::NS) {
7398 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7399 if (domain == DNSName("powerdns.com.")) {
7400 addRRSIG(keys, res->d_records, domain, 300);
7401 }
7402 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7403 if (domain == DNSName("powerdns.com.")) {
7404 addRRSIG(keys, res->d_records, domain, 300);
7405 }
3d5ebf10 7406 }
a69867f2
RG
7407 else {
7408 if (domain == target) {
7409 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7410 }
7411 else if (domain == targetCName) {
7412 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7413 addRRSIG(keys, res->d_records, domain, 300);
7414 }
3d5ebf10
RG
7415 }
7416 return 1;
7417 }
7418 }
7419
7420 return 0;
7421 });
7422
7423 vector<DNSRecord> ret;
7424 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7425 BOOST_CHECK_EQUAL(res, RCode::NoError);
7426 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7427 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7428 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7429
7430 /* again, to test the cache */
7431 ret.clear();
7432 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7433 BOOST_CHECK_EQUAL(res, RCode::NoError);
7434 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
7435 BOOST_REQUIRE_EQUAL(ret.size(), 3);
a69867f2 7436 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7437}
7438
7439BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) {
7440 std::unique_ptr<SyncRes> sr;
7441 initSR(sr, true);
7442
0c43f455 7443 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7444
7445 primeHints();
7446 const DNSName target("power-dns.com.");
7447 const DNSName targetCName("powerdns.com.");
7448 const ComboAddress targetCNameAddr("192.0.2.42");
7449 testkeysset_t keys;
7450
7451 auto luaconfsCopy = g_luaconfs.getCopy();
7452 luaconfsCopy.dsAnchors.clear();
7453 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7454 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7455 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7456 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7457 g_luaconfs.setState(luaconfsCopy);
7458
7459 size_t queriesCount = 0;
7460
18d5b679 7461 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, bool* chained) {
3d5ebf10
RG
7462 queriesCount++;
7463
5374b03b
RG
7464 if (type == QType::DS || type == QType::DNSKEY) {
7465 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7466 }
7467 else {
7468 if (isRootServer(ip)) {
7469 setLWResult(res, 0, false, false, true);
7470 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7471 addDS(DNSName("com."), 300, res->d_records, keys);
7472 addRRSIG(keys, res->d_records, DNSName("."), 300);
7473 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7474 return 1;
7475 }
7476 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7477 if (domain == DNSName("com.")) {
7478 setLWResult(res, 0, true, false, true);
7479 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7480 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7481 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7482 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7483 }
7484 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7485 setLWResult(res, 0, false, false, true);
7486 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7487 addDS(DNSName(domain), 300, res->d_records, keys);
7488 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7489 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7490 }
3d5ebf10
RG
7491 return 1;
7492 }
7493 else if (ip == ComboAddress("192.0.2.2:53")) {
7494 setLWResult(res, 0, true, false, true);
a69867f2
RG
7495 if (type == QType::NS) {
7496 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7497 addRRSIG(keys, res->d_records, domain, 300);
7498 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7499 addRRSIG(keys, res->d_records, domain, 300);
7500 }
a69867f2
RG
7501 else {
7502 if (domain == target) {
7503 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7504 /* No RRSIG, leading to bogus */
7505 }
7506 else if (domain == targetCName) {
7507 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7508 addRRSIG(keys, res->d_records, domain, 300);
7509 }
7510 }
3d5ebf10
RG
7511 return 1;
7512 }
7513 }
7514
7515 return 0;
7516 });
7517
7518 vector<DNSRecord> ret;
7519 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7520 BOOST_CHECK_EQUAL(res, RCode::NoError);
7521 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7522 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7523 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7524
7525 /* again, to test the cache */
7526 ret.clear();
7527 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7528 BOOST_CHECK_EQUAL(res, RCode::NoError);
7529 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7530 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7531 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7532}
7533
7534BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) {
7535 std::unique_ptr<SyncRes> sr;
7536 initSR(sr, true);
7537
0c43f455 7538 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7539
7540 primeHints();
7541 const DNSName target("power-dns.com.");
7542 const DNSName targetCName("powerdns.com.");
7543 const ComboAddress targetCNameAddr("192.0.2.42");
7544 testkeysset_t keys;
7545
7546 auto luaconfsCopy = g_luaconfs.getCopy();
7547 luaconfsCopy.dsAnchors.clear();
7548 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7549 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7550 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7551 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7552 g_luaconfs.setState(luaconfsCopy);
7553
7554 size_t queriesCount = 0;
7555
18d5b679 7556 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, bool* chained) {
3d5ebf10
RG
7557 queriesCount++;
7558
5374b03b
RG
7559 if (type == QType::DS || type == QType::DNSKEY) {
7560 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7561 }
7562 else {
7563 if (isRootServer(ip)) {
7564 setLWResult(res, 0, false, false, true);
7565 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7566 addDS(DNSName("com."), 300, res->d_records, keys);
7567 addRRSIG(keys, res->d_records, DNSName("."), 300);
7568 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7569 return 1;
7570 }
7571 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7572 if (domain == DNSName("com.")) {
7573 setLWResult(res, 0, true, false, true);
7574 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7575 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7576 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7577 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7578 }
7579 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7580 setLWResult(res, 0, false, false, true);
7581 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7582 addDS(DNSName(domain), 300, res->d_records, keys);
7583 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7584 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7585 }
3d5ebf10
RG
7586 return 1;
7587 }
7588 else if (ip == ComboAddress("192.0.2.2:53")) {
7589 setLWResult(res, 0, true, false, true);
a69867f2
RG
7590 if (type == QType::NS) {
7591 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7592 addRRSIG(keys, res->d_records, domain, 300);
7593 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7594 addRRSIG(keys, res->d_records, domain, 300);
7595 }
a69867f2
RG
7596 else {
7597 if (domain == target) {
7598 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7599 addRRSIG(keys, res->d_records, domain, 300);
7600 }
7601 else if (domain == targetCName) {
7602 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7603 /* No RRSIG, leading to bogus */
7604 }
3d5ebf10
RG
7605 }
7606 return 1;
7607 }
7608 }
7609
7610 return 0;
7611 });
7612
7613 vector<DNSRecord> ret;
7614 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7615 BOOST_CHECK_EQUAL(res, RCode::NoError);
7616 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7617 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7618 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7619
7620 /* again, to test the cache */
7621 ret.clear();
7622 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7623 BOOST_CHECK_EQUAL(res, RCode::NoError);
7624 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7625 BOOST_REQUIRE_EQUAL(ret.size(), 3);
428f41b7 7626 BOOST_CHECK_EQUAL(queriesCount, 11);
3d5ebf10
RG
7627}
7628
7629BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) {
7630 std::unique_ptr<SyncRes> sr;
7631 initSR(sr, true);
7632
0c43f455 7633 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7634
7635 primeHints();
7636 const DNSName target("power-dns.com.");
7637 const DNSName targetCName("powerdns.com.");
7638 const ComboAddress targetCNameAddr("192.0.2.42");
7639 testkeysset_t keys;
7640
7641 auto luaconfsCopy = g_luaconfs.getCopy();
7642 luaconfsCopy.dsAnchors.clear();
7643 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7644 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7645 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7646 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7647 g_luaconfs.setState(luaconfsCopy);
7648
7649 size_t queriesCount = 0;
7650
18d5b679 7651 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, bool* chained) {
3d5ebf10
RG
7652 queriesCount++;
7653
5374b03b
RG
7654 if (type == QType::DS || type == QType::DNSKEY) {
7655 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
3d5ebf10
RG
7656 }
7657 else {
7658 if (isRootServer(ip)) {
7659 setLWResult(res, 0, false, false, true);
7660 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7661 addDS(DNSName("com."), 300, res->d_records, keys);
7662 addRRSIG(keys, res->d_records, DNSName("."), 300);
7663 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7664 return 1;
7665 }
7666 else if (ip == ComboAddress("192.0.2.1:53")) {
a69867f2
RG
7667 if (domain == DNSName("com.")) {
7668 setLWResult(res, 0, true, false, true);
7669 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7670 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7671 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7672 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7673 }
7674 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7675 setLWResult(res, 0, false, false, true);
7676 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7677 addDS(DNSName(domain), 300, res->d_records, keys);
7678 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7679 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7680 }
3d5ebf10
RG
7681 return 1;
7682 }
7683 else if (ip == ComboAddress("192.0.2.2:53")) {
7684 setLWResult(res, 0, true, false, true);
a69867f2
RG
7685 if (type == QType::NS) {
7686 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
3d5ebf10 7687 addRRSIG(keys, res->d_records, domain, 300);
a69867f2 7688 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10
RG
7689 addRRSIG(keys, res->d_records, domain, 300);
7690 }
a69867f2
RG
7691 else {
7692 if (domain == target) {
7693 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7694 addRRSIG(keys, res->d_records, domain, 300);
7695 }
7696 else if (domain == targetCName) {
7697 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7698 addRRSIG(keys, res->d_records, domain, 300);
7699 }
7700 }
3d5ebf10
RG
7701 return 1;
7702 }
7703 }
7704
7705 return 0;
7706 });
7707
7708 vector<DNSRecord> ret;
7709 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7710 BOOST_CHECK_EQUAL(res, RCode::NoError);
7711 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7712 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7713 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7714
7715 /* again, to test the cache */
7716 ret.clear();
7717 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7718 BOOST_CHECK_EQUAL(res, RCode::NoError);
7719 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7720 BOOST_REQUIRE_EQUAL(ret.size(), 4);
a69867f2 7721 BOOST_CHECK_EQUAL(queriesCount, 12);
3d5ebf10
RG
7722}
7723
7724BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) {
7725 std::unique_ptr<SyncRes> sr;
a69867f2 7726 initSR(sr, true);
3d5ebf10 7727
0c43f455 7728 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
3d5ebf10
RG
7729
7730 primeHints();
7731 const DNSName target("powerdns.com.");
7732 const DNSName targetCName("power-dns.com.");
7733 const ComboAddress targetCNameAddr("192.0.2.42");
7734 testkeysset_t keys;
7735
7736 auto luaconfsCopy = g_luaconfs.getCopy();
7737 luaconfsCopy.dsAnchors.clear();
7738 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7739 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7740 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7741 generateKeyMaterial(DNSName("power-dns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7742 g_luaconfs.setState(luaconfsCopy);
7743
7744 size_t queriesCount = 0;
7745
18d5b679 7746 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, bool* chained) {
3d5ebf10
RG
7747 queriesCount++;
7748
7749 if (type == QType::DS) {
a53e8fe3 7750 if (domain == DNSName("power-dns.com.")) {
3d5ebf10
RG
7751 setLWResult(res, 0, false, false, true);
7752 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7753 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7754 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7755 return 1;
7756 }
5374b03b
RG
7757 else {
7758 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
7759 }
3d5ebf10
RG
7760 }
7761 else if (type == QType::DNSKEY) {
7762 if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) {
7763 setLWResult(res, 0, true, false, true);
7764 addDNSKEY(keys, domain, 300, res->d_records);
7765 addRRSIG(keys, res->d_records, domain, 300);
7766 return 1;
7767 }
7768 else {
7769 setLWResult(res, 0, false, false, true);
7770 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7771 return 1;
7772 }
7773 }
7774 else {
7775 if (isRootServer(ip)) {
7776 setLWResult(res, 0, false, false, true);
7777 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7778 addDS(DNSName("com."), 300, res->d_records, keys);
7779 addRRSIG(keys, res->d_records, DNSName("."), 300);
7780 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7781 return 1;
7782 }
7783 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7784 if (domain == DNSName("com.")) {
7785 setLWResult(res, 0, true, false, true);
a69867f2 7786 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0
RG
7787 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7788 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7789 addRRSIG(keys, res->d_records, DNSName("com."), 300);
3d5ebf10 7790 }
88cb0fe0
RG
7791 else if (domain == DNSName("powerdns.com.") || domain == DNSName("power-dns.com.")) {
7792 setLWResult(res, 0, false, false, true);
7793 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7794 if (domain == DNSName("powerdns.com.")) {
7795 addDS(DNSName("powerdns.com."), 300, res->d_records, keys);
7796 }
7797 else if (domain == targetCName) {
7798 addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records);
7799 }
7800 addRRSIG(keys, res->d_records, DNSName("com."), 300);
7801 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7802 }
3d5ebf10
RG
7803 return 1;
7804 }
7805 else if (ip == ComboAddress("192.0.2.2:53")) {
7806 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7807 if (type == QType::NS) {
7808 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7809 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
3d5ebf10 7810 }
88cb0fe0
RG
7811 else {
7812 if (domain == DNSName("powerdns.com.")) {
7813 addRecordToLW(res, domain, QType::CNAME, targetCName.toString());
7814 /* No RRSIG -> Bogus */
7815 }
7816 else if (domain == targetCName) {
7817 addRecordToLW(res, domain, QType::A, targetCNameAddr.toString());
7818 }
3d5ebf10
RG
7819 }
7820 return 1;
7821 }
7822 }
7823
7824 return 0;
7825 });
7826
7827 vector<DNSRecord> ret;
7828 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7829 BOOST_CHECK_EQUAL(res, RCode::NoError);
7830 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7831 /* no RRSIG to show */
7832 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7833 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7834
7835 /* again, to test the cache */
7836 ret.clear();
7837 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7838 BOOST_CHECK_EQUAL(res, RCode::NoError);
7839 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
7840 BOOST_CHECK_EQUAL(ret.size(), 2);
a69867f2 7841 BOOST_CHECK_EQUAL(queriesCount, 10);
3d5ebf10
RG
7842}
7843
895449a5
RG
7844BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) {
7845 std::unique_ptr<SyncRes> sr;
7846 initSR(sr, true);
7847
0c43f455 7848 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
7849
7850 primeHints();
7851 const DNSName target("powerdns.com.");
7852 const ComboAddress targetAddr("192.0.2.42");
7853 testkeysset_t keys;
7854
7855 auto luaconfsCopy = g_luaconfs.getCopy();
7856 luaconfsCopy.dsAnchors.clear();
7857 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7858 /* No key material for .com */
7859 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7860 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7861 g_luaconfs.setState(luaconfsCopy);
7862
7863 size_t queriesCount = 0;
7864
18d5b679 7865 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, bool* chained) {
895449a5
RG
7866 queriesCount++;
7867
a53e8fe3 7868 if (type == QType::DNSKEY) {
895449a5
RG
7869 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7870 setLWResult(res, 0, true, false, true);
7871 addDNSKEY(keys, domain, 300, res->d_records);
7872 addRRSIG(keys, res->d_records, domain, 300);
7873 return 1;
7874 }
7875 else if (domain == DNSName("com.")) {
7876 setLWResult(res, 0, false, false, true);
7877 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7878 return 1;
7879 }
7880 }
88cb0fe0 7881 else {
895449a5
RG
7882 if (isRootServer(ip)) {
7883 setLWResult(res, 0, false, false, true);
7884 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7885 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7886 addRRSIG(keys, res->d_records, DNSName("."), 300);
7887 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7888 return 1;
7889 }
7890 else if (ip == ComboAddress("192.0.2.1:53")) {
88cb0fe0
RG
7891 if (target == domain) {
7892 setLWResult(res, 0, false, false, true);
7893 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7894 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7895 }
7896 else if (domain == DNSName("com.")) {
7897 setLWResult(res, 0, true, false, true);
7898 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
7899 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7900 }
895449a5
RG
7901 return 1;
7902 }
7903 else if (ip == ComboAddress("192.0.2.2:53")) {
7904 setLWResult(res, 0, true, false, true);
88cb0fe0
RG
7905 if (type == QType::NS) {
7906 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
7907 }
7908 else {
7909 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
7910 }
895449a5
RG
7911 addRRSIG(keys, res->d_records, domain, 300);
7912 return 1;
7913 }
7914 }
7915
7916 return 0;
7917 });
7918
7919 vector<DNSRecord> ret;
7920 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7921 BOOST_CHECK_EQUAL(res, RCode::NoError);
7922 /* should be insecure but we have a TA for powerdns.com. */
7923 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7924 /* We got a RRSIG */
7925 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7926 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7927 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
7928
7929 /* again, to test the cache */
7930 ret.clear();
7931 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
7932 BOOST_CHECK_EQUAL(res, RCode::NoError);
7933 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
7934 BOOST_REQUIRE_EQUAL(ret.size(), 2);
7935 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 7936 BOOST_CHECK_EQUAL(queriesCount, 5);
895449a5
RG
7937}
7938
7939BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) {
7940 std::unique_ptr<SyncRes> sr;
7941 initSR(sr, true);
7942
0c43f455 7943 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5
RG
7944
7945 primeHints();
7946 const DNSName target("powerdns.com.");
7947 const ComboAddress targetAddr("192.0.2.42");
7948 testkeysset_t keys;
7949
7950 auto luaconfsCopy = g_luaconfs.getCopy();
7951 luaconfsCopy.dsAnchors.clear();
7952 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
7953 /* No key material for .com */
7954 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
7955 luaconfsCopy.dsAnchors[target].insert(keys[target].second);
7956 g_luaconfs.setState(luaconfsCopy);
7957
7958 size_t queriesCount = 0;
7959
18d5b679 7960 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, bool* chained) {
895449a5
RG
7961 queriesCount++;
7962
a53e8fe3 7963 if (type == QType::DNSKEY) {
895449a5
RG
7964 if (domain == g_rootdnsname || domain == DNSName("powerdns.com.")) {
7965 setLWResult(res, 0, true, false, true);
7966 addDNSKEY(keys, domain, 300, res->d_records);
7967 addRRSIG(keys, res->d_records, domain, 300);
7968 return 1;
7969 }
7970 else if (domain == DNSName("com.")) {
7971 setLWResult(res, 0, false, false, true);
7972 addRecordToLW(res, domain, QType::SOA, ". yop. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
7973 return 1;
7974 }
7975 }
70b3fe7a
RG
7976 else {
7977 if (target.isPartOf(domain) && isRootServer(ip)) {
895449a5
RG
7978 setLWResult(res, 0, false, false, true);
7979 addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600);
7980 addNSECRecordToLW(DNSName("com."), DNSName("com."), { QType::NS }, 600, res->d_records);
7981 addRRSIG(keys, res->d_records, DNSName("."), 300);
7982 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
7983 return 1;
7984 }
7985 else if (ip == ComboAddress("192.0.2.1:53")) {
70b3fe7a
RG
7986 if (target == domain) {
7987 setLWResult(res, 0, false, false, true);
7988 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600);
7989 addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
7990 }
7991 else if (domain == DNSName("com.")) {
7992 setLWResult(res, 0, true, false, true);
7993 addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com.");
88cb0fe0 7994 addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
70b3fe7a 7995 }
895449a5
RG
7996 return 1;
7997 }
70b3fe7a 7998 else if (domain == target && ip == ComboAddress("192.0.2.2:53")) {
895449a5 7999 setLWResult(res, 0, true, false, true);
70b3fe7a
RG
8000 if (type == QType::NS) {
8001 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com.");
8002 }
8003 else {
8004 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8005 }
895449a5
RG
8006 /* No RRSIG in a now (thanks to TA) Secure zone -> Bogus*/
8007 return 1;
8008 }
8009 }
8010
8011 return 0;
8012 });
8013
8014 vector<DNSRecord> ret;
8015 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8016 BOOST_CHECK_EQUAL(res, RCode::NoError);
8017 /* should be insecure but we have a TA for powerdns.com., but no RRSIG so Bogus */
8018 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8019 /* No RRSIG */
8020 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8021 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8022 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
8023
8024 /* again, to test the cache */
8025 ret.clear();
8026 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8027 BOOST_CHECK_EQUAL(res, RCode::NoError);
8028 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8029 BOOST_REQUIRE_EQUAL(ret.size(), 1);
8030 BOOST_CHECK(ret[0].d_type == QType::A);
5374b03b 8031 BOOST_CHECK_EQUAL(queriesCount, 4);
895449a5
RG
8032}
8033
895449a5
RG
8034BOOST_AUTO_TEST_CASE(test_dnssec_nta) {
8035 std::unique_ptr<SyncRes> sr;
8036 initSR(sr, true);
8037
0c43f455 8038 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
895449a5 8039
b7f378d1
RG
8040 primeHints();
8041 const DNSName target(".");
8042 testkeysset_t keys;
8043
8044 auto luaconfsCopy = g_luaconfs.getCopy();
8045 luaconfsCopy.dsAnchors.clear();
8046 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8047 /* Add a NTA for "." */
8048 luaconfsCopy.negAnchors[g_rootdnsname] = "NTA for Root";
8049 g_luaconfs.setState(luaconfsCopy);
8050
8051 size_t queriesCount = 0;
8052
18d5b679 8053 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, bool* chained) {
b7f378d1
RG
8054 queriesCount++;
8055
8056 if (domain == target && type == QType::NS) {
8057
8058 setLWResult(res, 0, true, false, true);
8059 char addr[] = "a.root-servers.net.";
8060 for (char idx = 'a'; idx <= 'm'; idx++) {
8061 addr[0] = idx;
8455425c
RG
8062 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8063 }
8064
8065 addRRSIG(keys, res->d_records, domain, 300);
8066
8067 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8068 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8069
8070 return 1;
8071 } else if (domain == target && type == QType::DNSKEY) {
8072
8073 setLWResult(res, 0, true, false, true);
8074
8075 /* No DNSKEY */
8076
8077 return 1;
8078 }
8079
8080 return 0;
8081 });
8082
8083 vector<DNSRecord> ret;
8084 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8085 BOOST_CHECK_EQUAL(res, RCode::NoError);
8086 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8087 /* 13 NS + 1 RRSIG */
8088 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8089 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8090
8091 /* again, to test the cache */
8092 ret.clear();
8093 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8094 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8095 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8096 BOOST_REQUIRE_EQUAL(ret.size(), 14);
8097 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8098}
8099
8100BOOST_AUTO_TEST_CASE(test_dnssec_no_ta) {
8101 std::unique_ptr<SyncRes> sr;
895449a5 8102 initSR(sr, true);
8455425c 8103
0c43f455 8104 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8455425c
RG
8105
8106 primeHints();
8107 const DNSName target(".");
b7f378d1 8108 testkeysset_t keys;
8455425c
RG
8109
8110 /* Remove the root DS */
8111 auto luaconfsCopy = g_luaconfs.getCopy();
8112 luaconfsCopy.dsAnchors.clear();
8113 g_luaconfs.setState(luaconfsCopy);
8114
8115 size_t queriesCount = 0;
8116
18d5b679 8117 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, bool* chained) {
8455425c
RG
8118 queriesCount++;
8119
8120 if (domain == target && type == QType::NS) {
8121
8122 setLWResult(res, 0, true, false, true);
8123 char addr[] = "a.root-servers.net.";
8124 for (char idx = 'a'; idx <= 'm'; idx++) {
8125 addr[0] = idx;
8126 addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
8127 }
8128
8129 addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
8130 addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
8131
8132 return 1;
8133 }
8134
8135 return 0;
8136 });
8137
8138 vector<DNSRecord> ret;
8139 int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
b7f378d1
RG
8140 BOOST_CHECK_EQUAL(res, RCode::NoError);
8141 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
8455425c
RG
8142 /* 13 NS + 0 RRSIG */
8143 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8144 BOOST_CHECK_EQUAL(queriesCount, 1);
b7f378d1
RG
8145
8146 /* again, to test the cache */
8147 ret.clear();
8148 res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
8149 BOOST_CHECK_EQUAL(res, RCode::NoError);
8455425c 8150 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
b7f378d1
RG
8151 BOOST_REQUIRE_EQUAL(ret.size(), 13);
8152 BOOST_CHECK_EQUAL(queriesCount, 1);
8455425c
RG
8153}
8154
114829cc
RG
8155BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) {
8156 std::unique_ptr<SyncRes> sr;
8157 initSR(sr, true);
8158
5d7b19c5 8159 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
114829cc
RG
8160
8161 primeHints();
8162 const DNSName target("powerdns.com.");
8163 testkeysset_t keys;
8164
8165 auto luaconfsCopy = g_luaconfs.getCopy();
8166 luaconfsCopy.dsAnchors.clear();
8167 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
5374b03b 8168 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
114829cc
RG
8169 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8170 g_luaconfs.setState(luaconfsCopy);
8171
8172 size_t queriesCount = 0;
8173
18d5b679 8174 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, bool* chained) {
114829cc
RG
8175 queriesCount++;
8176
5374b03b
RG
8177 if (type == QType::DS || type == QType::DNSKEY) {
8178 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
114829cc
RG
8179 }
8180 else {
8181
8182 setLWResult(res, 0, true, false, true);
8183 return 1;
8184 }
8185
8186 return 0;
8187 });
8188
8189 vector<DNSRecord> ret;
8190 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8191 BOOST_CHECK_EQUAL(res, RCode::NoError);
8192 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8193 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8194 /* com|NS, powerdns.com|NS, powerdns.com|A */
8195 BOOST_CHECK_EQUAL(queriesCount, 3);
8196
8197 /* again, to test the cache */
8198 ret.clear();
8199 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8200 BOOST_CHECK_EQUAL(res, RCode::NoError);
8201 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
8202 BOOST_REQUIRE_EQUAL(ret.size(), 0);
8203 /* we don't store empty results */
5374b03b 8204 BOOST_CHECK_EQUAL(queriesCount, 4);
114829cc
RG
8205}
8206
db04449e
RG
8207BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) {
8208 init();
8209
8210 testkeysset_t keys;
8211 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8212
8213 vector<DNSRecord> records;
8214
8215 vector<shared_ptr<DNSRecordContent>> recordContents;
8216 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8217
8218 /*
8219 No wrap test case:
8220 a.example.org. -> d.example.org. denies the existence of b.example.org.
8221 */
8222 addNSECRecordToLW(DNSName("a.example.org."), DNSName("d.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8223 recordContents.push_back(records.at(0).d_content);
8224 addRRSIG(keys, records, DNSName("example.org."), 300);
8225 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8226 records.clear();
8227
8228 ContentSigPair pair;
8229 pair.records = recordContents;
8230 pair.signatures = signatureContents;
8231 cspmap_t denialMap;
8232 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8233
9b061cf5
RG
8234 /* add wildcard denial */
8235 recordContents.clear();
8236 signatureContents.clear();
8237 addNSECRecordToLW(DNSName("example.org."), DNSName("+.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8238 recordContents.push_back(records.at(0).d_content);
8239 addRRSIG(keys, records, DNSName("example.org."), 300);
8240 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8241 records.clear();
8242
8243 pair.records = recordContents;
8244 pair.signatures = signatureContents;
8245 denialMap[std::make_pair(DNSName("example.org."), QType::NSEC)] = pair;
8246
00e3fef4 8247 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8248 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8249
00e3fef4 8250 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8251 /* let's check that d.example.org. is not denied by this proof */
8252 BOOST_CHECK_EQUAL(denialState, NODATA);
8253}
8254
8255BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) {
8256 init();
8257
8258 testkeysset_t keys;
8259 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8260
8261 vector<DNSRecord> records;
8262
8263 vector<shared_ptr<DNSRecordContent>> recordContents;
8264 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8265
8266 /*
8267 Wrap case 1 test case:
8268 z.example.org. -> b.example.org. denies the existence of a.example.org.
8269 */
8270 addNSECRecordToLW(DNSName("z.example.org."), DNSName("b.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8271 recordContents.push_back(records.at(0).d_content);
8272 addRRSIG(keys, records, DNSName("example.org."), 300);
8273 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8274 records.clear();
8275
8276 ContentSigPair pair;
8277 pair.records = recordContents;
8278 pair.signatures = signatureContents;
8279 cspmap_t denialMap;
8280 denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair;
8281
00e3fef4 8282 dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8283 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8284
00e3fef4 8285 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8286 /* let's check that d.example.org. is not denied by this proof */
8287 BOOST_CHECK_EQUAL(denialState, NODATA);
8288}
8289
8290BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) {
8291 init();
8292
8293 testkeysset_t keys;
8294 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8295
8296 vector<DNSRecord> records;
8297
8298 vector<shared_ptr<DNSRecordContent>> recordContents;
8299 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8300
8301 /*
8302 Wrap case 2 test case:
8303 y.example.org. -> a.example.org. denies the existence of z.example.org.
8304 */
8305 addNSECRecordToLW(DNSName("y.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8306 recordContents.push_back(records.at(0).d_content);
8307 addRRSIG(keys, records, DNSName("example.org."), 300);
8308 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8309 records.clear();
8310
8311 ContentSigPair pair;
8312 pair.records = recordContents;
8313 pair.signatures = signatureContents;
8314 cspmap_t denialMap;
8315 denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair;
8316
00e3fef4 8317 dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false);
db04449e
RG
8318 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8319
00e3fef4 8320 denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false);
db04449e
RG
8321 /* let's check that d.example.org. is not denied by this proof */
8322 BOOST_CHECK_EQUAL(denialState, NODATA);
8323}
8324
8325BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) {
8326 init();
8327
8328 testkeysset_t keys;
8329 generateKeyMaterial(DNSName("example.org."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8330
8331 vector<DNSRecord> records;
8332
8333 vector<shared_ptr<DNSRecordContent>> recordContents;
8334 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8335
8336 /*
8337 Only one NSEC in the whole zone test case:
8338 a.example.org. -> a.example.org. denies the existence of b.example.org.
8339 */
8340 addNSECRecordToLW(DNSName("a.example.org."), DNSName("a.example.org"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8341 recordContents.push_back(records.at(0).d_content);
8342 addRRSIG(keys, records, DNSName("example.org."), 300);
8343 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8344 records.clear();
8345
8346 ContentSigPair pair;
8347 pair.records = recordContents;
8348 pair.signatures = signatureContents;
8349 cspmap_t denialMap;
8350 denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair;
8351
00e3fef4 8352 dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false);
db04449e
RG
8353 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8354
00e3fef4 8355 denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false);
db04449e
RG
8356 /* let's check that d.example.org. is not denied by this proof */
8357 BOOST_CHECK_EQUAL(denialState, NODATA);
8358}
8359
1efd998a
RG
8360BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) {
8361 init();
8362
8363 testkeysset_t keys;
8364 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8365
8366 vector<DNSRecord> records;
8367
8368 vector<shared_ptr<DNSRecordContent>> recordContents;
8369 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8370
8371 /*
8372 The RRSIG from "." denies the existence of anything between a. and c.,
8373 including b.
8374 */
8375 addNSECRecordToLW(DNSName("a."), DNSName("c."), { QType::NS }, 600, records);
8376 recordContents.push_back(records.at(0).d_content);
8377 addRRSIG(keys, records, DNSName("."), 300);
8378 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8379 records.clear();
8380
8381 ContentSigPair pair;
8382 pair.records = recordContents;
8383 pair.signatures = signatureContents;
8384 cspmap_t denialMap;
8385 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8386
9b061cf5
RG
8387 /* add wildcard denial */
8388 recordContents.clear();
8389 signatureContents.clear();
8390 addNSECRecordToLW(DNSName("."), DNSName("+"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8391 recordContents.push_back(records.at(0).d_content);
8392 addRRSIG(keys, records, DNSName("."), 300);
8393 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8394 records.clear();
8395
8396 pair.records = recordContents;
8397 pair.signatures = signatureContents;
8398 denialMap[std::make_pair(DNSName("."), QType::NSEC)] = pair;
8399
00e3fef4 8400 dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false);
1efd998a
RG
8401 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
8402}
8403
8404BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) {
8405 init();
8406
8407 testkeysset_t keys;
8408 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8409
8410 vector<DNSRecord> records;
8411
8412 vector<shared_ptr<DNSRecordContent>> recordContents;
8413 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8414
8415 /*
8416 The RRSIG from "." denies the existence of any type except NS at a.
8417 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8418 signer field that is shorter than the owner name of the NSEC RR) it can't
8419 be used to deny anything except the whole name or a DS.
8420 */
8421 addNSECRecordToLW(DNSName("a."), DNSName("b."), { QType::NS }, 600, records);
8422 recordContents.push_back(records.at(0).d_content);
8423 addRRSIG(keys, records, DNSName("."), 300);
8424 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8425 records.clear();
8426
8427 ContentSigPair pair;
8428 pair.records = recordContents;
8429 pair.signatures = signatureContents;
8430 cspmap_t denialMap;
8431 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8432
8433 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8434 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8435 nonexistence of any RRs below that zone cut, which include all RRs at
8436 that (original) owner name other than DS RRs, and all RRs below that
8437 owner name regardless of type.
8438 */
8439
00e3fef4 8440 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false);
1efd998a
RG
8441 /* no data means the qname/qtype is not denied, because an ancestor
8442 delegation NSEC can only deny the DS */
8443 BOOST_CHECK_EQUAL(denialState, NODATA);
8444
b93be4a0
RG
8445 /* it can not be used to deny any RRs below that owner name either */
8446 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, false);
8447 BOOST_CHECK_EQUAL(denialState, NODATA);
8448
00e3fef4 8449 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
1efd998a
RG
8450 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
8451}
8452
95823c07
RG
8453BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) {
8454 init();
8455
8456 testkeysset_t keys;
8457 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8458
8459 vector<DNSRecord> records;
8460
8461 vector<shared_ptr<DNSRecordContent>> recordContents;
8462 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8463
8464 /*
8465 * RFC 5155 section 8.9:
8466 * If there is an NSEC3 RR present in the response that matches the
8467 * delegation name, then the validator MUST ensure that the NS bit is
8468 * set and that the DS bit is not set in the Type Bit Maps field of the
8469 * NSEC3 RR.
8470 */
8471 /*
8472 The RRSIG from "." denies the existence of any type at a.
8473 NS should be set if it was proving an insecure delegation, let's check that
8474 we correctly detect that it's not.
8475 */
8476 addNSECRecordToLW(DNSName("a."), DNSName("b."), { }, 600, records);
8477 recordContents.push_back(records.at(0).d_content);
8478 addRRSIG(keys, records, DNSName("."), 300);
8479 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8480 records.clear();
8481
8482 ContentSigPair pair;
8483 pair.records = recordContents;
8484 pair.signatures = signatureContents;
8485 cspmap_t denialMap;
8486 denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair;
8487
8488 /* Insecure because the NS is not set, so while it does
8489 denies the DS, it can't prove an insecure delegation */
00e3fef4 8490 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8491 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8492}
8493
9b061cf5
RG
8494BOOST_AUTO_TEST_CASE(test_nsec_nxqtype_cname) {
8495 init();
8496
8497 testkeysset_t keys;
8498 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8499
8500 vector<DNSRecord> records;
8501
8502 vector<shared_ptr<DNSRecordContent>> recordContents;
8503 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8504
8505 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::CNAME }, 600, records);
8506 recordContents.push_back(records.at(0).d_content);
8507 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8508 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8509 records.clear();
8510
8511 ContentSigPair pair;
8512 pair.records = recordContents;
8513 pair.signatures = signatureContents;
8514 cspmap_t denialMap;
8515 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8516
8517 /* this NSEC is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8518 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, true, true);
8519 BOOST_CHECK_EQUAL(denialState, NODATA);
8520}
8521
8522BOOST_AUTO_TEST_CASE(test_nsec3_nxqtype_cname) {
8523 init();
8524
8525 testkeysset_t keys;
8526 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8527
8528 vector<DNSRecord> records;
8529
8530 vector<shared_ptr<DNSRecordContent>> recordContents;
8531 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8532
8533 addNSEC3UnhashedRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::CNAME }, 600, records);
8534 recordContents.push_back(records.at(0).d_content);
8535 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8536 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8537
8538 ContentSigPair pair;
8539 pair.records = recordContents;
8540 pair.signatures = signatureContents;
8541 cspmap_t denialMap;
8542 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8543 records.clear();
8544
8545 /* this NSEC3 is not valid to deny a.powerdns.com|A since it states that a CNAME exists */
8546 dState denialState = getDenial(denialMap, DNSName("a.powerdns.com."), QType::A, false, true);
8547 BOOST_CHECK_EQUAL(denialState, NODATA);
8548}
8549
8550BOOST_AUTO_TEST_CASE(test_nsec_nxdomain_denial_missing_wildcard) {
8551 init();
8552
8553 testkeysset_t keys;
8554 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8555
8556 vector<DNSRecord> records;
8557
8558 vector<shared_ptr<DNSRecordContent>> recordContents;
8559 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8560
8561 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("d.powerdns.com"), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8562 recordContents.push_back(records.at(0).d_content);
8563 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8564 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8565 records.clear();
8566
8567 ContentSigPair pair;
8568 pair.records = recordContents;
8569 pair.signatures = signatureContents;
8570 cspmap_t denialMap;
8571 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8572
8573 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8574 BOOST_CHECK_EQUAL(denialState, NODATA);
8575}
8576
8577BOOST_AUTO_TEST_CASE(test_nsec3_nxdomain_denial_missing_wildcard) {
8578 init();
8579
8580 testkeysset_t keys;
8581 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8582
8583 vector<DNSRecord> records;
8584
8585 vector<shared_ptr<DNSRecordContent>> recordContents;
8586 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8587
8588 addNSEC3NarrowRecordToLW(DNSName("a.powerdns.com."), DNSName("powerdns.com."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8589 recordContents.push_back(records.at(0).d_content);
8590 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8591 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8592
8593 ContentSigPair pair;
8594 pair.records = recordContents;
8595 pair.signatures = signatureContents;
8596 cspmap_t denialMap;
8597 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8598
8599 /* Add NSEC3 for the closest encloser */
8600 recordContents.clear();
8601 signatureContents.clear();
8602 records.clear();
8603 addNSEC3UnhashedRecordToLW(DNSName("powerdns.com."), DNSName("powerdns.com."), "whatever", { QType::A, QType::TXT, QType::RRSIG, QType::NSEC }, 600, records);
8604 recordContents.push_back(records.at(0).d_content);
8605 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8606 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8607
8608 pair.records = recordContents;
8609 pair.signatures = signatureContents;
8610 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8611
8612 dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, false, false);
8613 BOOST_CHECK_EQUAL(denialState, NODATA);
8614}
8615
00e3fef4
RG
8616BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) {
8617 init();
8618
8619 testkeysset_t keys;
8620 generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8621
8622 vector<DNSRecord> records;
8623
8624 vector<shared_ptr<DNSRecordContent>> recordContents;
8625 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8626
8627 addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records);
8628 recordContents.push_back(records.at(0).d_content);
8629 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8630 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8631 records.clear();
8632
8633 ContentSigPair pair;
8634 pair.records = recordContents;
8635 pair.signatures = signatureContents;
8636 cspmap_t denialMap;
8637 denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair;
8638
9b061cf5 8639 /* this NSEC is valid to prove a NXQTYPE at c.powerdns.com because it proves that
00e3fef4 8640 it is an ENT */
9b061cf5 8641 dState denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true);
00e3fef4 8642 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
00be1ff6 8643
9b061cf5
RG
8644 /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com,
8645 it could prove a NXDOMAIN if it had an additional wildcard denial */
8646 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true);
8647 BOOST_CHECK_EQUAL(denialState, NODATA);
8648
00be1ff6
RG
8649 /* this NSEC is not valid to prove a NXQTYPE for QType::A at a.c.powerdns.com either */
8650 denialState = getDenial(denialMap, DNSName("a.c.powerdns.com."), QType::A, true, true);
8651 BOOST_CHECK_EQUAL(denialState, NODATA);
9b061cf5
RG
8652
8653 /* if we add the wildcard denial proof, we should get a NXDOMAIN proof for b.powerdns.com */
8654 recordContents.clear();
8655 signatureContents.clear();
8656 addNSECRecordToLW(DNSName(").powerdns.com."), DNSName("+.powerdns.com."), { }, 600, records);
8657 recordContents.push_back(records.at(0).d_content);
8658 addRRSIG(keys, records, DNSName("powerdns.com."), 300);
8659 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8660 records.clear();
8661 pair.records = recordContents;
8662 pair.signatures = signatureContents;
8663 denialMap[std::make_pair(DNSName(").powerdns.com."), QType::NSEC)] = pair;
8664
82566a96 8665 denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::A, true, false);
9b061cf5 8666 BOOST_CHECK_EQUAL(denialState, NXDOMAIN);
00e3fef4
RG
8667}
8668
95823c07
RG
8669BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) {
8670 init();
8671
8672 testkeysset_t keys;
8673 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8674
8675 vector<DNSRecord> records;
8676
8677 vector<shared_ptr<DNSRecordContent>> recordContents;
8678 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8679
8680 /*
8681 The RRSIG from "." denies the existence of any type except NS at a.
8682 However since it's an ancestor delegation NSEC (NS bit set, SOA bit clear,
8683 signer field that is shorter than the owner name of the NSEC RR) it can't
8684 be used to deny anything except the whole name or a DS.
8685 */
9b061cf5 8686 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::NS }, 600, records);
95823c07
RG
8687 recordContents.push_back(records.at(0).d_content);
8688 addRRSIG(keys, records, DNSName("."), 300);
8689 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8690
8691 ContentSigPair pair;
8692 pair.records = recordContents;
8693 pair.signatures = signatureContents;
8694 cspmap_t denialMap;
8695 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8696 records.clear();
8697
8698 /* RFC 6840 section 4.1 "Clarifications on Nonexistence Proofs":
8699 Ancestor delegation NSEC or NSEC3 RRs MUST NOT be used to assume
8700 nonexistence of any RRs below that zone cut, which include all RRs at
8701 that (original) owner name other than DS RRs, and all RRs below that
8702 owner name regardless of type.
8703 */
8704
00e3fef4 8705 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
95823c07
RG
8706 /* no data means the qname/qtype is not denied, because an ancestor
8707 delegation NSEC3 can only deny the DS */
8708 BOOST_CHECK_EQUAL(denialState, NODATA);
8709
00e3fef4 8710 denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
95823c07 8711 BOOST_CHECK_EQUAL(denialState, NXQTYPE);
b93be4a0
RG
8712
8713 /* it can not be used to deny any RRs below that owner name either */
8714 /* Add NSEC3 for the next closer */
8715 recordContents.clear();
8716 signatureContents.clear();
8717 records.clear();
8718 addNSEC3NarrowRecordToLW(DNSName("sub.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8719 recordContents.push_back(records.at(0).d_content);
8720 addRRSIG(keys, records, DNSName("."), 300);
8721 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8722
8723 pair.records = recordContents;
8724 pair.signatures = signatureContents;
8725 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8726
8727 /* add wildcard denial */
8728 recordContents.clear();
8729 signatureContents.clear();
8730 records.clear();
8731 addNSEC3NarrowRecordToLW(DNSName("*.a."), DNSName("."), { QType::A, QType::TXT, QType::RRSIG, QType::NSEC3 }, 600, records);
8732 recordContents.push_back(records.at(0).d_content);
8733 addRRSIG(keys, records, DNSName("."), 300);
8734 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8735
8736 pair.records = recordContents;
8737 pair.signatures = signatureContents;
8738 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8739
8740 denialState = getDenial(denialMap, DNSName("sub.a."), QType::A, false, true);
8741 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8742}
8743
b7c40613
RG
8744BOOST_AUTO_TEST_CASE(test_nsec3_denial_too_many_iterations) {
8745 init();
8746
8747 testkeysset_t keys;
8748 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8749
8750 vector<DNSRecord> records;
8751
8752 vector<shared_ptr<DNSRecordContent>> recordContents;
8753 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8754
8755 /* adding a NSEC3 with more iterations that we support */
8756 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { QType::AAAA }, 600, records, g_maxNSEC3Iterations + 100);
8757 recordContents.push_back(records.at(0).d_content);
8758 addRRSIG(keys, records, DNSName("."), 300);
8759 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8760
8761 ContentSigPair pair;
8762 pair.records = recordContents;
8763 pair.signatures = signatureContents;
8764 cspmap_t denialMap;
8765 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8766 records.clear();
8767
8768 dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true);
8769 /* since we refuse to compute more than g_maxNSEC3Iterations iterations, it should be Insecure */
8770 BOOST_CHECK_EQUAL(denialState, INSECURE);
8771}
8772
95823c07
RG
8773BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) {
8774 init();
8775
8776 testkeysset_t keys;
8777 generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8778
8779 vector<DNSRecord> records;
8780
8781 vector<shared_ptr<DNSRecordContent>> recordContents;
8782 vector<shared_ptr<RRSIGRecordContent>> signatureContents;
8783
8784 /*
8785 * RFC 5155 section 8.9:
8786 * If there is an NSEC3 RR present in the response that matches the
8787 * delegation name, then the validator MUST ensure that the NS bit is
8788 * set and that the DS bit is not set in the Type Bit Maps field of the
8789 * NSEC3 RR.
8790 */
8791 /*
8792 The RRSIG from "." denies the existence of any type at a.
8793 NS should be set if it was proving an insecure delegation, let's check that
8794 we correctly detect that it's not.
8795 */
9b061cf5 8796 addNSEC3UnhashedRecordToLW(DNSName("a."), DNSName("."), "whatever", { }, 600, records);
95823c07
RG
8797 recordContents.push_back(records.at(0).d_content);
8798 addRRSIG(keys, records, DNSName("."), 300);
8799 signatureContents.push_back(getRR<RRSIGRecordContent>(records.at(1)));
8800
8801 ContentSigPair pair;
8802 pair.records = recordContents;
8803 pair.signatures = signatureContents;
8804 cspmap_t denialMap;
8805 denialMap[std::make_pair(records.at(0).d_name, records.at(0).d_type)] = pair;
8806 records.clear();
8807
8808 /* Insecure because the NS is not set, so while it does
8809 denies the DS, it can't prove an insecure delegation */
00e3fef4 8810 dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true);
b7c40613 8811 BOOST_CHECK_EQUAL(denialState, NODATA);
95823c07
RG
8812}
8813
dbbef467
RG
8814BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_negcache_validity) {
8815 std::unique_ptr<SyncRes> sr;
dbbef467
RG
8816 initSR(sr, true);
8817
8818 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8819
8820 primeHints();
8821 const DNSName target("com.");
8822 testkeysset_t keys;
8823
8824 auto luaconfsCopy = g_luaconfs.getCopy();
8825 luaconfsCopy.dsAnchors.clear();
8826 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8827 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8828 g_luaconfs.setState(luaconfsCopy);
8829
8830 size_t queriesCount = 0;
8831
18d5b679 8832 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, bool* chained) {
dbbef467
RG
8833 queriesCount++;
8834
8835 DNSName auth = domain;
8836 auth.chopOff();
8837
8838 if (type == QType::DS || type == QType::DNSKEY) {
8839 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8840 }
8841 else {
8842 setLWResult(res, RCode::NoError, true, false, true);
8843 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
8844 addRRSIG(keys, res->d_records, domain, 300);
8845 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
8846 addRRSIG(keys, res->d_records, domain, 1);
8847 return 1;
8848 }
8849
8850 return 0;
8851 });
8852
934c35b9 8853 const time_t now = sr->getNow().tv_sec;
dbbef467
RG
8854 vector<DNSRecord> ret;
8855 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8856 BOOST_CHECK_EQUAL(res, RCode::NoError);
8857 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8858 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8859 BOOST_CHECK_EQUAL(queriesCount, 4);
8860
8861 /* check that the entry has not been negatively cached for longer than the RRSIG validity */
8862 NegCache::NegCacheEntry ne;
8863 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
8864 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
8865 BOOST_CHECK_EQUAL(ne.d_ttd, now + 1);
b25712fd 8866 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
dbbef467
RG
8867 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
8868 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
8869 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
8870 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
8871
8872 /* again, to test the cache */
8873 ret.clear();
8874 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8875 BOOST_CHECK_EQUAL(res, RCode::NoError);
8876 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8877 BOOST_REQUIRE_EQUAL(ret.size(), 4);
8878 BOOST_CHECK_EQUAL(queriesCount, 4);
8879}
8880
8881BOOST_AUTO_TEST_CASE(test_dnssec_rrsig_cache_validity) {
8882 std::unique_ptr<SyncRes> sr;
dbbef467
RG
8883 initSR(sr, true);
8884
8885 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
8886
8887 primeHints();
8888 const DNSName target("com.");
8889 const ComboAddress targetAddr("192.0.2.42");
8890 testkeysset_t keys;
8891
8892 auto luaconfsCopy = g_luaconfs.getCopy();
8893 luaconfsCopy.dsAnchors.clear();
8894 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8895 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
8896 g_luaconfs.setState(luaconfsCopy);
8897
8898 size_t queriesCount = 0;
8899
18d5b679 8900 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, bool* chained) {
dbbef467
RG
8901 queriesCount++;
8902
8903 DNSName auth = domain;
8904 auth.chopOff();
8905
8906 if (type == QType::DS || type == QType::DNSKEY) {
8907 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
8908 }
8909 else {
8910 setLWResult(res, RCode::NoError, true, false, true);
8911 addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600);
8912 addRRSIG(keys, res->d_records, domain, 1);
8913 return 1;
8914 }
8915
8916 return 0;
8917 });
8918
934c35b9 8919 const time_t now = sr->getNow().tv_sec;
dbbef467
RG
8920 vector<DNSRecord> ret;
8921 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8922 BOOST_CHECK_EQUAL(res, RCode::NoError);
8923 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8924 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8925 BOOST_CHECK_EQUAL(queriesCount, 4);
8926
8927 /* check that the entry has not been cached for longer than the RRSIG validity */
8928 const ComboAddress who;
8929 vector<DNSRecord> cached;
8930 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
8931 BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), true, &cached, who, &signatures), 1);
8932 BOOST_REQUIRE_EQUAL(cached.size(), 1);
8933 BOOST_REQUIRE_EQUAL(signatures.size(), 1);
8934 BOOST_CHECK_EQUAL((cached[0].d_ttl - now), 1);
8935
8936 /* again, to test the cache */
8937 ret.clear();
8938 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8939 BOOST_CHECK_EQUAL(res, RCode::NoError);
8940 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
8941 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8942 BOOST_CHECK_EQUAL(queriesCount, 4);
8943}
8944
f4de85a3
RG
8945BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_secure) {
8946 /*
8947 Validation is optional, and the first query does not ask for it,
8948 so the answer is cached as Indeterminate.
8949 The second query asks for validation, answer should be marked as
8950 Secure.
8951 */
8952 std::unique_ptr<SyncRes> sr;
8953 initSR(sr, true);
8954
8955 setDNSSECValidation(sr, DNSSECMode::Process);
8956
8957 primeHints();
8958 const DNSName target("com.");
8959 testkeysset_t keys;
8960
8961 auto luaconfsCopy = g_luaconfs.getCopy();
8962 luaconfsCopy.dsAnchors.clear();
8963 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
8964 g_luaconfs.setState(luaconfsCopy);
8965
8966 size_t queriesCount = 0;
8967
18d5b679 8968 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, bool* chained) {
f4de85a3
RG
8969 queriesCount++;
8970
8971 if (type == QType::DS || type == QType::DNSKEY) {
8972 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
8973 }
8974 else {
8975 if (domain == target && type == QType::A) {
8976 setLWResult(res, 0, true, false, true);
8977 addRecordToLW(res, target, QType::A, "192.0.2.1");
8978 addRRSIG(keys, res->d_records, DNSName("."), 300);
8979 return 1;
8980 }
8981 }
8982
8983 return 0;
8984 });
8985
8986 vector<DNSRecord> ret;
8987 /* first query does not require validation */
8988 sr->setDNSSECValidationRequested(false);
8989 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
8990 BOOST_CHECK_EQUAL(res, RCode::NoError);
8991 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
8992 BOOST_REQUIRE_EQUAL(ret.size(), 2);
8993 for (const auto& record : ret) {
8994 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
8995 }
8996 BOOST_CHECK_EQUAL(queriesCount, 1);
8997
8998
8999 ret.clear();
9000 /* second one _does_ require validation */
9001 sr->setDNSSECValidationRequested(true);
9002 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9003 BOOST_CHECK_EQUAL(res, RCode::NoError);
9004 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9005 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9006 for (const auto& record : ret) {
9007 BOOST_CHECK(record.d_type == QType::A || record.d_type == QType::RRSIG);
9008 }
9009 BOOST_CHECK_EQUAL(queriesCount, 3);
9010}
9011
9012BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_insecure) {
9013 /*
9014 Validation is optional, and the first query does not ask for it,
9015 so the answer is cached as Indeterminate.
9016 The second query asks for validation, answer should be marked as
9017 Insecure.
9018 */
9019 std::unique_ptr<SyncRes> sr;
9020 initSR(sr, true);
9021
9022 setDNSSECValidation(sr, DNSSECMode::Process);
9023
9024 primeHints();
9025 const DNSName target("com.");
9026 testkeysset_t keys;
9027
9028 auto luaconfsCopy = g_luaconfs.getCopy();
9029 luaconfsCopy.dsAnchors.clear();
9030 g_luaconfs.setState(luaconfsCopy);
9031
9032 size_t queriesCount = 0;
9033
18d5b679 9034 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, bool* chained) {
f4de85a3
RG
9035 queriesCount++;
9036
9037 if (type == QType::DS || type == QType::DNSKEY) {
9038 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9039 }
9040 else {
9041 if (domain == target && type == QType::A) {
9042 setLWResult(res, 0, true, false, true);
9043 addRecordToLW(res, target, QType::A, "192.0.2.1");
9044 return 1;
9045 }
9046 }
9047
9048 return 0;
9049 });
9050
9051 vector<DNSRecord> ret;
9052 /* first query does not require validation */
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_REQUIRE_EQUAL(ret.size(), 1);
9058 for (const auto& record : ret) {
55acb073 9059 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9060 }
9061 BOOST_CHECK_EQUAL(queriesCount, 1);
9062
9063
9064 ret.clear();
9065 /* second one _does_ require validation */
9066 sr->setDNSSECValidationRequested(true);
9067 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9068 BOOST_CHECK_EQUAL(res, RCode::NoError);
9069 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9070 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9071 for (const auto& record : ret) {
55acb073 9072 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9073 }
9074 BOOST_CHECK_EQUAL(queriesCount, 1);
9075}
9076
9077BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cache_bogus) {
9078 /*
9079 Validation is optional, and the first query does not ask for it,
9080 so the answer is cached as Indeterminate.
9081 The second query asks for validation, answer should be marked as
9082 Bogus.
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 g_luaconfs.setState(luaconfsCopy);
9097
9098 size_t queriesCount = 0;
9099
18d5b679 9100 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, bool* chained) {
f4de85a3
RG
9101 queriesCount++;
9102
9103 if (type == QType::DS || type == QType::DNSKEY) {
9104 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9105 }
9106 else {
9107 if (domain == target && type == QType::A) {
9108 setLWResult(res, 0, true, false, true);
9109 addRecordToLW(res, target, QType::A, "192.0.2.1");
9110 /* no RRSIG */
9111 return 1;
9112 }
9113 }
9114
9115 return 0;
9116 });
9117
9118 vector<DNSRecord> ret;
9119 /* first query does not require validation */
9120 sr->setDNSSECValidationRequested(false);
9121 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9122 BOOST_CHECK_EQUAL(res, RCode::NoError);
9123 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9124 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9125 for (const auto& record : ret) {
55acb073 9126 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9127 }
9128 BOOST_CHECK_EQUAL(queriesCount, 1);
9129
9130
9131 ret.clear();
9132 /* second one _does_ require validation */
9133 sr->setDNSSECValidationRequested(true);
9134 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9135 BOOST_CHECK_EQUAL(res, RCode::NoError);
9136 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9137 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9138 for (const auto& record : ret) {
55acb073 9139 BOOST_CHECK(record.d_type == QType::A);
f4de85a3
RG
9140 }
9141 BOOST_CHECK_EQUAL(queriesCount, 3);
9142}
9143
55acb073
RG
9144BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_secure) {
9145 /*
9146 Validation is optional, and the first query does not ask for it,
9147 so the answer is cached as Indeterminate.
9148 The second query asks for validation, answer should be marked as
9149 Secure.
9150 */
9151 std::unique_ptr<SyncRes> sr;
9152 initSR(sr, true);
9153
9154 setDNSSECValidation(sr, DNSSECMode::Process);
9155
9156 primeHints();
9157 const DNSName target("com.");
9158 const DNSName cnameTarget("cname-com.");
9159 testkeysset_t keys;
9160
9161 auto luaconfsCopy = g_luaconfs.getCopy();
9162 luaconfsCopy.dsAnchors.clear();
9163 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9164 g_luaconfs.setState(luaconfsCopy);
9165
9166 size_t queriesCount = 0;
9167
18d5b679 9168 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, bool* chained) {
55acb073
RG
9169 queriesCount++;
9170
9171 if (type == QType::DS || type == QType::DNSKEY) {
9172 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9173 }
9174 else {
9175 if (domain == target && type == QType::A) {
9176 setLWResult(res, 0, true, false, true);
9177 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9178 addRRSIG(keys, res->d_records, DNSName("."), 300);
9179 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9180 addRRSIG(keys, res->d_records, DNSName("."), 300);
9181 return 1;
9182 } else if (domain == cnameTarget && type == QType::A) {
9183 setLWResult(res, 0, true, false, true);
9184 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9185 addRRSIG(keys, res->d_records, DNSName("."), 300);
9186 return 1;
9187 }
9188 }
9189
9190 return 0;
9191 });
9192
9193 vector<DNSRecord> ret;
9194 /* first query does not require validation */
9195 sr->setDNSSECValidationRequested(false);
9196 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9197 BOOST_CHECK_EQUAL(res, RCode::NoError);
9198 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9199 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9200 for (const auto& record : ret) {
9201 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9202 }
9203 BOOST_CHECK_EQUAL(queriesCount, 2);
9204
9205
9206 ret.clear();
9207 /* second one _does_ require validation */
9208 sr->setDNSSECValidationRequested(true);
9209 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9210 BOOST_CHECK_EQUAL(res, RCode::NoError);
9211 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9212 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9213 for (const auto& record : ret) {
9214 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A || record.d_type == QType::RRSIG);
9215 }
9216 BOOST_CHECK_EQUAL(queriesCount, 5);
9217}
9218
9219BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_insecure) {
9220 /*
9221 Validation is optional, and the first query does not ask for it,
9222 so the answer is cached as Indeterminate.
9223 The second query asks for validation, answer should be marked as
9224 Insecure.
9225 */
9226 std::unique_ptr<SyncRes> sr;
9227 initSR(sr, true);
9228
9229 setDNSSECValidation(sr, DNSSECMode::Process);
9230
9231 primeHints();
9232 const DNSName target("com.");
9233 const DNSName cnameTarget("cname-com.");
9234 testkeysset_t keys;
9235
9236 auto luaconfsCopy = g_luaconfs.getCopy();
9237 luaconfsCopy.dsAnchors.clear();
9238 g_luaconfs.setState(luaconfsCopy);
9239
9240 size_t queriesCount = 0;
9241
18d5b679 9242 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, bool* chained) {
55acb073
RG
9243 queriesCount++;
9244
9245 if (type == QType::DS || type == QType::DNSKEY) {
9246 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9247 }
9248 else {
9249 if (domain == target && type == QType::A) {
9250 setLWResult(res, 0, true, false, true);
9251 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9252 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9253 return 1;
9254 } else if (domain == cnameTarget && type == QType::A) {
9255 setLWResult(res, 0, true, false, true);
9256 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9257 return 1;
9258 }
9259 }
9260
9261 return 0;
9262 });
9263
9264 vector<DNSRecord> ret;
9265 /* first query does not require validation */
9266 sr->setDNSSECValidationRequested(false);
9267 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9268 BOOST_CHECK_EQUAL(res, RCode::NoError);
9269 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9270 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9271 for (const auto& record : ret) {
9272 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9273 }
9274 BOOST_CHECK_EQUAL(queriesCount, 2);
9275
9276
9277 ret.clear();
9278 /* second one _does_ require validation */
9279 sr->setDNSSECValidationRequested(true);
9280 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9281 BOOST_CHECK_EQUAL(res, RCode::NoError);
9282 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9283 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9284 for (const auto& record : ret) {
9285 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9286 }
9287 BOOST_CHECK_EQUAL(queriesCount, 2);
9288}
9289
9290BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_cname_cache_bogus) {
9291 /*
9292 Validation is optional, and the first query does not ask for it,
9293 so the answer is cached as Indeterminate.
9294 The second query asks for validation, answer should be marked as
9295 Bogus.
9296 */
9297 std::unique_ptr<SyncRes> sr;
9298 initSR(sr, true);
9299
9300 setDNSSECValidation(sr, DNSSECMode::Process);
9301
9302 primeHints();
9303 const DNSName target("com.");
9304 const DNSName cnameTarget("cname-com.");
9305 testkeysset_t keys;
9306
9307 auto luaconfsCopy = g_luaconfs.getCopy();
9308 luaconfsCopy.dsAnchors.clear();
9309 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9310 g_luaconfs.setState(luaconfsCopy);
9311
9312 size_t queriesCount = 0;
9313
18d5b679 9314 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, bool* chained) {
55acb073
RG
9315 queriesCount++;
9316
9317 if (type == QType::DS || type == QType::DNSKEY) {
9318 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9319 }
9320 else {
9321 if (domain == target && type == QType::A) {
9322 setLWResult(res, 0, true, false, true);
9323 addRecordToLW(res, target, QType::CNAME, cnameTarget.toString());
9324 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9325 /* no RRSIG */
9326 return 1;
9327 } else if (domain == cnameTarget && type == QType::A) {
9328 setLWResult(res, 0, true, false, true);
9329 addRecordToLW(res, cnameTarget, QType::A, "192.0.2.1");
9330 /* no RRSIG */
9331 return 1;
9332 }
9333 }
9334
9335 return 0;
9336 });
9337
9338 vector<DNSRecord> ret;
9339 /* first query does not require validation */
9340 sr->setDNSSECValidationRequested(false);
9341 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9342 BOOST_CHECK_EQUAL(res, RCode::NoError);
9343 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9344 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9345 for (const auto& record : ret) {
9346 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9347 }
9348 BOOST_CHECK_EQUAL(queriesCount, 2);
9349
9350
9351 ret.clear();
9352 /* second one _does_ require validation */
9353 sr->setDNSSECValidationRequested(true);
9354 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9355 BOOST_CHECK_EQUAL(res, RCode::NoError);
9356 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9357 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9358 for (const auto& record : ret) {
9359 BOOST_CHECK(record.d_type == QType::CNAME || record.d_type == QType::A);
9360 }
9361 BOOST_CHECK_EQUAL(queriesCount, 5);
9362}
9363
405a26bd
RG
9364BOOST_AUTO_TEST_CASE(test_dnssec_validation_additional_without_rrsig) {
9365 /*
9366 We get a record from a secure zone in the additional section, without
9367 the corresponding RRSIG. The record should not be marked as authoritative
9368 and should be correctly validated.
9369 */
9370 std::unique_ptr<SyncRes> sr;
9371 initSR(sr, true);
9372
9373 setDNSSECValidation(sr, DNSSECMode::Process);
9374
9375 primeHints();
9376 const DNSName target("com.");
9377 const DNSName addTarget("nsX.com.");
9378 testkeysset_t keys;
9379
9380 auto luaconfsCopy = g_luaconfs.getCopy();
9381 luaconfsCopy.dsAnchors.clear();
9382 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9383 g_luaconfs.setState(luaconfsCopy);
9384
9385 size_t queriesCount = 0;
9386
18d5b679 9387 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, bool* chained) {
405a26bd
RG
9388 queriesCount++;
9389
9390 if (type == QType::DS || type == QType::DNSKEY) {
9391 if (domain == addTarget) {
9392 DNSName auth(domain);
9393 /* no DS for com, auth will be . */
9394 auth.chopOff();
9395 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys, false);
9396 }
9397 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9398 }
9399 else {
9400 if (domain == target && type == QType::A) {
9401 setLWResult(res, 0, true, false, true);
9402 addRecordToLW(res, target, QType::A, "192.0.2.1");
9403 addRRSIG(keys, res->d_records, DNSName("."), 300);
9404 addRecordToLW(res, addTarget, QType::A, "192.0.2.42", DNSResourceRecord::ADDITIONAL);
9405 /* no RRSIG for the additional record */
9406 return 1;
9407 } else if (domain == addTarget && type == QType::A) {
9408 setLWResult(res, 0, true, false, true);
9409 addRecordToLW(res, addTarget, QType::A, "192.0.2.42");
9410 addRRSIG(keys, res->d_records, DNSName("."), 300);
9411 return 1;
9412 }
9413 }
9414
9415 return 0;
9416 });
9417
9418 vector<DNSRecord> ret;
9419 /* first query for target/A, will pick up the additional record as non-auth / unvalidated */
9420 sr->setDNSSECValidationRequested(false);
9421 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9422 BOOST_CHECK_EQUAL(res, RCode::NoError);
9423 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9424 BOOST_CHECK_EQUAL(ret.size(), 2);
9425 for (const auto& record : ret) {
9426 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9427 }
9428 BOOST_CHECK_EQUAL(queriesCount, 1);
9429
9430 ret.clear();
9431 /* ask for the additional record directly, we should not use
9432 the non-auth one and issue a new query, properly validated */
9433 sr->setDNSSECValidationRequested(true);
9434 res = sr->beginResolve(addTarget, QType(QType::A), QClass::IN, ret);
9435 BOOST_CHECK_EQUAL(res, RCode::NoError);
9436 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9437 BOOST_CHECK_EQUAL(ret.size(), 2);
9438 for (const auto& record : ret) {
9439 BOOST_CHECK(record.d_type == QType::RRSIG || record.d_type == QType::A);
9440 }
9441 BOOST_CHECK_EQUAL(queriesCount, 5);
9442}
9443
f4de85a3
RG
9444BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure) {
9445 /*
9446 Validation is optional, and the first query does not ask for it,
9447 so the answer is negatively cached as Indeterminate.
9448 The second query asks for validation, answer should be marked as
9449 Secure.
9450 */
9451 std::unique_ptr<SyncRes> sr;
9452 initSR(sr, true);
9453
9454 setDNSSECValidation(sr, DNSSECMode::Process);
9455
9456 primeHints();
9457 const DNSName target("com.");
9458 testkeysset_t keys;
9459
9460 auto luaconfsCopy = g_luaconfs.getCopy();
9461 luaconfsCopy.dsAnchors.clear();
9462 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9463 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9464 g_luaconfs.setState(luaconfsCopy);
9465
9466 size_t queriesCount = 0;
9467
18d5b679 9468 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, bool* chained) {
f4de85a3
RG
9469 queriesCount++;
9470
9471 DNSName auth = domain;
9472 auth.chopOff();
9473
9474 if (type == QType::DS || type == QType::DNSKEY) {
9475 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9476 }
9477 else {
9478 setLWResult(res, RCode::NoError, true, false, true);
9479 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9480 addRRSIG(keys, res->d_records, domain, 300);
9481 addNSECRecordToLW(domain, DNSName("z."), { QType::NSEC, QType::RRSIG }, 600, res->d_records);
9482 addRRSIG(keys, res->d_records, domain, 1);
9483 return 1;
9484 }
9485
9486 return 0;
9487 });
9488
9489 vector<DNSRecord> ret;
9490 /* first query does not require validation */
9491 sr->setDNSSECValidationRequested(false);
9492 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9493 BOOST_CHECK_EQUAL(res, RCode::NoError);
9494 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9495 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9496 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9497 /* check that the entry has not been negatively cached */
9498 NegCache::NegCacheEntry ne;
9499 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9500 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9501 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9502 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9503 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9504 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9505 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9506
9507 ret.clear();
9508 /* second one _does_ require validation */
9509 sr->setDNSSECValidationRequested(true);
9510 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9511 BOOST_CHECK_EQUAL(res, RCode::NoError);
9512 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9513 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9514 BOOST_CHECK_EQUAL(queriesCount, 4);
b25712fd
RG
9515 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9516 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9517 BOOST_CHECK_EQUAL(ne.d_validationState, Secure);
9518 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9519 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9520 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 1);
9521 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 1);
f4de85a3
RG
9522}
9523
f5a747bb
RG
9524BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_secure_ds) {
9525 /*
9526 Validation is optional, and the first query does not ask for it,
9527 so the answer is negatively cached as Indeterminate.
9528 The second query asks for validation, answer should be marked as
9529 Secure.
9530 The difference with test_dnssec_validation_from_negcache_secure is
9531 that have one more level here, so we are going to look for the proof
9532 that the DS does not exist for the last level. Since there is no cut,
9533 we should accept the fact that the NSEC denies DS and NS both.
9534 */
9535 std::unique_ptr<SyncRes> sr;
9536 initSR(sr, true);
9537
9538 setDNSSECValidation(sr, DNSSECMode::Process);
9539
9540 primeHints();
9541 const DNSName target("www.com.");
9542 testkeysset_t keys;
9543
9544 auto luaconfsCopy = g_luaconfs.getCopy();
9545 luaconfsCopy.dsAnchors.clear();
9546 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9547 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9548 g_luaconfs.setState(luaconfsCopy);
9549
9550 size_t queriesCount = 0;
9551
18d5b679 9552 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, bool* chained) {
f5a747bb
RG
9553 queriesCount++;
9554
9555 if (type == QType::DS || type == QType::DNSKEY) {
9556 if (domain == target) {
9557 /* there is no cut */
9558 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys, false);
9559 }
9560 return genericDSAndDNSKEYHandler(res, domain, domain, type, keys);
9561 }
9562
9563 return 0;
9564 });
9565
9566 vector<DNSRecord> ret;
9567 /* first query does not require validation */
9568 sr->setDNSSECValidationRequested(false);
9569 int res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9570 BOOST_CHECK_EQUAL(res, RCode::NoError);
9571 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9572 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9573 BOOST_CHECK_EQUAL(queriesCount, 1);
9574
9575 ret.clear();
9576 /* second one _does_ require validation */
9577 sr->setDNSSECValidationRequested(true);
9578 res = sr->beginResolve(target, QType(QType::DS), QClass::IN, ret);
9579 BOOST_CHECK_EQUAL(res, RCode::NoError);
9580 BOOST_CHECK_EQUAL(sr->getValidationState(), Secure);
9581 BOOST_REQUIRE_EQUAL(ret.size(), 4);
9582 BOOST_CHECK_EQUAL(queriesCount, 4);
9583}
9584
f4de85a3
RG
9585BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_insecure) {
9586 /*
9587 Validation is optional, and the first query does not ask for it,
9588 so the answer is negatively cached as Indeterminate.
9589 The second query asks for validation, answer should be marked as
9590 Insecure.
9591 */
9592 std::unique_ptr<SyncRes> sr;
9593 initSR(sr, true);
9594
9595 setDNSSECValidation(sr, DNSSECMode::Process);
9596
9597 primeHints();
9598 const DNSName target("com.");
9599 testkeysset_t keys;
9600
9601 auto luaconfsCopy = g_luaconfs.getCopy();
9602 luaconfsCopy.dsAnchors.clear();
9603 g_luaconfs.setState(luaconfsCopy);
9604
9605 size_t queriesCount = 0;
9606
18d5b679 9607 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, bool* chained) {
f4de85a3
RG
9608 queriesCount++;
9609
9610 DNSName auth = domain;
9611 auth.chopOff();
9612
9613 if (type == QType::DS || type == QType::DNSKEY) {
9614 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9615 }
9616 else {
9617 setLWResult(res, RCode::NoError, true, false, true);
9618 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9619 return 1;
9620 }
9621
9622 return 0;
9623 });
9624
9625 vector<DNSRecord> ret;
9626 /* first query does not require validation */
9627 sr->setDNSSECValidationRequested(false);
9628 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9629 BOOST_CHECK_EQUAL(res, RCode::NoError);
9630 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9631 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9632 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9633 /* check that the entry has not been negatively cached */
9634 NegCache::NegCacheEntry ne;
9635 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9636 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9637 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9638 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9639 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9640 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9641 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9642
9643 ret.clear();
9644 /* second one _does_ require validation */
9645 sr->setDNSSECValidationRequested(true);
9646 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9647 BOOST_CHECK_EQUAL(res, RCode::NoError);
9648 BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure);
9649 BOOST_REQUIRE_EQUAL(ret.size(), 1);
9650 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9651 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9652 BOOST_CHECK_EQUAL(ne.d_validationState, Insecure);
9653 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9654 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0);
9655 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9656 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9657}
9658
9659BOOST_AUTO_TEST_CASE(test_dnssec_validation_from_negcache_bogus) {
9660 /*
9661 Validation is optional, and the first query does not ask for it,
9662 so the answer is negatively cached as Indeterminate.
9663 The second query asks for validation, answer should be marked as
9664 Bogus.
9665 */
9666 std::unique_ptr<SyncRes> sr;
9667 initSR(sr, true);
9668
9669 setDNSSECValidation(sr, DNSSECMode::Process);
9670
9671 primeHints();
9672 const DNSName target("com.");
9673 testkeysset_t keys;
9674
9675 auto luaconfsCopy = g_luaconfs.getCopy();
9676 luaconfsCopy.dsAnchors.clear();
9677 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9678 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9679 g_luaconfs.setState(luaconfsCopy);
9680
9681 size_t queriesCount = 0;
9682
18d5b679 9683 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, bool* chained) {
f4de85a3
RG
9684 queriesCount++;
9685
9686 DNSName auth = domain;
9687 auth.chopOff();
9688
9689 if (type == QType::DS || type == QType::DNSKEY) {
9690 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9691 }
9692 else {
9693 setLWResult(res, RCode::NoError, true, false, true);
9694 addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600);
9695 addRRSIG(keys, res->d_records, domain, 300);
9696 /* no denial */
9697 return 1;
9698 }
9699
9700 return 0;
9701 });
9702
9703 vector<DNSRecord> ret;
9704 /* first query does not require validation */
9705 sr->setDNSSECValidationRequested(false);
9706 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9707 BOOST_CHECK_EQUAL(res, RCode::NoError);
9708 BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
9709 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9710 BOOST_CHECK_EQUAL(queriesCount, 1);
b25712fd
RG
9711 NegCache::NegCacheEntry ne;
9712 BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1);
9713 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9714 BOOST_CHECK_EQUAL(ne.d_validationState, Indeterminate);
9715 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9716 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9717 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9718 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9719
9720 ret.clear();
9721 /* second one _does_ require validation */
9722 sr->setDNSSECValidationRequested(true);
9723 res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9724 BOOST_CHECK_EQUAL(res, RCode::NoError);
9725 BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
9726 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9727 BOOST_CHECK_EQUAL(queriesCount, 4);
b25712fd
RG
9728 BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
9729 BOOST_CHECK_EQUAL(ne.d_validationState, Bogus);
9730 BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1);
9731 BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1);
9732 BOOST_CHECK_EQUAL(ne.DNSSECRecords.records.size(), 0);
9733 BOOST_CHECK_EQUAL(ne.DNSSECRecords.signatures.size(), 0);
f4de85a3
RG
9734}
9735
429ce1da
PL
9736BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
9737 g_lowercaseOutgoing = true;
9738 std::unique_ptr<SyncRes> sr;
9739 initSR(sr);
9740
9741 primeHints();
9742
9743 vector<DNSName> sentOutQnames;
9744
9745 const DNSName target("WWW.POWERDNS.COM");
9746 const DNSName cname("WWW.PowerDNS.org");
9747
18d5b679 9748 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, bool* chained) {
429ce1da
PL
9749
9750 sentOutQnames.push_back(domain);
9751
9752 if (isRootServer(ip)) {
9753 if (domain == target) {
9754 setLWResult(res, 0, false, false, true);
9755 addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800);
9756 addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600);
9757 return 1;
9758 }
9759 if (domain == cname) {
9760 setLWResult(res, 0, false, false, true);
9761 addRecordToLW(res, "powerdns.org.", QType::NS, "pdns-public-ns1.powerdns.org.", DNSResourceRecord::AUTHORITY, 172800);
9762 addRecordToLW(res, "pdns-public-ns1.powerdns.org.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600);
9763 return 1;
9764 }
9765 } else if (ip == ComboAddress("192.0.2.1:53")) {
9766 if (domain == target) {
9767 setLWResult(res, 0, true, false, false);
9768 addRecordToLW(res, domain, QType::CNAME, cname.toString());
9769 return 1;
9770 }
9771 } else if (ip == ComboAddress("192.0.2.2:53")) {
9772 if (domain == cname) {
9773 setLWResult(res, 0, true, false, false);
9774 addRecordToLW(res, domain, QType::A, "127.0.0.1");
9775 return 1;
9776 }
9777 }
9778 return 0;
9779 });
9780
9781 vector<DNSRecord> ret;
9782 int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
9783
9784 BOOST_CHECK_EQUAL(res, RCode::NoError);
9785
9786 BOOST_REQUIRE_EQUAL(ret.size(), 2);
9787 BOOST_CHECK_EQUAL(ret[0].d_content->getZoneRepresentation(), cname.toString());
9788
9789 BOOST_REQUIRE_EQUAL(sentOutQnames.size(), 4);
9790 BOOST_CHECK_EQUAL(sentOutQnames[0].toString(), target.makeLowerCase().toString());
9791 BOOST_CHECK_EQUAL(sentOutQnames[1].toString(), target.makeLowerCase().toString());
9792 BOOST_CHECK_EQUAL(sentOutQnames[2].toString(), cname.makeLowerCase().toString());
9793 BOOST_CHECK_EQUAL(sentOutQnames[3].toString(), cname.makeLowerCase().toString());
9794
9795 g_lowercaseOutgoing = false;
9796}
9797
4d787d30
PL
9798BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
9799 std::unique_ptr<SyncRes> sr;
9800 initSR(sr, true);
9801
9802 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9803
9804 primeHints();
9805 const DNSName target("com.");
9806 testkeysset_t keys, keys2;
9807
9808 auto luaconfsCopy = g_luaconfs.getCopy();
9809 luaconfsCopy.dsAnchors.clear();
9810 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9811 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9812 g_luaconfs.setState(luaconfsCopy);
9813
9814 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9815 generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9816 // But add the existing root key otherwise no RRSIG can be created
9817 auto rootkey = keys.find(g_rootdnsname);
9818 keys2.insert(*rootkey);
9819
18d5b679 9820 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, bool* chained) {
4d787d30
PL
9821 DNSName auth = domain;
9822 auth.chopOff();
9823 if (type == QType::DS || type == QType::DNSKEY) {
9824 if (domain == target) {
9825 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9826 return 0;
9827 }
9828 }
9829 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9830 }
9831 return 0;
9832 });
9833
9834 dsmap_t ds;
9835 auto state = sr->getDSRecords(target, ds, false, 0, false);
9836 BOOST_CHECK_EQUAL(state, Secure);
9837 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9838 for (const auto& i : ds) {
9839 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9840 }
9841}
9842
9843BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) {
9844 std::unique_ptr<SyncRes> sr;
9845 initSR(sr, true);
9846
9847 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9848
9849 primeHints();
9850 const DNSName target("com.");
9851 testkeysset_t keys, keys2, keys3;
9852
9853 auto luaconfsCopy = g_luaconfs.getCopy();
9854 luaconfsCopy.dsAnchors.clear();
9855 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9856 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9857 g_luaconfs.setState(luaconfsCopy);
9858
9859 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9860 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2);
9861 // But add the existing root key otherwise no RRSIG can be created
9862 auto rootkey = keys.find(g_rootdnsname);
9863 keys2.insert(*rootkey);
9864
9865 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3);
9866 // But add the existing root key otherwise no RRSIG can be created
9867 keys3.insert(*rootkey);
9868
18d5b679 9869 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, bool* chained) {
4d787d30
PL
9870 DNSName auth = domain;
9871 auth.chopOff();
9872 if (type == QType::DS || type == QType::DNSKEY) {
9873 if (domain == target) {
9874 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9875 return 0;
9876 }
9877 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9878 return 0;
9879 }
9880 }
9881 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9882 }
9883 return 0;
9884 });
9885
9886 dsmap_t ds;
9887 auto state = sr->getDSRecords(target, ds, false, 0, false);
9888 BOOST_CHECK_EQUAL(state, Secure);
9889 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9890 for (const auto& i : ds) {
9891 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9892 }
9893}
9894
9895BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) {
9896 std::unique_ptr<SyncRes> sr;
9897 initSR(sr, true);
9898
9899 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9900
9901 primeHints();
9902 const DNSName target("com.");
9903 testkeysset_t keys, keys2, keys3;
9904
9905 auto luaconfsCopy = g_luaconfs.getCopy();
9906 luaconfsCopy.dsAnchors.clear();
9907 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9908 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
9909 g_luaconfs.setState(luaconfsCopy);
9910
9911 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9912 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2);
9913 // But add the existing root key otherwise no RRSIG can be created
9914 auto rootkey = keys.find(g_rootdnsname);
9915 keys2.insert(*rootkey);
9916
9917 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3);
9918 // But add the existing root key otherwise no RRSIG can be created
9919 keys3.insert(*rootkey);
9920
18d5b679 9921 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, bool* chained) {
4d787d30
PL
9922 DNSName auth = domain;
9923 auth.chopOff();
9924 if (type == QType::DS || type == QType::DNSKEY) {
9925 if (domain == target) {
9926 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9927 return 0;
9928 }
9929 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) {
9930 return 0;
9931 }
9932 }
9933 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9934 }
9935 return 0;
9936 });
9937
9938 dsmap_t ds;
9939 auto state = sr->getDSRecords(target, ds, false, 0, false);
9940 BOOST_CHECK_EQUAL(state, Secure);
9941 BOOST_REQUIRE_EQUAL(ds.size(), 2);
9942 for (const auto& i : ds) {
9943 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
9944 }
9945}
9946
77cb3d33 9947#ifdef HAVE_BOTAN
4d787d30
PL
9948BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) {
9949 std::unique_ptr<SyncRes> sr;
9950 initSR(sr, true);
9951
9952 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9953
9954 primeHints();
9955 const DNSName target("com.");
9956 testkeysset_t keys, keys2;
9957
9958 auto luaconfsCopy = g_luaconfs.getCopy();
9959 luaconfsCopy.dsAnchors.clear();
9960 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
9961 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys);
9962 g_luaconfs.setState(luaconfsCopy);
9963
9964 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
9965 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
9966 // But add the existing root key otherwise no RRSIG can be created
9967 auto rootkey = keys.find(g_rootdnsname);
9968 keys2.insert(*rootkey);
9969
18d5b679 9970 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, bool* chained) {
4d787d30
PL
9971 DNSName auth = domain;
9972 auth.chopOff();
9973 if (type == QType::DS || type == QType::DNSKEY) {
9974 if (domain == target) {
9975 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
9976 return 0;
9977 }
9978 }
9979 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
9980 }
9981 return 0;
9982 });
9983
9984 dsmap_t ds;
9985 auto state = sr->getDSRecords(target, ds, false, 0, false);
9986 BOOST_CHECK_EQUAL(state, Secure);
9987 BOOST_REQUIRE_EQUAL(ds.size(), 1);
9988 for (const auto& i : ds) {
9989 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384);
9990 }
9991}
9992
9993BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) {
9994 std::unique_ptr<SyncRes> sr;
9995 initSR(sr, true);
9996
9997 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
9998
9999 primeHints();
10000 const DNSName target("com.");
10001 testkeysset_t keys, keys2;
10002
10003 auto luaconfsCopy = g_luaconfs.getCopy();
10004 luaconfsCopy.dsAnchors.clear();
10005 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10006 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys);
10007 g_luaconfs.setState(luaconfsCopy);
10008
10009 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10010 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
10011 // But add the existing root key otherwise no RRSIG can be created
10012 auto rootkey = keys.find(g_rootdnsname);
10013 keys2.insert(*rootkey);
10014
18d5b679 10015 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, bool* chained) {
4d787d30
PL
10016 DNSName auth = domain;
10017 auth.chopOff();
10018 if (type == QType::DS || type == QType::DNSKEY) {
10019 if (domain == target) {
10020 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10021 return 0;
10022 }
10023 }
10024 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10025 }
10026 return 0;
10027 });
10028
10029 dsmap_t ds;
10030 auto state = sr->getDSRecords(target, ds, false, 0, false);
10031 BOOST_CHECK_EQUAL(state, Secure);
10032 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10033 for (const auto& i : ds) {
10034 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256);
10035 }
10036}
10037
10038BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) {
10039 std::unique_ptr<SyncRes> sr;
10040 initSR(sr, true);
10041
10042 setDNSSECValidation(sr, DNSSECMode::ValidateAll);
10043
10044 primeHints();
10045 const DNSName target("com.");
10046 testkeysset_t keys, keys2;
10047
10048 auto luaconfsCopy = g_luaconfs.getCopy();
10049 luaconfsCopy.dsAnchors.clear();
10050 generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors);
10051 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys);
10052 g_luaconfs.setState(luaconfsCopy);
10053
10054 // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo
10055 generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2);
10056 // But add the existing root key otherwise no RRSIG can be created
10057 auto rootkey = keys.find(g_rootdnsname);
10058 keys2.insert(*rootkey);
10059
18d5b679 10060 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, bool* chained) {
4d787d30
PL
10061 DNSName auth = domain;
10062 auth.chopOff();
10063 if (type == QType::DS || type == QType::DNSKEY) {
10064 if (domain == target) {
10065 if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) {
10066 return 0;
10067 }
10068 }
10069 return genericDSAndDNSKEYHandler(res, domain, auth, type, keys);
10070 }
10071 return 0;
10072 });
10073
10074 dsmap_t ds;
10075 auto state = sr->getDSRecords(target, ds, false, 0, false);
10076 BOOST_CHECK_EQUAL(state, Secure);
10077 BOOST_REQUIRE_EQUAL(ds.size(), 1);
10078 for (const auto& i : ds) {
10079 BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST);
10080 }
10081}
21a10e0c 10082#endif // HAVE_BOTAN110
4d787d30 10083
d6e797b8
RG
10084/*
10085// cerr<<"asyncresolve called to ask "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;
10086
648bcbd1 10087- check out of band support
d6e797b8 10088
648bcbd1 10089- check preoutquery
d6e797b8 10090
30ee601a
RG
10091*/
10092
10093BOOST_AUTO_TEST_SUITE_END()