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