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