1 #define BOOST_TEST_DYN_LINK
2 #include <boost/test/unit_test.hpp>
4 #include "aggressive_nsec.hh"
6 #include "lua-recursor4.hh"
7 #include "root-dnssec.hh"
8 #include "rec-taskqueue.hh"
9 #include "test-syncres_cc.hh"
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;
20 pdns::TaskQueue g_test_tasks
;
21 pdns::TaskQueue g_resolve_tasks
;
23 /* Fake some required functions we didn't want the trouble to
27 static ArgvMap theArg
;
35 void BaseLua4::getFeatures(Features
& /* features */)
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
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
49 RecursorLua4::~RecursorLua4()
53 void RecursorLua4::postPrepareContext()
57 void RecursorLua4::postLoad()
61 void RecursorLua4::getFeatures(Features
& /* features */)
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 */)
67 return LWResult::Result::Timeout
;
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
76 #include "root-addresses.hh"
78 bool primeHints(time_t now
)
80 vector
<DNSRecord
> nsset
;
82 g_recCache
= std::make_unique
<MemRecursorCache
>();
84 g_negCache
= std::make_unique
<NegCache
>();
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;
93 for (char c
= 'a'; c
<= 'm'; ++c
) {
95 strncpy(templ
, "a.root-servers.net.", sizeof(templ
) - 1);
96 templ
[sizeof(templ
) - 1] = '\0';
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
;
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'])));
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
);
112 nsset
.push_back(nsrr
);
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
118 LuaConfigItems::LuaConfigItems()
120 for (const auto& dsRecord
: rootDSs
) {
121 auto ds
= std::dynamic_pointer_cast
<DSRecordContent
>(DSRecordContent::make(dsRecord
));
122 dsAnchors
[g_rootdnsname
].insert(*ds
);
126 /* Some helpers functions */
128 void initSR(bool debug
)
130 g_log
.setName("test");
131 g_log
.disableSyslog(true);
134 g_log
.setLoglevel((Logger::Urgency
)(6)); // info and up
135 g_log
.toConsole(Logger::Info
);
138 g_log
.setLoglevel(Logger::None
);
139 g_log
.toConsole(Logger::Error
);
142 MemRecursorCache::s_maxServedStaleExtensions
= 0;
143 NegCache::s_maxServedStaleExtensions
= 0;
144 g_recCache
= std::make_unique
<MemRecursorCache
>();
145 g_negCache
= std::make_unique
<NegCache
>();
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;
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);
198 SyncRes::clearECSStats();
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
);
207 luaconfsCopy
.negAnchors
.clear();
208 g_luaconfs
.setState(luaconfsCopy
);
210 g_dnssecmode
= DNSSECMode::Off
;
211 g_maxNSEC3Iterations
= 2500;
213 g_aggressiveNSECCache
.reset();
214 AggressiveNSECCache::s_maxNSEC3CommonPrefix
= AggressiveNSECCache::s_default_maxNSEC3CommonPrefix
;
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";
223 void initSR(std::unique_ptr
<SyncRes
>& sr
, bool dnssec
, bool debug
, time_t fakeNow
)
227 now
.tv_sec
= fakeNow
;
231 Utility::gettimeofday(&now
, 0);
236 sr
= std::make_unique
<SyncRes
>(now
);
237 sr
->setDoEDNS0(true);
239 sr
->setDoDNSSEC(dnssec
);
242 sr
->setLogMode(debug
== false ? SyncRes::LogNone
: SyncRes::Log
);
244 SyncRes::setDomainMap(std::make_shared
<SyncRes::domainmap_t
>());
248 void setDNSSECValidation(std::unique_ptr
<SyncRes
>& sr
, const DNSSECMode
& mode
)
250 sr
->setDNSSECValidationRequested(true);
254 void setLWResult(LWResult
* res
, int rcode
, bool aa
, bool tc
, bool edns
, bool validpacket
)
256 res
->d_rcode
= rcode
;
259 res
->d_haveEDNS
= edns
;
260 res
->d_validpacket
= validpacket
;
263 void addRecordToLW(LWResult
* res
, const DNSName
& name
, uint16_t type
, const std::string
& content
, DNSResourceRecord::Place place
, uint32_t ttl
)
265 addRecordToList(res
->d_records
, name
, type
, content
, place
, ttl
);
268 void addRecordToLW(LWResult
* res
, const std::string
& name
, uint16_t type
, const std::string
& content
, DNSResourceRecord::Place place
, uint32_t ttl
)
270 addRecordToLW(res
, DNSName(name
), type
, content
, place
, ttl
);
273 bool isRootServer(const ComboAddress
& ip
)
276 for (size_t idx
= 0; idx
< rootIps4
.size(); idx
++) {
277 if (ip
.toString() == rootIps4
[idx
]) {
283 for (size_t idx
= 0; idx
< rootIps6
.size(); idx
++) {
284 if (ip
.toString() == rootIps6
[idx
]) {
293 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
)
298 DNSKEYRecordContent drc
= dpk
.getDNSKEY();
299 const auto& rc
= dpk
.getKey();
301 rrc
.d_type
= signQType
;
302 rrc
.d_labels
= signQName
.countLabels() - (signQName
.isWildcard() ? 1 : 0);
303 rrc
.d_originalttl
= signTTL
;
304 rrc
.d_siginception
= inception
? *inception
: (*now
- 10);
305 rrc
.d_sigexpire
= *now
+ sigValidity
;
306 rrc
.d_signer
= signer
;
307 rrc
.d_tag
= drc
.getTag();
308 rrc
.d_algorithm
= algo
? *algo
: drc
.d_algorithm
;
310 std::string msg
= getMessageForRRSET(signQName
, rrc
, toSign
);
312 rrc
.d_signature
= rc
->sign(msg
);
315 typedef std::unordered_map
<DNSName
, std::pair
<DNSSECPrivateKey
, DSRecordContent
>> testkeysset_t
;
317 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 if (records
.empty()) {
323 const auto it
= keys
.find(signer
);
324 if (it
== keys
.cend()) {
325 throw std::runtime_error("No DNSKEY found for " + signer
.toLogString() + ", unable to compute the requested RRSIG");
328 size_t recordsCount
= records
.size();
329 const DNSName
& name
= records
[recordsCount
- 1].d_name
;
330 const uint16_t type
= records
[recordsCount
- 1].d_type
;
332 sortedRecords_t recordcontents
;
333 for (const auto& record
: records
) {
334 if (record
.d_name
== name
&& record
.d_type
== type
) {
335 recordcontents
.insert(record
.getContent());
339 RRSIGRecordContent rrc
;
340 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 rrc
.d_signature
[0] ^= 42;
346 rec
.d_type
= QType::RRSIG
;
347 rec
.d_place
= records
[recordsCount
- 1].d_place
;
348 rec
.d_name
= records
[recordsCount
- 1].d_name
;
349 rec
.d_ttl
= records
[recordsCount
- 1].d_ttl
;
351 rec
.setContent(std::make_shared
<RRSIGRecordContent
>(rrc
));
352 records
.push_back(rec
);
357 void addDNSKEY(const testkeysset_t
& keys
, const DNSName
& signer
, uint32_t ttl
, std::vector
<DNSRecord
>& records
)
359 const auto it
= keys
.find(signer
);
360 if (it
== keys
.cend()) {
361 throw std::runtime_error("No DNSKEY found for " + signer
.toLogString());
365 rec
.d_place
= DNSResourceRecord::ANSWER
;
367 rec
.d_type
= QType::DNSKEY
;
370 rec
.setContent(std::make_shared
<DNSKEYRecordContent
>(it
->second
.first
.getDNSKEY()));
371 records
.push_back(rec
);
374 bool addDS(const DNSName
& domain
, uint32_t ttl
, std::vector
<DNSRecord
>& records
, const testkeysset_t
& keys
, DNSResourceRecord::Place place
)
376 const auto it
= keys
.find(domain
);
377 if (it
== keys
.cend()) {
383 rec
.d_type
= QType::DS
;
386 rec
.setContent(std::make_shared
<DSRecordContent
>(it
->second
.second
));
388 records
.push_back(rec
);
392 void addNSECRecordToLW(const DNSName
& domain
, const DNSName
& next
, const std::set
<uint16_t>& types
, uint32_t ttl
, std::vector
<DNSRecord
>& records
)
394 NSECRecordContent nrc
;
396 for (const auto& type
: types
) {
403 rec
.d_type
= QType::NSEC
;
404 rec
.setContent(std::make_shared
<NSECRecordContent
>(std::move(nrc
)));
405 rec
.d_place
= DNSResourceRecord::AUTHORITY
;
407 records
.push_back(rec
);
410 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 NSEC3RecordContent nrc
;
414 nrc
.d_flags
= optOut
? 1 : 0;
415 nrc
.d_iterations
= iterations
;
417 nrc
.d_nexthash
= hashedNext
;
418 for (const auto& type
: types
) {
423 rec
.d_name
= hashedName
;
425 rec
.d_type
= QType::NSEC3
;
426 rec
.setContent(std::make_shared
<NSEC3RecordContent
>(std::move(nrc
)));
427 rec
.d_place
= DNSResourceRecord::AUTHORITY
;
429 records
.push_back(rec
);
432 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 static const std::string salt
= "deadbeef";
435 std::string hashed
= hashQNameWithSalt(salt
, iterations
, domain
);
437 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed
)) + zone
, next
, salt
, iterations
, types
, ttl
, records
, optOut
);
440 /* 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 */
441 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 static const std::string salt
= "deadbeef";
444 std::string hashed
= hashQNameWithSalt(salt
, iterations
, domain
);
445 std::string
hashedNext(hashed
);
446 incrementHash(hashedNext
);
448 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed
)) + zone
, hashedNext
, salt
, iterations
, types
, ttl
, records
, optOut
);
451 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 static const std::string salt
= "deadbeef";
454 std::string hashed
= hashQNameWithSalt(salt
, iterations
, domain
);
455 std::string
hashedNext(hashed
);
456 incrementHash(hashedNext
);
457 decrementHash(hashed
);
459 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed
)) + zone
, hashedNext
, salt
, iterations
, types
, ttl
, records
, optOut
);
462 void generateKeyMaterial(const DNSName
& name
, unsigned int algo
, uint8_t digest
, testkeysset_t
& keys
)
464 auto dcke
= std::shared_ptr
<DNSCryptoKeyEngine
>(DNSCryptoKeyEngine::make(algo
));
465 dcke
->create((algo
<= 10) ? 2048 : dcke
->getBits());
466 DNSSECPrivateKey dpk
;
467 dpk
.setKey(dcke
, 256);
468 DSRecordContent ds
= makeDSFromDNSKey(name
, dpk
.getDNSKEY(), digest
);
469 keys
[name
] = std::pair
<DNSSECPrivateKey
, DSRecordContent
>(dpk
, ds
);
472 void generateKeyMaterial(const DNSName
& name
, unsigned int algo
, uint8_t digest
, testkeysset_t
& keys
, map
<DNSName
, dsmap_t
>& dsAnchors
)
474 generateKeyMaterial(name
, algo
, digest
, keys
);
475 dsAnchors
[name
].insert(keys
[name
].second
);
478 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 if (type
== QType::DS
) {
483 setLWResult(res
, 0, true, false, true);
485 if (addDS(domain
, 300, res
->d_records
, keys
, DNSResourceRecord::ANSWER
)) {
486 addRRSIG(keys
, res
->d_records
, auth
, 300, false, boost::none
, boost::none
, now
);
489 addRecordToLW(res
, auth
, QType::SOA
, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY
, 86400);
491 /* if the auth zone is signed, we need to provide a secure denial */
492 const auto it
= keys
.find(auth
);
493 if (it
!= keys
.cend()) {
495 addRRSIG(keys
, res
->d_records
, auth
, 300, false, boost::none
, boost::none
, now
);
496 /* add a NSEC denying the DS */
497 std::set
<uint16_t> types
= {QType::RRSIG
};
499 types
.insert(QType::NS
);
503 addNSECRecordToLW(domain
, DNSName("+") + domain
, types
, 600, res
->d_records
);
506 DNSName
next(DNSName("z") + domain
);
507 next
.makeUsRelative(auth
);
508 addNSEC3UnhashedRecordToLW(domain
, auth
, next
.toString(), types
, 600, res
->d_records
, 10, optOut
);
511 addRRSIG(keys
, res
->d_records
, auth
, 300, false, boost::none
, boost::none
, now
);
515 return LWResult::Result::Success
;
518 if (type
== QType::DNSKEY
) {
519 setLWResult(res
, 0, true, false, true);
520 addDNSKEY(keys
, domain
, 300, res
->d_records
);
521 addRRSIG(keys
, res
->d_records
, domain
, 300, false, boost::none
, boost::none
, now
);
522 return LWResult::Result::Success
;
525 return LWResult::Result::Timeout
;
528 LWResult::Result
basicRecordsForQnameMinimization(LWResult
* res
, const DNSName
& domain
, int type
)
530 if (domain
== DNSName(".") && type
== QType::A
) {
531 setLWResult(res
, 0, true);
532 addRecordToLW(res
, DNSName("."), QType::SOA
, "a.root-servers.net. nstld.verisign-grs.com. 2019042400 1800 900 604800 86400", DNSResourceRecord::AUTHORITY
);
533 return LWResult::Result::Success
;
535 if (domain
== DNSName("com") && type
== QType::A
) {
536 setLWResult(res
, 0, true);
537 addRecordToLW(res
, DNSName("com"), QType::NS
, "ns1.com", DNSResourceRecord::AUTHORITY
);
538 addRecordToLW(res
, DNSName("ns1.com"), QType::A
, "1.2.3.4", DNSResourceRecord::ADDITIONAL
);
539 return LWResult::Result::Success
;
541 if (domain
== DNSName("ns1.com") && type
== QType::A
) {
542 setLWResult(res
, 0, true);
543 addRecordToLW(res
, DNSName("ns1.com"), QType::A
, "1.2.3.4");
544 return LWResult::Result::Success
;
546 if (domain
== DNSName("powerdns.com") && type
== QType::A
) {
547 setLWResult(res
, 0, true);
548 addRecordToLW(res
, domain
, QType::NS
, "ns1.powerdns.com", DNSResourceRecord::AUTHORITY
);
549 addRecordToLW(res
, DNSName("ns1.powerdns.com"), QType::A
, "4.5.6.7", DNSResourceRecord::ADDITIONAL
);
550 return LWResult::Result::Success
;
552 if (domain
== DNSName("powerdns.com") && type
== QType::NS
) {
553 setLWResult(res
, 0, true);
554 addRecordToLW(res
, domain
, QType::NS
, "ns1.powerdns.com");
555 addRecordToLW(res
, DNSName("ns1.powerdns.com"), QType::A
, "4.5.6.7", DNSResourceRecord::ADDITIONAL
);
556 return LWResult::Result::Success
;
558 return LWResult::Result::Timeout
;