]> git.ipfire.org Git - thirdparty/pdns.git/blob - modules/bindbackend/binddnssec.cc
d96c6834c4c56a0cccea4f6c8f836c754ae0c911
[thirdparty/pdns.git] / modules / bindbackend / binddnssec.cc
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002-2012 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
7 as published by the Free Software Foundation
8
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
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
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "bindbackend2.hh"
27 #include "pdns/arguments.hh"
28 #include "pdns/dnsrecords.hh"
29
30 #ifndef HAVE_SQLITE3
31
32 void Bind2Backend::setupDNSSEC()
33 {
34 if(!getArg("dnssec-db").empty())
35 throw runtime_error("bind-dnssec-db requires building PowerDNS with SQLite3");
36 }
37
38 bool Bind2Backend::doesDNSSEC()
39 { return d_hybrid; }
40
41 bool Bind2Backend::getNSEC3PARAM(const DNSName& name, NSEC3PARAMRecordContent* ns3p)
42 { return false; }
43
44 bool Bind2Backend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta)
45 { return false; }
46
47 bool Bind2Backend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta)
48 { return false; }
49
50 bool Bind2Backend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta)
51 { return false; }
52
53 bool Bind2Backend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys)
54 { return false; }
55
56 bool Bind2Backend::removeDomainKey(const DNSName& name, unsigned int id)
57 { return false; }
58
59 int Bind2Backend::addDomainKey(const DNSName& name, const KeyData& key)
60 { return -1; }
61
62 bool Bind2Backend::activateDomainKey(const DNSName& name, unsigned int id)
63 { return false; }
64
65 bool Bind2Backend::deactivateDomainKey(const DNSName& name, unsigned int id)
66 { return false; }
67
68 bool Bind2Backend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content)
69 { return false; }
70
71 bool Bind2Backend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
72 { return false; }
73
74 bool Bind2Backend::deleteTSIGKey(const DNSName& name)
75 { return false; }
76
77 bool Bind2Backend::getTSIGKeys(std::vector<struct TSIGKey> &keys)
78 { return false; }
79
80 void Bind2Backend::setupStatements()
81 { return; }
82
83 void Bind2Backend::freeStatements()
84 { return; }
85
86 #else
87
88 #include "pdns/bind-dnssec.schema.sqlite3.sql.h"
89 #include "pdns/logger.hh"
90 #include "pdns/ssqlite3.hh"
91
92 void Bind2Backend::setupDNSSEC()
93 {
94 if(getArg("dnssec-db").empty() || d_hybrid)
95 return;
96 try {
97 d_dnssecdb = shared_ptr<SSQLite3>(new SSQLite3(getArg("dnssec-db")));
98 setupStatements();
99 }
100 catch(SSqlException& se) {
101 // this error is meant to kill the server dead - it makes no sense to continue..
102 throw runtime_error("Error opening DNSSEC database in BIND backend: "+se.txtReason());
103 }
104
105 d_dnssecdb->setLog(::arg().mustDo("query-logging"));
106 }
107
108 void Bind2Backend::setupStatements()
109 {
110 d_getAllDomainMetadataQuery_stmt = d_dnssecdb->prepare("select kind, content from domainmetadata where domain=:domain",1);
111 d_getDomainMetadataQuery_stmt = d_dnssecdb->prepare("select content from domainmetadata where domain=:domain and kind=:kind",2);
112 d_deleteDomainMetadataQuery_stmt = d_dnssecdb->prepare("delete from domainmetadata where domain=:domain and kind=:kind",2);
113 d_insertDomainMetadataQuery_stmt = d_dnssecdb->prepare("insert into domainmetadata (domain, kind, content) values (:domain,:kind,:content)",3);
114 d_getDomainKeysQuery_stmt = d_dnssecdb->prepare("select id,flags, active, content from cryptokeys where domain=:domain",1);
115 d_deleteDomainKeyQuery_stmt = d_dnssecdb->prepare("delete from cryptokeys where domain=:domain and id=:key_id",2);
116 d_insertDomainKeyQuery_stmt = d_dnssecdb->prepare("insert into cryptokeys (domain, flags, active, content) values (:domain, :flags, :active, :content)", 4);
117 d_activateDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set active=1 where domain=:domain and id=:key_id", 2);
118 d_deactivateDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set active=0 where domain=:domain and id=:key_id", 2);
119 d_getTSIGKeyQuery_stmt = d_dnssecdb->prepare("select algorithm, secret from tsigkeys where name=:key_name", 1);
120 d_setTSIGKeyQuery_stmt = d_dnssecdb->prepare("replace into tsigkeys (name,algorithm,secret) values(:key_name, :algorithm, :content)", 3);
121 d_deleteTSIGKeyQuery_stmt = d_dnssecdb->prepare("delete from tsigkeys where name=:key_name", 1);
122 d_getTSIGKeysQuery_stmt = d_dnssecdb->prepare("select name,algorithm,secret from tsigkeys", 0);
123 }
124
125 void Bind2Backend::release(SSqlStatement** stmt) {
126 delete *stmt;
127 *stmt = NULL;
128 }
129
130 void Bind2Backend::freeStatements()
131 {
132 release(&d_getAllDomainMetadataQuery_stmt);
133 release(&d_getDomainMetadataQuery_stmt);
134 release(&d_deleteDomainMetadataQuery_stmt);
135 release(&d_insertDomainMetadataQuery_stmt);
136 release(&d_getDomainKeysQuery_stmt);
137 release(&d_deleteDomainKeyQuery_stmt);
138 release(&d_insertDomainKeyQuery_stmt);
139 release(&d_activateDomainKeyQuery_stmt);
140 release(&d_deactivateDomainKeyQuery_stmt);
141 release(&d_getTSIGKeyQuery_stmt);
142 release(&d_setTSIGKeyQuery_stmt);
143 release(&d_deleteTSIGKeyQuery_stmt);
144 release(&d_getTSIGKeysQuery_stmt);
145 }
146
147 bool Bind2Backend::doesDNSSEC()
148 {
149 return d_dnssecdb || d_hybrid;
150 }
151
152 bool Bind2Backend::getNSEC3PARAM(const DNSName& name, NSEC3PARAMRecordContent* ns3p)
153 {
154 if(!d_dnssecdb || d_hybrid)
155 return false;
156
157 string value;
158 vector<string> meta;
159 getDomainMetadata(name, "NSEC3PARAM", meta);
160 if(!meta.empty())
161 value=*meta.begin();
162 else
163 return false; // No NSEC3 zone
164
165 static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
166 if(ns3p) {
167 NSEC3PARAMRecordContent* tmp=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, value));
168 *ns3p = *tmp;
169 delete tmp;
170
171 if (ns3p->d_iterations > maxNSEC3Iterations) {
172 ns3p->d_iterations = maxNSEC3Iterations;
173 L<<Logger::Error<<"Number of NSEC3 iterations for zone '"<<name<<"' is above 'max-nsec3-iterations'. Value adjsted to: "<<maxNSEC3Iterations<<endl;
174 }
175
176 if (ns3p->d_algorithm != 1) {
177 L<<Logger::Error<<"Invalid hash algorithm for NSEC3: '"<<std::to_string(ns3p->d_algorithm)<<"', setting to 1 for zone '"<<name<<"'."<<endl;
178 ns3p->d_algorithm = 1;
179 }
180 }
181
182 return true;
183 }
184
185 bool Bind2Backend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta)
186 {
187 if(!d_dnssecdb || d_hybrid)
188 return false;
189
190 try {
191 d_getAllDomainMetadataQuery_stmt->
192 bind("domain", name)->
193 execute();
194
195 SSqlStatement::row_t row;
196 while(d_getAllDomainMetadataQuery_stmt->hasNextRow()) {
197 d_getAllDomainMetadataQuery_stmt->nextRow(row);
198 meta[row[0]].push_back(row[1]);
199 }
200
201 d_getAllDomainMetadataQuery_stmt->reset();
202 }
203 catch(SSqlException& se) {
204 throw PDNSException("Error accessing DNSSEC database in BIND backend, getAllDomainMetadata(): "+se.txtReason());
205 }
206 return true;
207 }
208
209 bool Bind2Backend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta)
210 {
211 if(!d_dnssecdb || d_hybrid)
212 return false;
213
214 try {
215 d_getDomainMetadataQuery_stmt->
216 bind("domain", name)->
217 bind("kind", kind)->
218 execute();
219
220 SSqlStatement::row_t row;
221 while(d_getDomainMetadataQuery_stmt->hasNextRow()) {
222 d_getDomainMetadataQuery_stmt->nextRow(row);
223 meta.push_back(row[0]);
224 }
225
226 d_getDomainMetadataQuery_stmt->reset();
227 }
228 catch(SSqlException& se) {
229 throw PDNSException("Error accessing DNSSEC database in BIND backend, getDomainMetadata(): "+se.txtReason());
230 }
231 return true;
232 }
233
234 bool Bind2Backend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta)
235 {
236 if(!d_dnssecdb || d_hybrid)
237 return false;
238
239 try {
240 d_deleteDomainMetadataQuery_stmt->
241 bind("domain", name)->
242 bind("kind", kind)->
243 execute()->
244 reset();
245 if(!meta.empty()) {
246 for(const auto& value: meta) {
247 d_insertDomainMetadataQuery_stmt->
248 bind("domain", name)->
249 bind("kind", kind)->
250 bind("content", value)->
251 execute()->
252 reset();
253 }
254 }
255 }
256 catch(SSqlException& se) {
257 throw PDNSException("Error accessing DNSSEC database in BIND backend, setDomainMetadata(): "+se.txtReason());
258 }
259 return true;
260 }
261
262 bool Bind2Backend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys)
263 {
264 if(!d_dnssecdb || d_hybrid)
265 return false;
266
267 try {
268 d_getDomainKeysQuery_stmt->
269 bind("domain", name)->
270 execute();
271
272 KeyData kd;
273 SSqlStatement::row_t row;
274 while(d_getDomainKeysQuery_stmt->hasNextRow()) {
275 d_getDomainKeysQuery_stmt->nextRow(row);
276 kd.id = pdns_stou(row[0]);
277 kd.flags = pdns_stou(row[1]);
278 kd.active = (row[2] == "1");
279 kd.content = row[3];
280 keys.push_back(kd);
281 }
282
283 d_getDomainKeysQuery_stmt->reset();
284 }
285 catch(SSqlException& se) {
286 throw PDNSException("Error accessing DNSSEC database in BIND backend, getDomainKeys(): "+se.txtReason());
287 }
288 return true;
289 }
290
291 bool Bind2Backend::removeDomainKey(const DNSName& name, unsigned int id)
292 {
293 if(!d_dnssecdb || d_hybrid)
294 return false;
295
296 try {
297 d_deleteDomainKeyQuery_stmt->
298 bind("domain", name)->
299 bind("key_id", id)->
300 execute()->
301 reset();
302 }
303 catch(SSqlException& se) {
304 throw PDNSException("Error accessing DNSSEC database in BIND backend, removeDomainKeys(): "+se.txtReason());
305 }
306 return true;
307 }
308
309 int Bind2Backend::addDomainKey(const DNSName& name, const KeyData& key)
310 {
311 if(!d_dnssecdb || d_hybrid)
312 return -1;
313
314 try {
315 d_insertDomainKeyQuery_stmt->
316 bind("domain", name)->
317 bind("flags", key.flags)->
318 bind("active", key.active)->
319 bind("content", key.content)->
320 execute()->
321 reset();
322 }
323 catch(SSqlException& se) {
324 throw PDNSException("Error accessing DNSSEC database in BIND backend, addDomainKey(): "+se.txtReason());
325 }
326 return true;
327 }
328
329 bool Bind2Backend::activateDomainKey(const DNSName& name, unsigned int id)
330 {
331 if(!d_dnssecdb || d_hybrid)
332 return false;
333
334 try {
335 d_activateDomainKeyQuery_stmt->
336 bind("domain", name)->
337 bind("key_id", id)->
338 execute()->
339 reset();
340 }
341 catch(SSqlException& se) {
342 throw PDNSException("Error accessing DNSSEC database in BIND backend, activateDomainKey(): "+se.txtReason());
343 }
344 return true;
345 }
346
347 bool Bind2Backend::deactivateDomainKey(const DNSName& name, unsigned int id)
348 {
349 if(!d_dnssecdb || d_hybrid)
350 return false;
351
352 try {
353 d_deactivateDomainKeyQuery_stmt->
354 bind("domain", name)->
355 bind("key_id", id)->
356 execute()->
357 reset();
358 }
359 catch(SSqlException& se) {
360 throw PDNSException("Error accessing DNSSEC database in BIND backend, deactivateDomainKey(): "+se.txtReason());
361 }
362 return true;
363 }
364
365 bool Bind2Backend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content)
366 {
367 if(!d_dnssecdb || d_hybrid)
368 return false;
369
370 try {
371 d_getTSIGKeyQuery_stmt->
372 bind("key_name", name)->
373 execute();
374
375 SSqlStatement::row_t row;
376 content->clear();
377 while(d_getTSIGKeyQuery_stmt->hasNextRow()) {
378 d_getTSIGKeyQuery_stmt->nextRow(row);
379 if(row.size() >= 2 && (algorithm->empty() || *algorithm == DNSName(row[0]))) {
380 *algorithm = DNSName(row[0]);
381 *content = row[1];
382 }
383 }
384
385 d_getTSIGKeyQuery_stmt->reset();
386 }
387 catch (SSqlException &e) {
388 throw PDNSException("Error accessing DNSSEC database in BIND backend, getTSIGKey(): "+e.txtReason());
389 }
390 return !content->empty();
391 }
392
393 bool Bind2Backend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
394 {
395 if(!d_dnssecdb || d_hybrid)
396 return false;
397
398 try {
399 d_setTSIGKeyQuery_stmt->
400 bind("key_name", name)->
401 bind("algorithm", algorithm)->
402 bind("content", content)->
403 execute()->
404 reset();
405 }
406 catch (SSqlException &e) {
407 throw PDNSException("Error accessing DNSSEC database in BIND backend, setTSIGKey(): "+e.txtReason());
408 }
409 return true;
410 }
411
412 bool Bind2Backend::deleteTSIGKey(const DNSName& name)
413 {
414 if(!d_dnssecdb || d_hybrid)
415 return false;
416
417 try {
418 d_deleteTSIGKeyQuery_stmt->
419 bind("key_name", name)->
420 execute()->
421 reset();
422 }
423 catch (SSqlException &e) {
424 throw PDNSException("Error accessing DNSSEC database in BIND backend, deleteTSIGKey(): "+e.txtReason());
425 }
426 return true;
427 }
428
429 bool Bind2Backend::getTSIGKeys(std::vector< struct TSIGKey > &keys)
430 {
431 if(!d_dnssecdb || d_hybrid)
432 return false;
433
434 try {
435 d_getTSIGKeysQuery_stmt->
436 execute();
437
438 SSqlStatement::row_t row;
439 while(d_getTSIGKeysQuery_stmt->hasNextRow()) {
440 d_getTSIGKeysQuery_stmt->nextRow(row);
441 struct TSIGKey key;
442 key.name = DNSName(row[0]);
443 key.algorithm = DNSName(row[1]);
444 key.key = row[2];
445 keys.push_back(key);
446 }
447
448 d_getTSIGKeysQuery_stmt->reset();
449 }
450 catch (SSqlException &e) {
451 throw PDNSException("Error accessing DNSSEC database in BIND backend, getTSIGKeys(): "+e.txtReason());
452 }
453 return !keys.empty();
454 }
455
456 #endif