]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/pdnssec.cc
Added tsig.com
[thirdparty/pdns.git] / pdns / pdnssec.cc
CommitLineData
1d211b1b 1#include "dnsseckeeper.hh"
d3151289 2#include "dnssecinfra.hh"
1d211b1b 3#include "statbag.hh"
01fde57c 4#include "base32.hh"
ed3f8559 5#include "base64.hh"
1d211b1b
BH
6#include <boost/foreach.hpp>
7#include <boost/program_options.hpp>
20002664
BH
8#include "dnsbackend.hh"
9#include "ueberbackend.hh"
10#include "arguments.hh"
11#include "packetcache.hh"
aa65a832 12#include "zoneparser-tng.hh"
ea937fd4 13#include "signingpipe.hh"
c3221d6e 14#include <boost/scoped_ptr.hpp>
2717b8b3 15#include "bindbackend2.hh"
49449751 16
20002664
BH
17StatBag S;
18PacketCache PC;
1d211b1b 19
de43ec0f 20using boost::scoped_ptr;
1d211b1b
BH
21namespace po = boost::program_options;
22po::variables_map g_vm;
23
39a8b5c0 24string s_programname="pdns";
20002664 25
b3ce3dec
BH
26namespace {
27 bool g_verbose; // doesn't yet do anything though
49449751
BH
28}
29
20002664
BH
30ArgvMap &arg()
31{
32 static ArgvMap arg;
33 return arg;
34}
35
1d211b1b
BH
36string humanTime(time_t t)
37{
38 char ret[256];
39 struct tm tm;
40 localtime_r(&t, &tm);
41 strftime(ret, sizeof(ret)-1, "%c", &tm); // %h:%M %Y-%m-%d
42 return ret;
43}
44
e0ad7bb1
PD
45static void algorithm2name(uint8_t algo, string &name) {
46 switch(algo) {
47 case 0:
48 name = "Reserved"; return;
49 case 1:
50 name = "RSAMD5"; return;
51 case 2:
52 name = "DH"; return;
53 case 3:
54 name = "DSA"; return;
55 case 4:
56 name = "ECC"; return;
57 case 5:
58 name = "RSASHA1"; return;
59 case 6:
60 name = "DSA-NSEC3-SHA1"; return;
61 case 7:
62 name = "RSASHA1-NSEC3-SHA1"; return;
63 case 8:
64 name = "RSASHA256"; return;
65 case 9:
66 name = "Reserved"; return;
67 case 10:
68 name = "RSASHA512"; return;
69 case 11:
70 name = "Reserved"; return;
71 case 12:
72 name = "ECC-GOST"; return;
73 case 13:
74 name = "ECDSAP256SHA256"; return;
75 case 14:
76 name = "ECDSAP384SHA384"; return;
77 case 252:
78 name = "INDIRECT"; return;
79 case 253:
80 name = "PRIVATEDNS"; return;
81 case 254:
82 name = "PRIVATEOID"; return;
83 default:
84 name = "Unallocated/Reserved"; return;
85 }
86};
87
36758d25
PD
88static int shorthand2algorithm(const string &algorithm)
89{
90 if (!algorithm.compare("rsamd5")) return 1;
91 if (!algorithm.compare("dh")) return 2;
92 if (!algorithm.compare("dsa")) return 3;
93 if (!algorithm.compare("ecc")) return 4;
94 if (!algorithm.compare("rsasha1")) return 5;
95 if (!algorithm.compare("rsasha256")) return 8;
96 if (!algorithm.compare("rsasha512")) return 10;
97 if (!algorithm.compare("gost")) return 12;
98 if (!algorithm.compare("ecdsa256")) return 13;
99 if (!algorithm.compare("ecdsa384")) return 14;
100 if (!algorithm.compare("ed25519")) return 250;
101 return -1;
102}
103
7d9dcde0 104void loadMainConfig(const std::string& configdir)
20002664 105{
7d9dcde0 106 ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=configdir;
c6347f61 107 ::arg().set("pipebackend-abi-version","Version of the pipe backend ABI")="1";
f2e7d77b 108 ::arg().set("default-ttl","Seconds a result is valid if not set otherwise")="3600";
20002664 109 ::arg().set("launch","Which backends to launch");
6dfa0aa0 110 ::arg().set("dnssec","if we should do dnssec")="true";
4f6cf113 111 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")=g_vm["config-name"].as<string>();
20002664
BH
112 ::arg().setCmd("help","Provide a helpful message");
113 //::arg().laxParse(argc,argv);
114
115 if(::arg().mustDo("help")) {
116 cerr<<"syntax:"<<endl<<endl;
117 cerr<<::arg().helpstring(::arg()["help"])<<endl;
118 exit(99);
119 }
120
121 if(::arg()["config-name"]!="")
122 s_programname+="-"+::arg()["config-name"];
123
124 string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
125 cleanSlashes(configname);
36758d25
PD
126
127 ::arg().set("default-ksk-algorithms","Default KSK algorithms")="rsasha256";
128 ::arg().set("default-ksk-size","Default KSK size (0 means default)")="0";
129 ::arg().set("default-zsk-algorithms","Default ZSK algorithms")="rsasha256";
130 ::arg().set("default-zsk-size","Default KSK size (0 means default)")="0";
20002664 131
b5baefaf 132 ::arg().set("max-ent-entries", "Maximum number of empty non-terminals in a zone")="100000";
a7e0acd8 133 ::arg().set("module-dir","Default directory for modules")=LIBDIR;
9097239c 134 ::arg().setSwitch("experimental-direct-dnskey","EXPERIMENTAL: fetch DNSKEY RRs from backend during DNSKEY synthesis")="no";
966828ac 135 ::arg().laxFile(configname.c_str());
12a92688 136
20002664
BH
137 BackendMakers().launch(::arg()["launch"]); // vrooooom!
138 ::arg().laxFile(configname.c_str());
9abd98d3 139 //cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" <<endl;
20002664
BH
140
141 S.declare("qsize-q","Number of questions waiting for database attention");
142
143 S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
144 S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
145
146 S.declare("query-cache-hit","Number of hits on the query cache");
147 S.declare("query-cache-miss","Number of misses on the query cache");
148 ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
149 ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no";
ec7f535c 150 ::arg().set("recursive-cache-ttl","Seconds to store packets for recursive queries in the PacketCache")="10";
20002664 151 ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
ec7f535c
PD
152 ::arg().set("negquery-cache-ttl","Seconds to store negative query results in the QueryCache")="60";
153 ::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
da6a2926 154 ::arg().set("default-soa-name","name to insert in the SOA record if none set in the backend")="a.misconfigured.powerdns.server";
20002664
BH
155 ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
156 ::arg().set("soa-retry-default","Default SOA retry")="3600";
157 ::arg().set("soa-expire-default","Default SOA expire")="604800";
ec7f535c 158 ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
abc1d928 159 ::arg().set("soa-minimum-ttl","Default SOA minimum ttl")="3600";
12a92688 160
20002664
BH
161 UeberBackend::go();
162}
163
d6c16697 164// irritatingly enough, rectifyZone needs its own ueberbackend and can't therefore benefit from transactions outside its scope
d4904322 165// I think this has to do with interlocking transactions between B and DK, but unsure.
032e3906 166bool rectifyZone(DNSSECKeeper& dk, const std::string& zone)
20002664 167{
9bd211e1
KM
168 if(dk.isPresigned(zone)){
169 cerr<<"Rectify presigned zone '"<<zone<<"' is not allowed/necessary."<<endl;
170 return false;
171 }
172
ba86110a 173 UeberBackend B("default");
d6c16697 174 bool doTransaction=true; // but see above
20002664 175 SOAData sd;
1325e8a2 176 sd.db = (DNSBackend*)-1;
81b39e4b 177
ba86110a 178 if(!B.getSOA(zone, sd)) {
f28f2324 179 cerr<<"No SOA known for '"<<zone<<"', is such a zone in the database?"<<endl;
032e3906 180 return false;
20002664 181 }
81b39e4b 182 sd.db->list(zone, sd.domain_id);
81b39e4b 183
b5baefaf
PD
184 DNSResourceRecord rr;
185 set<string> qnames, nsset, dsnames, nonterm, insnonterm, delnonterm;
186 bool doent=true;
20002664
BH
187
188 while(sd.db->get(rr)) {
b5baefaf
PD
189 if (rr.qtype.getCode())
190 {
191 qnames.insert(rr.qname);
192 if(rr.qtype.getCode() == QType::NS && !pdns_iequals(rr.qname, zone))
193 nsset.insert(rr.qname);
194 if(rr.qtype.getCode() == QType::DS)
195 dsnames.insert(rr.qname);
196 }
197 else
198 if(doent)
199 delnonterm.insert(rr.qname);
81b39e4b 200 }
9abd98d3 201
c3c89361 202 NSEC3PARAMRecordContent ns3pr;
f28f2324 203 bool narrow;
3c873e66 204 bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
ece45ffb
PD
205 if(sd.db->doesDNSSEC())
206 {
207 if(!haveNSEC3)
208 cerr<<"Adding NSEC ordering information "<<endl;
209 else if(!narrow)
210 cerr<<"Adding NSEC3 hashed ordering information for '"<<zone<<"'"<<endl;
211 else
212 cerr<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields"<<endl;
213 }
214 else
215 cerr<<"Non DNSSEC zone, only adding empty non-terminals"<<endl;
9abd98d3 216
d6c16697
BH
217 if(doTransaction)
218 sd.db->startTransaction("", -1);
b5baefaf
PD
219
220 bool realrr=true;
221 string hashed;
222
223 uint32_t maxent = ::arg().asNum("max-ent-entries");
224
225 dononterm:;
81b39e4b
BH
226 BOOST_FOREACH(const string& qname, qnames)
227 {
f28f2324 228 bool auth=true;
b5baefaf 229 string shorter(qname);
27045410 230
b5baefaf
PD
231 if(realrr) {
232 do {
233 if(nsset.count(shorter)) {
234 auth=false;
235 break;
236 }
237 } while(chopOff(shorter));
b5baefaf 238 }
27045410
PD
239
240 if(haveNSEC3)
241 {
f28f2324 242 if(!narrow) {
1bad4190 243 hashed=toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, qname));
4bf664d8
PD
244 if(g_verbose)
245 cerr<<"'"<<qname<<"' -> '"<< hashed <<"'"<<endl;
c2df797e 246 sd.db->updateDNSSECOrderAndAuthAbsolute(sd.domain_id, qname, hashed, auth);
f28f2324 247 }
c2df797e
PD
248 else
249 sd.db->nullifyDNSSECOrderNameAndUpdateAuth(sd.domain_id, qname, auth);
27045410
PD
250 }
251 else // NSEC
252 {
b8adb30d
KM
253 sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, qname, auth);
254 if (!realrr)
c2df797e 255 sd.db->nullifyDNSSECOrderNameAndUpdateAuth(sd.domain_id, qname, auth);
b5baefaf
PD
256 }
257
b8adb30d 258 if(realrr)
b5baefaf 259 {
b8adb30d
KM
260 if (dsnames.count(qname))
261 sd.db->setDNSSECAuthOnDsRecord(sd.domain_id, qname);
262 if (!auth || nsset.count(qname)) {
263 if(haveNSEC3 && ns3pr.d_flags)
264 sd.db->nullifyDNSSECOrderNameAndAuth(sd.domain_id, qname, "NS");
265 sd.db->nullifyDNSSECOrderNameAndAuth(sd.domain_id, qname, "A");
266 sd.db->nullifyDNSSECOrderNameAndAuth(sd.domain_id, qname, "AAAA");
267 }
268
269 if(auth && doent)
b5baefaf 270 {
b8adb30d
KM
271 shorter=qname;
272 while(!pdns_iequals(shorter, zone) && chopOff(shorter))
b5baefaf 273 {
b8adb30d 274 if(!qnames.count(shorter) && !nonterm.count(shorter))
b5baefaf 275 {
b8adb30d
KM
276 if(!(maxent))
277 {
278 cerr<<"Zone '"<<zone<<"' has too many empty non terminals."<<endl;
279 insnonterm.clear();
280 delnonterm.clear();
281 doent=false;
282 break;
283 }
284 nonterm.insert(shorter);
285 if (!delnonterm.count(shorter))
286 insnonterm.insert(shorter);
287 else
288 delnonterm.erase(shorter);
289 --maxent;
b5baefaf 290 }
b5baefaf 291 }
27045410 292 }
c3c89361 293 }
20002664 294 }
b5baefaf
PD
295
296 if(realrr)
297 {
298 //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
299 if(!insnonterm.empty() || !delnonterm.empty() || !doent)
300 {
301 sd.db->updateEmptyNonTerminals(sd.domain_id, zone, insnonterm, delnonterm, !doent);
302 }
303 if(doent)
304 {
305 realrr=false;
306 qnames=nonterm;
307 goto dononterm;
308 }
309 }
310
d6c16697
BH
311 if(doTransaction)
312 sd.db->commitTransaction();
032e3906
PD
313
314 return true;
20002664
BH
315}
316
1325e8a2
PD
317void rectifyAllZones(DNSSECKeeper &dk)
318{
ba86110a 319 UeberBackend B("default");
1325e8a2
PD
320 vector<DomainInfo> domainInfo;
321
ba86110a 322 B.getAllDomains(&domainInfo);
1325e8a2
PD
323 BOOST_FOREACH(DomainInfo di, domainInfo) {
324 cerr<<"Rectifying "<<di.zone<<": ";
325 rectifyZone(dk, di.zone);
326 }
327 cout<<"Rectified "<<domainInfo.size()<<" zones."<<endl;
328}
329
ba86110a 330int checkZone(DNSSECKeeper &dk, UeberBackend &B, const std::string& zone)
5d2e58b0 331{
5d2e58b0 332 SOAData sd;
1325e8a2 333 sd.db=(DNSBackend*)-1;
ba86110a 334 if(!B.getSOA(zone, sd)) {
0ae6a6cc
BH
335 cout<<"No SOA for zone '"<<zone<<"'"<<endl;
336 return -1;
5d2e58b0 337 }
5d2e58b0
BH
338 sd.db->list(zone, sd.domain_id);
339 DNSResourceRecord rr;
8c949c52 340 uint64_t numrecords=0, numerrors=0, numwarnings=0;
5d2e58b0 341
61717a51
PD
342 set<string> cnames, noncnames;
343
035297ad 344 while(sd.db->get(rr)) {
b191a835
PD
345 if(!endsOn(rr.qname, zone)) {
346 cout<<"[Warning] The record "<<rr.qname<<" with type "<<rr.qtype.getName()<<" in zone "<<zone<<" is out-of-zone."<<endl;
347 numwarnings++;
348 continue;
349 }
350
0c13544c
PD
351 if(!rr.qtype.getCode())
352 continue;
353
61717a51
PD
354 if (rr.qtype.getCode() == QType::CNAME) {
355 cnames.insert(rr.qname);
356 }
357 else {
358 if (rr.qtype.getCode() != QType::RRSIG)
359 noncnames.insert(rr.qname);
360 }
361
0aabca97
PD
362 if(rr.qtype.getCode() == QType::NSEC || rr.qtype.getCode() == QType::NSEC3)
363 {
364 cout<<"[Error] NSEC or NSEC3 found at '"<<rr.qname<<"'. These do not belong in the database."<<endl;
365 numerrors++;
366 continue;
367 }
368
12a92688
PD
369 if(rr.qtype.getCode() == QType::DNSKEY)
370 {
371 if(!dk.isPresigned(zone))
372 {
9097239c 373 if(::arg().mustDo("experimental-direct-dnskey"))
12a92688
PD
374 {
375 if(rr.ttl != sd.default_ttl)
376 {
377 cout<<"[Warning] DNSKEY TTL of "<<rr.ttl<<" at '"<<rr.qname<<"' differs from SOA minimum of "<<sd.default_ttl<<endl;
378 numwarnings++;
379 }
380 }
381 else
382 {
383 cout<<"[Error] DNSKEY in non-presigned zone will mostly be ignored and can cause problems."<<endl;
384 numerrors++;
385 }
386 }
387 }
388
0c13544c
PD
389 if(rr.qtype.getCode() == QType::SOA)
390 {
391 fillSOAData(rr.content, sd);
392 rr.content = serializeSOAData(sd);
393 }
394
01d2e77a 395 if(rr.qtype.getCode() == QType::URL || rr.qtype.getCode() == QType::MBOXFW) {
8c949c52 396 cout<<"[Error] The recordtype "<<rr.qtype.getName()<<" for record '"<<rr.qname<<"' is no longer supported."<<endl;
01d2e77a 397 numerrors++;
0ae6a6cc 398 continue;
01d2e77a
PD
399 }
400
8c949c52
PD
401 if (rr.qname[rr.qname.size()-1] == '.') {
402 cout<<"[Error] Record '"<<rr.qname<<"' has a trailing dot. PowerDNS will ignore this record!"<<endl;
403 numerrors++;
404 }
8c949c52 405
0ae6a6cc 406 if(rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV)
035297ad 407 rr.content = lexical_cast<string>(rr.priority)+" "+rr.content;
01d2e77a 408
ef1c4bf0 409 if ( (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::SRV || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::CNAME) &&
8c949c52
PD
410 rr.content[rr.content.size()-1] == '.') {
411 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;
412 numwarnings++;
413 }
414
5e42374c
BH
415 if(rr.qtype.getCode() == QType::TXT && !rr.content.empty() && rr.content[0]!='"')
416 rr.content = "\""+rr.content+"\"";
417
27045410 418 if(rr.auth == 0 && rr.qtype.getCode()!=QType::NS && rr.qtype.getCode()!=QType::A && rr.qtype.getCode()!=QType::AAAA)
7ddd79a7 419 {
8c949c52 420 cout<<"[Error] Following record is auth=0, run pdnssec rectify-zone?: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
5e42374c 421 numerrors++;
7ddd79a7 422 }
035297ad
BH
423 try {
424 shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content));
425 string tmp=drc->serialize(rr.qname);
5d2e58b0 426 }
035297ad
BH
427 catch(std::exception& e)
428 {
8c949c52
PD
429 cout<<"[Error] Following record had a problem: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
430 cout<<"[Error] Error was: "<<e.what()<<endl;
035297ad
BH
431 numerrors++;
432 }
433 numrecords++;
434 }
61717a51
PD
435
436 for(set<string>::const_iterator i = cnames.begin(); i != cnames.end(); i++) {
437 if (noncnames.find(*i) != noncnames.end()) {
438 cout<<"[Error] CNAME "<<*i<<" found, but other records with same label exist."<<endl;
439 numerrors++;
440 }
441 }
442
443
444
8c949c52 445 cout<<"Checked "<<numrecords<<" records of '"<<zone<<"', "<<numerrors<<" errors, "<<numwarnings<<" warnings."<<endl;
0ae6a6cc 446 return numerrors;
5d2e58b0
BH
447}
448
12a92688 449int checkAllZones(DNSSECKeeper &dk)
1325e8a2 450{
ba86110a 451 UeberBackend B("default");
1325e8a2
PD
452 vector<DomainInfo> domainInfo;
453
ba86110a 454 B.getAllDomains(&domainInfo);
1325e8a2
PD
455 int errors=0;
456 BOOST_FOREACH(DomainInfo di, domainInfo) {
ba86110a 457 if (checkZone(dk, B, di.zone) > 0)
1325e8a2 458 errors++;
1325e8a2
PD
459 }
460 cout<<"Checked "<<domainInfo.size()<<" zones, "<<errors<<" had errors."<<endl;
461 return 0;
462}
463
04576eed
RA
464int increaseSerial(const string& zone, DNSSECKeeper &dk)
465{
466 UeberBackend B("default");
467 SOAData sd;
468 sd.db=(DNSBackend*)-1;
469 if(!B.getSOA(zone, sd)) {
470 cout<<"No SOA for zone '"<<zone<<"'"<<endl;
471 return -1;
472 }
473
474 string soaEditKind;
475 dk.getFromMeta(zone, "SOA-EDIT", soaEditKind);
476
477 sd.db->lookup(QType(QType::SOA), zone);
478 vector<DNSResourceRecord> rrs;
479 DNSResourceRecord rr;
480 while (sd.db->get(rr)) {
481 if (rr.qtype.getCode() == QType::SOA)
482 rrs.push_back(rr);
483 }
484
485 if (rrs.size() > 1) {
486 cerr<<rrs.size()<<" SOA records found for "<<zone<<"!"<<endl;
487 return -1;
488 }
489 if (rrs.size() < 1) {
490 cerr<<zone<<" not found!"<<endl;
491 }
492
63347c6c 493 if (soaEditKind.empty()) {
04576eed 494 sd.serial++;
63347c6c
SB
495 }
496 else if(pdns_iequals(soaEditKind,"INCREMENT-WEEKS")) {
497 sd.serial++;
498 }
499 else if(pdns_iequals(soaEditKind,"INCEPTION-INCREMENT")) {
500 uint32_t today_serial = localtime_format_YYYYMMDDSS(time(NULL), 1);
501
502 if (sd.serial < today_serial) {
503 sd.serial = today_serial;
504 }
505 else {
506 sd.serial++;
507 }
508 }
509 else {
9f44333a 510 sd.serial = calculateEditSOA(sd, soaEditKind) + 1;
63347c6c 511 }
04576eed
RA
512 rrs[0].content = serializeSOAData(sd);
513
514 if (! sd.db->replaceRRSet(sd.domain_id, zone, rr.qtype, rrs)) {
515 cerr<<"Backend did not replace SOA record. Backend might not support this operation."<<endl;
516 return -1;
517 }
518 cout<<"SOA serial for zone "<<zone<<" set to "<<sd.serial<<endl;
519 return 0;
520}
521
cbb0025b
PD
522void testAlgorithm(int algo)
523{
524 DNSCryptoKeyEngine::testOne(algo);
525}
1325e8a2 526
189bb9d2
BH
527void testAlgorithms()
528{
529 DNSCryptoKeyEngine::testAll();
530}
531
49449751 532void testSpeed(DNSSECKeeper& dk, const string& zone, const string& remote, int cores)
ea937fd4
BH
533{
534 DNSResourceRecord rr;
535 rr.qname="blah."+zone;
536 rr.qtype=QType::A;
537 rr.ttl=3600;
538 rr.auth=1;
539 rr.qclass = 1;
540 rr.d_place=DNSResourceRecord::ANSWER;
541 rr.priority=0;
542
49449751 543 UeberBackend db("key-only");
ea937fd4 544
f0c4b9d5
PD
545 if ( ! db.backends.size() )
546 {
547 throw runtime_error("No backends available for DNSSEC key storage");
548 }
549
49449751 550 ChunkedSigningPipe csp(zone, 1, remote, cores);
ea937fd4
BH
551
552 vector<DNSResourceRecord> signatures;
553 uint32_t rnd;
554 unsigned char* octets = (unsigned char*)&rnd;
555 char tmp[25];
556 DTime dt;
557 dt.set();
558 for(unsigned int n=0; n < 100000; ++n) {
559 rnd = random();
560 snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
561 octets[0], octets[1], octets[2], octets[3]);
562 rr.content=tmp;
563
564 snprintf(tmp, sizeof(tmp), "r-%u", rnd);
565 rr.qname=string(tmp)+"."+zone;
566
567 if(csp.submit(rr))
568 while(signatures = csp.getChunk(), !signatures.empty())
569 ;
570 }
571 cerr<<"Flushing the pipe, "<<csp.d_signed<<" signed, "<<csp.d_queued<<" queued, "<<csp.d_outstanding<<" outstanding"<< endl;
572 cerr<<"Net speed: "<<csp.d_signed/ (dt.udiffNoReset()/1000000.0) << " sigs/s\n";
573 while(signatures = csp.getChunk(true), !signatures.empty())
574 ;
575 cerr<<"Done, "<<csp.d_signed<<" signed, "<<csp.d_queued<<" queued, "<<csp.d_outstanding<<" outstanding"<< endl;
576 cerr<<"Net speed: "<<csp.d_signed/ (dt.udiff()/1000000.0) << " sigs/s\n";
577}
578
aa65a832
BH
579void verifyCrypto(const string& zone)
580{
581 ZoneParserTNG zpt(zone);
582 DNSResourceRecord rr;
583 DNSKEYRecordContent drc;
584 RRSIGRecordContent rrc;
c3e26094 585 DSRecordContent dsrc;
aa65a832 586 vector<shared_ptr<DNSRecordContent> > toSign;
c3e26094
BH
587 string qname, apex;
588 dsrc.d_digesttype=0;
aa65a832
BH
589 while(zpt.get(rr)) {
590 if(rr.qtype.getCode() == QType::DNSKEY) {
591 cerr<<"got DNSKEY!"<<endl;
c3e26094 592 apex=rr.qname;
aa65a832
BH
593 drc = *dynamic_cast<DNSKEYRecordContent*>(DNSRecordContent::mastermake(QType::DNSKEY, 1, rr.content));
594 }
595 else if(rr.qtype.getCode() == QType::RRSIG) {
596 cerr<<"got RRSIG"<<endl;
597 rrc = *dynamic_cast<RRSIGRecordContent*>(DNSRecordContent::mastermake(QType::RRSIG, 1, rr.content));
598 }
c3e26094
BH
599 else if(rr.qtype.getCode() == QType::DS) {
600 cerr<<"got DS"<<endl;
601 dsrc = *dynamic_cast<DSRecordContent*>(DNSRecordContent::mastermake(QType::DS, 1, rr.content));
602 }
aa65a832
BH
603 else {
604 qname = rr.qname;
aa65a832
BH
605 toSign.push_back(shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)));
606 }
607 }
c3e26094 608
f309dacd 609 string msg = getMessageForRRSET(qname, rrc, toSign);
49449751 610 cerr<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc.d_algorithm, drc.d_key)->verify(msg, rrc.d_signature)<<endl;
c3e26094
BH
611 if(dsrc.d_digesttype) {
612 cerr<<"Calculated DS: "<<apex<<" IN DS "<<makeDSFromDNSKey(apex, drc, dsrc.d_digesttype).getZoneRepresentation()<<endl;
613 cerr<<"Original DS: "<<apex<<" IN DS "<<dsrc.getZoneRepresentation()<<endl;
614 }
295812a1 615#if 0
8d9f38f2 616 DNSCryptoKeyEngine*key=DNSCryptoKeyEngine::makeFromISCString(drc, "Private-key-format: v1.2\n"
295812a1
BH
617 "Algorithm: 12 (ECC-GOST)\n"
618 "GostAsn1: MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgQg/9MiXtXKg9FDXDN/R9CmVhJDyuzRAIgh4tPwCu4NHIs=\n");
619 string resign=key->sign(hash);
620 cerr<<Base64Encode(resign)<<endl;
8d9f38f2 621 cerr<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc.d_algorithm, drc.d_key)->verify(hash, resign)<<endl;
295812a1
BH
622#endif
623
aa65a832 624}
032e3906 625bool disableDNSSECOnZone(DNSSECKeeper& dk, const string& zone)
5935cede 626{
032e3906
PD
627 UeberBackend B("default");
628 DomainInfo di;
629
630 if (!B.getDomainInfo(zone, di)){
631 cerr << "No such zone in the database" << endl;
632 return false;
633 }
634
5935cede
BH
635 if(!dk.isSecuredZone(zone)) {
636 cerr<<"Zone is not secured\n";
032e3906 637 return false;
5935cede
BH
638 }
639 DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
aa65a832 640
5935cede
BH
641 if(keyset.empty()) {
642 cerr << "No keys for zone '"<<zone<<"'."<<endl;
643 }
644 else {
645 BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
646 dk.deactivateKey(zone, value.second.id);
37fd8771 647 dk.removeKey(zone, value.second.id);
5935cede
BH
648 }
649 }
650 dk.unsetNSEC3PARAM(zone);
651 dk.unsetPresigned(zone);
032e3906 652 return true;
5935cede 653}
032e3906 654bool showZone(DNSSECKeeper& dk, const std::string& zone)
ade1b1e9 655{
032e3906
PD
656 UeberBackend B("default");
657 DomainInfo di;
4831df57 658 std::vector<std::string> meta;
032e3906
PD
659
660 if (!B.getDomainInfo(zone, di)){
661 cerr << "No such zone in the database" << endl;
662 return false;
663 }
664
d3e7090c 665 if(!dk.isSecuredZone(zone)) {
d4a4176d 666 cerr<<"Zone is not actively secured\n";
d3e7090c 667 }
ade1b1e9
BH
668 NSEC3PARAMRecordContent ns3pr;
669 bool narrow;
3c873e66 670 bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
ade1b1e9 671
d4a4176d 672 DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
4831df57
AT
673 if (B.getDomainMetadata(zone, "TSIG-ALLOW-AXFR", meta) && meta.size() > 0) {
674 cerr << "Zone has following allowed TSIG key(s): " << boost::join(meta, ",") << endl;
675 }
676
677 if (B.getDomainMetadata(zone, "AXFR-MASTER-TSIG", meta) && meta.size() > 0) {
678 cerr << "Zone uses following TSIG key(s): " << boost::join(meta, ",") << endl;
679 }
d3e7090c 680
d4a4176d 681 cout <<"Zone is " << (dk.isPresigned(zone) ? "" : "not ") << "presigned\n";
ade1b1e9
BH
682
683 if(keyset.empty()) {
684 cerr << "No keys for zone '"<<zone<<"'."<<endl;
685 }
686 else {
d4a4176d
BH
687 if(!haveNSEC3)
688 cout<<"Zone has NSEC semantics"<<endl;
689 else
690 cout<<"Zone has " << (narrow ? "NARROW " : "") <<"hashed NSEC3 semantics, configuration: "<<ns3pr.getZoneRepresentation()<<endl;
691
ade1b1e9
BH
692 cout << "keys: "<<endl;
693 BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
e0ad7bb1
PD
694 string algname;
695 algorithm2name(value.first.d_algorithm, algname);
ade1b1e9 696 cout<<"ID = "<<value.second.id<<" ("<<(value.second.keyOrZone ? "KSK" : "ZSK")<<"), tag = "<<value.first.getDNSKEY().getTag();
ca2eb011
KM
697 cout<<", algo = "<<(int)value.first.d_algorithm<<", bits = "<<value.first.getKey()->getBits()<<"\tActive: "<<value.second.active<< " ( " + algname + " ) "<<endl;
698 if(value.second.keyOrZone || ::arg().mustDo("experimental-direct-dnskey"))
699 cout<<(value.second.keyOrZone ? "KSK" : "ZSK")<<" DNSKEY = "<<zone<<" IN DNSKEY "<< value.first.getDNSKEY().getZoneRepresentation() << " ; ( " + algname + " )" << endl;
ade1b1e9 700 if(value.second.keyOrZone) {
e0ad7bb1
PD
701 cout<<"DS = "<<zone<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 1).getZoneRepresentation() << " ; ( SHA1 digest )" << endl;
702 cout<<"DS = "<<zone<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 2).getZoneRepresentation() << " ; ( SHA256 digest )" << endl;
608d776f
BH
703 try {
704 string output=makeDSFromDNSKey(zone, value.first.getDNSKEY(), 3).getZoneRepresentation();
e0ad7bb1
PD
705 cout<<"DS = "<<zone<<" IN DS "<< output << " ; ( GOST R 34.11-94 digest )" << endl;
706 }
707 catch(...)
708 {
709 }
710 try {
711 string output=makeDSFromDNSKey(zone, value.first.getDNSKEY(), 4).getZoneRepresentation();
712 cout<<"DS = "<<zone<<" IN DS "<< output << " ; ( SHA-384 digest )" << endl;
608d776f
BH
713 }
714 catch(...)
715 {
716 }
717 cout<<endl;
ade1b1e9
BH
718 }
719 }
720 }
032e3906 721 return true;
ade1b1e9 722}
5d2e58b0 723
d6c16697 724bool secureZone(DNSSECKeeper& dk, const std::string& zone)
ddac7145 725{
36758d25
PD
726 // parse attribute
727 vector<string> k_algos;
728 vector<string> z_algos;
729 int k_size;
730 int z_size;
731
732 stringtok(k_algos, ::arg()["default-ksk-algorithms"], " ,");
733 k_size = ::arg().asNum("default-ksk-size");
734 stringtok(z_algos, ::arg()["default-zsk-algorithms"], " ,");
735 z_size = ::arg().asNum("default-zsk-size");
736
737 if (k_size < 0) {
738 throw runtime_error("KSK key size must be equal to or greater than 0");
739 }
740
741 if (k_algos.size() < 1) {
742 throw runtime_error("No algorithm(s) given for KSK");
743 }
744
745 if (z_size < 0) {
746 throw runtime_error("ZSK key size must be equal to or greater than 0");
747 }
748
749 if (z_algos.size() < 1) {
750 throw runtime_error("No algorithm(s) given for ZSK");
751 }
752
f60f4bcd
BH
753 if(dk.isSecuredZone(zone)) {
754 cerr << "Zone '"<<zone<<"' already secure, remove keys with pdnssec remove-zone-key if needed"<<endl;
755 return false;
756 }
757
2402c558
BH
758 DomainInfo di;
759 UeberBackend B("default");
760 if(!B.getDomainInfo(zone, di) || !di.backend) { // di.backend and B are mostly identical
761 cout<<"Can't find a zone called '"<<zone<<"'"<<endl;
762 return false;
763 }
764
3bf07122
PD
765 if(di.kind == DomainInfo::Slave)
766 {
767 cout<<"Warning! This is a slave domain! If this was a mistake, please run"<<endl;
768 cout<<"pdnssec disable-dnssec "<<zone<<" right now!"<<endl;
769 }
770
36758d25
PD
771 if (k_size)
772 cout << "Securing zone with " << k_algos[0] << " algorithm with key size " << k_size << endl;
773 else
774 cout << "Securing zone with " << k_algos[0] << " algorithm with default key size" << endl;
775
776 // run secure-zone with first default algorith, then add keys
777 if(!dk.secureZone(zone, shorthand2algorithm(k_algos[0]), k_size)) {
f60f4bcd
BH
778 cerr<<"No backend was able to secure '"<<zone<<"', most likely because no DNSSEC\n";
779 cerr<<"capable backends are loaded, or because the backends have DNSSEC disabled.\n";
21fb9631
BH
780 cerr<<"For the Generic SQL backends, set the 'gsqlite3-dnssec', 'gmysql-dnssec' or\n";
781 cerr<<"'gpgsql-dnssec' flag. Also make sure the schema has been updated for DNSSEC!\n";
f60f4bcd
BH
782 return false;
783 }
784
785 if(!dk.isSecuredZone(zone)) {
786 cerr<<"Failed to secure zone. Is your backend dnssec enabled? (set \n";
0c84faf7 787 cerr<<"gsqlite3-dnssec, or gmysql-dnssec etc). Check this first.\n";
21fb9631 788 cerr<<"If you run with the BIND backend, make sure you have configured\n";
b925384e 789 cerr<<"it to use DNSSEC with 'bind-dnssec-db=/path/fname' and\n";
790 cerr<<"'pdnssec create-bind-db /path/fname'!\n";
f60f4bcd
BH
791 return false;
792 }
793
794 DNSSECKeeper::keyset_t zskset=dk.getKeys(zone, false);
795
796 if(!zskset.empty()) {
797 cerr<<"There were ZSKs already for zone '"<<zone<<"', no need to add more"<<endl;
798 return false;
799 }
36758d25
PD
800
801 for(vector<string>::iterator i = k_algos.begin()+1; i != k_algos.end(); i++)
07bf35d1 802 dk.addKey(zone, true, shorthand2algorithm(*i), k_size, true); // obvious errors will have been caught above
36758d25
PD
803
804 BOOST_FOREACH(string z_algo, z_algos)
805 {
806 int algo = shorthand2algorithm(z_algo);
807 dk.addKey(zone, false, algo, z_size);
36758d25
PD
808 }
809
f60f4bcd
BH
810 // rectifyZone(dk, zone);
811 // showZone(dk, zone);
812 cout<<"Zone "<<zone<<" secured"<<endl;
d6c16697 813 return true;
ddac7145
BH
814}
815
46d2e0d6
PD
816void testSchema(DNSSECKeeper& dk, const std::string& zone)
817{
818 cout<<"Note: test-schema will try to create the zone, but it will not remove it."<<endl;
819 cout<<"Please clean up after this."<<endl;
820 cout<<endl;
821 cout<<"Constructing UeberBackend"<<endl;
2402c558 822 UeberBackend B("default");
46d2e0d6 823 cout<<"Picking first backend - if this is not what you want, edit launch line!"<<endl;
2402c558 824 DNSBackend *db = B.backends[0];
46d2e0d6
PD
825 cout<<"Creating slave domain "<<zone<<endl;
826 db->createSlaveDomain("127.0.0.1", zone, "_testschema");
827 cout<<"Slave domain created"<<endl;
828
829 DomainInfo di;
2402c558 830 if(!B.getDomainInfo(zone, di) || !di.backend) { // di.backend and B are mostly identical
46d2e0d6
PD
831 cout<<"Can't find domain we just created, aborting"<<endl;
832 return;
833 }
834 db=di.backend;
835 DNSResourceRecord rr, rrget;
836 cout<<"Starting transaction to feed records"<<endl;
837 db->startTransaction(zone, di.id);
838
839 rr.qtype=QType::SOA;
840 rr.qname=zone;
841 rr.ttl=86400;
842 rr.domain_id=di.id;
843 rr.auth=1;
844 rr.content="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
845 cout<<"Feeding SOA"<<endl;
846 db->feedRecord(rr);
847 rr.qtype=QType::TXT;
848 // 300 As
849 rr.content="\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"";
850 cout<<"Feeding overlong TXT"<<endl;
851 db->feedRecord(rr);
852 cout<<"Committing"<<endl;
853 db->commitTransaction();
854 cout<<"Querying TXT"<<endl;
855 db->lookup(QType(QType::TXT), zone, NULL, di.id);
856 if(db->get(rrget))
857 {
858 DNSResourceRecord rrthrowaway;
859 if(db->get(rrthrowaway)) // should not touch rr but don't assume anything
860 {
861 cout<<"Expected one record, got multiple, aborting"<<endl;
862 return;
863 }
864 int size=rrget.content.size();
865 if(size != 302)
866 {
867 cout<<"Expected 302 bytes, got "<<size<<", aborting"<<endl;
868 return;
869 }
870 }
871 cout<<"[+] content field is over 255 bytes"<<endl;
872
873 cout<<"Dropping all records, inserting SOA+2xA"<<endl;
874 db->startTransaction(zone, di.id);
875
876 rr.qtype=QType::SOA;
877 rr.qname=zone;
878 rr.ttl=86400;
879 rr.domain_id=di.id;
880 rr.auth=1;
881 rr.content="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
882 cout<<"Feeding SOA"<<endl;
883 db->feedRecord(rr);
884
885 rr.qtype=QType::A;
886 rr.qname="_underscore."+zone;
887 rr.content="127.0.0.1";
888 db->feedRecord(rr);
889
890 rr.qname="bla."+zone;
891 cout<<"Committing"<<endl;
892 db->commitTransaction();
893
894 cout<<"Securing zone"<<endl;
895 secureZone(dk, zone);
896 cout<<"Rectifying zone"<<endl;
897 rectifyZone(dk, zone);
898 cout<<"Checking underscore ordering"<<endl;
899 string before, after;
900 db->getBeforeAndAfterNames(di.id, zone, "z."+zone, before, after);
901 cout<<"got '"<<before<<"' < 'z."<<zone<<"' < '"<<after<<"'"<<endl;
902 if(before != "_underscore."+zone)
903 {
904 cout<<"before is wrong, got '"<<before<<"', expected '_underscore."<<zone<<"', aborting"<<endl;
905 return;
906 }
907 if(after != zone)
908 {
909 cout<<"after is wrong, got '"<<after<<"', expected '"<<zone<<"', aborting"<<endl;
910 return;
911 }
912 cout<<"[+] ordername sorting is correct for names starting with _"<<endl;
913 cout<<endl;
914 cout<<"End of tests, please remove "<<zone<<" from domains+records"<<endl;
915}
916
1d211b1b 917int main(int argc, char** argv)
20002664 918try
2fa33bce 919{
1d211b1b
BH
920 po::options_description desc("Allowed options");
921 desc.add_options()
922 ("help,h", "produce help message")
b3ce3dec 923 ("verbose,v", "be verbose")
1d211b1b 924 ("force", "force an action")
aa952078 925 ("config-name", po::value<string>()->default_value(""), "virtual configuration name")
7d9dcde0 926 ("config-dir", po::value<string>()->default_value(SYSCONFDIR), "location of pdns.conf")
1d211b1b
BH
927 ("commands", po::value<vector<string> >());
928
929 po::positional_options_description p;
930 p.add("commands", -1);
931 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), g_vm);
932 po::notify(g_vm);
933
934 vector<string> cmds;
935
936 if(g_vm.count("commands"))
937 cmds = g_vm["commands"].as<vector<string> >();
938
b3ce3dec
BH
939 g_verbose = g_vm.count("verbose");
940
1d211b1b 941 if(cmds.empty() || g_vm.count("help")) {
e1489e74
PD
942 cerr<<"Usage: \npdnssec [options] <command> [params ..]\n\n";
943 cerr<<"Commands:\n";
151b561f 944 cerr<<"activate-zone-key ZONE KEY-ID Activate the key with key id KEY-ID in ZONE\n";
4af49b80 945 cerr<<"add-zone-key ZONE zsk|ksk [bits] [active|passive]\n";
151b561f
PD
946 cerr<<" [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384]\n";
947 cerr<<" Add a ZSK or KSK to zone and specify algo&bits\n";
948 cerr<<"check-zone ZONE Check a zone for correctness\n";
949 cerr<<"check-all-zones Check all zones for correctness\n";
950 cerr<<"create-bind-db FNAME Create DNSSEC db for BIND backend (bind-dnssec-db)\n";
951 cerr<<"deactivate-zone-key ZONE KEY-ID Deactivate the key with key id KEY-ID in ZONE\n";
952 cerr<<"disable-dnssec ZONE Deactivate all keys and unset PRESIGNED in ZONE\n";
953 cerr<<"export-zone-dnskey ZONE KEY-ID Export to stdout the public DNSKEY described\n";
954 cerr<<"export-zone-key ZONE KEY-ID Export to stdout the private key described\n";
7e5b2860 955 cerr<<"generate-zone-key zsk|ksk [algorithm] [bits]\n";
49baee5f 956 cerr<<" Generate a ZSK or KSK to stdout with specified algo&bits\n";
151b561f 957 cerr<<"hash-zone-record ZONE RNAME Calculate the NSEC3 hash for RNAME in ZONE\n";
4b88a3cd 958 cerr<<"increase-serial ZONE Increases the SOA-serial by 1. Uses SOA-EDIT\n";
151b561f 959 cerr<<"import-zone-key ZONE FILE Import from a file a private key, ZSK or KSK\n";
4af49b80 960 cerr<<" [active|passive][ksk|zsk] Defaults to KSK and active\n";
151b561f
PD
961 cerr<<"rectify-zone ZONE [ZONE ..] Fix up DNSSEC fields (order, auth)\n";
962 cerr<<"rectify-all-zones Rectify all zones.\n";
963 cerr<<"remove-zone-key ZONE KEY-ID Remove key with KEY-ID from ZONE\n";
964 cerr<<"secure-zone ZONE [ZONE ..] Add KSK and two ZSKs\n";
965 cerr<<"set-nsec3 ZONE ['params' [narrow]] Enable NSEC3 with PARAMs. Optionally narrow\n";
966 cerr<<"set-presigned ZONE Use presigned RRSIGs from storage\n";
967 cerr<<"show-zone ZONE Show DNSSEC (public) key details about a zone\n";
968 cerr<<"unset-nsec3 ZONE Switch back to NSEC\n";
969 cerr<<"unset-presigned ZONE No longer use presigned RRSIGs\n";
6f872b78 970 cerr<<"test-schema ZONE Test DB schema - will create ZONE\n";
7e5b2860 971 cerr<<"import-tsig-key NAME ALGORITHM KEY Import TSIG key\n";
4831df57 972 cerr<<"create-tsig-key NAME ALGORITHM Generate new TSIG key\n";
7e5b2860
AT
973 cerr<<"list-tsig-keys List all TSIG keys\n";
974 cerr<<"delete-tsig-key NAME Delete TSIG key (warning! will not unmap key!)\n";
4831df57
AT
975 cerr<<"enable-tsig-key ZONE NAME [master|slave]\n";
976 cerr<<" Enable TSIG key for a zone\n";
977 cerr<<"disable-tsig-key ZONE NAME [master|slave]\n";
978 cerr<<" Disable TSIG key for a zone\n";
1d211b1b
BH
979 cerr<<desc<<endl;
980 return 0;
981 }
a7e0acd8 982
cbb0025b 983 if (cmds[0] == "test-algorithm") {
2551cc18
PD
984 if(cmds.size() != 2) {
985 cerr << "Syntax: pdnssec test-algorithm algonum"<<endl;
986 return 0;
987 }
cbb0025b
PD
988 testAlgorithm(lexical_cast<int>(cmds[1]));
989 return 0;
990 }
991
ea937fd4
BH
992 if(cmds[0] == "test-algorithms") {
993 testAlgorithms();
994 return 0;
995 }
996
7d9dcde0 997 loadMainConfig(g_vm["config-dir"].as<string>());
6dfa0aa0 998 reportAllTypes();
b925384e 999
2717b8b3 1000 if(cmds[0] == "create-bind-db") {
fbe72b7a
BH
1001 if(cmds.size() != 2) {
1002 cerr << "Syntax: pdnssec create-bind-db fname"<<endl;
1003 return 0;
1004 }
080f5d57
PD
1005 try {
1006 Bind2Backend::createDNSSECDB(cmds[1]);
1007 }
3f81d239 1008 catch (PDNSException& ae) {
080f5d57
PD
1009 cerr<<"Error: "<<ae.reason<<endl;
1010 return 1;
1011 }
1012 return 0;
2717b8b3 1013 }
fbe72b7a
BH
1014
1015 DNSSECKeeper dk;
1016
46d2e0d6
PD
1017 if (cmds[0] == "test-schema") {
1018 if(cmds.size() != 2) {
1019 cerr << "Syntax: pdnssec test-schema ZONE"<<endl;
1020 return 0;
1021 }
1022 testSchema(dk, cmds[1]);
1023 return 0;
1024 }
fbe72b7a 1025 if(cmds[0] == "rectify-zone") {
d4904322
BH
1026 if(cmds.size() < 2) {
1027 cerr << "Syntax: pdnssec rectify-zone ZONE [ZONE..]"<<endl;
81b39e4b
BH
1028 return 0;
1029 }
032e3906 1030 unsigned int exitCode = 0;
d4904322 1031 for(unsigned int n = 1; n < cmds.size(); ++n)
032e3906
PD
1032 if (!rectifyZone(dk, cmds[n])) exitCode = 1;
1033 return exitCode;
20002664 1034 }
1325e8a2
PD
1035 else if (cmds[0] == "rectify-all-zones") {
1036 rectifyAllZones(dk);
1037 }
9abd98d3 1038 else if(cmds[0] == "check-zone") {
5d2e58b0 1039 if(cmds.size() != 2) {
37fd8771 1040 cerr << "Syntax: pdnssec check-zone ZONE"<<endl;
5d2e58b0
BH
1041 return 0;
1042 }
ba86110a
PD
1043 UeberBackend B("default");
1044 exit(checkZone(dk, B, cmds[1]));
5d2e58b0 1045 }
1325e8a2 1046 else if (cmds[0] == "check-all-zones") {
12a92688 1047 exit(checkAllZones(dk));
1325e8a2 1048 }
81e9ba89
PD
1049 else if (cmds[0] == "test-zone") {
1050 cerr << "Did you mean check-zone?"<<endl;
1051 return 0;
1052 }
1053 else if (cmds[0] == "test-all-zones") {
1054 cerr << "Did you mean check-all-zones?"<<endl;
1055 return 0;
1056 }
49449751
BH
1057#if 0
1058 else if(cmds[0] == "signing-server" )
1059 {
1060 signingServer();
1061 }
1062 else if(cmds[0] == "signing-slave")
1063 {
1064 launchSigningService(0);
1065 }
1066#endif
ea937fd4 1067 else if(cmds[0] == "test-speed") {
37fd8771
BH
1068 if(cmds.size() < 2) {
1069 cerr << "Syntax: pdnssec test-speed numcores [signing-server]"<<endl;
ea937fd4
BH
1070 return 0;
1071 }
49449751 1072 testSpeed(dk, cmds[1], (cmds.size() > 3) ? cmds[3] : "", atoi(cmds[2].c_str()));
189bb9d2 1073 }
aa65a832
BH
1074 else if(cmds[0] == "verify-crypto") {
1075 if(cmds.size() != 2) {
37fd8771 1076 cerr << "Syntax: pdnssec verify-crypto FILE"<<endl;
aa65a832
BH
1077 return 0;
1078 }
1079 verifyCrypto(cmds[1]);
1080 }
da11ed0e
BH
1081
1082 else if(cmds[0] == "show-zone") {
a0472099 1083 if(cmds.size() != 2) {
37fd8771 1084 cerr << "Syntax: pdnssec show-zone ZONE"<<endl;
a0472099
BH
1085 return 0;
1086 }
1d211b1b 1087 const string& zone=cmds[1];
032e3906 1088 if (!showZone(dk, zone)) return 1;
1d211b1b 1089 }
5935cede
BH
1090 else if(cmds[0] == "disable-dnssec") {
1091 if(cmds.size() != 2) {
37fd8771 1092 cerr << "Syntax: pdnssec disable-dnssec ZONE"<<endl;
5935cede
BH
1093 return 0;
1094 }
1095 const string& zone=cmds[1];
032e3906
PD
1096 if(!disableDNSSECOnZone(dk, zone))
1097 return 1;
5935cede 1098 }
bed962b5 1099 else if(cmds[0] == "activate-zone-key") {
37fd8771
BH
1100 if(cmds.size() != 3) {
1101 cerr << "Syntax: pdnssec activate-zone-key ZONE KEY-ID"<<endl;
1102 return 0;
1103 }
bed962b5
BH
1104 const string& zone=cmds[1];
1105 unsigned int id=atoi(cmds[2].c_str());
77b909cc
PD
1106 if(!id)
1107 {
1108 cerr<<"Invalid KEY-ID"<<endl;
1109 return 1;
1110 }
a84a8203
PD
1111 if (!dk.activateKey(zone, id)) {
1112 cerr<<"Activation of key failed"<<endl;
1113 return 1;
1114 }
1115 return 0;
bed962b5
BH
1116 }
1117 else if(cmds[0] == "deactivate-zone-key") {
37fd8771
BH
1118 if(cmds.size() != 3) {
1119 cerr << "Syntax: pdnssec deactivate-zone-key ZONE KEY-ID"<<endl;
1120 return 0;
1121 }
bed962b5
BH
1122 const string& zone=cmds[1];
1123 unsigned int id=atoi(cmds[2].c_str());
77b909cc
PD
1124 if(!id)
1125 {
1126 cerr<<"Invalid KEY-ID"<<endl;
1127 return 1;
1128 }
a84a8203
PD
1129 if (!dk.deactivateKey(zone, id)) {
1130 cerr<<"Deactivation of key failed"<<endl;
1131 return 1;
1132 }
1133 return 0;
bed962b5
BH
1134 }
1135 else if(cmds[0] == "add-zone-key") {
37fd8771 1136 if(cmds.size() < 3 ) {
52690ba5 1137 cerr << "Syntax: pdnssec add-zone-key ZONE zsk|ksk [bits] [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384]"<<endl;
37fd8771
BH
1138 return 0;
1139 }
bed962b5 1140 const string& zone=cmds[1];
032e3906
PD
1141
1142 UeberBackend B("default");
1143 DomainInfo di;
1144
1145 if (!B.getDomainInfo(zone, di)){
1146 cerr << "No such zone in the database" << endl;
1147 return 0;
1148 }
1149
36c394e5
BH
1150 // need to get algorithm, bits & ksk or zsk from commandline
1151 bool keyOrZone=false;
36758d25 1152 int tmp_algo=0;
36c394e5 1153 int bits=0;
0ba8e0f1 1154 int algorithm=8;
4af49b80 1155 bool active=false;
36c394e5
BH
1156 for(unsigned int n=2; n < cmds.size(); ++n) {
1157 if(pdns_iequals(cmds[n], "zsk"))
1158 keyOrZone = false;
1159 else if(pdns_iequals(cmds[n], "ksk"))
1160 keyOrZone = true;
36758d25
PD
1161 else if((tmp_algo = shorthand2algorithm(cmds[n]))>0) {
1162 algorithm = tmp_algo;
4af49b80 1163 } else if(pdns_iequals(cmds[n], "active")) {
1164 active=true;
1165 } else if(pdns_iequals(cmds[n], "inactive") || pdns_iequals(cmds[n], "passive")) {
1166 active=false;
1167 } else if(atoi(cmds[n].c_str())) {
36c394e5 1168 bits = atoi(cmds[n].c_str());
4af49b80 1169 } else {
a254438f 1170 cerr<<"Unknown algorithm, key flag or size '"<<cmds[n]<<"'"<<endl;
07bf35d1 1171 exit(EXIT_FAILURE);;
36c394e5
BH
1172 }
1173 }
07bf35d1 1174 if(!dk.addKey(zone, keyOrZone, algorithm, bits, active)) {
1175 cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
1176 exit(1);
1177 }
1178 else {
1179 cerr<<"Added a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "<<algorithm<<", active="<<active<<endl;
1180 if(bits)
1181 cerr<<"Requested specific key size of "<<bits<<" bits"<<endl;
1182 }
bed962b5
BH
1183 }
1184 else if(cmds[0] == "remove-zone-key") {
471304cc 1185 if(cmds.size() < 3) {
48cb6e2a 1186 cerr<<"Syntax: pdnssec remove-zone-key ZONE KEY-ID"<<endl;
471304cc
BH
1187 return 0;
1188 }
bed962b5
BH
1189 const string& zone=cmds[1];
1190 unsigned int id=atoi(cmds[2].c_str());
a84a8203
PD
1191 if (!dk.removeKey(zone, id)) {
1192 return 1;
1193 }
1194 return 0;
bed962b5
BH
1195 }
1196
c3c89361 1197 else if(cmds[0] == "secure-zone") {
ddac7145 1198 if(cmds.size() < 2) {
37fd8771 1199 cerr << "Syntax: pdnssec secure-zone ZONE"<<endl;
a9175ad6
BH
1200 return 0;
1201 }
d6c16697 1202 vector<string> mustRectify;
ddac7145 1203 dk.startTransaction();
1325e8a2 1204 unsigned int zoneErrors=0;
ddac7145 1205 for(unsigned int n = 1; n < cmds.size(); ++n) {
f60f4bcd
BH
1206 const string& zone=cmds[n];
1207 if(secureZone(dk, zone)) {
d6c16697 1208 mustRectify.push_back(zone);
1325e8a2
PD
1209 } else {
1210 zoneErrors++;
d6c16697 1211 }
f60f4bcd 1212 }
1d211b1b 1213
ddac7145 1214 dk.commitTransaction();
d6c16697
BH
1215 BOOST_FOREACH(string& zone, mustRectify)
1216 rectifyZone(dk, zone);
1325e8a2
PD
1217
1218 if (zoneErrors) {
1219 return 1;
1220 }
1221 return 0;
1d211b1b 1222 }
da11ed0e 1223 else if(cmds[0]=="set-nsec3") {
37fd8771
BH
1224 if(cmds.size() < 2) {
1225 cerr<<"Syntax: pdnssec set-nsec3 ZONE 'params' [narrow]"<<endl;
1226 return 0;
1227 }
b8adb30d 1228 string nsec3params = cmds.size() > 2 ? cmds[2] : "1 0 1 ab";
22c5aa60 1229 bool narrow = cmds.size() > 3 && cmds[3]=="narrow";
da11ed0e 1230 NSEC3PARAMRecordContent ns3pr(nsec3params);
775acd9e 1231
1232 string zone=cmds[1];
1233 if(!dk.isSecuredZone(zone)) {
1234 cerr<<"Zone '"<<zone<<"' is not secured, can't set NSEC3 parameters"<<endl;
1235 exit(EXIT_FAILURE);
1236 }
1237 dk.setNSEC3PARAM(zone, ns3pr, narrow);
1238
b8adb30d
KM
1239 if (!ns3pr.d_flags)
1240 cerr<<"NSEC3 set, please rectify-zone if your backend needs it"<<endl;
1241 else
1242 cerr<<"NSEC3 (opt-out) set, please rectify-zone if your backend needs it"<<endl;
da11ed0e 1243 }
d3e7090c 1244 else if(cmds[0]=="set-presigned") {
5935cede 1245 if(cmds.size() < 2) {
37fd8771
BH
1246 cerr<<"Syntax: pdnssec set-presigned ZONE"<<endl;
1247 return 0;
5935cede 1248 }
a84a8203
PD
1249 if (! dk.setPresigned(cmds[1])) {
1250 return 1;
1251 }
1252 return 0;
d3e7090c
BH
1253 }
1254 else if(cmds[0]=="unset-presigned") {
37fd8771
BH
1255 if(cmds.size() < 2) {
1256 cerr<<"Syntax: pdnssec unset-presigned ZONE"<<endl;
f60f4bcd 1257 return 0;
37fd8771 1258 }
a84a8203
PD
1259 if (! dk.unsetPresigned(cmds[1])) {
1260 return 1;
1261 }
1262 return 0;
d3e7090c 1263 }
65c87942
BH
1264 else if(cmds[0]=="hash-zone-record") {
1265 if(cmds.size() < 3) {
37fd8771 1266 cerr<<"Syntax: pdnssec hash-zone-record ZONE RNAME"<<endl;
65c87942
BH
1267 return 0;
1268 }
1269 string& zone=cmds[1];
1270 string& record=cmds[2];
1271 NSEC3PARAMRecordContent ns3pr;
1272 bool narrow;
1273 if(!dk.getNSEC3PARAM(zone, &ns3pr, &narrow)) {
1274 cerr<<"The '"<<zone<<"' zone does not use NSEC3"<<endl;
1275 return 0;
1276 }
5e42374c 1277 if(narrow) {
65c87942
BH
1278 cerr<<"The '"<<zone<<"' zone uses narrow NSEC3, but calculating hash anyhow"<<endl;
1279 }
1280
1bad4190 1281 cout<<toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, record))<<endl;
65c87942 1282 }
da11ed0e 1283 else if(cmds[0]=="unset-nsec3") {
37fd8771
BH
1284 if(cmds.size() < 2) {
1285 cerr<<"Syntax: pdnssec unset-nsec3 ZONE"<<endl;
a84a8203 1286 return 0;
37fd8771 1287 }
a84a8203
PD
1288 if ( ! dk.unsetNSEC3PARAM(cmds[1])) {
1289 return 1;
1290 }
1291 return 0;
da11ed0e
BH
1292 }
1293 else if(cmds[0]=="export-zone-key") {
7ddd79a7 1294 if(cmds.size() < 3) {
37fd8771 1295 cerr<<"Syntax: pdnssec export-zone-key ZONE KEY-ID"<<endl;
a84a8203 1296 return 0;
7ddd79a7
BH
1297 }
1298
da11ed0e
BH
1299 string zone=cmds[1];
1300 unsigned int id=atoi(cmds[2].c_str());
1301 DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
189bb9d2 1302 cout << dpk.getKey()->convertToISC() <<endl;
4496f66f 1303 }
04576eed
RA
1304 else if(cmds[0]=="increase-serial") {
1305 if (cmds.size() < 2) {
1306 cerr<<"Syntax: pdnssec increase-serial ZONE"<<endl;
1307 return 0;
1308 }
1309 return increaseSerial(cmds[1], dk);
1310 }
ed3f8559
BH
1311 else if(cmds[0]=="import-zone-key-pem") {
1312 if(cmds.size() < 4) {
4af49b80 1313 cerr<<"Syntax: pdnssec import-zone-key-pem ZONE FILE algorithm [ksk|zsk]"<<endl;
ed3f8559
BH
1314 exit(1);
1315 }
1316 string zone=cmds[1];
1317 string fname=cmds[2];
1318 string line;
1319 ifstream ifs(fname.c_str());
1320 string tmp, interim, raw;
1321 while(getline(ifs, line)) {
1322 if(line[0]=='-')
1323 continue;
1324 trim(line);
1325 interim += line;
1326 }
1327 B64Decode(interim, raw);
1328 DNSSECPrivateKey dpk;
699e6e37 1329 DNSKEYRecordContent drc;
8d9f38f2 1330 shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromPEMString(drc, raw));
699e6e37 1331 dpk.setKey(key);
ed3f8559
BH
1332
1333 dpk.d_algorithm = atoi(cmds[3].c_str());
1334
1335 if(dpk.d_algorithm == 7)
1336 dpk.d_algorithm = 5;
1337
1338 cerr<<(int)dpk.d_algorithm<<endl;
1339
1340 if(cmds.size() > 4) {
1341 if(pdns_iequals(cmds[4], "ZSK"))
1342 dpk.d_flags = 256;
1343 else if(pdns_iequals(cmds[4], "KSK"))
1344 dpk.d_flags = 257;
1345 else {
1346 cerr<<"Unknown key flag '"<<cmds[4]<<"'\n";
1347 exit(1);
1348 }
1349 }
1350 else
1351 dpk.d_flags = 257; // ksk
1352
07bf35d1 1353 if(!dk.addKey(zone, dpk)) {
1354 cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
1355 exit(1);
1356 }
ed3f8559
BH
1357
1358 }
976b6541 1359 else if(cmds[0]=="import-zone-key") {
d1eacbeb 1360 if(cmds.size() < 3) {
4af49b80 1361 cerr<<"Syntax: pdnssec import-zone-key ZONE FILE [ksk|zsk] [active|passive]"<<endl;
4496f66f
BH
1362 exit(1);
1363 }
976b6541
BH
1364 string zone=cmds[1];
1365 string fname=cmds[2];
1366 DNSSECPrivateKey dpk;
699e6e37 1367 DNSKEYRecordContent drc;
8d9f38f2 1368 shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromISCFile(drc, fname.c_str()));
699e6e37 1369 dpk.setKey(key);
7ddd79a7
BH
1370 dpk.d_algorithm = drc.d_algorithm;
1371
1372 if(dpk.d_algorithm == 7)
1373 dpk.d_algorithm = 5;
aa952078 1374
4af49b80 1375 dpk.d_flags = 257;
4cec6ac5 1376 bool active=true;
4af49b80 1377
1378 for(unsigned int n = 3; n < cmds.size(); ++n) {
1379 if(pdns_iequals(cmds[n], "ZSK"))
1380 dpk.d_flags = 256;
1381 else if(pdns_iequals(cmds[n], "KSK"))
1382 dpk.d_flags = 257;
1383 else if(pdns_iequals(cmds[n], "active"))
1384 active = 1;
1385 else if(pdns_iequals(cmds[n], "passive") || pdns_iequals(cmds[n], "inactive"))
1386 active = 0;
1387 else {
1388 cerr<<"Unknown key flag '"<<cmds[n]<<"'\n";
1389 exit(1);
1390 }
aa952078 1391 }
07bf35d1 1392 if(!dk.addKey(zone, dpk, active)) {
1393 cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
1394 exit(1);
1395 }
976b6541 1396 }
da11ed0e 1397 else if(cmds[0]=="export-zone-dnskey") {
7ddd79a7 1398 if(cmds.size() < 3) {
37fd8771 1399 cerr<<"Syntax: pdnssec export-zone-dnskey ZONE KEY-ID"<<endl;
7ddd79a7
BH
1400 exit(1);
1401 }
1402
da11ed0e
BH
1403 string zone=cmds[1];
1404 unsigned int id=atoi(cmds[2].c_str());
1405 DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
1406 cout << zone<<" IN DNSKEY "<<dpk.getDNSKEY().getZoneRepresentation() <<endl;
f8b25763
BH
1407 if(dpk.d_flags == 257) {
1408 cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 1).getZoneRepresentation() << endl;
1409 cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 2).getZoneRepresentation() << endl;
1410 }
da11ed0e 1411 }
950bdddf
PD
1412 else if(cmds[0] == "generate-zone-key") {
1413 if(cmds.size() < 2 ) {
7e5b2860 1414 cerr << "Syntax: pdnssec generate-zone-key zsk|ksk [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384] [bits]"<<endl;
950bdddf
PD
1415 return 0;
1416 }
1417 // need to get algorithm, bits & ksk or zsk from commandline
1418 bool keyOrZone=false;
1419 int tmp_algo=0;
1420 int bits=0;
1421 int algorithm=8;
1422 for(unsigned int n=1; n < cmds.size(); ++n) {
1423 if(pdns_iequals(cmds[n], "zsk"))
1424 keyOrZone = false;
1425 else if(pdns_iequals(cmds[n], "ksk"))
1426 keyOrZone = true;
1427 else if((tmp_algo = shorthand2algorithm(cmds[n]))>0) {
1428 algorithm = tmp_algo;
1429 } else if(atoi(cmds[n].c_str()))
1430 bits = atoi(cmds[n].c_str());
1431 else {
1432 cerr<<"Unknown algorithm, key flag or size '"<<cmds[n]<<"'"<<endl;
1433 return 0;
1434 }
1435 }
1436 cerr<<"Generating a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "<<algorithm<<endl;
1437 if(bits)
1438 cerr<<"Requesting specific key size of "<<bits<<" bits"<<endl;
1439
1440 DNSSECPrivateKey dspk;
1441 shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(algorithm)); // defaults to RSA for now, could be smart w/algorithm! XXX FIXME
1442 if(!bits) {
1443 if(algorithm <= 10)
1444 bits = keyOrZone ? 2048 : 1024;
1445 else {
1446 if(algorithm == 12 || algorithm == 13 || algorithm == 250) // ECDSA, GOST, ED25519
1447 bits = 256;
1448 else if(algorithm == 14)
1449 bits = 384;
1450 else {
1451 throw runtime_error("Can't guess key size for algoritm "+lexical_cast<string>(algorithm));
1452 }
1453 }
1454 }
1455 dpk->create(bits);
1456 dspk.setKey(dpk);
1457 dspk.d_algorithm = algorithm;
1458 dspk.d_flags = keyOrZone ? 257 : 256;
1459
1460 // print key to stdout
1461 cout << "Flags: " << dspk.d_flags << endl <<
1462 dspk.getKey()->convertToISC() << endl;
4831df57 1463 } else if (cmds[0]=="create-tsig-key") {
6f872b78
AT
1464 if (cmds.size() < 3) {
1465 cerr << "Syntax: " << cmds[0] << " name (hmac-md5|hmac-sha1|hmac-sha224|hmac-sha256|hmac-sha384|hmac-sha512)" << endl;
1466 return 0;
1467 }
1468 string name = cmds[1];
1469 string algo = cmds[2];
1470 string key;
1471 char tmpkey[64];
1472
d885cea7 1473 size_t klen = 0;
6f872b78
AT
1474 if (algo == "hmac-md5") {
1475 klen = 32;
1476 } else if (algo == "hmac-sha1") {
1477 klen = 32;
1478 } else if (algo == "hmac-sha224") {
1479 klen = 32;
1480 } else if (algo == "hmac-sha256") {
1481 klen = 64;
1482 } else if (algo == "hmac-sha384") {
1483 klen = 64;
1484 } else if (algo == "hmac-sha512") {
1485 klen = 64;
d885cea7
AT
1486 } else {
1487 cerr << "Cannot generate key for " << algo << endl;
1488 return 1;
6f872b78
AT
1489 }
1490
7e5b2860
AT
1491 cerr << "Generating new key with " << klen << " bytes (this can take a while)" << endl;
1492
6f872b78
AT
1493 ifstream keyin("/dev/random", ifstream::in|ifstream::binary);
1494 // read and hash data
1495 keyin.read(tmpkey, klen);
1496 key = Base64Encode(std::string(tmpkey, klen));
1497
1498 UeberBackend B("default");
1499 if (B.setTSIGKey(name, algo, key)) {
1500 cout << "Create new TSIG key " << name << " " << algo << " " << key << endl;
1501 } else {
1502 cout << "Failure storing new TSIG key " << name << " " << algo << " " << key << endl;
1503 return 1;
1504 }
1505 return 0;
1506 } else if (cmds[0]=="import-tsig-key") {
1507 if (cmds.size() < 4) {
1508 cerr << "Syntax: " << cmds[0] << " name algorithm key" << endl;
1509 return 0;
1510 }
1511 string name = cmds[1];
1512 string algo = cmds[2];
1513 string key = cmds[3];
1514
1515 UeberBackend B("default");
1516 if (B.setTSIGKey(name, algo, key)) {
1517 cout << "Imported TSIG key " << name << " " << algo << endl;
1518 } else {
1519 cout << "Failure importing TSIG key " << name << " " << algo << endl;
1520 return 1;
1521 }
1522 return 0;
1523 } else if (cmds[0]=="delete-tsig-key") {
1524 if (cmds.size() < 2) {
1525 cerr << "Syntax: " << cmds[0] << " name" << endl;
1526 return 0;
1527 }
1528 string name = cmds[1];
1529 string algo = cmds[2];
1530
1531 UeberBackend B("default");
1532 if (B.deleteTSIGKey(name)) {
1533 cout << "Deleted TSIG key " << name << endl;
1534 } else {
1535 cout << "Failure deleting TSIG key " << name << endl;
1536 return 1;
1537 }
1538 return 0;
1539 } else if (cmds[0]=="list-tsig-keys") {
1540 std::vector<struct TSIGKey> keys;
1541 UeberBackend B("default");
1542 if (B.getTSIGKeys(keys)) {
1543 BOOST_FOREACH(const struct TSIGKey &key, keys) {
1544 cout << key.name << " " << key.algorithm << " " << key.key << endl;
1545 }
1546 }
1547 return 0;
1548 } else if (cmds[0]=="enable-tsig-key") {
4831df57
AT
1549 string metaKey;
1550 if (cmds.size() < 4) {
1551 cerr << "Syntax: " << cmds[0] << " zone name [master|slave]" << endl;
6f872b78
AT
1552 return 0;
1553 }
1554 string zname = cmds[1];
1555 string name = cmds[2];
4831df57
AT
1556 if (cmds[3] == "master")
1557 metaKey = "TSIG-ALLOW-AXFR";
1558 else if (cmds[3] == "slave")
1559 metaKey = "AXFR-MASTER-TSIG";
1560 else {
1561 cerr << "Invalid parameter '" << cmds[3] << "', expected master or slave" << endl;
1562 return 1;
1563 }
6f872b78
AT
1564 UeberBackend B("default");
1565 std::vector<std::string> meta;
4831df57 1566 if (!B.getDomainMetadata(zname, metaKey, meta)) {
6f872b78
AT
1567 cout << "Failure enabling TSIG key " << name << " for " << zname << endl;
1568 return 1;
1569 }
1570 bool found = false;
1571 BOOST_FOREACH(std::string tmpname, meta) {
1572 if (tmpname == name) { found = true; break; }
1573 }
1574 if (!found) meta.push_back(name);
4831df57 1575 if (B.setDomainMetadata(zname, metaKey, meta)) {
6f872b78
AT
1576 cout << "Enabled TSIG key " << name << " for " << zname << endl;
1577 } else {
1578 cout << "Failure enabling TSIG key " << name << " for " << zname << endl;
1579 return 1;
1580 }
1581 return 0;
1582 } else if (cmds[0]=="disable-tsig-key") {
4831df57
AT
1583 string metaKey;
1584 if (cmds.size() < 4) {
1585 cerr << "Syntax: " << cmds[0] << " zone name [master|slave]" << endl;
6f872b78
AT
1586 return 0;
1587 }
1588 string zname = cmds[1];
1589 string name = cmds[2];
4831df57
AT
1590 if (cmds[3] == "master")
1591 metaKey = "TSIG-ALLOW-AXFR";
1592 else if (cmds[3] == "slave")
1593 metaKey = "AXFR-MASTER-TSIG";
1594 else {
1595 cerr << "Invalid parameter '" << cmds[3] << "', expected master or slave" << endl;
1596 return 1;
1597 }
6f872b78
AT
1598
1599 UeberBackend B("default");
1600 std::vector<std::string> meta;
4831df57 1601 if (!B.getDomainMetadata(zname, metaKey, meta)) {
6f872b78
AT
1602 cout << "Failure disabling TSIG key " << name << " for " << zname << endl;
1603 return 1;
1604 }
1605 std::vector<std::string>::iterator iter = meta.begin();
1606 for(;iter != meta.end(); iter++) if (*iter == name) break;
1607 if (iter != meta.end()) meta.erase(iter);
4831df57 1608 if (B.setDomainMetadata(zname, metaKey, meta)) {
6f872b78
AT
1609 cout << "Disabled TSIG key " << name << " for " << zname << endl;
1610 } else {
1611 cout << "Failure disabling TSIG key " << name << " for " << zname << endl;
1612 return 1;
1613 }
1614 return 0;
950bdddf 1615 }
1d211b1b 1616 else {
6f872b78 1617 cerr<<"Unknown command '"<<cmds[0] << endl;
1d211b1b
BH
1618 return 1;
1619 }
1620 return 0;
1621}
3f81d239 1622catch(PDNSException& ae) {
20002664
BH
1623 cerr<<"Error: "<<ae.reason<<endl;
1624}
14133ba3
BH
1625catch(std::exception& e) {
1626 cerr<<"Error: "<<e.what()<<endl;
1627}
46d2e0d6 1628