]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dbdnsseckeeper.cc
rec: Don't shadow variables
[thirdparty/pdns.git] / pdns / dbdnsseckeeper.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "dnsseckeeper.hh"
26 #include "dnssecinfra.hh"
27 #include "ueberbackend.hh"
28 #include "statbag.hh"
29 #include <iostream>
30
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <fstream>
34 #include <boost/algorithm/string.hpp>
35 #include <boost/format.hpp>
36 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
37 #include <boost/assign/list_inserter.hpp>
38 #include "base32.hh"
39 #include "base64.hh"
40 #include "cachecleaner.hh"
41 #include "arguments.hh"
42
43
44 using namespace boost::assign;
45 #include "namespaces.hh"
46
47
48 DNSSECKeeper::keycache_t DNSSECKeeper::s_keycache;
49 DNSSECKeeper::metacache_t DNSSECKeeper::s_metacache;
50 pthread_rwlock_t DNSSECKeeper::s_metacachelock = PTHREAD_RWLOCK_INITIALIZER;
51 pthread_rwlock_t DNSSECKeeper::s_keycachelock = PTHREAD_RWLOCK_INITIALIZER;
52 AtomicCounter DNSSECKeeper::s_ops;
53 time_t DNSSECKeeper::s_last_prune;
54
55 bool DNSSECKeeper::doesDNSSEC()
56 {
57 return d_keymetadb->doesDNSSEC();
58 }
59
60 bool DNSSECKeeper::isSecuredZone(const DNSName& zone)
61 {
62 if(isPresigned(zone))
63 return true;
64
65 keyset_t keys = getKeys(zone); // does the cache
66
67 for(keyset_t::value_type& val : keys) {
68 if(val.second.active) {
69 return true;
70 }
71 }
72 return false;
73 }
74
75 bool DNSSECKeeper::isPresigned(const DNSName& name)
76 {
77 string meta;
78 getFromMeta(name, "PRESIGNED", meta);
79 return meta=="1";
80 }
81
82 bool DNSSECKeeper::addKey(const DNSName& name, bool setSEPBit, int algorithm, int64_t& id, int bits, bool active)
83 {
84 if(!bits) {
85 if(algorithm <= 10)
86 throw runtime_error("Creating an algorithm " +std::to_string(algorithm)+" ("+algorithm2name(algorithm)+") key requires the size (in bits) to be passed.");
87 else {
88 if(algorithm == 12 || algorithm == 13 || algorithm == 15) // GOST, ECDSAP256SHA256, ED25519
89 bits = 256;
90 else if(algorithm == 14) // ECDSAP384SHA384
91 bits = 384;
92 else if(algorithm == 16) // ED448
93 bits = 456;
94 else {
95 throw runtime_error("Can not guess key size for algorithm "+std::to_string(algorithm));
96 }
97 }
98 }
99 DNSSECPrivateKey dspk;
100 shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(algorithm));
101 try{
102 dpk->create(bits);
103 } catch (std::runtime_error error){
104 throw runtime_error("The algorithm does not support the given bit size.");
105 }
106 dspk.setKey(dpk);
107 dspk.d_algorithm = algorithm;
108 dspk.d_flags = setSEPBit ? 257 : 256;
109 return addKey(name, dspk, id, active);
110 }
111
112 void DNSSECKeeper::clearAllCaches() {
113 {
114 WriteLock l(&s_keycachelock);
115 s_keycache.clear();
116 }
117 WriteLock l(&s_metacachelock);
118 s_metacache.clear();
119 }
120
121 void DNSSECKeeper::clearCaches(const DNSName& name)
122 {
123 {
124 WriteLock l(&s_keycachelock);
125 s_keycache.erase(name);
126 }
127 WriteLock l(&s_metacachelock);
128 pair<metacache_t::iterator, metacache_t::iterator> range = s_metacache.equal_range(tie(name));
129 while(range.first != range.second)
130 s_metacache.erase(range.first++);
131 }
132
133
134 bool DNSSECKeeper::addKey(const DNSName& name, const DNSSECPrivateKey& dpk, int64_t& id, bool active)
135 {
136 clearCaches(name);
137 DNSBackend::KeyData kd;
138 kd.flags = dpk.d_flags; // the dpk doesn't get stored, only they key part
139 kd.active = active;
140 kd.content = dpk.getKey()->convertToISC();
141 // now store it
142 return d_keymetadb->addDomainKey(name, kd, id);
143 }
144
145
146 static bool keyCompareByKindAndID(const DNSSECKeeper::keyset_t::value_type& a, const DNSSECKeeper::keyset_t::value_type& b)
147 {
148 return make_pair(!a.second.keyType, a.second.id) <
149 make_pair(!b.second.keyType, b.second.id);
150 }
151
152 DNSSECPrivateKey DNSSECKeeper::getKeyById(const DNSName& zname, unsigned int id)
153 {
154 vector<DNSBackend::KeyData> keys;
155 d_keymetadb->getDomainKeys(zname, keys);
156 for(const DNSBackend::KeyData& kd : keys) {
157 if(kd.id != id)
158 continue;
159
160 DNSSECPrivateKey dpk;
161 DNSKEYRecordContent dkrc;
162 dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
163 dpk.d_flags = kd.flags;
164 dpk.d_algorithm = dkrc.d_algorithm;
165
166 if(dpk.d_algorithm == 5 && getNSEC3PARAM(zname)) {
167 dpk.d_algorithm += 2;
168 }
169
170 return dpk;
171 }
172 throw runtime_error("Can't find a key with id "+std::to_string(id)+" for zone '"+zname.toString()+"'");
173 }
174
175
176 bool DNSSECKeeper::removeKey(const DNSName& zname, unsigned int id)
177 {
178 clearCaches(zname);
179 return d_keymetadb->removeDomainKey(zname, id);
180 }
181
182 bool DNSSECKeeper::deactivateKey(const DNSName& zname, unsigned int id)
183 {
184 clearCaches(zname);
185 return d_keymetadb->deactivateDomainKey(zname, id);
186 }
187
188 bool DNSSECKeeper::activateKey(const DNSName& zname, unsigned int id)
189 {
190 clearCaches(zname);
191 return d_keymetadb->activateDomainKey(zname, id);
192 }
193
194
195 void DNSSECKeeper::getFromMeta(const DNSName& zname, const std::string& key, std::string& value)
196 {
197 static int ttl = ::arg().asNum("domain-metadata-cache-ttl");
198 value.clear();
199 unsigned int now = time(0);
200
201 if(!((++s_ops) % 100000)) {
202 cleanup();
203 }
204
205 if (ttl > 0) {
206 ReadLock l(&s_metacachelock);
207
208 metacache_t::const_iterator iter = s_metacache.find(tie(zname, key));
209 if(iter != s_metacache.end() && iter->d_ttd > now) {
210 value = iter->d_value;
211 return;
212 }
213 }
214 vector<string> meta;
215 d_keymetadb->getDomainMetadata(zname, key, meta);
216 if(!meta.empty())
217 value=*meta.begin();
218
219 if (ttl > 0) {
220 METACacheEntry nce;
221 nce.d_domain=zname;
222 nce.d_ttd = now + ttl;
223 nce.d_key= key;
224 nce.d_value = value;
225 {
226 WriteLock l(&s_metacachelock);
227 replacing_insert(s_metacache, nce);
228 }
229 }
230 }
231
232 void DNSSECKeeper::getSoaEdit(const DNSName& zname, std::string& value)
233 {
234 static const string soaEdit(::arg()["default-soa-edit"]);
235 static const string soaEditSigned(::arg()["default-soa-edit-signed"]);
236
237 if (isPresigned(zname)) {
238 // SOA editing on a presigned zone never makes sense
239 return;
240 }
241
242 getFromMeta(zname, "SOA-EDIT", value);
243
244 if ((!soaEdit.empty() || !soaEditSigned.empty()) && value.empty()) {
245 if (!soaEditSigned.empty() && isSecuredZone(zname))
246 value=soaEditSigned;
247 if (value.empty())
248 value=soaEdit;
249 }
250
251 return;
252 }
253
254 uint64_t DNSSECKeeper::dbdnssecCacheSizes(const std::string& str)
255 {
256 if(str=="meta-cache-size") {
257 ReadLock l(&s_metacachelock);
258 return s_metacache.size();
259 }
260 else if(str=="key-cache-size") {
261 ReadLock l(&s_keycachelock);
262 return s_keycache.size();
263 }
264 return (uint64_t)-1;
265 }
266
267 bool DNSSECKeeper::getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* ns3p, bool* narrow)
268 {
269 string value;
270 getFromMeta(zname, "NSEC3PARAM", value);
271 if(value.empty()) { // "no NSEC3"
272 return false;
273 }
274
275 static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
276 if(ns3p) {
277 *ns3p = NSEC3PARAMRecordContent(value);
278 if (ns3p->d_iterations > maxNSEC3Iterations) {
279 ns3p->d_iterations = maxNSEC3Iterations;
280 L<<Logger::Error<<"Number of NSEC3 iterations for zone '"<<zname<<"' is above 'max-nsec3-iterations'. Value adjusted to: "<<maxNSEC3Iterations<<endl;
281 }
282 if (ns3p->d_algorithm != 1) {
283 L<<Logger::Error<<"Invalid hash algorithm for NSEC3: '"<<std::to_string(ns3p->d_algorithm)<<"', setting to 1 for zone '"<<zname<<"'."<<endl;
284 ns3p->d_algorithm = 1;
285 }
286 }
287 if(narrow) {
288 getFromMeta(zname, "NSEC3NARROW", value);
289 *narrow = (value=="1");
290 }
291 return true;
292 }
293
294 /*
295 * Check is the provided NSEC3PARAM record is something we can work with
296 *
297 * \param ns3p NSEC3PARAMRecordContent to check
298 * \param msg string to fill with an error message
299 * \return true on valid, false otherwise
300 */
301 bool DNSSECKeeper::checkNSEC3PARAM(const NSEC3PARAMRecordContent& ns3p, string& msg)
302 {
303 static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
304 bool ret = true;
305 if (ns3p.d_iterations > maxNSEC3Iterations) {
306 msg += "Number of NSEC3 iterations is above 'max-nsec3-iterations'.";
307 ret = false;
308 }
309
310 if (ns3p.d_algorithm != 1) {
311 if (!ret)
312 msg += ' ';
313 msg += "Invalid hash algorithm for NSEC3: '"+std::to_string(ns3p.d_algorithm)+"', the only valid value is '1'.";
314 ret = false;
315 }
316
317 return ret;
318 }
319
320 bool DNSSECKeeper::setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& ns3p, const bool& narrow)
321 {
322 string error_msg = "";
323 if (!checkNSEC3PARAM(ns3p, error_msg))
324 throw runtime_error("NSEC3PARAMs provided for zone '"+zname.toString()+"' are invalid: " + error_msg);
325
326 clearCaches(zname);
327 string descr = ns3p.getZoneRepresentation();
328 vector<string> meta;
329 meta.push_back(descr);
330 if (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", meta)) {
331 meta.clear();
332
333 if(narrow)
334 meta.push_back("1");
335
336 return d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", meta);
337 }
338 return false;
339 }
340
341 bool DNSSECKeeper::unsetNSEC3PARAM(const DNSName& zname)
342 {
343 clearCaches(zname);
344 return (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", vector<string>()) && d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", vector<string>()));
345 }
346
347
348 bool DNSSECKeeper::setPresigned(const DNSName& zname)
349 {
350 clearCaches(zname);
351 vector<string> meta;
352 meta.push_back("1");
353 return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", meta);
354 }
355
356 bool DNSSECKeeper::unsetPresigned(const DNSName& zname)
357 {
358 clearCaches(zname);
359 return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", vector<string>());
360 }
361
362 /**
363 * Add domainmetadata to allow publishing CDS records for zone zname
364 *
365 * @param zname DNSName of the zone
366 * @param digestAlgos string with comma-separated numbers that describe the
367 * used digest algorithms. This is copied to the database
368 * verbatim
369 * @return true if the data was inserted, false otherwise
370 */
371 bool DNSSECKeeper::setPublishCDS(const DNSName& zname, const string& digestAlgos)
372 {
373 clearCaches(zname);
374 vector<string> meta;
375 meta.push_back(digestAlgos);
376 return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDS", meta);
377 }
378
379 /**
380 * Remove domainmetadata to stop publishing CDS records for zone zname
381 *
382 * @param zname DNSName of the zone
383 * @return true if the operation was successful, false otherwise
384 */
385 bool DNSSECKeeper::unsetPublishCDS(const DNSName& zname)
386 {
387 clearCaches(zname);
388 return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDS", vector<string>());
389 }
390
391 /**
392 * Add domainmetadata to allow publishing CDNSKEY records.for zone zname
393 *
394 * @param zname DNSName of the zone
395 * @return true if the data was inserted, false otherwise
396 */
397 bool DNSSECKeeper::setPublishCDNSKEY(const DNSName& zname)
398 {
399 clearCaches(zname);
400 vector<string> meta;
401 meta.push_back("1");
402 return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDNSKEY", meta);
403 }
404
405 /**
406 * Remove domainmetadata to stop publishing CDNSKEY records for zone zname
407 *
408 * @param zname DNSName of the zone
409 * @return true if the operation was successful, false otherwise
410 */
411 bool DNSSECKeeper::unsetPublishCDNSKEY(const DNSName& zname)
412 {
413 clearCaches(zname);
414 return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDNSKEY", vector<string>());
415 }
416
417 /**
418 * Returns all keys that are used to sign the DNSKEY RRSet in a zone
419 *
420 * @param zname DNSName of the zone
421 * @return a keyset_t with all keys that are used to sign the DNSKEY
422 * RRSet (these are the entrypoint(s) to the zone)
423 */
424 DNSSECKeeper::keyset_t DNSSECKeeper::getEntryPoints(const DNSName& zname)
425 {
426 DNSSECKeeper::keyset_t ret;
427 DNSSECKeeper::keyset_t keys = getKeys(zname);
428
429 for(auto const &keymeta : keys)
430 if(keymeta.second.keyType == KSK || keymeta.second.keyType == CSK)
431 ret.push_back(keymeta);
432 return ret;
433 }
434
435 DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const DNSName& zone, bool useCache)
436 {
437 static int ttl = ::arg().asNum("dnssec-key-cache-ttl");
438 unsigned int now = time(0);
439
440 if(!((++s_ops) % 100000)) {
441 cleanup();
442 }
443
444 if (useCache && ttl > 0) {
445 ReadLock l(&s_keycachelock);
446 keycache_t::const_iterator iter = s_keycache.find(zone);
447
448 if(iter != s_keycache.end() && iter->d_ttd > now) {
449 keyset_t ret;
450 for(const keyset_t::value_type& value : iter->d_keys)
451 ret.push_back(value);
452 return ret;
453 }
454 }
455
456 keyset_t retkeyset;
457 vector<DNSBackend::KeyData> dbkeyset;
458
459 d_keymetadb->getDomainKeys(zone, dbkeyset);
460
461 // Determine the algorithms that have a KSK/ZSK split
462 set<uint8_t> algoSEP, algoNoSEP;
463 vector<uint8_t> algoHasSeparateKSK;
464 for(const DNSBackend::KeyData &keydata : dbkeyset) {
465 DNSSECPrivateKey dpk;
466 DNSKEYRecordContent dkrc;
467
468 dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, keydata.content)));
469
470 if(keydata.active) {
471 if(keydata.flags == 257)
472 algoSEP.insert(dkrc.d_algorithm);
473 else
474 algoNoSEP.insert(dkrc.d_algorithm);
475 }
476 }
477 set_intersection(algoSEP.begin(), algoSEP.end(), algoNoSEP.begin(), algoNoSEP.end(), std::back_inserter(algoHasSeparateKSK));
478
479 for(DNSBackend::KeyData& kd : dbkeyset)
480 {
481 DNSSECPrivateKey dpk;
482 DNSKEYRecordContent dkrc;
483
484 dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
485
486 dpk.d_flags = kd.flags;
487 dpk.d_algorithm = dkrc.d_algorithm;
488 if(dpk.d_algorithm == 5 && getNSEC3PARAM(zone))
489 dpk.d_algorithm+=2;
490
491 KeyMetaData kmd;
492
493 kmd.active = kd.active;
494 kmd.hasSEPBit = (kd.flags == 257);
495 kmd.id = kd.id;
496
497 if (find(algoHasSeparateKSK.begin(), algoHasSeparateKSK.end(), dpk.d_algorithm) == algoHasSeparateKSK.end())
498 kmd.keyType = CSK;
499 else if(kmd.hasSEPBit)
500 kmd.keyType = KSK;
501 else
502 kmd.keyType = ZSK;
503
504 retkeyset.push_back(make_pair(dpk, kmd));
505 }
506 sort(retkeyset.begin(), retkeyset.end(), keyCompareByKindAndID);
507
508 if (ttl > 0) {
509 KeyCacheEntry kce;
510 kce.d_domain=zone;
511 kce.d_keys = retkeyset;
512 kce.d_ttd = now + ttl;
513 {
514 WriteLock l(&s_keycachelock);
515 replacing_insert(s_keycache, kce);
516 }
517 }
518
519 return retkeyset;
520 }
521
522 bool DNSSECKeeper::checkKeys(const DNSName& zone)
523 {
524 vector<DNSBackend::KeyData> dbkeyset;
525 d_keymetadb->getDomainKeys(zone, dbkeyset);
526
527 for(const DNSBackend::KeyData &keydata : dbkeyset) {
528 DNSKEYRecordContent dkrc;
529 shared_ptr<DNSCryptoKeyEngine> dke(DNSCryptoKeyEngine::makeFromISCString(dkrc, keydata.content));
530 if (!dke->checkKey()) {
531 return false;
532 }
533 }
534
535 return true;
536 }
537
538 bool DNSSECKeeper::getPreRRSIGs(UeberBackend& db, const DNSName& signer, const DNSName& qname,
539 const DNSName& wildcardname, const QType& qtype,
540 DNSResourceRecord::Place signPlace, vector<DNSZoneRecord>& rrsigs, uint32_t signTTL)
541 {
542 // cerr<<"Doing DB lookup for precomputed RRSIGs for '"<<(wildcardname.empty() ? qname : wildcardname)<<"'"<<endl;
543 SOAData sd;
544 if(!db.getSOAUncached(signer, sd)) {
545 DLOG(L<<"Could not get SOA for domain"<<endl);
546 return false;
547 }
548 db.lookup(QType(QType::RRSIG), wildcardname.countLabels() ? wildcardname : qname, NULL, sd.domain_id);
549 DNSZoneRecord rr;
550 while(db.get(rr)) {
551 auto rrsig = getRR<RRSIGRecordContent>(rr.dr);
552 if(rrsig->d_type == qtype.getCode() && rrsig->d_signer==signer) {
553 if (wildcardname.countLabels())
554 rr.dr.d_name = qname;
555 rr.dr.d_place = signPlace;
556 rr.dr.d_ttl = signTTL;
557 rrsigs.push_back(rr);
558 }
559 }
560 return true;
561 }
562
563 bool DNSSECKeeper::TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname)
564 {
565 vector<string> allowed;
566
567 d_keymetadb->getDomainMetadata(zone, "TSIG-ALLOW-AXFR", allowed);
568
569 for(const string& dbkey : allowed) {
570 if(DNSName(dbkey)==keyname)
571 return true;
572 }
573 return false;
574 }
575
576 bool DNSSECKeeper::getTSIGForAccess(const DNSName& zone, const string& master, DNSName* keyname)
577 {
578 vector<string> keynames;
579 d_keymetadb->getDomainMetadata(zone, "AXFR-MASTER-TSIG", keynames);
580 keyname->trimToLabels(0);
581
582 // XXX FIXME this should check for a specific master!
583 for(const string& dbkey : keynames) {
584 *keyname=DNSName(dbkey);
585 return true;
586 }
587 return false;
588 }
589
590 /* Rectifies the zone
591 *
592 * \param zone The zone to rectify
593 * \param error& A string where error messages are added
594 * \param doTransaction Whether or not to wrap the rectify in a transaction
595 */
596 bool DNSSECKeeper::rectifyZone(const DNSName& zone, string& error, bool doTransaction) {
597 if (isPresigned(zone)) {
598 error = "Rectify presigned zone '"+zone.toLogString()+"' is not allowed/necessary.";
599 return false;
600 }
601
602 UeberBackend* B = d_keymetadb;
603 std::unique_ptr<UeberBackend> b;
604
605 if (d_ourDB) {
606 // We don't have a *full* Ueberbackend, just a key-only one.
607 // Let's create one and use it
608 b = std::unique_ptr<UeberBackend>(new UeberBackend());
609 B = b.get();
610 }
611
612 SOAData sd;
613
614 if(!B->getSOAUncached(zone, sd)) {
615 error = "No SOA known for '" + zone.toLogString() + "', is such a zone in the database?";
616 return false;
617 }
618
619 sd.db->list(zone, sd.domain_id);
620
621 DNSResourceRecord rr;
622 set<DNSName> qnames, nsset, dsnames, insnonterm, delnonterm;
623 map<DNSName,bool> nonterm;
624 vector<DNSResourceRecord> rrs;
625
626 while(sd.db->get(rr)) {
627 rr.qname.makeUsLowerCase();
628 if (rr.qtype.getCode())
629 {
630 rrs.push_back(rr);
631 qnames.insert(rr.qname);
632 if(rr.qtype.getCode() == QType::NS && rr.qname != zone)
633 nsset.insert(rr.qname);
634 if(rr.qtype.getCode() == QType::DS)
635 dsnames.insert(rr.qname);
636 }
637 else
638 delnonterm.insert(rr.qname);
639 }
640
641 NSEC3PARAMRecordContent ns3pr;
642 bool narrow;
643 bool haveNSEC3 = getNSEC3PARAM(zone, &ns3pr, &narrow);
644 bool isOptOut = (haveNSEC3 && ns3pr.d_flags);
645
646 set<DNSName> nsec3set;
647 if (haveNSEC3 && !narrow) {
648 for (auto &loopRR: rrs) {
649 bool skip=false;
650 DNSName shorter = loopRR.qname;
651 if (shorter != zone && shorter.chopOff() && shorter != zone) {
652 do {
653 if(nsset.count(shorter)) {
654 skip=true;
655 break;
656 }
657 } while(shorter.chopOff() && shorter != zone);
658 }
659 shorter = loopRR.qname;
660 if(!skip && (loopRR.qtype.getCode() != QType::NS || !isOptOut)) {
661
662 do {
663 if(!nsec3set.count(shorter)) {
664 nsec3set.insert(shorter);
665 }
666 } while(shorter != zone && shorter.chopOff());
667 }
668 }
669 }
670
671 if (doTransaction)
672 sd.db->startTransaction(zone, -1);
673
674 bool realrr=true;
675 bool doent=true;
676 uint32_t maxent = ::arg().asNum("max-ent-entries");
677
678 dononterm:;
679 for (const auto& qname: qnames)
680 {
681 bool auth=true;
682 DNSName ordername;
683 auto shorter(qname);
684
685 if(realrr) {
686 do {
687 if(nsset.count(shorter)) {
688 auth=false;
689 break;
690 }
691 } while(shorter.chopOff());
692 } else {
693 auth=nonterm.find(qname)->second;
694 }
695
696 if(haveNSEC3) // NSEC3
697 {
698 if(!narrow && nsec3set.count(qname)) {
699 ordername=DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, qname)));
700 if(!realrr)
701 auth=true;
702 } else if(!realrr)
703 auth=false;
704 }
705 else if (realrr) // NSEC
706 ordername=qname.makeRelative(zone);
707
708 /*
709 if(g_verbose)
710 cerr<<"'"<<qname<<"' -> '"<< ordername <<"'"<<endl;
711 */
712 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, auth);
713
714 if(realrr)
715 {
716 if (dsnames.count(qname))
717 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, true, QType::DS);
718 if (!auth || nsset.count(qname)) {
719 ordername.clear();
720 if(isOptOut && !dsnames.count(qname))
721 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::NS);
722 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::A);
723 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::AAAA);
724 }
725
726 if(doent)
727 {
728 shorter=qname;
729 while(shorter!=zone && shorter.chopOff())
730 {
731 if(!qnames.count(shorter))
732 {
733 if(!(maxent))
734 {
735 L<<Logger::Warning<<"Zone '"<<zone<<"' has too many empty non terminals."<<endl;
736 insnonterm.clear();
737 delnonterm.clear();
738 doent=false;
739 break;
740 }
741
742 if (!delnonterm.count(shorter) && !nonterm.count(shorter))
743 insnonterm.insert(shorter);
744 else
745 delnonterm.erase(shorter);
746
747 if (!nonterm.count(shorter)) {
748 nonterm.insert(pair<DNSName, bool>(shorter, auth));
749 --maxent;
750 } else if (auth)
751 nonterm[shorter]=true;
752 }
753 }
754 }
755 }
756 }
757
758 if(realrr)
759 {
760 //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
761 if(!insnonterm.empty() || !delnonterm.empty() || !doent)
762 {
763 sd.db->updateEmptyNonTerminals(sd.domain_id, insnonterm, delnonterm, !doent);
764 }
765 if(doent)
766 {
767 realrr=false;
768 qnames.clear();
769 for(const auto& nt : nonterm){
770 qnames.insert(nt.first);
771 }
772 goto dononterm;
773 }
774 }
775
776 if (doTransaction)
777 sd.db->commitTransaction();
778
779 return true;
780 }
781
782 void DNSSECKeeper::cleanup()
783 {
784 struct timeval now;
785 Utility::gettimeofday(&now, 0);
786
787 if(now.tv_sec - s_last_prune > (time_t)(30)) {
788 {
789 WriteLock l(&s_metacachelock);
790 pruneCollection(*this, s_metacache, ::arg().asNum("max-cache-entries"));
791 }
792 {
793 WriteLock l(&s_keycachelock);
794 pruneCollection(*this, s_keycache, ::arg().asNum("max-cache-entries"));
795 }
796 s_last_prune=time(0);
797 }
798 }