1 #include "dnsseckeeper.hh"
2 #include "dnssecinfra.hh"
6 #include <boost/foreach.hpp>
7 #include <boost/program_options.hpp>
8 #include <boost/assign/std/vector.hpp>
9 #include <boost/assign/list_of.hpp>
10 #include "dnsbackend.hh"
11 #include "ueberbackend.hh"
12 #include "arguments.hh"
13 #include "packetcache.hh"
14 #include "zoneparser-tng.hh"
15 #include "signingpipe.hh"
16 #include "dns_random.hh"
19 #include "ssqlite3.hh"
20 #include "bind-dnssec.schema.sqlite3.sql.h"
26 namespace po
= boost::program_options
;
27 po::variables_map g_vm
;
29 string s_programname
="pdns";
41 string
humanTime(time_t t
)
46 strftime(ret
, sizeof(ret
)-1, "%c", &tm
); // %h:%M %Y-%m-%d
50 static void algorithm2name(uint8_t algo
, string
&name
) {
53 name
= "Reserved"; return;
55 name
= "RSAMD5"; return;
63 name
= "RSASHA1"; return;
65 name
= "DSA-NSEC3-SHA1"; return;
67 name
= "RSASHA1-NSEC3-SHA1"; return;
69 name
= "RSASHA256"; return;
71 name
= "Reserved"; return;
73 name
= "RSASHA512"; return;
75 name
= "Reserved"; return;
77 name
= "ECC-GOST"; return;
79 name
= "ECDSAP256SHA256"; return;
81 name
= "ECDSAP384SHA384"; return;
83 name
= "INDIRECT"; return;
85 name
= "PRIVATEDNS"; return;
87 name
= "PRIVATEOID"; return;
89 name
= "Unallocated/Reserved"; return;
93 static int shorthand2algorithm(const string
&algorithm
)
95 if (!algorithm
.compare("rsamd5")) return 1;
96 if (!algorithm
.compare("dh")) return 2;
97 if (!algorithm
.compare("dsa")) return 3;
98 if (!algorithm
.compare("ecc")) return 4;
99 if (!algorithm
.compare("rsasha1")) return 5;
100 if (!algorithm
.compare("rsasha256")) return 8;
101 if (!algorithm
.compare("rsasha512")) return 10;
102 if (!algorithm
.compare("gost")) return 12;
103 if (!algorithm
.compare("ecdsa256")) return 13;
104 if (!algorithm
.compare("ecdsa384")) return 14;
105 if (!algorithm
.compare("ed25519")) return 250;
109 void loadMainConfig(const std::string
& configdir
)
111 ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=configdir
;
112 ::arg().set("pipebackend-abi-version","Version of the pipe backend ABI")="1";
113 ::arg().set("default-ttl","Seconds a result is valid if not set otherwise")="3600";
114 ::arg().set("launch","Which backends to launch");
115 ::arg().set("dnssec","if we should do dnssec")="true";
116 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")=g_vm
["config-name"].as
<string
>();
117 ::arg().setCmd("help","Provide a helpful message");
118 //::arg().laxParse(argc,argv);
120 if(::arg().mustDo("help")) {
121 cout
<<"syntax:"<<endl
<<endl
;
122 cout
<<::arg().helpstring(::arg()["help"])<<endl
;
126 if(::arg()["config-name"]!="")
127 s_programname
+="-"+::arg()["config-name"];
129 string configname
=::arg()["config-dir"]+"/"+s_programname
+".conf";
130 cleanSlashes(configname
);
132 ::arg().set("default-ksk-algorithms","Default KSK algorithms")="rsasha256";
133 ::arg().set("default-ksk-size","Default KSK size (0 means default)")="0";
134 ::arg().set("default-zsk-algorithms","Default ZSK algorithms")="rsasha256";
135 ::arg().set("default-zsk-size","Default KSK size (0 means default)")="0";
136 ::arg().set("max-ent-entries", "Maximum number of empty non-terminals in a zone")="100000";
137 ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR
;
138 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
139 ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
140 ::arg().set("loglevel","Amount of logging. Higher is more.")="0";
141 ::arg().setSwitch("direct-dnskey","Fetch DNSKEY RRs from backend during DNSKEY synthesis")="no";
142 ::arg().set("max-nsec3-iterations","Limit the number of NSEC3 hash iterations")="500"; // RFC5155 10.3
143 ::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries")="";
144 ::arg().laxFile(configname
.c_str());
146 L
.toConsole((Logger::Urgency
)(::arg().asNum("loglevel")));
148 BackendMakers().launch(::arg()["launch"]); // vrooooom!
149 ::arg().laxFile(configname
.c_str());
150 //cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" <<endl;
152 S
.declare("qsize-q","Number of questions waiting for database attention");
154 S
.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
155 S
.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
157 S
.declare("query-cache-hit","Number of hits on the query cache");
158 S
.declare("query-cache-miss","Number of misses on the query cache");
159 ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
160 ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no";
161 ::arg().set("recursive-cache-ttl","Seconds to store packets for recursive queries in the PacketCache")="10";
162 ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
163 ::arg().set("negquery-cache-ttl","Seconds to store negative query results in the QueryCache")="60";
164 ::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
165 ::arg().set("default-soa-name","name to insert in the SOA record if none set in the backend")="a.misconfigured.powerdns.server";
166 ::arg().set("default-soa-mail","mail address to insert in the SOA record if none set in the backend")="";
167 ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
168 ::arg().set("soa-retry-default","Default SOA retry")="3600";
169 ::arg().set("soa-expire-default","Default SOA expire")="604800";
170 ::arg().set("soa-minimum-ttl","Default SOA minimum ttl")="3600";
175 // irritatingly enough, rectifyZone needs its own ueberbackend and can't therefore benefit from transactions outside its scope
176 // I think this has to do with interlocking transactions between B and DK, but unsure.
177 bool rectifyZone(DNSSECKeeper
& dk
, const std::string
& zone
)
179 if(dk
.isPresigned(zone
)){
180 cerr
<<"Rectify presigned zone '"<<zone
<<"' is not allowed/necessary."<<endl
;
184 UeberBackend
B("default");
185 bool doTransaction
=true; // but see above
187 sd
.db
= (DNSBackend
*)-1;
189 if(!B
.getSOA(zone
, sd
)) {
190 cerr
<<"No SOA known for '"<<zone
<<"', is such a zone in the database?"<<endl
;
193 sd
.db
->list(zone
, sd
.domain_id
);
195 DNSResourceRecord rr
;
196 set
<string
> qnames
, nsset
, dsnames
, insnonterm
, delnonterm
;
197 map
<string
,bool> nonterm
;
200 while(sd
.db
->get(rr
)) {
201 if (rr
.qtype
.getCode())
203 qnames
.insert(rr
.qname
);
204 if(rr
.qtype
.getCode() == QType::NS
&& !pdns_iequals(rr
.qname
, zone
))
205 nsset
.insert(rr
.qname
);
206 if(rr
.qtype
.getCode() == QType::DS
)
207 dsnames
.insert(rr
.qname
);
211 delnonterm
.insert(rr
.qname
);
214 NSEC3PARAMRecordContent ns3pr
;
216 bool haveNSEC3
=dk
.getNSEC3PARAM(zone
, &ns3pr
, &narrow
);
217 bool isOptOut
=(haveNSEC3
&& ns3pr
.d_flags
);
218 if(sd
.db
->doesDNSSEC())
221 cerr
<<"Adding NSEC ordering information "<<endl
;
224 cerr
<<"Adding NSEC3 hashed ordering information for '"<<zone
<<"'"<<endl
;
226 cerr
<<"Adding NSEC3 opt-out hashed ordering information for '"<<zone
<<"'"<<endl
;
228 cerr
<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields"<<endl
;
231 cerr
<<"Non DNSSEC zone, only adding empty non-terminals"<<endl
;
234 sd
.db
->startTransaction("", -1);
239 uint32_t maxent
= ::arg().asNum("max-ent-entries");
242 BOOST_FOREACH(const string
& qname
, qnames
)
245 string
shorter(qname
);
249 if(nsset
.count(shorter
)) {
253 } while(chopOff(shorter
));
258 if(!narrow
&& (realrr
|| !isOptOut
|| nonterm
.find(qname
)->second
)) {
259 hashed
=toBase32Hex(hashQNameWithSalt(ns3pr
.d_iterations
, ns3pr
.d_salt
, qname
));
261 cerr
<<"'"<<qname
<<"' -> '"<< hashed
<<"'"<<endl
;
262 sd
.db
->updateDNSSECOrderAndAuthAbsolute(sd
.domain_id
, qname
, hashed
, auth
);
267 sd
.db
->nullifyDNSSECOrderNameAndUpdateAuth(sd
.domain_id
, qname
, auth
);
272 sd
.db
->updateDNSSECOrderAndAuth(sd
.domain_id
, zone
, qname
, auth
);
274 sd
.db
->nullifyDNSSECOrderNameAndUpdateAuth(sd
.domain_id
, qname
, auth
);
279 if (dsnames
.count(qname
))
280 sd
.db
->setDNSSECAuthOnDsRecord(sd
.domain_id
, qname
);
281 if (!auth
|| nsset
.count(qname
)) {
283 sd
.db
->nullifyDNSSECOrderNameAndAuth(sd
.domain_id
, qname
, "NS");
284 sd
.db
->nullifyDNSSECOrderNameAndAuth(sd
.domain_id
, qname
, "A");
285 sd
.db
->nullifyDNSSECOrderNameAndAuth(sd
.domain_id
, qname
, "AAAA");
291 while(!pdns_iequals(shorter
, zone
) && chopOff(shorter
))
293 if(!qnames
.count(shorter
))
297 cerr
<<"Zone '"<<zone
<<"' has too many empty non terminals."<<endl
;
304 if (!delnonterm
.count(shorter
) && !nonterm
.count(shorter
))
305 insnonterm
.insert(shorter
);
307 delnonterm
.erase(shorter
);
309 if (!nonterm
.count(shorter
)) {
310 nonterm
.insert(pair
<string
, bool>(shorter
, auth
));
313 nonterm
[shorter
]=true;
322 //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
323 if(!insnonterm
.empty() || !delnonterm
.empty() || !doent
)
325 sd
.db
->updateEmptyNonTerminals(sd
.domain_id
, zone
, insnonterm
, delnonterm
, !doent
);
331 pair
<string
,bool> nt
;
332 BOOST_FOREACH(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 const string
& domain
= domains
[random() % domains
.size()];
373 B
.lookup(QType(QType::NS
), domain
);
377 B
.lookup(QType(QType::A
), boost::lexical_cast
<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 BOOST_FOREACH(DomainInfo di
, domainInfo
) {
395 cerr
<<"Rectifying "<<di
.zone
<<": ";
396 rectifyZone(dk
, di
.zone
);
398 cout
<<"Rectified "<<domainInfo
.size()<<" zones."<<endl
;
401 int checkZone(DNSSECKeeper
&dk
, UeberBackend
&B
, const std::string
& zone
)
404 sd
.db
=(DNSBackend
*)-1;
405 if(!B
.getSOA(zone
, sd
)) {
406 cout
<<"[error] No SOA record present, or active, in zone '"<<zone
<<"'"<<endl
;
407 cout
<<"Checked 0 records of '"<<zone
<<"', 1 errors, 0 warnings."<<endl
;
410 bool presigned
=dk
.isPresigned(zone
);
411 sd
.db
->list(zone
, sd
.domain_id
, true);
412 DNSResourceRecord rr
;
413 uint64_t numrecords
=0, numerrors
=0, numwarnings
=0;
415 bool hasNsAtApex
= false;
416 set
<string
> records
, cnames
, noncnames
;
417 map
<string
, unsigned int> ttl
;
419 ostringstream content
;
420 pair
<map
<string
, unsigned int>::iterator
,bool> ret
;
422 while(sd
.db
->get(rr
)) {
423 if(!rr
.qtype
.getCode())
428 if(rr
.qtype
.getCode() == QType::SOA
) {
430 stringtok(parts
, rr
.content
);
434 for(int pleft
=parts
.size(); pleft
< 7; ++pleft
) {
440 if(rr
.qtype
.getCode() == QType::TXT
&& !rr
.content
.empty() && rr
.content
[0]!='"')
441 rr
.content
= "\""+rr
.content
+"\"";
444 shared_ptr
<DNSRecordContent
> drc(DNSRecordContent::mastermake(rr
.qtype
.getCode(), 1, rr
.content
));
445 string tmp
=drc
->serialize(rr
.qname
);
446 tmp
= drc
->getZoneRepresentation();
447 if (rr
.qtype
.getCode() != QType::AAAA
) {
448 if (!pdns_iequals(tmp
, rr
.content
)) {
449 cout
<<"[Warning] Parsed and original record content are not equal: "<<rr
.qname
<<" IN " <<rr
.qtype
.getName()<< " '" << rr
.content
<<"' (Content parsed as '"<<tmp
<<"')"<<endl
;
453 struct in6_addr tmpbuf
;
454 if (inet_pton(AF_INET6
, rr
.content
.c_str(), &tmpbuf
) != 1 || rr
.content
.find('.') != string::npos
) {
455 cout
<<"[Warning] Following record is not a valid IPv6 address: "<<rr
.qname
<<" IN " <<rr
.qtype
.getName()<< " '" << rr
.content
<<"'"<<endl
;
460 catch(std::exception
& e
)
462 cout
<<"[Error] Following record had a problem: "<<rr
.qname
<<" IN " <<rr
.qtype
.getName()<< " " << rr
.content
<<endl
;
463 cout
<<"[Error] Error was: "<<e
.what()<<endl
;
468 if(!endsOn(rr
.qname
, zone
)) {
469 cout
<<"[Warning] Record '"<<rr
.qname
<<" IN "<<rr
.qtype
.getName()<<" "<<rr
.content
<<"' in zone '"<<zone
<<"' is out-of-zone."<<endl
;
475 content
<<rr
.qname
<<" "<<rr
.qtype
.getName()<<" "<<rr
.content
;
476 if (records
.count(toLower(content
.str()))) {
477 cout
<<"[Error] Duplicate record found in rrset: '"<<rr
.qname
<<" IN "<<rr
.qtype
.getName()<<" "<<rr
.content
<<"'"<<endl
;
481 records
.insert(toLower(content
.str()));
484 content
<<rr
.qname
<<" "<<rr
.qtype
.getName();
485 if (rr
.qtype
.getCode() == QType::RRSIG
) {
486 RRSIGRecordContent
rrc(rr
.content
);
487 content
<<" ("<<DNSRecordContent::NumberToType(rrc
.d_type
)<<")";
489 ret
= ttl
.insert(pair
<string
, unsigned int>(toLower(content
.str()), rr
.ttl
));
490 if (ret
.second
== false && ret
.first
->second
!= rr
.ttl
) {
491 cout
<<"[Error] TTL mismatch in rrset: '"<<rr
.qname
<<" IN " <<rr
.qtype
.getName()<<" "<<rr
.content
<<"' ("<<ret
.first
->second
<<" != "<<rr
.ttl
<<")"<<endl
;
496 if(pdns_iequals(rr
.qname
, zone
)) {
497 if (rr
.qtype
.getCode() == QType::NS
) {
499 } else if (rr
.qtype
.getCode() == QType::DS
) {
500 cout
<<"[Warning] DS at apex in zone '"<<zone
<<"', should not be here."<<endl
;
504 if (rr
.qtype
.getCode() == QType::SOA
) {
505 cout
<<"[Error] SOA record not at apex '"<<rr
.qname
<<" IN "<<rr
.qtype
.getName()<<" "<<rr
.content
<<"' in zone '"<<zone
<<"'"<<endl
;
508 } else if (rr
.qtype
.getCode() == QType::DNSKEY
) {
509 cout
<<"[Warning] DNSKEY record not at apex '"<<rr
.qname
<<" IN "<<rr
.qtype
.getName()<<" "<<rr
.content
<<"' in zone '"<<zone
<<"', should not be here."<<endl
;
514 if (rr
.qtype
.getCode() == QType::CNAME
) {
515 if (!cnames
.count(toLower(rr
.qname
)))
516 cnames
.insert(toLower(rr
.qname
));
518 cout
<<"[Error] Duplicate CNAME found at '"<<rr
.qname
<<"'"<<endl
;
523 if (rr
.qtype
.getCode() == QType::RRSIG
) {
525 cout
<<"[Error] RRSIG found at '"<<rr
.qname
<<"' in non-presigned zone. These do not belong in the database."<<endl
;
530 noncnames
.insert(toLower(rr
.qname
));
533 if(rr
.qtype
.getCode() == QType::NSEC
|| rr
.qtype
.getCode() == QType::NSEC3
)
535 cout
<<"[Error] NSEC or NSEC3 found at '"<<rr
.qname
<<"'. These do not belong in the database."<<endl
;
540 if(!presigned
&& rr
.qtype
.getCode() == QType::DNSKEY
)
542 if(::arg().mustDo("direct-dnskey"))
544 if(rr
.ttl
!= sd
.default_ttl
)
546 cout
<<"[Warning] DNSKEY TTL of "<<rr
.ttl
<<" at '"<<rr
.qname
<<"' differs from SOA minimum of "<<sd
.default_ttl
<<endl
;
552 cout
<<"[Warning] DNSKEY at '"<<rr
.qname
<<"' in non-presigned zone will mostly be ignored and can cause problems."<<endl
;
557 if(rr
.qtype
.getCode() == QType::URL
|| rr
.qtype
.getCode() == QType::MBOXFW
) {
558 cout
<<"[Error] The recordtype "<<rr
.qtype
.getName()<<" for record '"<<rr
.qname
<<"' is no longer supported."<<endl
;
563 if (rr
.qname
[rr
.qname
.size()-1] == '.') {
564 cout
<<"[Error] Record '"<<rr
.qname
<<"' has a trailing dot. PowerDNS will ignore this record!"<<endl
;
568 if ( (rr
.qtype
.getCode() == QType::NS
|| rr
.qtype
.getCode() == QType::SRV
|| rr
.qtype
.getCode() == QType::MX
|| rr
.qtype
.getCode() == QType::CNAME
) &&
569 rr
.content
[rr
.content
.size()-1] == '.') {
570 cout
<<"[Warning] The record "<<rr
.qname
<<" with type "<<rr
.qtype
.getName()<<" has a trailing dot in the content ("<<rr
.content
<<"). Your backend might not work well with this."<<endl
;
574 if(rr
.auth
== 0 && rr
.qtype
.getCode()!=QType::NS
&& rr
.qtype
.getCode()!=QType::A
&& rr
.qtype
.getCode()!=QType::AAAA
)
576 cout
<<"[Error] Following record is auth=0, run pdnssec rectify-zone?: "<<rr
.qname
<<" IN " <<rr
.qtype
.getName()<< " " << rr
.content
<<endl
;
581 for(set
<string
>::const_iterator i
= cnames
.begin(); i
!= cnames
.end(); i
++) {
582 if (noncnames
.find(*i
) != noncnames
.end()) {
583 cout
<<"[Error] CNAME "<<*i
<<" found, but other records with same label exist."<<endl
;
589 cout
<<"[Error] No NS record at zone apex in zone '"<<zone
<<"'"<<endl
;
593 cout
<<"Checked "<<numrecords
<<" records of '"<<zone
<<"', "<<numerrors
<<" errors, "<<numwarnings
<<" warnings."<<endl
;
597 int checkAllZones(DNSSECKeeper
&dk
)
599 UeberBackend
B("default");
600 vector
<DomainInfo
> domainInfo
;
602 B
.getAllDomains(&domainInfo
, true);
604 BOOST_FOREACH(DomainInfo di
, domainInfo
) {
605 if (checkZone(dk
, B
, di
.zone
) > 0)
608 cout
<<"Checked "<<domainInfo
.size()<<" zones, "<<errors
<<" had errors."<<endl
;
612 int increaseSerial(const string
& zone
, DNSSECKeeper
&dk
)
614 UeberBackend
B("default");
616 sd
.db
=(DNSBackend
*)-1;
617 if(!B
.getSOA(zone
, sd
)) {
618 cout
<<"No SOA for zone '"<<zone
<<"'"<<endl
;
623 dk
.getFromMeta(zone
, "SOA-EDIT", soaEditKind
);
625 sd
.db
->lookup(QType(QType::SOA
), zone
);
626 vector
<DNSResourceRecord
> rrs
;
627 DNSResourceRecord rr
;
628 while (sd
.db
->get(rr
)) {
629 if (rr
.qtype
.getCode() == QType::SOA
)
633 if (rrs
.size() > 1) {
634 cerr
<<rrs
.size()<<" SOA records found for "<<zone
<<"!"<<endl
;
637 if (rrs
.size() < 1) {
638 cerr
<<zone
<<" not found!"<<endl
;
641 if (soaEditKind
.empty()) {
644 else if(pdns_iequals(soaEditKind
,"INCREMENT-WEEKS")) {
647 else if(pdns_iequals(soaEditKind
,"INCEPTION-INCREMENT")) {
648 uint32_t today_serial
= localtime_format_YYYYMMDDSS(time(NULL
), 1);
650 if (sd
.serial
< today_serial
) {
651 sd
.serial
= today_serial
;
658 sd
.serial
= calculateEditSOA(sd
, soaEditKind
) + 1;
660 rrs
[0].content
= serializeSOAData(sd
);
662 sd
.db
->startTransaction("", -1);
664 if (! sd
.db
->replaceRRSet(sd
.domain_id
, zone
, rr
.qtype
, rrs
)) {
665 sd
.db
->abortTransaction();
666 cerr
<<"Backend did not replace SOA record. Backend might not support this operation."<<endl
;
670 if (sd
.db
->doesDNSSEC()) {
671 NSEC3PARAMRecordContent ns3pr
;
673 bool haveNSEC3
=dk
.getNSEC3PARAM(zone
, &ns3pr
, &narrow
);
678 string hashed
=toBase32Hex(hashQNameWithSalt(ns3pr
.d_iterations
, ns3pr
.d_salt
, rrs
[0].qname
));
680 cerr
<<"'"<<rrs
[0].qname
<<"' -> '"<< hashed
<<"'"<<endl
;
681 sd
.db
->updateDNSSECOrderAndAuthAbsolute(sd
.domain_id
, rrs
[0].qname
, hashed
, 1);
684 sd
.db
->nullifyDNSSECOrderNameAndUpdateAuth(sd
.domain_id
, rrs
[0].qname
, 1);
687 sd
.db
->updateDNSSECOrderAndAuth(sd
.domain_id
, zone
, rrs
[0].qname
, 1);
691 sd
.db
->commitTransaction();
693 cout
<<"SOA serial for zone "<<zone
<<" set to "<<sd
.serial
<<endl
;
697 int deleteZone(const string
&zone
) {
700 if (! B
.getDomainInfo(zone
, di
)) {
701 cerr
<<"Domain '"<<zone
<<"' not found!"<<endl
;
705 if(di
.backend
->deleteDomain(zone
))
708 cerr
<<"Failed to delete domain '"+zone
+"'"<<endl
;;
712 int listZone(const string
&zone
) {
716 if (! B
.getDomainInfo(zone
, di
)) {
717 cerr
<<"Domain '"<<zone
<<"' not found!"<<endl
;
720 di
.backend
->list(zone
, di
.id
);
721 DNSResourceRecord rr
;
722 while(di
.backend
->get(rr
)) {
723 if(rr
.qtype
.getCode()) {
724 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] != '.')
725 rr
.content
.append(1, '.');
727 cout
<<rr
.qname
<<".\t"<<rr
.ttl
<<"\tIN\t"<<rr
.qtype
.getName()<<"\t"<<rr
.content
<<endl
;
733 int loadZone(string zone
, const string
& fname
) {
737 if (B
.getDomainInfo(zone
, di
)) {
738 cerr
<<"Domain '"<<zone
<<"' exists already, replacing contents"<<endl
;
741 cerr
<<"Creating '"<<zone
<<"'"<<endl
;
742 B
.createDomain(zone
);
744 if(!B
.getDomainInfo(zone
, di
)) {
745 cerr
<<"Domain '"<<zone
<<"' was not created!"<<endl
;
749 DNSBackend
* db
= di
.backend
;
750 ZoneParserTNG
zpt(fname
, zone
);
752 DNSResourceRecord rr
;
753 if(!db
->startTransaction(zone
, di
.id
)) {
754 cerr
<<"Unable to start transaction for load of zone '"<<zone
<<"'"<<endl
;
759 if(!endsOn(stripDot(rr
.qname
), zone
) && rr
.qname
!=zone
) {
760 cerr
<<"File contains record named '"<<rr
.qname
<<"' which is not part of zone '"<<zone
<<"'"<<endl
;
763 rr
.qname
=stripDot(rr
.qname
);
766 db
->commitTransaction();
770 int createZone(const string
&zone
) {
773 if (B
.getDomainInfo(zone
, di
)) {
774 cerr
<<"Domain '"<<zone
<<"' exists already"<<endl
;
777 cerr
<<"Creating '"<<zone
<<"'"<<endl
;
778 B
.createDomain(zone
);
780 if(!B
.getDomainInfo(zone
, di
)) {
781 cerr
<<"Domain '"<<zone
<<"' was not created!"<<endl
;
788 int listAllZones(const string
&type
="") {
792 if (toUpper(type
) == "MASTER")
794 else if (toUpper(type
) == "SLAVE")
796 else if (toUpper(type
) == "NATIVE")
799 cerr
<<"Syntax: pdnssec list-all-zones [master|slave|native]"<<endl
;
804 UeberBackend
B("default");
806 vector
<DomainInfo
> domains
;
807 B
.getAllDomains(&domains
);
810 for (vector
<DomainInfo
>::const_iterator di
=domains
.begin(); di
!= domains
.end(); di
++) {
811 if (di
->kind
== kindFilter
|| kindFilter
== -1) {
812 cout
<<di
->zone
<<endl
;
817 if (kindFilter
!= -1)
818 cout
<<type
<<" zonecount:"<<count
<<endl
;
820 cout
<<"All zonecount:"<<count
<<endl
;
824 void testAlgorithm(int algo
)
826 DNSCryptoKeyEngine::testOne(algo
);
829 void testAlgorithms()
831 DNSCryptoKeyEngine::testAll();
834 void testSpeed(DNSSECKeeper
& dk
, const string
& zone
, const string
& remote
, int cores
)
836 DNSResourceRecord rr
;
837 rr
.qname
="blah."+zone
;
841 rr
.qclass
= QClass::IN
;
842 rr
.d_place
=DNSResourceRecord::ANSWER
;
844 UeberBackend
db("key-only");
846 if ( ! db
.backends
.size() )
848 throw runtime_error("No backends available for DNSSEC key storage");
851 ChunkedSigningPipe
csp(zone
, 1, remote
, cores
);
853 vector
<DNSResourceRecord
> signatures
;
855 unsigned char* octets
= (unsigned char*)&rnd
;
859 for(unsigned int n
=0; n
< 100000; ++n
) {
861 snprintf(tmp
, sizeof(tmp
), "%d.%d.%d.%d",
862 octets
[0], octets
[1], octets
[2], octets
[3]);
865 snprintf(tmp
, sizeof(tmp
), "r-%u", rnd
);
866 rr
.qname
=string(tmp
)+"."+zone
;
869 while(signatures
= csp
.getChunk(), !signatures
.empty())
872 cerr
<<"Flushing the pipe, "<<csp
.d_signed
<<" signed, "<<csp
.d_queued
<<" queued, "<<csp
.d_outstanding
<<" outstanding"<< endl
;
873 cerr
<<"Net speed: "<<csp
.d_signed
/ (dt
.udiffNoReset()/1000000.0) << " sigs/s"<<endl
;
874 while(signatures
= csp
.getChunk(true), !signatures
.empty())
876 cerr
<<"Done, "<<csp
.d_signed
<<" signed, "<<csp
.d_queued
<<" queued, "<<csp
.d_outstanding
<<" outstanding"<< endl
;
877 cerr
<<"Net speed: "<<csp
.d_signed
/ (dt
.udiff()/1000000.0) << " sigs/s"<<endl
;
880 void verifyCrypto(const string
& zone
)
882 ZoneParserTNG
zpt(zone
);
883 DNSResourceRecord rr
;
884 DNSKEYRecordContent drc
;
885 RRSIGRecordContent rrc
;
886 DSRecordContent dsrc
;
887 vector
<shared_ptr
<DNSRecordContent
> > toSign
;
891 if(rr
.qtype
.getCode() == QType::DNSKEY
) {
892 cerr
<<"got DNSKEY!"<<endl
;
894 drc
= *dynamic_cast<DNSKEYRecordContent
*>(DNSRecordContent::mastermake(QType::DNSKEY
, 1, rr
.content
));
896 else if(rr
.qtype
.getCode() == QType::RRSIG
) {
897 cerr
<<"got RRSIG"<<endl
;
898 rrc
= *dynamic_cast<RRSIGRecordContent
*>(DNSRecordContent::mastermake(QType::RRSIG
, 1, rr
.content
));
900 else if(rr
.qtype
.getCode() == QType::DS
) {
901 cerr
<<"got DS"<<endl
;
902 dsrc
= *dynamic_cast<DSRecordContent
*>(DNSRecordContent::mastermake(QType::DS
, 1, rr
.content
));
906 toSign
.push_back(shared_ptr
<DNSRecordContent
>(DNSRecordContent::mastermake(rr
.qtype
.getCode(), 1, rr
.content
)));
910 string msg
= getMessageForRRSET(qname
, rrc
, toSign
);
911 cerr
<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc
.d_algorithm
, drc
.d_key
)->verify(msg
, rrc
.d_signature
)<<endl
;
912 if(dsrc
.d_digesttype
) {
913 cerr
<<"Calculated DS: "<<apex
<<" IN DS "<<makeDSFromDNSKey(apex
, drc
, dsrc
.d_digesttype
).getZoneRepresentation()<<endl
;
914 cerr
<<"Original DS: "<<apex
<<" IN DS "<<dsrc
.getZoneRepresentation()<<endl
;
917 DNSCryptoKeyEngine
*key
=DNSCryptoKeyEngine::makeFromISCString(drc
, "Private-key-format: v1.2\n"
918 "Algorithm: 12 (ECC-GOST)\n"
919 "GostAsn1: MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgQg/9MiXtXKg9FDXDN/R9CmVhJDyuzRAIgh4tPwCu4NHIs=\n");
920 string resign
=key
->sign(hash
);
921 cerr
<<Base64Encode(resign
)<<endl
;
922 cerr
<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc
.d_algorithm
, drc
.d_key
)->verify(hash
, resign
)<<endl
;
926 bool disableDNSSECOnZone(DNSSECKeeper
& dk
, const string
& zone
)
928 UeberBackend
B("default");
931 if (!B
.getDomainInfo(zone
, di
)){
932 cerr
<< "No such zone in the database" << endl
;
936 if(!dk
.isSecuredZone(zone
)) {
937 cerr
<<"Zone is not secured"<<endl
;
940 DNSSECKeeper::keyset_t keyset
=dk
.getKeys(zone
);
943 cerr
<< "No keys for zone '"<<zone
<<"'."<<endl
;
946 BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value
, keyset
) {
947 dk
.deactivateKey(zone
, value
.second
.id
);
948 dk
.removeKey(zone
, value
.second
.id
);
951 dk
.unsetNSEC3PARAM(zone
);
952 dk
.unsetPresigned(zone
);
955 bool showZone(DNSSECKeeper
& dk
, const std::string
& zone
)
957 UeberBackend
B("default");
959 std::vector
<std::string
> meta
;
961 if (!B
.getDomainInfo(zone
, di
)){
962 cerr
<< "No such zone in the database" << endl
;
966 if(!dk
.isSecuredZone(zone
)) {
967 cerr
<<"Zone is not actively secured"<<endl
;
969 NSEC3PARAMRecordContent ns3pr
;
971 bool haveNSEC3
=dk
.getNSEC3PARAM(zone
, &ns3pr
, &narrow
);
973 DNSSECKeeper::keyset_t keyset
=dk
.getKeys(zone
);
974 if (B
.getDomainMetadata(zone
, "TSIG-ALLOW-AXFR", meta
) && meta
.size() > 0) {
975 cerr
<< "Zone has following allowed TSIG key(s): " << boost::join(meta
, ",") << endl
;
979 if (B
.getDomainMetadata(zone
, "AXFR-MASTER-TSIG", meta
) && meta
.size() > 0) {
980 cerr
<< "Zone uses following TSIG key(s): " << boost::join(meta
, ",") << endl
;
983 cout
<<"Zone is " << (dk
.isPresigned(zone
) ? "" : "not ") << "presigned"<<endl
;
986 cerr
<< "No keys for zone '"<<zone
<<"'."<<endl
;
990 cout
<<"Zone has NSEC semantics"<<endl
;
992 cout
<<"Zone has " << (narrow
? "NARROW " : "") <<"hashed NSEC3 semantics, configuration: "<<ns3pr
.getZoneRepresentation()<<endl
;
994 cout
<< "keys: "<<endl
;
995 BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value
, keyset
) {
997 algorithm2name(value
.first
.d_algorithm
, algname
);
998 cout
<<"ID = "<<value
.second
.id
<<" ("<<(value
.second
.keyOrZone
? "KSK" : "ZSK")<<"), tag = "<<value
.first
.getDNSKEY().getTag();
999 cout
<<", algo = "<<(int)value
.first
.d_algorithm
<<", bits = "<<value
.first
.getKey()->getBits()<<"\tActive: "<<value
.second
.active
<< " ( " + algname
+ " ) "<<endl
;
1000 if(value
.second
.keyOrZone
|| ::arg().mustDo("direct-dnskey") || g_verbose
)
1001 cout
<<(value
.second
.keyOrZone
? "KSK" : "ZSK")<<" DNSKEY = "<<zone
<<" IN DNSKEY "<< value
.first
.getDNSKEY().getZoneRepresentation() << " ; ( " + algname
+ " )" << endl
;
1002 if(value
.second
.keyOrZone
|| g_verbose
) {
1003 cout
<<"DS = "<<zone
<<" IN DS "<<makeDSFromDNSKey(zone
, value
.first
.getDNSKEY(), 1).getZoneRepresentation() << " ; ( SHA1 digest )" << endl
;
1004 cout
<<"DS = "<<zone
<<" IN DS "<<makeDSFromDNSKey(zone
, value
.first
.getDNSKEY(), 2).getZoneRepresentation() << " ; ( SHA256 digest )" << endl
;
1006 string output
=makeDSFromDNSKey(zone
, value
.first
.getDNSKEY(), 3).getZoneRepresentation();
1007 cout
<<"DS = "<<zone
<<" IN DS "<< output
<< " ; ( GOST R 34.11-94 digest )" << endl
;
1013 string output
=makeDSFromDNSKey(zone
, value
.first
.getDNSKEY(), 4).getZoneRepresentation();
1014 cout
<<"DS = "<<zone
<<" IN DS "<< output
<< " ; ( SHA-384 digest )" << endl
;
1026 bool secureZone(DNSSECKeeper
& dk
, const std::string
& zone
)
1029 vector
<string
> k_algos
;
1030 vector
<string
> z_algos
;
1034 stringtok(k_algos
, ::arg()["default-ksk-algorithms"], " ,");
1035 k_size
= ::arg().asNum("default-ksk-size");
1036 stringtok(z_algos
, ::arg()["default-zsk-algorithms"], " ,");
1037 z_size
= ::arg().asNum("default-zsk-size");
1040 throw runtime_error("KSK key size must be equal to or greater than 0");
1043 if (k_algos
.size() < 1) {
1044 throw runtime_error("No algorithm(s) given for KSK");
1048 throw runtime_error("ZSK key size must be equal to or greater than 0");
1051 if (z_algos
.size() < 1) {
1052 throw runtime_error("No algorithm(s) given for ZSK");
1055 if(dk
.isSecuredZone(zone
)) {
1056 cerr
<< "Zone '"<<zone
<<"' already secure, remove keys with pdnssec remove-zone-key if needed"<<endl
;
1061 UeberBackend
B("default");
1062 if(!B
.getDomainInfo(zone
, di
) || !di
.backend
) { // di.backend and B are mostly identical
1063 cout
<<"Can't find a zone called '"<<zone
<<"'"<<endl
;
1067 if(di
.kind
== DomainInfo::Slave
)
1069 cout
<<"Warning! This is a slave domain! If this was a mistake, please run"<<endl
;
1070 cout
<<"pdnssec disable-dnssec "<<zone
<<" right now!"<<endl
;
1074 cout
<< "Securing zone with " << k_algos
[0] << " algorithm with key size " << k_size
<< endl
;
1076 cout
<< "Securing zone with " << k_algos
[0] << " algorithm with default key size" << endl
;
1078 // run secure-zone with first default algorith, then add keys
1079 if(!dk
.secureZone(zone
, shorthand2algorithm(k_algos
[0]), k_size
)) {
1080 cerr
<<"No backend was able to secure '"<<zone
<<"', most likely because no DNSSEC"<<endl
;
1081 cerr
<<"capable backends are loaded, or because the backends have DNSSEC disabled."<<endl
;
1082 cerr
<<"For the Generic SQL backends, set the 'gsqlite3-dnssec', 'gmysql-dnssec' or"<<endl
;
1083 cerr
<<"'gpgsql-dnssec' flag. Also make sure the schema has been updated for DNSSEC!"<<endl
;
1087 if(!dk
.isSecuredZone(zone
)) {
1088 cerr
<<"Failed to secure zone. Is your backend dnssec enabled? (set "<<endl
;
1089 cerr
<<"gsqlite3-dnssec, or gmysql-dnssec etc). Check this first."<<endl
;
1090 cerr
<<"If you run with the BIND backend, make sure you have configured"<<endl
;
1091 cerr
<<"it to use DNSSEC with 'bind-dnssec-db=/path/fname' and"<<endl
;
1092 cerr
<<"'pdnssec create-bind-db /path/fname'!"<<endl
;
1096 DNSSECKeeper::keyset_t zskset
=dk
.getKeys(zone
, false);
1098 if(!zskset
.empty()) {
1099 cerr
<<"There were ZSKs already for zone '"<<zone
<<"', no need to add more"<<endl
;
1103 for(vector
<string
>::iterator i
= k_algos
.begin()+1; i
!= k_algos
.end(); i
++)
1104 dk
.addKey(zone
, true, shorthand2algorithm(*i
), k_size
, true); // obvious errors will have been caught above
1106 BOOST_FOREACH(string z_algo
, z_algos
)
1108 int algo
= shorthand2algorithm(z_algo
);
1109 dk
.addKey(zone
, false, algo
, z_size
);
1112 // rectifyZone(dk, zone);
1113 // showZone(dk, zone);
1114 cout
<<"Zone "<<zone
<<" secured"<<endl
;
1118 void testSchema(DNSSECKeeper
& dk
, const std::string
& zone
)
1120 cout
<<"Note: test-schema will try to create the zone, but it will not remove it."<<endl
;
1121 cout
<<"Please clean up after this."<<endl
;
1123 cout
<<"Constructing UeberBackend"<<endl
;
1124 UeberBackend
B("default");
1125 cout
<<"Picking first backend - if this is not what you want, edit launch line!"<<endl
;
1126 DNSBackend
*db
= B
.backends
[0];
1127 cout
<<"Creating slave domain "<<zone
<<endl
;
1128 db
->createSlaveDomain("127.0.0.1", zone
, "", "_testschema");
1129 cout
<<"Slave domain created"<<endl
;
1132 if(!B
.getDomainInfo(zone
, di
) || !di
.backend
) { // di.backend and B are mostly identical
1133 cout
<<"Can't find domain we just created, aborting"<<endl
;
1137 DNSResourceRecord rr
, rrget
;
1138 cout
<<"Starting transaction to feed records"<<endl
;
1139 db
->startTransaction(zone
, di
.id
);
1141 rr
.qtype
=QType::SOA
;
1146 rr
.content
="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
1147 cout
<<"Feeding SOA"<<endl
;
1149 rr
.qtype
=QType::TXT
;
1151 rr
.content
="\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"";
1152 cout
<<"Feeding overlong TXT"<<endl
;
1154 cout
<<"Committing"<<endl
;
1155 db
->commitTransaction();
1156 cout
<<"Querying TXT"<<endl
;
1157 db
->lookup(QType(QType::TXT
), zone
, NULL
, di
.id
);
1160 DNSResourceRecord rrthrowaway
;
1161 if(db
->get(rrthrowaway
)) // should not touch rr but don't assume anything
1163 cout
<<"Expected one record, got multiple, aborting"<<endl
;
1166 int size
=rrget
.content
.size();
1169 cout
<<"Expected 302 bytes, got "<<size
<<", aborting"<<endl
;
1173 cout
<<"[+] content field is over 255 bytes"<<endl
;
1175 cout
<<"Dropping all records, inserting SOA+2xA"<<endl
;
1176 db
->startTransaction(zone
, di
.id
);
1178 rr
.qtype
=QType::SOA
;
1183 rr
.content
="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
1184 cout
<<"Feeding SOA"<<endl
;
1188 rr
.qname
="_underscore."+zone
;
1189 rr
.content
="127.0.0.1";
1192 rr
.qname
="bla."+zone
;
1193 cout
<<"Committing"<<endl
;
1194 db
->commitTransaction();
1196 cout
<<"Securing zone"<<endl
;
1197 secureZone(dk
, zone
);
1198 cout
<<"Rectifying zone"<<endl
;
1199 rectifyZone(dk
, zone
);
1200 cout
<<"Checking underscore ordering"<<endl
;
1201 string before
, after
;
1202 db
->getBeforeAndAfterNames(di
.id
, zone
, "z."+zone
, before
, after
);
1203 cout
<<"got '"<<before
<<"' < 'z."<<zone
<<"' < '"<<after
<<"'"<<endl
;
1204 if(before
!= "_underscore."+zone
)
1206 cout
<<"before is wrong, got '"<<before
<<"', expected '_underscore."<<zone
<<"', aborting"<<endl
;
1211 cout
<<"after is wrong, got '"<<after
<<"', expected '"<<zone
<<"', aborting"<<endl
;
1214 cout
<<"[+] ordername sorting is correct for names starting with _"<<endl
;
1216 cout
<<"End of tests, please remove "<<zone
<<" from domains+records"<<endl
;
1219 int main(int argc
, char** argv
)
1222 po::options_description
desc("Allowed options");
1224 ("help,h", "produce help message")
1225 ("verbose,v", "be verbose")
1226 ("force", "force an action")
1227 ("config-name", po::value
<string
>()->default_value(""), "virtual configuration name")
1228 ("config-dir", po::value
<string
>()->default_value(SYSCONFDIR
), "location of pdns.conf")
1229 ("commands", po::value
<vector
<string
> >());
1231 po::positional_options_description p
;
1232 p
.add("commands", -1);
1233 po::store(po::command_line_parser(argc
, argv
).options(desc
).positional(p
).run(), g_vm
);
1236 vector
<string
> cmds
;
1238 if(g_vm
.count("commands"))
1239 cmds
= g_vm
["commands"].as
<vector
<string
> >();
1241 g_verbose
= g_vm
.count("verbose");
1243 if(cmds
.empty() || g_vm
.count("help")) {
1244 cerr
<<"Usage: \npdnssec [options] <command> [params ..]\n"<<endl
;
1245 cerr
<<"Commands:"<<endl
;
1246 cerr
<<"activate-tsig-key ZONE NAME [master|slave]"<<endl
;
1247 cerr
<<" Enable TSIG key for a zone"<<endl
;
1248 cerr
<<"activate-zone-key ZONE KEY-ID Activate the key with key id KEY-ID in ZONE"<<endl
;
1249 cerr
<<"add-zone-key ZONE zsk|ksk [bits] [active|passive]"<<endl
;
1250 cerr
<<" [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384]"<<endl
;
1251 cerr
<<" Add a ZSK or KSK to zone and specify algo&bits"<<endl
;
1252 cerr
<<"bench-db [filename] Bench database backend with queries, one domain per line"<<endl
;
1253 cerr
<<"check-zone ZONE Check a zone for correctness"<<endl
;
1254 cerr
<<"check-all-zones Check all zones for correctness"<<endl
;
1255 cerr
<<"create-bind-db FNAME Create DNSSEC db for BIND backend (bind-dnssec-db)"<<endl
;
1256 cerr
<<"create-zone ZONE Create empty zone ZONE"<<endl
;
1257 cerr
<<"deactivate-tsig-key ZONE NAME [master|slave]"<<endl
;
1258 cerr
<<" Disable TSIG key for a zone"<<endl
;
1259 cerr
<<"deactivate-zone-key ZONE KEY-ID Deactivate the key with key id KEY-ID in ZONE"<<endl
;
1260 cerr
<<"delete-tsig-key NAME Delete TSIG key (warning! will not unmap key!)"<<endl
;
1261 cerr
<<"delete-zone ZONE Delete the zone"<<endl
;
1262 cerr
<<"disable-dnssec ZONE Deactivate all keys and unset PRESIGNED in ZONE"<<endl
;
1263 cerr
<<"export-zone-dnskey ZONE KEY-ID Export to stdout the public DNSKEY described"<<endl
;
1264 cerr
<<"export-zone-key ZONE KEY-ID Export to stdout the private key described"<<endl
;
1265 cerr
<<"generate-tsig-key NAME ALGORITHM Generate new TSIG key"<<endl
;
1266 cerr
<<"generate-zone-key zsk|ksk [algorithm] [bits]"<<endl
;
1267 cerr
<<" Generate a ZSK or KSK to stdout with specified algo&bits"<<endl
;
1268 cerr
<<"get-meta ZONE [kind kind ..] Get zone metadata. If no KIND given, lists all known"<<endl
;
1269 cerr
<<"hash-zone-record ZONE RNAME Calculate the NSEC3 hash for RNAME in ZONE"<<endl
;
1271 cerr
<<"hsm assign zone zsk|ksk module slot pin label"<<endl
<<
1272 " Assign a hardware signing module to a ZONE"<<endl
;
1273 cerr
<<"hsm create-key zone [bits] Create a key using hardware signing module for ZONE (use assign first)"<<endl
;
1274 cerr
<<" bits defaults to 2048"<<endl
;
1276 cerr
<<"increase-serial ZONE Increases the SOA-serial by 1. Uses SOA-EDIT"<<endl
;
1277 cerr
<<"import-tsig-key NAME ALGORITHM KEY Import TSIG key"<<endl
;
1278 cerr
<<"import-zone-key ZONE FILE Import from a file a private key, ZSK or KSK"<<endl
;
1279 cerr
<<" [active|passive][ksk|zsk] Defaults to KSK and active"<<endl
;
1280 cerr
<<"load-zone ZONE FILE Load ZONE from FILE, possibly creating zone or atomically"<<endl
;
1281 cerr
<<" replacing contents"<<endl
;
1282 cerr
<<"list-zone ZONE List zone contents"<<endl
;
1283 cerr
<<"list-all-zones [master|slave|native]"<<endl
;
1284 cerr
<<" List all zone names"<<endl
;;
1285 cerr
<<"list-tsig-keys List all TSIG keys"<<endl
;
1286 cerr
<<"rectify-zone ZONE [ZONE ..] Fix up DNSSEC fields (order, auth)"<<endl
;
1287 cerr
<<"rectify-all-zones Rectify all zones."<<endl
;
1288 cerr
<<"remove-zone-key ZONE KEY-ID Remove key with KEY-ID from ZONE"<<endl
;
1289 cerr
<<"secure-all-zones [increase-serial] Secure all zones without keys."<<endl
;
1290 cerr
<<"secure-zone ZONE [ZONE ..] Add KSK and two ZSKs"<<endl
;
1291 cerr
<<"set-nsec3 ZONE ['params' [narrow]] Enable NSEC3 with PARAMs. Optionally narrow"<<endl
;
1292 cerr
<<"set-presigned ZONE Use presigned RRSIGs from storage"<<endl
;
1293 cerr
<<"set-meta ZONE KIND [value value ..]"<<endl
;
1294 cerr
<<" Set zone metadata, optionally providing a value. Empty clears meta."<<endl
;
1295 cerr
<<"show-zone ZONE Show DNSSEC (public) key details about a zone"<<endl
;
1296 cerr
<<"unset-nsec3 ZONE Switch back to NSEC"<<endl
;
1297 cerr
<<"unset-presigned ZONE No longer use presigned RRSIGs"<<endl
;
1298 cerr
<<"test-schema ZONE Test DB schema - will create ZONE"<<endl
;
1303 if (cmds
[0] == "test-algorithm") {
1304 if(cmds
.size() != 2) {
1305 cerr
<< "Syntax: pdnssec test-algorithm algonum"<<endl
;
1308 testAlgorithm(lexical_cast
<int>(cmds
[1]));
1312 if(cmds
[0] == "test-algorithms") {
1317 loadMainConfig(g_vm
["config-dir"].as
<string
>());
1320 if(cmds
[0] == "create-bind-db") {
1322 if(cmds
.size() != 2) {
1323 cerr
<< "Syntax: pdnssec create-bind-db fname"<<endl
;
1327 SSQLite3
db(cmds
[1], true); // create=ok
1328 vector
<string
> statements
;
1329 stringtok(statements
, sqlCreate
, ";");
1330 BOOST_FOREACH(const string
& statement
, statements
) {
1331 db
.execute(statement
);
1334 catch(SSqlException
& se
) {
1335 throw PDNSException("Error creating database in BIND backend: "+se
.txtReason());
1339 cerr
<<"bind-dnssec-db requires building PowerDNS with SQLite3"<<endl
;
1346 if (cmds
[0] == "test-schema") {
1347 if(cmds
.size() != 2) {
1348 cerr
<< "Syntax: pdnssec test-schema ZONE"<<endl
;
1351 testSchema(dk
, cmds
[1]);
1354 if(cmds
[0] == "rectify-zone") {
1355 if(cmds
.size() < 2) {
1356 cerr
<< "Syntax: pdnssec rectify-zone ZONE [ZONE..]"<<endl
;
1359 unsigned int exitCode
= 0;
1360 for(unsigned int n
= 1; n
< cmds
.size(); ++n
)
1361 if (!rectifyZone(dk
, cmds
[n
])) exitCode
= 1;
1364 else if (cmds
[0] == "rectify-all-zones") {
1365 rectifyAllZones(dk
);
1367 else if(cmds
[0] == "check-zone") {
1368 if(cmds
.size() != 2) {
1369 cerr
<< "Syntax: pdnssec check-zone ZONE"<<endl
;
1372 UeberBackend
B("default");
1373 exit(checkZone(dk
, B
, cmds
[1]));
1375 else if(cmds
[0] == "bench-db") {
1376 dbBench(cmds
.size() > 1 ? cmds
[1] : "");
1378 else if (cmds
[0] == "check-all-zones") {
1379 exit(checkAllZones(dk
));
1381 else if (cmds
[0] == "list-all-zones") {
1382 if (cmds
.size() > 2) {
1383 cerr
<< "Syntax: pdnssec list-all-zones [master|slave|native]"<<endl
;
1386 if (cmds
.size() == 2)
1387 return listAllZones(cmds
[1]);
1388 return listAllZones();
1390 else if (cmds
[0] == "test-zone") {
1391 cerr
<< "Did you mean check-zone?"<<endl
;
1394 else if (cmds
[0] == "test-all-zones") {
1395 cerr
<< "Did you mean check-all-zones?"<<endl
;
1399 else if(cmds
[0] == "signing-server" )
1403 else if(cmds
[0] == "signing-slave")
1405 launchSigningService(0);
1408 else if(cmds
[0] == "test-speed") {
1409 if(cmds
.size() < 2) {
1410 cerr
<< "Syntax: pdnssec test-speed numcores [signing-server]"<<endl
;
1413 testSpeed(dk
, cmds
[1], (cmds
.size() > 3) ? cmds
[3] : "", atoi(cmds
[2].c_str()));
1415 else if(cmds
[0] == "verify-crypto") {
1416 if(cmds
.size() != 2) {
1417 cerr
<< "Syntax: pdnssec verify-crypto FILE"<<endl
;
1420 verifyCrypto(cmds
[1]);
1423 else if(cmds
[0] == "show-zone") {
1424 if(cmds
.size() != 2) {
1425 cerr
<< "Syntax: pdnssec show-zone ZONE"<<endl
;
1428 const string
& zone
=cmds
[1];
1429 if (!showZone(dk
, zone
)) return 1;
1431 else if(cmds
[0] == "disable-dnssec") {
1432 if(cmds
.size() != 2) {
1433 cerr
<< "Syntax: pdnssec disable-dnssec ZONE"<<endl
;
1436 const string
& zone
=cmds
[1];
1437 if(!disableDNSSECOnZone(dk
, zone
)) {
1438 cerr
<< "Cannot disable DNSSEC on " << zone
<< endl
;
1442 else if(cmds
[0] == "activate-zone-key") {
1443 if(cmds
.size() != 3) {
1444 cerr
<< "Syntax: pdnssec activate-zone-key ZONE KEY-ID"<<endl
;
1447 const string
& zone
=cmds
[1];
1448 unsigned int id
=atoi(cmds
[2].c_str());
1451 cerr
<<"Invalid KEY-ID"<<endl
;
1454 if (!dk
.activateKey(zone
, id
)) {
1455 cerr
<<"Activation of key failed"<<endl
;
1460 else if(cmds
[0] == "deactivate-zone-key") {
1461 if(cmds
.size() != 3) {
1462 cerr
<< "Syntax: pdnssec deactivate-zone-key ZONE KEY-ID"<<endl
;
1465 const string
& zone
=cmds
[1];
1466 unsigned int id
=atoi(cmds
[2].c_str());
1469 cerr
<<"Invalid KEY-ID"<<endl
;
1472 if (!dk
.deactivateKey(zone
, id
)) {
1473 cerr
<<"Deactivation of key failed"<<endl
;
1478 else if(cmds
[0] == "add-zone-key") {
1479 if(cmds
.size() < 3 ) {
1480 cerr
<< "Syntax: pdnssec add-zone-key ZONE zsk|ksk [bits] [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384]"<<endl
;
1483 const string
& zone
=cmds
[1];
1485 UeberBackend
B("default");
1488 if (!B
.getDomainInfo(zone
, di
)){
1489 cerr
<< "No such zone in the database" << endl
;
1493 // need to get algorithm, bits & ksk or zsk from commandline
1494 bool keyOrZone
=false;
1499 for(unsigned int n
=2; n
< cmds
.size(); ++n
) {
1500 if(pdns_iequals(cmds
[n
], "zsk"))
1502 else if(pdns_iequals(cmds
[n
], "ksk"))
1504 else if((tmp_algo
= shorthand2algorithm(cmds
[n
]))>0) {
1505 algorithm
= tmp_algo
;
1506 } else if(pdns_iequals(cmds
[n
], "active")) {
1508 } else if(pdns_iequals(cmds
[n
], "inactive") || pdns_iequals(cmds
[n
], "passive")) {
1510 } else if(atoi(cmds
[n
].c_str())) {
1511 bits
= atoi(cmds
[n
].c_str());
1513 cerr
<<"Unknown algorithm, key flag or size '"<<cmds
[n
]<<"'"<<endl
;
1514 exit(EXIT_FAILURE
);;
1517 if(!dk
.addKey(zone
, keyOrZone
, algorithm
, bits
, active
)) {
1518 cerr
<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl
;
1522 cerr
<<"Added a " << (keyOrZone
? "KSK" : "ZSK")<<" with algorithm = "<<algorithm
<<", active="<<active
<<endl
;
1524 cerr
<<"Requested specific key size of "<<bits
<<" bits"<<endl
;
1527 else if(cmds
[0] == "remove-zone-key") {
1528 if(cmds
.size() < 3) {
1529 cerr
<<"Syntax: pdnssec remove-zone-key ZONE KEY-ID"<<endl
;
1532 const string
& zone
=cmds
[1];
1533 unsigned int id
=atoi(cmds
[2].c_str());
1534 if (!dk
.removeKey(zone
, id
)) {
1535 cerr
<<"Cannot remove key " << id
<< " from " << zone
<<endl
;
1540 else if(cmds
[0] == "delete-zone") {
1541 if(cmds
.size() != 2) {
1542 cerr
<<"Syntax: pdnssec delete-zone ZONE"<<endl
;
1545 exit(deleteZone(cmds
[1]));
1547 else if(cmds
[0] == "create-zone") {
1548 if(cmds
.size() != 2) {
1549 cerr
<<"Syntax: pdnssec create-zone ZONE"<<endl
;
1552 exit(createZone(cmds
[1]));
1554 else if(cmds
[0] == "list-zone") {
1555 if(cmds
.size() != 2) {
1556 cerr
<<"Syntax: pdnssec list-zone ZONE"<<endl
;
1562 exit(listZone(cmds
[1]));
1564 else if(cmds
[0] == "load-zone") {
1565 if(cmds
.size() != 3) {
1566 cerr
<<"Syntax: pdnssec load-zone ZONE FILENAME"<<endl
;
1572 exit(loadZone(cmds
[1], cmds
[2]));
1574 else if(cmds
[0] == "secure-zone") {
1575 if(cmds
.size() < 2) {
1576 cerr
<< "Syntax: pdnssec secure-zone ZONE"<<endl
;
1579 vector
<string
> mustRectify
;
1580 dk
.startTransaction();
1581 unsigned int zoneErrors
=0;
1582 for(unsigned int n
= 1; n
< cmds
.size(); ++n
) {
1583 const string
& zone
=cmds
[n
];
1584 if(secureZone(dk
, zone
)) {
1585 mustRectify
.push_back(zone
);
1591 dk
.commitTransaction();
1592 BOOST_FOREACH(string
& zone
, mustRectify
)
1593 rectifyZone(dk
, zone
);
1600 else if (cmds
[0] == "secure-all-zones") {
1601 if (cmds
.size() >= 2 && !pdns_iequals(cmds
[1], "increase-serial")) {
1602 cerr
<< "Syntax: pdnssec secure-all-zones [increase-serial]"<<endl
;
1606 UeberBackend
B("default");
1608 vector
<DomainInfo
> domainInfo
;
1609 B
.getAllDomains(&domainInfo
);
1611 unsigned int zonesSecured
=0, zoneErrors
=0;
1612 BOOST_FOREACH(DomainInfo di
, domainInfo
) {
1613 if(!dk
.isSecuredZone(di
.zone
)) {
1614 cout
<<"Securing "<<di
.zone
<<": ";
1615 if (secureZone(dk
, di
.zone
)) {
1617 if (cmds
.size() == 2) {
1618 if (!increaseSerial(di
.zone
, dk
))
1627 cout
<<"Secured: "<<zonesSecured
<<" zones. Errors: "<<zoneErrors
<<endl
;
1634 else if(cmds
[0]=="set-nsec3") {
1635 if(cmds
.size() < 2) {
1636 cerr
<<"Syntax: pdnssec set-nsec3 ZONE 'params' [narrow]"<<endl
;
1639 string nsec3params
= cmds
.size() > 2 ? cmds
[2] : "1 0 1 ab";
1640 bool narrow
= cmds
.size() > 3 && cmds
[3]=="narrow";
1641 NSEC3PARAMRecordContent
ns3pr(nsec3params
);
1643 string zone
=cmds
[1];
1644 if(!dk
.isSecuredZone(zone
)) {
1645 cerr
<<"Zone '"<<zone
<<"' is not secured, can't set NSEC3 parameters"<<endl
;
1648 dk
.setNSEC3PARAM(zone
, ns3pr
, narrow
);
1651 cerr
<<"NSEC3 set, please rectify-zone if your backend needs it"<<endl
;
1653 cerr
<<"NSEC3 (opt-out) set, please rectify-zone if your backend needs it"<<endl
;
1655 else if(cmds
[0]=="set-presigned") {
1656 if(cmds
.size() < 2) {
1657 cerr
<<"Syntax: pdnssec set-presigned ZONE"<<endl
;
1660 if (! dk
.setPresigned(cmds
[1])) {
1661 cerr
<< "Could not set presigned on for " << cmds
[1] << endl
;
1666 else if(cmds
[0]=="unset-presigned") {
1667 if(cmds
.size() < 2) {
1668 cerr
<<"Syntax: pdnssec unset-presigned ZONE"<<endl
;
1671 if (! dk
.unsetPresigned(cmds
[1])) {
1672 cerr
<< "Could not unset presigned on for " << cmds
[1] << endl
;
1677 else if(cmds
[0]=="hash-zone-record") {
1678 if(cmds
.size() < 3) {
1679 cerr
<<"Syntax: pdnssec hash-zone-record ZONE RNAME"<<endl
;
1682 string
& zone
=cmds
[1];
1683 string
& record
=cmds
[2];
1684 NSEC3PARAMRecordContent ns3pr
;
1686 if(!dk
.getNSEC3PARAM(zone
, &ns3pr
, &narrow
)) {
1687 cerr
<<"The '"<<zone
<<"' zone does not use NSEC3"<<endl
;
1691 cerr
<<"The '"<<zone
<<"' zone uses narrow NSEC3, but calculating hash anyhow"<<endl
;
1694 cout
<<toBase32Hex(hashQNameWithSalt(ns3pr
.d_iterations
, ns3pr
.d_salt
, record
))<<endl
;
1696 else if(cmds
[0]=="unset-nsec3") {
1697 if(cmds
.size() < 2) {
1698 cerr
<<"Syntax: pdnssec unset-nsec3 ZONE"<<endl
;
1701 if ( ! dk
.unsetNSEC3PARAM(cmds
[1])) {
1702 cerr
<<"Cannot unset NSEC3 param for " << cmds
[1] << endl
;
1707 else if(cmds
[0]=="export-zone-key") {
1708 if(cmds
.size() < 3) {
1709 cerr
<<"Syntax: pdnssec export-zone-key ZONE KEY-ID"<<endl
;
1713 string zone
=cmds
[1];
1714 unsigned int id
=atoi(cmds
[2].c_str());
1715 DNSSECPrivateKey dpk
=dk
.getKeyById(zone
, id
);
1716 cout
<< dpk
.getKey()->convertToISC() <<endl
;
1718 else if(cmds
[0]=="increase-serial") {
1719 if (cmds
.size() < 2) {
1720 cerr
<<"Syntax: pdnssec increase-serial ZONE"<<endl
;
1723 return increaseSerial(cmds
[1], dk
);
1725 else if(cmds
[0]=="import-zone-key-pem") {
1726 if(cmds
.size() < 4) {
1727 cerr
<<"Syntax: pdnssec import-zone-key-pem ZONE FILE algorithm [ksk|zsk]"<<endl
;
1730 string zone
=cmds
[1];
1731 string fname
=cmds
[2];
1733 ifstream
ifs(fname
.c_str());
1734 string tmp
, interim
, raw
;
1735 while(getline(ifs
, line
)) {
1741 B64Decode(interim
, raw
);
1742 DNSSECPrivateKey dpk
;
1743 DNSKEYRecordContent drc
;
1744 shared_ptr
<DNSCryptoKeyEngine
> key(DNSCryptoKeyEngine::makeFromPEMString(drc
, raw
));
1747 dpk
.d_algorithm
= atoi(cmds
[3].c_str());
1749 if(dpk
.d_algorithm
== 7)
1750 dpk
.d_algorithm
= 5;
1752 cerr
<<(int)dpk
.d_algorithm
<<endl
;
1754 if(cmds
.size() > 4) {
1755 if(pdns_iequals(cmds
[4], "ZSK"))
1757 else if(pdns_iequals(cmds
[4], "KSK"))
1760 cerr
<<"Unknown key flag '"<<cmds
[4]<<"'"<<endl
;
1765 dpk
.d_flags
= 257; // ksk
1767 if(!dk
.addKey(zone
, dpk
)) {
1768 cerr
<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl
;
1773 else if(cmds
[0]=="import-zone-key") {
1774 if(cmds
.size() < 3) {
1775 cerr
<<"Syntax: pdnssec import-zone-key ZONE FILE [ksk|zsk] [active|passive]"<<endl
;
1778 string zone
=cmds
[1];
1779 string fname
=cmds
[2];
1780 DNSSECPrivateKey dpk
;
1781 DNSKEYRecordContent drc
;
1782 shared_ptr
<DNSCryptoKeyEngine
> key(DNSCryptoKeyEngine::makeFromISCFile(drc
, fname
.c_str()));
1784 dpk
.d_algorithm
= drc
.d_algorithm
;
1786 if(dpk
.d_algorithm
== 7)
1787 dpk
.d_algorithm
= 5;
1792 for(unsigned int n
= 3; n
< cmds
.size(); ++n
) {
1793 if(pdns_iequals(cmds
[n
], "ZSK"))
1795 else if(pdns_iequals(cmds
[n
], "KSK"))
1797 else if(pdns_iequals(cmds
[n
], "active"))
1799 else if(pdns_iequals(cmds
[n
], "passive") || pdns_iequals(cmds
[n
], "inactive"))
1802 cerr
<<"Unknown key flag '"<<cmds
[n
]<<"'"<<endl
;
1806 if(!dk
.addKey(zone
, dpk
, active
)) {
1807 cerr
<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl
;
1811 else if(cmds
[0]=="export-zone-dnskey") {
1812 if(cmds
.size() < 3) {
1813 cerr
<<"Syntax: pdnssec export-zone-dnskey ZONE KEY-ID"<<endl
;
1817 string zone
=cmds
[1];
1818 unsigned int id
=atoi(cmds
[2].c_str());
1819 DNSSECPrivateKey dpk
=dk
.getKeyById(zone
, id
);
1820 cout
<< zone
<<" IN DNSKEY "<<dpk
.getDNSKEY().getZoneRepresentation() <<endl
;
1821 if(dpk
.d_flags
== 257) {
1822 cout
<< zone
<< " IN DS "<<makeDSFromDNSKey(zone
, dpk
.getDNSKEY(), 1).getZoneRepresentation() << endl
;
1823 cout
<< zone
<< " IN DS "<<makeDSFromDNSKey(zone
, dpk
.getDNSKEY(), 2).getZoneRepresentation() << endl
;
1826 else if(cmds
[0] == "generate-zone-key") {
1827 if(cmds
.size() < 2 ) {
1828 cerr
<< "Syntax: pdnssec generate-zone-key zsk|ksk [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384] [bits]"<<endl
;
1831 // need to get algorithm, bits & ksk or zsk from commandline
1832 bool keyOrZone
=false;
1836 for(unsigned int n
=1; n
< cmds
.size(); ++n
) {
1837 if(pdns_iequals(cmds
[n
], "zsk"))
1839 else if(pdns_iequals(cmds
[n
], "ksk"))
1841 else if((tmp_algo
= shorthand2algorithm(cmds
[n
]))>0) {
1842 algorithm
= tmp_algo
;
1843 } else if(atoi(cmds
[n
].c_str()))
1844 bits
= atoi(cmds
[n
].c_str());
1846 cerr
<<"Unknown algorithm, key flag or size '"<<cmds
[n
]<<"'"<<endl
;
1850 cerr
<<"Generating a " << (keyOrZone
? "KSK" : "ZSK")<<" with algorithm = "<<algorithm
<<endl
;
1852 cerr
<<"Requesting specific key size of "<<bits
<<" bits"<<endl
;
1854 DNSSECPrivateKey dspk
;
1855 shared_ptr
<DNSCryptoKeyEngine
> dpk(DNSCryptoKeyEngine::make(algorithm
)); // defaults to RSA for now, could be smart w/algorithm! XXX FIXME
1858 bits
= keyOrZone
? 2048 : 1024;
1860 if(algorithm
== 12 || algorithm
== 13 || algorithm
== 250) // ECDSA, GOST, ED25519
1862 else if(algorithm
== 14)
1865 throw runtime_error("Can't guess key size for algorithm "+lexical_cast
<string
>(algorithm
));
1871 dspk
.d_algorithm
= algorithm
;
1872 dspk
.d_flags
= keyOrZone
? 257 : 256;
1874 // print key to stdout
1875 cout
<< "Flags: " << dspk
.d_flags
<< endl
<<
1876 dspk
.getKey()->convertToISC() << endl
;
1877 } else if (cmds
[0]=="generate-tsig-key") {
1878 if (cmds
.size() < 3) {
1879 cerr
<< "Syntax: " << cmds
[0] << " name (hmac-md5|hmac-sha1|hmac-sha224|hmac-sha256|hmac-sha384|hmac-sha512)" << endl
;
1882 string name
= cmds
[1];
1883 string algo
= cmds
[2];
1888 if (algo
== "hmac-md5") {
1890 } else if (algo
== "hmac-sha1") {
1892 } else if (algo
== "hmac-sha224") {
1894 } else if (algo
== "hmac-sha256") {
1896 } else if (algo
== "hmac-sha384") {
1898 } else if (algo
== "hmac-sha512") {
1901 cerr
<< "Cannot generate key for " << algo
<< endl
;
1905 cerr
<< "Generating new key with " << klen
<< " bytes (this can take a while)" << endl
;
1906 seedRandom(::arg()["entropy-source"]);
1907 for(size_t i
= 0; i
< klen
; i
+=4) {
1908 *(unsigned int*)(tmpkey
+i
) = dns_random(0xffffffff);
1910 key
= Base64Encode(std::string(tmpkey
, klen
));
1912 UeberBackend
B("default");
1913 if (B
.setTSIGKey(name
, algo
, key
)) {
1914 cout
<< "Create new TSIG key " << name
<< " " << algo
<< " " << key
<< endl
;
1916 cout
<< "Failure storing new TSIG key " << name
<< " " << algo
<< " " << key
<< endl
;
1920 } else if (cmds
[0]=="import-tsig-key") {
1921 if (cmds
.size() < 4) {
1922 cerr
<< "Syntax: " << cmds
[0] << " name algorithm key" << endl
;
1925 string name
= cmds
[1];
1926 string algo
= cmds
[2];
1927 string key
= cmds
[3];
1929 UeberBackend
B("default");
1930 if (B
.setTSIGKey(name
, algo
, key
)) {
1931 cout
<< "Imported TSIG key " << name
<< " " << algo
<< endl
;
1933 cout
<< "Failure importing TSIG key " << name
<< " " << algo
<< endl
;
1937 } else if (cmds
[0]=="delete-tsig-key") {
1938 if (cmds
.size() < 2) {
1939 cerr
<< "Syntax: " << cmds
[0] << " name" << endl
;
1942 string name
= cmds
[1];
1944 UeberBackend
B("default");
1945 if (B
.deleteTSIGKey(name
)) {
1946 cout
<< "Deleted TSIG key " << name
<< endl
;
1948 cout
<< "Failure deleting TSIG key " << name
<< endl
;
1952 } else if (cmds
[0]=="list-tsig-keys") {
1953 std::vector
<struct TSIGKey
> keys
;
1954 UeberBackend
B("default");
1955 if (B
.getTSIGKeys(keys
)) {
1956 BOOST_FOREACH(const struct TSIGKey
&key
, keys
) {
1957 cout
<< key
.name
<< " " << key
.algorithm
<< " " << key
.key
<< endl
;
1961 } else if (cmds
[0]=="activate-tsig-key") {
1963 if (cmds
.size() < 4) {
1964 cerr
<< "Syntax: " << cmds
[0] << " zone name [master|slave]" << endl
;
1967 string zname
= cmds
[1];
1968 string name
= cmds
[2];
1969 if (cmds
[3] == "master")
1970 metaKey
= "TSIG-ALLOW-AXFR";
1971 else if (cmds
[3] == "slave")
1972 metaKey
= "AXFR-MASTER-TSIG";
1974 cerr
<< "Invalid parameter '" << cmds
[3] << "', expected master or slave" << endl
;
1977 UeberBackend
B("default");
1978 std::vector
<std::string
> meta
;
1979 if (!B
.getDomainMetadata(zname
, metaKey
, meta
)) {
1980 cout
<< "Failure enabling TSIG key " << name
<< " for " << zname
<< endl
;
1984 BOOST_FOREACH(std::string tmpname
, meta
) {
1985 if (tmpname
== name
) { found
= true; break; }
1987 if (!found
) meta
.push_back(name
);
1988 if (B
.setDomainMetadata(zname
, metaKey
, meta
)) {
1989 cout
<< "Enabled TSIG key " << name
<< " for " << zname
<< endl
;
1991 cout
<< "Failure enabling TSIG key " << name
<< " for " << zname
<< endl
;
1995 } else if (cmds
[0]=="deactivate-tsig-key") {
1997 if (cmds
.size() < 4) {
1998 cerr
<< "Syntax: " << cmds
[0] << " zone name [master|slave]" << endl
;
2001 string zname
= cmds
[1];
2002 string name
= cmds
[2];
2003 if (cmds
[3] == "master")
2004 metaKey
= "TSIG-ALLOW-AXFR";
2005 else if (cmds
[3] == "slave")
2006 metaKey
= "AXFR-MASTER-TSIG";
2008 cerr
<< "Invalid parameter '" << cmds
[3] << "', expected master or slave" << endl
;
2012 UeberBackend
B("default");
2013 std::vector
<std::string
> meta
;
2014 if (!B
.getDomainMetadata(zname
, metaKey
, meta
)) {
2015 cout
<< "Failure disabling TSIG key " << name
<< " for " << zname
<< endl
;
2018 std::vector
<std::string
>::iterator iter
= meta
.begin();
2019 for(;iter
!= meta
.end(); iter
++) if (*iter
== name
) break;
2020 if (iter
!= meta
.end()) meta
.erase(iter
);
2021 if (B
.setDomainMetadata(zname
, metaKey
, meta
)) {
2022 cout
<< "Disabled TSIG key " << name
<< " for " << zname
<< endl
;
2024 cout
<< "Failure disabling TSIG key " << name
<< " for " << zname
<< endl
;
2028 } else if (cmds
[0]=="get-meta") {
2029 UeberBackend
B("default");
2030 if (cmds
.size() < 2) {
2031 cerr
<< "Syntax: " << cmds
[0] << " zone [kind kind ..]" << endl
;
2034 string zone
= cmds
[1];
2035 vector
<string
> keys
;
2038 if (!B
.getDomainInfo(zone
, di
)) {
2039 cerr
<< "Invalid zone '" << zone
<< "'" << endl
;
2043 if (cmds
.size() > 2) {
2044 keys
.assign(cmds
.begin() + 2, cmds
.end());
2045 std::cout
<< "Metadata for '" << zone
<< "'" << endl
;
2046 BOOST_FOREACH(const string kind
, keys
) {
2047 vector
<string
> meta
;
2049 if (B
.getDomainMetadata(zone
, kind
, meta
)) {
2050 cout
<< kind
<< " = " << boost::join(meta
, ", ") << endl
;
2054 std::map
<std::string
, std::vector
<std::string
> > meta
;
2055 std::cout
<< "Metadata for '" << zone
<< "'" << endl
;
2056 B
.getAllDomainMetadata(zone
, meta
);
2057 for(std::map
<std::string
, std::vector
<std::string
> >::const_iterator each_meta
= meta
.begin(); each_meta
!= meta
.end(); each_meta
++) {
2058 cout
<< each_meta
->first
<< " = " << boost::join(each_meta
->second
, ", ") << endl
;
2063 } else if (cmds
[0]=="set-meta") {
2064 UeberBackend
B("default");
2065 if (cmds
.size() < 3) {
2066 cerr
<< "Syntax: " << cmds
[0] << " zone kind [value value ..]" << endl
;
2069 string zone
= cmds
[1];
2070 string kind
= cmds
[2];
2071 vector
<string
> meta(cmds
.begin() + 3, cmds
.end());
2073 if (!B
.setDomainMetadata(zone
, kind
, meta
)) {
2074 cerr
<< "Unable to set meta for '" << zone
<< "'" << endl
;
2077 cout
<< "Set '" << zone
<< "' meta " << kind
<< " = " << boost::join(meta
, ", ") << endl
;
2079 } else if (cmds
[0]=="hsm") {
2081 UeberBackend
B("default");
2082 if (cmds
[1] == "assign") {
2083 DNSCryptoKeyEngine::storvector_t storvect
;
2086 if (cmds
.size() < 9) {
2087 std::cout
<< "Usage: pdnssec hsm assign zone algorithm ksk|zsk module slot pin label" << std::endl
;
2091 string zone
= cmds
[2];
2094 if (!B
.getDomainInfo(zone
, di
)) {
2095 cerr
<< "Unable to assign module to unknown zone '" << zone
<< "'" << std::endl
;
2099 int algorithm
= shorthand2algorithm(cmds
[3]);
2101 bool keyOrZone
= (cmds
[4] == "ksk" ? true : false);
2102 string module
= cmds
[5];
2103 string slot
= cmds
[6];
2104 string pin
= cmds
[7];
2105 string label
= cmds
[8];
2107 std::ostringstream iscString
;
2108 iscString
<< "Private-key-format: v1.2" << std::endl
<<
2109 "Algorithm: " << algorithm
<< std::endl
<<
2110 "Engine: " << module
<< std::endl
<<
2111 "Slot: " << slot
<< std::endl
<<
2112 "PIN: " << pin
<< std::endl
<<
2113 "Label: " << label
<< std::endl
;
2115 DNSKEYRecordContent drc
;
2116 DNSSECPrivateKey dpk
;
2117 dpk
.d_flags
= (keyOrZone
? 257 : 256);
2118 dpk
.setKey(shared_ptr
<DNSCryptoKeyEngine
>(DNSCryptoKeyEngine::makeFromISCString(drc
, iscString
.str())));
2120 if (!(id
= dk
.addKey(zone
, dpk
))) {
2121 cerr
<< "Unable to assign module slot to zone" << std::endl
;
2125 cerr
<< "Module " << module
<< " slot " << slot
<< " assigned to " << zone
<< " with key id " << id
<< endl
;
2127 } else if (cmds
[1] == "create-key") {
2129 if (cmds
.size() < 4) {
2130 cerr
<< "Usage: pdnssec hsm create-key zone key-id [bits]" << endl
;
2134 string zone
= cmds
[2];
2138 if (!B
.getDomainInfo(zone
, di
)) {
2139 cerr
<< "Unable to create key for unknown zone '" << zone
<< "'" << std::endl
;
2143 id
= boost::lexical_cast
<unsigned int>(cmds
[3]);
2144 std::vector
<DNSBackend::KeyData
> keys
;
2145 if (!B
.getDomainKeys(zone
, 0, keys
)) {
2146 cerr
<< "No keys found for zone " << zone
<< std::endl
;
2150 DNSCryptoKeyEngine
*dke
= NULL
;
2151 // lookup correct key
2152 BOOST_FOREACH(DNSBackend::KeyData
&kd
, keys
) {
2155 DNSKEYRecordContent dkrc
;
2156 dke
= DNSCryptoKeyEngine::makeFromISCString(dkrc
, kd
.content
);
2161 cerr
<< "Could not find key with ID " << id
<< endl
;
2164 if (cmds
.size() > 4) {
2165 bits
= boost::lexical_cast
<int>(cmds
[4]);
2168 cerr
<< "Invalid bit size " << bits
<< "given, must be positive integer";
2173 } catch (PDNSException
& e
) {
2174 cerr
<< e
.reason
<< endl
;
2178 cerr
<< "Key of size " << bits
<< " created" << std::endl
;
2182 cerr
<<"PKCS#11 support not enabled"<<endl
;
2186 cerr
<<"Unknown command '"<<cmds
[0] <<"'"<< endl
;
2191 catch(PDNSException
& ae
) {
2192 cerr
<<"Error: "<<ae
.reason
<<endl
;
2195 catch(std::exception
& e
) {
2196 cerr
<<"Error: "<<e
.what()<<endl
;