]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/pdnssec.cc
show-zone output partially went to stderr
[thirdparty/pdns.git] / pdns / pdnssec.cc
CommitLineData
1d211b1b 1#include "dnsseckeeper.hh"
d3151289 2#include "dnssecinfra.hh"
1d211b1b 3#include "statbag.hh"
01fde57c 4#include "base32.hh"
1d211b1b
BH
5#include <boost/foreach.hpp>
6#include <boost/program_options.hpp>
20002664
BH
7#include "dnsbackend.hh"
8#include "ueberbackend.hh"
9#include "arguments.hh"
10#include "packetcache.hh"
11
12StatBag S;
13PacketCache PC;
1d211b1b
BH
14
15using namespace boost;
16namespace po = boost::program_options;
17po::variables_map g_vm;
18
39a8b5c0 19string s_programname="pdns";
20002664
BH
20
21ArgvMap &arg()
22{
23 static ArgvMap arg;
24 return arg;
25}
26
1d211b1b
BH
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
7d9dcde0 36void loadMainConfig(const std::string& configdir)
20002664 37{
7d9dcde0 38 ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=configdir;
20002664
BH
39
40 ::arg().set("launch","Which backends to launch");
6dfa0aa0 41 ::arg().set("dnssec","if we should do dnssec")="true";
4f6cf113 42 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")=g_vm["config-name"].as<string>();
20002664
BH
43 ::arg().setCmd("help","Provide a helpful message");
44 //::arg().laxParse(argc,argv);
45
46 if(::arg().mustDo("help")) {
47 cerr<<"syntax:"<<endl<<endl;
48 cerr<<::arg().helpstring(::arg()["help"])<<endl;
49 exit(99);
50 }
51
52 if(::arg()["config-name"]!="")
53 s_programname+="-"+::arg()["config-name"];
54
55 string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
56 cleanSlashes(configname);
57
58 cerr<<"configname: '"<<configname<<"'\n";
59
60 ::arg().laxFile(configname.c_str());
a7e0acd8 61 ::arg().set("module-dir","Default directory for modules")=LIBDIR;
20002664
BH
62 BackendMakers().launch(::arg()["launch"]); // vrooooom!
63 ::arg().laxFile(configname.c_str());
9abd98d3 64 //cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" <<endl;
20002664
BH
65
66 S.declare("qsize-q","Number of questions waiting for database attention");
67
68 S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
69 S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
70
71 S.declare("query-cache-hit","Number of hits on the query cache");
72 S.declare("query-cache-miss","Number of misses on the query cache");
73 ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
74 ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no";
75 ::arg().set("recursive-cache-ttl","Seconds to store packets in the PacketCache")="10";
76 ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
77 ::arg().set("negquery-cache-ttl","Seconds to store packets in the PacketCache")="60";
78 ::arg().set("query-cache-ttl","Seconds to store packets in the PacketCache")="20";
79 ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
80 ::arg().set("soa-retry-default","Default SOA retry")="3600";
81 ::arg().set("soa-expire-default","Default SOA expire")="604800";
82 ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
83 ::arg().set("soa-minimum-ttl","Default SOA mininum ttl")="3600";
a7e0acd8 84
20002664
BH
85 UeberBackend::go();
86}
87
f28f2324 88void rectifyZone(DNSSECKeeper& dk, const std::string& zone)
20002664 89{
20002664
BH
90 UeberBackend* B = new UeberBackend("default");
91 SOAData sd;
81b39e4b
BH
92
93 if(!B->getSOA(zone, sd)) {
f28f2324 94 cerr<<"No SOA known for '"<<zone<<"', is such a zone in the database?"<<endl;
01fde57c 95 return;
20002664 96 }
81b39e4b 97 sd.db->list(zone, sd.domain_id);
20002664 98 DNSResourceRecord rr;
81b39e4b 99
f28f2324 100 set<string> qnames, nsset;
20002664
BH
101
102 while(sd.db->get(rr)) {
81b39e4b 103 qnames.insert(rr.qname);
f28f2324
BH
104 if(rr.qtype.getCode() == QType::NS && !pdns_iequals(rr.qname, zone))
105 nsset.insert(rr.qname);
81b39e4b 106 }
9abd98d3 107
c3c89361 108 NSEC3PARAMRecordContent ns3pr;
f28f2324
BH
109 bool narrow;
110 dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
c3c89361 111 string hashed;
9abd98d3
BH
112 if(ns3pr.d_salt.empty())
113 cerr<<"Adding NSEC ordering information"<<endl;
f28f2324
BH
114 else if(!narrow)
115 cerr<<"Adding NSEC3 hashed ordering information for '"<<zone<<"'"<<endl;
116 else
117 cerr<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields"<<endl;
9abd98d3 118
81b39e4b
BH
119 BOOST_FOREACH(const string& qname, qnames)
120 {
f28f2324
BH
121 string shorter(qname);
122 bool auth=true;
123 do {
124 if(nsset.count(shorter)) {
125 auth=false;
126 break;
127 }
128 }while(chopOff(shorter));
129
c3c89361 130 if(ns3pr.d_salt.empty()) // NSEC
f28f2324 131 sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, qname, auth);
c3c89361 132 else {
f28f2324
BH
133 if(!narrow) {
134 hashed=toLower(toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, qname)));
135 cerr<<"'"<<qname<<"' -> '"<< hashed <<"'"<<endl;
136 }
137 sd.db->updateDNSSECOrderAndAuthAbsolute(sd.domain_id, qname, hashed, auth);
c3c89361 138 }
20002664
BH
139 }
140 cerr<<"Done listing"<<endl;
141}
142
5d2e58b0
BH
143void checkZone(DNSSECKeeper& dk, const std::string& zone)
144{
5d2e58b0
BH
145 UeberBackend* B = new UeberBackend("default");
146 SOAData sd;
147
148 if(!B->getSOA(zone, sd)) {
149 cerr<<"No SOA!"<<endl;
150 return;
151 }
5d2e58b0
BH
152 sd.db->list(zone, sd.domain_id);
153 DNSResourceRecord rr;
154 uint64_t numrecords=0, numerrors=0;
155
035297ad
BH
156 while(sd.db->get(rr)) {
157 if(rr.qtype.getCode() == QType::MX)
158 rr.content = lexical_cast<string>(rr.priority)+" "+rr.content;
7ddd79a7
BH
159 if(rr.auth == 0 && rr.qtype.getCode()!=QType::NS && rr.qtype.getCode()!=QType::A)
160 {
161 cerr<<"Following record is auth=0, run pdnssec rectify-zone?: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
162 }
035297ad
BH
163 try {
164 shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content));
165 string tmp=drc->serialize(rr.qname);
5d2e58b0 166 }
035297ad
BH
167 catch(std::exception& e)
168 {
169 cerr<<"Following record had a problem: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
170 cerr<<"Error was: "<<e.what()<<endl;
171 numerrors++;
172 }
173 numrecords++;
174 }
175 cerr<<"Checked "<<numrecords<<" records, "<<numerrors<<" errors"<<endl;
5d2e58b0
BH
176}
177
ade1b1e9
BH
178void showZone(DNSSECKeeper& dk, const std::string& zone)
179{
180 NSEC3PARAMRecordContent ns3pr;
181 bool narrow;
182 dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
183
184 if(ns3pr.d_salt.empty())
7ddd79a7 185 cout<<"Zone has NSEC semantics"<<endl;
ade1b1e9 186 else
7ddd79a7 187 cout<<"Zone has " << (narrow ? "NARROW " : "") <<"hashed NSEC3 semantics, configuration: "<<ns3pr.getZoneRepresentation()<<endl;
ade1b1e9
BH
188
189 DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
190
191 if(keyset.empty()) {
192 cerr << "No keys for zone '"<<zone<<"'."<<endl;
193 }
194 else {
195 cout << "keys: "<<endl;
196 BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
197 cout<<"ID = "<<value.second.id<<" ("<<(value.second.keyOrZone ? "KSK" : "ZSK")<<"), tag = "<<value.first.getDNSKEY().getTag();
198 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;
199 if(value.second.keyOrZone) {
200 cout<<"KSK DNSKEY = "<<zone<<" IN DNSKEY "<< value.first.getDNSKEY().getZoneRepresentation() << endl;
201 cout<<"DS = "<<zone<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 1).getZoneRepresentation() << endl;
202 cout<<"DS = "<<zone<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 2).getZoneRepresentation() << endl << endl;
203 }
204 }
205 }
206}
5d2e58b0 207
1d211b1b 208int main(int argc, char** argv)
20002664 209try
1d211b1b
BH
210{
211 po::options_description desc("Allowed options");
212 desc.add_options()
213 ("help,h", "produce help message")
1d211b1b
BH
214 ("verbose,v", po::value<bool>(), "be verbose")
215 ("force", "force an action")
aa952078 216 ("config-name", po::value<string>()->default_value(""), "virtual configuration name")
7d9dcde0 217 ("config-dir", po::value<string>()->default_value(SYSCONFDIR), "location of pdns.conf")
1d211b1b
BH
218 ("commands", po::value<vector<string> >());
219
220 po::positional_options_description p;
221 p.add("commands", -1);
222 po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), g_vm);
223 po::notify(g_vm);
224
225 vector<string> cmds;
226
227 if(g_vm.count("commands"))
228 cmds = g_vm["commands"].as<vector<string> >();
229
230 if(cmds.empty() || g_vm.count("help")) {
f28f2324
BH
231 cerr<<"Usage: \npdnssec [options] [show-zone] [secure-zone] [rectify-zone] [add-zone-key] [deactivate-zone-key] [remove-zone-key] [activate-zone-key]\n";
232 cerr<<" [import-zone-key] [export-zone-key] [set-nsec3] [unset-nsec3] [export-zone-dnskey]\n\n";
233 cerr<<"activate-zone-key ZONE KEY-ID Activate the key with key id KEY-ID in ZONE\n";
7ddd79a7
BH
234 cerr<<"add-zone-key ZONE [zsk|ksk] Add a ZSK or KSK to a zone\n";
235 cerr<<" [bits] [rsasha1|rsasha256] and specify algorithm & bits\n";
236 cerr<<"check-zone ZONE Check a zone for correctness\n";
f28f2324
BH
237 cerr<<"deactivate-zone-key Dectivate the key with key id KEY-ID in ZONE\n";
238 cerr<<"export-zone-dnskey ZONE KEY-ID Export to stdout the public DNSKEY described\n";
239 cerr<<"export-zone-key ZONE KEY-ID Export to stdout the private key described\n";
7ddd79a7
BH
240 cerr<<"import-zone-key ZONE FILE Import from a file a private key, ZSK or KSK\n";
241 cerr<<" [ksk|zsk] Defaults to KSK\n";
f28f2324
BH
242 cerr<<"rectify-zone ZONE Fix up DNSSEC fields (order, auth)\n";
243 cerr<<"remove-zone-key ZONE KEY-ID Remove key with KEY-ID from ZONE\n";
244 cerr<<"secure-zone Add KSK and two ZSKs\n";
245 cerr<<"set-nsec3 'params' [narrow] Enable NSEC3 with PARAMs. Optionally narrow\n";
246 cerr<<"show-zone ZONE Show DNSSEC (public) key details about a zone\n";
247 cerr<<"unset-nsec3 ZONE Switch back to NSEC\n\n";
248
7d9dcde0 249 cerr<<"Options:"<<endl;
1d211b1b
BH
250 cerr<<desc<<endl;
251 return 0;
252 }
a7e0acd8 253
7d9dcde0 254 loadMainConfig(g_vm["config-dir"].as<string>());
6dfa0aa0 255 reportAllTypes();
976b6541 256 DNSSECKeeper dk;
1d211b1b 257
f28f2324 258 if(cmds[0] == "rectify-zone" || cmds[0] == "order-zone") {
81b39e4b
BH
259 if(cmds.size() != 2) {
260 cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
261 return 0;
262 }
f28f2324 263 rectifyZone(dk, cmds[1]);
20002664 264 }
9abd98d3 265 else if(cmds[0] == "check-zone") {
5d2e58b0
BH
266 if(cmds.size() != 2) {
267 cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
268 return 0;
269 }
270 checkZone(dk, cmds[1]);
271 }
da11ed0e
BH
272
273 else if(cmds[0] == "show-zone") {
a0472099
BH
274 if(cmds.size() != 2) {
275 cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
276 return 0;
277 }
1d211b1b 278 const string& zone=cmds[1];
ade1b1e9 279 showZone(dk, zone);
1d211b1b 280 }
bed962b5
BH
281 else if(cmds[0] == "activate-zone-key") {
282 const string& zone=cmds[1];
283 unsigned int id=atoi(cmds[2].c_str());
284 dk.activateKey(zone, id);
285 }
286 else if(cmds[0] == "deactivate-zone-key") {
287 const string& zone=cmds[1];
288 unsigned int id=atoi(cmds[2].c_str());
289 dk.deactivateKey(zone, id);
290 }
291 else if(cmds[0] == "add-zone-key") {
292 const string& zone=cmds[1];
36c394e5
BH
293 // need to get algorithm, bits & ksk or zsk from commandline
294 bool keyOrZone=false;
295 int bits=0;
a254438f 296 int algorithm=5;
36c394e5
BH
297 for(unsigned int n=2; n < cmds.size(); ++n) {
298 if(pdns_iequals(cmds[n], "zsk"))
299 keyOrZone = false;
300 else if(pdns_iequals(cmds[n], "ksk"))
301 keyOrZone = true;
a254438f
BH
302 else if(pdns_iequals(cmds[n], "rsasha1"))
303 algorithm=5;
304 else if(pdns_iequals(cmds[n], "rsasha256"))
305 algorithm=8;
36c394e5
BH
306 else if(atoi(cmds[n].c_str()))
307 bits = atoi(cmds[n].c_str());
308 else {
a254438f 309 cerr<<"Unknown algorithm, key flag or size '"<<cmds[n]<<"'"<<endl;
36c394e5
BH
310 }
311 }
a254438f 312 cerr<<"Adding a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "<<algorithm<<endl;
36c394e5
BH
313 if(bits)
314 cerr<<"Requesting specific key size of "<<bits<<" bits"<<endl;
a254438f 315 dk.addKey(zone, keyOrZone, algorithm, bits);
bed962b5
BH
316 }
317 else if(cmds[0] == "remove-zone-key") {
318 const string& zone=cmds[1];
319 unsigned int id=atoi(cmds[2].c_str());
320 dk.removeKey(zone, id);
321 }
322
c3c89361 323 else if(cmds[0] == "secure-zone") {
a9175ad6 324 if(cmds.size() != 2) {
a0472099 325 cerr << "Error: "<<cmds[0]<<" takes exactly 1 parameter"<<endl;
a9175ad6
BH
326 return 0;
327 }
1d211b1b
BH
328 const string& zone=cmds[1];
329 DNSSECPrivateKey dpk;
330
ade1b1e9
BH
331 if(dk.haveActiveKSKFor(zone)) {
332 cerr << "There is a KSK already for zone '"<<zone<<"', remove with pdnssec remove-zone-key if needed"<<endl;
1d211b1b
BH
333 return 0;
334 }
335
ade1b1e9 336 dk.secureZone(zone, 8);
1d211b1b 337
ade1b1e9 338 if(!dk.haveActiveKSKFor(zone)) {
1d211b1b 339 cerr << "This should not happen, still no key!" << endl;
6dfa0aa0 340 return 0;
1d211b1b 341 }
1d211b1b 342
bed962b5 343 DNSSECKeeper::keyset_t zskset=dk.getKeys(zone, false);
1d211b1b 344
ade1b1e9
BH
345 if(!zskset.empty()) {
346 cerr<<"There were ZSKs already for zone '"<<zone<<"', no need to add more"<<endl;
1d211b1b
BH
347 return 0;
348 }
349
ade1b1e9
BH
350 dk.addKey(zone, false, 8);
351 dk.addKey(zone, false, 8, 0, false); // not active
352 rectifyZone(dk, zone);
353 showZone(dk, zone);
1d211b1b 354 }
da11ed0e
BH
355 else if(cmds[0]=="set-nsec3") {
356 string nsec3params = cmds.size() > 2 ? cmds[2] : "1 0 1 ab";
22c5aa60 357 bool narrow = cmds.size() > 3 && cmds[3]=="narrow";
da11ed0e 358 NSEC3PARAMRecordContent ns3pr(nsec3params);
22c5aa60 359 dk.setNSEC3PARAM(cmds[1], ns3pr, narrow);
da11ed0e
BH
360 }
361 else if(cmds[0]=="unset-nsec3") {
362 dk.unsetNSEC3PARAM(cmds[1]);
363 }
364 else if(cmds[0]=="export-zone-key") {
7ddd79a7
BH
365 if(cmds.size() < 3) {
366 cerr<<"Syntax: pdnssec export-zone-key zone-name id"<<endl;
367 cerr<<cmds.size()<<endl;
368 exit(1);
369 }
370
da11ed0e
BH
371 string zone=cmds[1];
372 unsigned int id=atoi(cmds[2].c_str());
373 DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
339fe708 374 cout << dpk.d_key.convertToISC(dpk.d_algorithm) <<endl;
4496f66f 375 }
976b6541 376 else if(cmds[0]=="import-zone-key") {
c34fc2df 377 if(cmds.size() < 3) {
7ddd79a7 378 cerr<<"Syntax: pdnssec import-zone-key zone-name filename [zsk|ksk]"<<endl;
4496f66f
BH
379 exit(1);
380 }
976b6541
BH
381 string zone=cmds[1];
382 string fname=cmds[2];
383 DNSSECPrivateKey dpk;
7ddd79a7
BH
384 DNSKEYRecordContent drc = getRSAKeyFromISC(&dpk.d_key.getContext(), fname.c_str());
385 dpk.d_algorithm = drc.d_algorithm;
386
387 if(dpk.d_algorithm == 7)
388 dpk.d_algorithm = 5;
389
390 cerr<<(int)dpk.d_algorithm<<endl;
aa952078
BH
391
392 if(cmds.size() > 3) {
393 if(pdns_iequals(cmds[3], "ZSK"))
394 dpk.d_flags = 256;
395 else if(pdns_iequals(cmds[3], "KSK"))
396 dpk.d_flags = 257;
397 else {
398 cerr<<"Unknown key flag '"<<cmds[3]<<"'\n";
399 exit(1);
400 }
401 }
402 else
403 dpk.d_flags = 257;
404
7ddd79a7 405 dk.addKey(zone, dpk);
976b6541 406 }
da11ed0e 407 else if(cmds[0]=="export-zone-dnskey") {
7ddd79a7
BH
408 if(cmds.size() < 3) {
409 cerr<<"Syntax: pdnssec export-zone-dnskey zone-name id"<<endl;
410 exit(1);
411 }
412
da11ed0e
BH
413 string zone=cmds[1];
414 unsigned int id=atoi(cmds[2].c_str());
415 DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
416 cout << zone<<" IN DNSKEY "<<dpk.getDNSKEY().getZoneRepresentation() <<endl;
f8b25763
BH
417 if(dpk.d_flags == 257) {
418 cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 1).getZoneRepresentation() << endl;
419 cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 2).getZoneRepresentation() << endl;
420 }
da11ed0e 421 }
1d211b1b
BH
422 else {
423 cerr<<"Unknown command '"<<cmds[0]<<"'\n";
424 return 1;
425 }
426 return 0;
427}
20002664
BH
428catch(AhuException& ae) {
429 cerr<<"Error: "<<ae.reason<<endl;
430}
14133ba3
BH
431catch(std::exception& e) {
432 cerr<<"Error: "<<e.what()<<endl;
433}