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

Revision 2369, 26.4 KB (checked in by peter, 16 months ago)

Make pdnssec error uit clearly, instead of segfaulting, when there are no dnssec-capable backends

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