4 #include "dnsseckeeper.hh"
5 #include "dnssecinfra.hh"
10 #include <boost/program_options.hpp>
11 #include <boost/assign/std/vector.hpp>
12 #include <boost/assign/list_of.hpp>
13 #include "dnsbackend.hh"
14 #include "ueberbackend.hh"
15 #include "arguments.hh"
16 #include "packetcache.hh"
17 #include "zoneparser-tng.hh"
18 #include "signingpipe.hh"
19 #include "dns_random.hh"
25 #include "ssqlite3.hh"
26 #include "bind-dnssec.schema.sqlite3.sql.h"
32 namespace po
= boost::program_options
;
33 po::variables_map g_vm
;
35 string s_programname
="pdns";
47 string
humanTime(time_t t
)
52 strftime(ret
, sizeof(ret
)-1, "%c", &tm
); // %h:%M %Y-%m-%d
56 static void algorithm2name(uint8_t algo
, string
&name
) {
59 name
= "Reserved"; return;
61 name
= "RSAMD5"; return;
69 name
= "RSASHA1"; return;
71 name
= "DSA-NSEC3-SHA1"; return;
73 name
= "RSASHA1-NSEC3-SHA1"; return;
75 name
= "RSASHA256"; return;
77 name
= "Reserved"; return;
79 name
= "RSASHA512"; return;
81 name
= "Reserved"; return;
83 name
= "ECC-GOST"; return;
85 name
= "ECDSAP256SHA256"; return;
87 name
= "ECDSAP384SHA384"; return;
89 name
= "ED25519SHA512"; return;
91 name
= "INDIRECT"; return;
93 name
= "PRIVATEDNS"; return;
95 name
= "PRIVATEOID"; return;
97 name
= "Unallocated/Reserved"; return;
101 static int shorthand2algorithm(const string
&algorithm
)
103 if (!algorithm
.compare("rsamd5")) return 1;
104 if (!algorithm
.compare("dh")) return 2;
105 if (!algorithm
.compare("dsa")) return 3;
106 if (!algorithm
.compare("ecc")) return 4;
107 if (!algorithm
.compare("rsasha1")) return 5;
108 if (!algorithm
.compare("rsasha256")) return 8;
109 if (!algorithm
.compare("rsasha512")) return 10;
110 if (!algorithm
.compare("gost")) return 12;
111 if (!algorithm
.compare("ecdsa256")) return 13;
112 if (!algorithm
.compare("ecdsa384")) return 14;
113 if (!algorithm
.compare("experimental-ed25519")) return 250;
117 void loadMainConfig(const std::string
& configdir
)
119 ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=configdir
;
120 ::arg().set("default-ttl","Seconds a result is valid if not set otherwise")="3600";
121 ::arg().set("launch","Which backends to launch");
122 ::arg().set("dnssec","if we should do dnssec")="true";
123 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")=g_vm
["config-name"].as
<string
>();
124 ::arg().setCmd("help","Provide a helpful message");
125 //::arg().laxParse(argc,argv);
127 if(::arg().mustDo("help")) {
128 cout
<<"syntax:"<<endl
<<endl
;
129 cout
<<::arg().helpstring(::arg()["help"])<<endl
;
133 if(::arg()["config-name"]!="")
134 s_programname
+="-"+::arg()["config-name"];
136 string configname
=::arg()["config-dir"]+"/"+s_programname
+".conf";
137 cleanSlashes(configname
);
139 ::arg().set("default-ksk-algorithms","Default KSK algorithms")="";
140 ::arg().set("default-ksk-size","Default KSK size (0 means default)")="0";
141 ::arg().set("default-zsk-algorithms","Default ZSK algorithms")="ecdsa256";
142 ::arg().set("default-zsk-size","Default ZSK size (0 means default)")="0";
143 ::arg().set("default-soa-edit","Default SOA-EDIT value")="";
144 ::arg().set("default-soa-edit-signed","Default SOA-EDIT value for signed zones")="";
145 ::arg().set("max-ent-entries", "Maximum number of empty non-terminals in a zone")="100000";
146 ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR
;
147 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
148 ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
149 ::arg().set("loglevel","Amount of logging. Higher is more.")="0";
150 ::arg().setSwitch("direct-dnskey","Fetch DNSKEY RRs from backend during DNSKEY synthesis")="no";
151 ::arg().set("max-nsec3-iterations","Limit the number of NSEC3 hash iterations")="500"; // RFC5155 10.3
152 ::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries")="";
153 ::arg().laxFile(configname
.c_str());
155 L
.toConsole(Logger::Error
); // so we print any errors
156 BackendMakers().launch(::arg()["launch"]); // vrooooom!
157 L
.toConsole((Logger::Urgency
)(::arg().asNum("loglevel")));
158 ::arg().laxFile(configname
.c_str());
159 //cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" <<endl;
161 S
.declare("qsize-q","Number of questions waiting for database attention");
163 S
.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
164 S
.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
166 S
.declare("query-cache-hit","Number of hits on the query cache");
167 S
.declare("query-cache-miss","Number of misses on the query cache");
168 ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
169 ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no";
170 ::arg().set("recursive-cache-ttl","Seconds to store packets for recursive queries in the PacketCache")="10";
171 ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
172 ::arg().set("negquery-cache-ttl","Seconds to store negative query results in the QueryCache")="60";
173 ::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
174 ::arg().set("default-soa-name","name to insert in the SOA record if none set in the backend")="a.misconfigured.powerdns.server";
175 ::arg().set("default-soa-mail","mail address to insert in the SOA record if none set in the backend")="";
176 ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
177 ::arg().set("soa-retry-default","Default SOA retry")="3600";
178 ::arg().set("soa-expire-default","Default SOA expire")="604800";
179 ::arg().set("soa-minimum-ttl","Default SOA minimum ttl")="3600";
184 // irritatingly enough, rectifyZone needs its own ueberbackend and can't therefore benefit from transactions outside its scope
185 // I think this has to do with interlocking transactions between B and DK, but unsure.
186 bool rectifyZone(DNSSECKeeper
& dk
, const DNSName
& zone
)
188 if(dk
.isPresigned(zone
)){
189 cerr
<<"Rectify presigned zone '"<<zone
.toString()<<"' is not allowed/necessary."<<endl
;
193 UeberBackend
B("default");
194 bool doTransaction
=true; // but see above
197 if(!B
.getSOAUncached(zone
, sd
)) {
198 cerr
<<"No SOA known for '"<<zone
.toString()<<"', is such a zone in the database?"<<endl
;
201 sd
.db
->list(zone
, sd
.domain_id
);
203 DNSResourceRecord rr
;
204 set
<DNSName
> qnames
, nsset
, dsnames
, insnonterm
, delnonterm
;
205 map
<DNSName
,bool> nonterm
;
208 while(sd
.db
->get(rr
)) {
209 if (rr
.qtype
.getCode())
211 qnames
.insert(rr
.qname
);
212 if(rr
.qtype
.getCode() == QType::NS
&& rr
.qname
!= zone
)
213 nsset
.insert(rr
.qname
);
214 if(rr
.qtype
.getCode() == QType::DS
)
215 dsnames
.insert(rr
.qname
);
219 delnonterm
.insert(rr
.qname
);
222 NSEC3PARAMRecordContent ns3pr
;
224 bool haveNSEC3
=dk
.getNSEC3PARAM(zone
, &ns3pr
, &narrow
);
225 bool isOptOut
=(haveNSEC3
&& ns3pr
.d_flags
);
226 if(sd
.db
->doesDNSSEC())
229 cerr
<<"Adding NSEC ordering information "<<endl
;
232 cerr
<<"Adding NSEC3 hashed ordering information for '"<<zone
.toString()<<"'"<<endl
;
234 cerr
<<"Adding NSEC3 opt-out hashed ordering information for '"<<zone
.toString()<<"'"<<endl
;
236 cerr
<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields"<<endl
;
239 cerr
<<"Non DNSSEC zone, only adding empty non-terminals"<<endl
;
242 sd
.db
->startTransaction(zone
, -1);
245 uint32_t maxent
= ::arg().asNum("max-ent-entries");
248 for (const auto& qname
: qnames
)
256 if(nsset
.count(shorter
)) {
260 } while(shorter
.chopOff());
263 if(haveNSEC3
) // NSEC3
265 if(!narrow
&& (realrr
|| !isOptOut
|| nonterm
.find(qname
)->second
))
266 ordername
=DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, qname
))) + zone
;
270 else if (realrr
) // NSEC
274 cerr
<<"'"<<qname
.toString()<<"' -> '"<< ordername
.toString() <<"'"<<endl
;
275 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, zone
, qname
, ordername
, auth
);
279 if (dsnames
.count(qname
))
280 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, zone
, qname
, ordername
, true, QType::DS
);
281 if (!auth
|| nsset
.count(qname
)) {
284 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, zone
, qname
, ordername
, false, QType::NS
);
285 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, zone
, qname
, ordername
, false, QType::A
);
286 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, zone
, qname
, ordername
, false, QType::AAAA
);
292 while(shorter
!=zone
&& shorter
.chopOff())
294 if(!qnames
.count(shorter
))
298 cerr
<<"Zone '"<<zone
.toString()<<"' has too many empty non terminals."<<endl
;
305 if (!delnonterm
.count(shorter
) && !nonterm
.count(shorter
))
306 insnonterm
.insert(shorter
);
308 delnonterm
.erase(shorter
);
310 if (!nonterm
.count(shorter
)) {
311 nonterm
.insert(pair
<DNSName
, bool>(shorter
, auth
));
314 nonterm
[shorter
]=true;
323 //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
324 if(!insnonterm
.empty() || !delnonterm
.empty() || !doent
)
326 sd
.db
->updateEmptyNonTerminals(sd
.domain_id
, zone
, insnonterm
, delnonterm
, !doent
);
332 for(const auto& nt
: nonterm
){
333 qnames
.insert(nt
.first
);
340 sd
.db
->commitTransaction();
345 void dbBench(const std::string
& fname
)
347 ::arg().set("query-cache-ttl")="0";
348 ::arg().set("negquery-cache-ttl")="0";
349 UeberBackend
B("default");
351 vector
<string
> domains
;
353 ifstream
ifs(fname
.c_str());
355 cerr
<<"Could not open '"<<fname
<<"' for reading domain names to query"<<endl
;
358 while(getline(ifs
,line
)) {
360 domains
.push_back(line
);
364 domains
.push_back("powerdns.com");
367 DNSResourceRecord rr
;
370 unsigned int hits
=0, misses
=0;
371 for(; n
< 10000; ++n
) {
372 DNSName
domain(domains
[random() % domains
.size()]);
373 B
.lookup(QType(QType::NS
), domain
);
377 B
.lookup(QType(QType::A
), DNSName(std::to_string(random()))+domain
);
383 cout
<<0.001*dt
.udiff()/n
<<" millisecond/lookup"<<endl
;
384 cout
<<"Retrieved "<<hits
<<" records, did "<<misses
<<" queries which should have no match"<<endl
;
385 cout
<<"Packet cache reports: "<<S
.read("query-cache-hit")<<" hits (should be 0) and "<<S
.read("query-cache-miss") <<" misses"<<endl
;
388 void rectifyAllZones(DNSSECKeeper
&dk
)
390 UeberBackend
B("default");
391 vector
<DomainInfo
> domainInfo
;
393 B
.getAllDomains(&domainInfo
);
394 for(DomainInfo di
: domainInfo
) {
395 cerr
<<"Rectifying "<<di
.zone
.toString()<<": ";
396 rectifyZone(dk
, di
.zone
);
398 cout
<<"Rectified "<<domainInfo
.size()<<" zones."<<endl
;
401 int checkZone(DNSSECKeeper
&dk
, UeberBackend
&B
, const DNSName
& zone
)
404 if(!B
.getSOAUncached(zone
, sd
)) {
405 cout
<<"[error] No SOA record present, or active, in zone '"<<zone
.toString()<<"'"<<endl
;
406 cout
<<"Checked 0 records of '"<<zone
.toString()<<"', 1 errors, 0 warnings."<<endl
;
410 NSEC3PARAMRecordContent ns3pr
;
412 bool haveNSEC3
= dk
.getNSEC3PARAM(zone
, &ns3pr
, &narrow
);
413 bool isOptOut
=(haveNSEC3
&& ns3pr
.d_flags
);
415 bool isSecure
=dk
.isSecuredZone(zone
);
416 bool presigned
=dk
.isPresigned(zone
);
418 DNSResourceRecord rr
;
419 uint64_t numrecords
=0, numerrors
=0, numwarnings
=0;
421 if (haveNSEC3
&& isSecure
&& zone
.wirelength() > 222) {
423 cerr
<<"[Error] zone '" << zone
.toStringNoDot() << "' has NSEC3 semantics but is too long to have the hash prepended. Zone name is " << zone
.wirelength() << " bytes long, whereas the maximum is 222 bytes." << endl
;
426 // Check for delegation in parent zone
427 DNSName
parent(zone
);
428 while(parent
.chopOff()) {
430 if(B
.getSOAUncached(parent
, sd_p
)) {
432 DNSResourceRecord rr
;
433 B
.lookup(QType(QType::ANY
), zone
, NULL
, sd_p
.domain_id
);
435 ns
|= (rr
.qtype
== QType::NS
);
437 cerr
<<"[Error] No delegation for zone '"<<zone
.toString()<<"' in parent '"<<parent
.toString()<<"'"<<endl
;
445 bool hasNsAtApex
= false;
446 set
<DNSName
> tlsas
, cnames
, noncnames
, glue
, checkglue
;
448 map
<string
, unsigned int> ttl
;
450 ostringstream content
;
451 pair
<map
<string
, unsigned int>::iterator
,bool> ret
;
453 sd
.db
->list(zone
, sd
.domain_id
, true);
455 while(sd
.db
->get(rr
)) {
456 if(!rr
.qtype
.getCode())
461 if(rr
.qtype
.getCode() == QType::TLSA
)
462 tlsas
.insert(rr
.qname
);
463 if(rr
.qtype
.getCode() == QType::SOA
) {
465 stringtok(parts
, rr
.content
);
469 for(int pleft
=parts
.size(); pleft
< 7; ++pleft
) {
475 if(rr
.qtype
.getCode() == QType::TXT
&& !rr
.content
.empty() && rr
.content
[0]!='"')
476 rr
.content
= "\""+rr
.content
+"\"";
479 shared_ptr
<DNSRecordContent
> drc(DNSRecordContent::mastermake(rr
.qtype
.getCode(), 1, rr
.content
));
480 string tmp
=drc
->serialize(rr
.qname
);
481 tmp
= drc
->getZoneRepresentation(true);
482 if (rr
.qtype
.getCode() != QType::AAAA
) {
483 if (!pdns_iequals(tmp
, rr
.content
)) {
484 cout
<<"[Warning] Parsed and original record content are not equal: "<<rr
.qname
.toString()<<" IN " <<rr
.qtype
.getName()<< " '" << rr
.content
<<"' (Content parsed as '"<<tmp
<<"')"<<endl
;
488 struct in6_addr tmpbuf
;
489 if (inet_pton(AF_INET6
, rr
.content
.c_str(), &tmpbuf
) != 1 || rr
.content
.find('.') != string::npos
) {
490 cout
<<"[Warning] Following record is not a valid IPv6 address: "<<rr
.qname
.toString()<<" IN " <<rr
.qtype
.getName()<< " '" << rr
.content
<<"'"<<endl
;
495 catch(std::exception
& e
)
497 cout
<<"[Error] Following record had a problem: "<<rr
.qname
.toString()<<" IN " <<rr
.qtype
.getName()<< " " << rr
.content
<<endl
;
498 cout
<<"[Error] Error was: "<<e
.what()<<endl
;
503 if(!rr
.qname
.isPartOf(zone
)) {
504 cout
<<"[Warning] Record '"<<rr
.qname
.toString()<<" IN "<<rr
.qtype
.getName()<<" "<<rr
.content
<<"' in zone '"<<zone
.toString()<<"' is out-of-zone."<<endl
;
510 content
<<rr
.qname
.toString()<<" "<<rr
.qtype
.getName()<<" "<<rr
.content
;
511 if (records
.count(toLower(content
.str()))) {
512 cout
<<"[Error] Duplicate record found in rrset: '"<<rr
.qname
.toString()<<" IN "<<rr
.qtype
.getName()<<" "<<rr
.content
<<"'"<<endl
;
516 records
.insert(toLower(content
.str()));
519 content
<<rr
.qname
.toString()<<" "<<rr
.qtype
.getName();
520 if (rr
.qtype
.getCode() == QType::RRSIG
) {
521 RRSIGRecordContent
rrc(rr
.content
);
522 content
<<" ("<<DNSRecordContent::NumberToType(rrc
.d_type
)<<")";
524 ret
= ttl
.insert(pair
<string
, unsigned int>(toLower(content
.str()), rr
.ttl
));
525 if (ret
.second
== false && ret
.first
->second
!= rr
.ttl
) {
526 cout
<<"[Error] TTL mismatch in rrset: '"<<rr
.qname
.toString()<<" IN " <<rr
.qtype
.getName()<<" "<<rr
.content
<<"' ("<<ret
.first
->second
<<" != "<<rr
.ttl
<<")"<<endl
;
531 if (isSecure
&& isOptOut
&& (rr
.qname
.countLabels() && rr
.qname
.getRawLabels()[0] == "*")) {
532 cout
<<"[Warning] wildcard record '"<<rr
.qname
.toString()<<" IN " <<rr
.qtype
.getName()<<" "<<rr
.content
<<"' is insecure"<<endl
;
533 cout
<<"[Info] Wildcard records in opt-out zones are insecure. Disable the opt-out flag for this zone to avoid this warning. Command: pdnsutil set-nsec3 "<<zone
.toString()<<endl
;
538 if (rr
.qtype
.getCode() == QType::NS
) {
540 } else if (rr
.qtype
.getCode() == QType::DS
) {
541 cout
<<"[Warning] DS at apex in zone '"<<zone
.toString()<<"', should not be here."<<endl
;
545 if (rr
.qtype
.getCode() == QType::SOA
) {
546 cout
<<"[Error] SOA record not at apex '"<<rr
.qname
.toString()<<" IN "<<rr
.qtype
.getName()<<" "<<rr
.content
<<"' in zone '"<<zone
.toString()<<"'"<<endl
;
549 } else if (rr
.qtype
.getCode() == QType::DNSKEY
) {
550 cout
<<"[Warning] DNSKEY record not at apex '"<<rr
.qname
.toString()<<" IN "<<rr
.qtype
.getName()<<" "<<rr
.content
<<"' in zone '"<<zone
.toString()<<"', should not be here."<<endl
;
552 } else if (rr
.qtype
.getCode() == QType::NS
&& DNSName(rr
.content
).isPartOf(rr
.qname
)) {
553 checkglue
.insert(DNSName(toLower(rr
.content
)));
554 } else if (rr
.qtype
.getCode() == QType::A
|| rr
.qtype
.getCode() == QType::AAAA
) {
555 glue
.insert(rr
.qname
);
559 if (rr
.qtype
.getCode() == QType::CNAME
) {
560 if (!cnames
.count(rr
.qname
))
561 cnames
.insert(rr
.qname
);
563 cout
<<"[Error] Duplicate CNAME found at '"<<rr
.qname
.toString()<<"'"<<endl
;
568 if (rr
.qtype
.getCode() == QType::RRSIG
) {
570 cout
<<"[Error] RRSIG found at '"<<rr
.qname
.toString()<<"' in non-presigned zone. These do not belong in the database."<<endl
;
575 noncnames
.insert(rr
.qname
);
578 if(rr
.qtype
.getCode() == QType::NSEC
|| rr
.qtype
.getCode() == QType::NSEC3
)
580 cout
<<"[Error] NSEC or NSEC3 found at '"<<rr
.qname
.toString()<<"'. These do not belong in the database."<<endl
;
585 if(!presigned
&& rr
.qtype
.getCode() == QType::DNSKEY
)
587 if(::arg().mustDo("direct-dnskey"))
589 if(rr
.ttl
!= sd
.default_ttl
)
591 cout
<<"[Warning] DNSKEY TTL of "<<rr
.ttl
<<" at '"<<rr
.qname
.toString()<<"' differs from SOA minimum of "<<sd
.default_ttl
<<endl
;
597 cout
<<"[Warning] DNSKEY at '"<<rr
.qname
.toString()<<"' in non-presigned zone will mostly be ignored and can cause problems."<<endl
;
602 // if (rr.qname[rr.qname.size()-1] == '.') {
603 // cout<<"[Error] Record '"<<rr.qname.toString()<<"' has a trailing dot. PowerDNS will ignore this record!"<<endl;
607 if ( (rr
.qtype
.getCode() == QType::NS
|| rr
.qtype
.getCode() == QType::SRV
|| rr
.qtype
.getCode() == QType::MX
|| rr
.qtype
.getCode() == QType::CNAME
|| rr
.qtype
.getCode() == QType::DNAME
) &&
608 rr
.content
[rr
.content
.size()-1] == '.') {
609 cout
<<"[Warning] The record "<<rr
.qname
.toString()<<" with type "<<rr
.qtype
.getName()<<" has a trailing dot in the content ("<<rr
.content
<<"). Your backend might not work well with this."<<endl
;
613 if(rr
.auth
== 0 && rr
.qtype
.getCode()!=QType::NS
&& rr
.qtype
.getCode()!=QType::A
&& rr
.qtype
.getCode()!=QType::AAAA
)
615 cout
<<"[Error] Following record is auth=0, run pdnsutil rectify-zone?: "<<rr
.qname
.toString()<<" IN " <<rr
.qtype
.getName()<< " " << rr
.content
<<endl
;
620 for(auto &i
: cnames
) {
621 if (noncnames
.find(i
) != noncnames
.end()) {
622 cout
<<"[Error] CNAME "<<i
.toString()<<" found, but other records with same label exist."<<endl
;
627 for(const auto &i
: tlsas
) {
628 DNSName name
= DNSName(i
);
629 name
.trimToLabels(name
.getRawLabels().size()-2);
630 if (cnames
.find(name
) == cnames
.end() && noncnames
.find(name
) == noncnames
.end()) {
631 // No specific record for the name in the TLSA record exists, this
632 // is already worth emitting a warning. Let's see if a wildcard exist.
634 DNSName
wcname(name
);
636 wcname
.prependRawLabel("*");
637 if (cnames
.find(wcname
) != cnames
.end() || noncnames
.find(wcname
) != noncnames
.end()) {
638 cout
<<"A wildcard record exist for '"<<wcname
.toString()<<"' and a TLSA record for '"<<i
.toString()<<"'.";
640 cout
<<"No record for '"<<name
.toString()<<"' exists, but a TLSA record for '"<<i
.toString()<<"' does.";
643 cout
<<" A query for '"<<name
.toString()<<"' will yield an empty response. This is most likely a mistake, please create records for '"<<name
.toString()<<"'."<<endl
;
648 cout
<<"[Error] No NS record at zone apex in zone '"<<zone
.toString()<<"'"<<endl
;
652 for(const auto &qname
: checkglue
) {
653 if (!glue
.count(qname
)) {
654 cerr
<<"[Warning] Missing glue for '"<<qname
.toString()<<"' in zone '"<<zone
.toString()<<"'"<<endl
;
659 cout
<<"Checked "<<numrecords
<<" records of '"<<zone
.toString()<<"', "<<numerrors
<<" errors, "<<numwarnings
<<" warnings."<<endl
;
665 int checkAllZones(DNSSECKeeper
&dk
, bool exitOnError
)
667 UeberBackend
B("default");
668 vector
<DomainInfo
> domainInfo
;
670 B
.getAllDomains(&domainInfo
, true);
672 for(auto di
: domainInfo
) {
673 if (checkZone(dk
, B
, di
.zone
) > 0) {
679 cout
<<"Checked "<<domainInfo
.size()<<" zones, "<<errors
<<" had errors."<<endl
;
685 int increaseSerial(const DNSName
& zone
, DNSSECKeeper
&dk
)
687 UeberBackend
B("default");
689 if(!B
.getSOAUncached(zone
, sd
)) {
690 cout
<<"No SOA for zone '"<<zone
.toString()<<"'"<<endl
;
694 if (dk
.isPresigned(zone
)) {
695 cerr
<<"Serial increase of presigned zone '"<<zone
<<"' is not allowed."<<endl
;
700 dk
.getSoaEdit(zone
, soaEditKind
);
702 sd
.db
->lookup(QType(QType::SOA
), zone
);
703 vector
<DNSResourceRecord
> rrs
;
704 DNSResourceRecord rr
;
705 while (sd
.db
->get(rr
)) {
706 if (rr
.qtype
.getCode() == QType::SOA
)
710 if (rrs
.size() > 1) {
711 cerr
<<rrs
.size()<<" SOA records found for "<<zone
.toString()<<"!"<<endl
;
714 if (rrs
.size() < 1) {
715 cerr
<<zone
.toString()<<" not found!"<<endl
;
718 if (soaEditKind
.empty()) {
721 else if(pdns_iequals(soaEditKind
,"INCREMENT-WEEKS")) {
724 else if(pdns_iequals(soaEditKind
,"INCEPTION-INCREMENT")) {
725 uint32_t today_serial
= localtime_format_YYYYMMDDSS(time(NULL
), 1);
727 if (sd
.serial
< today_serial
) {
728 sd
.serial
= today_serial
;
735 sd
.serial
= calculateEditSOA(sd
, soaEditKind
) + 1;
737 rrs
[0].content
= serializeSOAData(sd
);
739 sd
.db
->startTransaction(zone
, -1);
741 if (! sd
.db
->replaceRRSet(sd
.domain_id
, zone
, rr
.qtype
, rrs
)) {
742 sd
.db
->abortTransaction();
743 cerr
<<"Backend did not replace SOA record. Backend might not support this operation."<<endl
;
747 if (sd
.db
->doesDNSSEC()) {
748 NSEC3PARAMRecordContent ns3pr
;
750 bool haveNSEC3
=dk
.getNSEC3PARAM(zone
, &ns3pr
, &narrow
);
755 ordername
=DNSName(toBase32Hex(hashQNameWithSalt(ns3pr
, zone
))) + zone
;
759 cerr
<<"'"<<rrs
[0].qname
.toString()<<"' -> '"<< ordername
.toString() <<"'"<<endl
;
760 sd
.db
->updateDNSSECOrderNameAndAuth(sd
.domain_id
, zone
, rrs
[0].qname
, ordername
, true);
763 sd
.db
->commitTransaction();
765 cout
<<"SOA serial for zone "<<zone
.toString()<<" set to "<<sd
.serial
<<endl
;
769 int deleteZone(const DNSName
&zone
) {
772 if (! B
.getDomainInfo(zone
, di
)) {
773 cerr
<<"Domain '"<<zone
.toString()<<"' not found!"<<endl
;
777 if(di
.backend
->deleteDomain(zone
))
780 cerr
<<"Failed to delete domain '"<<zone
.toString()<<"'"<<endl
;;
784 void listKey(DomainInfo
const &di
, DNSSECKeeper
& dk
, bool printHeader
= true) {
786 cout
<<"Zone Type Size Algorithm ID Location Keytag"<<endl
;
787 cout
<<"----------------------------------------------------------------------------------"<<endl
;
789 unsigned int spacelen
= 0;
790 for (auto const &key
: dk
.getKeys(di
.zone
)) {
791 cout
<<di
.zone
.toStringNoDot();
792 if (di
.zone
.toStringNoDot().length() > 29)
793 cout
<<endl
<<string(30, ' ');
795 cout
<<string(30 - di
.zone
.toStringNoDot().length(), ' ');
797 cout
<<(key
.second
.keyOrZone
? "KSK" : "ZSK")<<" ";
799 spacelen
= (std::to_string(key
.first
.getKey()->getBits()).length() >= 8) ? 1 : 8 - std::to_string(key
.first
.getKey()->getBits()).length();
800 if (key
.first
.getKey()->getBits() < 1) {
801 cout
<<"invalid "<<endl
;
804 cout
<<key
.first
.getKey()->getBits()<<string(spacelen
, ' ');
808 algorithm2name(key
.first
.d_algorithm
, algname
);
809 spacelen
= (algname
.length() >= 13) ? 1 : 13 - algname
.length();
810 cout
<<algname
<<string(spacelen
, ' ');
812 spacelen
= (std::to_string(key
.second
.id
).length() > 5) ? 1 : 5 - std::to_string(key
.second
.id
).length();
813 cout
<<key
.second
.id
<<string(spacelen
, ' ');
816 auto stormap
= key
.first
.getKey()->convertToISCVector();
817 string engine
, slot
, label
= "";
818 for (auto const &elem
: stormap
) {
819 //cout<<elem.first<<" "<<elem.second<<endl;
820 if (elem
.first
== "Engine")
821 engine
= elem
.second
;
822 if (elem
.first
== "Slot")
824 if (elem
.first
== "Label")
827 if (engine
.empty() || slot
.empty()){
830 spacelen
= (engine
.length()+slot
.length()+label
.length()+2 >= 12) ? 1 : 12 - engine
.length()-slot
.length()-label
.length()-2;
831 cout
<<engine
<<","<<slot
<<","<<label
<<string(spacelen
, ' ');
836 cout
<<key
.first
.getDNSKEY().getTag()<<endl
;
840 bool listKeys(const string
&zname
, DNSSECKeeper
& dk
){
841 UeberBackend
B("default");
843 if (zname
!= "all") {
845 if(!B
.getDomainInfo(DNSName(zname
), di
)) {
846 cerr
<< "Zone "<<zname
<<" not found."<<endl
;
851 vector
<DomainInfo
> domainInfo
;
852 B
.getAllDomains(&domainInfo
);
853 bool printHeader
= true;
854 for (auto const di
: domainInfo
) {
855 listKey(di
, dk
, printHeader
);
862 int listZone(const DNSName
&zone
) {
866 if (! B
.getDomainInfo(zone
, di
)) {
867 cerr
<<"Domain '"<<zone
.toString()<<"' not found!"<<endl
;
870 di
.backend
->list(zone
, di
.id
);
871 DNSResourceRecord rr
;
872 while(di
.backend
->get(rr
)) {
873 if(rr
.qtype
.getCode()) {
874 if ( (rr
.qtype
.getCode() == QType::NS
|| rr
.qtype
.getCode() == QType::SRV
|| rr
.qtype
.getCode() == QType::MX
|| rr
.qtype
.getCode() == QType::CNAME
) && !rr
.content
.empty() && rr
.content
[rr
.content
.size()-1] != '.')
875 rr
.content
.append(1, '.');
877 cout
<<rr
.qname
.toString()<<"\t"<<rr
.ttl
<<"\tIN\t"<<rr
.qtype
.getName()<<"\t"<<rr
.content
<<endl
;
883 int loadZone(DNSName zone
, const string
& fname
) {
887 if (B
.getDomainInfo(zone
, di
)) {
888 cerr
<<"Domain '"<<zone
.toString()<<"' exists already, replacing contents"<<endl
;
891 cerr
<<"Creating '"<<zone
.toString()<<"'"<<endl
;
892 B
.createDomain(zone
);
894 if(!B
.getDomainInfo(zone
, di
)) {
895 cerr
<<"Domain '"<<zone
.toString()<<"' was not created - perhaps backend ("<<::arg()["launch"]<<") does not support storing new zones."<<endl
;
899 DNSBackend
* db
= di
.backend
;
900 ZoneParserTNG
zpt(fname
, zone
);
902 DNSResourceRecord rr
;
903 if(!db
->startTransaction(zone
, di
.id
)) {
904 cerr
<<"Unable to start transaction for load of zone '"<<zone
.toString()<<"'"<<endl
;
909 if(!rr
.qname
.isPartOf(zone
) && rr
.qname
!=zone
) {
910 cerr
<<"File contains record named '"<<rr
.qname
.toString()<<"' which is not part of zone '"<<zone
.toString()<<"'"<<endl
;
915 db
->commitTransaction();
919 int createZone(const DNSName
&zone
) {
922 if (B
.getDomainInfo(zone
, di
)) {
923 cerr
<<"Domain '"<<zone
.toString()<<"' exists already"<<endl
;
926 cerr
<<"Creating '"<<zone
.toString()<<"'"<<endl
;
927 B
.createDomain(zone
);
929 if(!B
.getDomainInfo(zone
, di
)) {
930 cerr
<<"Domain '"<<zone
.toString()<<"' was not created!"<<endl
;
937 int listAllZones(const string
&type
="") {
941 if (toUpper(type
) == "MASTER")
943 else if (toUpper(type
) == "SLAVE")
945 else if (toUpper(type
) == "NATIVE")
948 cerr
<<"Syntax: pdnsutil list-all-zones [master|slave|native]"<<endl
;
953 UeberBackend
B("default");
955 vector
<DomainInfo
> domains
;
956 B
.getAllDomains(&domains
);
959 for (vector
<DomainInfo
>::const_iterator di
=domains
.begin(); di
!= domains
.end(); di
++) {
960 if (di
->kind
== kindFilter
|| kindFilter
== -1) {
961 cout
<<di
->zone
.toString()<<endl
;
966 if (kindFilter
!= -1)
967 cout
<<type
<<" zonecount:"<<count
<<endl
;
969 cout
<<"All zonecount:"<<count
<<endl
;
973 bool testAlgorithm(int algo
)
975 return DNSCryptoKeyEngine::testOne(algo
);
978 bool testAlgorithms()
980 return DNSCryptoKeyEngine::testAll();
983 void testSpeed(DNSSECKeeper
& dk
, const DNSName
& zone
, const string
& remote
, int cores
)
985 DNSResourceRecord rr
;
986 rr
.qname
=DNSName("blah")+zone
;
990 rr
.qclass
= QClass::IN
;
991 rr
.d_place
=DNSResourceRecord::ANSWER
;
993 UeberBackend
db("key-only");
995 if ( ! db
.backends
.size() )
997 throw runtime_error("No backends available for DNSSEC key storage");
1000 ChunkedSigningPipe
csp(DNSName(zone
), 1, remote
, cores
);
1002 vector
<DNSResourceRecord
> signatures
;
1004 unsigned char* octets
= (unsigned char*)&rnd
;
1008 for(unsigned int n
=0; n
< 100000; ++n
) {
1010 snprintf(tmp
, sizeof(tmp
), "%d.%d.%d.%d",
1011 octets
[0], octets
[1], octets
[2], octets
[3]);
1014 snprintf(tmp
, sizeof(tmp
), "r-%u", rnd
);
1015 rr
.qname
=DNSName(tmp
)+zone
;
1018 while(signatures
= csp
.getChunk(), !signatures
.empty())
1021 cerr
<<"Flushing the pipe, "<<csp
.d_signed
<<" signed, "<<csp
.d_queued
<<" queued, "<<csp
.d_outstanding
<<" outstanding"<< endl
;
1022 cerr
<<"Net speed: "<<csp
.d_signed
/ (dt
.udiffNoReset()/1000000.0) << " sigs/s"<<endl
;
1023 while(signatures
= csp
.getChunk(true), !signatures
.empty())
1025 cerr
<<"Done, "<<csp
.d_signed
<<" signed, "<<csp
.d_queued
<<" queued, "<<csp
.d_outstanding
<<" outstanding"<< endl
;
1026 cerr
<<"Net speed: "<<csp
.d_signed
/ (dt
.udiff()/1000000.0) << " sigs/s"<<endl
;
1029 void verifyCrypto(const string
& zone
)
1031 ZoneParserTNG
zpt(zone
);
1032 DNSResourceRecord rr
;
1033 DNSKEYRecordContent drc
;
1034 RRSIGRecordContent rrc
;
1035 DSRecordContent dsrc
;
1036 vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1037 DNSName qname
, apex
;
1038 dsrc
.d_digesttype
=0;
1039 while(zpt
.get(rr
)) {
1040 if(rr
.qtype
.getCode() == QType::DNSKEY
) {
1041 cerr
<<"got DNSKEY!"<<endl
;
1043 drc
= *dynamic_cast<DNSKEYRecordContent
*>(DNSRecordContent::mastermake(QType::DNSKEY
, 1, rr
.content
));
1045 else if(rr
.qtype
.getCode() == QType::RRSIG
) {
1046 cerr
<<"got RRSIG"<<endl
;
1047 rrc
= *dynamic_cast<RRSIGRecordContent
*>(DNSRecordContent::mastermake(QType::RRSIG
, 1, rr
.content
));
1049 else if(rr
.qtype
.getCode() == QType::DS
) {
1050 cerr
<<"got DS"<<endl
;
1051 dsrc
= *dynamic_cast<DSRecordContent
*>(DNSRecordContent::mastermake(QType::DS
, 1, rr
.content
));
1055 toSign
.push_back(shared_ptr
<DNSRecordContent
>(DNSRecordContent::mastermake(rr
.qtype
.getCode(), 1, rr
.content
)));
1059 string msg
= getMessageForRRSET(qname
, rrc
, toSign
);
1060 cerr
<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc
.d_algorithm
, drc
.d_key
)->verify(msg
, rrc
.d_signature
)<<endl
;
1061 if(dsrc
.d_digesttype
) {
1062 cerr
<<"Calculated DS: "<<apex
.toString()<<" IN DS "<<makeDSFromDNSKey(apex
, drc
, dsrc
.d_digesttype
).getZoneRepresentation()<<endl
;
1063 cerr
<<"Original DS: "<<apex
.toString()<<" IN DS "<<dsrc
.getZoneRepresentation()<<endl
;
1066 DNSCryptoKeyEngine
*key
=DNSCryptoKeyEngine::makeFromISCString(drc
, "Private-key-format: v1.2\n"
1067 "Algorithm: 12 (ECC-GOST)\n"
1068 "GostAsn1: MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgQg/9MiXtXKg9FDXDN/R9CmVhJDyuzRAIgh4tPwCu4NHIs=\n");
1069 string resign
=key
->sign(hash
);
1070 cerr
<<Base64Encode(resign
)<<endl
;
1071 cerr
<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc
.d_algorithm
, drc
.d_key
)->verify(hash
, resign
)<<endl
;
1075 bool disableDNSSECOnZone(DNSSECKeeper
& dk
, const DNSName
& zone
)
1077 UeberBackend
B("default");
1080 if (!B
.getDomainInfo(zone
, di
)){
1081 cerr
<< "No such zone in the database" << endl
;
1085 if(!dk
.isSecuredZone(zone
)) {
1086 cerr
<<"Zone is not secured"<<endl
;
1089 DNSSECKeeper::keyset_t keyset
=dk
.getKeys(zone
);
1091 if(keyset
.empty()) {
1092 cerr
<< "No keys for zone '"<<zone
.toString()<<"'."<<endl
;
1095 for(DNSSECKeeper::keyset_t::value_type value
: keyset
) {
1096 dk
.deactivateKey(zone
, value
.second
.id
);
1097 dk
.removeKey(zone
, value
.second
.id
);
1100 dk
.unsetNSEC3PARAM(zone
);
1101 dk
.unsetPresigned(zone
);
1104 bool showZone(DNSSECKeeper
& dk
, const DNSName
& zone
)
1106 UeberBackend
B("default");
1108 std::vector
<std::string
> meta
;
1110 if (!B
.getDomainInfo(zone
, di
)){
1111 cerr
<< "No such zone in the database" << endl
;
1115 if(!dk
.isSecuredZone(zone
)) {
1116 cerr
<<"Zone is not actively secured"<<endl
;
1118 NSEC3PARAMRecordContent ns3pr
;
1120 bool haveNSEC3
=dk
.getNSEC3PARAM(zone
, &ns3pr
, &narrow
);
1122 DNSSECKeeper::keyset_t keyset
=dk
.getKeys(zone
);
1123 if (B
.getDomainMetadata(zone
, "TSIG-ALLOW-AXFR", meta
) && meta
.size() > 0) {
1124 cerr
<< "Zone has following allowed TSIG key(s): " << boost::join(meta
, ",") << endl
;
1128 if (B
.getDomainMetadata(zone
, "AXFR-MASTER-TSIG", meta
) && meta
.size() > 0) {
1129 cerr
<< "Zone uses following TSIG key(s): " << boost::join(meta
, ",") << endl
;
1132 if (dk
.isPresigned(zone
)) {
1133 cout
<<"Zone is " << (dk
.isPresigned(zone
) ? "" : "not ") << "presigned"<<endl
;
1135 vector
<DNSKEYRecordContent
> keys
;
1136 DNSResourceRecord rr
;
1138 B
.lookup(QType(QType::DNSKEY
), DNSName(zone
));
1140 if (rr
.qtype
!= QType::DNSKEY
) continue;
1141 keys
.push_back(*dynamic_cast<DNSKEYRecordContent
*>(DNSKEYRecordContent::make(rr
.getZoneRepresentation())));
1145 cerr
<< "No keys for zone '"<<zone
.toString()<<"'."<<endl
;
1150 cout
<<"Zone has NSEC semantics"<<endl
;
1152 cout
<<"Zone has " << (narrow
? "NARROW " : "") <<"hashed NSEC3 semantics, configuration: "<<ns3pr
.getZoneRepresentation()<<endl
;
1153 cout
<< "keys: "<<endl
;
1154 sort(keys
.begin(),keys
.end());
1155 reverse(keys
.begin(),keys
.end());
1156 for(const auto& key
: keys
) {
1158 algorithm2name(key
.d_algorithm
,algname
);
1159 cout
<< "tag = " << key
.getTag() << ", algo = "<<(int)key
.d_algorithm
<<endl
;
1160 cout
<< (key
.d_flags
== 257 ? "KSK" : "ZSK") << " DNSKEY = " << key
.getZoneRepresentation() << "; ( " + algname
+ " ) " <<endl
;
1161 cout
<<"DS = "<<zone
.toString()<<" IN DS "<<makeDSFromDNSKey(zone
, key
, 1).getZoneRepresentation() << " ; ( SHA1 digest )" << endl
;
1162 cout
<<"DS = "<<zone
.toString()<<" IN DS "<<makeDSFromDNSKey(zone
, key
, 2).getZoneRepresentation() << " ; ( SHA256 digest )" << endl
;
1164 cout
<<"DS = "<<zone
.toString()<<" IN DS "<<makeDSFromDNSKey(zone
, key
, 3).getZoneRepresentation() << " ; ( GOST R 34.11-94 digest )" << endl
;
1169 cout
<<"DS = "<<zone
.toString()<<" IN DS "<<makeDSFromDNSKey(zone
, key
, 4).getZoneRepresentation() << " ; ( SHA-384 digest )" << endl
;
1175 else if(keyset
.empty()) {
1176 cerr
<< "No keys for zone '"<<zone
.toString()<<"'."<<endl
;
1180 cout
<<"Zone has NSEC semantics"<<endl
;
1182 cout
<<"Zone has " << (narrow
? "NARROW " : "") <<"hashed NSEC3 semantics, configuration: "<<ns3pr
.getZoneRepresentation()<<endl
;
1184 cout
<< "keys: "<<endl
;
1185 for(DNSSECKeeper::keyset_t::value_type value
: keyset
) {
1187 algorithm2name(value
.first
.d_algorithm
, algname
);
1188 if (value
.first
.getKey()->getBits() < 1) {
1189 cout
<<"ID = "<<value
.second
.id
<<" ("<<(value
.second
.keyOrZone
? "KSK" : "ZSK")<<") <key missing or defunct>" <<endl
;
1192 cout
<<"ID = "<<value
.second
.id
<<" ("<<(value
.second
.keyOrZone
? "KSK" : "ZSK")<<"), tag = "<<value
.first
.getDNSKEY().getTag();
1193 cout
<<", algo = "<<(int)value
.first
.d_algorithm
<<", bits = "<<value
.first
.getKey()->getBits()<<"\t"<<((int)value
.second
.active
== 1 ? " A" : "Ina")<<"ctive ( " + algname
+ " ) "<<endl
;
1194 if(value
.second
.keyOrZone
|| ::arg().mustDo("direct-dnskey") || 1)
1195 cout
<<(value
.second
.keyOrZone
? "KSK" : "ZSK")<<" DNSKEY = "<<zone
.toString()<<" IN DNSKEY "<< value
.first
.getDNSKEY().getZoneRepresentation() << " ; ( " + algname
+ " )" << endl
;
1196 if(value
.second
.keyOrZone
|| 1) {
1197 cout
<<"DS = "<<zone
.toString()<<" IN DS "<<makeDSFromDNSKey(zone
, value
.first
.getDNSKEY(), 1).getZoneRepresentation() << " ; ( SHA1 digest )" << endl
;
1198 cout
<<"DS = "<<zone
.toString()<<" IN DS "<<makeDSFromDNSKey(zone
, value
.first
.getDNSKEY(), 2).getZoneRepresentation() << " ; ( SHA256 digest )" << endl
;
1200 string output
=makeDSFromDNSKey(zone
, value
.first
.getDNSKEY(), 3).getZoneRepresentation();
1201 cout
<<"DS = "<<zone
.toString()<<" IN DS "<< output
<< " ; ( GOST R 34.11-94 digest )" << endl
;
1207 string output
=makeDSFromDNSKey(zone
, value
.first
.getDNSKEY(), 4).getZoneRepresentation();
1208 cout
<<"DS = "<<zone
.toString()<<" IN DS "<< output
<< " ; ( SHA-384 digest )" << endl
;
1220 bool secureZone(DNSSECKeeper
& dk
, const DNSName
& zone
)
1223 vector
<string
> k_algos
;
1224 vector
<string
> z_algos
;
1228 stringtok(k_algos
, ::arg()["default-ksk-algorithms"], " ,");
1229 k_size
= ::arg().asNum("default-ksk-size");
1230 stringtok(z_algos
, ::arg()["default-zsk-algorithms"], " ,");
1231 z_size
= ::arg().asNum("default-zsk-size");
1234 throw runtime_error("KSK key size must be equal to or greater than 0");
1237 if (k_algos
.size() < 1 && z_algos
.size() < 1) {
1238 throw runtime_error("Zero algorithms given for KSK+ZSK in total");
1242 throw runtime_error("ZSK key size must be equal to or greater than 0");
1245 if(dk
.isSecuredZone(zone
)) {
1246 cerr
<< "Zone '"<<zone
.toString()<<"' already secure, remove keys with pdnsutil remove-zone-key if needed"<<endl
;
1251 UeberBackend
B("default");
1252 if(!B
.getDomainInfo(zone
, di
) || !di
.backend
) { // di.backend and B are mostly identical
1253 cout
<<"Can't find a zone called '"<<zone
.toString()<<"'"<<endl
;
1257 if(di
.kind
== DomainInfo::Slave
)
1259 cout
<<"Warning! This is a slave domain! If this was a mistake, please run"<<endl
;
1260 cout
<<"pdnsutil disable-dnssec "<<zone
.toString()<<" right now!"<<endl
;
1264 cout
<< "Securing zone with key size " << k_size
<< endl
;
1266 cout
<< "Securing zone with default key size" << endl
;
1269 DNSSECKeeper::keyset_t zskset
=dk
.getKeys(zone
, false);
1271 if(!zskset
.empty()) {
1272 cerr
<<"There were ZSKs already for zone '"<<zone
.toString()<<"', no need to add more"<<endl
;
1276 for(auto &k_algo
: k_algos
) {
1277 cout
<< "Adding KSK with algorithm " << k_algo
<< endl
;
1279 int algo
= shorthand2algorithm(k_algo
);
1281 if(!dk
.addKey(zone
, true, algo
, k_size
, true)) {
1282 cerr
<<"No backend was able to secure '"<<zone
.toString()<<"', most likely because no DNSSEC"<<endl
;
1283 cerr
<<"capable backends are loaded, or because the backends have DNSSEC disabled."<<endl
;
1284 cerr
<<"For the Generic SQL backends, set the 'gsqlite3-dnssec', 'gmysql-dnssec' or"<<endl
;
1285 cerr
<<"'gpgsql-dnssec' flag. Also make sure the schema has been updated for DNSSEC!"<<endl
;
1290 for(auto &z_algo
: z_algos
)
1292 cout
<< "Adding ZSK with algorithm " << z_algo
<< endl
;
1294 int algo
= shorthand2algorithm(z_algo
);
1296 if(!dk
.addKey(zone
, false, algo
, z_size
, true)) {
1297 cerr
<<"No backend was able to secure '"<<zone
.toString()<<"', most likely because no DNSSEC"<<endl
;
1298 cerr
<<"capable backends are loaded, or because the backends have DNSSEC disabled."<<endl
;
1299 cerr
<<"For the Generic SQL backends, set the 'gsqlite3-dnssec', 'gmysql-dnssec' or"<<endl
;
1300 cerr
<<"'gpgsql-dnssec' flag. Also make sure the schema has been updated for DNSSEC!"<<endl
;
1305 if(!dk
.isSecuredZone(zone
)) {
1306 cerr
<<"Failed to secure zone. Is your backend dnssec enabled? (set "<<endl
;
1307 cerr
<<"gsqlite3-dnssec, or gmysql-dnssec etc). Check this first."<<endl
;
1308 cerr
<<"If you run with the BIND backend, make sure you have configured"<<endl
;
1309 cerr
<<"it to use DNSSEC with 'bind-dnssec-db=/path/fname' and"<<endl
;
1310 cerr
<<"'pdnsutil create-bind-db /path/fname'!"<<endl
;
1314 // rectifyZone(dk, zone);
1315 // showZone(dk, zone);
1316 cout
<<"Zone "<<zone
.toString()<<" secured"<<endl
;
1320 void testSchema(DNSSECKeeper
& dk
, const DNSName
& zone
)
1322 cout
<<"Note: test-schema will try to create the zone, but it will not remove it."<<endl
;
1323 cout
<<"Please clean up after this."<<endl
;
1325 cout
<<"Constructing UeberBackend"<<endl
;
1326 UeberBackend
B("default");
1327 cout
<<"Picking first backend - if this is not what you want, edit launch line!"<<endl
;
1328 DNSBackend
*db
= B
.backends
[0];
1329 cout
<<"Creating slave domain "<<zone
.toString()<<endl
;
1330 db
->createSlaveDomain("127.0.0.1", zone
, "", "_testschema");
1331 cout
<<"Slave domain created"<<endl
;
1334 if(!B
.getDomainInfo(zone
, di
) || !di
.backend
) { // di.backend and B are mostly identical
1335 cout
<<"Can't find domain we just created, aborting"<<endl
;
1339 DNSResourceRecord rr
, rrget
;
1340 cout
<<"Starting transaction to feed records"<<endl
;
1341 db
->startTransaction(zone
, di
.id
);
1343 rr
.qtype
=QType::SOA
;
1348 rr
.content
="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
1349 cout
<<"Feeding SOA"<<endl
;
1351 rr
.qtype
=QType::TXT
;
1353 rr
.content
="\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"";
1354 cout
<<"Feeding overlong TXT"<<endl
;
1356 cout
<<"Committing"<<endl
;
1357 db
->commitTransaction();
1358 cout
<<"Querying TXT"<<endl
;
1359 db
->lookup(QType(QType::TXT
), zone
, NULL
, di
.id
);
1362 DNSResourceRecord rrthrowaway
;
1363 if(db
->get(rrthrowaway
)) // should not touch rr but don't assume anything
1365 cout
<<"Expected one record, got multiple, aborting"<<endl
;
1368 int size
=rrget
.content
.size();
1371 cout
<<"Expected 302 bytes, got "<<size
<<", aborting"<<endl
;
1375 cout
<<"[+] content field is over 255 bytes"<<endl
;
1377 cout
<<"Dropping all records, inserting SOA+2xA"<<endl
;
1378 db
->startTransaction(zone
, di
.id
);
1380 rr
.qtype
=QType::SOA
;
1385 rr
.content
="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
1386 cout
<<"Feeding SOA"<<endl
;
1390 rr
.qname
=DNSName("_underscore")+zone
;
1391 rr
.content
="127.0.0.1";
1394 rr
.qname
=DNSName("bla")+zone
;
1395 cout
<<"Committing"<<endl
;
1396 db
->commitTransaction();
1398 cout
<<"Securing zone"<<endl
;
1399 secureZone(dk
, zone
);
1400 cout
<<"Rectifying zone"<<endl
;
1401 rectifyZone(dk
, zone
);
1402 cout
<<"Checking underscore ordering"<<endl
;
1403 DNSName before
, after
;
1404 db
->getBeforeAndAfterNames(di
.id
, zone
, DNSName("z")+zone
, before
, after
);
1405 cout
<<"got '"<<before
.toString()<<"' < 'z."<<zone
.toString()<<"' < '"<<after
.toString()<<"'"<<endl
;
1406 if(before
!= DNSName("_underscore")+zone
)
1408 cout
<<"before is wrong, got '"<<before
.toString()<<"', expected '_underscore."<<zone
.toString()<<"', aborting"<<endl
;
1413 cout
<<"after is wrong, got '"<<after
.toString()<<"', expected '"<<zone
.toString()<<"', aborting"<<endl
;
1416 cout
<<"[+] ordername sorting is correct for names starting with _"<<endl
;
1418 cout
<<"End of tests, please remove "<<zone
.toString()<<" from domains+records"<<endl
;
1421 int main(int argc
, char** argv
)
1424 po::options_description
desc("Allowed options");
1426 ("help,h", "produce help message")
1427 ("verbose,v", "be verbose")
1428 ("force", "force an action")
1429 ("config-name", po::value
<string
>()->default_value(""), "virtual configuration name")
1430 ("config-dir", po::value
<string
>()->default_value(SYSCONFDIR
), "location of pdns.conf")
1431 ("commands", po::value
<vector
<string
> >());
1433 po::positional_options_description p
;
1434 p
.add("commands", -1);
1435 po::store(po::command_line_parser(argc
, argv
).options(desc
).positional(p
).run(), g_vm
);
1438 vector
<string
> cmds
;
1440 if(g_vm
.count("commands"))
1441 cmds
= g_vm
["commands"].as
<vector
<string
> >();
1443 g_verbose
= g_vm
.count("verbose");
1445 if(cmds
.empty() || g_vm
.count("help")) {
1446 cerr
<<"Usage: \npdnsutil [options] <command> [params ..]\n"<<endl
;
1447 cerr
<<"Commands:"<<endl
;
1448 cerr
<<"activate-tsig-key ZONE NAME {master|slave}"<<endl
;
1449 cerr
<<" Enable TSIG key for a zone"<<endl
;
1450 cerr
<<"activate-zone-key ZONE KEY-ID Activate the key with key id KEY-ID in ZONE"<<endl
;
1451 cerr
<<"add-zone-key ZONE {zsk|ksk} [BITS] [active|inactive]"<<endl
;
1452 cerr
<<" [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384";
1453 #ifdef HAVE_LIBSODIUM
1454 cerr
<<"|experimental-ed25519";
1457 cerr
<<" Add a ZSK or KSK to zone and specify algo&bits"<<endl
;
1458 cerr
<<"backend-cmd BACKEND CMD [CMD..] Perform one or more backend commands"<<endl
;
1459 cerr
<<"b2b-migrate OLD NEW Move all data from one backend to another"<<endl
;
1460 cerr
<<"bench-db [filename] Bench database backend with queries, one domain per line"<<endl
;
1461 cerr
<<"check-zone ZONE Check a zone for correctness"<<endl
;
1462 cerr
<<"check-all-zones [exit-on-error] Check all zones for correctness. Set exit-on-error to exit immediately"<<endl
;
1463 cerr
<<" after finding an error in a zone."<<endl
;
1464 cerr
<<"create-bind-db FNAME Create DNSSEC db for BIND backend (bind-dnssec-db)"<<endl
;
1465 cerr
<<"create-zone ZONE Create empty zone ZONE"<<endl
;
1466 cerr
<<"deactivate-tsig-key ZONE NAME {master|slave}"<<endl
;
1467 cerr
<<" Disable TSIG key for a zone"<<endl
;
1468 cerr
<<"deactivate-zone-key ZONE KEY-ID Deactivate the key with key id KEY-ID in ZONE"<<endl
;
1469 cerr
<<"delete-tsig-key NAME Delete TSIG key (warning! will not unmap key!)"<<endl
;
1470 cerr
<<"delete-zone ZONE Delete the zone"<<endl
;
1471 cerr
<<"disable-dnssec ZONE Deactivate all keys and unset PRESIGNED in ZONE"<<endl
;
1472 cerr
<<"export-zone-dnskey ZONE KEY-ID Export to stdout the public DNSKEY described"<<endl
;
1473 cerr
<<"export-zone-key ZONE KEY-ID Export to stdout the private key described"<<endl
;
1474 cerr
<<"generate-tsig-key NAME ALGORITHM Generate new TSIG key"<<endl
;
1475 cerr
<<"generate-zone-key {zsk|ksk} [ALGORITHM] [BITS]"<<endl
;
1476 cerr
<<" Generate a ZSK or KSK to stdout with specified ALGORITHM and BITS"<<endl
;
1477 cerr
<<"get-meta ZONE [KIND ...] Get zone metadata. If no KIND given, lists all known"<<endl
;
1478 cerr
<<"hash-zone-record ZONE RNAME Calculate the NSEC3 hash for RNAME in ZONE"<<endl
;
1480 cerr
<<"hsm assign ZONE ALGORITHM {ksk|zsk} MODULE SLOT PIN LABEL"<<endl
<<
1481 " Assign a hardware signing module to a ZONE"<<endl
;
1482 cerr
<<"hsm create-key ZONE KEY-ID [BITS] Create a key using hardware signing module for ZONE (use assign first)"<<endl
;
1483 cerr
<<" BITS defaults to 2048"<<endl
;
1485 cerr
<<"increase-serial ZONE Increases the SOA-serial by 1. Uses SOA-EDIT"<<endl
;
1486 cerr
<<"import-tsig-key NAME ALGORITHM KEY Import TSIG key"<<endl
;
1487 cerr
<<"import-zone-key ZONE FILE Import from a file a private key, ZSK or KSK"<<endl
;
1488 cerr
<<" [active|inactive] [ksk|zsk] Defaults to KSK and active"<<endl
;
1489 cerr
<<"load-zone ZONE FILE Load ZONE from FILE, possibly creating zone or atomically"<<endl
;
1490 cerr
<<" replacing contents"<<endl
;
1491 cerr
<<"list-keys [ZONE] List DNSSEC keys for ZONE. When ZONE is unset or \"all\", display all keys for all zones"<<endl
;
1492 cerr
<<"list-zone ZONE List zone contents"<<endl
;
1493 cerr
<<"list-all-zones [master|slave|native]"<<endl
;
1494 cerr
<<" List all zone names"<<endl
;;
1495 cerr
<<"list-tsig-keys List all TSIG keys"<<endl
;
1496 cerr
<<"rectify-zone ZONE [ZONE ..] Fix up DNSSEC fields (order, auth)"<<endl
;
1497 cerr
<<"rectify-all-zones Rectify all zones."<<endl
;
1498 cerr
<<"remove-zone-key ZONE KEY-ID Remove key with KEY-ID from ZONE"<<endl
;
1499 cerr
<<"secure-all-zones [increase-serial] Secure all zones without keys."<<endl
;
1500 cerr
<<"secure-zone ZONE [ZONE ..] Add KSK and two ZSKs for ZONE"<<endl
;
1501 cerr
<<"set-nsec3 ZONE ['PARAMS' [narrow]] Enable NSEC3 with PARAMS. Optionally narrow"<<endl
;
1502 cerr
<<"set-presigned ZONE Use presigned RRSIGs from storage"<<endl
;
1503 cerr
<<"set-publish-cdnskey ZONE Enable sending CDNSKEY responses for ZONE"<<endl
;
1504 cerr
<<"set-publish-cds ZONE [DIGESTALGOS] Enable sending CDS responses for ZONE, using DIGESTALGOS as signature algirithms"<<endl
;
1505 cerr
<<" DIGESTALGOS should be a comma separated list of numbers, is is '1,2' by default"<<endl
;
1506 cerr
<<"set-meta ZONE KIND [VALUE ..]"<<endl
;
1507 cerr
<<" Set zone metadata, optionally providing a value. Empty clears meta."<<endl
;
1508 cerr
<<"show-zone ZONE Show DNSSEC (public) key details about a zone"<<endl
;
1509 cerr
<<"unset-nsec3 ZONE Switch back to NSEC"<<endl
;
1510 cerr
<<"unset-presigned ZONE No longer use presigned RRSIGs"<<endl
;
1511 cerr
<<"unset-publish-cdnskey ZONE Disable sending CDNSKEY responses for ZONE"<<endl
;
1512 cerr
<<"unset-publish-cds ZONE Disable sending CDS responses for ZONE"<<endl
;
1513 cerr
<<"test-schema ZONE Test DB schema - will create ZONE"<<endl
;
1518 #ifdef HAVE_LIBSODIUM
1519 if (sodium_init() == -1) {
1520 cerr
<<"Unable to initialize sodium crypto library"<<endl
;
1525 if (cmds
[0] == "test-algorithm") {
1526 if(cmds
.size() != 2) {
1527 cerr
<< "Syntax: pdnsutil test-algorithm algonum"<<endl
;
1530 if (testAlgorithm(pdns_stou(cmds
[1])))
1535 if(cmds
[0] == "test-algorithms") {
1536 if (testAlgorithms())
1541 loadMainConfig(g_vm
["config-dir"].as
<string
>());
1544 if(cmds
[0] == "create-bind-db") {
1546 if(cmds
.size() != 2) {
1547 cerr
<< "Syntax: pdnsutil create-bind-db FNAME"<<endl
;
1551 SSQLite3
db(cmds
[1], true); // create=ok
1552 vector
<string
> statements
;
1553 stringtok(statements
, sqlCreate
, ";");
1554 for(const string
& statement
: statements
) {
1555 db
.execute(statement
);
1558 catch(SSqlException
& se
) {
1559 throw PDNSException("Error creating database in BIND backend: "+se
.txtReason());
1563 cerr
<<"bind-dnssec-db requires building PowerDNS with SQLite3"<<endl
;
1570 if (cmds
[0] == "test-schema") {
1571 if(cmds
.size() != 2) {
1572 cerr
<< "Syntax: pdnsutil test-schema ZONE"<<endl
;
1575 testSchema(dk
, DNSName(cmds
[1]));
1578 if(cmds
[0] == "rectify-zone") {
1579 if(cmds
.size() < 2) {
1580 cerr
<< "Syntax: pdnsutil rectify-zone ZONE [ZONE..]"<<endl
;
1583 unsigned int exitCode
= 0;
1584 for(unsigned int n
= 1; n
< cmds
.size(); ++n
)
1585 if (!rectifyZone(dk
, DNSName(cmds
[n
])))
1589 else if (cmds
[0] == "rectify-all-zones") {
1590 rectifyAllZones(dk
);
1592 else if(cmds
[0] == "check-zone") {
1593 if(cmds
.size() != 2) {
1594 cerr
<< "Syntax: pdnsutil check-zone ZONE"<<endl
;
1597 UeberBackend
B("default");
1598 exit(checkZone(dk
, B
, DNSName(cmds
[1])));
1600 else if(cmds
[0] == "bench-db") {
1601 dbBench(cmds
.size() > 1 ? cmds
[1] : "");
1603 else if (cmds
[0] == "check-all-zones") {
1604 bool exitOnError
= (cmds
[1] == "exit-on-error");
1605 exit(checkAllZones(dk
, exitOnError
));
1607 else if (cmds
[0] == "list-all-zones") {
1608 if (cmds
.size() > 2) {
1609 cerr
<< "Syntax: pdnsutil list-all-zones [master|slave|native]"<<endl
;
1612 if (cmds
.size() == 2)
1613 return listAllZones(cmds
[1]);
1614 return listAllZones();
1616 else if (cmds
[0] == "test-zone") {
1617 cerr
<< "Did you mean check-zone?"<<endl
;
1620 else if (cmds
[0] == "test-all-zones") {
1621 cerr
<< "Did you mean check-all-zones?"<<endl
;
1625 else if(cmds
[0] == "signing-server" )
1629 else if(cmds
[0] == "signing-slave")
1631 launchSigningService(0);
1634 else if(cmds
[0] == "test-speed") {
1635 if(cmds
.size() < 2) {
1636 cerr
<< "Syntax: pdnsutil test-speed numcores [signing-server]"<<endl
;
1639 testSpeed(dk
, DNSName(cmds
[1]), (cmds
.size() > 3) ? cmds
[3] : "", pdns_stou(cmds
[2]));
1641 else if(cmds
[0] == "verify-crypto") {
1642 if(cmds
.size() != 2) {
1643 cerr
<< "Syntax: pdnsutil verify-crypto FILE"<<endl
;
1646 verifyCrypto(cmds
[1]);
1649 else if(cmds
[0] == "show-zone") {
1650 if(cmds
.size() != 2) {
1651 cerr
<< "Syntax: pdnsutil show-zone ZONE"<<endl
;
1654 if (!showZone(dk
, DNSName(cmds
[1]))) return 1;
1656 else if(cmds
[0] == "disable-dnssec") {
1657 if(cmds
.size() != 2) {
1658 cerr
<< "Syntax: pdnsutil disable-dnssec ZONE"<<endl
;
1661 DNSName
zone(cmds
[1]);
1662 if(!disableDNSSECOnZone(dk
, zone
)) {
1663 cerr
<< "Cannot disable DNSSEC on " << zone
<< endl
;
1667 else if(cmds
[0] == "activate-zone-key") {
1668 if(cmds
.size() != 3) {
1669 cerr
<< "Syntax: pdnsutil activate-zone-key ZONE KEY-ID"<<endl
;
1672 DNSName
zone(cmds
[1]);
1673 unsigned int id
=pdns_stou(cmds
[2]);
1676 cerr
<<"Invalid KEY-ID"<<endl
;
1679 if (!dk
.activateKey(zone
, id
)) {
1680 cerr
<<"Activation of key failed"<<endl
;
1685 else if(cmds
[0] == "deactivate-zone-key") {
1686 if(cmds
.size() != 3) {
1687 cerr
<< "Syntax: pdnsutil deactivate-zone-key ZONE KEY-ID"<<endl
;
1690 DNSName
zone(cmds
[1]);
1691 unsigned int id
=pdns_stou(cmds
[2]);
1694 cerr
<<"Invalid KEY-ID"<<endl
;
1697 if (!dk
.deactivateKey(zone
, id
)) {
1698 cerr
<<"Deactivation of key failed"<<endl
;
1703 else if(cmds
[0] == "add-zone-key") {
1704 if(cmds
.size() < 3 ) {
1705 cerr
<< "Syntax: pdnsutil add-zone-key ZONE zsk|ksk [bits] [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384]"<<endl
;
1708 DNSName
zone(cmds
[1]);
1710 UeberBackend
B("default");
1713 if (!B
.getDomainInfo(zone
, di
)){
1714 cerr
<< "No such zone in the database" << endl
;
1718 // need to get algorithm, bits & ksk or zsk from commandline
1719 bool keyOrZone
=false;
1724 for(unsigned int n
=2; n
< cmds
.size(); ++n
) {
1725 if(pdns_iequals(cmds
[n
], "zsk"))
1727 else if(pdns_iequals(cmds
[n
], "ksk"))
1729 else if((tmp_algo
= shorthand2algorithm(cmds
[n
]))>0) {
1730 algorithm
= tmp_algo
;
1731 } else if(pdns_iequals(cmds
[n
], "active")) {
1733 } else if(pdns_iequals(cmds
[n
], "inactive") || pdns_iequals(cmds
[n
], "passive")) { // 'passive' eventually needs to be removed
1735 } else if(pdns_stou(cmds
[n
])) {
1736 bits
= pdns_stou(cmds
[n
]);
1738 cerr
<<"Unknown algorithm, key flag or size '"<<cmds
[n
]<<"'"<<endl
;
1739 exit(EXIT_FAILURE
);;
1742 if(!dk
.addKey(zone
, keyOrZone
, algorithm
, bits
, active
)) {
1743 cerr
<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl
;
1747 cerr
<<"Added a " << (keyOrZone
? "KSK" : "ZSK")<<" with algorithm = "<<algorithm
<<", active="<<active
<<endl
;
1749 cerr
<<"Requested specific key size of "<<bits
<<" bits"<<endl
;
1752 else if(cmds
[0] == "remove-zone-key") {
1753 if(cmds
.size() < 3) {
1754 cerr
<<"Syntax: pdnsutil remove-zone-key ZONE KEY-ID"<<endl
;
1757 DNSName
zone(cmds
[1]);
1758 unsigned int id
=pdns_stou(cmds
[2]);
1759 if (!dk
.removeKey(zone
, id
)) {
1760 cerr
<<"Cannot remove key " << id
<< " from " << zone
<<endl
;
1765 else if(cmds
[0] == "delete-zone") {
1766 if(cmds
.size() != 2) {
1767 cerr
<<"Syntax: pdnsutil delete-zone ZONE"<<endl
;
1770 exit(deleteZone(DNSName(cmds
[1])));
1772 else if(cmds
[0] == "create-zone") {
1773 if(cmds
.size() != 2) {
1774 cerr
<<"Syntax: pdnsutil create-zone ZONE"<<endl
;
1777 exit(createZone(DNSName(cmds
[1])));
1779 else if(cmds
[0] == "list-zone") {
1780 if(cmds
.size() != 2) {
1781 cerr
<<"Syntax: pdnsutil list-zone ZONE"<<endl
;
1787 exit(listZone(DNSName(cmds
[1])));
1789 else if(cmds
[0] == "list-keys") {
1790 if(cmds
.size() > 2) {
1791 cerr
<<"Syntax: pdnsutil list-keys [ZONE]"<<endl
;
1794 string zname
= (cmds
.size() == 2) ? cmds
[1] : "all";
1795 exit(listKeys(zname
, dk
));
1797 else if(cmds
[0] == "load-zone") {
1798 if(cmds
.size() != 3) {
1799 cerr
<<"Syntax: pdnsutil load-zone ZONE FILENAME"<<endl
;
1805 exit(loadZone(DNSName(cmds
[1]), cmds
[2]));
1807 else if(cmds
[0] == "secure-zone") {
1808 if(cmds
.size() < 2) {
1809 cerr
<< "Syntax: pdnsutil secure-zone ZONE"<<endl
;
1812 vector
<DNSName
> mustRectify
;
1813 unsigned int zoneErrors
=0;
1814 for(unsigned int n
= 1; n
< cmds
.size(); ++n
) {
1815 DNSName
zone(cmds
[n
]);
1816 dk
.startTransaction(zone
, -1);
1817 if(secureZone(dk
, zone
)) {
1818 mustRectify
.push_back(zone
);
1822 dk
.commitTransaction();
1825 for(const auto& zone
: mustRectify
)
1826 rectifyZone(dk
, zone
);
1833 else if (cmds
[0] == "secure-all-zones") {
1834 if (cmds
.size() >= 2 && !pdns_iequals(cmds
[1], "increase-serial")) {
1835 cerr
<< "Syntax: pdnsutil secure-all-zones [increase-serial]"<<endl
;
1839 UeberBackend
B("default");
1841 vector
<DomainInfo
> domainInfo
;
1842 B
.getAllDomains(&domainInfo
);
1844 unsigned int zonesSecured
=0, zoneErrors
=0;
1845 for(DomainInfo di
: domainInfo
) {
1846 if(!dk
.isSecuredZone(di
.zone
)) {
1847 cout
<<"Securing "<<di
.zone
.toString()<<": ";
1848 if (secureZone(dk
, di
.zone
)) {
1850 if (cmds
.size() == 2) {
1851 if (!increaseSerial(di
.zone
, dk
))
1860 cout
<<"Secured: "<<zonesSecured
<<" zones. Errors: "<<zoneErrors
<<endl
;
1867 else if(cmds
[0]=="set-nsec3") {
1868 if(cmds
.size() < 2) {
1869 cerr
<<"Syntax: pdnsutil set-nsec3 ZONE 'params' [narrow]"<<endl
;
1872 string nsec3params
= cmds
.size() > 2 ? cmds
[2] : "1 0 1 ab";
1873 bool narrow
= cmds
.size() > 3 && cmds
[3]=="narrow";
1874 NSEC3PARAMRecordContent
ns3pr(nsec3params
);
1876 DNSName
zone(cmds
[1]);
1877 if (zone
.wirelength() > 222) {
1878 cerr
<<"Cannot enable NSEC3 for " << zone
.toString() << " as it is too long (" << zone
.wirelength() << " bytes, maximum is 222 bytes)"<<endl
;
1881 if (! dk
.setNSEC3PARAM(zone
, ns3pr
, narrow
)) {
1882 cerr
<<"Cannot set NSEC3 param for " << zone
.toString() << endl
;
1887 cerr
<<"NSEC3 set, ";
1889 cerr
<<"NSEC3 (opt-out) set, ";
1891 if(dk
.isSecuredZone(zone
))
1892 cerr
<<"please rectify your zone if your backend needs it"<<endl
;
1894 cerr
<<"please secure and rectify your zone."<<endl
;
1898 else if(cmds
[0]=="set-presigned") {
1899 if(cmds
.size() < 2) {
1900 cerr
<<"Syntax: pdnsutil set-presigned ZONE"<<endl
;
1903 if (! dk
.setPresigned(DNSName(cmds
[1]))) {
1904 cerr
<< "Could not set presigned on for " << cmds
[1] << endl
;
1909 else if(cmds
[0]=="set-publish-cdnskey") {
1910 if(cmds
.size() < 2) {
1911 cerr
<<"Syntax: pdnsutil set-publish-cdnskey ZONE"<<endl
;
1914 if (! dk
.setPublishCDNSKEY(DNSName(cmds
[1]))) {
1915 cerr
<< "Could not set publishing for CDNSKEY records for "<< cmds
[1]<<endl
;
1920 else if(cmds
[0]=="set-publish-cds") {
1921 if(cmds
.size() < 2) {
1922 cerr
<<"Syntax: pdnsutil set-publish-cds ZONE [DIGESTALGOS]"<<endl
;
1926 // If DIGESTALGOS is unset
1927 if(cmds
.size() == 2)
1928 cmds
.push_back("1,2");
1930 if (! dk
.setPublishCDS(DNSName(cmds
[1]), cmds
[2])) {
1931 cerr
<< "Could not set publishing for CDS records for "<< cmds
[1]<<endl
;
1936 else if(cmds
[0]=="unset-presigned") {
1937 if(cmds
.size() < 2) {
1938 cerr
<<"Syntax: pdnsutil unset-presigned ZONE"<<endl
;
1941 if (! dk
.unsetPresigned(DNSName(cmds
[1]))) {
1942 cerr
<< "Could not unset presigned on for " << cmds
[1] << endl
;
1947 else if(cmds
[0]=="unset-publish-cdnskey") {
1948 if(cmds
.size() < 2) {
1949 cerr
<<"Syntax: pdnsutil unset-publish-cdnskey ZONE"<<endl
;
1952 if (! dk
.unsetPublishCDNSKEY(DNSName(cmds
[1]))) {
1953 cerr
<< "Could not unset publishing for CDNSKEY records for "<< cmds
[1]<<endl
;
1958 else if(cmds
[0]=="unset-publish-cds") {
1959 if(cmds
.size() < 2) {
1960 cerr
<<"Syntax: pdnsutil unset-publish-cds ZONE"<<endl
;
1963 if (! dk
.unsetPublishCDS(DNSName(cmds
[1]))) {
1964 cerr
<< "Could not unset publishing for CDS records for "<< cmds
[1]<<endl
;
1969 else if(cmds
[0]=="hash-zone-record") {
1970 if(cmds
.size() < 3) {
1971 cerr
<<"Syntax: pdnsutil hash-zone-record ZONE RNAME"<<endl
;
1974 DNSName
zone(cmds
[1]);
1975 DNSName
record(cmds
[2]);
1976 NSEC3PARAMRecordContent ns3pr
;
1978 if(!dk
.getNSEC3PARAM(zone
, &ns3pr
, &narrow
)) {
1979 cerr
<<"The '"<<zone
.toString()<<"' zone does not use NSEC3"<<endl
;
1983 cerr
<<"The '"<<zone
.toString()<<"' zone uses narrow NSEC3, but calculating hash anyhow"<<endl
;
1986 cout
<<toBase32Hex(hashQNameWithSalt(ns3pr
, record
))<<endl
;
1988 else if(cmds
[0]=="unset-nsec3") {
1989 if(cmds
.size() < 2) {
1990 cerr
<<"Syntax: pdnsutil unset-nsec3 ZONE"<<endl
;
1993 if ( ! dk
.unsetNSEC3PARAM(DNSName(cmds
[1]))) {
1994 cerr
<<"Cannot unset NSEC3 param for " << cmds
[1] << endl
;
1999 else if(cmds
[0]=="export-zone-key") {
2000 if(cmds
.size() < 3) {
2001 cerr
<<"Syntax: pdnsutil export-zone-key ZONE KEY-ID"<<endl
;
2005 string zone
=cmds
[1];
2006 unsigned int id
=pdns_stou(cmds
[2]);
2007 DNSSECPrivateKey dpk
=dk
.getKeyById(DNSName(zone
), id
);
2008 cout
<< dpk
.getKey()->convertToISC() <<endl
;
2010 else if(cmds
[0]=="increase-serial") {
2011 if (cmds
.size() < 2) {
2012 cerr
<<"Syntax: pdnsutil increase-serial ZONE"<<endl
;
2015 return increaseSerial(DNSName(cmds
[1]), dk
);
2017 else if(cmds
[0]=="import-zone-key-pem") {
2018 if(cmds
.size() < 4) {
2019 cerr
<<"Syntax: pdnsutil import-zone-key-pem ZONE FILE ALGORITHM {ksk|zsk}"<<endl
;
2022 string zone
=cmds
[1];
2023 string fname
=cmds
[2];
2025 ifstream
ifs(fname
.c_str());
2026 string tmp
, interim
, raw
;
2027 while(getline(ifs
, line
)) {
2033 B64Decode(interim
, raw
);
2034 DNSSECPrivateKey dpk
;
2035 DNSKEYRecordContent drc
;
2036 shared_ptr
<DNSCryptoKeyEngine
> key(DNSCryptoKeyEngine::makeFromPEMString(drc
, raw
));
2039 dpk
.d_algorithm
= pdns_stou(cmds
[3]);
2041 if(dpk
.d_algorithm
== 7)
2042 dpk
.d_algorithm
= 5;
2044 cerr
<<(int)dpk
.d_algorithm
<<endl
;
2046 if(cmds
.size() > 4) {
2047 if(pdns_iequals(cmds
[4], "ZSK"))
2049 else if(pdns_iequals(cmds
[4], "KSK"))
2052 cerr
<<"Unknown key flag '"<<cmds
[4]<<"'"<<endl
;
2057 dpk
.d_flags
= 257; // ksk
2059 if(!dk
.addKey(DNSName(zone
), dpk
)) {
2060 cerr
<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl
;
2065 else if(cmds
[0]=="import-zone-key") {
2066 if(cmds
.size() < 3) {
2067 cerr
<<"Syntax: pdnsutil import-zone-key ZONE FILE [ksk|zsk] [active|inactive]"<<endl
;
2070 string zone
=cmds
[1];
2071 string fname
=cmds
[2];
2072 DNSSECPrivateKey dpk
;
2073 DNSKEYRecordContent drc
;
2074 shared_ptr
<DNSCryptoKeyEngine
> key(DNSCryptoKeyEngine::makeFromISCFile(drc
, fname
.c_str()));
2076 dpk
.d_algorithm
= drc
.d_algorithm
;
2078 if(dpk
.d_algorithm
== 7)
2079 dpk
.d_algorithm
= 5;
2084 for(unsigned int n
= 3; n
< cmds
.size(); ++n
) {
2085 if(pdns_iequals(cmds
[n
], "ZSK"))
2087 else if(pdns_iequals(cmds
[n
], "KSK"))
2089 else if(pdns_iequals(cmds
[n
], "active"))
2091 else if(pdns_iequals(cmds
[n
], "passive") || pdns_iequals(cmds
[n
], "inactive")) // passive eventually needs to be removed
2094 cerr
<<"Unknown key flag '"<<cmds
[n
]<<"'"<<endl
;
2098 if(!dk
.addKey(DNSName(zone
), dpk
, active
)) {
2099 cerr
<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl
;
2103 else if(cmds
[0]=="export-zone-dnskey") {
2104 if(cmds
.size() < 3) {
2105 cerr
<<"Syntax: pdnsutil export-zone-dnskey ZONE KEY-ID"<<endl
;
2109 DNSName
zone(cmds
[1]);
2110 unsigned int id
=pdns_stou(cmds
[2]);
2111 DNSSECPrivateKey dpk
=dk
.getKeyById(zone
, id
);
2112 cout
<< zone
<<" IN DNSKEY "<<dpk
.getDNSKEY().getZoneRepresentation() <<endl
;
2113 if(dpk
.d_flags
== 257) {
2114 cout
<< zone
<< " IN DS "<<makeDSFromDNSKey(zone
, dpk
.getDNSKEY(), 1).getZoneRepresentation() << endl
;
2115 cout
<< zone
<< " IN DS "<<makeDSFromDNSKey(zone
, dpk
.getDNSKEY(), 2).getZoneRepresentation() << endl
;
2118 else if(cmds
[0] == "generate-zone-key") {
2119 if(cmds
.size() < 2 ) {
2120 cerr
<< "Syntax: pdnsutil generate-zone-key zsk|ksk [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384] [bits]"<<endl
;
2123 // need to get algorithm, bits & ksk or zsk from commandline
2124 bool keyOrZone
=false;
2128 for(unsigned int n
=1; n
< cmds
.size(); ++n
) {
2129 if(pdns_iequals(cmds
[n
], "zsk"))
2131 else if(pdns_iequals(cmds
[n
], "ksk"))
2133 else if((tmp_algo
= shorthand2algorithm(cmds
[n
]))>0) {
2134 algorithm
= tmp_algo
;
2135 } else if(pdns_stou(cmds
[n
]))
2136 bits
= pdns_stou(cmds
[n
]);
2138 cerr
<<"Unknown algorithm, key flag or size '"<<cmds
[n
]<<"'"<<endl
;
2142 cerr
<<"Generating a " << (keyOrZone
? "KSK" : "ZSK")<<" with algorithm = "<<algorithm
<<endl
;
2144 cerr
<<"Requesting specific key size of "<<bits
<<" bits"<<endl
;
2146 DNSSECPrivateKey dspk
;
2147 shared_ptr
<DNSCryptoKeyEngine
> dpk(DNSCryptoKeyEngine::make(algorithm
)); // defaults to RSA for now, could be smart w/algorithm! XXX FIXME
2150 bits
= keyOrZone
? 2048 : 1024;
2152 if(algorithm
== 12 || algorithm
== 13 || algorithm
== 250) // ECDSA, GOST, ED25519
2154 else if(algorithm
== 14)
2157 throw runtime_error("Can't guess key size for algorithm "+std::to_string(algorithm
));
2163 dspk
.d_algorithm
= algorithm
;
2164 dspk
.d_flags
= keyOrZone
? 257 : 256;
2166 // print key to stdout
2167 cout
<< "Flags: " << dspk
.d_flags
<< endl
<<
2168 dspk
.getKey()->convertToISC() << endl
;
2169 } else if (cmds
[0]=="generate-tsig-key") {
2170 if (cmds
.size() < 3) {
2171 cerr
<< "Syntax: " << cmds
[0] << " name (hmac-md5|hmac-sha1|hmac-sha224|hmac-sha256|hmac-sha384|hmac-sha512)" << endl
;
2174 DNSName
name(cmds
[1]);
2175 string algo
= cmds
[2];
2180 if (algo
== "hmac-md5") {
2182 } else if (algo
== "hmac-sha1") {
2184 } else if (algo
== "hmac-sha224") {
2186 } else if (algo
== "hmac-sha256") {
2188 } else if (algo
== "hmac-sha384") {
2190 } else if (algo
== "hmac-sha512") {
2193 cerr
<< "Cannot generate key for " << algo
<< endl
;
2197 cerr
<< "Generating new key with " << klen
<< " bytes (this can take a while)" << endl
;
2198 seedRandom(::arg()["entropy-source"]);
2199 for(size_t i
= 0; i
< klen
; i
+=4) {
2200 *(unsigned int*)(tmpkey
+i
) = dns_random(0xffffffff);
2202 key
= Base64Encode(std::string(tmpkey
, klen
));
2204 UeberBackend
B("default");
2205 if (B
.setTSIGKey(name
, DNSName(algo
), key
)) { // you are feeling bored, put up DNSName(algo) up earlier
2206 cout
<< "Create new TSIG key " << name
<< " " << algo
<< " " << key
<< endl
;
2208 cout
<< "Failure storing new TSIG key " << name
<< " " << algo
<< " " << key
<< endl
;
2212 } else if (cmds
[0]=="import-tsig-key") {
2213 if (cmds
.size() < 4) {
2214 cerr
<< "Syntax: " << cmds
[0] << " name algorithm key" << endl
;
2217 DNSName
name(cmds
[1]);
2218 string algo
= cmds
[2];
2219 string key
= cmds
[3];
2221 UeberBackend
B("default");
2222 if (B
.setTSIGKey(name
, DNSName(algo
), key
)) {
2223 cout
<< "Imported TSIG key " << name
<< " " << algo
<< endl
;
2225 cout
<< "Failure importing TSIG key " << name
<< " " << algo
<< endl
;
2229 } else if (cmds
[0]=="delete-tsig-key") {
2230 if (cmds
.size() < 2) {
2231 cerr
<< "Syntax: " << cmds
[0] << " name" << endl
;
2234 DNSName
name(cmds
[1]);
2236 UeberBackend
B("default");
2237 if (B
.deleteTSIGKey(name
)) {
2238 cout
<< "Deleted TSIG key " << name
<< endl
;
2240 cout
<< "Failure deleting TSIG key " << name
<< endl
;
2244 } else if (cmds
[0]=="list-tsig-keys") {
2245 std::vector
<struct TSIGKey
> keys
;
2246 UeberBackend
B("default");
2247 if (B
.getTSIGKeys(keys
)) {
2248 for(const struct TSIGKey
&key
: keys
) {
2249 cout
<< key
.name
.toString() << " " << key
.algorithm
.toString() << " " << key
.key
<< endl
;
2253 } else if (cmds
[0]=="activate-tsig-key") {
2255 if (cmds
.size() < 4) {
2256 cerr
<< "Syntax: " << cmds
[0] << " ZONE NAME {master|slave}" << endl
;
2259 DNSName
zname(cmds
[1]);
2260 string name
= cmds
[2];
2261 if (cmds
[3] == "master")
2262 metaKey
= "TSIG-ALLOW-AXFR";
2263 else if (cmds
[3] == "slave")
2264 metaKey
= "AXFR-MASTER-TSIG";
2266 cerr
<< "Invalid parameter '" << cmds
[3] << "', expected master or slave" << endl
;
2269 UeberBackend
B("default");
2270 std::vector
<std::string
> meta
;
2271 if (!B
.getDomainMetadata(zname
, metaKey
, meta
)) {
2272 cout
<< "Failure enabling TSIG key " << name
<< " for " << zname
<< endl
;
2276 for(std::string tmpname
: meta
) {
2277 if (tmpname
== name
) { found
= true; break; }
2279 if (!found
) meta
.push_back(name
);
2280 if (B
.setDomainMetadata(zname
, metaKey
, meta
)) {
2281 cout
<< "Enabled TSIG key " << name
<< " for " << zname
<< endl
;
2283 cout
<< "Failure enabling TSIG key " << name
<< " for " << zname
<< endl
;
2287 } else if (cmds
[0]=="deactivate-tsig-key") {
2289 if (cmds
.size() < 4) {
2290 cerr
<< "Syntax: " << cmds
[0] << " ZONE NAME {master|slave}" << endl
;
2293 DNSName
zname(cmds
[1]);
2294 string name
= cmds
[2];
2295 if (cmds
[3] == "master")
2296 metaKey
= "TSIG-ALLOW-AXFR";
2297 else if (cmds
[3] == "slave")
2298 metaKey
= "AXFR-MASTER-TSIG";
2300 cerr
<< "Invalid parameter '" << cmds
[3] << "', expected master or slave" << endl
;
2304 UeberBackend
B("default");
2305 std::vector
<std::string
> meta
;
2306 if (!B
.getDomainMetadata(zname
, metaKey
, meta
)) {
2307 cout
<< "Failure disabling TSIG key " << name
<< " for " << zname
<< endl
;
2310 std::vector
<std::string
>::iterator iter
= meta
.begin();
2311 for(;iter
!= meta
.end(); iter
++) if (*iter
== name
) break;
2312 if (iter
!= meta
.end()) meta
.erase(iter
);
2313 if (B
.setDomainMetadata(zname
, metaKey
, meta
)) {
2314 cout
<< "Disabled TSIG key " << name
<< " for " << zname
<< endl
;
2316 cout
<< "Failure disabling TSIG key " << name
<< " for " << zname
<< endl
;
2320 } else if (cmds
[0]=="get-meta") {
2321 UeberBackend
B("default");
2322 if (cmds
.size() < 2) {
2323 cerr
<< "Syntax: " << cmds
[0] << " zone [kind kind ..]" << endl
;
2326 DNSName
zone(cmds
[1]);
2327 vector
<string
> keys
;
2330 if (!B
.getDomainInfo(zone
, di
)) {
2331 cerr
<< "Invalid zone '" << zone
<< "'" << endl
;
2335 if (cmds
.size() > 2) {
2336 keys
.assign(cmds
.begin() + 2, cmds
.end());
2337 std::cout
<< "Metadata for '" << zone
<< "'" << endl
;
2338 for(const string kind
: keys
) {
2339 vector
<string
> meta
;
2341 if (B
.getDomainMetadata(zone
, kind
, meta
)) {
2342 cout
<< kind
<< " = " << boost::join(meta
, ", ") << endl
;
2346 std::map
<std::string
, std::vector
<std::string
> > meta
;
2347 std::cout
<< "Metadata for '" << zone
<< "'" << endl
;
2348 B
.getAllDomainMetadata(zone
, meta
);
2349 for(std::map
<std::string
, std::vector
<std::string
> >::const_iterator each_meta
= meta
.begin(); each_meta
!= meta
.end(); each_meta
++) {
2350 cout
<< each_meta
->first
<< " = " << boost::join(each_meta
->second
, ", ") << endl
;
2355 } else if (cmds
[0]=="set-meta") {
2356 UeberBackend
B("default");
2357 if (cmds
.size() < 3) {
2358 cerr
<< "Syntax: " << cmds
[0] << " zone kind [value value ..]" << endl
;
2361 DNSName
zone(cmds
[1]);
2362 string kind
= cmds
[2];
2363 vector
<string
> meta(cmds
.begin() + 3, cmds
.end());
2365 if (!B
.setDomainMetadata(zone
, kind
, meta
)) {
2366 cerr
<< "Unable to set meta for '" << zone
<< "'" << endl
;
2369 cout
<< "Set '" << zone
.toStringNoDot() << "' meta " << kind
<< " = " << boost::join(meta
, ", ") << endl
;
2371 } else if (cmds
[0]=="hsm") {
2373 UeberBackend
B("default");
2374 if (cmds
[1] == "assign") {
2375 DNSCryptoKeyEngine::storvector_t storvect
;
2377 std::vector
<DNSBackend::KeyData
> keys
;
2379 if (cmds
.size() < 9) {
2380 std::cout
<< "Usage: pdnsutil hsm assign ZONE ALGORITHM {ksk|zsk} MODULE TOKEN PIN LABEL" << std::endl
;
2384 DNSName
zone(cmds
[2]);
2387 if (!B
.getDomainInfo(zone
, di
)) {
2388 cerr
<< "Unable to assign module to unknown zone '" << zone
<< "'" << std::endl
;
2392 int algorithm
= shorthand2algorithm(cmds
[3]);
2394 cerr
<< "Unable to use unknown algorithm '" << cmds
[3] << "'" << std::endl
;
2399 bool keyOrZone
= (cmds
[4] == "ksk" ? true : false);
2400 string module
= cmds
[5];
2401 string slot
= cmds
[6];
2402 string pin
= cmds
[7];
2403 string label
= cmds
[8];
2405 std::ostringstream iscString
;
2406 iscString
<< "Private-key-format: v1.2" << std::endl
<<
2407 "Algorithm: " << algorithm
<< std::endl
<<
2408 "Engine: " << module
<< std::endl
<<
2409 "Slot: " << slot
<< std::endl
<<
2410 "PIN: " << pin
<< std::endl
<<
2411 "Label: " << label
<< std::endl
;
2413 DNSKEYRecordContent drc
;
2414 DNSSECPrivateKey dpk
;
2415 dpk
.d_flags
= (keyOrZone
? 257 : 256);
2416 dpk
.setKey(shared_ptr
<DNSCryptoKeyEngine
>(DNSCryptoKeyEngine::makeFromISCString(drc
, iscString
.str())));
2418 // make sure this key isn't being reused.
2419 B
.getDomainKeys(zone
, 0, keys
);
2422 for(DNSBackend::KeyData
& kd
: keys
) {
2423 if (kd
.content
== iscString
.str()) {
2424 // it's this one, I guess...
2431 cerr
<< "You have already assigned this key with ID=" << id
<< std::endl
;
2435 if (!(id
= dk
.addKey(zone
, dpk
))) {
2436 cerr
<< "Unable to assign module slot to zone" << std::endl
;
2440 // figure out key id.
2442 B
.getDomainKeys(zone
, 0, keys
);
2444 // validate which one got the key...
2445 for(DNSBackend::KeyData
& kd
: keys
) {
2446 if (kd
.content
== iscString
.str()) {
2447 // it's this one, I guess...
2453 cerr
<< "Module " << module
<< " slot " << slot
<< " assigned to " << zone
<< " with key id " << id
<< endl
;
2456 } else if (cmds
[1] == "create-key") {
2458 if (cmds
.size() < 4) {
2459 cerr
<< "Usage: pdnsutil hsm create-key ZONE KEY-ID [BITS]" << endl
;
2463 DNSName
zone(cmds
[2]);
2467 if (!B
.getDomainInfo(zone
, di
)) {
2468 cerr
<< "Unable to create key for unknown zone '" << zone
<< "'" << std::endl
;
2472 id
= pdns_stou(cmds
[3]);
2473 std::vector
<DNSBackend::KeyData
> keys
;
2474 if (!B
.getDomainKeys(zone
, 0, keys
)) {
2475 cerr
<< "No keys found for zone " << zone
<< std::endl
;
2479 DNSCryptoKeyEngine
*dke
= NULL
;
2480 // lookup correct key
2481 for(DNSBackend::KeyData
&kd
: keys
) {
2484 DNSKEYRecordContent dkrc
;
2485 dke
= DNSCryptoKeyEngine::makeFromISCString(dkrc
, kd
.content
);
2490 cerr
<< "Could not find key with ID " << id
<< endl
;
2493 if (cmds
.size() > 4) {
2494 bits
= pdns_stou(cmds
[4]);
2497 cerr
<< "Invalid bit size " << bits
<< "given, must be positive integer";
2502 } catch (PDNSException
& e
) {
2503 cerr
<< e
.reason
<< endl
;
2507 cerr
<< "Key of size " << bits
<< " created" << std::endl
;
2511 cerr
<<"PKCS#11 support not enabled"<<endl
;
2514 } else if (cmds
[0] == "b2b-migrate") {
2515 if (cmds
.size() < 3) {
2516 cerr
<<"Usage: b2b-migrate OLD NEW"<<endl
;
2520 DNSBackend
*src
,*tgt
;
2523 for(DNSBackend
*b
: BackendMakers().all()) {
2524 if (b
->getPrefix() == cmds
[1]) src
= b
;
2525 if (b
->getPrefix() == cmds
[2]) tgt
= b
;
2528 cerr
<<"Unknown source backend '"<<cmds
[1]<<"'"<<endl
;
2532 cerr
<<"Unknown target backend '"<<cmds
[2]<<"'"<<endl
;
2536 cout
<<"Moving zone(s) from "<<src
->getPrefix()<<" to "<<tgt
->getPrefix()<<endl
;
2538 vector
<DomainInfo
> domains
;
2540 tgt
->getAllDomains(&domains
, true);
2541 if (domains
.size()>0)
2542 throw PDNSException("Target backend has domain(s), please clean it first");
2544 src
->getAllDomains(&domains
, true);
2546 for(const DomainInfo
& di
: domains
) {
2548 DNSResourceRecord rr
;
2549 cout
<<"Processing '"<<di
.zone
.toString()<<"'"<<endl
;
2551 if (!tgt
->createDomain(di
.zone
)) throw PDNSException("Failed to create zone");
2552 tgt
->setKind(di
.zone
, di
.kind
);
2553 tgt
->setAccount(di
.zone
,di
.account
);
2554 for(const string
& master
: di
.masters
) {
2555 tgt
->setMaster(di
.zone
, master
);
2558 if (!src
->list(di
.zone
, di
.id
, true)) throw PDNSException("Failed to list records");
2560 while(src
->get(rr
)) {
2561 if (!tgt
->feedRecord(rr
)) throw PDNSException("Failed to feed record");
2566 if (src
->listComments(di
.id
)) {
2568 while(src
->getComment(c
)) {
2569 tgt
->feedComment(c
);
2575 std::map
<std::string
, std::vector
<std::string
> > meta
;
2576 if (src
->getAllDomainMetadata(di
.zone
, meta
)) {
2577 std::map
<std::string
, std::vector
<std::string
> >::iterator i
;
2578 for(i
=meta
.begin(); i
!= meta
.end(); i
++) {
2579 if (!tgt
->setDomainMetadata(di
.zone
, i
->first
, i
->second
)) throw PDNSException("Failed to feed domain metadata");
2585 std::vector
<DNSBackend::KeyData
> keys
;
2586 if (src
->getDomainKeys(di
.zone
, 0, keys
)) {
2587 for(const DNSBackend::KeyData
& k
: keys
) {
2588 tgt
->addDomainKey(di
.zone
, k
);
2592 cout
<<"Moved "<<nr
<<" record(s), "<<nc
<<" comment(s), "<<nm
<<" metadata(s) and "<<nk
<<" cryptokey(s)"<<endl
;
2597 std::vector
<struct TSIGKey
> tkeys
;
2598 if (src
->getTSIGKeys(tkeys
)) {
2599 for(const struct TSIGKey
& tk
: tkeys
) {
2600 if (!tgt
->setTSIGKey(tk
.name
, tk
.algorithm
, tk
.key
)) throw PDNSException("Failed to feed TSIG key");
2604 cout
<<"Moved "<<ntk
<<" TSIG key(s)"<<endl
;
2606 cout
<<"Remember to drop the old backend and run rectify-all-zones"<<endl
;
2609 } else if (cmds
[0] == "backend-cmd") {
2610 if (cmds
.size() < 3) {
2611 cerr
<<"Usage: backend-cmd BACKEND CMD [CMD..]"<<endl
;
2618 for(DNSBackend
*b
: BackendMakers().all()) {
2619 if (b
->getPrefix() == cmds
[1]) db
= b
;
2623 cerr
<<"Unknown backend '"<<cmds
[1]<<"'"<<endl
;
2627 for(auto i
=next(begin(cmds
),2); i
!= end(cmds
); ++i
) {
2628 cerr
<<"== "<<*i
<<endl
;
2629 cout
<<db
->directBackendCmd(*i
);
2634 cerr
<<"Unknown command '"<<cmds
[0] <<"'"<< endl
;
2639 catch(PDNSException
& ae
) {
2640 cerr
<<"Error: "<<ae
.reason
<<endl
;
2643 catch(std::exception
& e
) {
2644 cerr
<<"Error: "<<e
.what()<<endl
;
2649 cerr
<<"Caught an unknown exception"<<endl
;