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