]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/pdnssec.cc
Display correct key ID after assign
[thirdparty/pdns.git] / pdns / pdnssec.cc
CommitLineData
870a0fe4
AT
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
1d211b1b 4#include "dnsseckeeper.hh"
d3151289 5#include "dnssecinfra.hh"
1d211b1b 6#include "statbag.hh"
01fde57c 7#include "base32.hh"
ed3f8559 8#include "base64.hh"
1d211b1b
BH
9#include <boost/foreach.hpp>
10#include <boost/program_options.hpp>
8daea594 11#include <boost/assign/std/vector.hpp>
451ba512 12#include <boost/assign/list_of.hpp>
20002664
BH
13#include "dnsbackend.hh"
14#include "ueberbackend.hh"
15#include "arguments.hh"
16#include "packetcache.hh"
aa65a832 17#include "zoneparser-tng.hh"
ea937fd4 18#include "signingpipe.hh"
a56bc64d 19#include "dns_random.hh"
a0a6cb58 20#include <fstream>
a2b0e9b5
KM
21#ifdef HAVE_SQLITE3
22#include "ssqlite3.hh"
fd9f80de 23#include "bind-dnssec.schema.sqlite3.sql.h"
a2b0e9b5 24#endif
49449751 25
20002664
BH
26StatBag S;
27PacketCache PC;
1d211b1b 28
1d211b1b
BH
29namespace po = boost::program_options;
30po::variables_map g_vm;
31
39a8b5c0 32string s_programname="pdns";
20002664 33
b3ce3dec 34namespace {
b8572438 35 bool g_verbose;
49449751
BH
36}
37
20002664
BH
38ArgvMap &arg()
39{
40 static ArgvMap arg;
41 return arg;
42}
43
1d211b1b
BH
44string humanTime(time_t t)
45{
46 char ret[256];
47 struct tm tm;
48 localtime_r(&t, &tm);
49 strftime(ret, sizeof(ret)-1, "%c", &tm); // %h:%M %Y-%m-%d
50 return ret;
51}
52
e0ad7bb1
PD
53static void algorithm2name(uint8_t algo, string &name) {
54 switch(algo) {
55 case 0:
56 name = "Reserved"; return;
57 case 1:
58 name = "RSAMD5"; return;
59 case 2:
60 name = "DH"; return;
61 case 3:
62 name = "DSA"; return;
63 case 4:
64 name = "ECC"; return;
65 case 5:
66 name = "RSASHA1"; return;
67 case 6:
68 name = "DSA-NSEC3-SHA1"; return;
69 case 7:
70 name = "RSASHA1-NSEC3-SHA1"; return;
71 case 8:
72 name = "RSASHA256"; return;
73 case 9:
74 name = "Reserved"; return;
75 case 10:
76 name = "RSASHA512"; return;
77 case 11:
78 name = "Reserved"; return;
79 case 12:
80 name = "ECC-GOST"; return;
81 case 13:
82 name = "ECDSAP256SHA256"; return;
83 case 14:
84 name = "ECDSAP384SHA384"; return;
85 case 252:
86 name = "INDIRECT"; return;
87 case 253:
88 name = "PRIVATEDNS"; return;
89 case 254:
90 name = "PRIVATEOID"; return;
91 default:
92 name = "Unallocated/Reserved"; return;
232f0877 93 }
e0ad7bb1
PD
94};
95
36758d25
PD
96static int shorthand2algorithm(const string &algorithm)
97{
98 if (!algorithm.compare("rsamd5")) return 1;
99 if (!algorithm.compare("dh")) return 2;
100 if (!algorithm.compare("dsa")) return 3;
101 if (!algorithm.compare("ecc")) return 4;
102 if (!algorithm.compare("rsasha1")) return 5;
103 if (!algorithm.compare("rsasha256")) return 8;
104 if (!algorithm.compare("rsasha512")) return 10;
105 if (!algorithm.compare("gost")) return 12;
106 if (!algorithm.compare("ecdsa256")) return 13;
107 if (!algorithm.compare("ecdsa384")) return 14;
108 if (!algorithm.compare("ed25519")) return 250;
109 return -1;
110}
111
7d9dcde0 112void loadMainConfig(const std::string& configdir)
20002664 113{
7d9dcde0 114 ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=configdir;
c6347f61 115 ::arg().set("pipebackend-abi-version","Version of the pipe backend ABI")="1";
f2e7d77b 116 ::arg().set("default-ttl","Seconds a result is valid if not set otherwise")="3600";
20002664 117 ::arg().set("launch","Which backends to launch");
6dfa0aa0 118 ::arg().set("dnssec","if we should do dnssec")="true";
4f6cf113 119 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")=g_vm["config-name"].as<string>();
20002664
BH
120 ::arg().setCmd("help","Provide a helpful message");
121 //::arg().laxParse(argc,argv);
122
123 if(::arg().mustDo("help")) {
ff5ba4f9
WA
124 cout<<"syntax:"<<endl<<endl;
125 cout<<::arg().helpstring(::arg()["help"])<<endl;
126 exit(0);
20002664
BH
127 }
128
129 if(::arg()["config-name"]!="")
130 s_programname+="-"+::arg()["config-name"];
131
132 string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
133 cleanSlashes(configname);
36758d25
PD
134
135 ::arg().set("default-ksk-algorithms","Default KSK algorithms")="rsasha256";
136 ::arg().set("default-ksk-size","Default KSK size (0 means default)")="0";
137 ::arg().set("default-zsk-algorithms","Default ZSK algorithms")="rsasha256";
92bdc094 138 ::arg().set("default-zsk-size","Default ZSK size (0 means default)")="0";
b5baefaf 139 ::arg().set("max-ent-entries", "Maximum number of empty non-terminals in a zone")="100000";
0949b8ae 140 ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR;
a56bc64d 141 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
0f310932
AT
142 ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
143 ::arg().set("loglevel","Amount of logging. Higher is more.")="0";
cc8df07f 144 ::arg().setSwitch("direct-dnskey","Fetch DNSKEY RRs from backend during DNSKEY synthesis")="no";
28b66a94 145 ::arg().set("max-nsec3-iterations","Limit the number of NSEC3 hash iterations")="500"; // RFC5155 10.3
bba84134 146 ::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries")="";
966828ac 147 ::arg().laxFile(configname.c_str());
12a92688 148
38392ad7 149 L.toConsole(Logger::Error); // so we print any errors
20002664 150 BackendMakers().launch(::arg()["launch"]); // vrooooom!
38392ad7 151 L.toConsole((Logger::Urgency)(::arg().asNum("loglevel")));
20002664 152 ::arg().laxFile(configname.c_str());
9abd98d3 153 //cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" <<endl;
20002664
BH
154
155 S.declare("qsize-q","Number of questions waiting for database attention");
156
157 S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
158 S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
159
160 S.declare("query-cache-hit","Number of hits on the query cache");
161 S.declare("query-cache-miss","Number of misses on the query cache");
162 ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
163 ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no";
ec7f535c 164 ::arg().set("recursive-cache-ttl","Seconds to store packets for recursive queries in the PacketCache")="10";
20002664 165 ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
ec7f535c
PD
166 ::arg().set("negquery-cache-ttl","Seconds to store negative query results in the QueryCache")="60";
167 ::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
da6a2926 168 ::arg().set("default-soa-name","name to insert in the SOA record if none set in the backend")="a.misconfigured.powerdns.server";
326a1978 169 ::arg().set("default-soa-mail","mail address to insert in the SOA record if none set in the backend")="";
20002664
BH
170 ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
171 ::arg().set("soa-retry-default","Default SOA retry")="3600";
172 ::arg().set("soa-expire-default","Default SOA expire")="604800";
abc1d928 173 ::arg().set("soa-minimum-ttl","Default SOA minimum ttl")="3600";
12a92688 174
20002664
BH
175 UeberBackend::go();
176}
177
d6c16697 178// irritatingly enough, rectifyZone needs its own ueberbackend and can't therefore benefit from transactions outside its scope
d4904322 179// I think this has to do with interlocking transactions between B and DK, but unsure.
032e3906 180bool rectifyZone(DNSSECKeeper& dk, const std::string& zone)
20002664 181{
9bd211e1
KM
182 if(dk.isPresigned(zone)){
183 cerr<<"Rectify presigned zone '"<<zone<<"' is not allowed/necessary."<<endl;
184 return false;
185 }
186
ba86110a 187 UeberBackend B("default");
d6c16697 188 bool doTransaction=true; // but see above
20002664 189 SOAData sd;
a279bc18 190
79ba7763 191 if(!B.getSOAUncached(zone, sd)) {
f28f2324 192 cerr<<"No SOA known for '"<<zone<<"', is such a zone in the database?"<<endl;
032e3906 193 return false;
a279bc18 194 }
81b39e4b 195 sd.db->list(zone, sd.domain_id);
81b39e4b 196
b5baefaf 197 DNSResourceRecord rr;
a279bc18
KM
198 set<string> qnames, nsset, dsnames, insnonterm, delnonterm;
199 map<string,bool> nonterm;
b5baefaf 200 bool doent=true;
a279bc18 201
20002664 202 while(sd.db->get(rr)) {
b5baefaf
PD
203 if (rr.qtype.getCode())
204 {
205 qnames.insert(rr.qname);
a279bc18 206 if(rr.qtype.getCode() == QType::NS && !pdns_iequals(rr.qname, zone))
b5baefaf
PD
207 nsset.insert(rr.qname);
208 if(rr.qtype.getCode() == QType::DS)
209 dsnames.insert(rr.qname);
210 }
211 else
212 if(doent)
213 delnonterm.insert(rr.qname);
81b39e4b 214 }
9abd98d3 215
c3c89361 216 NSEC3PARAMRecordContent ns3pr;
f28f2324 217 bool narrow;
3c873e66 218 bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
a279bc18 219 bool isOptOut=(haveNSEC3 && ns3pr.d_flags);
ece45ffb
PD
220 if(sd.db->doesDNSSEC())
221 {
a279bc18 222 if(!haveNSEC3)
ece45ffb 223 cerr<<"Adding NSEC ordering information "<<endl;
a279bc18
KM
224 else if(!narrow) {
225 if(!isOptOut)
226 cerr<<"Adding NSEC3 hashed ordering information for '"<<zone<<"'"<<endl;
227 else
228 cerr<<"Adding NSEC3 opt-out hashed ordering information for '"<<zone<<"'"<<endl;
229 } else
ece45ffb
PD
230 cerr<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields"<<endl;
231 }
232 else
233 cerr<<"Non DNSSEC zone, only adding empty non-terminals"<<endl;
a279bc18 234
d6c16697
BH
235 if(doTransaction)
236 sd.db->startTransaction("", -1);
a279bc18 237
b5baefaf
PD
238 bool realrr=true;
239 string hashed;
240
241 uint32_t maxent = ::arg().asNum("max-ent-entries");
242
243 dononterm:;
81b39e4b
BH
244 BOOST_FOREACH(const string& qname, qnames)
245 {
f28f2324 246 bool auth=true;
b5baefaf 247 string shorter(qname);
27045410 248
b5baefaf
PD
249 if(realrr) {
250 do {
251 if(nsset.count(shorter)) {
252 auth=false;
253 break;
254 }
255 } while(chopOff(shorter));
b5baefaf 256 }
27045410
PD
257
258 if(haveNSEC3)
259 {
a279bc18 260 if(!narrow && (realrr || !isOptOut || nonterm.find(qname)->second)) {
1bad4190 261 hashed=toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, qname));
4bf664d8
PD
262 if(g_verbose)
263 cerr<<"'"<<qname<<"' -> '"<< hashed <<"'"<<endl;
c2df797e 264 sd.db->updateDNSSECOrderAndAuthAbsolute(sd.domain_id, qname, hashed, auth);
f28f2324 265 }
a279bc18
KM
266 else {
267 if(!realrr)
268 auth=false;
c2df797e 269 sd.db->nullifyDNSSECOrderNameAndUpdateAuth(sd.domain_id, qname, auth);
a279bc18 270 }
27045410
PD
271 }
272 else // NSEC
273 {
b8adb30d
KM
274 sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, qname, auth);
275 if (!realrr)
c2df797e 276 sd.db->nullifyDNSSECOrderNameAndUpdateAuth(sd.domain_id, qname, auth);
b5baefaf
PD
277 }
278
b8adb30d 279 if(realrr)
b5baefaf 280 {
b8adb30d
KM
281 if (dsnames.count(qname))
282 sd.db->setDNSSECAuthOnDsRecord(sd.domain_id, qname);
283 if (!auth || nsset.count(qname)) {
a279bc18 284 if(isOptOut)
b8adb30d
KM
285 sd.db->nullifyDNSSECOrderNameAndAuth(sd.domain_id, qname, "NS");
286 sd.db->nullifyDNSSECOrderNameAndAuth(sd.domain_id, qname, "A");
287 sd.db->nullifyDNSSECOrderNameAndAuth(sd.domain_id, qname, "AAAA");
288 }
289
a279bc18 290 if(doent)
b5baefaf 291 {
b8adb30d
KM
292 shorter=qname;
293 while(!pdns_iequals(shorter, zone) && chopOff(shorter))
b5baefaf 294 {
54c9247e 295 if(!qnames.count(shorter))
b5baefaf 296 {
b8adb30d
KM
297 if(!(maxent))
298 {
299 cerr<<"Zone '"<<zone<<"' has too many empty non terminals."<<endl;
300 insnonterm.clear();
301 delnonterm.clear();
302 doent=false;
303 break;
304 }
a279bc18 305
54c9247e
KM
306 if (!delnonterm.count(shorter) && !nonterm.count(shorter))
307 insnonterm.insert(shorter);
308 else
309 delnonterm.erase(shorter);
310
a279bc18
KM
311 if (!nonterm.count(shorter)) {
312 nonterm.insert(pair<string, bool>(shorter, auth));
313 --maxent;
314 } else if (auth)
315 nonterm[shorter]=true;
b5baefaf 316 }
b5baefaf 317 }
27045410 318 }
c3c89361 319 }
20002664 320 }
b5baefaf
PD
321
322 if(realrr)
323 {
324 //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
325 if(!insnonterm.empty() || !delnonterm.empty() || !doent)
326 {
327 sd.db->updateEmptyNonTerminals(sd.domain_id, zone, insnonterm, delnonterm, !doent);
328 }
329 if(doent)
330 {
331 realrr=false;
a279bc18
KM
332 qnames.clear();
333 pair<string,bool> nt;
334 BOOST_FOREACH(nt, nonterm){
335 qnames.insert(nt.first);
336 }
b5baefaf
PD
337 goto dononterm;
338 }
339 }
340
d6c16697
BH
341 if(doTransaction)
342 sd.db->commitTransaction();
032e3906
PD
343
344 return true;
20002664
BH
345}
346
a0a6cb58 347void dbBench(const std::string& fname)
348{
349 ::arg().set("query-cache-ttl")="0";
350 ::arg().set("negquery-cache-ttl")="0";
351 UeberBackend B("default");
352
353 vector<string> domains;
354 if(!fname.empty()) {
355 ifstream ifs(fname.c_str());
356 if(!ifs) {
357 cerr<<"Could not open '"<<fname<<"' for reading domain names to query"<<endl;
358 }
359 string line;
360 while(getline(ifs,line)) {
361 trim(line);
362 domains.push_back(line);
363 }
364 }
365 if(domains.empty())
366 domains.push_back("powerdns.com");
367
368 int n=0;
369 DNSResourceRecord rr;
370 DTime dt;
371 dt.set();
372 unsigned int hits=0, misses=0;
373 for(; n < 10000; ++n) {
374 const string& domain = domains[random() % domains.size()];
375 B.lookup(QType(QType::NS), domain);
376 while(B.get(rr)) {
377 hits++;
378 }
379 B.lookup(QType(QType::A), boost::lexical_cast<string>(random())+"."+domain);
380 while(B.get(rr)) {
381 }
382 misses++;
383
384 }
385 cout<<0.001*dt.udiff()/n<<" millisecond/lookup"<<endl;
386 cout<<"Retrieved "<<hits<<" records, did "<<misses<<" queries which should have no match"<<endl;
387 cout<<"Packet cache reports: "<<S.read("query-cache-hit")<<" hits (should be 0) and "<<S.read("query-cache-miss") <<" misses"<<endl;
388}
389
1325e8a2
PD
390void rectifyAllZones(DNSSECKeeper &dk)
391{
ba86110a 392 UeberBackend B("default");
1325e8a2
PD
393 vector<DomainInfo> domainInfo;
394
ba86110a 395 B.getAllDomains(&domainInfo);
1325e8a2
PD
396 BOOST_FOREACH(DomainInfo di, domainInfo) {
397 cerr<<"Rectifying "<<di.zone<<": ";
398 rectifyZone(dk, di.zone);
399 }
400 cout<<"Rectified "<<domainInfo.size()<<" zones."<<endl;
401}
402
ba86110a 403int checkZone(DNSSECKeeper &dk, UeberBackend &B, const std::string& zone)
5d2e58b0 404{
5d2e58b0 405 SOAData sd;
79ba7763 406 if(!B.getSOAUncached(zone, sd)) {
fdc0adaf
KM
407 cout<<"[error] No SOA record present, or active, in zone '"<<zone<<"'"<<endl;
408 cout<<"Checked 0 records of '"<<zone<<"', 1 errors, 0 warnings."<<endl;
409 return 1;
bb0bbee2
KM
410 }
411 bool presigned=dk.isPresigned(zone);
fdc0adaf 412 sd.db->list(zone, sd.domain_id, true);
5d2e58b0 413 DNSResourceRecord rr;
8c949c52 414 uint64_t numrecords=0, numerrors=0, numwarnings=0;
f1b672ae 415
1e2e9565 416 bool hasNsAtApex = false;
befcd641 417 set<string> records, cnames, noncnames;
bb0bbee2 418 map<string, unsigned int> ttl;
f1b672ae
KM
419
420 ostringstream content;
bb0bbee2 421 pair<map<string, unsigned int>::iterator,bool> ret;
61717a51 422
035297ad 423 while(sd.db->get(rr)) {
f1b672ae
KM
424 if(!rr.qtype.getCode())
425 continue;
426
a6230867 427 numrecords++;
b191a835 428
84a0d08c
KM
429 if(rr.qtype.getCode() == QType::SOA) {
430 vector<string>parts;
431 stringtok(parts, rr.content);
432
433 ostringstream o;
434 o<<rr.content;
435 for(int pleft=parts.size(); pleft < 7; ++pleft) {
436 o<<" 0";
437 }
438 rr.content=o.str();
bb0bbee2
KM
439 }
440
77da04f6
KM
441 if(rr.qtype.getCode() == QType::TXT && !rr.content.empty() && rr.content[0]!='"')
442 rr.content = "\""+rr.content+"\"";
443
444 try {
445 shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content));
446 string tmp=drc->serialize(rr.qname);
447 tmp = drc->getZoneRepresentation();
0f470360
KM
448 if (rr.qtype.getCode() != QType::AAAA) {
449 if (!pdns_iequals(tmp, rr.content)) {
450 cout<<"[Warning] Parsed and original record content are not equal: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " '" << rr.content<<"' (Content parsed as '"<<tmp<<"')"<<endl;
0f470360
KM
451 numwarnings++;
452 }
453 } else {
1cac2653
KM
454 struct in6_addr tmpbuf;
455 if (inet_pton(AF_INET6, rr.content.c_str(), &tmpbuf) != 1 || rr.content.find('.') != string::npos) {
d4302710 456 cout<<"[Warning] Following record is not a valid IPv6 address: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " '" << rr.content<<"'"<<endl;
0f470360 457 numwarnings++;
1cac2653 458 }
77da04f6
KM
459 }
460 }
461 catch(std::exception& e)
462 {
463 cout<<"[Error] Following record had a problem: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
464 cout<<"[Error] Error was: "<<e.what()<<endl;
465 numerrors++;
466 continue;
467 }
468
a6230867
KM
469 if(!endsOn(rr.qname, zone)) {
470 cout<<"[Warning] Record '"<<rr.qname<<" IN "<<rr.qtype.getName()<<" "<<rr.content<<"' in zone '"<<zone<<"' is out-of-zone."<<endl;
471 numwarnings++;
472 continue;
473 }
474
f1b672ae 475 content.str("");
77da04f6 476 content<<rr.qname<<" "<<rr.qtype.getName()<<" "<<rr.content;
bb0bbee2
KM
477 if (records.count(toLower(content.str()))) {
478 cout<<"[Error] Duplicate record found in rrset: '"<<rr.qname<<" IN "<<rr.qtype.getName()<<" "<<rr.content<<"'"<<endl;
befcd641
KM
479 numerrors++;
480 continue;
481 } else
bb0bbee2 482 records.insert(toLower(content.str()));
befcd641 483
f1b672ae
KM
484 content.str("");
485 content<<rr.qname<<" "<<rr.qtype.getName();
63372f34
KM
486 if (rr.qtype.getCode() == QType::RRSIG) {
487 RRSIGRecordContent rrc(rr.content);
488 content<<" ("<<DNSRecordContent::NumberToType(rrc.d_type)<<")";
489 }
bb0bbee2
KM
490 ret = ttl.insert(pair<string, unsigned int>(toLower(content.str()), rr.ttl));
491 if (ret.second == false && ret.first->second != rr.ttl) {
492 cout<<"[Error] TTL mismatch in rrset: '"<<rr.qname<<" IN " <<rr.qtype.getName()<<" "<<rr.content<<"' ("<<ret.first->second<<" != "<<rr.ttl<<")"<<endl;
f1b672ae
KM
493 numerrors++;
494 continue;
495 }
496
1e2e9565
KM
497 if(pdns_iequals(rr.qname, zone)) {
498 if (rr.qtype.getCode() == QType::NS) {
499 hasNsAtApex=true;
500 } else if (rr.qtype.getCode() == QType::DS) {
06843d91 501 cout<<"[Warning] DS at apex in zone '"<<zone<<"', should not be here."<<endl;
1e2e9565
KM
502 numwarnings++;
503 }
504 } else {
505 if (rr.qtype.getCode() == QType::SOA) {
506 cout<<"[Error] SOA record not at apex '"<<rr.qname<<" IN "<<rr.qtype.getName()<<" "<<rr.content<<"' in zone '"<<zone<<"'"<<endl;
507 numerrors++;
508 continue;
509 } else if (rr.qtype.getCode() == QType::DNSKEY) {
510 cout<<"[Warning] DNSKEY record not at apex '"<<rr.qname<<" IN "<<rr.qtype.getName()<<" "<<rr.content<<"' in zone '"<<zone<<"', should not be here."<<endl;
511 numwarnings++;
512 }
513 }
514
61717a51 515 if (rr.qtype.getCode() == QType::CNAME) {
bb0bbee2
KM
516 if (!cnames.count(toLower(rr.qname)))
517 cnames.insert(toLower(rr.qname));
c90d822b 518 else {
bb0bbee2 519 cout<<"[Error] Duplicate CNAME found at '"<<rr.qname<<"'"<<endl;
ca57aa98
KM
520 numerrors++;
521 continue;
522 }
c90d822b
KM
523 } else {
524 if (rr.qtype.getCode() == QType::RRSIG) {
3aa5b00f 525 if(!presigned) {
c90d822b
KM
526 cout<<"[Error] RRSIG found at '"<<rr.qname<<"' in non-presigned zone. These do not belong in the database."<<endl;
527 numerrors++;
befcd641 528 continue;
c90d822b
KM
529 }
530 } else
bb0bbee2 531 noncnames.insert(toLower(rr.qname));
61717a51
PD
532 }
533
0aabca97
PD
534 if(rr.qtype.getCode() == QType::NSEC || rr.qtype.getCode() == QType::NSEC3)
535 {
536 cout<<"[Error] NSEC or NSEC3 found at '"<<rr.qname<<"'. These do not belong in the database."<<endl;
537 numerrors++;
538 continue;
539 }
540
0a0f82c8 541 if(!presigned && rr.qtype.getCode() == QType::DNSKEY)
12a92688 542 {
cc8df07f 543 if(::arg().mustDo("direct-dnskey"))
12a92688 544 {
0a0f82c8 545 if(rr.ttl != sd.default_ttl)
12a92688 546 {
0a0f82c8 547 cout<<"[Warning] DNSKEY TTL of "<<rr.ttl<<" at '"<<rr.qname<<"' differs from SOA minimum of "<<sd.default_ttl<<endl;
c90d822b 548 numwarnings++;
12a92688
PD
549 }
550 }
0a0f82c8
KM
551 else
552 {
553 cout<<"[Warning] DNSKEY at '"<<rr.qname<<"' in non-presigned zone will mostly be ignored and can cause problems."<<endl;
554 numwarnings++;
555 }
12a92688
PD
556 }
557
8c949c52
PD
558 if (rr.qname[rr.qname.size()-1] == '.') {
559 cout<<"[Error] Record '"<<rr.qname<<"' has a trailing dot. PowerDNS will ignore this record!"<<endl;
560 numerrors++;
561 }
bb0bbee2 562
ef1c4bf0 563 if ( (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::SRV || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::CNAME) &&
8c949c52
PD
564 rr.content[rr.content.size()-1] == '.') {
565 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;
566 numwarnings++;
567 }
568
27045410 569 if(rr.auth == 0 && rr.qtype.getCode()!=QType::NS && rr.qtype.getCode()!=QType::A && rr.qtype.getCode()!=QType::AAAA)
7ddd79a7 570 {
8c949c52 571 cout<<"[Error] Following record is auth=0, run pdnssec rectify-zone?: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
5e42374c 572 numerrors++;
7ddd79a7 573 }
035297ad 574 }
61717a51
PD
575
576 for(set<string>::const_iterator i = cnames.begin(); i != cnames.end(); i++) {
577 if (noncnames.find(*i) != noncnames.end()) {
578 cout<<"[Error] CNAME "<<*i<<" found, but other records with same label exist."<<endl;
579 numerrors++;
580 }
581 }
582
1e2e9565
KM
583 if(!hasNsAtApex) {
584 cout<<"[Error] No NS record at zone apex in zone '"<<zone<<"'"<<endl;
585 numerrors++;
586 }
587
8c949c52 588 cout<<"Checked "<<numrecords<<" records of '"<<zone<<"', "<<numerrors<<" errors, "<<numwarnings<<" warnings."<<endl;
0ae6a6cc 589 return numerrors;
5d2e58b0
BH
590}
591
12a92688 592int checkAllZones(DNSSECKeeper &dk)
1325e8a2 593{
ba86110a 594 UeberBackend B("default");
1325e8a2
PD
595 vector<DomainInfo> domainInfo;
596
fdc0adaf 597 B.getAllDomains(&domainInfo, true);
1325e8a2
PD
598 int errors=0;
599 BOOST_FOREACH(DomainInfo di, domainInfo) {
ba86110a 600 if (checkZone(dk, B, di.zone) > 0)
1325e8a2 601 errors++;
1325e8a2
PD
602 }
603 cout<<"Checked "<<domainInfo.size()<<" zones, "<<errors<<" had errors."<<endl;
604 return 0;
605}
606
04576eed
RA
607int increaseSerial(const string& zone, DNSSECKeeper &dk)
608{
609 UeberBackend B("default");
610 SOAData sd;
79ba7763 611 if(!B.getSOAUncached(zone, sd)) {
04576eed
RA
612 cout<<"No SOA for zone '"<<zone<<"'"<<endl;
613 return -1;
614 }
615
616 string soaEditKind;
617 dk.getFromMeta(zone, "SOA-EDIT", soaEditKind);
618
619 sd.db->lookup(QType(QType::SOA), zone);
620 vector<DNSResourceRecord> rrs;
621 DNSResourceRecord rr;
622 while (sd.db->get(rr)) {
623 if (rr.qtype.getCode() == QType::SOA)
624 rrs.push_back(rr);
625 }
626
627 if (rrs.size() > 1) {
628 cerr<<rrs.size()<<" SOA records found for "<<zone<<"!"<<endl;
629 return -1;
630 }
631 if (rrs.size() < 1) {
632 cerr<<zone<<" not found!"<<endl;
633 }
634
63347c6c 635 if (soaEditKind.empty()) {
04576eed 636 sd.serial++;
63347c6c
SB
637 }
638 else if(pdns_iequals(soaEditKind,"INCREMENT-WEEKS")) {
639 sd.serial++;
640 }
641 else if(pdns_iequals(soaEditKind,"INCEPTION-INCREMENT")) {
642 uint32_t today_serial = localtime_format_YYYYMMDDSS(time(NULL), 1);
643
644 if (sd.serial < today_serial) {
645 sd.serial = today_serial;
646 }
647 else {
648 sd.serial++;
649 }
650 }
651 else {
9f44333a 652 sd.serial = calculateEditSOA(sd, soaEditKind) + 1;
63347c6c 653 }
04576eed
RA
654 rrs[0].content = serializeSOAData(sd);
655
0881012f
AT
656 sd.db->startTransaction("", -1);
657
04576eed 658 if (! sd.db->replaceRRSet(sd.domain_id, zone, rr.qtype, rrs)) {
0881012f 659 sd.db->abortTransaction();
04576eed
RA
660 cerr<<"Backend did not replace SOA record. Backend might not support this operation."<<endl;
661 return -1;
662 }
481350e4
AT
663
664 if (sd.db->doesDNSSEC()) {
665 NSEC3PARAMRecordContent ns3pr;
666 bool narrow;
667 bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
668
669 if(haveNSEC3)
670 {
671 if(!narrow) {
672 string hashed=toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rrs[0].qname));
673 if(g_verbose)
674 cerr<<"'"<<rrs[0].qname<<"' -> '"<< hashed <<"'"<<endl;
675 sd.db->updateDNSSECOrderAndAuthAbsolute(sd.domain_id, rrs[0].qname, hashed, 1);
676 }
677 else {
678 sd.db->nullifyDNSSECOrderNameAndUpdateAuth(sd.domain_id, rrs[0].qname, 1);
679 }
680 } else {
681 sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, rrs[0].qname, 1);
682 }
683 }
684
0881012f
AT
685 sd.db->commitTransaction();
686
04576eed
RA
687 cout<<"SOA serial for zone "<<zone<<" set to "<<sd.serial<<endl;
688 return 0;
689}
690
51f6bca1
RA
691int deleteZone(const string &zone) {
692 UeberBackend B;
693 DomainInfo di;
694 if (! B.getDomainInfo(zone, di)) {
cad297e6 695 cerr<<"Domain '"<<zone<<"' not found!"<<endl;
51f6bca1
RA
696 return 1;
697 }
698
699 if(di.backend->deleteDomain(zone))
700 return 0;
701
702 cerr<<"Failed to delete domain '"+zone+"'"<<endl;;
703 return 1;
704}
705
c9865bc5 706int listZone(const string &zone) {
707 UeberBackend B;
708 DomainInfo di;
709
710 if (! B.getDomainInfo(zone, di)) {
711 cerr<<"Domain '"<<zone<<"' not found!"<<endl;
712 return 1;
713 }
714 di.backend->list(zone, di.id);
715 DNSResourceRecord rr;
716 while(di.backend->get(rr)) {
717 if(rr.qtype.getCode()) {
718 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] != '.')
719 rr.content.append(1, '.');
720
721 cout<<rr.qname<<".\t"<<rr.ttl<<"\tIN\t"<<rr.qtype.getName()<<"\t"<<rr.content<<endl;
722 }
723 }
724 return 0;
725}
726
727int loadZone(string zone, const string& fname) {
728 UeberBackend B;
729 DomainInfo di;
730
731 if (B.getDomainInfo(zone, di)) {
732 cerr<<"Domain '"<<zone<<"' exists already, replacing contents"<<endl;
733 }
734 else {
735 cerr<<"Creating '"<<zone<<"'"<<endl;
736 B.createDomain(zone);
737
738 if(!B.getDomainInfo(zone, di)) {
739 cerr<<"Domain '"<<zone<<"' was not created!"<<endl;
740 return 1;
741 }
742 }
743 DNSBackend* db = di.backend;
744 ZoneParserTNG zpt(fname, zone);
745
746 DNSResourceRecord rr;
747 if(!db->startTransaction(zone, di.id)) {
748 cerr<<"Unable to start transaction for load of zone '"<<zone<<"'"<<endl;
749 return 1;
750 }
751 rr.domain_id=di.id;
752 while(zpt.get(rr)) {
753 if(!endsOn(stripDot(rr.qname), zone) && rr.qname!=zone) {
754 cerr<<"File contains record named '"<<rr.qname<<"' which is not part of zone '"<<zone<<"'"<<endl;
755 return 1;
756 }
757 rr.qname=stripDot(rr.qname);
758 db->feedRecord(rr);
759 }
760 db->commitTransaction();
761 return 0;
762}
763
764int createZone(const string &zone) {
765 UeberBackend B;
766 DomainInfo di;
767 if (B.getDomainInfo(zone, di)) {
768 cerr<<"Domain '"<<zone<<"' exists already"<<endl;
769 return 1;
770 }
771 cerr<<"Creating '"<<zone<<"'"<<endl;
772 B.createDomain(zone);
773
774 if(!B.getDomainInfo(zone, di)) {
775 cerr<<"Domain '"<<zone<<"' was not created!"<<endl;
776 return 1;
777 }
778 return 1;
779}
780
781
22c68348 782int listAllZones(const string &type="") {
bd108049
RA
783
784 int kindFilter = -1;
785 if (type.size()) {
786 if (toUpper(type) == "MASTER")
787 kindFilter = 0;
788 else if (toUpper(type) == "SLAVE")
789 kindFilter = 1;
790 else if (toUpper(type) == "NATIVE")
791 kindFilter = 2;
22c68348
KM
792 else {
793 cerr<<"Syntax: pdnssec list-all-zones [master|slave|native]"<<endl;
794 return 1;
795 }
bd108049
RA
796 }
797
8ecfea3a 798 UeberBackend B("default");
bd108049 799
8ecfea3a
KM
800 vector<DomainInfo> domains;
801 B.getAllDomains(&domains);
802
803 int count = 0;
bd108049
RA
804 for (vector<DomainInfo>::const_iterator di=domains.begin(); di != domains.end(); di++) {
805 if (di->kind == kindFilter || kindFilter == -1) {
806 cout<<di->zone<<endl;
807 count++;
808 }
809 }
810
811 if (kindFilter != -1)
812 cout<<type<<" zonecount:"<<count<<endl;
813 else
814 cout<<"All zonecount:"<<count<<endl;
815 return 0;
816}
817
cbb0025b
PD
818void testAlgorithm(int algo)
819{
820 DNSCryptoKeyEngine::testOne(algo);
821}
1325e8a2 822
189bb9d2
BH
823void testAlgorithms()
824{
825 DNSCryptoKeyEngine::testAll();
826}
827
49449751 828void testSpeed(DNSSECKeeper& dk, const string& zone, const string& remote, int cores)
ea937fd4
BH
829{
830 DNSResourceRecord rr;
831 rr.qname="blah."+zone;
832 rr.qtype=QType::A;
833 rr.ttl=3600;
834 rr.auth=1;
703761cc 835 rr.qclass = QClass::IN;
ea937fd4 836 rr.d_place=DNSResourceRecord::ANSWER;
ea937fd4 837
49449751 838 UeberBackend db("key-only");
ea937fd4 839
f0c4b9d5
PD
840 if ( ! db.backends.size() )
841 {
842 throw runtime_error("No backends available for DNSSEC key storage");
843 }
844
49449751 845 ChunkedSigningPipe csp(zone, 1, remote, cores);
ea937fd4
BH
846
847 vector<DNSResourceRecord> signatures;
848 uint32_t rnd;
849 unsigned char* octets = (unsigned char*)&rnd;
850 char tmp[25];
851 DTime dt;
852 dt.set();
853 for(unsigned int n=0; n < 100000; ++n) {
854 rnd = random();
855 snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
856 octets[0], octets[1], octets[2], octets[3]);
857 rr.content=tmp;
858
859 snprintf(tmp, sizeof(tmp), "r-%u", rnd);
860 rr.qname=string(tmp)+"."+zone;
861
862 if(csp.submit(rr))
863 while(signatures = csp.getChunk(), !signatures.empty())
864 ;
865 }
866 cerr<<"Flushing the pipe, "<<csp.d_signed<<" signed, "<<csp.d_queued<<" queued, "<<csp.d_outstanding<<" outstanding"<< endl;
451ba512 867 cerr<<"Net speed: "<<csp.d_signed/ (dt.udiffNoReset()/1000000.0) << " sigs/s"<<endl;
ea937fd4
BH
868 while(signatures = csp.getChunk(true), !signatures.empty())
869 ;
870 cerr<<"Done, "<<csp.d_signed<<" signed, "<<csp.d_queued<<" queued, "<<csp.d_outstanding<<" outstanding"<< endl;
451ba512 871 cerr<<"Net speed: "<<csp.d_signed/ (dt.udiff()/1000000.0) << " sigs/s"<<endl;
ea937fd4
BH
872}
873
aa65a832
BH
874void verifyCrypto(const string& zone)
875{
876 ZoneParserTNG zpt(zone);
877 DNSResourceRecord rr;
878 DNSKEYRecordContent drc;
879 RRSIGRecordContent rrc;
c3e26094 880 DSRecordContent dsrc;
aa65a832 881 vector<shared_ptr<DNSRecordContent> > toSign;
c3e26094
BH
882 string qname, apex;
883 dsrc.d_digesttype=0;
aa65a832
BH
884 while(zpt.get(rr)) {
885 if(rr.qtype.getCode() == QType::DNSKEY) {
886 cerr<<"got DNSKEY!"<<endl;
c3e26094 887 apex=rr.qname;
aa65a832
BH
888 drc = *dynamic_cast<DNSKEYRecordContent*>(DNSRecordContent::mastermake(QType::DNSKEY, 1, rr.content));
889 }
890 else if(rr.qtype.getCode() == QType::RRSIG) {
891 cerr<<"got RRSIG"<<endl;
892 rrc = *dynamic_cast<RRSIGRecordContent*>(DNSRecordContent::mastermake(QType::RRSIG, 1, rr.content));
893 }
c3e26094
BH
894 else if(rr.qtype.getCode() == QType::DS) {
895 cerr<<"got DS"<<endl;
896 dsrc = *dynamic_cast<DSRecordContent*>(DNSRecordContent::mastermake(QType::DS, 1, rr.content));
897 }
aa65a832
BH
898 else {
899 qname = rr.qname;
aa65a832
BH
900 toSign.push_back(shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)));
901 }
902 }
c3e26094 903
f309dacd 904 string msg = getMessageForRRSET(qname, rrc, toSign);
49449751 905 cerr<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc.d_algorithm, drc.d_key)->verify(msg, rrc.d_signature)<<endl;
c3e26094
BH
906 if(dsrc.d_digesttype) {
907 cerr<<"Calculated DS: "<<apex<<" IN DS "<<makeDSFromDNSKey(apex, drc, dsrc.d_digesttype).getZoneRepresentation()<<endl;
908 cerr<<"Original DS: "<<apex<<" IN DS "<<dsrc.getZoneRepresentation()<<endl;
909 }
295812a1 910#if 0
8d9f38f2 911 DNSCryptoKeyEngine*key=DNSCryptoKeyEngine::makeFromISCString(drc, "Private-key-format: v1.2\n"
295812a1
BH
912 "Algorithm: 12 (ECC-GOST)\n"
913 "GostAsn1: MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgQg/9MiXtXKg9FDXDN/R9CmVhJDyuzRAIgh4tPwCu4NHIs=\n");
914 string resign=key->sign(hash);
915 cerr<<Base64Encode(resign)<<endl;
8d9f38f2 916 cerr<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc.d_algorithm, drc.d_key)->verify(hash, resign)<<endl;
295812a1
BH
917#endif
918
aa65a832 919}
032e3906 920bool disableDNSSECOnZone(DNSSECKeeper& dk, const string& zone)
5935cede 921{
032e3906
PD
922 UeberBackend B("default");
923 DomainInfo di;
924
925 if (!B.getDomainInfo(zone, di)){
926 cerr << "No such zone in the database" << endl;
927 return false;
928 }
929
5935cede 930 if(!dk.isSecuredZone(zone)) {
451ba512 931 cerr<<"Zone is not secured"<<endl;
032e3906 932 return false;
5935cede
BH
933 }
934 DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
aa65a832 935
5935cede
BH
936 if(keyset.empty()) {
937 cerr << "No keys for zone '"<<zone<<"'."<<endl;
938 }
939 else {
940 BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
941 dk.deactivateKey(zone, value.second.id);
37fd8771 942 dk.removeKey(zone, value.second.id);
5935cede
BH
943 }
944 }
945 dk.unsetNSEC3PARAM(zone);
946 dk.unsetPresigned(zone);
032e3906 947 return true;
5935cede 948}
032e3906 949bool showZone(DNSSECKeeper& dk, const std::string& zone)
ade1b1e9 950{
032e3906
PD
951 UeberBackend B("default");
952 DomainInfo di;
4831df57 953 std::vector<std::string> meta;
032e3906
PD
954
955 if (!B.getDomainInfo(zone, di)){
956 cerr << "No such zone in the database" << endl;
957 return false;
958 }
959
d3e7090c 960 if(!dk.isSecuredZone(zone)) {
451ba512 961 cerr<<"Zone is not actively secured"<<endl;
d3e7090c 962 }
ade1b1e9
BH
963 NSEC3PARAMRecordContent ns3pr;
964 bool narrow;
3c873e66 965 bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
ade1b1e9 966
d4a4176d 967 DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
4831df57
AT
968 if (B.getDomainMetadata(zone, "TSIG-ALLOW-AXFR", meta) && meta.size() > 0) {
969 cerr << "Zone has following allowed TSIG key(s): " << boost::join(meta, ",") << endl;
970 }
971
a56bc64d 972 meta.clear();
4831df57
AT
973 if (B.getDomainMetadata(zone, "AXFR-MASTER-TSIG", meta) && meta.size() > 0) {
974 cerr << "Zone uses following TSIG key(s): " << boost::join(meta, ",") << endl;
975 }
d3e7090c 976
451ba512 977 cout <<"Zone is " << (dk.isPresigned(zone) ? "" : "not ") << "presigned"<<endl;
ade1b1e9
BH
978
979 if(keyset.empty()) {
980 cerr << "No keys for zone '"<<zone<<"'."<<endl;
981 }
982 else {
d4a4176d
BH
983 if(!haveNSEC3)
984 cout<<"Zone has NSEC semantics"<<endl;
985 else
986 cout<<"Zone has " << (narrow ? "NARROW " : "") <<"hashed NSEC3 semantics, configuration: "<<ns3pr.getZoneRepresentation()<<endl;
987
ade1b1e9
BH
988 cout << "keys: "<<endl;
989 BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
e0ad7bb1
PD
990 string algname;
991 algorithm2name(value.first.d_algorithm, algname);
ade1b1e9 992 cout<<"ID = "<<value.second.id<<" ("<<(value.second.keyOrZone ? "KSK" : "ZSK")<<"), tag = "<<value.first.getDNSKEY().getTag();
ca2eb011 993 cout<<", algo = "<<(int)value.first.d_algorithm<<", bits = "<<value.first.getKey()->getBits()<<"\tActive: "<<value.second.active<< " ( " + algname + " ) "<<endl;
b8bd119e 994 if(value.second.keyOrZone || ::arg().mustDo("direct-dnskey") || g_verbose)
ca2eb011 995 cout<<(value.second.keyOrZone ? "KSK" : "ZSK")<<" DNSKEY = "<<zone<<" IN DNSKEY "<< value.first.getDNSKEY().getZoneRepresentation() << " ; ( " + algname + " )" << endl;
b8bd119e 996 if(value.second.keyOrZone || g_verbose) {
e0ad7bb1
PD
997 cout<<"DS = "<<zone<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 1).getZoneRepresentation() << " ; ( SHA1 digest )" << endl;
998 cout<<"DS = "<<zone<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 2).getZoneRepresentation() << " ; ( SHA256 digest )" << endl;
608d776f
BH
999 try {
1000 string output=makeDSFromDNSKey(zone, value.first.getDNSKEY(), 3).getZoneRepresentation();
e0ad7bb1
PD
1001 cout<<"DS = "<<zone<<" IN DS "<< output << " ; ( GOST R 34.11-94 digest )" << endl;
1002 }
1003 catch(...)
1004 {
1005 }
1006 try {
1007 string output=makeDSFromDNSKey(zone, value.first.getDNSKEY(), 4).getZoneRepresentation();
1008 cout<<"DS = "<<zone<<" IN DS "<< output << " ; ( SHA-384 digest )" << endl;
608d776f
BH
1009 }
1010 catch(...)
1011 {
1012 }
1013 cout<<endl;
ade1b1e9
BH
1014 }
1015 }
1016 }
032e3906 1017 return true;
ade1b1e9 1018}
5d2e58b0 1019
d6c16697 1020bool secureZone(DNSSECKeeper& dk, const std::string& zone)
ddac7145 1021{
36758d25
PD
1022 // parse attribute
1023 vector<string> k_algos;
1024 vector<string> z_algos;
1025 int k_size;
1026 int z_size;
1027
1028 stringtok(k_algos, ::arg()["default-ksk-algorithms"], " ,");
1029 k_size = ::arg().asNum("default-ksk-size");
1030 stringtok(z_algos, ::arg()["default-zsk-algorithms"], " ,");
1031 z_size = ::arg().asNum("default-zsk-size");
1032
1033 if (k_size < 0) {
1034 throw runtime_error("KSK key size must be equal to or greater than 0");
1035 }
1036
1037 if (k_algos.size() < 1) {
1038 throw runtime_error("No algorithm(s) given for KSK");
1039 }
1040
1041 if (z_size < 0) {
1042 throw runtime_error("ZSK key size must be equal to or greater than 0");
1043 }
1044
1045 if (z_algos.size() < 1) {
1046 throw runtime_error("No algorithm(s) given for ZSK");
1047 }
1048
f60f4bcd
BH
1049 if(dk.isSecuredZone(zone)) {
1050 cerr << "Zone '"<<zone<<"' already secure, remove keys with pdnssec remove-zone-key if needed"<<endl;
1051 return false;
1052 }
1053
2402c558
BH
1054 DomainInfo di;
1055 UeberBackend B("default");
1056 if(!B.getDomainInfo(zone, di) || !di.backend) { // di.backend and B are mostly identical
1057 cout<<"Can't find a zone called '"<<zone<<"'"<<endl;
1058 return false;
1059 }
1060
3bf07122
PD
1061 if(di.kind == DomainInfo::Slave)
1062 {
1063 cout<<"Warning! This is a slave domain! If this was a mistake, please run"<<endl;
1064 cout<<"pdnssec disable-dnssec "<<zone<<" right now!"<<endl;
1065 }
1066
36758d25
PD
1067 if (k_size)
1068 cout << "Securing zone with " << k_algos[0] << " algorithm with key size " << k_size << endl;
1069 else
1070 cout << "Securing zone with " << k_algos[0] << " algorithm with default key size" << endl;
1071
1072 // run secure-zone with first default algorith, then add keys
1073 if(!dk.secureZone(zone, shorthand2algorithm(k_algos[0]), k_size)) {
451ba512
AT
1074 cerr<<"No backend was able to secure '"<<zone<<"', most likely because no DNSSEC"<<endl;
1075 cerr<<"capable backends are loaded, or because the backends have DNSSEC disabled."<<endl;
1076 cerr<<"For the Generic SQL backends, set the 'gsqlite3-dnssec', 'gmysql-dnssec' or"<<endl;
1077 cerr<<"'gpgsql-dnssec' flag. Also make sure the schema has been updated for DNSSEC!"<<endl;
f60f4bcd
BH
1078 return false;
1079 }
1080
1081 if(!dk.isSecuredZone(zone)) {
451ba512
AT
1082 cerr<<"Failed to secure zone. Is your backend dnssec enabled? (set "<<endl;
1083 cerr<<"gsqlite3-dnssec, or gmysql-dnssec etc). Check this first."<<endl;
1084 cerr<<"If you run with the BIND backend, make sure you have configured"<<endl;
1085 cerr<<"it to use DNSSEC with 'bind-dnssec-db=/path/fname' and"<<endl;
1086 cerr<<"'pdnssec create-bind-db /path/fname'!"<<endl;
f60f4bcd
BH
1087 return false;
1088 }
1089
1090 DNSSECKeeper::keyset_t zskset=dk.getKeys(zone, false);
1091
1092 if(!zskset.empty()) {
1093 cerr<<"There were ZSKs already for zone '"<<zone<<"', no need to add more"<<endl;
1094 return false;
1095 }
36758d25
PD
1096
1097 for(vector<string>::iterator i = k_algos.begin()+1; i != k_algos.end(); i++)
07bf35d1 1098 dk.addKey(zone, true, shorthand2algorithm(*i), k_size, true); // obvious errors will have been caught above
36758d25
PD
1099
1100 BOOST_FOREACH(string z_algo, z_algos)
1101 {
1102 int algo = shorthand2algorithm(z_algo);
1103 dk.addKey(zone, false, algo, z_size);
36758d25
PD
1104 }
1105
f60f4bcd
BH
1106 // rectifyZone(dk, zone);
1107 // showZone(dk, zone);
1108 cout<<"Zone "<<zone<<" secured"<<endl;
d6c16697 1109 return true;
ddac7145
BH
1110}
1111
46d2e0d6
PD
1112void testSchema(DNSSECKeeper& dk, const std::string& zone)
1113{
1114 cout<<"Note: test-schema will try to create the zone, but it will not remove it."<<endl;
1115 cout<<"Please clean up after this."<<endl;
1116 cout<<endl;
1117 cout<<"Constructing UeberBackend"<<endl;
2402c558 1118 UeberBackend B("default");
46d2e0d6 1119 cout<<"Picking first backend - if this is not what you want, edit launch line!"<<endl;
2402c558 1120 DNSBackend *db = B.backends[0];
46d2e0d6 1121 cout<<"Creating slave domain "<<zone<<endl;
719f9024 1122 db->createSlaveDomain("127.0.0.1", zone, "", "_testschema");
46d2e0d6
PD
1123 cout<<"Slave domain created"<<endl;
1124
1125 DomainInfo di;
2402c558 1126 if(!B.getDomainInfo(zone, di) || !di.backend) { // di.backend and B are mostly identical
46d2e0d6
PD
1127 cout<<"Can't find domain we just created, aborting"<<endl;
1128 return;
1129 }
1130 db=di.backend;
1131 DNSResourceRecord rr, rrget;
1132 cout<<"Starting transaction to feed records"<<endl;
1133 db->startTransaction(zone, di.id);
1134
1135 rr.qtype=QType::SOA;
1136 rr.qname=zone;
1137 rr.ttl=86400;
1138 rr.domain_id=di.id;
1139 rr.auth=1;
1140 rr.content="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
1141 cout<<"Feeding SOA"<<endl;
1142 db->feedRecord(rr);
1143 rr.qtype=QType::TXT;
1144 // 300 As
1145 rr.content="\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"";
1146 cout<<"Feeding overlong TXT"<<endl;
1147 db->feedRecord(rr);
1148 cout<<"Committing"<<endl;
1149 db->commitTransaction();
1150 cout<<"Querying TXT"<<endl;
1151 db->lookup(QType(QType::TXT), zone, NULL, di.id);
1152 if(db->get(rrget))
1153 {
1154 DNSResourceRecord rrthrowaway;
1155 if(db->get(rrthrowaway)) // should not touch rr but don't assume anything
1156 {
1157 cout<<"Expected one record, got multiple, aborting"<<endl;
1158 return;
1159 }
1160 int size=rrget.content.size();
1161 if(size != 302)
1162 {
1163 cout<<"Expected 302 bytes, got "<<size<<", aborting"<<endl;
1164 return;
1165 }
1166 }
1167 cout<<"[+] content field is over 255 bytes"<<endl;
1168
1169 cout<<"Dropping all records, inserting SOA+2xA"<<endl;
1170 db->startTransaction(zone, di.id);
1171
1172 rr.qtype=QType::SOA;
1173 rr.qname=zone;
1174 rr.ttl=86400;
1175 rr.domain_id=di.id;
1176 rr.auth=1;
1177 rr.content="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
1178 cout<<"Feeding SOA"<<endl;
1179 db->feedRecord(rr);
1180
1181 rr.qtype=QType::A;
1182 rr.qname="_underscore."+zone;
1183 rr.content="127.0.0.1";
1184 db->feedRecord(rr);
1185
1186 rr.qname="bla."+zone;
1187 cout<<"Committing"<<endl;
1188 db->commitTransaction();
1189
1190 cout<<"Securing zone"<<endl;
1191 secureZone(dk, zone);
1192 cout<<"Rectifying zone"<<endl;
1193 rectifyZone(dk, zone);
1194 cout<<"Checking underscore ordering"<<endl;
1195 string before, after;
1196 db->getBeforeAndAfterNames(di.id, zone, "z."+zone, before, after);
1197 cout<<"got '"<<before<<"' < 'z."<<zone<<"' < '"<<after<<"'"<<endl;
1198 if(before != "_underscore."+zone)
1199 {
1200 cout<<"before is wrong, got '"<<before<<"', expected '_underscore."<<zone<<"', aborting"<<endl;
1201 return;
1202 }
1203 if(after != zone)
1204 {
1205 cout<<"after is wrong, got '"<<after<<"', expected '"<<zone<<"', aborting"<<endl;
1206 return;
1207 }
1208 cout<<"[+] ordername sorting is correct for names starting with _"<<endl;
1209 cout<<endl;
1210 cout<<"End of tests, please remove "<<zone<<" from domains+records"<<endl;
1211}
1212
1d211b1b 1213int main(int argc, char** argv)
20002664 1214try
2fa33bce 1215{
1d211b1b
BH
1216 po::options_description desc("Allowed options");
1217 desc.add_options()
1218 ("help,h", "produce help message")
b3ce3dec 1219 ("verbose,v", "be verbose")
1d211b1b 1220 ("force", "force an action")
aa952078 1221 ("config-name", po::value<string>()->default_value(""), "virtual configuration name")
7d9dcde0 1222 ("config-dir", po::value<string>()->default_value(SYSCONFDIR), "location of pdns.conf")
1d211b1b
BH
1223 ("commands", po::value<vector<string> >());
1224
1225 po::positional_options_description p;
1226 p.add("commands", -1);
1227 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), g_vm);
1228 po::notify(g_vm);
1229
1230 vector<string> cmds;
1231
1232 if(g_vm.count("commands"))
1233 cmds = g_vm["commands"].as<vector<string> >();
1234
b3ce3dec
BH
1235 g_verbose = g_vm.count("verbose");
1236
1d211b1b 1237 if(cmds.empty() || g_vm.count("help")) {
451ba512
AT
1238 cerr<<"Usage: \npdnssec [options] <command> [params ..]\n"<<endl;
1239 cerr<<"Commands:"<<endl;
da7f2896
AT
1240 cerr<<"activate-tsig-key ZONE NAME [master|slave]"<<endl;
1241 cerr<<" Enable TSIG key for a zone"<<endl;
451ba512
AT
1242 cerr<<"activate-zone-key ZONE KEY-ID Activate the key with key id KEY-ID in ZONE"<<endl;
1243 cerr<<"add-zone-key ZONE zsk|ksk [bits] [active|passive]"<<endl;
1244 cerr<<" [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384]"<<endl;
1245 cerr<<" Add a ZSK or KSK to zone and specify algo&bits"<<endl;
a0a6cb58 1246 cerr<<"bench-db [filename] Bench database backend with queries, one domain per line"<<endl;
451ba512
AT
1247 cerr<<"check-zone ZONE Check a zone for correctness"<<endl;
1248 cerr<<"check-all-zones Check all zones for correctness"<<endl;
ca8e1742 1249 cerr<<"create-bind-db FNAME Create DNSSEC db for BIND backend (bind-dnssec-db)"<<endl;
c9865bc5 1250 cerr<<"create-zone ZONE Create empty zone ZONE"<<endl;
fbcc99aa 1251 cerr<<"deactivate-tsig-key ZONE NAME [master|slave]"<<endl;
da7f2896 1252 cerr<<" Disable TSIG key for a zone"<<endl;
451ba512
AT
1253 cerr<<"deactivate-zone-key ZONE KEY-ID Deactivate the key with key id KEY-ID in ZONE"<<endl;
1254 cerr<<"delete-tsig-key NAME Delete TSIG key (warning! will not unmap key!)"<<endl;
17d89a3e 1255 cerr<<"delete-zone ZONE Delete the zone"<<endl;
451ba512 1256 cerr<<"disable-dnssec ZONE Deactivate all keys and unset PRESIGNED in ZONE"<<endl;
451ba512
AT
1257 cerr<<"export-zone-dnskey ZONE KEY-ID Export to stdout the public DNSKEY described"<<endl;
1258 cerr<<"export-zone-key ZONE KEY-ID Export to stdout the private key described"<<endl;
da7f2896 1259 cerr<<"generate-tsig-key NAME ALGORITHM Generate new TSIG key"<<endl;
451ba512
AT
1260 cerr<<"generate-zone-key zsk|ksk [algorithm] [bits]"<<endl;
1261 cerr<<" Generate a ZSK or KSK to stdout with specified algo&bits"<<endl;
61fbddee 1262 cerr<<"get-meta ZONE [kind kind ..] Get zone metadata. If no KIND given, lists all known"<<endl;
451ba512 1263 cerr<<"hash-zone-record ZONE RNAME Calculate the NSEC3 hash for RNAME in ZONE"<<endl;
3c12a7e9 1264#ifdef HAVE_P11KIT1
6b116a42 1265 cerr<<"hsm assign zone algorithm ksk|zsk module slot pin label"<<endl<<
3c12a7e9 1266 " Assign a hardware signing module to a ZONE"<<endl;
6b116a42 1267 cerr<<"hsm create-key zone key-id [bits] Create a key using hardware signing module for ZONE (use assign first)"<<endl;
70f0f8c4 1268 cerr<<" bits defaults to 2048"<<endl;
3c12a7e9 1269#endif
451ba512
AT
1270 cerr<<"increase-serial ZONE Increases the SOA-serial by 1. Uses SOA-EDIT"<<endl;
1271 cerr<<"import-tsig-key NAME ALGORITHM KEY Import TSIG key"<<endl;
ca8e1742 1272 cerr<<"import-zone-key ZONE FILE Import from a file a private key, ZSK or KSK"<<endl;
451ba512 1273 cerr<<" [active|passive][ksk|zsk] Defaults to KSK and active"<<endl;
c9865bc5 1274 cerr<<"load-zone ZONE FILE Load ZONE from FILE, possibly creating zone or atomically"<<endl;
1275 cerr<<" replacing contents"<<endl;
1276 cerr<<"list-zone ZONE List zone contents"<<endl;
cd76677f 1277 cerr<<"list-all-zones [master|slave|native]"<<endl;
c9865bc5 1278 cerr<<" List all zone names"<<endl;;
451ba512
AT
1279 cerr<<"list-tsig-keys List all TSIG keys"<<endl;
1280 cerr<<"rectify-zone ZONE [ZONE ..] Fix up DNSSEC fields (order, auth)"<<endl;
1281 cerr<<"rectify-all-zones Rectify all zones."<<endl;
1282 cerr<<"remove-zone-key ZONE KEY-ID Remove key with KEY-ID from ZONE"<<endl;
f84dba01 1283 cerr<<"secure-all-zones [increase-serial] Secure all zones without keys."<<endl;
451ba512
AT
1284 cerr<<"secure-zone ZONE [ZONE ..] Add KSK and two ZSKs"<<endl;
1285 cerr<<"set-nsec3 ZONE ['params' [narrow]] Enable NSEC3 with PARAMs. Optionally narrow"<<endl;
1286 cerr<<"set-presigned ZONE Use presigned RRSIGs from storage"<<endl;
61fbddee
AT
1287 cerr<<"set-meta ZONE KIND [value value ..]"<<endl;
1288 cerr<<" Set zone metadata, optionally providing a value. Empty clears meta."<<endl;
451ba512
AT
1289 cerr<<"show-zone ZONE Show DNSSEC (public) key details about a zone"<<endl;
1290 cerr<<"unset-nsec3 ZONE Switch back to NSEC"<<endl;
1291 cerr<<"unset-presigned ZONE No longer use presigned RRSIGs"<<endl;
1292 cerr<<"test-schema ZONE Test DB schema - will create ZONE"<<endl;
1d211b1b
BH
1293 cerr<<desc<<endl;
1294 return 0;
1295 }
ca8e1742 1296
cbb0025b 1297 if (cmds[0] == "test-algorithm") {
2551cc18
PD
1298 if(cmds.size() != 2) {
1299 cerr << "Syntax: pdnssec test-algorithm algonum"<<endl;
1300 return 0;
1301 }
cbb0025b
PD
1302 testAlgorithm(lexical_cast<int>(cmds[1]));
1303 return 0;
1304 }
1305
ea937fd4
BH
1306 if(cmds[0] == "test-algorithms") {
1307 testAlgorithms();
1308 return 0;
1309 }
1310
7d9dcde0 1311 loadMainConfig(g_vm["config-dir"].as<string>());
6dfa0aa0 1312 reportAllTypes();
b925384e 1313
2717b8b3 1314 if(cmds[0] == "create-bind-db") {
a2b0e9b5 1315#ifdef HAVE_SQLITE3
fbe72b7a
BH
1316 if(cmds.size() != 2) {
1317 cerr << "Syntax: pdnssec create-bind-db fname"<<endl;
1318 return 0;
1319 }
080f5d57 1320 try {
a2b0e9b5
KM
1321 SSQLite3 db(cmds[1], true); // create=ok
1322 vector<string> statements;
1323 stringtok(statements, sqlCreate, ";");
0f310932
AT
1324 BOOST_FOREACH(const string& statement, statements) {
1325 db.execute(statement);
1326 }
080f5d57 1327 }
a2b0e9b5
KM
1328 catch(SSqlException& se) {
1329 throw PDNSException("Error creating database in BIND backend: "+se.txtReason());
080f5d57
PD
1330 }
1331 return 0;
a2b0e9b5 1332#else
bd6c6334 1333 cerr<<"bind-dnssec-db requires building PowerDNS with SQLite3"<<endl;
a2b0e9b5
KM
1334 return 1;
1335#endif
2717b8b3 1336 }
9a798fb0 1337
fbe72b7a
BH
1338 DNSSECKeeper dk;
1339
46d2e0d6
PD
1340 if (cmds[0] == "test-schema") {
1341 if(cmds.size() != 2) {
1342 cerr << "Syntax: pdnssec test-schema ZONE"<<endl;
1343 return 0;
1344 }
1345 testSchema(dk, cmds[1]);
1346 return 0;
1347 }
fbe72b7a 1348 if(cmds[0] == "rectify-zone") {
d4904322
BH
1349 if(cmds.size() < 2) {
1350 cerr << "Syntax: pdnssec rectify-zone ZONE [ZONE..]"<<endl;
81b39e4b
BH
1351 return 0;
1352 }
032e3906 1353 unsigned int exitCode = 0;
d4904322 1354 for(unsigned int n = 1; n < cmds.size(); ++n)
032e3906
PD
1355 if (!rectifyZone(dk, cmds[n])) exitCode = 1;
1356 return exitCode;
20002664 1357 }
1325e8a2
PD
1358 else if (cmds[0] == "rectify-all-zones") {
1359 rectifyAllZones(dk);
1360 }
9abd98d3 1361 else if(cmds[0] == "check-zone") {
5d2e58b0 1362 if(cmds.size() != 2) {
37fd8771 1363 cerr << "Syntax: pdnssec check-zone ZONE"<<endl;
5d2e58b0
BH
1364 return 0;
1365 }
ba86110a
PD
1366 UeberBackend B("default");
1367 exit(checkZone(dk, B, cmds[1]));
5d2e58b0 1368 }
a0a6cb58 1369 else if(cmds[0] == "bench-db") {
1370 dbBench(cmds.size() > 1 ? cmds[1] : "");
1371 }
1325e8a2 1372 else if (cmds[0] == "check-all-zones") {
12a92688 1373 exit(checkAllZones(dk));
1325e8a2 1374 }
bd108049 1375 else if (cmds[0] == "list-all-zones") {
22c68348
KM
1376 if (cmds.size() > 2) {
1377 cerr << "Syntax: pdnssec list-all-zones [master|slave|native]"<<endl;
1378 return 0;
1379 }
1380 if (cmds.size() == 2)
1381 return listAllZones(cmds[1]);
1382 return listAllZones();
bd108049 1383 }
81e9ba89
PD
1384 else if (cmds[0] == "test-zone") {
1385 cerr << "Did you mean check-zone?"<<endl;
1386 return 0;
1387 }
1388 else if (cmds[0] == "test-all-zones") {
1389 cerr << "Did you mean check-all-zones?"<<endl;
1390 return 0;
1391 }
49449751
BH
1392#if 0
1393 else if(cmds[0] == "signing-server" )
1394 {
1395 signingServer();
1396 }
1397 else if(cmds[0] == "signing-slave")
1398 {
1399 launchSigningService(0);
1400 }
1401#endif
ea937fd4 1402 else if(cmds[0] == "test-speed") {
37fd8771
BH
1403 if(cmds.size() < 2) {
1404 cerr << "Syntax: pdnssec test-speed numcores [signing-server]"<<endl;
ea937fd4
BH
1405 return 0;
1406 }
49449751 1407 testSpeed(dk, cmds[1], (cmds.size() > 3) ? cmds[3] : "", atoi(cmds[2].c_str()));
189bb9d2 1408 }
aa65a832
BH
1409 else if(cmds[0] == "verify-crypto") {
1410 if(cmds.size() != 2) {
37fd8771 1411 cerr << "Syntax: pdnssec verify-crypto FILE"<<endl;
aa65a832
BH
1412 return 0;
1413 }
1414 verifyCrypto(cmds[1]);
1415 }
da11ed0e
BH
1416
1417 else if(cmds[0] == "show-zone") {
a0472099 1418 if(cmds.size() != 2) {
37fd8771 1419 cerr << "Syntax: pdnssec show-zone ZONE"<<endl;
a0472099
BH
1420 return 0;
1421 }
1d211b1b 1422 const string& zone=cmds[1];
032e3906 1423 if (!showZone(dk, zone)) return 1;
1d211b1b 1424 }
5935cede
BH
1425 else if(cmds[0] == "disable-dnssec") {
1426 if(cmds.size() != 2) {
37fd8771 1427 cerr << "Syntax: pdnssec disable-dnssec ZONE"<<endl;
5935cede
BH
1428 return 0;
1429 }
1430 const string& zone=cmds[1];
0b8e59ea
AT
1431 if(!disableDNSSECOnZone(dk, zone)) {
1432 cerr << "Cannot disable DNSSEC on " << zone << endl;
032e3906 1433 return 1;
0b8e59ea 1434 }
5935cede 1435 }
bed962b5 1436 else if(cmds[0] == "activate-zone-key") {
37fd8771
BH
1437 if(cmds.size() != 3) {
1438 cerr << "Syntax: pdnssec activate-zone-key ZONE KEY-ID"<<endl;
1439 return 0;
1440 }
bed962b5
BH
1441 const string& zone=cmds[1];
1442 unsigned int id=atoi(cmds[2].c_str());
77b909cc
PD
1443 if(!id)
1444 {
1445 cerr<<"Invalid KEY-ID"<<endl;
1446 return 1;
1447 }
a84a8203
PD
1448 if (!dk.activateKey(zone, id)) {
1449 cerr<<"Activation of key failed"<<endl;
1450 return 1;
1451 }
1452 return 0;
bed962b5
BH
1453 }
1454 else if(cmds[0] == "deactivate-zone-key") {
37fd8771
BH
1455 if(cmds.size() != 3) {
1456 cerr << "Syntax: pdnssec deactivate-zone-key ZONE KEY-ID"<<endl;
1457 return 0;
1458 }
bed962b5
BH
1459 const string& zone=cmds[1];
1460 unsigned int id=atoi(cmds[2].c_str());
77b909cc
PD
1461 if(!id)
1462 {
1463 cerr<<"Invalid KEY-ID"<<endl;
1464 return 1;
1465 }
a84a8203
PD
1466 if (!dk.deactivateKey(zone, id)) {
1467 cerr<<"Deactivation of key failed"<<endl;
1468 return 1;
1469 }
1470 return 0;
bed962b5
BH
1471 }
1472 else if(cmds[0] == "add-zone-key") {
37fd8771 1473 if(cmds.size() < 3 ) {
52690ba5 1474 cerr << "Syntax: pdnssec add-zone-key ZONE zsk|ksk [bits] [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384]"<<endl;
37fd8771
BH
1475 return 0;
1476 }
bed962b5 1477 const string& zone=cmds[1];
032e3906
PD
1478
1479 UeberBackend B("default");
1480 DomainInfo di;
1481
1482 if (!B.getDomainInfo(zone, di)){
1483 cerr << "No such zone in the database" << endl;
1484 return 0;
1485 }
1486
36c394e5
BH
1487 // need to get algorithm, bits & ksk or zsk from commandline
1488 bool keyOrZone=false;
36758d25 1489 int tmp_algo=0;
36c394e5 1490 int bits=0;
0ba8e0f1 1491 int algorithm=8;
4af49b80 1492 bool active=false;
36c394e5
BH
1493 for(unsigned int n=2; n < cmds.size(); ++n) {
1494 if(pdns_iequals(cmds[n], "zsk"))
1495 keyOrZone = false;
1496 else if(pdns_iequals(cmds[n], "ksk"))
1497 keyOrZone = true;
36758d25
PD
1498 else if((tmp_algo = shorthand2algorithm(cmds[n]))>0) {
1499 algorithm = tmp_algo;
4af49b80 1500 } else if(pdns_iequals(cmds[n], "active")) {
1501 active=true;
1502 } else if(pdns_iequals(cmds[n], "inactive") || pdns_iequals(cmds[n], "passive")) {
1503 active=false;
1504 } else if(atoi(cmds[n].c_str())) {
36c394e5 1505 bits = atoi(cmds[n].c_str());
4af49b80 1506 } else {
a254438f 1507 cerr<<"Unknown algorithm, key flag or size '"<<cmds[n]<<"'"<<endl;
07bf35d1 1508 exit(EXIT_FAILURE);;
36c394e5
BH
1509 }
1510 }
07bf35d1 1511 if(!dk.addKey(zone, keyOrZone, algorithm, bits, active)) {
1512 cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
1513 exit(1);
1514 }
1515 else {
1516 cerr<<"Added a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "<<algorithm<<", active="<<active<<endl;
1517 if(bits)
232f0877 1518 cerr<<"Requested specific key size of "<<bits<<" bits"<<endl;
07bf35d1 1519 }
bed962b5
BH
1520 }
1521 else if(cmds[0] == "remove-zone-key") {
471304cc 1522 if(cmds.size() < 3) {
48cb6e2a 1523 cerr<<"Syntax: pdnssec remove-zone-key ZONE KEY-ID"<<endl;
471304cc
BH
1524 return 0;
1525 }
bed962b5
BH
1526 const string& zone=cmds[1];
1527 unsigned int id=atoi(cmds[2].c_str());
a84a8203 1528 if (!dk.removeKey(zone, id)) {
0b8e59ea 1529 cerr<<"Cannot remove key " << id << " from " << zone <<endl;
a84a8203
PD
1530 return 1;
1531 }
1532 return 0;
bed962b5 1533 }
51f6bca1
RA
1534 else if(cmds[0] == "delete-zone") {
1535 if(cmds.size() != 2) {
1536 cerr<<"Syntax: pdnssec delete-zone ZONE"<<endl;
1537 return 0;
1538 }
1539 exit(deleteZone(cmds[1]));
1540 }
c9865bc5 1541 else if(cmds[0] == "create-zone") {
1542 if(cmds.size() != 2) {
1543 cerr<<"Syntax: pdnssec create-zone ZONE"<<endl;
1544 return 0;
1545 }
1546 exit(createZone(cmds[1]));
1547 }
1548 else if(cmds[0] == "list-zone") {
1549 if(cmds.size() != 2) {
1550 cerr<<"Syntax: pdnssec list-zone ZONE"<<endl;
1551 return 0;
1552 }
1553 if(cmds[1]==".")
1554 cmds[1].clear();
1555
1556 exit(listZone(cmds[1]));
1557 }
1558 else if(cmds[0] == "load-zone") {
1559 if(cmds.size() != 3) {
1560 cerr<<"Syntax: pdnssec load-zone ZONE FILENAME"<<endl;
1561 return 0;
1562 }
1563 if(cmds[1]==".")
1564 cmds[1].clear();
1565
1566 exit(loadZone(cmds[1], cmds[2]));
1567 }
c3c89361 1568 else if(cmds[0] == "secure-zone") {
ddac7145 1569 if(cmds.size() < 2) {
37fd8771 1570 cerr << "Syntax: pdnssec secure-zone ZONE"<<endl;
a9175ad6
BH
1571 return 0;
1572 }
d6c16697 1573 vector<string> mustRectify;
ddac7145 1574 dk.startTransaction();
1325e8a2 1575 unsigned int zoneErrors=0;
ddac7145 1576 for(unsigned int n = 1; n < cmds.size(); ++n) {
f60f4bcd
BH
1577 const string& zone=cmds[n];
1578 if(secureZone(dk, zone)) {
d6c16697 1579 mustRectify.push_back(zone);
1325e8a2
PD
1580 } else {
1581 zoneErrors++;
d6c16697 1582 }
f60f4bcd 1583 }
1d211b1b 1584
ddac7145 1585 dk.commitTransaction();
d6c16697
BH
1586 BOOST_FOREACH(string& zone, mustRectify)
1587 rectifyZone(dk, zone);
1325e8a2
PD
1588
1589 if (zoneErrors) {
1590 return 1;
1591 }
1592 return 0;
1d211b1b 1593 }
fa377773 1594 else if (cmds[0] == "secure-all-zones") {
f84dba01
KM
1595 if (cmds.size() >= 2 && !pdns_iequals(cmds[1], "increase-serial")) {
1596 cerr << "Syntax: pdnssec secure-all-zones [increase-serial]"<<endl;
1597 return 0;
1598 }
1599
fa377773
KM
1600 UeberBackend B("default");
1601
fa377773
KM
1602 vector<DomainInfo> domainInfo;
1603 B.getAllDomains(&domainInfo);
1604
f84dba01 1605 unsigned int zonesSecured=0, zoneErrors=0;
fa377773
KM
1606 BOOST_FOREACH(DomainInfo di, domainInfo) {
1607 if(!dk.isSecuredZone(di.zone)) {
1608 cout<<"Securing "<<di.zone<<": ";
f84dba01
KM
1609 if (secureZone(dk, di.zone)) {
1610 zonesSecured++;
1611 if (cmds.size() == 2) {
1612 if (!increaseSerial(di.zone, dk))
1613 continue;
1614 } else
1615 continue;
1616 }
1617 zoneErrors++;
fa377773
KM
1618 }
1619 }
fa377773 1620
f84dba01 1621 cout<<"Secured: "<<zonesSecured<<" zones. Errors: "<<zoneErrors<<endl;
fa377773
KM
1622
1623 if (zoneErrors) {
1624 return 1;
1625 }
1626 return 0;
1627 }
da11ed0e 1628 else if(cmds[0]=="set-nsec3") {
37fd8771
BH
1629 if(cmds.size() < 2) {
1630 cerr<<"Syntax: pdnssec set-nsec3 ZONE 'params' [narrow]"<<endl;
1631 return 0;
1632 }
b8adb30d 1633 string nsec3params = cmds.size() > 2 ? cmds[2] : "1 0 1 ab";
22c5aa60 1634 bool narrow = cmds.size() > 3 && cmds[3]=="narrow";
da11ed0e 1635 NSEC3PARAMRecordContent ns3pr(nsec3params);
775acd9e 1636
1637 string zone=cmds[1];
1638 if(!dk.isSecuredZone(zone)) {
1639 cerr<<"Zone '"<<zone<<"' is not secured, can't set NSEC3 parameters"<<endl;
1640 exit(EXIT_FAILURE);
1641 }
1642 dk.setNSEC3PARAM(zone, ns3pr, narrow);
1643
b8adb30d
KM
1644 if (!ns3pr.d_flags)
1645 cerr<<"NSEC3 set, please rectify-zone if your backend needs it"<<endl;
1646 else
1647 cerr<<"NSEC3 (opt-out) set, please rectify-zone if your backend needs it"<<endl;
da11ed0e 1648 }
d3e7090c 1649 else if(cmds[0]=="set-presigned") {
5935cede 1650 if(cmds.size() < 2) {
37fd8771
BH
1651 cerr<<"Syntax: pdnssec set-presigned ZONE"<<endl;
1652 return 0;
5935cede 1653 }
a84a8203 1654 if (! dk.setPresigned(cmds[1])) {
e15dce0c 1655 cerr << "Could not set presigned on for " << cmds[1] << endl;
a84a8203
PD
1656 return 1;
1657 }
1658 return 0;
d3e7090c
BH
1659 }
1660 else if(cmds[0]=="unset-presigned") {
37fd8771
BH
1661 if(cmds.size() < 2) {
1662 cerr<<"Syntax: pdnssec unset-presigned ZONE"<<endl;
f60f4bcd 1663 return 0;
37fd8771 1664 }
a84a8203 1665 if (! dk.unsetPresigned(cmds[1])) {
e15dce0c 1666 cerr << "Could not unset presigned on for " << cmds[1] << endl;
a84a8203
PD
1667 return 1;
1668 }
1669 return 0;
d3e7090c 1670 }
65c87942
BH
1671 else if(cmds[0]=="hash-zone-record") {
1672 if(cmds.size() < 3) {
37fd8771 1673 cerr<<"Syntax: pdnssec hash-zone-record ZONE RNAME"<<endl;
65c87942
BH
1674 return 0;
1675 }
1676 string& zone=cmds[1];
1677 string& record=cmds[2];
1678 NSEC3PARAMRecordContent ns3pr;
1679 bool narrow;
1680 if(!dk.getNSEC3PARAM(zone, &ns3pr, &narrow)) {
1681 cerr<<"The '"<<zone<<"' zone does not use NSEC3"<<endl;
1682 return 0;
1683 }
5e42374c 1684 if(narrow) {
65c87942
BH
1685 cerr<<"The '"<<zone<<"' zone uses narrow NSEC3, but calculating hash anyhow"<<endl;
1686 }
1687
1bad4190 1688 cout<<toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, record))<<endl;
65c87942 1689 }
da11ed0e 1690 else if(cmds[0]=="unset-nsec3") {
37fd8771
BH
1691 if(cmds.size() < 2) {
1692 cerr<<"Syntax: pdnssec unset-nsec3 ZONE"<<endl;
a84a8203 1693 return 0;
37fd8771 1694 }
a84a8203 1695 if ( ! dk.unsetNSEC3PARAM(cmds[1])) {
e15dce0c 1696 cerr<<"Cannot unset NSEC3 param for " << cmds[1] << endl;
a84a8203
PD
1697 return 1;
1698 }
1699 return 0;
da11ed0e
BH
1700 }
1701 else if(cmds[0]=="export-zone-key") {
7ddd79a7 1702 if(cmds.size() < 3) {
37fd8771 1703 cerr<<"Syntax: pdnssec export-zone-key ZONE KEY-ID"<<endl;
a84a8203 1704 return 0;
7ddd79a7
BH
1705 }
1706
da11ed0e
BH
1707 string zone=cmds[1];
1708 unsigned int id=atoi(cmds[2].c_str());
1709 DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
189bb9d2 1710 cout << dpk.getKey()->convertToISC() <<endl;
4496f66f 1711 }
04576eed
RA
1712 else if(cmds[0]=="increase-serial") {
1713 if (cmds.size() < 2) {
1714 cerr<<"Syntax: pdnssec increase-serial ZONE"<<endl;
1715 return 0;
1716 }
1717 return increaseSerial(cmds[1], dk);
1718 }
ed3f8559
BH
1719 else if(cmds[0]=="import-zone-key-pem") {
1720 if(cmds.size() < 4) {
4af49b80 1721 cerr<<"Syntax: pdnssec import-zone-key-pem ZONE FILE algorithm [ksk|zsk]"<<endl;
ed3f8559
BH
1722 exit(1);
1723 }
1724 string zone=cmds[1];
1725 string fname=cmds[2];
1726 string line;
1727 ifstream ifs(fname.c_str());
1728 string tmp, interim, raw;
1729 while(getline(ifs, line)) {
1730 if(line[0]=='-')
1731 continue;
1732 trim(line);
1733 interim += line;
1734 }
1735 B64Decode(interim, raw);
1736 DNSSECPrivateKey dpk;
699e6e37 1737 DNSKEYRecordContent drc;
8d9f38f2 1738 shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromPEMString(drc, raw));
699e6e37 1739 dpk.setKey(key);
ed3f8559
BH
1740
1741 dpk.d_algorithm = atoi(cmds[3].c_str());
1742
1743 if(dpk.d_algorithm == 7)
1744 dpk.d_algorithm = 5;
1745
1746 cerr<<(int)dpk.d_algorithm<<endl;
1747
1748 if(cmds.size() > 4) {
1749 if(pdns_iequals(cmds[4], "ZSK"))
1750 dpk.d_flags = 256;
1751 else if(pdns_iequals(cmds[4], "KSK"))
1752 dpk.d_flags = 257;
1753 else {
451ba512 1754 cerr<<"Unknown key flag '"<<cmds[4]<<"'"<<endl;
ed3f8559
BH
1755 exit(1);
1756 }
1757 }
1758 else
1759 dpk.d_flags = 257; // ksk
1760
07bf35d1 1761 if(!dk.addKey(zone, dpk)) {
1762 cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
1763 exit(1);
1764 }
ed3f8559
BH
1765
1766 }
976b6541 1767 else if(cmds[0]=="import-zone-key") {
d1eacbeb 1768 if(cmds.size() < 3) {
4af49b80 1769 cerr<<"Syntax: pdnssec import-zone-key ZONE FILE [ksk|zsk] [active|passive]"<<endl;
4496f66f
BH
1770 exit(1);
1771 }
976b6541
BH
1772 string zone=cmds[1];
1773 string fname=cmds[2];
1774 DNSSECPrivateKey dpk;
699e6e37 1775 DNSKEYRecordContent drc;
8d9f38f2 1776 shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromISCFile(drc, fname.c_str()));
699e6e37 1777 dpk.setKey(key);
7ddd79a7
BH
1778 dpk.d_algorithm = drc.d_algorithm;
1779
1780 if(dpk.d_algorithm == 7)
1781 dpk.d_algorithm = 5;
aa952078 1782
4af49b80 1783 dpk.d_flags = 257;
4cec6ac5 1784 bool active=true;
4af49b80 1785
1786 for(unsigned int n = 3; n < cmds.size(); ++n) {
1787 if(pdns_iequals(cmds[n], "ZSK"))
232f0877 1788 dpk.d_flags = 256;
4af49b80 1789 else if(pdns_iequals(cmds[n], "KSK"))
232f0877 1790 dpk.d_flags = 257;
4af49b80 1791 else if(pdns_iequals(cmds[n], "active"))
232f0877 1792 active = 1;
4af49b80 1793 else if(pdns_iequals(cmds[n], "passive") || pdns_iequals(cmds[n], "inactive"))
232f0877 1794 active = 0;
4af49b80 1795 else {
232f0877
CH
1796 cerr<<"Unknown key flag '"<<cmds[n]<<"'"<<endl;
1797 exit(1);
1798 }
aa952078 1799 }
07bf35d1 1800 if(!dk.addKey(zone, dpk, active)) {
1801 cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
1802 exit(1);
1803 }
976b6541 1804 }
da11ed0e 1805 else if(cmds[0]=="export-zone-dnskey") {
7ddd79a7 1806 if(cmds.size() < 3) {
37fd8771 1807 cerr<<"Syntax: pdnssec export-zone-dnskey ZONE KEY-ID"<<endl;
7ddd79a7
BH
1808 exit(1);
1809 }
1810
da11ed0e
BH
1811 string zone=cmds[1];
1812 unsigned int id=atoi(cmds[2].c_str());
1813 DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
1814 cout << zone<<" IN DNSKEY "<<dpk.getDNSKEY().getZoneRepresentation() <<endl;
f8b25763
BH
1815 if(dpk.d_flags == 257) {
1816 cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 1).getZoneRepresentation() << endl;
1817 cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 2).getZoneRepresentation() << endl;
1818 }
da11ed0e 1819 }
950bdddf
PD
1820 else if(cmds[0] == "generate-zone-key") {
1821 if(cmds.size() < 2 ) {
7e5b2860 1822 cerr << "Syntax: pdnssec generate-zone-key zsk|ksk [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384] [bits]"<<endl;
950bdddf
PD
1823 return 0;
1824 }
1825 // need to get algorithm, bits & ksk or zsk from commandline
1826 bool keyOrZone=false;
1827 int tmp_algo=0;
1828 int bits=0;
1829 int algorithm=8;
1830 for(unsigned int n=1; n < cmds.size(); ++n) {
1831 if(pdns_iequals(cmds[n], "zsk"))
1832 keyOrZone = false;
1833 else if(pdns_iequals(cmds[n], "ksk"))
1834 keyOrZone = true;
1835 else if((tmp_algo = shorthand2algorithm(cmds[n]))>0) {
1836 algorithm = tmp_algo;
1837 } else if(atoi(cmds[n].c_str()))
1838 bits = atoi(cmds[n].c_str());
1839 else {
1840 cerr<<"Unknown algorithm, key flag or size '"<<cmds[n]<<"'"<<endl;
1841 return 0;
1842 }
1843 }
1844 cerr<<"Generating a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "<<algorithm<<endl;
1845 if(bits)
1846 cerr<<"Requesting specific key size of "<<bits<<" bits"<<endl;
1847
1848 DNSSECPrivateKey dspk;
1849 shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(algorithm)); // defaults to RSA for now, could be smart w/algorithm! XXX FIXME
1850 if(!bits) {
1851 if(algorithm <= 10)
1852 bits = keyOrZone ? 2048 : 1024;
1853 else {
1854 if(algorithm == 12 || algorithm == 13 || algorithm == 250) // ECDSA, GOST, ED25519
1855 bits = 256;
1856 else if(algorithm == 14)
1857 bits = 384;
1858 else {
0f4b0d97 1859 throw runtime_error("Can't guess key size for algorithm "+lexical_cast<string>(algorithm));
950bdddf
PD
1860 }
1861 }
1862 }
1863 dpk->create(bits);
1864 dspk.setKey(dpk);
1865 dspk.d_algorithm = algorithm;
1866 dspk.d_flags = keyOrZone ? 257 : 256;
1867
1868 // print key to stdout
1869 cout << "Flags: " << dspk.d_flags << endl <<
1870 dspk.getKey()->convertToISC() << endl;
79b4ea54 1871 } else if (cmds[0]=="generate-tsig-key") {
6f872b78
AT
1872 if (cmds.size() < 3) {
1873 cerr << "Syntax: " << cmds[0] << " name (hmac-md5|hmac-sha1|hmac-sha224|hmac-sha256|hmac-sha384|hmac-sha512)" << endl;
1874 return 0;
1875 }
1876 string name = cmds[1];
1877 string algo = cmds[2];
1878 string key;
1879 char tmpkey[64];
1880
d885cea7 1881 size_t klen = 0;
6f872b78
AT
1882 if (algo == "hmac-md5") {
1883 klen = 32;
1884 } else if (algo == "hmac-sha1") {
1885 klen = 32;
1886 } else if (algo == "hmac-sha224") {
1887 klen = 32;
1888 } else if (algo == "hmac-sha256") {
1889 klen = 64;
1890 } else if (algo == "hmac-sha384") {
1891 klen = 64;
1892 } else if (algo == "hmac-sha512") {
1893 klen = 64;
d885cea7
AT
1894 } else {
1895 cerr << "Cannot generate key for " << algo << endl;
1896 return 1;
6f872b78
AT
1897 }
1898
7e5b2860 1899 cerr << "Generating new key with " << klen << " bytes (this can take a while)" << endl;
a56bc64d
AT
1900 seedRandom(::arg()["entropy-source"]);
1901 for(size_t i = 0; i < klen; i+=4) {
1902 *(unsigned int*)(tmpkey+i) = dns_random(0xffffffff);
1903 }
6f872b78
AT
1904 key = Base64Encode(std::string(tmpkey, klen));
1905
1906 UeberBackend B("default");
1907 if (B.setTSIGKey(name, algo, key)) {
1908 cout << "Create new TSIG key " << name << " " << algo << " " << key << endl;
1909 } else {
1910 cout << "Failure storing new TSIG key " << name << " " << algo << " " << key << endl;
1911 return 1;
1912 }
1913 return 0;
1914 } else if (cmds[0]=="import-tsig-key") {
1915 if (cmds.size() < 4) {
1916 cerr << "Syntax: " << cmds[0] << " name algorithm key" << endl;
1917 return 0;
1918 }
1919 string name = cmds[1];
1920 string algo = cmds[2];
1921 string key = cmds[3];
1922
1923 UeberBackend B("default");
1924 if (B.setTSIGKey(name, algo, key)) {
1925 cout << "Imported TSIG key " << name << " " << algo << endl;
1926 } else {
1927 cout << "Failure importing TSIG key " << name << " " << algo << endl;
1928 return 1;
1929 }
1930 return 0;
1931 } else if (cmds[0]=="delete-tsig-key") {
1932 if (cmds.size() < 2) {
1933 cerr << "Syntax: " << cmds[0] << " name" << endl;
1934 return 0;
1935 }
1936 string name = cmds[1];
6f872b78
AT
1937
1938 UeberBackend B("default");
1939 if (B.deleteTSIGKey(name)) {
1940 cout << "Deleted TSIG key " << name << endl;
1941 } else {
1942 cout << "Failure deleting TSIG key " << name << endl;
1943 return 1;
1944 }
1945 return 0;
1946 } else if (cmds[0]=="list-tsig-keys") {
1947 std::vector<struct TSIGKey> keys;
1948 UeberBackend B("default");
1949 if (B.getTSIGKeys(keys)) {
1950 BOOST_FOREACH(const struct TSIGKey &key, keys) {
1951 cout << key.name << " " << key.algorithm << " " << key.key << endl;
1952 }
1953 }
1954 return 0;
79b4ea54 1955 } else if (cmds[0]=="activate-tsig-key") {
4831df57
AT
1956 string metaKey;
1957 if (cmds.size() < 4) {
1958 cerr << "Syntax: " << cmds[0] << " zone name [master|slave]" << endl;
6f872b78
AT
1959 return 0;
1960 }
1961 string zname = cmds[1];
1962 string name = cmds[2];
4831df57
AT
1963 if (cmds[3] == "master")
1964 metaKey = "TSIG-ALLOW-AXFR";
1965 else if (cmds[3] == "slave")
1966 metaKey = "AXFR-MASTER-TSIG";
1967 else {
1968 cerr << "Invalid parameter '" << cmds[3] << "', expected master or slave" << endl;
1969 return 1;
1970 }
6f872b78
AT
1971 UeberBackend B("default");
1972 std::vector<std::string> meta;
4831df57 1973 if (!B.getDomainMetadata(zname, metaKey, meta)) {
6f872b78
AT
1974 cout << "Failure enabling TSIG key " << name << " for " << zname << endl;
1975 return 1;
1976 }
1977 bool found = false;
1978 BOOST_FOREACH(std::string tmpname, meta) {
1979 if (tmpname == name) { found = true; break; }
1980 }
1981 if (!found) meta.push_back(name);
4831df57 1982 if (B.setDomainMetadata(zname, metaKey, meta)) {
6f872b78
AT
1983 cout << "Enabled TSIG key " << name << " for " << zname << endl;
1984 } else {
1985 cout << "Failure enabling TSIG key " << name << " for " << zname << endl;
1986 return 1;
1987 }
1988 return 0;
79b4ea54 1989 } else if (cmds[0]=="deactivate-tsig-key") {
4831df57
AT
1990 string metaKey;
1991 if (cmds.size() < 4) {
1992 cerr << "Syntax: " << cmds[0] << " zone name [master|slave]" << endl;
6f872b78
AT
1993 return 0;
1994 }
1995 string zname = cmds[1];
1996 string name = cmds[2];
4831df57
AT
1997 if (cmds[3] == "master")
1998 metaKey = "TSIG-ALLOW-AXFR";
1999 else if (cmds[3] == "slave")
2000 metaKey = "AXFR-MASTER-TSIG";
2001 else {
2002 cerr << "Invalid parameter '" << cmds[3] << "', expected master or slave" << endl;
2003 return 1;
2004 }
6f872b78
AT
2005
2006 UeberBackend B("default");
2007 std::vector<std::string> meta;
4831df57 2008 if (!B.getDomainMetadata(zname, metaKey, meta)) {
6f872b78
AT
2009 cout << "Failure disabling TSIG key " << name << " for " << zname << endl;
2010 return 1;
2011 }
2012 std::vector<std::string>::iterator iter = meta.begin();
2013 for(;iter != meta.end(); iter++) if (*iter == name) break;
2014 if (iter != meta.end()) meta.erase(iter);
4831df57 2015 if (B.setDomainMetadata(zname, metaKey, meta)) {
6f872b78
AT
2016 cout << "Disabled TSIG key " << name << " for " << zname << endl;
2017 } else {
2018 cout << "Failure disabling TSIG key " << name << " for " << zname << endl;
2019 return 1;
2020 }
2021 return 0;
451ba512
AT
2022 } else if (cmds[0]=="get-meta") {
2023 UeberBackend B("default");
2024 if (cmds.size() < 2) {
2025 cerr << "Syntax: " << cmds[0] << " zone [kind kind ..]" << endl;
2026 return 1;
2027 }
2028 string zone = cmds[1];
2029 vector<string> keys;
2030 DomainInfo di;
2031
2032 if (!B.getDomainInfo(zone, di)) {
2033 cerr << "Invalid zone '" << zone << "'" << endl;
2034 return 1;
2035 }
2036
2037 if (cmds.size() > 2) {
2e050d2c
AT
2038 keys.assign(cmds.begin() + 2, cmds.end());
2039 std::cout << "Metadata for '" << zone << "'" << endl;
2040 BOOST_FOREACH(const string kind, keys) {
2041 vector<string> meta;
2042 meta.clear();
2043 if (B.getDomainMetadata(zone, kind, meta)) {
2044 cout << kind << " = " << boost::join(meta, ", ") << endl;
2045 }
2046 }
451ba512 2047 } else {
2e050d2c
AT
2048 std::map<std::string, std::vector<std::string> > meta;
2049 std::cout << "Metadata for '" << zone << "'" << endl;
2050 B.getAllDomainMetadata(zone, meta);
2051 for(std::map<std::string, std::vector<std::string> >::const_iterator each_meta = meta.begin(); each_meta != meta.end(); each_meta++) {
2052 cout << each_meta->first << " = " << boost::join(each_meta->second, ", ") << endl;
451ba512 2053 }
2e050d2c
AT
2054 }
2055 return 0;
2056
451ba512
AT
2057 } else if (cmds[0]=="set-meta") {
2058 UeberBackend B("default");
2059 if (cmds.size() < 3) {
2060 cerr << "Syntax: " << cmds[0] << " zone kind [value value ..]" << endl;
2061 return 1;
2062 }
2063 string zone = cmds[1];
2064 string kind = cmds[2];
2065 vector<string> meta(cmds.begin() + 3, cmds.end());
2066
2067 if (!B.setDomainMetadata(zone, kind, meta)) {
2068 cerr << "Unable to set meta for '" << zone << "'" << endl;
2069 return 1;
2070 } else {
2071 cout << "Set '" << zone << "' meta " << kind << " = " << boost::join(meta, ", ") << endl;
2072 }
8daea594 2073 } else if (cmds[0]=="hsm") {
3c12a7e9 2074#ifdef HAVE_P11KIT1
8daea594
AT
2075 UeberBackend B("default");
2076 if (cmds[1] == "assign") {
2077 DNSCryptoKeyEngine::storvector_t storvect;
2078 DomainInfo di;
829035c1
AT
2079
2080 if (cmds.size() < 9) {
2081 std::cout << "Usage: pdnssec hsm assign zone algorithm ksk|zsk module slot pin label" << std::endl;
2082 return 1;
2083 }
2084
8daea594 2085 string zone = cmds[2];
829035c1 2086
8daea594
AT
2087 // verify zone
2088 if (!B.getDomainInfo(zone, di)) {
2089 cerr << "Unable to assign module to unknown zone '" << zone << "'" << std::endl;
2090 return 1;
2091 }
2092
2093 int algorithm = shorthand2algorithm(cmds[3]);
829035c1 2094 int id;
8daea594
AT
2095 bool keyOrZone = (cmds[4] == "ksk" ? true : false);
2096 string module = cmds[5];
2097 string slot = cmds[6];
2098 string pin = cmds[7];
2099 string label = cmds[8];
2100
2101 std::ostringstream iscString;
2102 iscString << "Private-key-format: v1.2" << std::endl <<
2103 "Algorithm: " << algorithm << std::endl <<
2104 "Engine: " << module << std::endl <<
2105 "Slot: " << slot << std::endl <<
2106 "PIN: " << pin << std::endl <<
2107 "Label: " << label << std::endl;
2108
2109 DNSKEYRecordContent drc;
2110 DNSSECPrivateKey dpk;
2111 dpk.d_flags = (keyOrZone ? 257 : 256);
2112 dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(drc, iscString.str())));
829035c1
AT
2113
2114 if (!(id = dk.addKey(zone, dpk))) {
8daea594
AT
2115 cerr << "Unable to assign module slot to zone" << std::endl;
2116 return 1;
2117 }
2118
86c979f5
AT
2119 // figure out key id.
2120
2121 std::vector<DNSBackend::KeyData> keys;
2122
2123 B.getDomainKeys(zone, 0, keys);
2124
2125 // validate which one got the key...
2126 BOOST_FOREACH(DNSBackend::KeyData& kd, keys) {
2127 if (kd.content == iscString.str()) {
2128 // it's this one, I guess...
2129 id = kd.id;
2130 break;
2131 }
2132 }
2133
829035c1 2134 cerr << "Module " << module << " slot " << slot << " assigned to " << zone << " with key id " << id << endl;
86c979f5 2135
8daea594
AT
2136 return 0;
2137 } else if (cmds[1] == "create-key") {
70f0f8c4
AT
2138
2139 if (cmds.size() < 4) {
2140 cerr << "Usage: pdnssec hsm create-key zone key-id [bits]" << endl;
2141 return 1;
2142 }
8daea594
AT
2143 DomainInfo di;
2144 string zone = cmds[2];
2145 unsigned int id;
70f0f8c4 2146 int bits = 2048;
8daea594
AT
2147 // verify zone
2148 if (!B.getDomainInfo(zone, di)) {
2149 cerr << "Unable to create key for unknown zone '" << zone << "'" << std::endl;
2150 return 1;
2151 }
2152
2153 id = boost::lexical_cast<unsigned int>(cmds[3]);
2154 std::vector<DNSBackend::KeyData> keys;
2155 if (!B.getDomainKeys(zone, 0, keys)) {
2156 cerr << "No keys found for zone " << zone << std::endl;
2157 return 1;
2158 }
2159
2160 DNSCryptoKeyEngine *dke = NULL;
2161 // lookup correct key
2162 BOOST_FOREACH(DNSBackend::KeyData &kd, keys) {
2163 if (kd.id == id) {
2164 // found our key.
2165 DNSKEYRecordContent dkrc;
2166 dke = DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content);
2167 }
2168 }
2169
2170 if (!dke) {
2171 cerr << "Could not find key with ID " << id << endl;
2172 return 1;
2173 }
70f0f8c4
AT
2174 if (cmds.size() > 4) {
2175 bits = boost::lexical_cast<int>(cmds[4]);
2176 }
2177 if (bits < 1) {
2178 cerr << "Invalid bit size " << bits << "given, must be positive integer";
2179 return 1;
2180 }
829035c1 2181 try {
70f0f8c4
AT
2182 dke->create(bits);
2183 } catch (PDNSException& e) {
2184 cerr << e.reason << endl;
829035c1
AT
2185 return 1;
2186 }
8daea594 2187
70f0f8c4 2188 cerr << "Key of size " << bits << " created" << std::endl;
8daea594
AT
2189 return 0;
2190 }
3c12a7e9
AT
2191#else
2192 cerr<<"PKCS#11 support not enabled"<<endl;
2193 return 1;
2194#endif
451ba512 2195 } else {
5cde65f4 2196 cerr<<"Unknown command '"<<cmds[0] <<"'"<< endl;
1d211b1b
BH
2197 return 1;
2198 }
2199 return 0;
2200}
3f81d239 2201catch(PDNSException& ae) {
20002664 2202 cerr<<"Error: "<<ae.reason<<endl;
0c4c552d 2203 return 1;
20002664 2204}
14133ba3
BH
2205catch(std::exception& e) {
2206 cerr<<"Error: "<<e.what()<<endl;
0c4c552d 2207 return 1;
14133ba3 2208}
38392ad7 2209catch(...)
2210{
2211 cerr<<"Caught an unknown exception"<<endl;
2212 return 1;
2213}