]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rec_channel_rec.cc
Merge pull request #7903 from Habbie/dnsdist-doc-nits
[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 /* This is a pretty weird set of functions. To get per-thread cpu usage numbers,
766 we have to ask a thread over a pipe. We could do so surgically, so if you want to know about
767 thread 3, we pick pipe 3, but we lack that infrastructure.
768
769 We can however ask "execute this function on all threads and add up the results".
770 This is what the first function does using a custom object ThreadTimes, which if you add
771 to each other keeps filling the first one with CPU usage numbers
772 */
773
774 static ThreadTimes* pleaseGetThreadCPUMsec()
775 {
776 uint64_t ret=0;
777 #ifdef RUSAGE_THREAD
778 struct rusage ru;
779 getrusage(RUSAGE_THREAD, &ru);
780 ret = (ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000);
781 ret += (ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000);
782 #endif
783 return new ThreadTimes{ret};
784 }
785
786 /* Next up, when you want msec data for a specific thread, we check
787 if we recently executed pleaseGetThreadCPUMsec. If we didn't we do so
788 now and consult all threads.
789
790 We then answer you from the (re)fresh(ed) ThreadTimes.
791 */
792 static uint64_t doGetThreadCPUMsec(int n)
793 {
794 static std::mutex s_mut;
795 static time_t last = 0;
796 static ThreadTimes tt;
797
798 std::lock_guard<std::mutex> l(s_mut);
799 if(last != time(nullptr)) {
800 tt = broadcastAccFunction<ThreadTimes>(pleaseGetThreadCPUMsec);
801 last = time(nullptr);
802 }
803
804 return tt.times.at(n);
805 }
806
807 static uint64_t calculateUptime()
808 {
809 return time(nullptr) - g_stats.startupTime;
810 }
811
812 static string* pleaseGetCurrentQueries()
813 {
814 ostringstream ostr;
815 struct timeval now;
816 gettimeofday(&now, 0);
817
818 ostr << getMT()->d_waiters.size() <<" currently outstanding questions\n";
819
820 boost::format fmt("%1% %|40t|%2% %|47t|%3% %|63t|%4% %|68t|%5% %|78t|%6%\n");
821
822 ostr << (fmt % "qname" % "qtype" % "remote" % "tcp" % "chained" % "spent(ms)");
823 unsigned int n=0;
824 for(const auto& mthread : getMT()->d_waiters) {
825 const PacketID& pident = mthread.key;
826 const double spent = g_networkTimeoutMsec - (DiffTime(now, mthread.ttd) * 1000);
827 ostr << (fmt
828 % pident.domain.toLogString() /* ?? */ % DNSRecordContent::NumberToType(pident.type)
829 % pident.remote.toString() % (pident.sock ? 'Y' : 'n')
830 % (pident.fd == -1 ? 'Y' : 'n')
831 % (spent > 0 ? spent : '0')
832 );
833 ++n;
834 if (n >= 100)
835 break;
836 }
837 ostr <<" - done\n";
838 return new string(ostr.str());
839 }
840
841 static string doCurrentQueries()
842 {
843 return broadcastAccFunction<string>(pleaseGetCurrentQueries);
844 }
845
846 uint64_t* pleaseGetThrottleSize()
847 {
848 return new uint64_t(SyncRes::getThrottledServersSize());
849 }
850
851 static uint64_t getThrottleSize()
852 {
853 return broadcastAccFunction<uint64_t>(pleaseGetThrottleSize);
854 }
855
856 uint64_t* pleaseGetNegCacheSize()
857 {
858 uint64_t tmp=(SyncRes::getNegCacheSize());
859 return new uint64_t(tmp);
860 }
861
862 static uint64_t getNegCacheSize()
863 {
864 return broadcastAccFunction<uint64_t>(pleaseGetNegCacheSize);
865 }
866
867 static uint64_t* pleaseGetFailedHostsSize()
868 {
869 uint64_t tmp=(SyncRes::getThrottledServersSize());
870 return new uint64_t(tmp);
871 }
872
873 static uint64_t getFailedHostsSize()
874 {
875 return broadcastAccFunction<uint64_t>(pleaseGetFailedHostsSize);
876 }
877
878 uint64_t* pleaseGetNsSpeedsSize()
879 {
880 return new uint64_t(SyncRes::getNSSpeedsSize());
881 }
882
883 static uint64_t getNsSpeedsSize()
884 {
885 return broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize);
886 }
887
888 uint64_t* pleaseGetConcurrentQueries()
889 {
890 return new uint64_t(getMT() ? getMT()->numProcesses() : 0);
891 }
892
893 static uint64_t getConcurrentQueries()
894 {
895 return broadcastAccFunction<uint64_t>(pleaseGetConcurrentQueries);
896 }
897
898 uint64_t* pleaseGetCacheSize()
899 {
900 return new uint64_t(t_RC ? t_RC->size() : 0);
901 }
902
903 static uint64_t* pleaseGetCacheBytes()
904 {
905 return new uint64_t(t_RC ? t_RC->bytes() : 0);
906 }
907
908 static uint64_t doGetCacheSize()
909 {
910 return broadcastAccFunction<uint64_t>(pleaseGetCacheSize);
911 }
912
913 static uint64_t doGetAvgLatencyUsec()
914 {
915 return (uint64_t) g_stats.avgLatencyUsec;
916 }
917
918 static uint64_t doGetCacheBytes()
919 {
920 return broadcastAccFunction<uint64_t>(pleaseGetCacheBytes);
921 }
922
923 uint64_t* pleaseGetCacheHits()
924 {
925 return new uint64_t(t_RC ? t_RC->cacheHits : 0);
926 }
927
928 static uint64_t doGetCacheHits()
929 {
930 return broadcastAccFunction<uint64_t>(pleaseGetCacheHits);
931 }
932
933 uint64_t* pleaseGetCacheMisses()
934 {
935 return new uint64_t(t_RC ? t_RC->cacheMisses : 0);
936 }
937
938 static uint64_t doGetCacheMisses()
939 {
940 return broadcastAccFunction<uint64_t>(pleaseGetCacheMisses);
941 }
942
943 uint64_t* pleaseGetPacketCacheSize()
944 {
945 return new uint64_t(t_packetCache ? t_packetCache->size() : 0);
946 }
947
948 static uint64_t* pleaseGetPacketCacheBytes()
949 {
950 return new uint64_t(t_packetCache ? t_packetCache->bytes() : 0);
951 }
952
953 static uint64_t doGetPacketCacheSize()
954 {
955 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheSize);
956 }
957
958 static uint64_t doGetPacketCacheBytes()
959 {
960 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheBytes);
961 }
962
963 uint64_t* pleaseGetPacketCacheHits()
964 {
965 return new uint64_t(t_packetCache ? t_packetCache->d_hits : 0);
966 }
967
968 static uint64_t doGetPacketCacheHits()
969 {
970 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheHits);
971 }
972
973 static uint64_t* pleaseGetPacketCacheMisses()
974 {
975 return new uint64_t(t_packetCache ? t_packetCache->d_misses : 0);
976 }
977
978 static uint64_t doGetPacketCacheMisses()
979 {
980 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheMisses);
981 }
982
983 static uint64_t doGetMallocated()
984 {
985 // this turned out to be broken
986 /* struct mallinfo mi = mallinfo();
987 return mi.uordblks; */
988 return 0;
989 }
990
991 extern ResponseStats g_rs;
992
993 void registerAllStats()
994 {
995 static std::atomic_flag s_init = ATOMIC_FLAG_INIT;
996 if(s_init.test_and_set())
997 return;
998
999 addGetStat("questions", &g_stats.qcounter);
1000 addGetStat("ipv6-questions", &g_stats.ipv6qcounter);
1001 addGetStat("tcp-questions", &g_stats.tcpqcounter);
1002
1003 addGetStat("cache-hits", doGetCacheHits);
1004 addGetStat("cache-misses", doGetCacheMisses);
1005 addGetStat("cache-entries", doGetCacheSize);
1006 addGetStat("max-cache-entries", []() { return g_maxCacheEntries.load(); });
1007 addGetStat("max-packetcache-entries", []() { return g_maxPacketCacheEntries.load();});
1008 addGetStat("cache-bytes", doGetCacheBytes);
1009
1010 addGetStat("packetcache-hits", doGetPacketCacheHits);
1011 addGetStat("packetcache-misses", doGetPacketCacheMisses);
1012 addGetStat("packetcache-entries", doGetPacketCacheSize);
1013 addGetStat("packetcache-bytes", doGetPacketCacheBytes);
1014
1015 addGetStat("malloc-bytes", doGetMallocated);
1016
1017 addGetStat("servfail-answers", &g_stats.servFails);
1018 addGetStat("nxdomain-answers", &g_stats.nxDomains);
1019 addGetStat("noerror-answers", &g_stats.noErrors);
1020
1021 addGetStat("unauthorized-udp", &g_stats.unauthorizedUDP);
1022 addGetStat("unauthorized-tcp", &g_stats.unauthorizedTCP);
1023 addGetStat("tcp-client-overflow", &g_stats.tcpClientOverflow);
1024
1025 addGetStat("client-parse-errors", &g_stats.clientParseError);
1026 addGetStat("server-parse-errors", &g_stats.serverParseError);
1027 addGetStat("too-old-drops", &g_stats.tooOldDrops);
1028 addGetStat("truncated-drops", &g_stats.truncatedDrops);
1029 addGetStat("query-pipe-full-drops", &g_stats.queryPipeFullDrops);
1030
1031 addGetStat("answers0-1", &g_stats.answers0_1);
1032 addGetStat("answers1-10", &g_stats.answers1_10);
1033 addGetStat("answers10-100", &g_stats.answers10_100);
1034 addGetStat("answers100-1000", &g_stats.answers100_1000);
1035 addGetStat("answers-slow", &g_stats.answersSlow);
1036
1037 addGetStat("x-ourtime0-1", &g_stats.ourtime0_1);
1038 addGetStat("x-ourtime1-2", &g_stats.ourtime1_2);
1039 addGetStat("x-ourtime2-4", &g_stats.ourtime2_4);
1040 addGetStat("x-ourtime4-8", &g_stats.ourtime4_8);
1041 addGetStat("x-ourtime8-16", &g_stats.ourtime8_16);
1042 addGetStat("x-ourtime16-32", &g_stats.ourtime16_32);
1043 addGetStat("x-ourtime-slow", &g_stats.ourtimeSlow);
1044
1045 addGetStat("auth4-answers0-1", &g_stats.auth4Answers0_1);
1046 addGetStat("auth4-answers1-10", &g_stats.auth4Answers1_10);
1047 addGetStat("auth4-answers10-100", &g_stats.auth4Answers10_100);
1048 addGetStat("auth4-answers100-1000", &g_stats.auth4Answers100_1000);
1049 addGetStat("auth4-answers-slow", &g_stats.auth4AnswersSlow);
1050
1051 addGetStat("auth6-answers0-1", &g_stats.auth6Answers0_1);
1052 addGetStat("auth6-answers1-10", &g_stats.auth6Answers1_10);
1053 addGetStat("auth6-answers10-100", &g_stats.auth6Answers10_100);
1054 addGetStat("auth6-answers100-1000", &g_stats.auth6Answers100_1000);
1055 addGetStat("auth6-answers-slow", &g_stats.auth6AnswersSlow);
1056
1057
1058 addGetStat("qa-latency", doGetAvgLatencyUsec);
1059 addGetStat("x-our-latency", []() { return g_stats.avgLatencyOursUsec; });
1060 addGetStat("unexpected-packets", &g_stats.unexpectedCount);
1061 addGetStat("case-mismatches", &g_stats.caseMismatchCount);
1062 addGetStat("spoof-prevents", &g_stats.spoofCount);
1063
1064 addGetStat("nsset-invalidations", &g_stats.nsSetInvalidations);
1065
1066 addGetStat("resource-limits", &g_stats.resourceLimits);
1067 addGetStat("over-capacity-drops", &g_stats.overCapacityDrops);
1068 addGetStat("policy-drops", &g_stats.policyDrops);
1069 addGetStat("no-packet-error", &g_stats.noPacketError);
1070 addGetStat("dlg-only-drops", &SyncRes::s_nodelegated);
1071 addGetStat("ignored-packets", &g_stats.ignoredCount);
1072 addGetStat("empty-queries", &g_stats.emptyQueriesCount);
1073 addGetStat("max-mthread-stack", &g_stats.maxMThreadStackUsage);
1074
1075 addGetStat("negcache-entries", getNegCacheSize);
1076 addGetStat("throttle-entries", getThrottleSize);
1077
1078 addGetStat("nsspeeds-entries", getNsSpeedsSize);
1079 addGetStat("failed-host-entries", getFailedHostsSize);
1080
1081 addGetStat("concurrent-queries", getConcurrentQueries);
1082 addGetStat("security-status", &g_security_status);
1083 addGetStat("outgoing-timeouts", &SyncRes::s_outgoingtimeouts);
1084 addGetStat("outgoing4-timeouts", &SyncRes::s_outgoing4timeouts);
1085 addGetStat("outgoing6-timeouts", &SyncRes::s_outgoing6timeouts);
1086 addGetStat("auth-zone-queries", &SyncRes::s_authzonequeries);
1087 addGetStat("tcp-outqueries", &SyncRes::s_tcpoutqueries);
1088 addGetStat("all-outqueries", &SyncRes::s_outqueries);
1089 addGetStat("ipv6-outqueries", &g_stats.ipv6queries);
1090 addGetStat("throttled-outqueries", &SyncRes::s_throttledqueries);
1091 addGetStat("dont-outqueries", &SyncRes::s_dontqueries);
1092 addGetStat("throttled-out", &SyncRes::s_throttledqueries);
1093 addGetStat("unreachables", &SyncRes::s_unreachables);
1094 addGetStat("ecs-queries", &SyncRes::s_ecsqueries);
1095 addGetStat("ecs-responses", &SyncRes::s_ecsresponses);
1096 addGetStat("chain-resends", &g_stats.chainResends);
1097 addGetStat("tcp-clients", boost::bind(TCPConnection::getCurrentConnections));
1098
1099 #ifdef __linux__
1100 addGetStat("udp-recvbuf-errors", boost::bind(udpErrorStats, "udp-recvbuf-errors"));
1101 addGetStat("udp-sndbuf-errors", boost::bind(udpErrorStats, "udp-sndbuf-errors"));
1102 addGetStat("udp-noport-errors", boost::bind(udpErrorStats, "udp-noport-errors"));
1103 addGetStat("udp-in-errors", boost::bind(udpErrorStats, "udp-in-errors"));
1104 #endif
1105
1106 addGetStat("edns-ping-matches", &g_stats.ednsPingMatches);
1107 addGetStat("edns-ping-mismatches", &g_stats.ednsPingMismatches);
1108 addGetStat("dnssec-queries", &g_stats.dnssecQueries);
1109
1110 addGetStat("dnssec-authentic-data-queries", &g_stats.dnssecAuthenticDataQueries);
1111 addGetStat("dnssec-check-disabled-queries", &g_stats.dnssecCheckDisabledQueries);
1112
1113 addGetStat("variable-responses", &g_stats.variableResponses);
1114
1115 addGetStat("noping-outqueries", &g_stats.noPingOutQueries);
1116 addGetStat("noedns-outqueries", &g_stats.noEdnsOutQueries);
1117
1118 addGetStat("uptime", calculateUptime);
1119 addGetStat("real-memory-usage", boost::bind(getRealMemoryUsage, string()));
1120 addGetStat("special-memory-usage", boost::bind(getSpecialMemoryUsage, string()));
1121 addGetStat("fd-usage", boost::bind(getOpenFileDescriptors, string()));
1122
1123 // addGetStat("query-rate", getQueryRate);
1124 addGetStat("user-msec", getUserTimeMsec);
1125 addGetStat("sys-msec", getSysTimeMsec);
1126
1127 for(unsigned int n=0; n < g_numThreads; ++n)
1128 addGetStat("cpu-msec-thread-"+std::to_string(n), boost::bind(&doGetThreadCPUMsec, n));
1129
1130 #ifdef MALLOC_TRACE
1131 addGetStat("memory-allocs", boost::bind(&MallocTracer::getAllocs, g_mtracer, string()));
1132 addGetStat("memory-alloc-flux", boost::bind(&MallocTracer::getAllocFlux, g_mtracer, string()));
1133 addGetStat("memory-allocated", boost::bind(&MallocTracer::getTotAllocated, g_mtracer, string()));
1134 #endif
1135
1136 addGetStat("dnssec-validations", &g_stats.dnssecValidations);
1137 addGetStat("dnssec-result-insecure", &g_stats.dnssecResults[Insecure]);
1138 addGetStat("dnssec-result-secure", &g_stats.dnssecResults[Secure]);
1139 addGetStat("dnssec-result-bogus", &g_stats.dnssecResults[Bogus]);
1140 addGetStat("dnssec-result-indeterminate", &g_stats.dnssecResults[Indeterminate]);
1141 addGetStat("dnssec-result-nta", &g_stats.dnssecResults[NTA]);
1142
1143 addGetStat("policy-result-noaction", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NoAction]);
1144 addGetStat("policy-result-drop", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Drop]);
1145 addGetStat("policy-result-nxdomain", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NXDOMAIN]);
1146 addGetStat("policy-result-nodata", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NODATA]);
1147 addGetStat("policy-result-truncate", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Truncate]);
1148 addGetStat("policy-result-custom", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Custom]);
1149
1150 addGetStat("rebalanced-queries", &g_stats.rebalancedQueries);
1151
1152 /* make sure that the ECS stats are properly initialized */
1153 SyncRes::clearECSStats();
1154 for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize4.size(); idx++) {
1155 const std::string name = "ecs-v4-response-bits-" + std::to_string(idx + 1);
1156 addGetStat(name, &(SyncRes::s_ecsResponsesBySubnetSize4.at(idx)));
1157 }
1158 for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize6.size(); idx++) {
1159 const std::string name = "ecs-v6-response-bits-" + std::to_string(idx + 1);
1160 addGetStat(name, &(SyncRes::s_ecsResponsesBySubnetSize6.at(idx)));
1161 }
1162 }
1163
1164 static void doExitGeneric(bool nicely)
1165 {
1166 g_log<<Logger::Error<<"Exiting on user request"<<endl;
1167 extern RecursorControlChannel s_rcc;
1168 s_rcc.~RecursorControlChannel();
1169
1170 extern string s_pidfname;
1171 if(!s_pidfname.empty())
1172 unlink(s_pidfname.c_str()); // we can at least try..
1173 if(nicely)
1174 exit(1);
1175 else
1176 _exit(1);
1177 }
1178
1179 static void doExit()
1180 {
1181 doExitGeneric(false);
1182 }
1183
1184 static void doExitNicely()
1185 {
1186 doExitGeneric(true);
1187 }
1188
1189 vector<pair<DNSName, uint16_t> >* pleaseGetQueryRing()
1190 {
1191 typedef pair<DNSName,uint16_t> query_t;
1192 vector<query_t >* ret = new vector<query_t>();
1193 if(!t_queryring)
1194 return ret;
1195 ret->reserve(t_queryring->size());
1196
1197 for(const query_t& q : *t_queryring) {
1198 ret->push_back(q);
1199 }
1200 return ret;
1201 }
1202 vector<pair<DNSName,uint16_t> >* pleaseGetServfailQueryRing()
1203 {
1204 typedef pair<DNSName,uint16_t> query_t;
1205 vector<query_t>* ret = new vector<query_t>();
1206 if(!t_servfailqueryring)
1207 return ret;
1208 ret->reserve(t_servfailqueryring->size());
1209 for(const query_t& q : *t_servfailqueryring) {
1210 ret->push_back(q);
1211 }
1212 return ret;
1213 }
1214 vector<pair<DNSName,uint16_t> >* pleaseGetBogusQueryRing()
1215 {
1216 typedef pair<DNSName,uint16_t> query_t;
1217 vector<query_t>* ret = new vector<query_t>();
1218 if(!t_bogusqueryring)
1219 return ret;
1220 ret->reserve(t_bogusqueryring->size());
1221 for(const query_t& q : *t_bogusqueryring) {
1222 ret->push_back(q);
1223 }
1224 return ret;
1225 }
1226
1227
1228
1229 typedef boost::function<vector<ComboAddress>*()> pleaseremotefunc_t;
1230 typedef boost::function<vector<pair<DNSName,uint16_t> >*()> pleasequeryfunc_t;
1231
1232 vector<ComboAddress>* pleaseGetRemotes()
1233 {
1234 vector<ComboAddress>* ret = new vector<ComboAddress>();
1235 if(!t_remotes)
1236 return ret;
1237
1238 ret->reserve(t_remotes->size());
1239 for(const ComboAddress& ca : *t_remotes) {
1240 ret->push_back(ca);
1241 }
1242 return ret;
1243 }
1244
1245 vector<ComboAddress>* pleaseGetServfailRemotes()
1246 {
1247 vector<ComboAddress>* ret = new vector<ComboAddress>();
1248 if(!t_servfailremotes)
1249 return ret;
1250 ret->reserve(t_servfailremotes->size());
1251 for(const ComboAddress& ca : *t_servfailremotes) {
1252 ret->push_back(ca);
1253 }
1254 return ret;
1255 }
1256
1257 vector<ComboAddress>* pleaseGetBogusRemotes()
1258 {
1259 vector<ComboAddress>* ret = new vector<ComboAddress>();
1260 if(!t_bogusremotes)
1261 return ret;
1262 ret->reserve(t_bogusremotes->size());
1263 for(const ComboAddress& ca : *t_bogusremotes) {
1264 ret->push_back(ca);
1265 }
1266 return ret;
1267 }
1268
1269 vector<ComboAddress>* pleaseGetLargeAnswerRemotes()
1270 {
1271 vector<ComboAddress>* ret = new vector<ComboAddress>();
1272 if(!t_largeanswerremotes)
1273 return ret;
1274 ret->reserve(t_largeanswerremotes->size());
1275 for(const ComboAddress& ca : *t_largeanswerremotes) {
1276 ret->push_back(ca);
1277 }
1278 return ret;
1279 }
1280
1281 vector<ComboAddress>* pleaseGetTimeouts()
1282 {
1283 vector<ComboAddress>* ret = new vector<ComboAddress>();
1284 if(!t_timeouts)
1285 return ret;
1286 ret->reserve(t_timeouts->size());
1287 for(const ComboAddress& ca : *t_timeouts) {
1288 ret->push_back(ca);
1289 }
1290 return ret;
1291 }
1292
1293 string doGenericTopRemotes(pleaseremotefunc_t func)
1294 {
1295 typedef map<ComboAddress, int, ComboAddress::addressOnlyLessThan> counts_t;
1296 counts_t counts;
1297
1298 vector<ComboAddress> remotes=broadcastAccFunction<vector<ComboAddress> >(func);
1299
1300 unsigned int total=0;
1301 for(const ComboAddress& ca : remotes) {
1302 total++;
1303 counts[ca]++;
1304 }
1305
1306 typedef std::multimap<int, ComboAddress> rcounts_t;
1307 rcounts_t rcounts;
1308
1309 for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
1310 rcounts.insert(make_pair(-i->second, i->first));
1311
1312 ostringstream ret;
1313 ret<<"Over last "<<total<<" entries:\n";
1314 format fmt("%.02f%%\t%s\n");
1315 int limit=0, accounted=0;
1316 if(total) {
1317 for(rcounts_t::const_iterator i=rcounts.begin(); i != rcounts.end() && limit < 20; ++i, ++limit) {
1318 ret<< fmt % (-100.0*i->first/total) % i->second.toString();
1319 accounted+= -i->first;
1320 }
1321 ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest";
1322 }
1323 return ret.str();
1324 }
1325
1326 // XXX DNSName Pain - this function should benefit from native DNSName methods
1327 DNSName getRegisteredName(const DNSName& dom)
1328 {
1329 auto parts=dom.getRawLabels();
1330 if(parts.size()<=2)
1331 return dom;
1332 reverse(parts.begin(), parts.end());
1333 for(string& str : parts) { str=toLower(str); };
1334
1335 // uk co migweb
1336 string last;
1337 while(!parts.empty()) {
1338 if(parts.size()==1 || binary_search(g_pubs.begin(), g_pubs.end(), parts)) {
1339
1340 string ret=last;
1341 if(!ret.empty())
1342 ret+=".";
1343
1344 for(auto p = parts.crbegin(); p != parts.crend(); ++p) {
1345 ret+=(*p)+".";
1346 }
1347 return DNSName(ret);
1348 }
1349
1350 last=parts[parts.size()-1];
1351 parts.resize(parts.size()-1);
1352 }
1353 return DNSName("??");
1354 }
1355
1356 static DNSName nopFilter(const DNSName& name)
1357 {
1358 return name;
1359 }
1360
1361 string doGenericTopQueries(pleasequeryfunc_t func, boost::function<DNSName(const DNSName&)> filter=nopFilter)
1362 {
1363 typedef pair<DNSName,uint16_t> query_t;
1364 typedef map<query_t, int> counts_t;
1365 counts_t counts;
1366 vector<query_t> queries=broadcastAccFunction<vector<query_t> >(func);
1367
1368 unsigned int total=0;
1369 for(const query_t& q : queries) {
1370 total++;
1371 counts[make_pair(filter(q.first),q.second)]++;
1372 }
1373
1374 typedef std::multimap<int, query_t> rcounts_t;
1375 rcounts_t rcounts;
1376
1377 for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
1378 rcounts.insert(make_pair(-i->second, i->first));
1379
1380 ostringstream ret;
1381 ret<<"Over last "<<total<<" entries:\n";
1382 format fmt("%.02f%%\t%s\n");
1383 int limit=0, accounted=0;
1384 if(total) {
1385 for(rcounts_t::const_iterator i=rcounts.begin(); i != rcounts.end() && limit < 20; ++i, ++limit) {
1386 ret<< fmt % (-100.0*i->first/total) % (i->second.first.toLogString()+"|"+DNSRecordContent::NumberToType(i->second.second));
1387 accounted+= -i->first;
1388 }
1389 ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest";
1390 }
1391
1392
1393 return ret.str();
1394 }
1395
1396 static string* nopFunction()
1397 {
1398 return new string("pong\n");
1399 }
1400
1401 static string getDontThrottleNames() {
1402 auto dtn = g_dontThrottleNames.getLocal();
1403 return dtn->toString() + "\n";
1404 }
1405
1406 static string getDontThrottleNetmasks() {
1407 auto dtn = g_dontThrottleNetmasks.getLocal();
1408 return dtn->toString() + "\n";
1409 }
1410
1411 template<typename T>
1412 static string addDontThrottleNames(T begin, T end) {
1413 if (begin == end) {
1414 return "No names specified, keeping existing list\n";
1415 }
1416 vector<DNSName> toAdd;
1417 while (begin != end) {
1418 try {
1419 auto d = DNSName(*begin);
1420 toAdd.push_back(d);
1421 }
1422 catch(const std::exception &e) {
1423 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
1424 }
1425 begin++;
1426 }
1427
1428 string ret = "Added";
1429 auto dnt = g_dontThrottleNames.getCopy();
1430 bool first = true;
1431 for (auto const &d : toAdd) {
1432 if (!first) {
1433 ret += ",";
1434 }
1435 first = false;
1436 ret += " " + d.toLogString();
1437 dnt.add(d);
1438 }
1439
1440 g_dontThrottleNames.setState(dnt);
1441
1442 ret += " to the list of nameservers that may not be throttled";
1443 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1444 return ret + "\n";
1445 }
1446
1447 template<typename T>
1448 static string addDontThrottleNetmasks(T begin, T end) {
1449 if (begin == end) {
1450 return "No netmasks specified, keeping existing list\n";
1451 }
1452 vector<Netmask> toAdd;
1453 while (begin != end) {
1454 try {
1455 auto n = Netmask(*begin);
1456 toAdd.push_back(n);
1457 }
1458 catch(const std::exception &e) {
1459 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
1460 }
1461 catch(const PDNSException &e) {
1462 return "Problem parsing '" + *begin + "': "+ e.reason + ", nothing added\n";
1463 }
1464 begin++;
1465 }
1466
1467 string ret = "Added";
1468 auto dnt = g_dontThrottleNetmasks.getCopy();
1469 bool first = true;
1470 for (auto const &t : toAdd) {
1471 if (!first) {
1472 ret += ",";
1473 }
1474 first = false;
1475 ret += " " + t.toString();
1476 dnt.addMask(t);
1477 }
1478
1479 g_dontThrottleNetmasks.setState(dnt);
1480
1481 ret += " to the list of nameserver netmasks that may not be throttled";
1482 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1483 return ret + "\n";
1484 }
1485
1486 template<typename T>
1487 static string clearDontThrottleNames(T begin, T end) {
1488 if(begin == end)
1489 return "No names specified, doing nothing.\n";
1490
1491 if (begin + 1 == end && *begin == "*"){
1492 SuffixMatchNode smn;
1493 g_dontThrottleNames.setState(smn);
1494 string ret = "Cleared list of nameserver names that may not be throttled";
1495 g_log<<Logger::Warning<<ret<<", requested via control channel"<<endl;
1496 return ret + "\n";
1497 }
1498
1499 vector<DNSName> toRemove;
1500 while (begin != end) {
1501 try {
1502 if (*begin == "*") {
1503 return "Please don't mix '*' with other names, nothing removed\n";
1504 }
1505 toRemove.push_back(DNSName(*begin));
1506 }
1507 catch (const std::exception &e) {
1508 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing removed\n";
1509 }
1510 begin++;
1511 }
1512
1513 string ret = "Removed";
1514 bool first = true;
1515 auto dnt = g_dontThrottleNames.getCopy();
1516 for (const auto &name : toRemove) {
1517 if (!first) {
1518 ret += ",";
1519 }
1520 first = false;
1521 ret += " " + name.toLogString();
1522 dnt.remove(name);
1523 }
1524
1525 g_dontThrottleNames.setState(dnt);
1526
1527 ret += " from the list of nameservers that may not be throttled";
1528 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1529 return ret + "\n";
1530 }
1531
1532 template<typename T>
1533 static string clearDontThrottleNetmasks(T begin, T end) {
1534 if(begin == end)
1535 return "No netmasks specified, doing nothing.\n";
1536
1537 if (begin + 1 == end && *begin == "*"){
1538 auto nmg = g_dontThrottleNetmasks.getCopy();
1539 nmg.clear();
1540 g_dontThrottleNetmasks.setState(nmg);
1541
1542 string ret = "Cleared list of nameserver addresses that may not be throttled";
1543 g_log<<Logger::Warning<<ret<<", requested via control channel"<<endl;
1544 return ret + "\n";
1545 }
1546
1547 std::vector<Netmask> toRemove;
1548 while (begin != end) {
1549 try {
1550 if (*begin == "*") {
1551 return "Please don't mix '*' with other netmasks, nothing removed\n";
1552 }
1553 auto n = Netmask(*begin);
1554 toRemove.push_back(n);
1555 }
1556 catch(const std::exception &e) {
1557 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
1558 }
1559 catch(const PDNSException &e) {
1560 return "Problem parsing '" + *begin + "': "+ e.reason + ", nothing added\n";
1561 }
1562 begin++;
1563 }
1564
1565 string ret = "Removed";
1566 bool first = true;
1567 auto dnt = g_dontThrottleNetmasks.getCopy();
1568 for (const auto &mask : toRemove) {
1569 if (!first) {
1570 ret += ",";
1571 }
1572 first = false;
1573 ret += " " + mask.toString();
1574 dnt.deleteMask(mask);
1575 }
1576
1577 g_dontThrottleNetmasks.setState(dnt);
1578
1579 ret += " from the list of nameservers that may not be throttled";
1580 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1581 return ret + "\n";
1582 }
1583
1584
1585 string RecursorControlParser::getAnswer(const string& question, RecursorControlParser::func_t** command)
1586 {
1587 *command=nop;
1588 vector<string> words;
1589 stringtok(words, question);
1590
1591 if(words.empty())
1592 return "invalid command\n";
1593
1594 string cmd=toLower(words[0]);
1595 vector<string>::const_iterator begin=words.begin()+1, end=words.end();
1596
1597 // should probably have a smart dispatcher here, like auth has
1598 if(cmd=="help")
1599 return
1600 "add-dont-throttle-names [N...] add names that are not allowed to be throttled\n"
1601 "add-dont-throttle-netmasks [N...]\n"
1602 " add netmasks that are not allowed to be throttled\n"
1603 "add-nta DOMAIN [REASON] add a Negative Trust Anchor for DOMAIN with the comment REASON\n"
1604 "add-ta DOMAIN DSRECORD add a Trust Anchor for DOMAIN with data DSRECORD\n"
1605 "current-queries show currently active queries\n"
1606 "clear-dont-throttle-names [N...] remove names that are not allowed to be throttled. If N is '*', remove all\n"
1607 "clear-dont-throttle-netmasks [N...]\n"
1608 " remove netmasks that are not allowed to be throttled. If N is '*', remove all\n"
1609 "clear-nta [DOMAIN]... Clear the Negative Trust Anchor for DOMAINs, if no DOMAIN is specified, remove all\n"
1610 "clear-ta [DOMAIN]... Clear the Trust Anchor for DOMAINs\n"
1611 "dump-cache <filename> dump cache contents to the named file\n"
1612 "dump-edns [status] <filename> dump EDNS status to the named file\n"
1613 "dump-nsspeeds <filename> dump nsspeeds statistics to the named file\n"
1614 "dump-rpz <zone name> <filename> dump the content of a RPZ zone to the named file\n"
1615 "dump-throttlemap <filename> dump the contents of the throttle to the named file\n"
1616 "get [key1] [key2] .. get specific statistics\n"
1617 "get-all get all statistics\n"
1618 "get-dont-throttle-names get the list of names that are not allowed to be throttled\n"
1619 "get-dont-throttle-netmasks get the list of netmasks that are not allowed to be throttled\n"
1620 "get-ntas get all configured Negative Trust Anchors\n"
1621 "get-tas get all configured Trust Anchors\n"
1622 "get-parameter [key1] [key2] .. get configuration parameters\n"
1623 "get-qtypelist get QType statistics\n"
1624 " notice: queries from cache aren't being counted yet\n"
1625 "help get this list\n"
1626 "ping check that all threads are alive\n"
1627 "quit stop the recursor daemon\n"
1628 "quit-nicely stop the recursor daemon nicely\n"
1629 "reload-acls reload ACLS\n"
1630 "reload-lua-script [filename] (re)load Lua script\n"
1631 "reload-lua-config [filename] (re)load Lua configuration file\n"
1632 "reload-zones reload all auth and forward zones\n"
1633 "set-ecs-minimum-ttl value set ecs-minimum-ttl-override\n"
1634 "set-max-cache-entries value set new maximum cache size\n"
1635 "set-max-packetcache-entries val set new maximum packet cache size\n"
1636 "set-minimum-ttl value set minimum-ttl-override\n"
1637 "set-carbon-server set a carbon server for telemetry\n"
1638 "set-dnssec-log-bogus SETTING enable (SETTING=yes) or disable (SETTING=no) logging of DNSSEC validation failures\n"
1639 "trace-regex [regex] emit resolution trace for matching queries (empty regex to clear trace)\n"
1640 "top-largeanswer-remotes show top remotes receiving large answers\n"
1641 "top-queries show top queries\n"
1642 "top-pub-queries show top queries grouped by public suffix list\n"
1643 "top-remotes show top remotes\n"
1644 "top-timeouts show top downstream timeouts\n"
1645 "top-servfail-queries show top queries receiving servfail answers\n"
1646 "top-bogus-queries show top queries validating as bogus\n"
1647 "top-pub-servfail-queries show top queries receiving servfail answers grouped by public suffix list\n"
1648 "top-pub-bogus-queries show top queries validating as bogus grouped by public suffix list\n"
1649 "top-servfail-remotes show top remotes receiving servfail answers\n"
1650 "top-bogus-remotes show top remotes receiving bogus answers\n"
1651 "unload-lua-script unload Lua script\n"
1652 "version return Recursor version number\n"
1653 "wipe-cache domain0 [domain1] .. wipe domain data from cache\n";
1654
1655 if(cmd=="get-all")
1656 return getAllStats();
1657
1658 if(cmd=="get")
1659 return doGet(begin, end);
1660
1661 if(cmd=="get-parameter")
1662 return doGetParameter(begin, end);
1663
1664 if(cmd=="quit") {
1665 *command=&doExit;
1666 return "bye\n";
1667 }
1668
1669 if(cmd=="version") {
1670 return getPDNSVersion()+"\n";
1671 }
1672
1673 if(cmd=="quit-nicely") {
1674 *command=&doExitNicely;
1675 return "bye nicely\n";
1676 }
1677
1678 if(cmd=="dump-cache")
1679 return doDumpCache(begin, end);
1680
1681 if(cmd=="dump-ednsstatus" || cmd=="dump-edns")
1682 return doDumpEDNSStatus(begin, end);
1683
1684 if(cmd=="dump-nsspeeds")
1685 return doDumpNSSpeeds(begin, end);
1686
1687 if(cmd=="dump-rpz") {
1688 return doDumpRPZ(begin, end);
1689 }
1690
1691 if(cmd=="dump-throttlemap")
1692 return doDumpThrottleMap(begin, end);
1693
1694 if(cmd=="wipe-cache" || cmd=="flushname")
1695 return doWipeCache(begin, end);
1696
1697 if(cmd=="reload-lua-script")
1698 return doQueueReloadLuaScript(begin, end);
1699
1700 if(cmd=="reload-lua-config") {
1701 if(begin != end)
1702 ::arg().set("lua-config-file") = *begin;
1703
1704 try {
1705 luaConfigDelayedThreads delayedLuaThreads;
1706 loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads);
1707 startLuaConfigDelayedThreads(delayedLuaThreads, g_luaconfs.getCopy().generation);
1708 g_log<<Logger::Warning<<"Reloaded Lua configuration file '"<<::arg()["lua-config-file"]<<"', requested via control channel"<<endl;
1709 return "Reloaded Lua configuration file '"+::arg()["lua-config-file"]+"'\n";
1710 }
1711 catch(std::exception& e) {
1712 return "Unable to load Lua script from '"+::arg()["lua-config-file"]+"': "+e.what()+"\n";
1713 }
1714 catch(const PDNSException& e) {
1715 return "Unable to load Lua script from '"+::arg()["lua-config-file"]+"': "+e.reason+"\n";
1716 }
1717 }
1718
1719 if(cmd=="set-carbon-server")
1720 return doSetCarbonServer(begin, end);
1721
1722 if(cmd=="trace-regex")
1723 return doTraceRegex(begin, end);
1724
1725 if(cmd=="unload-lua-script") {
1726 vector<string> empty;
1727 empty.push_back(string());
1728 return doQueueReloadLuaScript(empty.begin(), empty.end());
1729 }
1730
1731 if(cmd=="reload-acls") {
1732 if(!::arg()["chroot"].empty()) {
1733 g_log<<Logger::Error<<"Unable to reload ACL when chroot()'ed, requested via control channel"<<endl;
1734 return "Unable to reload ACL when chroot()'ed, please restart\n";
1735 }
1736
1737 try {
1738 parseACLs();
1739 }
1740 catch(std::exception& e)
1741 {
1742 g_log<<Logger::Error<<"Reloading ACLs failed (Exception: "<<e.what()<<")"<<endl;
1743 return e.what() + string("\n");
1744 }
1745 catch(PDNSException& ae)
1746 {
1747 g_log<<Logger::Error<<"Reloading ACLs failed (PDNSException: "<<ae.reason<<")"<<endl;
1748 return ae.reason + string("\n");
1749 }
1750 return "ok\n";
1751 }
1752
1753
1754 if(cmd=="top-remotes")
1755 return doGenericTopRemotes(pleaseGetRemotes);
1756
1757 if(cmd=="top-queries")
1758 return doGenericTopQueries(pleaseGetQueryRing);
1759
1760 if(cmd=="top-pub-queries")
1761 return doGenericTopQueries(pleaseGetQueryRing, getRegisteredName);
1762
1763 if(cmd=="top-servfail-queries")
1764 return doGenericTopQueries(pleaseGetServfailQueryRing);
1765
1766 if(cmd=="top-pub-servfail-queries")
1767 return doGenericTopQueries(pleaseGetServfailQueryRing, getRegisteredName);
1768
1769 if(cmd=="top-bogus-queries")
1770 return doGenericTopQueries(pleaseGetBogusQueryRing);
1771
1772 if(cmd=="top-pub-bogus-queries")
1773 return doGenericTopQueries(pleaseGetBogusQueryRing, getRegisteredName);
1774
1775
1776 if(cmd=="top-servfail-remotes")
1777 return doGenericTopRemotes(pleaseGetServfailRemotes);
1778
1779 if(cmd=="top-bogus-remotes")
1780 return doGenericTopRemotes(pleaseGetBogusRemotes);
1781
1782 if(cmd=="top-largeanswer-remotes")
1783 return doGenericTopRemotes(pleaseGetLargeAnswerRemotes);
1784
1785 if(cmd=="top-timeouts")
1786 return doGenericTopRemotes(pleaseGetTimeouts);
1787
1788
1789 if(cmd=="current-queries")
1790 return doCurrentQueries();
1791
1792 if(cmd=="ping") {
1793 return broadcastAccFunction<string>(nopFunction);
1794 }
1795
1796 if(cmd=="reload-zones") {
1797 if(!::arg()["chroot"].empty()) {
1798 g_log<<Logger::Error<<"Unable to reload zones and forwards when chroot()'ed, requested via control channel"<<endl;
1799 return "Unable to reload zones and forwards when chroot()'ed, please restart\n";
1800 }
1801 return reloadAuthAndForwards();
1802 }
1803
1804 if(cmd=="set-ecs-minimum-ttl") {
1805 return setMinimumECSTTL(begin, end);
1806 }
1807
1808 if(cmd=="set-max-cache-entries") {
1809 return setMaxCacheEntries(begin, end);
1810 }
1811 if(cmd=="set-max-packetcache-entries") {
1812 return setMaxPacketCacheEntries(begin, end);
1813 }
1814
1815 if(cmd=="set-minimum-ttl") {
1816 return setMinimumTTL(begin, end);
1817 }
1818
1819 if(cmd=="get-qtypelist") {
1820 return g_rs.getQTypeReport();
1821 }
1822
1823 if(cmd=="add-nta") {
1824 return doAddNTA(begin, end);
1825 }
1826
1827 if(cmd=="clear-nta") {
1828 return doClearNTA(begin, end);
1829 }
1830
1831 if(cmd=="get-ntas") {
1832 return getNTAs();
1833 }
1834
1835 if(cmd=="add-ta") {
1836 return doAddTA(begin, end);
1837 }
1838
1839 if(cmd=="clear-ta") {
1840 return doClearTA(begin, end);
1841 }
1842
1843 if(cmd=="get-tas") {
1844 return getTAs();
1845 }
1846
1847 if (cmd=="set-dnssec-log-bogus")
1848 return doSetDnssecLogBogus(begin, end);
1849
1850 if (cmd == "get-dont-throttle-names") {
1851 return getDontThrottleNames();
1852 }
1853
1854 if (cmd == "get-dont-throttle-netmasks") {
1855 return getDontThrottleNetmasks();
1856 }
1857
1858 if (cmd == "add-dont-throttle-names") {
1859 return addDontThrottleNames(begin, end);
1860 }
1861
1862 if (cmd == "add-dont-throttle-netmasks") {
1863 return addDontThrottleNetmasks(begin, end);
1864 }
1865
1866 if (cmd == "clear-dont-throttle-names") {
1867 return clearDontThrottleNames(begin, end);
1868 }
1869
1870 if (cmd == "clear-dont-throttle-netmasks") {
1871 return clearDontThrottleNetmasks(begin, end);
1872 }
1873
1874 return "Unknown command '"+cmd+"', try 'help'\n";
1875 }