1 #define BOOST_TEST_DYN_LINK
2 #include <boost/test/unit_test.hpp>
5 #include "lua-recursor4.hh"
6 #include "root-dnssec.hh"
7 #include "test-syncres_cc.hh"
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;
17 /* Fake some required functions we didn't want the trouble to
21 static ArgvMap theArg
;
30 void primeRootNSZones(bool)
34 bool RecursorLua4::preoutquery(const ComboAddress
& ns
, const ComboAddress
& requestor
, const DNSName
& query
, const QType
& qtype
, bool isTcp
, vector
<DNSRecord
>& res
, int& ret
) const
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
)
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
50 #include "root-addresses.hh"
54 vector
<DNSRecord
> nsset
;
56 s_RC
= std::unique_ptr
<MemRecursorCache
>(new MemRecursorCache());
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;
65 for (char c
= 'a'; c
<= 'm'; ++c
) {
67 strncpy(templ
, "a.root-servers.net.", sizeof(templ
) - 1);
68 templ
[sizeof(templ
) - 1] = '\0';
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
;
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']));
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);
84 nsset
.push_back(nsrr
);
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
89 LuaConfigItems::LuaConfigItems()
91 for (const auto& dsRecord
: rootDSs
) {
92 auto ds
= std::dynamic_pointer_cast
<DSRecordContent
>(DSRecordContent::make(dsRecord
));
93 dsAnchors
[g_rootdnsname
].insert(*ds
);
97 /* Some helpers functions */
99 void initSR(bool debug
)
101 g_log
.setName("test");
102 g_log
.disableSyslog(true);
105 g_log
.setLoglevel((Logger::Urgency
)(6)); // info and up
106 g_log
.toConsole(Logger::Info
);
109 g_log
.setLoglevel(Logger::None
);
110 g_log
.toConsole(Logger::Error
);
113 s_RC
= std::unique_ptr
<MemRecursorCache
>(new MemRecursorCache());
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;
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);
155 SyncRes::clearECSStats();
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
);
164 luaconfsCopy
.negAnchors
.clear();
165 g_luaconfs
.setState(luaconfsCopy
);
167 g_dnssecmode
= DNSSECMode::Off
;
169 g_maxNSEC3Iterations
= 2500;
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";
176 void initSR(std::unique_ptr
<SyncRes
>& sr
, bool dnssec
, bool debug
, time_t fakeNow
)
180 now
.tv_sec
= fakeNow
;
184 Utility::gettimeofday(&now
, 0);
189 sr
= std::unique_ptr
<SyncRes
>(new SyncRes(now
));
190 sr
->setDoEDNS0(true);
192 sr
->setDoDNSSEC(dnssec
);
195 sr
->setLogMode(debug
== false ? SyncRes::LogNone
: SyncRes::Log
);
197 SyncRes::setDomainMap(std::make_shared
<SyncRes::domainmap_t
>());
198 SyncRes::clearNegCache();
201 void setDNSSECValidation(std::unique_ptr
<SyncRes
>& sr
, const DNSSECMode
& mode
)
203 sr
->setDNSSECValidationRequested(true);
207 void setLWResult(LWResult
* res
, int rcode
, bool aa
, bool tc
, bool edns
, bool validpacket
)
209 res
->d_rcode
= rcode
;
212 res
->d_haveEDNS
= edns
;
213 res
->d_validpacket
= validpacket
;
216 void addRecordToLW(LWResult
* res
, const DNSName
& name
, uint16_t type
, const std::string
& content
, DNSResourceRecord::Place place
, uint32_t ttl
)
218 addRecordToList(res
->d_records
, name
, type
, content
, place
, ttl
);
221 void addRecordToLW(LWResult
* res
, const std::string
& name
, uint16_t type
, const std::string
& content
, DNSResourceRecord::Place place
, uint32_t ttl
)
223 addRecordToLW(res
, DNSName(name
), type
, content
, place
, ttl
);
226 bool isRootServer(const ComboAddress
& ip
)
229 for (size_t idx
= 0; idx
< rootIps4Count
; idx
++) {
230 if (ip
.toString() == rootIps4
[idx
]) {
236 for (size_t idx
= 0; idx
< rootIps6Count
; idx
++) {
237 if (ip
.toString() == rootIps6
[idx
]) {
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
)
251 DNSKEYRecordContent drc
= dpk
.getDNSKEY();
252 const std::shared_ptr
<DNSCryptoKeyEngine
> rc
= dpk
.getKey();
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
;
261 rrc
.d_tag
= drc
.getTag();
262 rrc
.d_algorithm
= algo
? *algo
: drc
.d_algorithm
;
264 std::string msg
= getMessageForRRSET(signQName
, rrc
, toSign
);
266 rrc
.d_signature
= rc
->sign(msg
);
269 typedef std::unordered_map
<DNSName
, std::pair
<DNSSECPrivateKey
, DSRecordContent
>> testkeysset_t
;
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
)
273 if (records
.empty()) {
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");
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
;
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
);
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
);
296 rrc
.d_signature
[0] ^= 42;
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
;
305 rec
.d_content
= std::make_shared
<RRSIGRecordContent
>(rrc
);
306 records
.push_back(rec
);
311 void addDNSKEY(const testkeysset_t
& keys
, const DNSName
& signer
, uint32_t ttl
, std::vector
<DNSRecord
>& records
)
313 const auto it
= keys
.find(signer
);
314 if (it
== keys
.cend()) {
315 throw std::runtime_error("No DNSKEY found for " + signer
.toLogString());
319 rec
.d_place
= DNSResourceRecord::ANSWER
;
321 rec
.d_type
= QType::DNSKEY
;
324 rec
.d_content
= std::make_shared
<DNSKEYRecordContent
>(it
->second
.first
.getDNSKEY());
325 records
.push_back(rec
);
328 bool addDS(const DNSName
& domain
, uint32_t ttl
, std::vector
<DNSRecord
>& records
, const testkeysset_t
& keys
, DNSResourceRecord::Place place
)
330 const auto it
= keys
.find(domain
);
331 if (it
== keys
.cend()) {
337 rec
.d_type
= QType::DS
;
340 rec
.d_content
= std::make_shared
<DSRecordContent
>(it
->second
.second
);
342 records
.push_back(rec
);
346 void addNSECRecordToLW(const DNSName
& domain
, const DNSName
& next
, const std::set
<uint16_t>& types
, uint32_t ttl
, std::vector
<DNSRecord
>& records
)
348 NSECRecordContent nrc
;
350 for (const auto& type
: types
) {
357 rec
.d_type
= QType::NSEC
;
358 rec
.d_content
= std::make_shared
<NSECRecordContent
>(std::move(nrc
));
359 rec
.d_place
= DNSResourceRecord::AUTHORITY
;
361 records
.push_back(rec
);
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
)
366 NSEC3RecordContent nrc
;
368 nrc
.d_flags
= optOut
? 1 : 0;
369 nrc
.d_iterations
= iterations
;
371 nrc
.d_nexthash
= hashedNext
;
372 for (const auto& type
: types
) {
377 rec
.d_name
= hashedName
;
379 rec
.d_type
= QType::NSEC3
;
380 rec
.d_content
= std::make_shared
<NSEC3RecordContent
>(std::move(nrc
));
381 rec
.d_place
= DNSResourceRecord::AUTHORITY
;
383 records
.push_back(rec
);
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
)
388 static const std::string salt
= "deadbeef";
389 std::string hashed
= hashQNameWithSalt(salt
, iterations
, domain
);
391 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed
)) + zone
, next
, salt
, iterations
, types
, ttl
, records
, optOut
);
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
)
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
);
402 addNSEC3RecordToLW(DNSName(toBase32Hex(hashed
)) + zone
, hashedNext
, salt
, iterations
, types
, ttl
, records
, optOut
);
405 void generateKeyMaterial(const DNSName
& name
, unsigned int algo
, uint8_t digest
, testkeysset_t
& keys
)
407 auto dcke
= std::shared_ptr
<DNSCryptoKeyEngine
>(DNSCryptoKeyEngine::make(algo
));
408 dcke
->create((algo
<= 10) ? 2048 : dcke
->getBits());
409 DNSSECPrivateKey dpk
;
412 DSRecordContent ds
= makeDSFromDNSKey(name
, dpk
.getDNSKEY(), digest
);
413 keys
[name
] = std::pair
<DNSSECPrivateKey
, DSRecordContent
>(dpk
, ds
);
416 void generateKeyMaterial(const DNSName
& name
, unsigned int algo
, uint8_t digest
, testkeysset_t
& keys
, map
<DNSName
, dsmap_t
>& dsAnchors
)
418 generateKeyMaterial(name
, algo
, digest
, keys
);
419 dsAnchors
[name
].insert(keys
[name
].second
);
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
)
424 if (type
== QType::DS
) {
427 setLWResult(res
, 0, true, false, true);
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
);
433 addRecordToLW(res
, auth
, QType::SOA
, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY
, 86400);
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()) {
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
};
443 types
.insert(QType::NS
);
447 addNSECRecordToLW(domain
, DNSName("z") + domain
, types
, 600, res
->d_records
);
450 addNSEC3UnhashedRecordToLW(domain
, auth
, (DNSName("z") + domain
).toString(), types
, 600, res
->d_records
, 10, optOut
);
453 addRRSIG(keys
, res
->d_records
, auth
, 300, false, boost::none
, boost::none
, now
);
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);
470 int basicRecordsForQnameMinimization(LWResult
* res
, const DNSName
& domain
, int type
)
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
);
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
);
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");
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
);
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
);