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

Revision 1882, 7.9 KB (checked in by ahu, 2 years ago)

properly invalidate keycache on adding a new key - this removes the 'should not happen' error on pdnssec-secure

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;
35using namespace std;
36using namespace boost;
37
38DNSSECKeeper::keycache_t DNSSECKeeper::s_keycache;
39DNSSECKeeper::nseccache_t DNSSECKeeper::s_nseccache;
40pthread_mutex_t DNSSECKeeper::s_nseccachelock = PTHREAD_MUTEX_INITIALIZER;
41pthread_mutex_t DNSSECKeeper::s_keycachelock = PTHREAD_MUTEX_INITIALIZER;
42
43bool DNSSECKeeper::haveActiveKSKFor(const std::string& zone) 
44{
45  {
46    Lock l(&s_keycachelock);
47    keycache_t::const_iterator iter = s_keycache.find(zone);
48    if(iter != s_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
67
68void DNSSECKeeper::addKey(const std::string& name, bool keyOrZone, int algorithm, int bits, bool active)
69{
70  if(!bits)
71    bits = keyOrZone ? 2048 : 1024;
72  DNSSECPrivateKey dpk;
73  dpk.d_key.create(bits); 
74  dpk.d_algorithm = algorithm;
75  dpk.d_flags = keyOrZone ? 257 : 256;
76  addKey(name, dpk, active);
77}
78
79void DNSSECKeeper::clearCaches(const std::string& name)
80{
81  Lock l(&s_keycachelock);
82  s_keycache.erase(name);
83  s_nseccache.erase(name);
84}
85
86
87void DNSSECKeeper::addKey(const std::string& name, const DNSSECPrivateKey& dpk, bool active)
88{
89  clearCaches(name);
90  DNSBackend::KeyData kd;
91  kd.flags = dpk.d_flags; // the dpk doesn't get stored, only they key part
92  kd.active = active;
93  kd.content = dpk.d_key.convertToISC(dpk.d_algorithm);
94 // now store it
95  d_db.addDomainKey(name, kd);
96}
97
98
99static bool keyCompareByKindAndID(const DNSSECKeeper::keyset_t::value_type& a, const DNSSECKeeper::keyset_t::value_type& b)
100{
101  return make_pair(!a.second.keyOrZone, a.second.id) <
102         make_pair(!b.second.keyOrZone, b.second.id);
103}
104
105DNSSECPrivateKey DNSSECKeeper::getKeyById(const std::string& zname, unsigned int id)
106{ 
107  vector<DNSBackend::KeyData> keys;
108  d_db.getDomainKeys(zname, 0, keys);
109  BOOST_FOREACH(const DNSBackend::KeyData& kd, keys) {
110    if(kd.id != id) 
111      continue;
112   
113    DNSSECPrivateKey dpk;
114    DNSKEYRecordContent dkrc = getRSAKeyFromISCString(&dpk.d_key.getContext(), kd.content);
115    dpk.d_flags = kd.flags;
116    dpk.d_algorithm = dkrc.d_algorithm;
117   
118    if(dpk.d_algorithm == 5 && getNSEC3PARAM(zname)) {
119      dpk.d_algorithm += 2;
120    }
121   
122    return dpk;   
123  }
124  throw runtime_error("Can't find a key with id "+lexical_cast<string>(id)+" for zone '"+zname+"'");
125}
126
127
128void DNSSECKeeper::removeKey(const std::string& zname, unsigned int id)
129{
130  clearCaches(zname);
131  d_db.removeDomainKey(zname, id);
132}
133
134void DNSSECKeeper::deactivateKey(const std::string& zname, unsigned int id)
135{
136  clearCaches(zname);
137  d_db.deactivateDomainKey(zname, id);
138}
139
140void DNSSECKeeper::activateKey(const std::string& zname, unsigned int id)
141{
142  clearCaches(zname);
143  d_db.activateDomainKey(zname, id);
144}
145
146bool DNSSECKeeper::getNSEC3PARAM(const std::string& zname, NSEC3PARAMRecordContent* ns3p, bool* narrow)
147{
148  unsigned int now = time(0);
149  {
150    Lock l(&s_nseccachelock); 
151   
152    nseccache_t::const_iterator iter = s_nseccache.find(zname);
153    if(iter != s_nseccache.end() && iter->d_ttd > now)
154    {
155      if(iter->d_nsec3param.empty()) // this says: no NSEC3
156        return false;
157       
158      if(ns3p) {
159        NSEC3PARAMRecordContent* tmp=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, iter->d_nsec3param));
160        *ns3p = *tmp;
161        delete tmp;
162      }
163      if(narrow)
164        *narrow = iter->d_narrow;
165      return true;
166    }
167  }
168  vector<string> meta;
169  d_db.getDomainMetadata(zname, "NSEC3PARAM", meta);
170 
171  NSECCacheEntry nce;
172  nce.d_domain=zname;
173  nce.d_ttd = now+60;
174 
175  if(meta.empty()) {
176    nce.d_nsec3param.clear(); // store 'no nsec3'
177    nce.d_narrow = false;
178    Lock l(&s_nseccachelock);
179    replacing_insert(s_nseccache, nce);
180   
181    return false;
182  }
183  nce.d_nsec3param = *meta.begin();
184 
185  meta.clear();
186  d_db.getDomainMetadata(zname, "NSEC3NARROW", meta);
187  nce.d_narrow = !meta.empty() && meta[0]=="1";
188 
189  if(narrow) {
190    *narrow=nce.d_narrow;
191  }
192 
193  if(ns3p) {
194    string descr = nce.d_nsec3param;
195    reportAllTypes();
196    NSEC3PARAMRecordContent* tmp=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, descr));
197    if(!tmp) {
198      cerr<<"descr: '"<<descr<<"'\n";
199      return false;
200    }
201    *ns3p = *tmp;
202    delete tmp;
203  }
204  Lock l(&s_nseccachelock);
205  replacing_insert(s_nseccache, nce);
206 
207  return true;
208}
209
210void DNSSECKeeper::setNSEC3PARAM(const std::string& zname, const NSEC3PARAMRecordContent& ns3p, const bool& narrow)
211{
212  clearCaches(zname);
213  string descr = ns3p.getZoneRepresentation();
214  vector<string> meta;
215  meta.push_back(descr);
216  d_db.setDomainMetadata(zname, "NSEC3PARAM", meta);
217 
218  meta.clear();
219  if(narrow)
220    meta.push_back("1");
221  d_db.setDomainMetadata(zname, "NSEC3NARROW", meta);
222}
223
224void DNSSECKeeper::unsetNSEC3PARAM(const std::string& zname)
225{
226  clearCaches(zname);
227  d_db.setDomainMetadata(zname, "NSEC3PARAM", vector<string>());
228}
229
230
231DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const std::string& zone, boost::tribool allOrKeyOrZone) 
232{
233  unsigned int now = time(0);
234  {
235    Lock l(&s_keycachelock);
236    keycache_t::const_iterator iter = s_keycache.find(zone);
237   
238    if(iter != s_keycache.end() && iter->d_ttd > now) { 
239      keyset_t ret;
240      BOOST_FOREACH(const keyset_t::value_type& value, iter->d_keys) {
241        if(boost::indeterminate(allOrKeyOrZone) || allOrKeyOrZone == value.second.keyOrZone)
242          ret.push_back(value);
243      }
244      return ret;
245    }
246  }
247 
248  keyset_t retkeyset, allkeyset;
249  vector<UeberBackend::KeyData> dbkeyset;
250 
251  d_db.getDomainKeys(zone, 0, dbkeyset);
252 
253  BOOST_FOREACH(UeberBackend::KeyData& kd, dbkeyset) 
254  {
255    DNSSECPrivateKey dpk;
256
257    DNSKEYRecordContent dkrc=getRSAKeyFromISCString(&dpk.d_key.getContext(), kd.content);
258    dpk.d_flags = kd.flags;
259    dpk.d_algorithm = dkrc.d_algorithm;
260    if(dpk.d_algorithm == 5 && getNSEC3PARAM(zone))
261      dpk.d_algorithm+=2;
262   
263    KeyMetaData kmd;
264
265    kmd.active = kd.active;
266    kmd.keyOrZone = (kd.flags == 257);
267    kmd.id = kd.id;
268   
269    if(boost::indeterminate(allOrKeyOrZone) || allOrKeyOrZone == kmd.keyOrZone)
270      retkeyset.push_back(make_pair(dpk, kmd));
271    allkeyset.push_back(make_pair(dpk, kmd));
272  }
273  sort(retkeyset.begin(), retkeyset.end(), keyCompareByKindAndID);
274  sort(allkeyset.begin(), allkeyset.end(), keyCompareByKindAndID);
275  Lock l(&s_keycachelock);
276 
277  KeyCacheEntry kce;
278  kce.d_domain=zone;
279  kce.d_keys = allkeyset;
280  kce.d_ttd = now + 30;
281  replacing_insert(s_keycache, kce);
282 
283  return retkeyset;
284}
285
286void DNSSECKeeper::secureZone(const std::string& name, int algorithm)
287{
288  clearCaches(name); // just to be sure ;)
289  addKey(name, true, algorithm);
290}
Note: See TracBrowser for help on using the browser.