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

Revision 2580, 27.9 KB (checked in by peter, 13 months ago)

make pdnssec check-zone report MBOXFW and URL records. Reported by Gerwin Krist of Digitalus, patch by Ruben d'Arco. Closes #446

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