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