]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dbdnsseckeeper.cc
snap
[thirdparty/pdns.git] / pdns / dbdnsseckeeper.cc
CommitLineData
882358c8
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
ccc3f9ed 3 Copyright (C) 2001 - 2012 PowerDNS.COM BV
882358c8
BH
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation
8
f782fe38
MH
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
12
882358c8
BH
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 St, Fifth Floor, Boston, MA 02110-1301 USA
21*/
22
870a0fe4
AT
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
c0273500
BH
26#include "dnsseckeeper.hh"
27#include "dnssecinfra.hh"
28#include "ueberbackend.hh"
29#include "statbag.hh"
30#include <iostream>
c0273500
BH
31#include <boost/foreach.hpp>
32#include <sys/stat.h>
33#include <sys/types.h>
34#include <fstream>
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>
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;
18a144ef
BH
50pthread_rwlock_t DNSSECKeeper::s_metacachelock = PTHREAD_RWLOCK_INITIALIZER;
51pthread_rwlock_t DNSSECKeeper::s_keycachelock = PTHREAD_RWLOCK_INITIALIZER;
16f7d28d 52AtomicCounter DNSSECKeeper::s_ops;
157f806e 53time_t DNSSECKeeper::s_last_prune;
d473cb9a 54
675fa24c 55bool DNSSECKeeper::isSecuredZone(const DNSName& zone)
c0273500 56{
d3e7090c 57 if(isPresigned(zone))
d6f3dcdc 58 return true;
157f806e 59
8a95b04c
KM
60 keyset_t keys = getKeys(zone); // does the cache
61
ade1b1e9
BH
62 BOOST_FOREACH(keyset_t::value_type& val, keys) {
63 if(val.second.active) {
64 return true;
65 }
c0273500 66 }
ade1b1e9 67 return false;
c0273500
BH
68}
69
675fa24c 70bool DNSSECKeeper::isPresigned(const DNSName& name)
d3e7090c 71{
9cb28241
BH
72 string meta;
73 getFromMeta(name, "PRESIGNED", meta);
74 return meta=="1";
d3e7090c 75}
c0273500 76
675fa24c 77bool DNSSECKeeper::addKey(const DNSName& name, bool keyOrZone, int algorithm, int bits, bool active)
c0273500 78{
022e5e0b
BH
79 if(!bits) {
80 if(algorithm <= 10)
81 bits = keyOrZone ? 2048 : 1024;
82 else {
59d84dc2 83 if(algorithm == 12 || algorithm == 13 || algorithm == 250) // ECDSA, GOST, ED25519
022e5e0b
BH
84 bits = 256;
85 else if(algorithm == 14)
86 bits = 384;
87 else {
0f4b0d97 88 throw runtime_error("Can't guess key size for algorithm "+lexical_cast<string>(algorithm));
022e5e0b
BH
89 }
90 }
91 }
699e6e37 92 DNSSECPrivateKey dspk;
8d9f38f2 93 shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(algorithm)); // defaults to RSA for now, could be smart w/algorithm! XXX FIXME
699e6e37
BH
94 dpk->create(bits);
95 dspk.setKey(dpk);
96 dspk.d_algorithm = algorithm;
97 dspk.d_flags = keyOrZone ? 257 : 256;
40fe813d 98 return addKey(name, dspk, active);
f7bcc763
BH
99}
100
627d2ca2
PD
101void DNSSECKeeper::clearAllCaches() {
102 {
18a144ef 103 WriteLock l(&s_keycachelock);
627d2ca2
PD
104 s_keycache.clear();
105 }
18a144ef 106 WriteLock l(&s_metacachelock);
627d2ca2
PD
107 s_metacache.clear();
108}
109
675fa24c 110void DNSSECKeeper::clearCaches(const DNSName& name)
5e91adff 111{
40fe813d 112 {
18a144ef 113 WriteLock l(&s_keycachelock);
40fe813d
BH
114 s_keycache.erase(name);
115 }
18a144ef 116 WriteLock l(&s_metacachelock);
0b7d7191 117 pair<metacache_t::iterator, metacache_t::iterator> range = s_metacache.equal_range(tie(name));
d6f3dcdc
BH
118 while(range.first != range.second)
119 s_metacache.erase(range.first++);
5e91adff
BH
120}
121
122
675fa24c 123bool DNSSECKeeper::addKey(const DNSName& name, const DNSSECPrivateKey& dpk, bool active)
f7bcc763 124{
5e91adff 125 clearCaches(name);
c0273500 126 DNSBackend::KeyData kd;
7ddd79a7 127 kd.flags = dpk.d_flags; // the dpk doesn't get stored, only they key part
c0273500 128 kd.active = active;
189bb9d2 129 kd.content = dpk.getKey()->convertToISC();
c0273500 130 // now store it
936eb34a 131 return d_keymetadb->addDomainKey(name, kd) >= 0; // >= 0 == s
c0273500
BH
132}
133
134
135static bool keyCompareByKindAndID(const DNSSECKeeper::keyset_t::value_type& a, const DNSSECKeeper::keyset_t::value_type& b)
136{
137 return make_pair(!a.second.keyOrZone, a.second.id) <
138 make_pair(!b.second.keyOrZone, b.second.id);
139}
140
675fa24c 141DNSSECPrivateKey DNSSECKeeper::getKeyById(const DNSName& zname, unsigned int id)
c0273500 142{
c0273500 143 vector<DNSBackend::KeyData> keys;
936eb34a 144 d_keymetadb->getDomainKeys(zname, 0, keys);
c0273500
BH
145 BOOST_FOREACH(const DNSBackend::KeyData& kd, keys) {
146 if(kd.id != id)
147 continue;
148
149 DNSSECPrivateKey dpk;
699e6e37 150 DNSKEYRecordContent dkrc;
8d9f38f2 151 dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
c0273500 152 dpk.d_flags = kd.flags;
a254438f 153 dpk.d_algorithm = dkrc.d_algorithm;
c0273500 154
a254438f
BH
155 if(dpk.d_algorithm == 5 && getNSEC3PARAM(zname)) {
156 dpk.d_algorithm += 2;
157 }
c0273500
BH
158
159 return dpk;
160 }
675fa24c 161 throw runtime_error("Can't find a key with id "+lexical_cast<string>(id)+" for zone '"+zname.toString()+"'");
c0273500
BH
162}
163
164
675fa24c 165bool DNSSECKeeper::removeKey(const DNSName& zname, unsigned int id)
c0273500 166{
5e91adff 167 clearCaches(zname);
a84a8203 168 return d_keymetadb->removeDomainKey(zname, id);
c0273500
BH
169}
170
675fa24c 171bool DNSSECKeeper::deactivateKey(const DNSName& zname, unsigned int id)
c0273500 172{
5e91adff 173 clearCaches(zname);
a84a8203 174 return d_keymetadb->deactivateDomainKey(zname, id);
c0273500
BH
175}
176
675fa24c 177bool DNSSECKeeper::activateKey(const DNSName& zname, unsigned int id)
c0273500 178{
5e91adff 179 clearCaches(zname);
a84a8203 180 return d_keymetadb->activateDomainKey(zname, id);
c0273500
BH
181}
182
d6f3dcdc 183
675fa24c 184void DNSSECKeeper::getFromMeta(const DNSName& zname, const std::string& key, std::string& value)
c0273500 185{
d6f3dcdc 186 value.clear();
5e91adff 187 unsigned int now = time(0);
157f806e 188
16f7d28d 189 if(!((++s_ops) % 100000)) {
157f806e
PD
190 cleanup();
191 }
192
d473cb9a 193 {
18a144ef 194 ReadLock l(&s_metacachelock);
d473cb9a 195
d6f3dcdc
BH
196 metacache_t::const_iterator iter = s_metacache.find(tie(zname, key));
197 if(iter != s_metacache.end() && iter->d_ttd > now) {
198 value = iter->d_value;
199 return;
d473cb9a 200 }
22c5aa60 201 }
d473cb9a 202 vector<string> meta;
936eb34a 203 d_keymetadb->getDomainMetadata(zname, key, meta);
d6f3dcdc
BH
204 if(!meta.empty())
205 value=*meta.begin();
206
207 METACacheEntry nce;
d473cb9a
BH
208 nce.d_domain=zname;
209 nce.d_ttd = now+60;
d6f3dcdc
BH
210 nce.d_key= key;
211 nce.d_value = value;
212 {
18a144ef 213 WriteLock l(&s_metacachelock);
d6f3dcdc 214 replacing_insert(s_metacache, nce);
d473cb9a 215 }
d6f3dcdc
BH
216}
217
e903706d 218uint64_t DNSSECKeeper::dbdnssecCacheSizes(const std::string& str)
219{
220 if(str=="meta-cache-size") {
221 ReadLock l(&s_metacachelock);
222 return s_metacache.size();
223 }
224 else if(str=="key-cache-size") {
225 ReadLock l(&s_keycachelock);
226 return s_keycache.size();
227 }
228 return (uint64_t)-1;
229}
230
675fa24c 231bool DNSSECKeeper::getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* ns3p, bool* narrow)
d6f3dcdc
BH
232{
233 string value;
234 getFromMeta(zname, "NSEC3PARAM", value);
5935cede 235 if(value.empty()) { // "no NSEC3"
d6f3dcdc 236 return false;
5935cede 237 }
28b66a94
KM
238
239 static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
c0273500 240 if(ns3p) {
d6f3dcdc 241 NSEC3PARAMRecordContent* tmp=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, value));
c0273500
BH
242 *ns3p = *tmp;
243 delete tmp;
28b66a94
KM
244 if (ns3p->d_iterations > maxNSEC3Iterations) {
245 ns3p->d_iterations = maxNSEC3Iterations;
675fa24c 246 L<<Logger::Error<<"Number of NSEC3 iterations for zone '"<<zname.toString()<<"' is above 'max-nsec3-iterations'. Value adjusted to: "<<maxNSEC3Iterations<<endl;
28b66a94 247 }
c0273500 248 }
d6f3dcdc
BH
249 if(narrow) {
250 getFromMeta(zname, "NSEC3NARROW", value);
251 *narrow = (value=="1");
252 }
c0273500
BH
253 return true;
254}
255
675fa24c 256bool DNSSECKeeper::setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& ns3p, const bool& narrow)
c0273500 257{
28b66a94
KM
258 static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
259 if (ns3p.d_iterations > maxNSEC3Iterations)
675fa24c 260 throw runtime_error("Can't set NSEC3PARAM for zone '"+zname.toString()+"': number of NSEC3 iterations is above 'max-nsec3-iterations'");
28b66a94 261
5e91adff 262 clearCaches(zname);
c0273500
BH
263 string descr = ns3p.getZoneRepresentation();
264 vector<string> meta;
265 meta.push_back(descr);
a84a8203
PD
266 if (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", meta)) {
267 meta.clear();
268
269 if(narrow)
270 meta.push_back("1");
271
272 return d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", meta);
273 }
274 return false;
c0273500
BH
275}
276
675fa24c 277bool DNSSECKeeper::unsetNSEC3PARAM(const DNSName& zname)
c0273500 278{
5e91adff 279 clearCaches(zname);
a84a8203 280 return (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", vector<string>()) && d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", vector<string>()));
c0273500
BH
281}
282
283
675fa24c 284bool DNSSECKeeper::setPresigned(const DNSName& zname)
d3e7090c
BH
285{
286 clearCaches(zname);
287 vector<string> meta;
288 meta.push_back("1");
a84a8203 289 return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", meta);
d3e7090c
BH
290}
291
675fa24c 292bool DNSSECKeeper::unsetPresigned(const DNSName& zname)
d3e7090c
BH
293{
294 clearCaches(zname);
a84a8203 295 return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", vector<string>());
d3e7090c
BH
296}
297
298
675fa24c 299DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const DNSName& zone, boost::tribool allOrKeyOrZone, bool useCache)
c0273500 300{
5e91adff 301 unsigned int now = time(0);
157f806e 302
16f7d28d 303 if(!((++s_ops) % 100000)) {
157f806e
PD
304 cleanup();
305 }
306
d8455c78 307 if (useCache) {
18a144ef 308 ReadLock l(&s_keycachelock);
40fe813d
BH
309 keycache_t::const_iterator iter = s_keycache.find(zone);
310
311 if(iter != s_keycache.end() && iter->d_ttd > now) {
312 keyset_t ret;
313 BOOST_FOREACH(const keyset_t::value_type& value, iter->d_keys) {
314 if(boost::indeterminate(allOrKeyOrZone) || allOrKeyOrZone == value.second.keyOrZone)
315 ret.push_back(value);
316 }
317 return ret;
7aff7ead 318 }
40fe813d 319 }
7aff7ead 320 keyset_t retkeyset, allkeyset;
3971cf53 321 vector<DNSBackend::KeyData> dbkeyset;
c0273500 322
936eb34a 323 d_keymetadb->getDomainKeys(zone, 0, dbkeyset);
d473cb9a 324
3971cf53 325 BOOST_FOREACH(DNSBackend::KeyData& kd, dbkeyset)
c0273500
BH
326 {
327 DNSSECPrivateKey dpk;
328
699e6e37 329 DNSKEYRecordContent dkrc;
7df3258b 330
8d9f38f2 331 dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
7df3258b 332
c0273500 333 dpk.d_flags = kd.flags;
a254438f
BH
334 dpk.d_algorithm = dkrc.d_algorithm;
335 if(dpk.d_algorithm == 5 && getNSEC3PARAM(zone))
336 dpk.d_algorithm+=2;
c0273500
BH
337
338 KeyMetaData kmd;
339
340 kmd.active = kd.active;
341 kmd.keyOrZone = (kd.flags == 257);
342 kmd.id = kd.id;
343
344 if(boost::indeterminate(allOrKeyOrZone) || allOrKeyOrZone == kmd.keyOrZone)
7aff7ead
BH
345 retkeyset.push_back(make_pair(dpk, kmd));
346 allkeyset.push_back(make_pair(dpk, kmd));
c0273500 347 }
7aff7ead
BH
348 sort(retkeyset.begin(), retkeyset.end(), keyCompareByKindAndID);
349 sort(allkeyset.begin(), allkeyset.end(), keyCompareByKindAndID);
d473cb9a
BH
350
351 KeyCacheEntry kce;
352 kce.d_domain=zone;
7aff7ead
BH
353 kce.d_keys = allkeyset;
354 kce.d_ttd = now + 30;
40fe813d 355 {
18a144ef 356 WriteLock l(&s_keycachelock);
40fe813d
BH
357 replacing_insert(s_keycache, kce);
358 }
d473cb9a 359
7aff7ead 360 return retkeyset;
c0273500
BH
361}
362
675fa24c 363bool DNSSECKeeper::secureZone(const DNSName& name, int algorithm, int size)
c0273500 364{
5e91adff 365 clearCaches(name); // just to be sure ;)
36758d25 366 return addKey(name, true, algorithm, size);
c0273500 367}
d3e7090c 368
675fa24c
PD
369bool DNSSECKeeper::getPreRRSIGs(UeberBackend& db, const DNSName& signer, const DNSName& qname,
370 const DNSName& wildcardname, const QType& qtype,
232f0877 371 DNSPacketWriter::Place signPlace, vector<DNSResourceRecord>& rrsigs, uint32_t signTTL)
d3e7090c 372{
461a0401 373 vector<DNSResourceRecord> sigs;
675fa24c 374 if(db.getDirectRRSIGs(signer, wildcardname.countLabels() ? wildcardname : qname, qtype, sigs)) {
461a0401 375 BOOST_FOREACH(DNSResourceRecord &rr, sigs) {
461a0401
KM
376 rr.d_place = (DNSResourceRecord::Place)signPlace;
377 rr.ttl = signTTL;
378 rrsigs.push_back(rr);
379 }
380 return true;
381 }
382
f1485b68 383 // cerr<<"Doing DB lookup for precomputed RRSIGs for '"<<(wildcardname.empty() ? qname : wildcardname)<<"'"<<endl;
232f0877 384 SOAData sd;
79ba7763 385 if(!db.getSOAUncached(signer, sd)) {
232f0877
CH
386 DLOG(L<<"Could not get SOA for domain"<<endl);
387 return false;
388 }
675fa24c 389 db.lookup(QType(QType::RRSIG), wildcardname.countLabels() ? wildcardname : qname, NULL, sd.domain_id);
232f0877
CH
390 DNSResourceRecord rr;
391 while(db.get(rr)) {
392 // cerr<<"Considering for '"<<qtype.getName()<<"' RRSIG '"<<rr.content<<"'\n";
393 vector<string> parts;
394 stringtok(parts, rr.content);
675fa24c 395 if(parts[0] == qtype.getName() && DNSName(parts[7])==signer) {
232f0877 396 // cerr<<"Got it"<<endl;
675fa24c 397 if (wildcardname.countLabels())
232f0877
CH
398 rr.qname = qname;
399 rr.d_place = (DNSResourceRecord::Place)signPlace;
400 rr.ttl = signTTL;
401 rrsigs.push_back(rr);
402 }
e125fc69 403 // else cerr<<"Skipping!"<<endl;
232f0877
CH
404 }
405 return true;
d3e7090c 406}
78bcb858 407
675fa24c 408bool DNSSECKeeper::TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname)
78bcb858
BH
409{
410 vector<string> allowed;
411
936eb34a 412 d_keymetadb->getDomainMetadata(zone, "TSIG-ALLOW-AXFR", allowed);
78bcb858
BH
413
414 BOOST_FOREACH(const string& dbkey, allowed) {
675fa24c 415 if(DNSName(dbkey)==keyname)
78bcb858
BH
416 return true;
417 }
418 return false;
419}
29b92d6f 420
675fa24c 421bool DNSSECKeeper::getTSIGForAccess(const DNSName& zone, const string& master, DNSName* keyname)
29b92d6f
BH
422{
423 vector<string> keynames;
936eb34a 424 d_keymetadb->getDomainMetadata(zone, "AXFR-MASTER-TSIG", keynames);
675fa24c 425 keyname->trimToLabels(0);
29b92d6f
BH
426
427 // XXX FIXME this should check for a specific master!
428 BOOST_FOREACH(const string& dbkey, keynames) {
675fa24c 429 *keyname=DNSName(dbkey);
29b92d6f
BH
430 return true;
431 }
432 return false;
433}
157f806e
PD
434
435void DNSSECKeeper::cleanup()
436{
437 struct timeval now;
438 Utility::gettimeofday(&now, 0);
439
440 if(now.tv_sec - s_last_prune > (time_t)(30)) {
441 {
18a144ef 442 WriteLock l(&s_metacachelock);
157f806e
PD
443 pruneCollection(s_metacache, ::arg().asNum("max-cache-entries"));
444 }
445 {
18a144ef 446 WriteLock l(&s_keycachelock);
157f806e
PD
447 pruneCollection(s_keycache, ::arg().asNum("max-cache-entries"));
448 }
449 s_last_prune=time(0);
450 }
627d2ca2 451}