root/trunk/pdns/pdns/pdnssec.cc @ 2221

Revision 2221, 26.1 KB (checked in by ahu, 2 years ago)

someone anonymous contributed this patch, thanks!

- Fix up spelling mistake - remove keys when using disable-dnssec - Fix
- formatting of help - Do better checking of arguments given to commands -
- When adding a key don't activate it initially.

Line 
1#include "dnsseckeeper.hh"
2#include "dnssecinfra.hh"
3#include "statbag.hh"
4#include "base32.hh"
5#include "base64.hh"
6#include <boost/foreach.hpp>
7#include <boost/program_options.hpp>
8#include "dnsbackend.hh"
9#include "ueberbackend.hh"
10#include "arguments.hh"
11#include "packetcache.hh"
12#include "zoneparser-tng.hh"
13#include "signingpipe.hh"
14#include <boost/scoped_ptr.hpp>
15
16StatBag S;
17PacketCache PC;
18
19using boost::scoped_ptr;
20namespace po = boost::program_options;
21po::variables_map g_vm;
22
23string s_programname="pdns";
24
25#if 0
26void launchSigningService(int fd)
27{
28  UeberBackend db("key-only");
29  DNSSECKeeper dk;
30  string str;
31  vector<DNSResourceRecord> chunk;
32  uint64_t signatures=0;
33  while(readLStringFromSocket(fd, str))
34  {
35    if(str.empty())
36      break;
37    chunk=convertDNSRRVectorFromPBString(str);
38 
39    addRRSigs(dk, db, "big.aa", chunk); // sucks
40 
41    ++signatures;
42    str=convertDNSRRVectorToPBString(chunk);
43    writeLStringToSocket(fd, str);   
44  }
45  cerr<<"Exiting after "<<signatures<<" signatures"<<endl;
46  char c;
47  //read(fd, &c, 1); // wait for EOF, signifies that the other side received everything
48  _exit(1);
49}
50
51void signingServer()
52{
53  ComboAddress local("::", 2000);
54  int sock = socket(AF_INET6, SOCK_STREAM, 0);
55 
56  setSocketReusable(sock);
57  if(::bind(sock, (struct sockaddr*)&local, local.getSocklen()) < 0)
58    unixDie("Binding signing server to socket");
59  listen(sock, 5);
60  for(;;) {
61    ComboAddress remote("::");
62    socklen_t remotelen = remote.getSocklen();
63    int client = accept(sock, (struct sockaddr*)&remote, &remotelen);
64   
65    if(client < 0)
66      break;
67    cerr<<"Got connection from "<<remote.toString()<<endl; 
68    if(fork())
69      continue;
70    launchSigningService(client);
71  }
72}
73#endif
74
75ArgvMap &arg()
76{
77  static ArgvMap arg;
78  return arg;
79}
80
81string humanTime(time_t t)
82{
83  char ret[256];
84  struct tm tm;
85  localtime_r(&t, &tm);
86  strftime(ret, sizeof(ret)-1, "%c", &tm);   // %h:%M %Y-%m-%d
87  return ret;
88}
89
90void loadMainConfig(const std::string& configdir)
91{
92  ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=configdir;
93 
94  ::arg().set("launch","Which backends to launch");
95  ::arg().set("dnssec","if we should do dnssec")="true";
96  ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")=g_vm["config-name"].as<string>();
97  ::arg().setCmd("help","Provide a helpful message");
98  //::arg().laxParse(argc,argv);
99
100  if(::arg().mustDo("help")) {
101    cerr<<"syntax:"<<endl<<endl;
102    cerr<<::arg().helpstring(::arg()["help"])<<endl;
103    exit(99);
104  }
105
106  if(::arg()["config-name"]!="") 
107    s_programname+="-"+::arg()["config-name"];
108
109  string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
110  cleanSlashes(configname);
111 
112  ::arg().laxFile(configname.c_str());
113  ::arg().set("module-dir","Default directory for modules")=LIBDIR;
114  BackendMakers().launch(::arg()["launch"]); // vrooooom!
115  ::arg().laxFile(configname.c_str());   
116  //cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" <<endl;
117
118  S.declare("qsize-q","Number of questions waiting for database attention");
119   
120  S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
121  S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
122         
123  S.declare("query-cache-hit","Number of hits on the query cache");
124  S.declare("query-cache-miss","Number of misses on the query cache");
125  ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
126  ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no"; 
127  ::arg().set("recursive-cache-ttl","Seconds to store packets in the PacketCache")="10";
128  ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";             
129  ::arg().set("negquery-cache-ttl","Seconds to store packets in the PacketCache")="60";
130  ::arg().set("query-cache-ttl","Seconds to store packets in the PacketCache")="20";             
131  ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
132  ::arg().set("soa-retry-default","Default SOA retry")="3600";
133  ::arg().set("soa-expire-default","Default SOA expire")="604800";
134    ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
135  ::arg().set("soa-minimum-ttl","Default SOA mininum ttl")="3600";   
136 
137  UeberBackend::go();
138}
139
140// irritatingly enough, rectifyZone needs its own ueberbackend and can't therefore benefit from transactions outside its scope
141void rectifyZone(DNSSECKeeper& dk, const std::string& zone)
142{
143  scoped_ptr<UeberBackend> B(new UeberBackend("default"));
144  bool doTransaction=true; // but see above
145  SOAData sd;
146 
147  if(!B->getSOA(zone, sd)) {
148    cerr<<"No SOA known for '"<<zone<<"', is such a zone in the database?"<<endl;
149    return;
150  } 
151  sd.db->list(zone, sd.domain_id);
152  DNSResourceRecord rr;
153
154  set<string> qnames, nsset;
155 
156  while(sd.db->get(rr)) {
157    qnames.insert(rr.qname);
158    if(rr.qtype.getCode() == QType::NS && !pdns_iequals(rr.qname, zone)) 
159      nsset.insert(rr.qname);
160  }
161
162  NSEC3PARAMRecordContent ns3pr;
163  bool narrow;
164  bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
165  string hashed;
166  if(!haveNSEC3) 
167    cerr<<"Adding NSEC ordering information"<<endl;
168  else if(!narrow)
169    cerr<<"Adding NSEC3 hashed ordering information for '"<<zone<<"'"<<endl;
170  else 
171    cerr<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields"<<endl;
172 
173  if(doTransaction)
174    sd.db->startTransaction("", -1);
175  BOOST_FOREACH(const string& qname, qnames)
176  {
177    string shorter(qname);
178    bool auth=true;
179    do {
180      if(nsset.count(shorter)) { 
181        auth=false;
182        break;
183      }
184    }while(chopOff(shorter));
185
186    if(!haveNSEC3) // NSEC
187      sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, qname, auth);
188    else {
189      if(!narrow) {
190        hashed=toLower(toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, qname)));
191        cerr<<"'"<<qname<<"' -> '"<< hashed <<"'"<<endl;
192      }
193      sd.db->updateDNSSECOrderAndAuthAbsolute(sd.domain_id, qname, hashed, auth);
194    }
195  }
196  if(doTransaction)
197    sd.db->commitTransaction();
198}
199
200int checkZone(DNSSECKeeper& dk, const std::string& zone)
201{
202  scoped_ptr<UeberBackend> B(new UeberBackend("default"));
203  SOAData sd;
204 
205  if(!B->getSOA(zone, sd)) {
206    cout<<"No SOA for zone '"<<zone<<"'"<<endl;
207    return -1;
208  } 
209  sd.db->list(zone, sd.domain_id);
210  DNSResourceRecord rr;
211  uint64_t numrecords=0, numerrors=0;
212 
213  while(sd.db->get(rr)) {
214    if(rr.qtype.getCode() == QType::URL || rr.qtype.getCode() == QType::MBOXFW) 
215      continue;
216    if(rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) 
217      rr.content = lexical_cast<string>(rr.priority)+" "+rr.content;
218    if(rr.qtype.getCode() == QType::TXT && !rr.content.empty() && rr.content[0]!='"')
219      rr.content = "\""+rr.content+"\""; 
220     
221    if(rr.auth == 0 && rr.qtype.getCode()!=QType::NS && rr.qtype.getCode()!=QType::A)
222    {
223      cout<<"Following record is auth=0, run pdnssec rectify-zone?: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
224      numerrors++;
225    }
226    try {
227      shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content));
228      string tmp=drc->serialize(rr.qname);
229    }
230    catch(std::exception& e) 
231    {
232      cout<<"Following record had a problem: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
233      cout<<"Error was: "<<e.what()<<endl;
234      numerrors++;
235    }
236    numrecords++;
237  }
238  cout<<"Checked "<<numrecords<<" records of '"<<zone<<"', "<<numerrors<<" errors"<<endl;
239  return numerrors;
240}
241
242void testAlgorithms()
243{
244  DNSCryptoKeyEngine::testAll();
245}
246
247void testSpeed(DNSSECKeeper& dk, const string& zone, const string& remote, int cores)
248{
249  DNSResourceRecord rr;
250  rr.qname="blah."+zone;
251  rr.qtype=QType::A;
252  rr.ttl=3600;
253  rr.auth=1;
254  rr.qclass = 1;
255  rr.d_place=DNSResourceRecord::ANSWER;
256  rr.priority=0;
257 
258  UeberBackend db("key-only");
259 
260  ChunkedSigningPipe csp(zone, 1, remote, cores);
261 
262  vector<DNSResourceRecord> signatures;
263  uint32_t rnd;
264  unsigned char* octets = (unsigned char*)&rnd;
265  char tmp[25];
266  DTime dt;
267  dt.set();
268  for(unsigned int n=0; n < 100000; ++n) {
269    rnd = random();
270    snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", 
271      octets[0], octets[1], octets[2], octets[3]);
272    rr.content=tmp;
273   
274    snprintf(tmp, sizeof(tmp), "r-%u", rnd);
275    rr.qname=string(tmp)+"."+zone;
276   
277    if(csp.submit(rr))
278      while(signatures = csp.getChunk(), !signatures.empty())
279        ;
280  }
281  cerr<<"Flushing the pipe, "<<csp.d_signed<<" signed, "<<csp.d_queued<<" queued, "<<csp.d_outstanding<<" outstanding"<< endl;
282  cerr<<"Net speed: "<<csp.d_signed/ (dt.udiffNoReset()/1000000.0) << " sigs/s\n";
283  while(signatures = csp.getChunk(true), !signatures.empty())
284      ;
285  cerr<<"Done, "<<csp.d_signed<<" signed, "<<csp.d_queued<<" queued, "<<csp.d_outstanding<<" outstanding"<< endl;
286  cerr<<"Net speed: "<<csp.d_signed/ (dt.udiff()/1000000.0) << " sigs/s\n";
287}
288
289void verifyCrypto(const string& zone)
290{
291  ZoneParserTNG zpt(zone);
292  DNSResourceRecord rr;
293  DNSKEYRecordContent drc;
294  RRSIGRecordContent rrc;
295  DSRecordContent dsrc;
296  vector<shared_ptr<DNSRecordContent> > toSign;
297  unsigned int ttl;
298  string qname, apex;
299  dsrc.d_digesttype=0;
300  while(zpt.get(rr)) {
301    if(rr.qtype.getCode() == QType::DNSKEY) {
302      cerr<<"got DNSKEY!"<<endl;
303      apex=rr.qname;
304      drc = *dynamic_cast<DNSKEYRecordContent*>(DNSRecordContent::mastermake(QType::DNSKEY, 1, rr.content));
305    }
306    else if(rr.qtype.getCode() == QType::RRSIG) {
307      cerr<<"got RRSIG"<<endl;
308      rrc = *dynamic_cast<RRSIGRecordContent*>(DNSRecordContent::mastermake(QType::RRSIG, 1, rr.content));
309    }
310    else if(rr.qtype.getCode() == QType::DS) {
311      cerr<<"got DS"<<endl;
312      dsrc = *dynamic_cast<DSRecordContent*>(DNSRecordContent::mastermake(QType::DS, 1, rr.content));
313    }
314    else {
315      qname = rr.qname;
316      ttl = rr.ttl;
317      toSign.push_back(shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)));
318    }
319  }
320 
321  string msg = getMessageForRRSET(qname, rrc, toSign);       
322  cerr<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc.d_algorithm, drc.d_key)->verify(msg, rrc.d_signature)<<endl;
323  if(dsrc.d_digesttype) {
324    cerr<<"Calculated DS: "<<apex<<" IN DS "<<makeDSFromDNSKey(apex, drc, dsrc.d_digesttype).getZoneRepresentation()<<endl;
325    cerr<<"Original DS:   "<<apex<<" IN DS "<<dsrc.getZoneRepresentation()<<endl;
326  }
327#if 0
328  DNSCryptoKeyEngine*key=DNSCryptoKeyEngine::makeFromISCString(drc, "Private-key-format: v1.2\n"
329      "Algorithm: 12 (ECC-GOST)\n"
330      "GostAsn1: MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgQg/9MiXtXKg9FDXDN/R9CmVhJDyuzRAIgh4tPwCu4NHIs=\n");
331  string resign=key->sign(hash);
332  cerr<<Base64Encode(resign)<<endl;
333  cerr<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc.d_algorithm, drc.d_key)->verify(hash, resign)<<endl;
334#endif
335
336}
337void disableDNSSECOnZone(DNSSECKeeper& dk, const string& zone)
338{
339  if(!dk.isSecuredZone(zone)) {
340    cerr<<"Zone is not secured\n";
341    return;
342  }
343  DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
344
345  if(keyset.empty())  {
346    cerr << "No keys for zone '"<<zone<<"'."<<endl;
347  }
348  else { 
349    BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
350      dk.deactivateKey(zone, value.second.id);
351      dk.removeKey(zone, value.second.id);
352    }
353  }
354  dk.unsetNSEC3PARAM(zone);
355  dk.unsetPresigned(zone);
356}
357void showZone(DNSSECKeeper& dk, const std::string& zone)
358{
359  if(!dk.isSecuredZone(zone)) {
360    cerr<<"Zone is not secured\n";
361    return;
362  }
363  NSEC3PARAMRecordContent ns3pr;
364  bool narrow;
365  bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
366 
367  if(!haveNSEC3) 
368    cout<<"Zone has NSEC semantics"<<endl;
369  else
370    cout<<"Zone has " << (narrow ? "NARROW " : "") <<"hashed NSEC3 semantics, configuration: "<<ns3pr.getZoneRepresentation()<<endl;
371 
372  cout <<"Zone is " << (dk.isPresigned(zone) ? "" : "not ") << "presigned\n";
373 
374  DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
375
376  if(keyset.empty())  {
377    cerr << "No keys for zone '"<<zone<<"'."<<endl;
378  }
379  else { 
380    cout << "keys: "<<endl;
381    BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
382      cout<<"ID = "<<value.second.id<<" ("<<(value.second.keyOrZone ? "KSK" : "ZSK")<<"), tag = "<<value.first.getDNSKEY().getTag();
383      cout<<", algo = "<<(int)value.first.d_algorithm<<", bits = "<<value.first.getKey()->getBits()<<"\tActive: "<<value.second.active<< endl; 
384      if(value.second.keyOrZone) {
385        cout<<"KSK DNSKEY = "<<zone<<" IN DNSKEY "<< value.first.getDNSKEY().getZoneRepresentation() << endl;
386        cout<<"DS = "<<zone<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 1).getZoneRepresentation() << endl;
387        cout<<"DS = "<<zone<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 2).getZoneRepresentation() << endl;
388        try {
389          string output=makeDSFromDNSKey(zone, value.first.getDNSKEY(), 3).getZoneRepresentation();
390          cout<<"DS = "<<zone<<" IN DS "<< output << endl;
391        }
392        catch(...)
393        {
394        }
395        cout<<endl; 
396      }
397    }
398  }
399}
400
401bool secureZone(DNSSECKeeper& dk, const std::string& zone)
402{
403        if(dk.isSecuredZone(zone)) {
404                cerr << "Zone '"<<zone<<"' already secure, remove keys with pdnssec remove-zone-key if needed"<<endl;
405                return false;
406        }
407
408        if(!dk.secureZone(zone, 8)) {
409                cerr<<"No backend was able to secure '"<<zone<<"', most likely because no DNSSEC\n";
410                cerr<<"capable backends are loaded, or because the backends have DNSSEC disabled.\n";
411                cerr<<"For the Generic SQL backends, set 'gsqlite3-dnssec' or 'gmysql-dnssec' or\n";
412                cerr<<"'gpgsql-dnssec' etc. Also make sure the schema has been updated for DNSSEC!\n";
413                return false;
414        }
415
416        if(!dk.isSecuredZone(zone)) {
417                cerr<<"Failed to secure zone. Is your backend dnssec enabled? (set \n";
418                cerr<<"sqlite3-dnssec, or gmysql-dnssec etc). Check this first.\n";
419                cerr<<"If you run with the BIND backend, make sure to also launch another\n";
420                cerr<<"backend which supports storage of DNSSEC settings.\n";
421                cerr<<"In addition, add '"<<zone<<"' to this backend, possibly like this: \n\n";
422                cerr<<"   insert into domains (name, type) values ('"<<zone<<"', 'NATIVE');\n\n";
423                cerr<<"And then rerun secure-zone"<<endl;
424                return false;
425        }
426
427        DNSSECKeeper::keyset_t zskset=dk.getKeys(zone, false);
428
429        if(!zskset.empty())  {
430                cerr<<"There were ZSKs already for zone '"<<zone<<"', no need to add more"<<endl;
431                return false;
432        }
433               
434        dk.addKey(zone, false, 8);
435        dk.addKey(zone, false, 8, 0, false); // not active
436        // rectifyZone(dk, zone);
437        // showZone(dk, zone);
438        cout<<"Zone "<<zone<<" secured"<<endl;
439  return true;
440}
441
442int main(int argc, char** argv)
443try
444{ 
445  po::options_description desc("Allowed options");
446  desc.add_options()
447    ("help,h", "produce help message")
448    ("verbose,v", po::value<bool>(), "be verbose")
449    ("force", "force an action")
450    ("config-name", po::value<string>()->default_value(""), "virtual configuration name")
451    ("config-dir", po::value<string>()->default_value(SYSCONFDIR), "location of pdns.conf")
452    ("commands", po::value<vector<string> >());
453
454  po::positional_options_description p;
455  p.add("commands", -1);
456  po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), g_vm);
457  po::notify(g_vm);
458
459  vector<string> cmds;
460
461  if(g_vm.count("commands")) 
462    cmds = g_vm["commands"].as<vector<string> >();
463
464  if(cmds.empty() || g_vm.count("help")) {
465    cerr<<"Usage: \npdnssec [options] [show-zone] [secure-zone] [rectify-zone] [add-zone-key] [deactivate-zone-key] [remove-zone-key] [activate-zone-key]\n";
466    cerr<<"         [import-zone-key] [export-zone-key] [set-nsec3] [set-presigned] [unset-nsec3] [unset-presigned] [export-zone-dnskey]\n\n";
467    cerr<<"activate-zone-key ZONE KEY-ID    Activate the key with key id KEY-ID in ZONE\n";
468    cerr<<"add-zone-key ZONE [zsk|ksk]      Add a ZSK or KSK to a zone\n";
469    cerr<<"  [bits] [rsasha1|rsasha256]     and specify algorithm & bits\n";
470    cerr<<"check-zone ZONE                  Check a zone for correctness\n";
471    cerr<<"deactivate-zone-key ZONE KEY-ID  Deactivate the key with key id KEY-ID in ZONE\n";
472    cerr<<"disable-dnssec ZONE              Deactivate all keys and unset PRESIGNED in ZONE\n";
473    cerr<<"export-zone-dnskey ZONE KEY-ID   Export to stdout the public DNSKEY described\n";
474    cerr<<"export-zone-key ZONE KEY-ID      Export to stdout the private key described\n";
475    cerr<<"hash-zone-record ZONE RNAME      Calculate the NSEC3 hash for RNAME in ZONE\n";
476    cerr<<"import-zone-key ZONE FILE        Import from a file a private key, ZSK or KSK\n";           
477    cerr<<"                [ksk|zsk]        Defaults to KSK\n";
478    cerr<<"rectify-zone ZONE                Fix up DNSSEC fields (order, auth)\n";
479    cerr<<"remove-zone-key ZONE KEY-ID      Remove key with KEY-ID from ZONE\n";
480    cerr<<"secure-zone ZONE                 Add KSK and two ZSKs\n";
481    cerr<<"set-nsec3 ZONE 'params' [narrow] Enable NSEC3 with PARAMs. Optionally narrow\n";
482    cerr<<"set-presigned ZONE               Use presigned RRSIGs from storage\n";
483    cerr<<"show-zone ZONE                   Show DNSSEC (public) key details about a zone\n";
484    cerr<<"unset-nsec3 ZONE                 Switch back to NSEC\n";
485    cerr<<"unset-presigned ZONE             No longer use presigned RRSIGs\n\n";
486    cerr<<"Options:"<<endl;
487    cerr<<desc<<endl;
488    return 0;
489  }
490 
491  if(cmds[0] == "test-algorithms") {
492    testAlgorithms();
493    return 0;
494  }
495
496  loadMainConfig(g_vm["config-dir"].as<string>());
497  reportAllTypes();
498  DNSSECKeeper dk;
499
500  if(cmds[0] == "rectify-zone") {
501    if(cmds.size() != 2) {
502      cerr << "Syntax: pdnssec rectify-zone ZONE"<<endl;
503      return 0;
504    }
505    rectifyZone(dk, cmds[1]);
506  }
507  else if(cmds[0] == "check-zone") {
508    if(cmds.size() != 2) {
509      cerr << "Syntax: pdnssec check-zone ZONE"<<endl;
510      return 0;
511    }
512    exit(checkZone(dk, cmds[1]));
513  }
514#if 0
515  else if(cmds[0] == "signing-server" )
516  {
517    signingServer();
518  }
519  else if(cmds[0] == "signing-slave")
520  {
521    launchSigningService(0);
522  }
523#endif
524  else if(cmds[0] == "test-speed") {
525    if(cmds.size() < 2) {
526      cerr << "Syntax: pdnssec test-speed numcores [signing-server]"<<endl;
527      return 0;
528    }
529    testSpeed(dk, cmds[1],  (cmds.size() > 3) ? cmds[3] : "", atoi(cmds[2].c_str()));
530  }
531  else if(cmds[0] == "verify-crypto") {
532    if(cmds.size() != 2) {
533      cerr << "Syntax: pdnssec verify-crypto FILE"<<endl;
534      return 0;
535    }
536    verifyCrypto(cmds[1]);
537  }
538
539  else if(cmds[0] == "show-zone") {
540    if(cmds.size() != 2) {
541      cerr << "Syntax: pdnssec show-zone ZONE"<<endl;
542      return 0;
543    }
544    const string& zone=cmds[1];
545    showZone(dk, zone);
546  }
547  else if(cmds[0] == "disable-dnssec") {
548    if(cmds.size() != 2) {
549      cerr << "Syntax: pdnssec disable-dnssec ZONE"<<endl;
550      return 0;
551    }
552    const string& zone=cmds[1];
553    disableDNSSECOnZone(dk, zone);
554  }
555  else if(cmds[0] == "activate-zone-key") {
556    if(cmds.size() != 3) {
557      cerr << "Syntax: pdnssec activate-zone-key ZONE KEY-ID"<<endl;
558      return 0;
559    }
560    const string& zone=cmds[1];
561    unsigned int id=atoi(cmds[2].c_str());
562    dk.activateKey(zone, id);
563  }
564  else if(cmds[0] == "deactivate-zone-key") {
565    if(cmds.size() != 3) {
566      cerr << "Syntax: pdnssec deactivate-zone-key ZONE KEY-ID"<<endl;
567      return 0;
568    }
569    const string& zone=cmds[1];
570    unsigned int id=atoi(cmds[2].c_str());
571    dk.deactivateKey(zone, id);
572  }
573  else if(cmds[0] == "add-zone-key") {
574    if(cmds.size() < 3 ) {
575      cerr << "Syntax: pdnssec add-zone-key ZONE [zsk|ksk] [bits] [rsasha1|rsasha256]"<<endl;
576      return 0;
577    }
578    const string& zone=cmds[1];
579    // need to get algorithm, bits & ksk or zsk from commandline
580    bool keyOrZone=false;
581    int bits=0;
582    int algorithm=5;
583    for(unsigned int n=2; n < cmds.size(); ++n) {
584      if(pdns_iequals(cmds[n], "zsk"))
585        keyOrZone = false;
586      else if(pdns_iequals(cmds[n], "ksk"))
587        keyOrZone = true;
588      else if(pdns_iequals(cmds[n], "rsasha1"))
589        algorithm=5;
590      else if(pdns_iequals(cmds[n], "rsasha256"))
591        algorithm=8;
592      else if(pdns_iequals(cmds[n], "rsasha512"))
593        algorithm=10;
594      else if(pdns_iequals(cmds[n], "gost"))
595        algorithm=12;
596      else if(pdns_iequals(cmds[n], "ecdsa256"))
597        algorithm=13;
598      else if(pdns_iequals(cmds[n], "ecdsa384"))
599        algorithm=14;
600      else if(atoi(cmds[n].c_str()))
601        bits = atoi(cmds[n].c_str());
602      else { 
603        cerr<<"Unknown algorithm, key flag or size '"<<cmds[n]<<"'"<<endl;
604        return 0;
605      }
606    }
607    cerr<<"Adding a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "<<algorithm<<endl;
608    if(bits)
609      cerr<<"Requesting specific key size of "<<bits<<" bits"<<endl;
610    dk.addKey(zone, keyOrZone, algorithm, bits, false); 
611  }
612  else if(cmds[0] == "remove-zone-key") {
613    if(cmds.size() < 3) {
614      cerr<<"Syntax: pdnssec remove-zone-key ZONE KEY-ID";
615      return 0;
616    }
617    const string& zone=cmds[1];
618    unsigned int id=atoi(cmds[2].c_str());
619    dk.removeKey(zone, id);
620  }
621 
622  else if(cmds[0] == "secure-zone") {
623    if(cmds.size() < 2) {
624      cerr << "Syntax: pdnssec secure-zone ZONE"<<endl;
625      return 0;
626    }
627    vector<string> mustRectify;
628    dk.startTransaction();   
629    for(unsigned int n = 1; n < cmds.size(); ++n) {
630                        const string& zone=cmds[n];
631                        if(secureZone(dk, zone)) {
632        mustRectify.push_back(zone);
633      }
634                }
635   
636    dk.commitTransaction();
637    BOOST_FOREACH(string& zone, mustRectify)
638      rectifyZone(dk, zone);
639  }
640  else if(cmds[0]=="set-nsec3") {
641    if(cmds.size() < 2) {
642      cerr<<"Syntax: pdnssec set-nsec3 ZONE 'params' [narrow]"<<endl;
643      return 0;
644    }
645    string nsec3params =  cmds.size() > 2 ? cmds[2] : "1 1 1 ab";
646    bool narrow = cmds.size() > 3 && cmds[3]=="narrow";
647    NSEC3PARAMRecordContent ns3pr(nsec3params);
648    if(!ns3pr.d_flags) {
649      cerr<<"PowerDNS only implements opt-out zones, please set the second parameter to '1' (example, '1 1 1 ab')"<<endl;
650      return 0;
651    }
652   
653    dk.setNSEC3PARAM(cmds[1], ns3pr, narrow);
654  }
655  else if(cmds[0]=="set-presigned") {
656    if(cmds.size() < 2) {
657      cerr<<"Syntax: pdnssec set-presigned ZONE"<<endl;
658      return 0; 
659    }
660    dk.setPresigned(cmds[1]);
661  }
662  else if(cmds[0]=="unset-presigned") {
663    if(cmds.size() < 2) {
664      cerr<<"Syntax: pdnssec unset-presigned ZONE"<<endl;
665      return 0; 
666    }
667    dk.unsetPresigned(cmds[1]);
668  }
669  else if(cmds[0]=="hash-zone-record") {
670    if(cmds.size() < 3) {
671      cerr<<"Syntax: pdnssec hash-zone-record ZONE RNAME"<<endl;
672      return 0;
673    }
674    string& zone=cmds[1];
675    string& record=cmds[2];
676    NSEC3PARAMRecordContent ns3pr;
677    bool narrow;
678    if(!dk.getNSEC3PARAM(zone, &ns3pr, &narrow)) {
679      cerr<<"The '"<<zone<<"' zone does not use NSEC3"<<endl;
680      return 0;
681    }
682    if(narrow) {
683      cerr<<"The '"<<zone<<"' zone uses narrow NSEC3, but calculating hash anyhow"<<endl;
684    }
685     
686    cout<<toLower(toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, record)))<<endl;
687  }
688  else if(cmds[0]=="unset-nsec3") {
689    if(cmds.size() < 2) {
690      cerr<<"Syntax: pdnssec unset-nsec3 ZONE"<<endl;
691      exit(1);
692    }
693    dk.unsetNSEC3PARAM(cmds[1]);
694  }
695  else if(cmds[0]=="export-zone-key") {
696    if(cmds.size() < 3) {
697      cerr<<"Syntax: pdnssec export-zone-key ZONE KEY-ID"<<endl;
698      exit(1);
699    }
700
701    string zone=cmds[1];
702    unsigned int id=atoi(cmds[2].c_str());
703    DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
704    cout << dpk.getKey()->convertToISC() <<endl;
705  } 
706  else if(cmds[0]=="import-zone-key-pem") {
707    if(cmds.size() < 4) {
708      cerr<<"Syntax: pdnssec import-zone-key ZONE FILE algorithm [zsk|ksk]"<<endl;
709      exit(1);
710    }
711    string zone=cmds[1];
712    string fname=cmds[2];
713    string line;
714    ifstream ifs(fname.c_str());
715    string tmp, interim, raw;
716    while(getline(ifs, line)) {
717      if(line[0]=='-')
718        continue;
719      trim(line);
720      interim += line;
721    }
722    B64Decode(interim, raw);
723    DNSSECPrivateKey dpk;
724    DNSKEYRecordContent drc;
725    shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromPEMString(drc, raw));
726    dpk.setKey(key);
727   
728    dpk.d_algorithm = atoi(cmds[3].c_str());
729   
730    if(dpk.d_algorithm == 7)
731      dpk.d_algorithm = 5;
732     
733    cerr<<(int)dpk.d_algorithm<<endl;
734   
735    if(cmds.size() > 4) {
736      if(pdns_iequals(cmds[4], "ZSK"))
737        dpk.d_flags = 256;
738      else if(pdns_iequals(cmds[4], "KSK"))
739        dpk.d_flags = 257;
740      else {
741        cerr<<"Unknown key flag '"<<cmds[4]<<"'\n";
742        exit(1);
743      }
744    }
745    else
746      dpk.d_flags = 257; // ksk
747     
748    dk.addKey(zone, dpk); 
749   
750  }
751  else if(cmds[0]=="import-zone-key") {
752    if(cmds.size() < 4) {
753      cerr<<"Syntax: pdnssec import-zone-key ZONE FILE [zsk|ksk]"<<endl;
754      exit(1);
755    }
756    string zone=cmds[1];
757    string fname=cmds[2];
758    DNSSECPrivateKey dpk;
759    DNSKEYRecordContent drc;
760    shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromISCFile(drc, fname.c_str()));
761    dpk.setKey(key);
762    dpk.d_algorithm = drc.d_algorithm;
763   
764    if(dpk.d_algorithm == 7)
765      dpk.d_algorithm = 5;
766     
767    cerr<<(int)dpk.d_algorithm<<endl;
768   
769    if(cmds.size() > 3) {
770      if(pdns_iequals(cmds[3], "ZSK"))
771        dpk.d_flags = 256;
772      else if(pdns_iequals(cmds[3], "KSK"))
773        dpk.d_flags = 257;
774      else {
775        cerr<<"Unknown key flag '"<<cmds[3]<<"'\n";
776        exit(1);
777      }
778    }
779    else
780      dpk.d_flags = 257; 
781     
782    dk.addKey(zone, dpk); 
783  }
784  else if(cmds[0]=="export-zone-dnskey") {
785    if(cmds.size() < 3) {
786      cerr<<"Syntax: pdnssec export-zone-dnskey ZONE KEY-ID"<<endl;
787      exit(1);
788    }
789
790    string zone=cmds[1];
791    unsigned int id=atoi(cmds[2].c_str());
792    DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
793    cout << zone<<" IN DNSKEY "<<dpk.getDNSKEY().getZoneRepresentation() <<endl;
794    if(dpk.d_flags == 257) {
795      cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 1).getZoneRepresentation() << endl;
796      cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 2).getZoneRepresentation() << endl;
797    }
798  }
799  else {
800    cerr<<"Unknown command '"<<cmds[0]<<"'\n";
801    return 1;
802  }
803  return 0;
804}
805catch(AhuException& ae) {
806  cerr<<"Error: "<<ae.reason<<endl;
807}
808catch(std::exception& e) {
809  cerr<<"Error: "<<e.what()<<endl;
810}
Note: See TracBrowser for help on using the browser.