]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-syncres_cc.cc
wip
[thirdparty/pdns.git] / pdns / recursordist / test-syncres_cc.cc
1 #define BOOST_TEST_DYN_LINK
2 #include <boost/test/unit_test.hpp>
3
4 #include "base32.hh"
5 #include "lua-recursor4.hh"
6 #include "root-dnssec.hh"
7 #include "test-syncres_cc.hh"
8
9 RecursorStats g_stats;
10 GlobalStateHolder<LuaConfigItems> g_luaconfs;
11 GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames;
12 GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks;
13 std::unique_ptr<MemRecursorCache> s_RC{nullptr};
14 unsigned int g_numThreads = 1;
15 bool g_lowercaseOutgoing = false;
16
17 /* Fake some required functions we didn't want the trouble to
18 link with */
19 ArgvMap& arg()
20 {
21 static ArgvMap theArg;
22 return theArg;
23 }
24
25 int getMTaskerTID()
26 {
27 return 0;
28 }
29
30 void primeRootNSZones(bool)
31 {
32 }
33
34 bool RecursorLua4::preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret) const
35 {
36 return false;
37 }
38
39 int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstrmLoggers, const std::set<uint16_t>& exportTypes, LWResult* res, bool* chained)
40 {
41 return 0;
42 }
43
44 /* primeHints() is only here for now because it
45 was way too much trouble to link with the real one.
46 We should fix this, empty functions are one thing, but this is
47 bad.
48 */
49
50 #include "root-addresses.hh"
51
52 void primeHints(void)
53 {
54 vector<DNSRecord> nsset;
55 if (!s_RC)
56 s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
57
58 DNSRecord arr, aaaarr, nsrr;
59 nsrr.d_name = g_rootdnsname;
60 arr.d_type = QType::A;
61 aaaarr.d_type = QType::AAAA;
62 nsrr.d_type = QType::NS;
63 arr.d_ttl = aaaarr.d_ttl = nsrr.d_ttl = time(nullptr) + 3600000;
64
65 for (char c = 'a'; c <= 'm'; ++c) {
66 char templ[40];
67 strncpy(templ, "a.root-servers.net.", sizeof(templ) - 1);
68 templ[sizeof(templ) - 1] = '\0';
69 *templ = c;
70 aaaarr.d_name = arr.d_name = DNSName(templ);
71 nsrr.d_content = std::make_shared<NSRecordContent>(DNSName(templ));
72 arr.d_content = std::make_shared<ARecordContent>(ComboAddress(rootIps4[c - 'a']));
73 vector<DNSRecord> aset;
74 aset.push_back(arr);
75 s_RC->replace(time(nullptr), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
76 if (rootIps6[c - 'a'] != NULL) {
77 aaaarr.d_content = std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c - 'a']));
78
79 vector<DNSRecord> aaaaset;
80 aaaaset.push_back(aaaarr);
81 s_RC->replace(time(nullptr), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
82 }
83
84 nsset.push_back(nsrr);
85 }
86 s_RC->replace(time(nullptr), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
87 }
88
89 LuaConfigItems::LuaConfigItems()
90 {
91 for (const auto& dsRecord : rootDSs) {
92 auto ds = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
93 dsAnchors[g_rootdnsname].insert(*ds);
94 }
95 }
96
97 /* Some helpers functions */
98
99 void initSR(bool debug)
100 {
101 g_log.setName("test");
102 g_log.disableSyslog(true);
103
104 if (debug) {
105 g_log.setLoglevel((Logger::Urgency)(6)); // info and up
106 g_log.toConsole(Logger::Info);
107 }
108 else {
109 g_log.setLoglevel(Logger::None);
110 g_log.toConsole(Logger::Error);
111 }
112
113 s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
114
115 SyncRes::s_maxqperq = 50;
116 SyncRes::s_maxtotusec = 1000 * 7000;
117 SyncRes::s_maxdepth = 40;
118 SyncRes::s_maxnegttl = 3600;
119 SyncRes::s_maxbogusttl = 3600;
120 SyncRes::s_maxcachettl = 86400;
121 SyncRes::s_packetcachettl = 3600;
122 SyncRes::s_packetcacheservfailttl = 60;
123 SyncRes::s_serverdownmaxfails = 64;
124 SyncRes::s_serverdownthrottletime = 60;
125 SyncRes::s_doIPv6 = true;
126 SyncRes::s_ecsipv4limit = 24;
127 SyncRes::s_ecsipv6limit = 56;
128 SyncRes::s_ecsipv4cachelimit = 24;
129 SyncRes::s_ecsipv6cachelimit = 56;
130 SyncRes::s_ecscachelimitttl = 0;
131 SyncRes::s_rootNXTrust = true;
132 SyncRes::s_hardenNXD = SyncRes::HardenNXD::DNSSEC;
133 SyncRes::s_minimumTTL = 0;
134 SyncRes::s_minimumECSTTL = 0;
135 SyncRes::s_serverID = "PowerDNS Unit Tests Server ID";
136 SyncRes::clearEDNSLocalSubnets();
137 SyncRes::addEDNSLocalSubnet("0.0.0.0/0");
138 SyncRes::addEDNSLocalSubnet("::/0");
139 SyncRes::clearEDNSRemoteSubnets();
140 SyncRes::clearEDNSDomains();
141 SyncRes::clearDelegationOnly();
142 SyncRes::clearDontQuery();
143 SyncRes::setECSScopeZeroAddress(Netmask("127.0.0.1/32"));
144 SyncRes::s_qnameminimization = false;
145
146 SyncRes::clearNSSpeeds();
147 BOOST_CHECK_EQUAL(SyncRes::getNSSpeedsSize(), 0U);
148 SyncRes::clearEDNSStatuses();
149 BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 0U);
150 SyncRes::clearThrottle();
151 BOOST_CHECK_EQUAL(SyncRes::getThrottledServersSize(), 0U);
152 SyncRes::clearFailedServers();
153 BOOST_CHECK_EQUAL(SyncRes::getFailedServersSize(), 0U);
154
155 SyncRes::clearECSStats();
156
157 auto luaconfsCopy = g_luaconfs.getCopy();
158 luaconfsCopy.dfe.clear();
159 luaconfsCopy.dsAnchors.clear();
160 for (const auto& dsRecord : rootDSs) {
161 auto ds = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsRecord));
162 luaconfsCopy.dsAnchors[g_rootdnsname].insert(*ds);
163 }
164 luaconfsCopy.negAnchors.clear();
165 g_luaconfs.setState(luaconfsCopy);
166
167 g_dnssecmode = DNSSECMode::Off;
168 g_dnssecLOG = debug;
169 g_maxNSEC3Iterations = 2500;
170
171 ::arg().set("version-string", "string reported on version.pdns or version.bind") = "PowerDNS Unit Tests";
172 ::arg().set("rng") = "auto";
173 ::arg().set("entropy-source") = "/dev/urandom";
174 }
175
176 void initSR(std::unique_ptr<SyncRes>& sr, bool dnssec, bool debug, time_t fakeNow)
177 {
178 struct timeval now;
179 if (fakeNow > 0) {
180 now.tv_sec = fakeNow;
181 now.tv_usec = 0;
182 }
183 else {
184 Utility::gettimeofday(&now, 0);
185 }
186
187 initSR(debug);
188
189 sr = std::unique_ptr<SyncRes>(new SyncRes(now));
190 sr->setDoEDNS0(true);
191 if (dnssec) {
192 sr->setDoDNSSEC(dnssec);
193 }
194
195 sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
196
197 SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
198 SyncRes::clearNegCache();
199 }
200
201 void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
202 {
203 sr->setDNSSECValidationRequested(true);
204 g_dnssecmode = mode;
205 }
206
207 void setLWResult(LWResult* res, int rcode, bool aa, bool tc, bool edns, bool validpacket)
208 {
209 res->d_rcode = rcode;
210 res->d_aabit = aa;
211 res->d_tcbit = tc;
212 res->d_haveEDNS = edns;
213 res->d_validpacket = validpacket;
214 }
215
216 void addRecordToLW(LWResult* res, const DNSName& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place, uint32_t ttl)
217 {
218 addRecordToList(res->d_records, name, type, content, place, ttl);
219 }
220
221 void addRecordToLW(LWResult* res, const std::string& name, uint16_t type, const std::string& content, DNSResourceRecord::Place place, uint32_t ttl)
222 {
223 addRecordToLW(res, DNSName(name), type, content, place, ttl);
224 }
225
226 bool isRootServer(const ComboAddress& ip)
227 {
228 if (ip.isIPv4()) {
229 for (size_t idx = 0; idx < rootIps4Count; idx++) {
230 if (ip.toString() == rootIps4[idx]) {
231 return true;
232 }
233 }
234 }
235 else {
236 for (size_t idx = 0; idx < rootIps6Count; idx++) {
237 if (ip.toString() == rootIps6[idx]) {
238 return true;
239 }
240 }
241 }
242
243 return false;
244 }
245
246 void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSName& signQName, uint16_t signQType, uint32_t signTTL, uint32_t sigValidity, RRSIGRecordContent& rrc, const sortedRecords_t& toSign, boost::optional<uint8_t> algo, boost::optional<uint32_t> inception, boost::optional<time_t> now)
247 {
248 if (!now) {
249 now = time(nullptr);
250 }
251 DNSKEYRecordContent drc = dpk.getDNSKEY();
252 const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
253
254 rrc.d_type = signQType;
255 rrc.d_labels = signQName.countLabels() - signQName.isWildcard();
256 rrc.d_originalttl = signTTL;
257 rrc.d_siginception = inception ? *inception : (*now - 10);
258 rrc.d_sigexpire = *now + sigValidity;
259 rrc.d_signer = signer;
260 rrc.d_tag = 0;
261 rrc.d_tag = drc.getTag();
262 rrc.d_algorithm = algo ? *algo : drc.d_algorithm;
263
264 std::string msg = getMessageForRRSET(signQName, rrc, toSign);
265
266 rrc.d_signature = rc->sign(msg);
267 }
268
269 typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent>> testkeysset_t;
270
271 bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken, boost::optional<uint8_t> algo, boost::optional<DNSName> wildcard, boost::optional<time_t> now)
272 {
273 if (records.empty()) {
274 return false;
275 }
276
277 const auto it = keys.find(signer);
278 if (it == keys.cend()) {
279 throw std::runtime_error("No DNSKEY found for " + signer.toLogString() + ", unable to compute the requested RRSIG");
280 }
281
282 size_t recordsCount = records.size();
283 const DNSName& name = records[recordsCount - 1].d_name;
284 const uint16_t type = records[recordsCount - 1].d_type;
285
286 sortedRecords_t recordcontents;
287 for (const auto record : records) {
288 if (record.d_name == name && record.d_type == type) {
289 recordcontents.insert(record.d_content);
290 }
291 }
292
293 RRSIGRecordContent rrc;
294 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, boost::none, now);
295 if (broken) {
296 rrc.d_signature[0] ^= 42;
297 }
298
299 DNSRecord rec;
300 rec.d_type = QType::RRSIG;
301 rec.d_place = records[recordsCount - 1].d_place;
302 rec.d_name = records[recordsCount - 1].d_name;
303 rec.d_ttl = records[recordsCount - 1].d_ttl;
304
305 rec.d_content = std::make_shared<RRSIGRecordContent>(rrc);
306 records.push_back(rec);
307
308 return true;
309 }
310
311 void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records)
312 {
313 const auto it = keys.find(signer);
314 if (it == keys.cend()) {
315 throw std::runtime_error("No DNSKEY found for " + signer.toLogString());
316 }
317
318 DNSRecord rec;
319 rec.d_place = DNSResourceRecord::ANSWER;
320 rec.d_name = signer;
321 rec.d_type = QType::DNSKEY;
322 rec.d_ttl = ttl;
323
324 rec.d_content = std::make_shared<DNSKEYRecordContent>(it->second.first.getDNSKEY());
325 records.push_back(rec);
326 }
327
328 bool addDS(const DNSName& domain, uint32_t ttl, std::vector<DNSRecord>& records, const testkeysset_t& keys, DNSResourceRecord::Place place)
329 {
330 const auto it = keys.find(domain);
331 if (it == keys.cend()) {
332 return false;
333 }
334
335 DNSRecord rec;
336 rec.d_name = domain;
337 rec.d_type = QType::DS;
338 rec.d_place = place;
339 rec.d_ttl = ttl;
340 rec.d_content = std::make_shared<DSRecordContent>(it->second.second);
341
342 records.push_back(rec);
343 return true;
344 }
345
346 void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records)
347 {
348 NSECRecordContent nrc;
349 nrc.d_next = next;
350 for (const auto& type : types) {
351 nrc.set(type);
352 }
353
354 DNSRecord rec;
355 rec.d_name = domain;
356 rec.d_ttl = ttl;
357 rec.d_type = QType::NSEC;
358 rec.d_content = std::make_shared<NSECRecordContent>(std::move(nrc));
359 rec.d_place = DNSResourceRecord::AUTHORITY;
360
361 records.push_back(rec);
362 }
363
364 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, bool optOut)
365 {
366 NSEC3RecordContent nrc;
367 nrc.d_algorithm = 1;
368 nrc.d_flags = optOut ? 1 : 0;
369 nrc.d_iterations = iterations;
370 nrc.d_salt = salt;
371 nrc.d_nexthash = hashedNext;
372 for (const auto& type : types) {
373 nrc.set(type);
374 }
375
376 DNSRecord rec;
377 rec.d_name = hashedName;
378 rec.d_ttl = ttl;
379 rec.d_type = QType::NSEC3;
380 rec.d_content = std::make_shared<NSEC3RecordContent>(std::move(nrc));
381 rec.d_place = DNSResourceRecord::AUTHORITY;
382
383 records.push_back(rec);
384 }
385
386 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, bool optOut)
387 {
388 static const std::string salt = "deadbeef";
389 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
390
391 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, next, salt, iterations, types, ttl, records, optOut);
392 }
393
394 void addNSEC3NarrowRecordToLW(const DNSName& domain, const DNSName& zone, const std::set<uint16_t>& types, uint32_t ttl, std::vector<DNSRecord>& records, unsigned int iterations, bool optOut)
395 {
396 static const std::string salt = "deadbeef";
397 std::string hashed = hashQNameWithSalt(salt, iterations, domain);
398 std::string hashedNext(hashed);
399 incrementHash(hashedNext);
400 decrementHash(hashed);
401
402 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed)) + zone, hashedNext, salt, iterations, types, ttl, records, optOut);
403 }
404
405 void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys)
406 {
407 auto dcke = std::shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::make(algo));
408 dcke->create((algo <= 10) ? 2048 : dcke->getBits());
409 DNSSECPrivateKey dpk;
410 dpk.d_flags = 256;
411 dpk.setKey(dcke);
412 DSRecordContent ds = makeDSFromDNSKey(name, dpk.getDNSKEY(), digest);
413 keys[name] = std::pair<DNSSECPrivateKey, DSRecordContent>(dpk, ds);
414 }
415
416 void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t digest, testkeysset_t& keys, map<DNSName, dsmap_t>& dsAnchors)
417 {
418 generateKeyMaterial(name, algo, digest, keys);
419 dsAnchors[name].insert(keys[name].second);
420 }
421
422 int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys, bool proveCut, boost::optional<time_t> now, bool nsec3, bool optOut)
423 {
424 if (type == QType::DS) {
425 auth.chopOff();
426
427 setLWResult(res, 0, true, false, true);
428
429 if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) {
430 addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, now);
431 }
432 else {
433 addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400);
434
435 /* if the auth zone is signed, we need to provide a secure denial */
436 const auto it = keys.find(auth);
437 if (it != keys.cend()) {
438 /* sign the SOA */
439 addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, now);
440 /* add a NSEC denying the DS */
441 std::set<uint16_t> types = {nsec3 ? QType::NSEC : QType::NSEC3};
442 if (proveCut) {
443 types.insert(QType::NS);
444 }
445
446 if (!nsec3) {
447 addNSECRecordToLW(domain, DNSName("z") + domain, types, 600, res->d_records);
448 }
449 else {
450 addNSEC3UnhashedRecordToLW(domain, auth, (DNSName("z") + domain).toString(), types, 600, res->d_records, 10, optOut);
451 }
452
453 addRRSIG(keys, res->d_records, auth, 300, false, boost::none, boost::none, now);
454 }
455 }
456
457 return 1;
458 }
459
460 if (type == QType::DNSKEY) {
461 setLWResult(res, 0, true, false, true);
462 addDNSKEY(keys, domain, 300, res->d_records);
463 addRRSIG(keys, res->d_records, domain, 300);
464 return 1;
465 }
466
467 return 0;
468 }
469
470 int basicRecordsForQnameMinimization(LWResult* res, const DNSName& domain, int type)
471 {
472 if (domain == DNSName(".") && type == QType::A) {
473 setLWResult(res, 0, true);
474 addRecordToLW(res, DNSName("."), QType::SOA, "a.root-servers.net. nstld.verisign-grs.com. 2019042400 1800 900 604800 86400", DNSResourceRecord::AUTHORITY);
475 return 1;
476 }
477 if (domain == DNSName("com") && type == QType::A) {
478 setLWResult(res, 0, true);
479 addRecordToLW(res, DNSName("com"), QType::NS, "ns1.com", DNSResourceRecord::AUTHORITY);
480 addRecordToLW(res, DNSName("ns1.com"), QType::A, "1.2.3.4", DNSResourceRecord::ADDITIONAL);
481 return 1;
482 }
483 if (domain == DNSName("ns1.com") && type == QType::A) {
484 setLWResult(res, 0, true);
485 addRecordToLW(res, DNSName("ns1.com"), QType::A, "1.2.3.4");
486 return 1;
487 }
488 if (domain == DNSName("powerdns.com") && type == QType::A) {
489 setLWResult(res, 0, true);
490 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com", DNSResourceRecord::AUTHORITY);
491 addRecordToLW(res, DNSName("ns1.powerdns.com"), QType::A, "4.5.6.7", DNSResourceRecord::ADDITIONAL);
492 return 1;
493 }
494 if (domain == DNSName("powerdns.com") && type == QType::NS) {
495 setLWResult(res, 0, true);
496 addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com");
497 addRecordToLW(res, DNSName("ns1.powerdns.com"), QType::A, "4.5.6.7", DNSResourceRecord::ADDITIONAL);
498 return 1;
499 }
500 return 0;
501 }