2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "dnsseckeeper.hh"
26 #include "dnssecinfra.hh"
27 #include "ueberbackend.hh"
32 #include <sys/types.h>
34 #include <unordered_map>
35 #include <boost/algorithm/string.hpp>
36 #include <boost/format.hpp>
37 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
38 #include <boost/assign/list_inserter.hpp>
41 #include "cachecleaner.hh"
42 #include "arguments.hh"
45 using namespace boost::assign
;
46 #include "namespaces.hh"
49 SharedLockGuarded
<DNSSECKeeper::keycache_t
> DNSSECKeeper::s_keycache
;
50 SharedLockGuarded
<DNSSECKeeper::metacache_t
> DNSSECKeeper::s_metacache
;
51 int64_t DNSSECKeeper::s_metaCacheCleanActions
= 0;
52 AtomicCounter
DNSSECKeeper::s_ops
;
53 time_t DNSSECKeeper::s_last_prune
;
54 size_t DNSSECKeeper::s_maxEntries
= 0;
56 bool DNSSECKeeper::doesDNSSEC()
58 return d_keymetadb
->doesDNSSEC();
61 bool DNSSECKeeper::isSecuredZone(const DNSName
& zone
, bool useCache
)
63 if(isPresigned(zone
, useCache
))
66 keyset_t keys
= getKeys(zone
); // does the cache
68 for(keyset_t::value_type
& val
: keys
) {
69 if(val
.second
.active
) {
76 bool DNSSECKeeper::isPresigned(const DNSName
& name
, bool useCache
)
80 getFromMeta(name
, "PRESIGNED", meta
);
83 getFromMetaNoCache(name
, "PRESIGNED", meta
);
89 bool DNSSECKeeper::addKey(const DNSName
& name
, bool setSEPBit
, int algorithm
, int64_t& id
, int bits
, bool active
, bool published
)
93 throw runtime_error("Creating an algorithm " +std::to_string(algorithm
)+" ("+algorithm2name(algorithm
)+") key requires the size (in bits) to be passed.");
95 if(algorithm
== DNSSECKeeper::ECCGOST
|| algorithm
== DNSSECKeeper::ECDSA256
|| algorithm
== DNSSECKeeper::ED25519
)
97 else if(algorithm
== DNSSECKeeper::ECDSA384
)
99 else if(algorithm
== DNSSECKeeper::ED448
)
102 throw runtime_error("Can not guess key size for algorithm "+std::to_string(algorithm
));
106 shared_ptr
<DNSCryptoKeyEngine
> dpk(DNSCryptoKeyEngine::make(algorithm
));
109 } catch (const std::runtime_error
& error
){
110 throw runtime_error("The algorithm does not support the given bit size.");
112 DNSSECPrivateKey dspk
;
113 dspk
.setKey(dpk
, setSEPBit
? 257 : 256, algorithm
);
114 return addKey(name
, dspk
, id
, active
, published
) && clearKeyCache(name
);
117 void DNSSECKeeper::clearAllCaches() {
118 s_keycache
.write_lock()->clear();
119 s_metacache
.write_lock()->clear();
122 /* This function never fails, the return value is to simplify call chains
123 elsewhere so we can do mutate<cache> && clear<cache> */
124 bool DNSSECKeeper::clearKeyCache(const DNSName
& name
)
126 s_keycache
.write_lock()->erase(name
);
130 bool DNSSECKeeper::clearMetaCache(const DNSName
& name
)
132 s_metacache
.write_lock()->erase(name
);
133 ++s_metaCacheCleanActions
;
137 void DNSSECKeeper::clearCaches(const DNSName
& name
)
139 (void)clearKeyCache(name
);
140 (void)clearMetaCache(name
);
143 bool DNSSECKeeper::addKey(const DNSName
& name
, const DNSSECPrivateKey
& dpk
, int64_t& id
, bool active
, bool published
)
145 DNSBackend::KeyData kd
;
146 kd
.flags
= dpk
.getFlags(); // the dpk doesn't get stored, only they key part
148 kd
.published
= published
;
149 kd
.content
= dpk
.getKey()->convertToISC();
151 return d_keymetadb
->addDomainKey(name
, kd
, id
) && clearKeyCache(name
);
155 static bool keyCompareByKindAndID(const DNSSECKeeper::keyset_t::value_type
& a
, const DNSSECKeeper::keyset_t::value_type
& b
)
157 return pair(!a
.second
.keyType
, a
.second
.id
) <
158 pair(!b
.second
.keyType
, b
.second
.id
);
161 DNSSECPrivateKey
DNSSECKeeper::getKeyById(const DNSName
& zname
, unsigned int id
)
163 vector
<DNSBackend::KeyData
> keys
;
164 d_keymetadb
->getDomainKeys(zname
, keys
);
165 for(const DNSBackend::KeyData
& kd
: keys
) {
169 DNSKEYRecordContent dkrc
;
170 auto key
= shared_ptr
<DNSCryptoKeyEngine
>(DNSCryptoKeyEngine::makeFromISCString(dkrc
, kd
.content
));
171 DNSSECPrivateKey dpk
;
172 dpk
.setKey(key
, kd
.flags
, dkrc
.d_algorithm
);
176 throw runtime_error("Can't find a key with id "+std::to_string(id
)+" for zone '"+zname
.toLogString()+"'");
180 bool DNSSECKeeper::removeKey(const DNSName
& zname
, unsigned int id
)
182 return d_keymetadb
->removeDomainKey(zname
, id
) && clearKeyCache(zname
);
185 bool DNSSECKeeper::deactivateKey(const DNSName
& zname
, unsigned int id
)
187 return d_keymetadb
->deactivateDomainKey(zname
, id
) && clearKeyCache(zname
);
190 bool DNSSECKeeper::activateKey(const DNSName
& zname
, unsigned int id
)
192 return d_keymetadb
->activateDomainKey(zname
, id
) && clearKeyCache(zname
);
195 bool DNSSECKeeper::unpublishKey(const DNSName
& zname
, unsigned int id
)
197 return d_keymetadb
->unpublishDomainKey(zname
, id
) && clearKeyCache(zname
);
200 bool DNSSECKeeper::publishKey(const DNSName
& zname
, unsigned int id
)
202 return d_keymetadb
->publishDomainKey(zname
, id
) && clearKeyCache(zname
);
205 void DNSSECKeeper::getFromMetaOrDefault(const DNSName
& zname
, const std::string
& key
, std::string
& value
, const std::string
& defaultvalue
)
207 if (getFromMeta(zname
, key
, value
))
210 value
= defaultvalue
;
213 bool DNSSECKeeper::getFromMeta(const DNSName
& zname
, const std::string
& key
, std::string
& value
)
216 if (d_keymetadb
->inTransaction()) {
217 throw runtime_error("DNSSECKeeper::getFromMeta() called after an update from within a transaction.");
222 static int ttl
= ::arg().asNum("zone-metadata-cache-ttl");
224 if(!((++s_ops
) % 100000)) {
229 time_t now
= time(nullptr);
232 bool fromCache
= false;
236 auto metacache
= s_metacache
.read_lock();
237 auto iter
= metacache
->find(zname
);
238 if(iter
!= metacache
->end() && iter
->d_ttd
> now
) {
239 meta
= iter
->d_value
;
243 d_metaCacheCleanAction
= s_metaCacheCleanActions
;
248 d_keymetadb
->getAllDomainMetadata(zname
, meta
);
251 auto iter
= meta
.find(key
);
252 if (iter
!= meta
.end()) {
253 if (!iter
->second
.empty()) {
254 value
= *iter
->second
.begin();
259 if (ttl
&& !fromCache
) {
262 nce
.d_ttd
= now
+ ttl
;
263 nce
.d_value
= std::move(meta
);
265 auto metacache
= s_metacache
.write_lock();
266 if(d_metaCacheCleanAction
!= s_metaCacheCleanActions
) {
269 lruReplacingInsert
<SequencedTag
>(*metacache
, nce
);
276 bool DNSSECKeeper::getFromMetaNoCache(const DNSName
& name
, const std::string
& kind
, std::string
& value
)
278 std::vector
<std::string
> meta
;
279 if (d_keymetadb
->getDomainMetadata(name
, kind
, meta
)) {
281 value
= *meta
.begin();
288 void DNSSECKeeper::getSoaEdit(const DNSName
& zname
, std::string
& value
, bool useCache
)
290 static const string
soaEdit(::arg()["default-soa-edit"]);
291 static const string
soaEditSigned(::arg()["default-soa-edit-signed"]);
293 if (isPresigned(zname
, useCache
)) {
294 // SOA editing on a presigned zone never makes sense
298 getFromMeta(zname
, "SOA-EDIT", value
);
300 if ((!soaEdit
.empty() || !soaEditSigned
.empty()) && value
.empty()) {
301 if (!soaEditSigned
.empty() && isSecuredZone(zname
, useCache
))
310 uint64_t DNSSECKeeper::dbdnssecCacheSizes(const std::string
& str
)
312 if(str
=="meta-cache-size") {
313 return s_metacache
.read_lock()->size();
315 else if(str
=="key-cache-size") {
316 return s_keycache
.read_lock()->size();
321 bool DNSSECKeeper::getNSEC3PARAM(const DNSName
& zname
, NSEC3PARAMRecordContent
* ns3p
, bool* narrow
, bool useCache
)
325 getFromMeta(zname
, "NSEC3PARAM", value
);
328 getFromMetaNoCache(zname
, "NSEC3PARAM", value
);
330 if(value
.empty()) { // "no NSEC3"
334 static int maxNSEC3Iterations
=::arg().asNum("max-nsec3-iterations");
335 if(ns3p
!= nullptr) {
336 *ns3p
= NSEC3PARAMRecordContent(value
);
337 if (ns3p
->d_iterations
> maxNSEC3Iterations
&& !isPresigned(zname
, useCache
)) {
338 ns3p
->d_iterations
= maxNSEC3Iterations
;
339 g_log
<<Logger::Error
<<"Number of NSEC3 iterations for zone '"<<zname
<<"' is above 'max-nsec3-iterations'. Value adjusted to: "<<maxNSEC3Iterations
<<endl
;
341 if (ns3p
->d_algorithm
!= 1) {
342 g_log
<<Logger::Error
<<"Invalid hash algorithm for NSEC3: '"<<std::to_string(ns3p
->d_algorithm
)<<"', setting to 1 for zone '"<<zname
<<"'."<<endl
;
343 ns3p
->d_algorithm
= 1;
346 if(narrow
!= nullptr) {
348 getFromMeta(zname
, "NSEC3NARROW", value
);
351 getFromMetaNoCache(zname
, "NSEC3NARROW", value
);
353 *narrow
= (value
=="1");
359 * Check is the provided NSEC3PARAM record is something we can work with
361 * \param ns3p NSEC3PARAMRecordContent to check
362 * \param msg string to fill with an error message
363 * \return true on valid, false otherwise
365 bool DNSSECKeeper::checkNSEC3PARAM(const NSEC3PARAMRecordContent
& ns3p
, string
& msg
)
367 static int maxNSEC3Iterations
=::arg().asNum("max-nsec3-iterations");
369 if (ns3p
.d_iterations
> maxNSEC3Iterations
) {
370 msg
+= "Number of NSEC3 iterations is above 'max-nsec3-iterations'.";
374 if (ns3p
.d_algorithm
!= 1) {
377 msg
+= "Invalid hash algorithm for NSEC3: '"+std::to_string(ns3p
.d_algorithm
)+"', the only valid value is '1'.";
384 bool DNSSECKeeper::setNSEC3PARAM(const DNSName
& zname
, const NSEC3PARAMRecordContent
& ns3p
, const bool& narrow
)
386 if (d_keymetadb
->inTransaction()) {
390 string error_msg
= "";
391 if (!checkNSEC3PARAM(ns3p
, error_msg
))
392 throw runtime_error("NSEC3PARAMs provided for zone '"+zname
.toLogString()+"' are invalid: " + error_msg
);
394 string descr
= ns3p
.getZoneRepresentation();
396 meta
.push_back(descr
);
397 if (d_keymetadb
->setDomainMetadata(zname
, "NSEC3PARAM", meta
)) {
403 return d_keymetadb
->setDomainMetadata(zname
, "NSEC3NARROW", meta
) && clearMetaCache(zname
);
408 bool DNSSECKeeper::unsetNSEC3PARAM(const DNSName
& zname
)
410 if (d_keymetadb
->inTransaction()) {
414 return (d_keymetadb
->setDomainMetadata(zname
, "NSEC3PARAM", vector
<string
>()) && d_keymetadb
->setDomainMetadata(zname
, "NSEC3NARROW", vector
<string
>())) && clearMetaCache(zname
);
418 bool DNSSECKeeper::setPresigned(const DNSName
& zname
)
420 if (d_keymetadb
->inTransaction()) {
426 return d_keymetadb
->setDomainMetadata(zname
, "PRESIGNED", meta
) && clearMetaCache(zname
);
429 bool DNSSECKeeper::unsetPresigned(const DNSName
& zname
)
431 if (d_keymetadb
->inTransaction()) {
435 return d_keymetadb
->setDomainMetadata(zname
, "PRESIGNED", vector
<string
>()) && clearMetaCache(zname
);
439 * Add domainmetadata to allow publishing CDS records for zone zname
441 * @param zname DNSName of the zone
442 * @param digestAlgos string with comma-separated numbers that describe the
443 * used digest algorithms. This is copied to the database
445 * @return true if the data was inserted, false otherwise
447 bool DNSSECKeeper::setPublishCDS(const DNSName
& zname
, const string
& digestAlgos
)
449 if (d_keymetadb
->inTransaction()) {
454 meta
.push_back(digestAlgos
);
455 return d_keymetadb
->setDomainMetadata(zname
, "PUBLISH-CDS", meta
) && clearMetaCache(zname
);
458 void DNSSECKeeper::getPublishCDS(const DNSName
& zname
, std::string
& value
)
460 getFromMetaOrDefault(zname
, "PUBLISH-CDS", value
, ::arg()["default-publish-cds"]);
464 * Remove domainmetadata to stop publishing CDS records for zone zname
466 * @param zname DNSName of the zone
467 * @return true if the operation was successful, false otherwise
469 bool DNSSECKeeper::unsetPublishCDS(const DNSName
& zname
)
471 if (d_keymetadb
->inTransaction()) {
475 return d_keymetadb
->setDomainMetadata(zname
, "PUBLISH-CDS", vector
<string
>()) && clearMetaCache(zname
);
479 * Add domainmetadata to allow publishing CDNSKEY records.for zone zname
481 * @param zname DNSName of the zone
482 * @return true if the data was inserted, false otherwise
484 bool DNSSECKeeper::setPublishCDNSKEY(const DNSName
& zname
, bool deleteAlg
)
486 if (d_keymetadb
->inTransaction()) {
491 meta
.push_back(deleteAlg
? "0" : "1");
492 return d_keymetadb
->setDomainMetadata(zname
, "PUBLISH-CDNSKEY", meta
) && clearMetaCache(zname
);
495 void DNSSECKeeper::getPublishCDNSKEY(const DNSName
& zname
, std::string
& value
)
497 getFromMetaOrDefault(zname
, "PUBLISH-CDNSKEY", value
, ::arg()["default-publish-cdnskey"]);
501 * Remove domainmetadata to stop publishing CDNSKEY records for zone zname
503 * @param zname DNSName of the zone
504 * @return true if the operation was successful, false otherwise
506 bool DNSSECKeeper::unsetPublishCDNSKEY(const DNSName
& zname
)
508 if (d_keymetadb
->inTransaction()) {
512 return d_keymetadb
->setDomainMetadata(zname
, "PUBLISH-CDNSKEY", vector
<string
>()) && clearMetaCache(zname
);
516 * Returns all keys that are used to sign the DNSKEY RRSet in a zone
518 * @param zname DNSName of the zone
519 * @return a keyset_t with all keys that are used to sign the DNSKEY
520 * RRSet (these are the entrypoint(s) to the zone)
522 DNSSECKeeper::keyset_t
DNSSECKeeper::getEntryPoints(const DNSName
& zname
)
524 DNSSECKeeper::keyset_t ret
;
525 DNSSECKeeper::keyset_t keys
= getKeys(zname
);
527 for(auto const &keymeta
: keys
)
528 if(keymeta
.second
.keyType
== KSK
|| keymeta
.second
.keyType
== CSK
)
529 ret
.push_back(keymeta
);
533 DNSSECKeeper::keyset_t
DNSSECKeeper::getKeys(const DNSName
& zone
, bool useCache
)
535 static int ttl
= ::arg().asNum("dnssec-key-cache-ttl");
536 // coverity[store_truncates_time_t]
537 unsigned int now
= time(nullptr);
539 if(!((++s_ops
) % 100000)) {
543 if (useCache
&& ttl
> 0) {
544 auto keycache
= s_keycache
.read_lock();
545 auto iter
= keycache
->find(zone
);
547 if (iter
!= keycache
->end() && iter
->d_ttd
> now
) {
549 ret
.reserve(iter
->d_keys
.size());
550 for(const keyset_t::value_type
& value
: iter
->d_keys
)
551 ret
.push_back(value
);
557 vector
<DNSBackend::KeyData
> dbkeyset
;
559 d_keymetadb
->getDomainKeys(zone
, dbkeyset
);
561 // Determine the algorithms that have a KSK/ZSK split
562 set
<uint8_t> algoSEP
, algoNoSEP
;
563 vector
<uint8_t> algoHasSeparateKSK
;
564 for(const DNSBackend::KeyData
&keydata
: dbkeyset
) {
565 DNSKEYRecordContent dkrc
;
566 auto key
= shared_ptr
<DNSCryptoKeyEngine
>(DNSCryptoKeyEngine::makeFromISCString(dkrc
, keydata
.content
));
567 DNSSECPrivateKey dpk
;
568 dpk
.setKey(key
, dkrc
.d_algorithm
);
571 if(keydata
.flags
== 257)
572 algoSEP
.insert(dkrc
.d_algorithm
);
574 algoNoSEP
.insert(dkrc
.d_algorithm
);
577 set_intersection(algoSEP
.begin(), algoSEP
.end(), algoNoSEP
.begin(), algoNoSEP
.end(), std::back_inserter(algoHasSeparateKSK
));
578 retkeyset
.reserve(dbkeyset
.size());
580 for(DNSBackend::KeyData
& kd
: dbkeyset
)
582 DNSKEYRecordContent dkrc
;
583 auto key
= shared_ptr
<DNSCryptoKeyEngine
>(DNSCryptoKeyEngine::makeFromISCString(dkrc
, kd
.content
));
584 DNSSECPrivateKey dpk
;
585 dpk
.setKey(key
, kd
.flags
, dkrc
.d_algorithm
);
589 kmd
.active
= kd
.active
;
590 kmd
.published
= kd
.published
;
591 kmd
.hasSEPBit
= (kd
.flags
== 257);
594 if (find(algoHasSeparateKSK
.begin(), algoHasSeparateKSK
.end(), dpk
.getAlgorithm()) == algoHasSeparateKSK
.end())
596 else if(kmd
.hasSEPBit
)
601 retkeyset
.emplace_back(dpk
, kmd
);
603 sort(retkeyset
.begin(), retkeyset
.end(), keyCompareByKindAndID
);
608 kce
.d_keys
= retkeyset
;
609 kce
.d_ttd
= now
+ ttl
;
611 lruReplacingInsert
<SequencedTag
>(*(s_keycache
.write_lock()), kce
);
618 bool DNSSECKeeper::checkKeys(const DNSName
& zone
, std::optional
<std::reference_wrapper
<std::vector
<std::string
>>> errorMessages
)
620 vector
<DNSBackend::KeyData
> dbkeyset
;
621 d_keymetadb
->getDomainKeys(zone
, dbkeyset
);
624 for(const DNSBackend::KeyData
&keydata
: dbkeyset
) {
625 DNSKEYRecordContent dkrc
;
626 auto dke
= DNSCryptoKeyEngine::makeFromISCString(dkrc
, keydata
.content
);
627 retval
= dke
->checkKey(errorMessages
) && retval
;
633 void DNSSECKeeper::getPreRRSIGs(UeberBackend
& db
, vector
<DNSZoneRecord
>& rrs
, uint32_t signTTL
)
639 const auto rr
= *rrs
.rbegin();
643 db
.lookup(QType(QType::RRSIG
), !rr
.wildcardname
.empty() ? rr
.wildcardname
: rr
.dr
.d_name
, rr
.domain_id
);
645 auto rrsig
= getRR
<RRSIGRecordContent
>(dzr
.dr
);
646 if (rrsig
->d_type
== rr
.dr
.d_type
) {
647 if(!rr
.wildcardname
.empty()) {
648 dzr
.dr
.d_name
= rr
.dr
.d_name
;
650 dzr
.dr
.d_place
= rr
.dr
.d_place
;
651 dzr
.dr
.d_ttl
= signTTL
;
653 rrs
.emplace_back(dzr
);
658 bool DNSSECKeeper::TSIGGrantsAccess(const DNSName
& zone
, const DNSName
& keyname
)
660 vector
<string
> allowed
;
662 d_keymetadb
->getDomainMetadata(zone
, "TSIG-ALLOW-AXFR", allowed
);
664 for(const string
& dbkey
: allowed
) {
665 if(DNSName(dbkey
)==keyname
)
671 bool DNSSECKeeper::getTSIGForAccess(const DNSName
& zone
, const ComboAddress
& /* primary */, DNSName
* keyname
)
673 vector
<string
> keynames
;
674 d_keymetadb
->getDomainMetadata(zone
, "AXFR-MASTER-TSIG", keynames
);
675 keyname
->trimToLabels(0);
677 // XXX FIXME this should check for a specific primary!
678 for(const string
& dbkey
: keynames
) {
679 *keyname
=DNSName(dbkey
);
685 bool DNSSECKeeper::unSecureZone(const DNSName
& zone
, string
& error
) {
686 // Not calling isSecuredZone(), as it will return false for zones with zero
688 DNSSECKeeper::keyset_t keyset
=getKeys(zone
);
691 error
= "No keys for zone '" + zone
.toLogString() + "'.";
695 for(auto& key
: keyset
) {
696 deactivateKey(zone
, key
.second
.id
);
697 removeKey(zone
, key
.second
.id
);
700 unsetNSEC3PARAM(zone
);
701 unsetPresigned(zone
);
714 /* Rectifies the zone
716 * \param zone The zone to rectify
717 * \param error& A string where error messages are added
718 * \param info& A string where informational messages are added
719 * \param doTransaction Whether or not to wrap the rectify in a transaction
721 bool DNSSECKeeper::rectifyZone(const DNSName
& zone
, string
& error
, string
& info
, bool doTransaction
) {
722 if (isPresigned(zone
, doTransaction
)) {
723 error
= "Rectify presigned zone '"+zone
.toLogString()+"' is not allowed/necessary.";
727 UeberBackend
* B
= d_keymetadb
;
728 std::unique_ptr
<UeberBackend
> b
;
731 if (!doTransaction
) {
732 error
= "Can not rectify a zone with a new Ueberbackend inside a transaction.";
735 // We don't have a *full* Ueberbackend, just a key-only one.
736 // Let's create one and use it
737 b
= std::make_unique
<UeberBackend
>();
743 if(!B
->getSOAUncached(zone
, sd
)) {
744 error
= "No SOA known for '" + zone
.toLogString() + "', is such a zone in the database?";
748 sd
.db
->list(zone
, sd
.domain_id
);
750 ostringstream infostream
;
751 DNSResourceRecord rr
;
752 set
<DNSName
> qnames
, nsset
, dsnames
, insnonterm
, delnonterm
;
753 std::unordered_map
<DNSName
,bool> nonterm
;
754 vector
<DNSResourceRecord
> rrs
;
755 std::unordered_map
<DNSName
,RecordStatus
> rss
;
757 NSEC3PARAMRecordContent ns3pr
;
758 bool securedZone
= isSecuredZone(zone
, doTransaction
);
759 bool haveNSEC3
= false, isOptOut
= false, narrow
= false;
762 haveNSEC3
= getNSEC3PARAM(zone
, &ns3pr
, &narrow
, doTransaction
);
763 isOptOut
= (haveNSEC3
&& ns3pr
.d_flags
);
766 while(sd
.db
->get(rr
)) {
767 rr
.qname
.makeUsLowerCase();
769 auto res
=rss
.insert({rr
.qname
,{rr
.ordername
, rr
.auth
, rr
.ordername
.empty() != (!securedZone
|| narrow
)}}); // only a set ordername is reliable
770 if (!res
.second
&& !res
.first
->second
.update
) {
771 res
.first
->second
.update
= res
.first
->second
.auth
!= rr
.auth
|| res
.first
->second
.ordername
!= rr
.ordername
;
773 else if ((!securedZone
|| narrow
) && rr
.qname
== zone
) {
774 res
.first
->second
.update
= true;
777 if (rr
.qtype
.getCode())
779 qnames
.insert(rr
.qname
);
780 if(rr
.qtype
.getCode() == QType::NS
&& rr
.qname
!= zone
)
781 nsset
.insert(rr
.qname
);
782 if(rr
.qtype
.getCode() == QType::DS
)
783 dsnames
.insert(rr
.qname
);
784 rrs
.emplace_back(rr
);
787 delnonterm
.insert(std::move(rr
.qname
));
792 infostream
<<"Adding NSEC ordering information for zone '"<<zone
<<"'";
796 infostream
<<"Adding NSEC3 hashed ordering information for zone '"<<zone
<<"'";
799 infostream
<<"Adding NSEC3 opt-out hashed ordering information for zone '"<<zone
<<"'";
802 infostream
<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields for zone '"<<zone
<<"'";
806 infostream
<<"Adding empty non-terminals for non-DNSSEC zone '"<<zone
<<"'";
809 set
<DNSName
> nsec3set
;
810 if (haveNSEC3
&& (!narrow
|| !isOptOut
)) {
811 for (auto &loopRR
: rrs
) {
813 DNSName shorter
= loopRR
.qname
;
814 if (shorter
!= zone
&& shorter
.chopOff() && shorter
!= zone
) {
816 if(nsset
.count(shorter
)) {
820 } while(shorter
.chopOff() && shorter
!= zone
);
822 shorter
= loopRR
.qname
;
823 if(!skip
&& (loopRR
.qtype
.getCode() != QType::NS
|| !isOptOut
)) {
826 if(!nsec3set
.count(shorter
)) {
827 nsec3set
.insert(shorter
);
829 } while(shorter
!= zone
&& shorter
.chopOff());
835 sd
.db
->startTransaction(zone
, -1);
840 uint32_t maxent
= ::arg().asNum("max-ent-entries");
843 std::unordered_map
<DNSName
,RecordStatus
>::const_iterator it
;
844 for (const auto& qname
: qnames
)
852 if(nsset
.count(shorter
)) {
856 } while(shorter
.chopOff());
858 auth
=nonterm
.find(qname
)->second
;
861 if(haveNSEC3
) // NSEC3
863 if(nsec3set
.count(qname
)) {
865 ordername
=DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, qname
)));
866 if(!realrr
&& !isOptOut
)
870 else if (realrr
&& securedZone
) // NSEC
872 ordername
=qname
.makeRelative(zone
);
875 it
= rss
.find(qname
);
876 if(it
== rss
.end() || it
->second
.update
|| it
->second
.auth
!= auth
|| it
->second
.ordername
!= ordername
) {
877 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, qname
, ordername
, auth
);
883 if (dsnames
.count(qname
)) {
884 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, qname
, ordername
, true, QType::DS
);
887 if (!auth
|| nsset
.count(qname
)) {
889 if(isOptOut
&& !dsnames
.count(qname
)){
890 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, qname
, ordername
, false, QType::NS
);
893 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, qname
, ordername
, false, QType::A
);
895 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, qname
, ordername
, false, QType::AAAA
);
902 while(shorter
!=zone
&& shorter
.chopOff())
904 if(!qnames
.count(shorter
))
908 g_log
<<Logger::Warning
<<"Zone '"<<zone
<<"' has too many empty non terminals."<<endl
;
915 if (!delnonterm
.count(shorter
) && !nonterm
.count(shorter
))
916 insnonterm
.insert(shorter
);
918 delnonterm
.erase(shorter
);
920 if (!nonterm
.count(shorter
)) {
921 nonterm
.insert(pair
<DNSName
, bool>(shorter
, auth
));
924 nonterm
[shorter
]=true;
933 //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
934 if(!insnonterm
.empty() || !delnonterm
.empty() || !doent
)
936 sd
.db
->updateEmptyNonTerminals(sd
.domain_id
, insnonterm
, delnonterm
, !doent
);
942 for(const auto& nt
: nonterm
){
943 qnames
.insert(nt
.first
);
950 sd
.db
->commitTransaction();
952 infostream
<<", "<<updates
<<" updates";
953 info
= infostream
.str();
957 void DNSSECKeeper::cleanup()
960 Utility::gettimeofday(&now
, nullptr);
962 if(now
.tv_sec
- s_last_prune
> (time_t)(30)) {
964 pruneCollection
<SequencedTag
>((*s_metacache
.write_lock()), s_maxEntries
);
967 pruneCollection
<SequencedTag
>((*s_keycache
.write_lock()), s_maxEntries
);
969 s_last_prune
= time(nullptr);
973 void DNSSECKeeper::setMaxEntries(size_t maxEntries
)
975 s_maxEntries
= maxEntries
;
976 #if BOOST_VERSION >= 105600
977 s_keycache
.write_lock()->get
<KeyCacheTag
>().reserve(s_maxEntries
);
978 #endif /* BOOST_VERSION >= 105600 */