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