]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rec_channel_rec.cc
Merge pull request #5406 from rgacogne/rec-netmask-ordering
[thirdparty/pdns.git] / pdns / rec_channel_rec.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include "utility.hh"
5 #include "rec_channel.hh"
6 #include <boost/bind.hpp>
7 #include <vector>
8 #ifdef MALLOC_TRACE
9 #include "malloctrace.hh"
10 #endif
11 #include "misc.hh"
12 #include "recursor_cache.hh"
13 #include "syncres.hh"
14 #include "negcache.hh"
15 #include <boost/function.hpp>
16 #include <boost/optional.hpp>
17 #include <boost/tuple/tuple.hpp>
18 #include <boost/format.hpp>
19 #include <boost/algorithm/string.hpp>
20
21 #include "version.hh"
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include "logger.hh"
26 #include "dnsparser.hh"
27 #include "arguments.hh"
28 #include <sys/resource.h>
29 #include <sys/time.h>
30 #include "lock.hh"
31 #include "responsestats.hh"
32 #include "rec-lua-conf.hh"
33
34 #include "validate-recursor.hh"
35 #include "filterpo.hh"
36
37 #include "secpoll-recursor.hh"
38 #include "pubsuffix.hh"
39 #include "namespaces.hh"
40 pthread_mutex_t g_carbon_config_lock=PTHREAD_MUTEX_INITIALIZER;
41
42 map<string, const uint32_t*> d_get32bitpointers;
43 map<string, const uint64_t*> d_get64bitpointers;
44 map<string, const std::atomic<uint64_t>*> d_getatomics;
45 map<string, function< uint64_t() > > d_get64bitmembers;
46 pthread_mutex_t d_dynmetricslock = PTHREAD_MUTEX_INITIALIZER;
47 map<string, std::atomic<unsigned long>* > d_dynmetrics;
48 void addGetStat(const string& name, const uint32_t* place)
49 {
50 d_get32bitpointers[name]=place;
51 }
52 void addGetStat(const string& name, const uint64_t* place)
53 {
54 d_get64bitpointers[name]=place;
55 }
56
57 void addGetStat(const string& name, const std::atomic<uint64_t>* place)
58 {
59 d_getatomics[name]=place;
60 }
61
62
63 void addGetStat(const string& name, function<uint64_t ()> f )
64 {
65 d_get64bitmembers[name]=f;
66 }
67
68
69 std::atomic<unsigned long>* getDynMetric(const std::string& str)
70 {
71 Lock l(&d_dynmetricslock);
72 auto f = d_dynmetrics.find(str);
73 if(f != d_dynmetrics.end())
74 return f->second;
75
76 auto ret = new std::atomic<unsigned long>();
77 d_dynmetrics[str]= ret;
78 return ret;
79 }
80
81 static optional<uint64_t> get(const string& name)
82 {
83 optional<uint64_t> ret;
84
85 if(d_get32bitpointers.count(name))
86 return *d_get32bitpointers.find(name)->second;
87 if(d_get64bitpointers.count(name))
88 return *d_get64bitpointers.find(name)->second;
89 if(d_getatomics.count(name))
90 return d_getatomics.find(name)->second->load();
91 if(d_get64bitmembers.count(name))
92 return d_get64bitmembers.find(name)->second();
93
94 Lock l(&d_dynmetricslock);
95 auto f =rplookup(d_dynmetrics, name);
96 if(f)
97 return (*f)->load();
98
99 return ret;
100 }
101
102 optional<uint64_t> getStatByName(const std::string& name)
103 {
104 return get(name);
105 }
106
107 map<string,string> getAllStatsMap()
108 {
109 map<string,string> ret;
110
111 for(const auto& the32bits : d_get32bitpointers) {
112 ret.insert(make_pair(the32bits.first, std::to_string(*the32bits.second)));
113 }
114 for(const auto& the64bits : d_get64bitpointers) {
115 ret.insert(make_pair(the64bits.first, std::to_string(*the64bits.second)));
116 }
117 for(const auto& atomic : d_getatomics) {
118 ret.insert(make_pair(atomic.first, std::to_string(atomic.second->load())));
119 }
120
121 for(const auto& the64bitmembers : d_get64bitmembers) {
122 if(the64bitmembers.first == "cache-bytes" || the64bitmembers.first=="packetcache-bytes")
123 continue; // too slow for 'get-all'
124 ret.insert(make_pair(the64bitmembers.first, std::to_string(the64bitmembers.second())));
125 }
126 Lock l(&d_dynmetricslock);
127 for(const auto& a : d_dynmetrics)
128 ret.insert({a.first, std::to_string(*a.second)});
129 return ret;
130 }
131
132 string getAllStats()
133 {
134 typedef map<string, string> varmap_t;
135 varmap_t varmap = getAllStatsMap();
136 string ret;
137 for(varmap_t::value_type& tup : varmap) {
138 ret += tup.first + "\t" + tup.second +"\n";
139 }
140 return ret;
141 }
142
143 template<typename T>
144 string doGet(T begin, T end)
145 {
146 string ret;
147
148 for(T i=begin; i != end; ++i) {
149 optional<uint64_t> num=get(*i);
150 if(num)
151 ret+=std::to_string(*num)+"\n";
152 else
153 ret+="UNKNOWN\n";
154 }
155 return ret;
156 }
157
158 template<typename T>
159 string doGetParameter(T begin, T end)
160 {
161 string ret;
162 string parm;
163 using boost::replace_all;
164 for(T i=begin; i != end; ++i) {
165 if(::arg().parmIsset(*i)) {
166 parm=::arg()[*i];
167 replace_all(parm, "\\", "\\\\");
168 replace_all(parm, "\"", "\\\"");
169 replace_all(parm, "\n", "\\n");
170 ret += *i +"=\""+ parm +"\"\n";
171 }
172 else
173 ret += *i +" not known\n";
174 }
175 return ret;
176 }
177
178
179 static uint64_t dumpNegCache(NegCache& negcache, int fd)
180 {
181 FILE* fp=fdopen(dup(fd), "w");
182 if(!fp) { // dup probably failed
183 return 0;
184 }
185 uint64_t ret;
186 fprintf(fp, "; negcache dump from thread follows\n;\n");
187 ret = negcache.dumpToFile(fp);
188 fclose(fp);
189 return ret;
190 }
191
192 static uint64_t* pleaseDump(int fd)
193 {
194 return new uint64_t(t_RC->doDump(fd) + dumpNegCache(SyncRes::t_sstorage.negcache, fd) + t_packetCache->doDump(fd));
195 }
196
197 static uint64_t* pleaseDumpNSSpeeds(int fd)
198 {
199 return new uint64_t(SyncRes::doDumpNSSpeeds(fd));
200 }
201
202 template<typename T>
203 string doDumpNSSpeeds(T begin, T end)
204 {
205 T i=begin;
206 string fname;
207
208 if(i!=end)
209 fname=*i;
210
211 int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
212 if(fd < 0)
213 return "Error opening dump file for writing: "+string(strerror(errno))+"\n";
214 uint64_t total = 0;
215 try {
216 total = broadcastAccFunction<uint64_t>(boost::bind(pleaseDumpNSSpeeds, fd));
217 }
218 catch(...){}
219
220 close(fd);
221 return "dumped "+std::to_string(total)+" records\n";
222 }
223
224 template<typename T>
225 string doDumpCache(T begin, T end)
226 {
227 T i=begin;
228 string fname;
229
230 if(i!=end)
231 fname=*i;
232
233 int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
234 if(fd < 0)
235 return "Error opening dump file for writing: "+string(strerror(errno))+"\n";
236 uint64_t total = 0;
237 try {
238 total = broadcastAccFunction<uint64_t>(boost::bind(pleaseDump, fd));
239 }
240 catch(...){}
241
242 close(fd);
243 return "dumped "+std::to_string(total)+" records\n";
244 }
245
246 template<typename T>
247 string doDumpEDNSStatus(T begin, T end)
248 {
249 T i=begin;
250 string fname;
251
252 if(i!=end)
253 fname=*i;
254
255 int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
256 if(fd < 0)
257 return "Error opening dump file for writing: "+string(strerror(errno))+"\n";
258
259 SyncRes::doEDNSDumpAndClose(fd);
260
261 return "done\n";
262 }
263
264 uint64_t* pleaseWipeCache(const DNSName& canon, bool subtree)
265 {
266 return new uint64_t(t_RC->doWipeCache(canon, subtree));
267 }
268
269 uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree)
270 {
271 return new uint64_t(t_packetCache->doWipePacketCache(canon,0xffff, subtree));
272 }
273
274
275 uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree)
276 {
277 uint64_t ret = SyncRes::wipeNegCache(canon, subtree);
278 return new uint64_t(ret);
279 }
280
281
282 template<typename T>
283 string doWipeCache(T begin, T end)
284 {
285 vector<pair<DNSName, bool> > toWipe;
286 for(T i=begin; i != end; ++i) {
287 DNSName canon;
288 bool subtree=false;
289
290 try {
291 if(boost::ends_with(*i, "$")) {
292 canon=DNSName(i->substr(0, i->size()-1));
293 subtree=true;
294 } else {
295 canon=DNSName(*i);
296 }
297 } catch (std::exception &e) {
298 return "Error: " + std::string(e.what()) + ", nothing wiped\n";
299 }
300 toWipe.push_back({canon, subtree});
301 }
302
303 int count=0, pcount=0, countNeg=0;
304 for (auto wipe : toWipe) {
305 count+= broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, wipe.first, wipe.second));
306 pcount+= broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, wipe.first, wipe.second));
307 countNeg+=broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, wipe.first, wipe.second));
308 }
309
310 return "wiped "+std::to_string(count)+" records, "+std::to_string(countNeg)+" negative records, "+std::to_string(pcount)+" packets\n";
311 }
312
313 template<typename T>
314 string doSetCarbonServer(T begin, T end)
315 {
316 Lock l(&g_carbon_config_lock);
317 if(begin==end) {
318 ::arg().set("carbon-server").clear();
319 return "cleared carbon-server setting\n";
320 }
321 string ret;
322 ::arg().set("carbon-server")=*begin;
323 ret="set carbon-server to '"+::arg()["carbon-server"]+"'\n";
324 ++begin;
325 if(begin != end) {
326 ::arg().set("carbon-ourname")=*begin;
327 ret+="set carbon-ourname to '"+*begin+"'\n";
328 }
329 return ret;
330 }
331
332 template<typename T>
333 string doSetDnssecLogBogus(T begin, T end)
334 {
335 if(checkDNSSECDisabled())
336 return "DNSSEC is disabled in the configuration, not changing the Bogus logging setting\n";
337
338 if (begin == end)
339 return "No DNSSEC Bogus logging setting specified\n";
340
341 if (pdns_iequals(*begin, "on") || pdns_iequals(*begin, "yes")) {
342 if (!g_dnssecLogBogus) {
343 L<<Logger::Warning<<"Enabling DNSSEC Bogus logging, requested via control channel"<<endl;
344 g_dnssecLogBogus = true;
345 return "DNSSEC Bogus logging enabled\n";
346 }
347 return "DNSSEC Bogus logging was already enabled\n";
348 }
349
350 if (pdns_iequals(*begin, "off") || pdns_iequals(*begin, "no")) {
351 if (g_dnssecLogBogus) {
352 L<<Logger::Warning<<"Disabling DNSSEC Bogus logging, requested via control channel"<<endl;
353 g_dnssecLogBogus = false;
354 return "DNSSEC Bogus logging disabled\n";
355 }
356 return "DNSSEC Bogus logging was already disabled\n";
357 }
358
359 return "Unknown DNSSEC Bogus setting: '" + *begin +"'\n";
360 }
361
362 template<typename T>
363 string doAddNTA(T begin, T end)
364 {
365 if(checkDNSSECDisabled())
366 return "DNSSEC is disabled in the configuration, not adding a Negative Trust Anchor\n";
367
368 if(begin == end)
369 return "No NTA specified, doing nothing\n";
370
371 DNSName who;
372 try {
373 who = DNSName(*begin);
374 }
375 catch(std::exception &e) {
376 string ret("Can't add Negative Trust Anchor: ");
377 ret += e.what();
378 ret += "\n";
379 return ret;
380 }
381 begin++;
382
383 string why("");
384 while (begin != end) {
385 why += *begin;
386 begin++;
387 if (begin != end)
388 why += " ";
389 }
390 L<<Logger::Warning<<"Adding Negative Trust Anchor for "<<who<<" with reason '"<<why<<"', requested via control channel"<<endl;
391 g_luaconfs.modify([who, why](LuaConfigItems& lci) {
392 lci.negAnchors[who] = why;
393 });
394 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, who, true));
395 return "Added Negative Trust Anchor for " + who.toLogString() + " with reason '" + why + "'\n";
396 }
397
398 template<typename T>
399 string doClearNTA(T begin, T end)
400 {
401 if(checkDNSSECDisabled())
402 return "DNSSEC is disabled in the configuration, not removing a Negative Trust Anchor\n";
403
404 if(begin == end)
405 return "No Negative Trust Anchor specified, doing nothing.\n";
406
407 if (begin + 1 == end && *begin == "*"){
408 L<<Logger::Warning<<"Clearing all Negative Trust Anchors, requested via control channel"<<endl;
409 g_luaconfs.modify([](LuaConfigItems& lci) {
410 lci.negAnchors.clear();
411 });
412 return "Cleared all Negative Trust Anchors.\n";
413 }
414
415 vector<DNSName> toRemove;
416 DNSName who;
417 while (begin != end) {
418 if (*begin == "*")
419 return "Don't mix all Negative Trust Anchor removal with multiple Negative Trust Anchor removal. Nothing removed\n";
420 try {
421 who = DNSName(*begin);
422 }
423 catch(std::exception &e) {
424 string ret("Error: ");
425 ret += e.what();
426 ret += ". No Negative Anchors removed\n";
427 return ret;
428 }
429 toRemove.push_back(who);
430 begin++;
431 }
432
433 string removed("");
434 bool first(true);
435 for (auto const &entry : toRemove) {
436 L<<Logger::Warning<<"Clearing Negative Trust Anchor for "<<entry<<", requested via control channel"<<endl;
437 g_luaconfs.modify([entry](LuaConfigItems& lci) {
438 lci.negAnchors.erase(entry);
439 });
440 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, entry, true));
441 if (!first) {
442 first = false;
443 removed += ",";
444 }
445 removed += " " + entry.toStringRootDot();
446 }
447 return "Removed Negative Trust Anchors for " + removed + "\n";
448 }
449
450 static string getNTAs()
451 {
452 if(checkDNSSECDisabled())
453 return "DNSSEC is disabled in the configuration\n";
454
455 string ret("Configured Negative Trust Anchors:\n");
456 auto luaconf = g_luaconfs.getLocal();
457 for (auto negAnchor : luaconf->negAnchors)
458 ret += negAnchor.first.toLogString() + "\t" + negAnchor.second + "\n";
459 return ret;
460 }
461
462 template<typename T>
463 string doAddTA(T begin, T end)
464 {
465 if(checkDNSSECDisabled())
466 return "DNSSEC is disabled in the configuration, not adding a Trust Anchor\n";
467
468 if(begin == end)
469 return "No TA specified, doing nothing\n";
470
471 DNSName who;
472 try {
473 who = DNSName(*begin);
474 }
475 catch(std::exception &e) {
476 string ret("Can't add Trust Anchor: ");
477 ret += e.what();
478 ret += "\n";
479 return ret;
480 }
481 begin++;
482
483 string what("");
484 while (begin != end) {
485 what += *begin + " ";
486 begin++;
487 }
488
489 try {
490 L<<Logger::Warning<<"Adding Trust Anchor for "<<who<<" with data '"<<what<<"', requested via control channel";
491 g_luaconfs.modify([who, what](LuaConfigItems& lci) {
492 auto ds = unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(what)));
493 lci.dsAnchors[who].insert(*ds);
494 });
495 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, who, true));
496 L<<Logger::Warning<<endl;
497 return "Added Trust Anchor for " + who.toStringRootDot() + " with data " + what + "\n";
498 }
499 catch(std::exception &e) {
500 L<<Logger::Warning<<", failed: "<<e.what()<<endl;
501 return "Unable to add Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n";
502 }
503 }
504
505 template<typename T>
506 string doClearTA(T begin, T end)
507 {
508 if(checkDNSSECDisabled())
509 return "DNSSEC is disabled in the configuration, not removing a Trust Anchor\n";
510
511 if(begin == end)
512 return "No Trust Anchor to clear\n";
513
514 vector<DNSName> toRemove;
515 DNSName who;
516 while (begin != end) {
517 try {
518 who = DNSName(*begin);
519 }
520 catch(std::exception &e) {
521 string ret("Error: ");
522 ret += e.what();
523 ret += ". No Anchors removed\n";
524 return ret;
525 }
526 if (who.isRoot())
527 return "Refusing to remove root Trust Anchor, no Anchors removed\n";
528 toRemove.push_back(who);
529 begin++;
530 }
531
532 string removed("");
533 bool first(true);
534 for (auto const &entry : toRemove) {
535 L<<Logger::Warning<<"Removing Trust Anchor for "<<entry<<", requested via control channel"<<endl;
536 g_luaconfs.modify([entry](LuaConfigItems& lci) {
537 lci.dsAnchors.erase(entry);
538 });
539 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, entry, true));
540 if (!first) {
541 first = false;
542 removed += ",";
543 }
544 removed += " " + entry.toStringRootDot();
545 }
546 return "Removed Trust Anchor(s) for" + removed + "\n";
547 }
548
549 static string getTAs()
550 {
551 if(checkDNSSECDisabled())
552 return "DNSSEC is disabled in the configuration\n";
553
554 string ret("Configured Trust Anchors:\n");
555 auto luaconf = g_luaconfs.getLocal();
556 for (auto anchor : luaconf->dsAnchors) {
557 ret += anchor.first.toLogString() + "\n";
558 for (auto e : anchor.second) {
559 ret+="\t\t"+e.getZoneRepresentation() + "\n";
560 }
561 }
562
563 return ret;
564 }
565
566 template<typename T>
567 string setMinimumTTL(T begin, T end)
568 {
569 if(end-begin != 1)
570 return "Need to supply new minimum TTL number\n";
571 SyncRes::s_minimumTTL = pdns_stou(*begin);
572 return "New minimum TTL: " + std::to_string(SyncRes::s_minimumTTL) + "\n";
573 }
574
575
576 static uint64_t getSysTimeMsec()
577 {
578 struct rusage ru;
579 getrusage(RUSAGE_SELF, &ru);
580 return (ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000);
581 }
582
583 static uint64_t getUserTimeMsec()
584 {
585 struct rusage ru;
586 getrusage(RUSAGE_SELF, &ru);
587 return (ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000);
588 }
589
590 static uint64_t calculateUptime()
591 {
592 return time(0) - g_stats.startupTime;
593 }
594
595 static string* pleaseGetCurrentQueries()
596 {
597 ostringstream ostr;
598
599 ostr << getMT()->d_waiters.size() <<" currently outstanding questions\n";
600
601 boost::format fmt("%1% %|40t|%2% %|47t|%3% %|63t|%4% %|68t|%5%\n");
602
603 ostr << (fmt % "qname" % "qtype" % "remote" % "tcp" % "chained");
604 unsigned int n=0;
605 for(const auto& mthread : getMT()->d_waiters) {
606 const PacketID& pident = mthread.key;
607 ostr << (fmt
608 % pident.domain.toLogString() /* ?? */ % DNSRecordContent::NumberToType(pident.type)
609 % pident.remote.toString() % (pident.sock ? 'Y' : 'n')
610 % (pident.fd == -1 ? 'Y' : 'n')
611 );
612 ++n;
613 if (n >= 100)
614 break;
615 }
616 ostr <<" - done\n";
617 return new string(ostr.str());
618 }
619
620 static string doCurrentQueries()
621 {
622 return broadcastAccFunction<string>(pleaseGetCurrentQueries);
623 }
624
625 uint64_t* pleaseGetThrottleSize()
626 {
627 return new uint64_t(SyncRes::getThrottledServersSize());
628 }
629
630 static uint64_t getThrottleSize()
631 {
632 return broadcastAccFunction<uint64_t>(pleaseGetThrottleSize);
633 }
634
635 uint64_t* pleaseGetNegCacheSize()
636 {
637 uint64_t tmp=(SyncRes::getNegCacheSize());
638 return new uint64_t(tmp);
639 }
640
641 uint64_t getNegCacheSize()
642 {
643 return broadcastAccFunction<uint64_t>(pleaseGetNegCacheSize);
644 }
645
646 uint64_t* pleaseGetFailedHostsSize()
647 {
648 uint64_t tmp=(SyncRes::getThrottledServersSize());
649 return new uint64_t(tmp);
650 }
651 uint64_t getFailedHostsSize()
652 {
653 return broadcastAccFunction<uint64_t>(pleaseGetFailedHostsSize);
654 }
655
656 uint64_t* pleaseGetNsSpeedsSize()
657 {
658 return new uint64_t(SyncRes::getNSSpeedsSize());
659 }
660
661 uint64_t getNsSpeedsSize()
662 {
663 return broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize);
664 }
665
666 uint64_t* pleaseGetConcurrentQueries()
667 {
668 return new uint64_t(getMT() ? getMT()->numProcesses() : 0);
669 }
670
671 static uint64_t getConcurrentQueries()
672 {
673 return broadcastAccFunction<uint64_t>(pleaseGetConcurrentQueries);
674 }
675
676 uint64_t* pleaseGetCacheSize()
677 {
678 return new uint64_t(t_RC ? t_RC->size() : 0);
679 }
680
681 uint64_t* pleaseGetCacheBytes()
682 {
683 return new uint64_t(t_RC ? t_RC->bytes() : 0);
684 }
685
686
687 uint64_t doGetCacheSize()
688 {
689 return broadcastAccFunction<uint64_t>(pleaseGetCacheSize);
690 }
691
692 uint64_t doGetAvgLatencyUsec()
693 {
694 return (uint64_t) g_stats.avgLatencyUsec;
695 }
696
697
698 uint64_t doGetCacheBytes()
699 {
700 return broadcastAccFunction<uint64_t>(pleaseGetCacheBytes);
701 }
702
703 uint64_t* pleaseGetCacheHits()
704 {
705 return new uint64_t(t_RC ? t_RC->cacheHits : 0);
706 }
707
708 uint64_t doGetCacheHits()
709 {
710 return broadcastAccFunction<uint64_t>(pleaseGetCacheHits);
711 }
712
713 uint64_t* pleaseGetCacheMisses()
714 {
715 return new uint64_t(t_RC ? t_RC->cacheMisses : 0);
716 }
717
718 uint64_t doGetCacheMisses()
719 {
720 return broadcastAccFunction<uint64_t>(pleaseGetCacheMisses);
721 }
722
723
724 uint64_t* pleaseGetPacketCacheSize()
725 {
726 return new uint64_t(t_packetCache ? t_packetCache->size() : 0);
727 }
728
729 uint64_t* pleaseGetPacketCacheBytes()
730 {
731 return new uint64_t(t_packetCache ? t_packetCache->bytes() : 0);
732 }
733
734
735 uint64_t doGetPacketCacheSize()
736 {
737 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheSize);
738 }
739
740 uint64_t doGetPacketCacheBytes()
741 {
742 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheBytes);
743 }
744
745
746 uint64_t* pleaseGetPacketCacheHits()
747 {
748 return new uint64_t(t_packetCache ? t_packetCache->d_hits : 0);
749 }
750
751 uint64_t doGetPacketCacheHits()
752 {
753 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheHits);
754 }
755
756 uint64_t* pleaseGetPacketCacheMisses()
757 {
758 return new uint64_t(t_packetCache ? t_packetCache->d_misses : 0);
759 }
760
761 uint64_t doGetPacketCacheMisses()
762 {
763 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheMisses);
764 }
765
766 uint64_t doGetMallocated()
767 {
768 // this turned out to be broken
769 /* struct mallinfo mi = mallinfo();
770 return mi.uordblks; */
771 return 0;
772 }
773
774 extern ResponseStats g_rs;
775
776 void registerAllStats()
777 {
778 static bool s_init = false;
779 if(s_init)
780 return;
781 s_init=true;
782
783 addGetStat("questions", &g_stats.qcounter);
784 addGetStat("ipv6-questions", &g_stats.ipv6qcounter);
785 addGetStat("tcp-questions", &g_stats.tcpqcounter);
786
787 addGetStat("cache-hits", doGetCacheHits);
788 addGetStat("cache-misses", doGetCacheMisses);
789 addGetStat("cache-entries", doGetCacheSize);
790 addGetStat("cache-bytes", doGetCacheBytes);
791
792 addGetStat("packetcache-hits", doGetPacketCacheHits);
793 addGetStat("packetcache-misses", doGetPacketCacheMisses);
794 addGetStat("packetcache-entries", doGetPacketCacheSize);
795 addGetStat("packetcache-bytes", doGetPacketCacheBytes);
796
797 addGetStat("malloc-bytes", doGetMallocated);
798
799 addGetStat("servfail-answers", &g_stats.servFails);
800 addGetStat("nxdomain-answers", &g_stats.nxDomains);
801 addGetStat("noerror-answers", &g_stats.noErrors);
802
803 addGetStat("unauthorized-udp", &g_stats.unauthorizedUDP);
804 addGetStat("unauthorized-tcp", &g_stats.unauthorizedTCP);
805 addGetStat("tcp-client-overflow", &g_stats.tcpClientOverflow);
806
807 addGetStat("client-parse-errors", &g_stats.clientParseError);
808 addGetStat("server-parse-errors", &g_stats.serverParseError);
809 addGetStat("too-old-drops", &g_stats.tooOldDrops);
810
811 addGetStat("answers0-1", &g_stats.answers0_1);
812 addGetStat("answers1-10", &g_stats.answers1_10);
813 addGetStat("answers10-100", &g_stats.answers10_100);
814 addGetStat("answers100-1000", &g_stats.answers100_1000);
815 addGetStat("answers-slow", &g_stats.answersSlow);
816
817 addGetStat("auth4-answers0-1", &g_stats.auth4Answers0_1);
818 addGetStat("auth4-answers1-10", &g_stats.auth4Answers1_10);
819 addGetStat("auth4-answers10-100", &g_stats.auth4Answers10_100);
820 addGetStat("auth4-answers100-1000", &g_stats.auth4Answers100_1000);
821 addGetStat("auth4-answers-slow", &g_stats.auth4AnswersSlow);
822
823 addGetStat("auth6-answers0-1", &g_stats.auth6Answers0_1);
824 addGetStat("auth6-answers1-10", &g_stats.auth6Answers1_10);
825 addGetStat("auth6-answers10-100", &g_stats.auth6Answers10_100);
826 addGetStat("auth6-answers100-1000", &g_stats.auth6Answers100_1000);
827 addGetStat("auth6-answers-slow", &g_stats.auth6AnswersSlow);
828
829
830 addGetStat("qa-latency", doGetAvgLatencyUsec);
831 addGetStat("unexpected-packets", &g_stats.unexpectedCount);
832 addGetStat("case-mismatches", &g_stats.caseMismatchCount);
833 addGetStat("spoof-prevents", &g_stats.spoofCount);
834
835 addGetStat("nsset-invalidations", &g_stats.nsSetInvalidations);
836
837 addGetStat("resource-limits", &g_stats.resourceLimits);
838 addGetStat("over-capacity-drops", &g_stats.overCapacityDrops);
839 addGetStat("policy-drops", &g_stats.policyDrops);
840 addGetStat("no-packet-error", &g_stats.noPacketError);
841 addGetStat("dlg-only-drops", &SyncRes::s_nodelegated);
842 addGetStat("ignored-packets", &g_stats.ignoredCount);
843 addGetStat("max-mthread-stack", &g_stats.maxMThreadStackUsage);
844
845 addGetStat("negcache-entries", boost::bind(getNegCacheSize));
846 addGetStat("throttle-entries", boost::bind(getThrottleSize));
847
848 addGetStat("nsspeeds-entries", boost::bind(getNsSpeedsSize));
849 addGetStat("failed-host-entries", boost::bind(getFailedHostsSize));
850
851 addGetStat("concurrent-queries", boost::bind(getConcurrentQueries));
852 addGetStat("security-status", &g_security_status);
853 addGetStat("outgoing-timeouts", &SyncRes::s_outgoingtimeouts);
854 addGetStat("outgoing4-timeouts", &SyncRes::s_outgoing4timeouts);
855 addGetStat("outgoing6-timeouts", &SyncRes::s_outgoing6timeouts);
856 addGetStat("tcp-outqueries", &SyncRes::s_tcpoutqueries);
857 addGetStat("all-outqueries", &SyncRes::s_outqueries);
858 addGetStat("ipv6-outqueries", &g_stats.ipv6queries);
859 addGetStat("throttled-outqueries", &SyncRes::s_throttledqueries);
860 addGetStat("dont-outqueries", &SyncRes::s_dontqueries);
861 addGetStat("throttled-out", &SyncRes::s_throttledqueries);
862 addGetStat("unreachables", &SyncRes::s_unreachables);
863 addGetStat("ecs-queries", &SyncRes::s_ecsqueries);
864 addGetStat("ecs-responses", &SyncRes::s_ecsresponses);
865 addGetStat("chain-resends", &g_stats.chainResends);
866 addGetStat("tcp-clients", boost::bind(TCPConnection::getCurrentConnections));
867
868 #ifdef __linux__
869 addGetStat("udp-recvbuf-errors", boost::bind(udpErrorStats, "udp-recvbuf-errors"));
870 addGetStat("udp-sndbuf-errors", boost::bind(udpErrorStats, "udp-sndbuf-errors"));
871 addGetStat("udp-noport-errors", boost::bind(udpErrorStats, "udp-noport-errors"));
872 addGetStat("udp-in-errors", boost::bind(udpErrorStats, "udp-in-errors"));
873 #endif
874
875 addGetStat("edns-ping-matches", &g_stats.ednsPingMatches);
876 addGetStat("edns-ping-mismatches", &g_stats.ednsPingMismatches);
877 addGetStat("dnssec-queries", &g_stats.dnssecQueries);
878
879 addGetStat("noping-outqueries", &g_stats.noPingOutQueries);
880 addGetStat("noedns-outqueries", &g_stats.noEdnsOutQueries);
881
882 addGetStat("uptime", calculateUptime);
883 addGetStat("real-memory-usage", boost::bind(getRealMemoryUsage, string()));
884 addGetStat("fd-usage", boost::bind(getOpenFileDescriptors, string()));
885
886 // addGetStat("query-rate", getQueryRate);
887 addGetStat("user-msec", getUserTimeMsec);
888 addGetStat("sys-msec", getSysTimeMsec);
889
890 #ifdef MALLOC_TRACE
891 addGetStat("memory-allocs", boost::bind(&MallocTracer::getAllocs, g_mtracer, string()));
892 addGetStat("memory-alloc-flux", boost::bind(&MallocTracer::getAllocFlux, g_mtracer, string()));
893 addGetStat("memory-allocated", boost::bind(&MallocTracer::getTotAllocated, g_mtracer, string()));
894 #endif
895
896 addGetStat("dnssec-validations", &g_stats.dnssecValidations);
897 addGetStat("dnssec-result-insecure", &g_stats.dnssecResults[Insecure]);
898 addGetStat("dnssec-result-secure", &g_stats.dnssecResults[Secure]);
899 addGetStat("dnssec-result-bogus", &g_stats.dnssecResults[Bogus]);
900 addGetStat("dnssec-result-indeterminate", &g_stats.dnssecResults[Indeterminate]);
901 addGetStat("dnssec-result-nta", &g_stats.dnssecResults[NTA]);
902
903 addGetStat("policy-result-noaction", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NoAction]);
904 addGetStat("policy-result-drop", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Drop]);
905 addGetStat("policy-result-nxdomain", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NXDOMAIN]);
906 addGetStat("policy-result-nodata", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NODATA]);
907 addGetStat("policy-result-truncate", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Truncate]);
908 addGetStat("policy-result-custom", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Custom]);
909 }
910
911 static void doExitGeneric(bool nicely)
912 {
913 L<<Logger::Error<<"Exiting on user request"<<endl;
914 extern RecursorControlChannel s_rcc;
915 s_rcc.~RecursorControlChannel();
916
917 extern string s_pidfname;
918 if(!s_pidfname.empty())
919 unlink(s_pidfname.c_str()); // we can at least try..
920 if(nicely)
921 exit(1);
922 else
923 _exit(1);
924 }
925
926 static void doExit()
927 {
928 doExitGeneric(false);
929 }
930
931 static void doExitNicely()
932 {
933 doExitGeneric(true);
934 }
935
936 vector<pair<DNSName, uint16_t> >* pleaseGetQueryRing()
937 {
938 typedef pair<DNSName,uint16_t> query_t;
939 vector<query_t >* ret = new vector<query_t>();
940 if(!t_queryring)
941 return ret;
942 ret->reserve(t_queryring->size());
943
944 for(const query_t& q : *t_queryring) {
945 ret->push_back(q);
946 }
947 return ret;
948 }
949 vector<pair<DNSName,uint16_t> >* pleaseGetServfailQueryRing()
950 {
951 typedef pair<DNSName,uint16_t> query_t;
952 vector<query_t>* ret = new vector<query_t>();
953 if(!t_servfailqueryring)
954 return ret;
955 ret->reserve(t_servfailqueryring->size());
956 for(const query_t& q : *t_servfailqueryring) {
957 ret->push_back(q);
958 }
959 return ret;
960 }
961
962
963
964 typedef boost::function<vector<ComboAddress>*()> pleaseremotefunc_t;
965 typedef boost::function<vector<pair<DNSName,uint16_t> >*()> pleasequeryfunc_t;
966
967 vector<ComboAddress>* pleaseGetRemotes()
968 {
969 vector<ComboAddress>* ret = new vector<ComboAddress>();
970 if(!t_remotes)
971 return ret;
972
973 ret->reserve(t_remotes->size());
974 for(const ComboAddress& ca : *t_remotes) {
975 ret->push_back(ca);
976 }
977 return ret;
978 }
979
980 vector<ComboAddress>* pleaseGetServfailRemotes()
981 {
982 vector<ComboAddress>* ret = new vector<ComboAddress>();
983 if(!t_servfailremotes)
984 return ret;
985 ret->reserve(t_servfailremotes->size());
986 for(const ComboAddress& ca : *t_servfailremotes) {
987 ret->push_back(ca);
988 }
989 return ret;
990 }
991
992 vector<ComboAddress>* pleaseGetLargeAnswerRemotes()
993 {
994 vector<ComboAddress>* ret = new vector<ComboAddress>();
995 if(!t_largeanswerremotes)
996 return ret;
997 ret->reserve(t_largeanswerremotes->size());
998 for(const ComboAddress& ca : *t_largeanswerremotes) {
999 ret->push_back(ca);
1000 }
1001 return ret;
1002 }
1003
1004 string doGenericTopRemotes(pleaseremotefunc_t func)
1005 {
1006 typedef map<ComboAddress, int, ComboAddress::addressOnlyLessThan> counts_t;
1007 counts_t counts;
1008
1009 vector<ComboAddress> remotes=broadcastAccFunction<vector<ComboAddress> >(func);
1010
1011 unsigned int total=0;
1012 for(const ComboAddress& ca : remotes) {
1013 total++;
1014 counts[ca]++;
1015 }
1016
1017 typedef std::multimap<int, ComboAddress> rcounts_t;
1018 rcounts_t rcounts;
1019
1020 for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
1021 rcounts.insert(make_pair(-i->second, i->first));
1022
1023 ostringstream ret;
1024 ret<<"Over last "<<total<<" entries:\n";
1025 format fmt("%.02f%%\t%s\n");
1026 int limit=0, accounted=0;
1027 if(total) {
1028 for(rcounts_t::const_iterator i=rcounts.begin(); i != rcounts.end() && limit < 20; ++i, ++limit) {
1029 ret<< fmt % (-100.0*i->first/total) % i->second.toString();
1030 accounted+= -i->first;
1031 }
1032 ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest";
1033 }
1034 return ret.str();
1035 }
1036
1037 namespace {
1038 typedef vector<vector<string> > pubs_t;
1039 pubs_t g_pubs;
1040 }
1041
1042 void sortPublicSuffixList()
1043 {
1044 for(const char** p=g_pubsuffix; *p; ++p) {
1045 string low=toLower(*p);
1046
1047 vector<string> parts;
1048 stringtok(parts, low, ".");
1049 reverse(parts.begin(), parts.end());
1050 g_pubs.push_back(parts);
1051 }
1052 sort(g_pubs.begin(), g_pubs.end());
1053 }
1054
1055 // XXX DNSName Pain - this function should benefit from native DNSName methods
1056 DNSName getRegisteredName(const DNSName& dom)
1057 {
1058 auto parts=dom.getRawLabels();
1059 if(parts.size()<=2)
1060 return dom;
1061 reverse(parts.begin(), parts.end());
1062 for(string& str : parts) { str=toLower(str); };
1063
1064 // uk co migweb
1065 string last;
1066 while(!parts.empty()) {
1067 if(parts.size()==1 || binary_search(g_pubs.begin(), g_pubs.end(), parts)) {
1068
1069 string ret=last;
1070 if(!ret.empty())
1071 ret+=".";
1072
1073 for(auto p = parts.crbegin(); p != parts.crend(); ++p) {
1074 ret+=(*p)+".";
1075 }
1076 return DNSName(ret);
1077 }
1078
1079 last=parts[parts.size()-1];
1080 parts.resize(parts.size()-1);
1081 }
1082 return DNSName("??");
1083 }
1084
1085 static DNSName nopFilter(const DNSName& name)
1086 {
1087 return name;
1088 }
1089
1090 string doGenericTopQueries(pleasequeryfunc_t func, boost::function<DNSName(const DNSName&)> filter=nopFilter)
1091 {
1092 typedef pair<DNSName,uint16_t> query_t;
1093 typedef map<query_t, int> counts_t;
1094 counts_t counts;
1095 vector<query_t> queries=broadcastAccFunction<vector<query_t> >(func);
1096
1097 unsigned int total=0;
1098 for(const query_t& q : queries) {
1099 total++;
1100 counts[make_pair(filter(q.first),q.second)]++;
1101 }
1102
1103 typedef std::multimap<int, query_t> rcounts_t;
1104 rcounts_t rcounts;
1105
1106 for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
1107 rcounts.insert(make_pair(-i->second, i->first));
1108
1109 ostringstream ret;
1110 ret<<"Over last "<<total<<" entries:\n";
1111 format fmt("%.02f%%\t%s\n");
1112 int limit=0, accounted=0;
1113 if(total) {
1114 for(rcounts_t::const_iterator i=rcounts.begin(); i != rcounts.end() && limit < 20; ++i, ++limit) {
1115 ret<< fmt % (-100.0*i->first/total) % (i->second.first.toString()+"|"+DNSRecordContent::NumberToType(i->second.second));
1116 accounted+= -i->first;
1117 }
1118 ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest";
1119 }
1120
1121
1122 return ret.str();
1123 }
1124
1125 static string* nopFunction()
1126 {
1127 return new string("pong\n");
1128 }
1129
1130 string RecursorControlParser::getAnswer(const string& question, RecursorControlParser::func_t** command)
1131 {
1132 *command=nop;
1133 vector<string> words;
1134 stringtok(words, question);
1135
1136 if(words.empty())
1137 return "invalid command\n";
1138
1139 string cmd=toLower(words[0]);
1140 vector<string>::const_iterator begin=words.begin()+1, end=words.end();
1141
1142 // should probably have a smart dispatcher here, like auth has
1143 if(cmd=="help")
1144 return
1145 "add-nta DOMAIN [REASON] add a Negative Trust Anchor for DOMAIN with the comment REASON\n"
1146 "add-ta DOMAIN DSRECORD add a Trust Anchor for DOMAIN with data DSRECORD\n"
1147 "current-queries show currently active queries\n"
1148 "clear-nta [DOMAIN]... Clear the Negative Trust Anchor for DOMAINs, if no DOMAIN is specified, remove all\n"
1149 "clear-ta [DOMAIN]... Clear the Trust Anchor for DOMAINs\n"
1150 "dump-cache <filename> dump cache contents to the named file\n"
1151 "dump-edns [status] <filename> dump EDNS status to the named file\n"
1152 "dump-nsspeeds <filename> dump nsspeeds statistics to the named file\n"
1153 "get [key1] [key2] .. get specific statistics\n"
1154 "get-all get all statistics\n"
1155 "get-ntas get all configured Negative Trust Anchors\n"
1156 "get-tas get all configured Trust Anchors\n"
1157 "get-parameter [key1] [key2] .. get configuration parameters\n"
1158 "get-qtypelist get QType statistics\n"
1159 " notice: queries from cache aren't being counted yet\n"
1160 "help get this list\n"
1161 "ping check that all threads are alive\n"
1162 "quit stop the recursor daemon\n"
1163 "quit-nicely stop the recursor daemon nicely\n"
1164 "reload-acls reload ACLS\n"
1165 "reload-lua-script [filename] (re)load Lua script\n"
1166 "reload-lua-config [filename] (re)load Lua configuration file\n"
1167 "reload-zones reload all auth and forward zones\n"
1168 "set-minimum-ttl value set minimum-ttl-override\n"
1169 "set-carbon-server set a carbon server for telemetry\n"
1170 "set-dnssec-log-bogus SETTING enable (SETTING=yes) or disable (SETTING=no) logging of DNSSEC validation failures\n"
1171 "trace-regex [regex] emit resolution trace for matching queries (empty regex to clear trace)\n"
1172 "top-largeanswer-remotes show top remotes receiving large answers\n"
1173 "top-queries show top queries\n"
1174 "top-pub-queries show top queries grouped by public suffix list\n"
1175 "top-remotes show top remotes\n"
1176 "top-servfail-queries show top queries receiving servfail answers\n"
1177 "top-pub-servfail-queries show top queries receiving servfail answers grouped by public suffix list\n"
1178 "top-servfail-remotes show top remotes receiving servfail answers\n"
1179 "unload-lua-script unload Lua script\n"
1180 "version return Recursor version number\n"
1181 "wipe-cache domain0 [domain1] .. wipe domain data from cache\n";
1182
1183 if(cmd=="get-all")
1184 return getAllStats();
1185
1186 if(cmd=="get")
1187 return doGet(begin, end);
1188
1189 if(cmd=="get-parameter")
1190 return doGetParameter(begin, end);
1191
1192 if(cmd=="quit") {
1193 *command=&doExit;
1194 return "bye\n";
1195 }
1196
1197 if(cmd=="version") {
1198 return getPDNSVersion()+"\n";
1199 }
1200
1201 if(cmd=="quit-nicely") {
1202 *command=&doExitNicely;
1203 return "bye nicely\n";
1204 }
1205
1206 if(cmd=="dump-cache")
1207 return doDumpCache(begin, end);
1208
1209 if(cmd=="dump-ednsstatus" || cmd=="dump-edns")
1210 return doDumpEDNSStatus(begin, end);
1211
1212 if(cmd=="dump-nsspeeds")
1213 return doDumpNSSpeeds(begin, end);
1214
1215 if(cmd=="wipe-cache" || cmd=="flushname")
1216 return doWipeCache(begin, end);
1217
1218 if(cmd=="reload-lua-script")
1219 return doQueueReloadLuaScript(begin, end);
1220
1221 if(cmd=="reload-lua-config") {
1222 if(begin != end)
1223 ::arg().set("lua-config-file") = *begin;
1224
1225 try {
1226 loadRecursorLuaConfig(::arg()["lua-config-file"], false);
1227 L<<Logger::Warning<<"Reloaded Lua configuration file '"<<::arg()["lua-config-file"]<<"', requested via control channel"<<endl;
1228 return "Reloaded Lua configuration file '"+::arg()["lua-config-file"]+"'\n";
1229 }
1230 catch(std::exception& e) {
1231 return "Unable to load Lua script from '"+::arg()["lua-config-file"]+"': "+e.what()+"\n";
1232 }
1233 catch(const PDNSException& e) {
1234 return "Unable to load Lua script from '"+::arg()["lua-config-file"]+"': "+e.reason+"\n";
1235 }
1236 }
1237
1238 if(cmd=="set-carbon-server")
1239 return doSetCarbonServer(begin, end);
1240
1241 if(cmd=="trace-regex")
1242 return doTraceRegex(begin, end);
1243
1244 if(cmd=="unload-lua-script") {
1245 vector<string> empty;
1246 empty.push_back(string());
1247 return doQueueReloadLuaScript(empty.begin(), empty.end());
1248 }
1249
1250 if(cmd=="reload-acls") {
1251 if(!::arg()["chroot"].empty()) {
1252 L<<Logger::Error<<"Unable to reload ACL when chroot()'ed, requested via control channel"<<endl;
1253 return "Unable to reload ACL when chroot()'ed, please restart\n";
1254 }
1255
1256 try {
1257 parseACLs();
1258 }
1259 catch(std::exception& e)
1260 {
1261 L<<Logger::Error<<"Reloading ACLs failed (Exception: "<<e.what()<<")"<<endl;
1262 return e.what() + string("\n");
1263 }
1264 catch(PDNSException& ae)
1265 {
1266 L<<Logger::Error<<"Reloading ACLs failed (PDNSException: "<<ae.reason<<")"<<endl;
1267 return ae.reason + string("\n");
1268 }
1269 return "ok\n";
1270 }
1271
1272
1273 if(cmd=="top-remotes")
1274 return doGenericTopRemotes(pleaseGetRemotes);
1275
1276 if(cmd=="top-queries")
1277 return doGenericTopQueries(pleaseGetQueryRing);
1278
1279 if(cmd=="top-pub-queries")
1280 return doGenericTopQueries(pleaseGetQueryRing, getRegisteredName);
1281
1282 if(cmd=="top-servfail-queries")
1283 return doGenericTopQueries(pleaseGetServfailQueryRing);
1284
1285 if(cmd=="top-pub-servfail-queries")
1286 return doGenericTopQueries(pleaseGetServfailQueryRing, getRegisteredName);
1287
1288
1289 if(cmd=="top-servfail-remotes")
1290 return doGenericTopRemotes(pleaseGetServfailRemotes);
1291
1292 if(cmd=="top-largeanswer-remotes")
1293 return doGenericTopRemotes(pleaseGetLargeAnswerRemotes);
1294
1295
1296 if(cmd=="current-queries")
1297 return doCurrentQueries();
1298
1299 if(cmd=="ping") {
1300 return broadcastAccFunction<string>(nopFunction);
1301 }
1302
1303 if(cmd=="reload-zones") {
1304 if(!::arg()["chroot"].empty()) {
1305 L<<Logger::Error<<"Unable to reload zones and forwards when chroot()'ed, requested via control channel"<<endl;
1306 return "Unable to reload zones and forwards when chroot()'ed, please restart\n";
1307 }
1308 return reloadAuthAndForwards();
1309 }
1310
1311 if(cmd=="set-minimum-ttl") {
1312 return setMinimumTTL(begin, end);
1313 }
1314
1315 if(cmd=="get-qtypelist") {
1316 return g_rs.getQTypeReport();
1317 }
1318
1319 if(cmd=="add-nta") {
1320 return doAddNTA(begin, end);
1321 }
1322
1323 if(cmd=="clear-nta") {
1324 return doClearNTA(begin, end);
1325 }
1326
1327 if(cmd=="get-ntas") {
1328 return getNTAs();
1329 }
1330
1331 if(cmd=="add-ta") {
1332 return doAddTA(begin, end);
1333 }
1334
1335 if(cmd=="clear-ta") {
1336 return doClearTA(begin, end);
1337 }
1338
1339 if(cmd=="get-tas") {
1340 return getTAs();
1341 }
1342
1343 if (cmd=="set-dnssec-log-bogus")
1344 return doSetDnssecLogBogus(begin, end);
1345
1346 return "Unknown command '"+cmd+"', try 'help'\n";
1347 }