2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002-2012 PowerDNS.COM BV
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
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.
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.
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
26 #include "bindbackend2.hh"
27 #include "pdns/arguments.hh"
28 #include "pdns/dnsrecords.hh"
32 void Bind2Backend::setupDNSSEC()
34 if(!getArg("dnssec-db").empty())
35 throw runtime_error("bind-dnssec-db requires building PowerDNS with SQLite3");
38 bool Bind2Backend::doesDNSSEC()
41 bool Bind2Backend::getNSEC3PARAM(const DNSName
& name
, NSEC3PARAMRecordContent
* ns3p
)
44 bool Bind2Backend::getAllDomainMetadata(const DNSName
& name
, std::map
<std::string
, std::vector
<std::string
> >& meta
)
47 bool Bind2Backend::getDomainMetadata(const DNSName
& name
, const std::string
& kind
, std::vector
<std::string
>& meta
)
50 bool Bind2Backend::setDomainMetadata(const DNSName
& name
, const std::string
& kind
, const std::vector
<std::string
>& meta
)
53 bool Bind2Backend::getDomainKeys(const DNSName
& name
, unsigned int kind
, std::vector
<KeyData
>& keys
)
56 bool Bind2Backend::removeDomainKey(const DNSName
& name
, unsigned int id
)
59 int Bind2Backend::addDomainKey(const DNSName
& name
, const KeyData
& key
)
62 bool Bind2Backend::activateDomainKey(const DNSName
& name
, unsigned int id
)
65 bool Bind2Backend::deactivateDomainKey(const DNSName
& name
, unsigned int id
)
68 bool Bind2Backend::getTSIGKey(const DNSName
& name
, DNSName
* algorithm
, string
* content
)
71 bool Bind2Backend::setTSIGKey(const DNSName
& name
, const DNSName
& algorithm
, const string
& content
)
74 bool Bind2Backend::deleteTSIGKey(const DNSName
& name
)
77 bool Bind2Backend::getTSIGKeys(std::vector
<struct TSIGKey
> &keys
)
80 void Bind2Backend::setupStatements()
83 void Bind2Backend::freeStatements()
88 #include "pdns/bind-dnssec.schema.sqlite3.sql.h"
89 #include "pdns/logger.hh"
90 #include "pdns/ssqlite3.hh"
92 void Bind2Backend::setupDNSSEC()
94 if(getArg("dnssec-db").empty() || d_hybrid
)
97 d_dnssecdb
= shared_ptr
<SSQLite3
>(new SSQLite3(getArg("dnssec-db")));
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());
105 d_dnssecdb
->setLog(::arg().mustDo("query-logging"));
108 void Bind2Backend::setupStatements()
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);
125 void Bind2Backend::release(SSqlStatement
** stmt
) {
130 void Bind2Backend::freeStatements()
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
);
147 bool Bind2Backend::doesDNSSEC()
149 return d_dnssecdb
|| d_hybrid
;
152 bool Bind2Backend::getNSEC3PARAM(const DNSName
& name
, NSEC3PARAMRecordContent
* ns3p
)
154 if(!d_dnssecdb
|| d_hybrid
)
159 getDomainMetadata(name
, "NSEC3PARAM", meta
);
163 return false; // No NSEC3 zone
165 static int maxNSEC3Iterations
=::arg().asNum("max-nsec3-iterations");
167 NSEC3PARAMRecordContent
* tmp
=dynamic_cast<NSEC3PARAMRecordContent
*>(DNSRecordContent::mastermake(QType::NSEC3PARAM
, 1, value
));
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
;
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;
185 bool Bind2Backend::getAllDomainMetadata(const DNSName
& name
, std::map
<std::string
, std::vector
<std::string
> >& meta
)
187 if(!d_dnssecdb
|| d_hybrid
)
191 d_getAllDomainMetadataQuery_stmt
->
192 bind("domain", name
)->
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]);
201 d_getAllDomainMetadataQuery_stmt
->reset();
203 catch(SSqlException
& se
) {
204 throw PDNSException("Error accessing DNSSEC database in BIND backend, getAllDomainMetadata(): "+se
.txtReason());
209 bool Bind2Backend::getDomainMetadata(const DNSName
& name
, const std::string
& kind
, std::vector
<std::string
>& meta
)
211 if(!d_dnssecdb
|| d_hybrid
)
215 d_getDomainMetadataQuery_stmt
->
216 bind("domain", name
)->
220 SSqlStatement::row_t row
;
221 while(d_getDomainMetadataQuery_stmt
->hasNextRow()) {
222 d_getDomainMetadataQuery_stmt
->nextRow(row
);
223 meta
.push_back(row
[0]);
226 d_getDomainMetadataQuery_stmt
->reset();
228 catch(SSqlException
& se
) {
229 throw PDNSException("Error accessing DNSSEC database in BIND backend, getDomainMetadata(): "+se
.txtReason());
234 bool Bind2Backend::setDomainMetadata(const DNSName
& name
, const std::string
& kind
, const std::vector
<std::string
>& meta
)
236 if(!d_dnssecdb
|| d_hybrid
)
240 d_deleteDomainMetadataQuery_stmt
->
241 bind("domain", name
)->
246 for(const auto& value
: meta
) {
247 d_insertDomainMetadataQuery_stmt
->
248 bind("domain", name
)->
250 bind("content", value
)->
256 catch(SSqlException
& se
) {
257 throw PDNSException("Error accessing DNSSEC database in BIND backend, setDomainMetadata(): "+se
.txtReason());
262 bool Bind2Backend::getDomainKeys(const DNSName
& name
, unsigned int kind
, std::vector
<KeyData
>& keys
)
264 if(!d_dnssecdb
|| d_hybrid
)
268 d_getDomainKeysQuery_stmt
->
269 bind("domain", name
)->
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");
283 d_getDomainKeysQuery_stmt
->reset();
285 catch(SSqlException
& se
) {
286 throw PDNSException("Error accessing DNSSEC database in BIND backend, getDomainKeys(): "+se
.txtReason());
291 bool Bind2Backend::removeDomainKey(const DNSName
& name
, unsigned int id
)
293 if(!d_dnssecdb
|| d_hybrid
)
297 d_deleteDomainKeyQuery_stmt
->
298 bind("domain", name
)->
303 catch(SSqlException
& se
) {
304 throw PDNSException("Error accessing DNSSEC database in BIND backend, removeDomainKeys(): "+se
.txtReason());
309 int Bind2Backend::addDomainKey(const DNSName
& name
, const KeyData
& key
)
311 if(!d_dnssecdb
|| d_hybrid
)
315 d_insertDomainKeyQuery_stmt
->
316 bind("domain", name
)->
317 bind("flags", key
.flags
)->
318 bind("active", key
.active
)->
319 bind("content", key
.content
)->
323 catch(SSqlException
& se
) {
324 throw PDNSException("Error accessing DNSSEC database in BIND backend, addDomainKey(): "+se
.txtReason());
329 bool Bind2Backend::activateDomainKey(const DNSName
& name
, unsigned int id
)
331 if(!d_dnssecdb
|| d_hybrid
)
335 d_activateDomainKeyQuery_stmt
->
336 bind("domain", name
)->
341 catch(SSqlException
& se
) {
342 throw PDNSException("Error accessing DNSSEC database in BIND backend, activateDomainKey(): "+se
.txtReason());
347 bool Bind2Backend::deactivateDomainKey(const DNSName
& name
, unsigned int id
)
349 if(!d_dnssecdb
|| d_hybrid
)
353 d_deactivateDomainKeyQuery_stmt
->
354 bind("domain", name
)->
359 catch(SSqlException
& se
) {
360 throw PDNSException("Error accessing DNSSEC database in BIND backend, deactivateDomainKey(): "+se
.txtReason());
365 bool Bind2Backend::getTSIGKey(const DNSName
& name
, DNSName
* algorithm
, string
* content
)
367 if(!d_dnssecdb
|| d_hybrid
)
371 d_getTSIGKeyQuery_stmt
->
372 bind("key_name", name
)->
375 SSqlStatement::row_t row
;
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]);
385 d_getTSIGKeyQuery_stmt
->reset();
387 catch (SSqlException
&e
) {
388 throw PDNSException("Error accessing DNSSEC database in BIND backend, getTSIGKey(): "+e
.txtReason());
390 return !content
->empty();
393 bool Bind2Backend::setTSIGKey(const DNSName
& name
, const DNSName
& algorithm
, const string
& content
)
395 if(!d_dnssecdb
|| d_hybrid
)
399 d_setTSIGKeyQuery_stmt
->
400 bind("key_name", name
)->
401 bind("algorithm", algorithm
)->
402 bind("content", content
)->
406 catch (SSqlException
&e
) {
407 throw PDNSException("Error accessing DNSSEC database in BIND backend, setTSIGKey(): "+e
.txtReason());
412 bool Bind2Backend::deleteTSIGKey(const DNSName
& name
)
414 if(!d_dnssecdb
|| d_hybrid
)
418 d_deleteTSIGKeyQuery_stmt
->
419 bind("key_name", name
)->
423 catch (SSqlException
&e
) {
424 throw PDNSException("Error accessing DNSSEC database in BIND backend, deleteTSIGKey(): "+e
.txtReason());
429 bool Bind2Backend::getTSIGKeys(std::vector
< struct TSIGKey
> &keys
)
431 if(!d_dnssecdb
|| d_hybrid
)
435 d_getTSIGKeysQuery_stmt
->
438 SSqlStatement::row_t row
;
439 while(d_getTSIGKeysQuery_stmt
->hasNextRow()) {
440 d_getTSIGKeysQuery_stmt
->nextRow(row
);
442 key
.name
= DNSName(row
[0]);
443 key
.algorithm
= DNSName(row
[1]);
448 d_getTSIGKeysQuery_stmt
->reset();
450 catch (SSqlException
&e
) {
451 throw PDNSException("Error accessing DNSSEC database in BIND backend, getTSIGKeys(): "+e
.txtReason());
453 return !keys
.empty();