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

Revision 1793, 11.2 KB (checked in by ahu, 2 years ago)

make pdnssec read the right configuration file, plus make add-zone-key add zsks

Line 
1#include "dnsseckeeper.hh"
2#include "dnssecinfra.hh"
3#include "statbag.hh"
4#include "base32.hh"
5#include <boost/foreach.hpp>
6#include <boost/program_options.hpp>
7#include "dnsbackend.hh"
8#include "ueberbackend.hh"
9#include "arguments.hh"
10#include "packetcache.hh"
11
12StatBag S;
13PacketCache PC;
14
15using namespace boost;
16namespace po = boost::program_options;
17po::variables_map g_vm;
18
19string s_programname="pdns";
20
21ArgvMap &arg()
22{
23  static ArgvMap arg;
24  return arg;
25}
26
27string humanTime(time_t t)
28{
29  char ret[256];
30  struct tm tm;
31  localtime_r(&t, &tm);
32  strftime(ret, sizeof(ret)-1, "%c", &tm);   // %h:%M %Y-%m-%d
33  return ret;
34}
35
36void loadMainConfig()
37{
38   static char pietje[128]="!@@SYSCONFDIR@@:";
39  ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=
40    strcmp(pietje+1,"@@SYSCONFDIR@@:") ? pietje+strlen("@@SYSCONFDIR@@:")+1 : SYSCONFDIR;
41 
42  ::arg().set("launch","Which backends to launch");
43  ::arg().set("dnssec","if we should do dnssec")="true";
44  ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
45  ::arg().setCmd("help","Provide a helpful message");
46  //::arg().laxParse(argc,argv);
47
48  if(::arg().mustDo("help")) {
49    cerr<<"syntax:"<<endl<<endl;
50    cerr<<::arg().helpstring(::arg()["help"])<<endl;
51    exit(99);
52  }
53
54  if(::arg()["config-name"]!="") 
55    s_programname+="-"+::arg()["config-name"];
56
57  string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
58  cleanSlashes(configname);
59
60  cerr<<"configname: '"<<configname<<"'\n";
61 
62  ::arg().laxFile(configname.c_str());
63
64  BackendMakers().launch(::arg()["launch"]); // vrooooom!
65  ::arg().laxFile(configname.c_str());   
66  //cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" <<endl;
67
68  S.declare("qsize-q","Number of questions waiting for database attention");
69   
70  S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
71  S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
72         
73  S.declare("query-cache-hit","Number of hits on the query cache");
74  S.declare("query-cache-miss","Number of misses on the query cache");
75  ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
76  ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no"; 
77  ::arg().set("recursive-cache-ttl","Seconds to store packets in the PacketCache")="10";
78  ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";             
79  ::arg().set("negquery-cache-ttl","Seconds to store packets in the PacketCache")="60";
80  ::arg().set("query-cache-ttl","Seconds to store packets in the PacketCache")="20";             
81  ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
82  ::arg().set("soa-retry-default","Default SOA retry")="3600";
83  ::arg().set("soa-expire-default","Default SOA expire")="604800";
84    ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
85  ::arg().set("soa-minimum-ttl","Default SOA mininum ttl")="3600";   
86  UeberBackend::go();
87}
88
89void orderZone(DNSSECKeeper& dk, const std::string& zone)
90{
91   
92  UeberBackend* B = new UeberBackend("default");
93  SOAData sd;
94 
95  if(!B->getSOA(zone, sd)) {
96    cerr<<"No SOA!"<<endl;
97    return;
98  } 
99  cerr<<"ID: "<<sd.domain_id<<endl;
100  sd.db->list(zone, sd.domain_id);
101  DNSResourceRecord rr;
102
103  set<string> qnames;
104 
105  while(sd.db->get(rr)) {
106  //  cerr<<rr.qname<<endl;
107    qnames.insert(rr.qname);
108  }
109
110  NSEC3PARAMRecordContent ns3pr;
111  dk.getNSEC3PARAM(zone, &ns3pr);
112  string hashed;
113  if(ns3pr.d_salt.empty()) 
114    cerr<<"Adding NSEC ordering information"<<endl;
115  else
116    cerr<<"Adding NSEC3 hashed ordering information"<<endl;
117 
118  BOOST_FOREACH(const string& qname, qnames)
119  {
120    if(ns3pr.d_salt.empty()) // NSEC
121      sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, qname, true);
122    else {
123      hashed=toLower(toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, qname)));
124      cerr<<"'"<<qname<<"' -> '"<< hashed <<"'"<<endl;
125      sd.db->updateDNSSECOrderAndAuthAbsolute(sd.domain_id, qname, hashed, true);
126    }
127  }
128  cerr<<"Done listing"<<endl;
129}
130
131void checkZone(DNSSECKeeper& dk, const std::string& zone)
132{
133  loadMainConfig();
134  reportAllTypes(); 
135  UeberBackend* B = new UeberBackend("default");
136  SOAData sd;
137 
138  if(!B->getSOA(zone, sd)) {
139    cerr<<"No SOA!"<<endl;
140    return;
141  } 
142  cerr<<"ID: "<<sd.domain_id<<endl;
143  sd.db->list(zone, sd.domain_id);
144  DNSResourceRecord rr;
145  uint64_t numrecords=0, numerrors=0;
146 
147  while(sd.db->get(rr)) {
148    if(rr.qtype.getCode() == QType::MX) 
149      rr.content = lexical_cast<string>(rr.priority)+" "+rr.content;
150     
151    try {
152      shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content));
153      string tmp=drc->serialize(rr.qname);
154    }
155    catch(std::exception& e) 
156    {
157      cerr<<"Following record had a problem: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
158      cerr<<"Error was: "<<e.what()<<endl;
159      numerrors++;
160    }
161    numrecords++;
162  }
163  cerr<<"Checked "<<numrecords<<" records, "<<numerrors<<" errors"<<endl;
164}
165
166
167int main(int argc, char** argv)
168try
169{
170  po::options_description desc("Allowed options");
171  desc.add_options()
172    ("help,h", "produce help message")
173    ("verbose,v", po::value<bool>(), "be verbose")
174    ("force", "force an action")
175    ("commands", po::value<vector<string> >());
176
177  po::positional_options_description p;
178  p.add("commands", -1);
179  po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), g_vm);
180  po::notify(g_vm);
181
182  vector<string> cmds;
183
184  if(g_vm.count("commands")) 
185    cmds = g_vm["commands"].as<vector<string> >();
186
187  if(cmds.empty() || g_vm.count("help")) {
188    cerr<<"Usage: \npdnssec [options] [show-zone] [secure-zone] [alter-zone] [order-zone] [add-zone-key] [deactivate-zone-key] [remove-zone-key] [activate-zone-key]\n";
189    cerr<<"         [import-zone-key] [export-zone-key] [set-nsec3] [unset-nsec3] [export-zone-dnskey]"<<endl;
190    cerr<<desc<<endl;
191    return 0;
192  }
193
194  loadMainConfig();
195  reportAllTypes();
196  DNSSECKeeper dk;
197
198  if(cmds[0] == "order-zone") {
199    if(cmds.size() != 2) {
200      cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
201      return 0;
202    }
203    orderZone(dk, cmds[1]);
204  }
205  else if(cmds[0] == "check-zone") {
206    if(cmds.size() != 2) {
207      cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
208      return 0;
209    }
210    checkZone(dk, cmds[1]);
211  }
212
213  else if(cmds[0] == "show-zone") {
214    if(cmds.size() != 2) {
215      cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
216      return 0;
217    }
218    const string& zone=cmds[1];
219
220    NSEC3PARAMRecordContent ns3pr;
221    dk.getNSEC3PARAM(zone, &ns3pr);
222   
223    if(ns3pr.d_salt.empty()) 
224      cerr<<"Zone has NSEC semantics"<<endl;
225    else
226      cerr<<"Zone has hashed NSEC3 semantics, configuration: "<<ns3pr.getZoneRepresentation()<<endl;
227   
228    DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
229
230    if(keyset.empty())  {
231      cerr << "No keys for zone '"<<zone<<"'."<<endl;
232    }
233    else { 
234      cout << "keys: "<<endl;
235      BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
236        cout<<"ID = "<<value.second.id<<" ("<<(value.second.keyOrZone ? "KSK" : "ZSK")<<"), tag = "<<value.first.getDNSKEY().getTag();
237        cout<<", algo = "<<(int)value.first.d_algorithm<<", bits = "<<value.first.d_key.getConstContext().len*8<<"\tActive: "<<value.second.active<< endl; // humanTime(value.second.beginValidity)<<" - "<<humanTime(value.second.endValidity)<<endl;
238        if(value.second.keyOrZone) {
239          cout<<"KSK DNSKEY = "<<zone<<" IN DNSKEY "<< value.first.getDNSKEY().getZoneRepresentation() << endl;
240          cout<<"DS = "<<zone<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY()).getZoneRepresentation() << endl << endl;
241        }
242      }
243    }
244  }
245  else if(cmds[0] == "activate-zone-key") {
246    const string& zone=cmds[1];
247    unsigned int id=atoi(cmds[2].c_str());
248    dk.activateKey(zone, id);
249  }
250  else if(cmds[0] == "deactivate-zone-key") {
251    const string& zone=cmds[1];
252    unsigned int id=atoi(cmds[2].c_str());
253    dk.deactivateKey(zone, id);
254  }
255  else if(cmds[0] == "add-zone-key") {
256    const string& zone=cmds[1];
257    // need to get algorithm & ksk or zsk from commandline
258    cerr<<"Adding a ZSK"<<endl;
259    dk.addKey(zone, 0, 5, 0); 
260  }
261  else if(cmds[0] == "remove-zone-key") {
262    const string& zone=cmds[1];
263    unsigned int id=atoi(cmds[2].c_str());
264    dk.removeKey(zone, id);
265  }
266 
267  else if(cmds[0] == "secure-zone") {
268    if(cmds.size() != 2) {
269      cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
270      return 0;
271    }
272    const string& zone=cmds[1];
273    DNSSECPrivateKey dpk;
274   
275    if(dk.haveActiveKSKFor(zone, &dpk) && !g_vm.count("force")) {
276      cerr << "There is a key already for zone '"<<zone<<"', use --force to overwrite"<<endl;
277      return 0;
278    }
279     
280    dk.secureZone(zone, 5);
281
282    if(!dk.haveActiveKSKFor(zone, &dpk)) {
283      cerr << "This should not happen, still no key!" << endl;
284      return 0;
285    }
286    cout<<"Created KSK with tag "<<dpk.getDNSKEY().getTag()<<endl;
287 
288    DNSSECKeeper::keyset_t zskset=dk.getKeys(zone, false);
289
290    if(!zskset.empty() && !g_vm.count("force"))  {
291      cerr<<"There were ZSKs already for zone '"<<zone<<"'"<<endl;
292      return 0;
293    }
294     
295    dk.addKey(zone, false, 5);
296    dk.addKey(zone, false, 5, 0, false); // not active
297
298    zskset = dk.getKeys(zone, false);
299    if(zskset.empty()) {
300      cerr<<"This should not happen, still no ZSK!"<<endl;
301    }
302
303    cout<<"There are now "<<zskset.size()<<" ZSKs"<<endl;
304    BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, zskset) {
305      cout<<"id = "<<value.second.id<<", tag = "<<value.first.getDNSKEY().getTag()<<", algo = "<<(int)value.first.d_algorithm<<
306        ", bits = "<<value.first.d_key.getContext().len*8;
307      cout<<"\tActive: "<<value.second.active<<endl;
308    }
309  }
310  else if(cmds[0]=="set-nsec3") {
311    string nsec3params =  cmds.size() > 2 ? cmds[2] : "1 0 1 ab";
312     
313    NSEC3PARAMRecordContent ns3pr(nsec3params);
314    dk.setNSEC3PARAM(cmds[1], ns3pr);
315  }
316  else if(cmds[0]=="unset-nsec3") {
317    dk.unsetNSEC3PARAM(cmds[1]);
318  }
319  else if(cmds[0]=="export-zone-key") {
320    string zone=cmds[1];
321    unsigned int id=atoi(cmds[2].c_str());
322    DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
323    cout << dpk.d_key.convertToISC(dpk.d_algorithm) <<endl;
324  } 
325  else if(cmds[0]=="import-zone-key") {
326    if(cmds.size()!=3) {
327      cerr<<"Syntax: pdnssec import-zone-key zone-name filename"<<endl;
328      exit(1);
329    }
330    string zone=cmds[1];
331    string fname=cmds[2];
332    DNSSECPrivateKey dpk;
333    getRSAKeyFromISC(&dpk.d_key.getContext(), fname.c_str());
334    dpk.d_algorithm = 5;
335    dpk.d_flags = 257;
336    dk.addKey(zone, true, dpk); // add a KSK
337  }
338  else if(cmds[0]=="export-zone-dnskey") {
339    string zone=cmds[1];
340    unsigned int id=atoi(cmds[2].c_str());
341    DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
342    cout << zone<<" IN DNSKEY "<<dpk.getDNSKEY().getZoneRepresentation() <<endl;
343    if(dpk.d_flags == 257)
344      cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY()).getZoneRepresentation() << endl;
345  }
346  else {
347    cerr<<"Unknown command '"<<cmds[0]<<"'\n";
348    return 1;
349  }
350  return 0;
351}
352catch(AhuException& ae) {
353  cerr<<"Error: "<<ae.reason<<endl;
354}
Note: See TracBrowser for help on using the browser.