root/trunk/pdns/pdns/dbdnsseckeeper.cc @ 1975

Revision 1975, 9.2 KB (checked in by ahu, 2 years ago)

turns out that for each signature, we consulted the database because we ignored the cache. Amazing what numbers we got anyhow!

Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2001 - 2011  PowerDNS.COM BV
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
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18
19#include "dnsseckeeper.hh"
20#include "dnssecinfra.hh"
21#include "ueberbackend.hh"
22#include "statbag.hh"
23#include <iostream>
24#include <boost/foreach.hpp>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <fstream>
28#include <boost/algorithm/string.hpp>
29#include <boost/format.hpp>
30#include <boost/assign/std/vector.hpp> // for 'operator+=()'
31#include <boost/assign/list_inserter.hpp>
32
33
34using namespace boost::assign;
35#include "namespaces.hh"
36using namespace boost;
37
38__thread DNSSECKeeper::keycache_t* DNSSECKeeper::t_keycache;
39DNSSECKeeper::metacache_t DNSSECKeeper::s_metacache;
40pthread_mutex_t DNSSECKeeper::s_metacachelock = PTHREAD_MUTEX_INITIALIZER;
41
42bool DNSSECKeeper::isSecuredZone(const std::string& zone) 
43{
44  if(isPresigned(zone))
45    return true;
46         
47  keycache_t::const_iterator iter = t_keycache->find(zone);
48  if(iter != t_keycache->end() && iter->d_ttd > (unsigned int)time(0)) { 
49    if(iter->d_keys.empty())
50      return false;
51    else
52      return true;
53  }
54  else
55    ; 
56 
57  keyset_t keys = getKeys(zone, true);
58 
59  BOOST_FOREACH(keyset_t::value_type& val, keys) {
60    if(val.second.active) {
61      return true;
62    }
63  }
64  return false;
65}
66
67bool DNSSECKeeper::isPresigned(const std::string& name)
68{
69  string meta;
70  getFromMeta(name, "PRESIGNED", meta);
71  return meta=="1";
72}
73
74void DNSSECKeeper::addKey(const std::string& name, bool keyOrZone, int algorithm, int bits, bool active)
75{
76  if(!bits) {
77    if(algorithm <= 10)
78      bits = keyOrZone ? 2048 : 1024;
79    else {
80      if(algorithm == 12 || algorithm == 13)
81        bits = 256;
82      else if(algorithm == 14)
83        bits = 384;
84      else {
85        throw runtime_error("Can't guess key size for algoritm "+lexical_cast<string>(algorithm));
86      }
87    }
88  }
89  DNSSECPrivateKey dspk;
90  shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(algorithm)); // defaults to RSA for now, could be smart w/algorithm! XXX FIXME
91  dpk->create(bits);
92  dspk.setKey(dpk);
93  dspk.d_algorithm = algorithm;
94  dspk.d_flags = keyOrZone ? 257 : 256;
95  addKey(name, dspk, active);
96}
97
98void DNSSECKeeper::clearCaches(const std::string& name)
99{
100  t_keycache->erase(name); // should this be broadcast in some way?
101 
102  Lock l(&s_metacachelock);
103  pair<metacache_t::iterator, metacache_t::iterator> range = s_metacache.equal_range(name);
104  while(range.first != range.second)
105    s_metacache.erase(range.first++);
106}
107
108
109void DNSSECKeeper::addKey(const std::string& name, const DNSSECPrivateKey& dpk, bool active)
110{
111  clearCaches(name);
112  DNSBackend::KeyData kd;
113  kd.flags = dpk.d_flags; // the dpk doesn't get stored, only they key part
114  kd.active = active;
115  kd.content = dpk.getKey()->convertToISC();
116 // now store it
117  d_keymetadb.addDomainKey(name, kd);
118}
119
120
121static bool keyCompareByKindAndID(const DNSSECKeeper::keyset_t::value_type& a, const DNSSECKeeper::keyset_t::value_type& b)
122{
123  return make_pair(!a.second.keyOrZone, a.second.id) <
124         make_pair(!b.second.keyOrZone, b.second.id);
125}
126
127DNSSECPrivateKey DNSSECKeeper::getKeyById(const std::string& zname, unsigned int id)
128{ 
129  vector<DNSBackend::KeyData> keys;
130  d_keymetadb.getDomainKeys(zname, 0, keys);
131  BOOST_FOREACH(const DNSBackend::KeyData& kd, keys) {
132    if(kd.id != id) 
133      continue;
134   
135    DNSSECPrivateKey dpk;
136    DNSKEYRecordContent dkrc;
137    dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
138    dpk.d_flags = kd.flags;
139    dpk.d_algorithm = dkrc.d_algorithm;
140   
141    if(dpk.d_algorithm == 5 && getNSEC3PARAM(zname)) {
142      dpk.d_algorithm += 2;
143    }
144   
145    return dpk;   
146  }
147  throw runtime_error("Can't find a key with id "+lexical_cast<string>(id)+" for zone '"+zname+"'");
148}
149
150
151void DNSSECKeeper::removeKey(const std::string& zname, unsigned int id)
152{
153  clearCaches(zname);
154  d_keymetadb.removeDomainKey(zname, id);
155}
156
157void DNSSECKeeper::deactivateKey(const std::string& zname, unsigned int id)
158{
159  clearCaches(zname);
160  d_keymetadb.deactivateDomainKey(zname, id);
161}
162
163void DNSSECKeeper::activateKey(const std::string& zname, unsigned int id)
164{
165  clearCaches(zname);
166  d_keymetadb.activateDomainKey(zname, id);
167}
168
169
170void DNSSECKeeper::getFromMeta(const std::string& zname, const std::string& key, std::string& value)
171{
172  value.clear();
173  unsigned int now = time(0);
174  {
175    Lock l(&s_metacachelock); 
176   
177    metacache_t::const_iterator iter = s_metacache.find(tie(zname, key));
178    if(iter != s_metacache.end() && iter->d_ttd > now) {
179      value = iter->d_value;
180      return;
181    }
182  }
183  vector<string> meta;
184  d_keymetadb.getDomainMetadata(zname, key, meta);
185  if(!meta.empty())
186    value=*meta.begin();
187   
188  METACacheEntry nce;
189  nce.d_domain=zname;
190  nce.d_ttd = now+60;
191  nce.d_key= key;
192  nce.d_value = value;
193  { 
194    Lock l(&s_metacachelock);
195    replacing_insert(s_metacache, nce);
196  }
197}
198
199bool DNSSECKeeper::getNSEC3PARAM(const std::string& zname, NSEC3PARAMRecordContent* ns3p, bool* narrow)
200{
201  string value;
202  getFromMeta(zname, "NSEC3PARAM", value);
203  if(value.empty()) // "no NSEC3"
204    return false;
205     
206  if(ns3p) {
207    NSEC3PARAMRecordContent* tmp=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, value));
208    *ns3p = *tmp;
209    delete tmp;
210  }
211  if(narrow) {
212    getFromMeta(zname, "NSEC3NARROW", value);
213    *narrow = (value=="1");
214  }
215 
216 
217  return true;
218}
219
220void DNSSECKeeper::setNSEC3PARAM(const std::string& zname, const NSEC3PARAMRecordContent& ns3p, const bool& narrow)
221{
222  clearCaches(zname);
223  string descr = ns3p.getZoneRepresentation();
224  vector<string> meta;
225  meta.push_back(descr);
226  d_keymetadb.setDomainMetadata(zname, "NSEC3PARAM", meta);
227 
228  meta.clear();
229  if(narrow)
230    meta.push_back("1");
231  d_keymetadb.setDomainMetadata(zname, "NSEC3NARROW", meta);
232}
233
234void DNSSECKeeper::unsetNSEC3PARAM(const std::string& zname)
235{
236  clearCaches(zname);
237  d_keymetadb.setDomainMetadata(zname, "NSEC3PARAM", vector<string>());
238}
239
240
241void DNSSECKeeper::setPresigned(const std::string& zname)
242{
243  clearCaches(zname);
244  vector<string> meta;
245  meta.push_back("1");
246  d_keymetadb.setDomainMetadata(zname, "PRESIGNED", meta);
247}
248
249void DNSSECKeeper::unsetPresigned(const std::string& zname)
250{
251  clearCaches(zname);
252  d_keymetadb.setDomainMetadata(zname, "PRESIGNED", vector<string>());
253}
254
255
256DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const std::string& zone, boost::tribool allOrKeyOrZone) 
257{
258  unsigned int now = time(0);
259  keycache_t::const_iterator iter = t_keycache->find(zone);
260   
261  if(iter != t_keycache->end() && iter->d_ttd > now) { 
262    keyset_t ret;
263    BOOST_FOREACH(const keyset_t::value_type& value, iter->d_keys) {
264      if(boost::indeterminate(allOrKeyOrZone) || allOrKeyOrZone == value.second.keyOrZone)
265        ret.push_back(value);
266    }
267    return ret;
268  }
269   
270  keyset_t retkeyset, allkeyset;
271  vector<UeberBackend::KeyData> dbkeyset;
272 
273  d_keymetadb.getDomainKeys(zone, 0, dbkeyset);
274 
275  BOOST_FOREACH(UeberBackend::KeyData& kd, dbkeyset) 
276  {
277    DNSSECPrivateKey dpk;
278
279    DNSKEYRecordContent dkrc;
280    dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
281    dpk.d_flags = kd.flags;
282    dpk.d_algorithm = dkrc.d_algorithm;
283    if(dpk.d_algorithm == 5 && getNSEC3PARAM(zone))
284      dpk.d_algorithm+=2;
285   
286    KeyMetaData kmd;
287
288    kmd.active = kd.active;
289    kmd.keyOrZone = (kd.flags == 257);
290    kmd.id = kd.id;
291   
292    if(boost::indeterminate(allOrKeyOrZone) || allOrKeyOrZone == kmd.keyOrZone)
293      retkeyset.push_back(make_pair(dpk, kmd));
294    allkeyset.push_back(make_pair(dpk, kmd));
295  }
296  sort(retkeyset.begin(), retkeyset.end(), keyCompareByKindAndID);
297  sort(allkeyset.begin(), allkeyset.end(), keyCompareByKindAndID);
298 
299  KeyCacheEntry kce;
300  kce.d_domain=zone;
301  kce.d_keys = allkeyset;
302  kce.d_ttd = now + 30;
303  replacing_insert(*t_keycache, kce);
304 
305  return retkeyset;
306}
307
308void DNSSECKeeper::secureZone(const std::string& name, int algorithm)
309{
310  clearCaches(name); // just to be sure ;)
311  addKey(name, true, algorithm);
312}
313
314bool DNSSECKeeper::getPreRRSIGs(DNSBackend& db, const std::string& signer, const std::string& qname, const QType& qtype, 
315        DNSPacketWriter::Place signPlace, vector<DNSResourceRecord>& rrsigs)
316{
317  // cerr<<"Doing DB lookup for precomputed RRSIGs for '"<<qname<<"'"<<endl;
318        db.lookup(QType(QType::RRSIG), qname);
319        DNSResourceRecord rr;
320        while(db.get(rr)) { 
321                // cerr<<"Considering for '"<<qtype.getName()<<"' RRSIG '"<<rr.content<<"'\n";
322                if(boost::starts_with(rr.content, qtype.getName()+" ")) {
323                        // cerr<<"Got it"<<endl;
324                        rr.d_place = (DNSResourceRecord::Place)signPlace;
325                        rrsigs.push_back(rr);
326                }
327                else ; // cerr<<"Skipping!"<<endl;
328        }
329        return true;
330}
Note: See TracBrowser for help on using the browser.