]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rec_channel_rec.cc
Merge pull request #8536 from Habbie/fix-lmdb-backend
[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 static uint64_t* pleaseDumpFailedServers(int fd)
235 {
236 return new uint64_t(SyncRes::doDumpFailedServers(fd));
237 }
238
239 template<typename T>
240 static string doDumpNSSpeeds(T begin, T end)
241 {
242 T i=begin;
243 string fname;
244
245 if(i!=end)
246 fname=*i;
247
248 int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
249 if(fd < 0)
250 return "Error opening dump file for writing: "+stringerror()+"\n";
251 uint64_t total = 0;
252 try {
253 total = broadcastAccFunction<uint64_t>(boost::bind(pleaseDumpNSSpeeds, fd));
254 }
255 catch(std::exception& e)
256 {
257 close(fd);
258 return "error dumping NS speeds: "+string(e.what())+"\n";
259 }
260 catch(PDNSException& e)
261 {
262 close(fd);
263 return "error dumping NS speeds: "+e.reason+"\n";
264 }
265
266 close(fd);
267 return "dumped "+std::to_string(total)+" records\n";
268 }
269
270 template<typename T>
271 static string doDumpCache(T begin, T end)
272 {
273 T i=begin;
274 string fname;
275
276 if(i!=end)
277 fname=*i;
278
279 int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
280 if(fd < 0)
281 return "Error opening dump file for writing: "+stringerror()+"\n";
282 uint64_t total = 0;
283 try {
284 total = broadcastAccFunction<uint64_t>(boost::bind(pleaseDump, fd));
285 }
286 catch(...){}
287
288 close(fd);
289 return "dumped "+std::to_string(total)+" records\n";
290 }
291
292 template<typename T>
293 static string doDumpEDNSStatus(T begin, T end)
294 {
295 T i=begin;
296 string fname;
297
298 if(i!=end)
299 fname=*i;
300
301 int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
302 if(fd < 0)
303 return "Error opening dump file for writing: "+stringerror()+"\n";
304 uint64_t total = 0;
305 try {
306 total = broadcastAccFunction<uint64_t>(boost::bind(pleaseDumpEDNSMap, fd));
307 }
308 catch(...){}
309
310 close(fd);
311 return "dumped "+std::to_string(total)+" records\n";
312 }
313
314 template<typename T>
315 static string doDumpRPZ(T begin, T end)
316 {
317 T i=begin;
318
319 if (i == end) {
320 return "No zone name specified\n";
321 }
322 string zoneName = *i;
323 i++;
324
325 if (i == end) {
326 return "No file name specified\n";
327 }
328 string fname = *i;
329
330 auto luaconf = g_luaconfs.getLocal();
331 const auto zone = luaconf->dfe.getZone(zoneName);
332 if (!zone) {
333 return "No RPZ zone named "+zoneName+"\n";
334 }
335
336 int fd = open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
337
338 if(fd < 0) {
339 return "Error opening dump file for writing: "+stringerror()+"\n";
340 }
341
342 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(fd, "w"), fclose);
343 if (!fp) {
344 close(fd);
345 return "Error converting file descriptor: "+stringerror()+"\n";
346 }
347
348 zone->dump(fp.get());
349
350 return "done\n";
351 }
352
353 template<typename T>
354 static string doDumpThrottleMap(T begin, T end)
355 {
356 T i=begin;
357 string fname;
358
359 if(i!=end)
360 fname=*i;
361
362 int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
363 if(fd < 0)
364 return "Error opening dump file for writing: "+stringerror()+"\n";
365 uint64_t total = 0;
366 try {
367 total = broadcastAccFunction<uint64_t>(boost::bind(pleaseDumpThrottleMap, fd));
368 }
369 catch(...){}
370
371 close(fd);
372 return "dumped "+std::to_string(total)+" records\n";
373 }
374
375 template<typename T>
376 static string doDumpFailedServers(T begin, T end)
377 {
378 T i=begin;
379 string fname;
380
381 if(i!=end)
382 fname=*i;
383
384 int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
385 if(fd < 0)
386 return "Error opening dump file for writing: "+stringerror()+"\n";
387 uint64_t total = 0;
388 try {
389 total = broadcastAccFunction<uint64_t>(boost::bind(pleaseDumpFailedServers, fd));
390 }
391 catch(...){}
392
393 close(fd);
394 return "dumped "+std::to_string(total)+" records\n";
395 }
396
397 uint64_t* pleaseWipeCache(const DNSName& canon, bool subtree)
398 {
399 return new uint64_t(t_RC->doWipeCache(canon, subtree));
400 }
401
402 uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree)
403 {
404 return new uint64_t(t_packetCache->doWipePacketCache(canon,0xffff, subtree));
405 }
406
407
408 uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree)
409 {
410 uint64_t ret = SyncRes::wipeNegCache(canon, subtree);
411 return new uint64_t(ret);
412 }
413
414
415 template<typename T>
416 static string doWipeCache(T begin, T end)
417 {
418 vector<pair<DNSName, bool> > toWipe;
419 for(T i=begin; i != end; ++i) {
420 DNSName canon;
421 bool subtree=false;
422
423 try {
424 if(boost::ends_with(*i, "$")) {
425 canon=DNSName(i->substr(0, i->size()-1));
426 subtree=true;
427 } else {
428 canon=DNSName(*i);
429 }
430 } catch (std::exception &e) {
431 return "Error: " + std::string(e.what()) + ", nothing wiped\n";
432 }
433 toWipe.push_back({canon, subtree});
434 }
435
436 int count=0, pcount=0, countNeg=0;
437 for (auto wipe : toWipe) {
438 count+= broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, wipe.first, wipe.second));
439 pcount+= broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, wipe.first, wipe.second));
440 countNeg+=broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, wipe.first, wipe.second));
441 }
442
443 return "wiped "+std::to_string(count)+" records, "+std::to_string(countNeg)+" negative records, "+std::to_string(pcount)+" packets\n";
444 }
445
446 template<typename T>
447 static string doSetCarbonServer(T begin, T end)
448 {
449 Lock l(&g_carbon_config_lock);
450 if(begin==end) {
451 ::arg().set("carbon-server").clear();
452 return "cleared carbon-server setting\n";
453 }
454 string ret;
455 ::arg().set("carbon-server")=*begin;
456 ret="set carbon-server to '"+::arg()["carbon-server"]+"'\n";
457 ++begin;
458 if(begin != end) {
459 ::arg().set("carbon-ourname")=*begin;
460 ret+="set carbon-ourname to '"+*begin+"'\n";
461 } else {
462 return ret;
463 }
464 ++begin;
465 if(begin != end) {
466 ::arg().set("carbon-namespace")=*begin;
467 ret+="set carbon-namespace to '"+*begin+"'\n";
468 } else {
469 return ret;
470 }
471 ++begin;
472 if(begin != end) {
473 ::arg().set("carbon-instance")=*begin;
474 ret+="set carbon-instance to '"+*begin+"'\n";
475 }
476 return ret;
477 }
478
479 template<typename T>
480 static string doSetDnssecLogBogus(T begin, T end)
481 {
482 if(checkDNSSECDisabled())
483 return "DNSSEC is disabled in the configuration, not changing the Bogus logging setting\n";
484
485 if (begin == end)
486 return "No DNSSEC Bogus logging setting specified\n";
487
488 if (pdns_iequals(*begin, "on") || pdns_iequals(*begin, "yes")) {
489 if (!g_dnssecLogBogus) {
490 g_log<<Logger::Warning<<"Enabling DNSSEC Bogus logging, requested via control channel"<<endl;
491 g_dnssecLogBogus = true;
492 return "DNSSEC Bogus logging enabled\n";
493 }
494 return "DNSSEC Bogus logging was already enabled\n";
495 }
496
497 if (pdns_iequals(*begin, "off") || pdns_iequals(*begin, "no")) {
498 if (g_dnssecLogBogus) {
499 g_log<<Logger::Warning<<"Disabling DNSSEC Bogus logging, requested via control channel"<<endl;
500 g_dnssecLogBogus = false;
501 return "DNSSEC Bogus logging disabled\n";
502 }
503 return "DNSSEC Bogus logging was already disabled\n";
504 }
505
506 return "Unknown DNSSEC Bogus setting: '" + *begin +"'\n";
507 }
508
509 template<typename T>
510 static string doAddNTA(T begin, T end)
511 {
512 if(checkDNSSECDisabled())
513 return "DNSSEC is disabled in the configuration, not adding a Negative Trust Anchor\n";
514
515 if(begin == end)
516 return "No NTA specified, doing nothing\n";
517
518 DNSName who;
519 try {
520 who = DNSName(*begin);
521 }
522 catch(std::exception &e) {
523 string ret("Can't add Negative Trust Anchor: ");
524 ret += e.what();
525 ret += "\n";
526 return ret;
527 }
528 begin++;
529
530 string why("");
531 while (begin != end) {
532 why += *begin;
533 begin++;
534 if (begin != end)
535 why += " ";
536 }
537 g_log<<Logger::Warning<<"Adding Negative Trust Anchor for "<<who<<" with reason '"<<why<<"', requested via control channel"<<endl;
538 g_luaconfs.modify([who, why](LuaConfigItems& lci) {
539 lci.negAnchors[who] = why;
540 });
541 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, who, true));
542 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, who, true));
543 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, who, true));
544 return "Added Negative Trust Anchor for " + who.toLogString() + " with reason '" + why + "'\n";
545 }
546
547 template<typename T>
548 static string doClearNTA(T begin, T end)
549 {
550 if(checkDNSSECDisabled())
551 return "DNSSEC is disabled in the configuration, not removing a Negative Trust Anchor\n";
552
553 if(begin == end)
554 return "No Negative Trust Anchor specified, doing nothing.\n";
555
556 if (begin + 1 == end && *begin == "*"){
557 g_log<<Logger::Warning<<"Clearing all Negative Trust Anchors, requested via control channel"<<endl;
558 g_luaconfs.modify([](LuaConfigItems& lci) {
559 lci.negAnchors.clear();
560 });
561 return "Cleared all Negative Trust Anchors.\n";
562 }
563
564 vector<DNSName> toRemove;
565 DNSName who;
566 while (begin != end) {
567 if (*begin == "*")
568 return "Don't mix all Negative Trust Anchor removal with multiple Negative Trust Anchor removal. Nothing removed\n";
569 try {
570 who = DNSName(*begin);
571 }
572 catch(std::exception &e) {
573 string ret("Error: ");
574 ret += e.what();
575 ret += ". No Negative Anchors removed\n";
576 return ret;
577 }
578 toRemove.push_back(who);
579 begin++;
580 }
581
582 string removed("");
583 bool first(true);
584 for (auto const &entry : toRemove) {
585 g_log<<Logger::Warning<<"Clearing Negative Trust Anchor for "<<entry<<", requested via control channel"<<endl;
586 g_luaconfs.modify([entry](LuaConfigItems& lci) {
587 lci.negAnchors.erase(entry);
588 });
589 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, entry, true));
590 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, entry, true));
591 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, entry, true));
592 if (!first) {
593 first = false;
594 removed += ",";
595 }
596 removed += " " + entry.toStringRootDot();
597 }
598 return "Removed Negative Trust Anchors for " + removed + "\n";
599 }
600
601 static string getNTAs()
602 {
603 if(checkDNSSECDisabled())
604 return "DNSSEC is disabled in the configuration\n";
605
606 string ret("Configured Negative Trust Anchors:\n");
607 auto luaconf = g_luaconfs.getLocal();
608 for (auto negAnchor : luaconf->negAnchors)
609 ret += negAnchor.first.toLogString() + "\t" + negAnchor.second + "\n";
610 return ret;
611 }
612
613 template<typename T>
614 static string doAddTA(T begin, T end)
615 {
616 if(checkDNSSECDisabled())
617 return "DNSSEC is disabled in the configuration, not adding a Trust Anchor\n";
618
619 if(begin == end)
620 return "No TA specified, doing nothing\n";
621
622 DNSName who;
623 try {
624 who = DNSName(*begin);
625 }
626 catch(std::exception &e) {
627 string ret("Can't add Trust Anchor: ");
628 ret += e.what();
629 ret += "\n";
630 return ret;
631 }
632 begin++;
633
634 string what("");
635 while (begin != end) {
636 what += *begin + " ";
637 begin++;
638 }
639
640 try {
641 g_log<<Logger::Warning<<"Adding Trust Anchor for "<<who<<" with data '"<<what<<"', requested via control channel";
642 g_luaconfs.modify([who, what](LuaConfigItems& lci) {
643 auto ds=std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(what));
644 lci.dsAnchors[who].insert(*ds);
645 });
646 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, who, true));
647 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, who, true));
648 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, who, true));
649 g_log<<Logger::Warning<<endl;
650 return "Added Trust Anchor for " + who.toStringRootDot() + " with data " + what + "\n";
651 }
652 catch(std::exception &e) {
653 g_log<<Logger::Warning<<", failed: "<<e.what()<<endl;
654 return "Unable to add Trust Anchor for " + who.toStringRootDot() + ": " + e.what() + "\n";
655 }
656 }
657
658 template<typename T>
659 static string doClearTA(T begin, T end)
660 {
661 if(checkDNSSECDisabled())
662 return "DNSSEC is disabled in the configuration, not removing a Trust Anchor\n";
663
664 if(begin == end)
665 return "No Trust Anchor to clear\n";
666
667 vector<DNSName> toRemove;
668 DNSName who;
669 while (begin != end) {
670 try {
671 who = DNSName(*begin);
672 }
673 catch(std::exception &e) {
674 string ret("Error: ");
675 ret += e.what();
676 ret += ". No Anchors removed\n";
677 return ret;
678 }
679 if (who.isRoot())
680 return "Refusing to remove root Trust Anchor, no Anchors removed\n";
681 toRemove.push_back(who);
682 begin++;
683 }
684
685 string removed("");
686 bool first(true);
687 for (auto const &entry : toRemove) {
688 g_log<<Logger::Warning<<"Removing Trust Anchor for "<<entry<<", requested via control channel"<<endl;
689 g_luaconfs.modify([entry](LuaConfigItems& lci) {
690 lci.dsAnchors.erase(entry);
691 });
692 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, entry, true));
693 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, entry, true));
694 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, entry, true));
695 if (!first) {
696 first = false;
697 removed += ",";
698 }
699 removed += " " + entry.toStringRootDot();
700 }
701 return "Removed Trust Anchor(s) for" + removed + "\n";
702 }
703
704 static string getTAs()
705 {
706 if(checkDNSSECDisabled())
707 return "DNSSEC is disabled in the configuration\n";
708
709 string ret("Configured Trust Anchors:\n");
710 auto luaconf = g_luaconfs.getLocal();
711 for (auto anchor : luaconf->dsAnchors) {
712 ret += anchor.first.toLogString() + "\n";
713 for (auto e : anchor.second) {
714 ret+="\t\t"+e.getZoneRepresentation() + "\n";
715 }
716 }
717
718 return ret;
719 }
720
721 template<typename T>
722 static string setMinimumTTL(T begin, T end)
723 {
724 if(end-begin != 1)
725 return "Need to supply new minimum TTL number\n";
726 try {
727 SyncRes::s_minimumTTL = pdns_stou(*begin);
728 return "New minimum TTL: " + std::to_string(SyncRes::s_minimumTTL) + "\n";
729 }
730 catch (const std::exception& e) {
731 return "Error parsing the new minimum TTL number: " + std::string(e.what()) + "\n";
732 }
733 }
734
735 template<typename T>
736 static string setMinimumECSTTL(T begin, T end)
737 {
738 if(end-begin != 1)
739 return "Need to supply new ECS minimum TTL number\n";
740 try {
741 SyncRes::s_minimumECSTTL = pdns_stou(*begin);
742 return "New minimum ECS TTL: " + std::to_string(SyncRes::s_minimumECSTTL) + "\n";
743 }
744 catch (const std::exception& e) {
745 return "Error parsing the new ECS minimum TTL number: " + std::string(e.what()) + "\n";
746 }
747 }
748
749 template<typename T>
750 static string setMaxCacheEntries(T begin, T end)
751 {
752 if(end-begin != 1)
753 return "Need to supply new cache size\n";
754 try {
755 g_maxCacheEntries = pdns_stou(*begin);
756 return "New max cache entries: " + std::to_string(g_maxCacheEntries) + "\n";
757 }
758 catch (const std::exception& e) {
759 return "Error parsing the new cache size: " + std::string(e.what()) + "\n";
760 }
761 }
762
763 template<typename T>
764 static string setMaxPacketCacheEntries(T begin, T end)
765 {
766 if(end-begin != 1)
767 return "Need to supply new packet cache size\n";
768 try {
769 g_maxPacketCacheEntries = pdns_stou(*begin);
770 return "New max packetcache entries: " + std::to_string(g_maxPacketCacheEntries) + "\n";
771 }
772 catch (const std::exception& e) {
773 return "Error parsing the new packet cache size: " + std::string(e.what()) + "\n";
774 }
775 }
776
777
778 static uint64_t getSysTimeMsec()
779 {
780 struct rusage ru;
781 getrusage(RUSAGE_SELF, &ru);
782 return (ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000);
783 }
784
785 static uint64_t getUserTimeMsec()
786 {
787 struct rusage ru;
788 getrusage(RUSAGE_SELF, &ru);
789 return (ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000);
790 }
791
792 /* This is a pretty weird set of functions. To get per-thread cpu usage numbers,
793 we have to ask a thread over a pipe. We could do so surgically, so if you want to know about
794 thread 3, we pick pipe 3, but we lack that infrastructure.
795
796 We can however ask "execute this function on all threads and add up the results".
797 This is what the first function does using a custom object ThreadTimes, which if you add
798 to each other keeps filling the first one with CPU usage numbers
799 */
800
801 static ThreadTimes* pleaseGetThreadCPUMsec()
802 {
803 uint64_t ret=0;
804 #ifdef RUSAGE_THREAD
805 struct rusage ru;
806 getrusage(RUSAGE_THREAD, &ru);
807 ret = (ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000);
808 ret += (ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000);
809 #endif
810 return new ThreadTimes{ret, vector<uint64_t>()};
811 }
812
813 /* Next up, when you want msec data for a specific thread, we check
814 if we recently executed pleaseGetThreadCPUMsec. If we didn't we do so
815 now and consult all threads.
816
817 We then answer you from the (re)fresh(ed) ThreadTimes.
818 */
819 static uint64_t doGetThreadCPUMsec(int n)
820 {
821 static std::mutex s_mut;
822 static time_t last = 0;
823 static ThreadTimes tt;
824
825 std::lock_guard<std::mutex> l(s_mut);
826 if(last != time(nullptr)) {
827 tt = broadcastAccFunction<ThreadTimes>(pleaseGetThreadCPUMsec);
828 last = time(nullptr);
829 }
830
831 return tt.times.at(n);
832 }
833
834 static uint64_t calculateUptime()
835 {
836 return time(nullptr) - g_stats.startupTime;
837 }
838
839 static string* pleaseGetCurrentQueries()
840 {
841 ostringstream ostr;
842 struct timeval now;
843 gettimeofday(&now, 0);
844
845 ostr << getMT()->d_waiters.size() <<" currently outstanding questions\n";
846
847 boost::format fmt("%1% %|40t|%2% %|47t|%3% %|63t|%4% %|68t|%5% %|78t|%6%\n");
848
849 ostr << (fmt % "qname" % "qtype" % "remote" % "tcp" % "chained" % "spent(ms)");
850 unsigned int n=0;
851 for(const auto& mthread : getMT()->d_waiters) {
852 const PacketID& pident = mthread.key;
853 const double spent = g_networkTimeoutMsec - (DiffTime(now, mthread.ttd) * 1000);
854 ostr << (fmt
855 % pident.domain.toLogString() /* ?? */ % DNSRecordContent::NumberToType(pident.type)
856 % pident.remote.toString() % (pident.sock ? 'Y' : 'n')
857 % (pident.fd == -1 ? 'Y' : 'n')
858 % (spent > 0 ? spent : '0')
859 );
860 ++n;
861 if (n >= 100)
862 break;
863 }
864 ostr <<" - done\n";
865 return new string(ostr.str());
866 }
867
868 static string doCurrentQueries()
869 {
870 return broadcastAccFunction<string>(pleaseGetCurrentQueries);
871 }
872
873 uint64_t* pleaseGetThrottleSize()
874 {
875 return new uint64_t(SyncRes::getThrottledServersSize());
876 }
877
878 static uint64_t getThrottleSize()
879 {
880 return broadcastAccFunction<uint64_t>(pleaseGetThrottleSize);
881 }
882
883 uint64_t* pleaseGetNegCacheSize()
884 {
885 uint64_t tmp=(SyncRes::getNegCacheSize());
886 return new uint64_t(tmp);
887 }
888
889 static uint64_t getNegCacheSize()
890 {
891 return broadcastAccFunction<uint64_t>(pleaseGetNegCacheSize);
892 }
893
894 static uint64_t* pleaseGetFailedHostsSize()
895 {
896 uint64_t tmp=(SyncRes::getThrottledServersSize());
897 return new uint64_t(tmp);
898 }
899
900 static uint64_t getFailedHostsSize()
901 {
902 return broadcastAccFunction<uint64_t>(pleaseGetFailedHostsSize);
903 }
904
905 uint64_t* pleaseGetNsSpeedsSize()
906 {
907 return new uint64_t(SyncRes::getNSSpeedsSize());
908 }
909
910 static uint64_t getNsSpeedsSize()
911 {
912 return broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize);
913 }
914
915 uint64_t* pleaseGetFailedServersSize()
916 {
917 return new uint64_t(SyncRes::getFailedServersSize());
918 }
919
920 uint64_t* pleaseGetEDNSStatusesSize()
921 {
922 return new uint64_t(SyncRes::getEDNSStatusesSize());
923 }
924
925 uint64_t* pleaseGetConcurrentQueries()
926 {
927 return new uint64_t(getMT() ? getMT()->numProcesses() : 0);
928 }
929
930 static uint64_t getConcurrentQueries()
931 {
932 return broadcastAccFunction<uint64_t>(pleaseGetConcurrentQueries);
933 }
934
935 uint64_t* pleaseGetCacheSize()
936 {
937 return new uint64_t(t_RC ? t_RC->size() : 0);
938 }
939
940 static uint64_t* pleaseGetCacheBytes()
941 {
942 return new uint64_t(t_RC ? t_RC->bytes() : 0);
943 }
944
945 static uint64_t doGetCacheSize()
946 {
947 return broadcastAccFunction<uint64_t>(pleaseGetCacheSize);
948 }
949
950 static uint64_t doGetAvgLatencyUsec()
951 {
952 return (uint64_t) g_stats.avgLatencyUsec;
953 }
954
955 static uint64_t doGetCacheBytes()
956 {
957 return broadcastAccFunction<uint64_t>(pleaseGetCacheBytes);
958 }
959
960 uint64_t* pleaseGetCacheHits()
961 {
962 return new uint64_t(t_RC ? t_RC->cacheHits : 0);
963 }
964
965 static uint64_t doGetCacheHits()
966 {
967 return broadcastAccFunction<uint64_t>(pleaseGetCacheHits);
968 }
969
970 uint64_t* pleaseGetCacheMisses()
971 {
972 return new uint64_t(t_RC ? t_RC->cacheMisses : 0);
973 }
974
975 static uint64_t doGetCacheMisses()
976 {
977 return broadcastAccFunction<uint64_t>(pleaseGetCacheMisses);
978 }
979
980 uint64_t* pleaseGetPacketCacheSize()
981 {
982 return new uint64_t(t_packetCache ? t_packetCache->size() : 0);
983 }
984
985 static uint64_t* pleaseGetPacketCacheBytes()
986 {
987 return new uint64_t(t_packetCache ? t_packetCache->bytes() : 0);
988 }
989
990 static uint64_t doGetPacketCacheSize()
991 {
992 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheSize);
993 }
994
995 static uint64_t doGetPacketCacheBytes()
996 {
997 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheBytes);
998 }
999
1000 uint64_t* pleaseGetPacketCacheHits()
1001 {
1002 return new uint64_t(t_packetCache ? t_packetCache->d_hits : 0);
1003 }
1004
1005 static uint64_t doGetPacketCacheHits()
1006 {
1007 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheHits);
1008 }
1009
1010 static uint64_t* pleaseGetPacketCacheMisses()
1011 {
1012 return new uint64_t(t_packetCache ? t_packetCache->d_misses : 0);
1013 }
1014
1015 static uint64_t doGetPacketCacheMisses()
1016 {
1017 return broadcastAccFunction<uint64_t>(pleaseGetPacketCacheMisses);
1018 }
1019
1020 static uint64_t doGetMallocated()
1021 {
1022 // this turned out to be broken
1023 /* struct mallinfo mi = mallinfo();
1024 return mi.uordblks; */
1025 return 0;
1026 }
1027
1028 extern ResponseStats g_rs;
1029
1030 void registerAllStats()
1031 {
1032 static std::atomic_flag s_init = ATOMIC_FLAG_INIT;
1033 if(s_init.test_and_set())
1034 return;
1035
1036 addGetStat("questions", &g_stats.qcounter);
1037 addGetStat("ipv6-questions", &g_stats.ipv6qcounter);
1038 addGetStat("tcp-questions", &g_stats.tcpqcounter);
1039
1040 addGetStat("cache-hits", doGetCacheHits);
1041 addGetStat("cache-misses", doGetCacheMisses);
1042 addGetStat("cache-entries", doGetCacheSize);
1043 addGetStat("max-cache-entries", []() { return g_maxCacheEntries.load(); });
1044 addGetStat("max-packetcache-entries", []() { return g_maxPacketCacheEntries.load();});
1045 addGetStat("cache-bytes", doGetCacheBytes);
1046
1047 addGetStat("packetcache-hits", doGetPacketCacheHits);
1048 addGetStat("packetcache-misses", doGetPacketCacheMisses);
1049 addGetStat("packetcache-entries", doGetPacketCacheSize);
1050 addGetStat("packetcache-bytes", doGetPacketCacheBytes);
1051
1052 addGetStat("malloc-bytes", doGetMallocated);
1053
1054 addGetStat("servfail-answers", &g_stats.servFails);
1055 addGetStat("nxdomain-answers", &g_stats.nxDomains);
1056 addGetStat("noerror-answers", &g_stats.noErrors);
1057
1058 addGetStat("unauthorized-udp", &g_stats.unauthorizedUDP);
1059 addGetStat("unauthorized-tcp", &g_stats.unauthorizedTCP);
1060 addGetStat("tcp-client-overflow", &g_stats.tcpClientOverflow);
1061
1062 addGetStat("client-parse-errors", &g_stats.clientParseError);
1063 addGetStat("server-parse-errors", &g_stats.serverParseError);
1064 addGetStat("too-old-drops", &g_stats.tooOldDrops);
1065 addGetStat("truncated-drops", &g_stats.truncatedDrops);
1066 addGetStat("query-pipe-full-drops", &g_stats.queryPipeFullDrops);
1067
1068 addGetStat("answers0-1", &g_stats.answers0_1);
1069 addGetStat("answers1-10", &g_stats.answers1_10);
1070 addGetStat("answers10-100", &g_stats.answers10_100);
1071 addGetStat("answers100-1000", &g_stats.answers100_1000);
1072 addGetStat("answers-slow", &g_stats.answersSlow);
1073
1074 addGetStat("x-ourtime0-1", &g_stats.ourtime0_1);
1075 addGetStat("x-ourtime1-2", &g_stats.ourtime1_2);
1076 addGetStat("x-ourtime2-4", &g_stats.ourtime2_4);
1077 addGetStat("x-ourtime4-8", &g_stats.ourtime4_8);
1078 addGetStat("x-ourtime8-16", &g_stats.ourtime8_16);
1079 addGetStat("x-ourtime16-32", &g_stats.ourtime16_32);
1080 addGetStat("x-ourtime-slow", &g_stats.ourtimeSlow);
1081
1082 addGetStat("auth4-answers0-1", &g_stats.auth4Answers0_1);
1083 addGetStat("auth4-answers1-10", &g_stats.auth4Answers1_10);
1084 addGetStat("auth4-answers10-100", &g_stats.auth4Answers10_100);
1085 addGetStat("auth4-answers100-1000", &g_stats.auth4Answers100_1000);
1086 addGetStat("auth4-answers-slow", &g_stats.auth4AnswersSlow);
1087
1088 addGetStat("auth6-answers0-1", &g_stats.auth6Answers0_1);
1089 addGetStat("auth6-answers1-10", &g_stats.auth6Answers1_10);
1090 addGetStat("auth6-answers10-100", &g_stats.auth6Answers10_100);
1091 addGetStat("auth6-answers100-1000", &g_stats.auth6Answers100_1000);
1092 addGetStat("auth6-answers-slow", &g_stats.auth6AnswersSlow);
1093
1094
1095 addGetStat("qa-latency", doGetAvgLatencyUsec);
1096 addGetStat("x-our-latency", []() { return g_stats.avgLatencyOursUsec; });
1097 addGetStat("unexpected-packets", &g_stats.unexpectedCount);
1098 addGetStat("case-mismatches", &g_stats.caseMismatchCount);
1099 addGetStat("spoof-prevents", &g_stats.spoofCount);
1100
1101 addGetStat("nsset-invalidations", &g_stats.nsSetInvalidations);
1102
1103 addGetStat("resource-limits", &g_stats.resourceLimits);
1104 addGetStat("over-capacity-drops", &g_stats.overCapacityDrops);
1105 addGetStat("policy-drops", &g_stats.policyDrops);
1106 addGetStat("no-packet-error", &g_stats.noPacketError);
1107 addGetStat("dlg-only-drops", &SyncRes::s_nodelegated);
1108 addGetStat("ignored-packets", &g_stats.ignoredCount);
1109 addGetStat("empty-queries", &g_stats.emptyQueriesCount);
1110 addGetStat("max-mthread-stack", &g_stats.maxMThreadStackUsage);
1111
1112 addGetStat("negcache-entries", getNegCacheSize);
1113 addGetStat("throttle-entries", getThrottleSize);
1114
1115 addGetStat("nsspeeds-entries", getNsSpeedsSize);
1116 addGetStat("failed-host-entries", getFailedHostsSize);
1117
1118 addGetStat("concurrent-queries", getConcurrentQueries);
1119 addGetStat("security-status", &g_security_status);
1120 addGetStat("outgoing-timeouts", &SyncRes::s_outgoingtimeouts);
1121 addGetStat("outgoing4-timeouts", &SyncRes::s_outgoing4timeouts);
1122 addGetStat("outgoing6-timeouts", &SyncRes::s_outgoing6timeouts);
1123 addGetStat("auth-zone-queries", &SyncRes::s_authzonequeries);
1124 addGetStat("tcp-outqueries", &SyncRes::s_tcpoutqueries);
1125 addGetStat("all-outqueries", &SyncRes::s_outqueries);
1126 addGetStat("ipv6-outqueries", &g_stats.ipv6queries);
1127 addGetStat("throttled-outqueries", &SyncRes::s_throttledqueries);
1128 addGetStat("dont-outqueries", &SyncRes::s_dontqueries);
1129 addGetStat("qname-min-fallback-success", &SyncRes::s_qnameminfallbacksuccess);
1130 addGetStat("throttled-out", &SyncRes::s_throttledqueries);
1131 addGetStat("unreachables", &SyncRes::s_unreachables);
1132 addGetStat("ecs-queries", &SyncRes::s_ecsqueries);
1133 addGetStat("ecs-responses", &SyncRes::s_ecsresponses);
1134 addGetStat("chain-resends", &g_stats.chainResends);
1135 addGetStat("tcp-clients", boost::bind(TCPConnection::getCurrentConnections));
1136
1137 #ifdef __linux__
1138 addGetStat("udp-recvbuf-errors", boost::bind(udpErrorStats, "udp-recvbuf-errors"));
1139 addGetStat("udp-sndbuf-errors", boost::bind(udpErrorStats, "udp-sndbuf-errors"));
1140 addGetStat("udp-noport-errors", boost::bind(udpErrorStats, "udp-noport-errors"));
1141 addGetStat("udp-in-errors", boost::bind(udpErrorStats, "udp-in-errors"));
1142 #endif
1143
1144 addGetStat("edns-ping-matches", &g_stats.ednsPingMatches);
1145 addGetStat("edns-ping-mismatches", &g_stats.ednsPingMismatches);
1146 addGetStat("dnssec-queries", &g_stats.dnssecQueries);
1147
1148 addGetStat("dnssec-authentic-data-queries", &g_stats.dnssecAuthenticDataQueries);
1149 addGetStat("dnssec-check-disabled-queries", &g_stats.dnssecCheckDisabledQueries);
1150
1151 addGetStat("variable-responses", &g_stats.variableResponses);
1152
1153 addGetStat("noping-outqueries", &g_stats.noPingOutQueries);
1154 addGetStat("noedns-outqueries", &g_stats.noEdnsOutQueries);
1155
1156 addGetStat("uptime", calculateUptime);
1157 addGetStat("real-memory-usage", boost::bind(getRealMemoryUsage, string()));
1158 addGetStat("special-memory-usage", boost::bind(getSpecialMemoryUsage, string()));
1159 addGetStat("fd-usage", boost::bind(getOpenFileDescriptors, string()));
1160
1161 // addGetStat("query-rate", getQueryRate);
1162 addGetStat("user-msec", getUserTimeMsec);
1163 addGetStat("sys-msec", getSysTimeMsec);
1164
1165 for(unsigned int n=0; n < g_numThreads; ++n)
1166 addGetStat("cpu-msec-thread-"+std::to_string(n), boost::bind(&doGetThreadCPUMsec, n));
1167
1168 #ifdef MALLOC_TRACE
1169 addGetStat("memory-allocs", boost::bind(&MallocTracer::getAllocs, g_mtracer, string()));
1170 addGetStat("memory-alloc-flux", boost::bind(&MallocTracer::getAllocFlux, g_mtracer, string()));
1171 addGetStat("memory-allocated", boost::bind(&MallocTracer::getTotAllocated, g_mtracer, string()));
1172 #endif
1173
1174 addGetStat("dnssec-validations", &g_stats.dnssecValidations);
1175 addGetStat("dnssec-result-insecure", &g_stats.dnssecResults[Insecure]);
1176 addGetStat("dnssec-result-secure", &g_stats.dnssecResults[Secure]);
1177 addGetStat("dnssec-result-bogus", &g_stats.dnssecResults[Bogus]);
1178 addGetStat("dnssec-result-indeterminate", &g_stats.dnssecResults[Indeterminate]);
1179 addGetStat("dnssec-result-nta", &g_stats.dnssecResults[NTA]);
1180
1181 addGetStat("policy-result-noaction", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NoAction]);
1182 addGetStat("policy-result-drop", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Drop]);
1183 addGetStat("policy-result-nxdomain", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NXDOMAIN]);
1184 addGetStat("policy-result-nodata", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NODATA]);
1185 addGetStat("policy-result-truncate", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Truncate]);
1186 addGetStat("policy-result-custom", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Custom]);
1187
1188 addGetStat("rebalanced-queries", &g_stats.rebalancedQueries);
1189
1190 /* make sure that the ECS stats are properly initialized */
1191 SyncRes::clearECSStats();
1192 for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize4.size(); idx++) {
1193 const std::string name = "ecs-v4-response-bits-" + std::to_string(idx + 1);
1194 addGetStat(name, &(SyncRes::s_ecsResponsesBySubnetSize4.at(idx)));
1195 }
1196 for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize6.size(); idx++) {
1197 const std::string name = "ecs-v6-response-bits-" + std::to_string(idx + 1);
1198 addGetStat(name, &(SyncRes::s_ecsResponsesBySubnetSize6.at(idx)));
1199 }
1200 }
1201
1202 void doExitGeneric(bool nicely)
1203 {
1204 g_log<<Logger::Error<<"Exiting on user request"<<endl;
1205 extern RecursorControlChannel s_rcc;
1206 s_rcc.~RecursorControlChannel();
1207
1208 extern string s_pidfname;
1209 if(!s_pidfname.empty())
1210 unlink(s_pidfname.c_str()); // we can at least try..
1211 if(nicely) {
1212 RecursorControlChannel::stop = 1;
1213 } else {
1214 _exit(1);
1215 }
1216 }
1217
1218 void doExit()
1219 {
1220 doExitGeneric(false);
1221 }
1222
1223 void doExitNicely()
1224 {
1225 doExitGeneric(true);
1226 }
1227
1228 vector<pair<DNSName, uint16_t> >* pleaseGetQueryRing()
1229 {
1230 typedef pair<DNSName,uint16_t> query_t;
1231 vector<query_t >* ret = new vector<query_t>();
1232 if(!t_queryring)
1233 return ret;
1234 ret->reserve(t_queryring->size());
1235
1236 for(const query_t& q : *t_queryring) {
1237 ret->push_back(q);
1238 }
1239 return ret;
1240 }
1241 vector<pair<DNSName,uint16_t> >* pleaseGetServfailQueryRing()
1242 {
1243 typedef pair<DNSName,uint16_t> query_t;
1244 vector<query_t>* ret = new vector<query_t>();
1245 if(!t_servfailqueryring)
1246 return ret;
1247 ret->reserve(t_servfailqueryring->size());
1248 for(const query_t& q : *t_servfailqueryring) {
1249 ret->push_back(q);
1250 }
1251 return ret;
1252 }
1253 vector<pair<DNSName,uint16_t> >* pleaseGetBogusQueryRing()
1254 {
1255 typedef pair<DNSName,uint16_t> query_t;
1256 vector<query_t>* ret = new vector<query_t>();
1257 if(!t_bogusqueryring)
1258 return ret;
1259 ret->reserve(t_bogusqueryring->size());
1260 for(const query_t& q : *t_bogusqueryring) {
1261 ret->push_back(q);
1262 }
1263 return ret;
1264 }
1265
1266
1267
1268 typedef boost::function<vector<ComboAddress>*()> pleaseremotefunc_t;
1269 typedef boost::function<vector<pair<DNSName,uint16_t> >*()> pleasequeryfunc_t;
1270
1271 vector<ComboAddress>* pleaseGetRemotes()
1272 {
1273 vector<ComboAddress>* ret = new vector<ComboAddress>();
1274 if(!t_remotes)
1275 return ret;
1276
1277 ret->reserve(t_remotes->size());
1278 for(const ComboAddress& ca : *t_remotes) {
1279 ret->push_back(ca);
1280 }
1281 return ret;
1282 }
1283
1284 vector<ComboAddress>* pleaseGetServfailRemotes()
1285 {
1286 vector<ComboAddress>* ret = new vector<ComboAddress>();
1287 if(!t_servfailremotes)
1288 return ret;
1289 ret->reserve(t_servfailremotes->size());
1290 for(const ComboAddress& ca : *t_servfailremotes) {
1291 ret->push_back(ca);
1292 }
1293 return ret;
1294 }
1295
1296 vector<ComboAddress>* pleaseGetBogusRemotes()
1297 {
1298 vector<ComboAddress>* ret = new vector<ComboAddress>();
1299 if(!t_bogusremotes)
1300 return ret;
1301 ret->reserve(t_bogusremotes->size());
1302 for(const ComboAddress& ca : *t_bogusremotes) {
1303 ret->push_back(ca);
1304 }
1305 return ret;
1306 }
1307
1308 vector<ComboAddress>* pleaseGetLargeAnswerRemotes()
1309 {
1310 vector<ComboAddress>* ret = new vector<ComboAddress>();
1311 if(!t_largeanswerremotes)
1312 return ret;
1313 ret->reserve(t_largeanswerremotes->size());
1314 for(const ComboAddress& ca : *t_largeanswerremotes) {
1315 ret->push_back(ca);
1316 }
1317 return ret;
1318 }
1319
1320 vector<ComboAddress>* pleaseGetTimeouts()
1321 {
1322 vector<ComboAddress>* ret = new vector<ComboAddress>();
1323 if(!t_timeouts)
1324 return ret;
1325 ret->reserve(t_timeouts->size());
1326 for(const ComboAddress& ca : *t_timeouts) {
1327 ret->push_back(ca);
1328 }
1329 return ret;
1330 }
1331
1332 string doGenericTopRemotes(pleaseremotefunc_t func)
1333 {
1334 typedef map<ComboAddress, int, ComboAddress::addressOnlyLessThan> counts_t;
1335 counts_t counts;
1336
1337 vector<ComboAddress> remotes=broadcastAccFunction<vector<ComboAddress> >(func);
1338
1339 unsigned int total=0;
1340 for(const ComboAddress& ca : remotes) {
1341 total++;
1342 counts[ca]++;
1343 }
1344
1345 typedef std::multimap<int, ComboAddress> rcounts_t;
1346 rcounts_t rcounts;
1347
1348 for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
1349 rcounts.insert(make_pair(-i->second, i->first));
1350
1351 ostringstream ret;
1352 ret<<"Over last "<<total<<" entries:\n";
1353 format fmt("%.02f%%\t%s\n");
1354 int limit=0, accounted=0;
1355 if(total) {
1356 for(rcounts_t::const_iterator i=rcounts.begin(); i != rcounts.end() && limit < 20; ++i, ++limit) {
1357 ret<< fmt % (-100.0*i->first/total) % i->second.toString();
1358 accounted+= -i->first;
1359 }
1360 ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest";
1361 }
1362 return ret.str();
1363 }
1364
1365 // XXX DNSName Pain - this function should benefit from native DNSName methods
1366 DNSName getRegisteredName(const DNSName& dom)
1367 {
1368 auto parts=dom.getRawLabels();
1369 if(parts.size()<=2)
1370 return dom;
1371 reverse(parts.begin(), parts.end());
1372 for(string& str : parts) { str=toLower(str); };
1373
1374 // uk co migweb
1375 string last;
1376 while(!parts.empty()) {
1377 if(parts.size()==1 || binary_search(g_pubs.begin(), g_pubs.end(), parts)) {
1378
1379 string ret=last;
1380 if(!ret.empty())
1381 ret+=".";
1382
1383 for(auto p = parts.crbegin(); p != parts.crend(); ++p) {
1384 ret+=(*p)+".";
1385 }
1386 return DNSName(ret);
1387 }
1388
1389 last=parts[parts.size()-1];
1390 parts.resize(parts.size()-1);
1391 }
1392 return DNSName("??");
1393 }
1394
1395 static DNSName nopFilter(const DNSName& name)
1396 {
1397 return name;
1398 }
1399
1400 string doGenericTopQueries(pleasequeryfunc_t func, boost::function<DNSName(const DNSName&)> filter=nopFilter)
1401 {
1402 typedef pair<DNSName,uint16_t> query_t;
1403 typedef map<query_t, int> counts_t;
1404 counts_t counts;
1405 vector<query_t> queries=broadcastAccFunction<vector<query_t> >(func);
1406
1407 unsigned int total=0;
1408 for(const query_t& q : queries) {
1409 total++;
1410 counts[make_pair(filter(q.first),q.second)]++;
1411 }
1412
1413 typedef std::multimap<int, query_t> rcounts_t;
1414 rcounts_t rcounts;
1415
1416 for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
1417 rcounts.insert(make_pair(-i->second, i->first));
1418
1419 ostringstream ret;
1420 ret<<"Over last "<<total<<" entries:\n";
1421 format fmt("%.02f%%\t%s\n");
1422 int limit=0, accounted=0;
1423 if(total) {
1424 for(rcounts_t::const_iterator i=rcounts.begin(); i != rcounts.end() && limit < 20; ++i, ++limit) {
1425 ret<< fmt % (-100.0*i->first/total) % (i->second.first.toLogString()+"|"+DNSRecordContent::NumberToType(i->second.second));
1426 accounted+= -i->first;
1427 }
1428 ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest";
1429 }
1430
1431
1432 return ret.str();
1433 }
1434
1435 static string* nopFunction()
1436 {
1437 return new string("pong\n");
1438 }
1439
1440 static string getDontThrottleNames() {
1441 auto dtn = g_dontThrottleNames.getLocal();
1442 return dtn->toString() + "\n";
1443 }
1444
1445 static string getDontThrottleNetmasks() {
1446 auto dtn = g_dontThrottleNetmasks.getLocal();
1447 return dtn->toString() + "\n";
1448 }
1449
1450 template<typename T>
1451 static string addDontThrottleNames(T begin, T end) {
1452 if (begin == end) {
1453 return "No names specified, keeping existing list\n";
1454 }
1455 vector<DNSName> toAdd;
1456 while (begin != end) {
1457 try {
1458 auto d = DNSName(*begin);
1459 toAdd.push_back(d);
1460 }
1461 catch(const std::exception &e) {
1462 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
1463 }
1464 begin++;
1465 }
1466
1467 string ret = "Added";
1468 auto dnt = g_dontThrottleNames.getCopy();
1469 bool first = true;
1470 for (auto const &d : toAdd) {
1471 if (!first) {
1472 ret += ",";
1473 }
1474 first = false;
1475 ret += " " + d.toLogString();
1476 dnt.add(d);
1477 }
1478
1479 g_dontThrottleNames.setState(dnt);
1480
1481 ret += " to the list of nameservers 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 addDontThrottleNetmasks(T begin, T end) {
1488 if (begin == end) {
1489 return "No netmasks specified, keeping existing list\n";
1490 }
1491 vector<Netmask> toAdd;
1492 while (begin != end) {
1493 try {
1494 auto n = Netmask(*begin);
1495 toAdd.push_back(n);
1496 }
1497 catch(const std::exception &e) {
1498 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
1499 }
1500 catch(const PDNSException &e) {
1501 return "Problem parsing '" + *begin + "': "+ e.reason + ", nothing added\n";
1502 }
1503 begin++;
1504 }
1505
1506 string ret = "Added";
1507 auto dnt = g_dontThrottleNetmasks.getCopy();
1508 bool first = true;
1509 for (auto const &t : toAdd) {
1510 if (!first) {
1511 ret += ",";
1512 }
1513 first = false;
1514 ret += " " + t.toString();
1515 dnt.addMask(t);
1516 }
1517
1518 g_dontThrottleNetmasks.setState(dnt);
1519
1520 ret += " to the list of nameserver netmasks that may not be throttled";
1521 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1522 return ret + "\n";
1523 }
1524
1525 template<typename T>
1526 static string clearDontThrottleNames(T begin, T end) {
1527 if(begin == end)
1528 return "No names specified, doing nothing.\n";
1529
1530 if (begin + 1 == end && *begin == "*"){
1531 SuffixMatchNode smn;
1532 g_dontThrottleNames.setState(smn);
1533 string ret = "Cleared list of nameserver names that may not be throttled";
1534 g_log<<Logger::Warning<<ret<<", requested via control channel"<<endl;
1535 return ret + "\n";
1536 }
1537
1538 vector<DNSName> toRemove;
1539 while (begin != end) {
1540 try {
1541 if (*begin == "*") {
1542 return "Please don't mix '*' with other names, nothing removed\n";
1543 }
1544 toRemove.push_back(DNSName(*begin));
1545 }
1546 catch (const std::exception &e) {
1547 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing removed\n";
1548 }
1549 begin++;
1550 }
1551
1552 string ret = "Removed";
1553 bool first = true;
1554 auto dnt = g_dontThrottleNames.getCopy();
1555 for (const auto &name : toRemove) {
1556 if (!first) {
1557 ret += ",";
1558 }
1559 first = false;
1560 ret += " " + name.toLogString();
1561 dnt.remove(name);
1562 }
1563
1564 g_dontThrottleNames.setState(dnt);
1565
1566 ret += " from the list of nameservers that may not be throttled";
1567 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1568 return ret + "\n";
1569 }
1570
1571 template<typename T>
1572 static string clearDontThrottleNetmasks(T begin, T end) {
1573 if(begin == end)
1574 return "No netmasks specified, doing nothing.\n";
1575
1576 if (begin + 1 == end && *begin == "*"){
1577 auto nmg = g_dontThrottleNetmasks.getCopy();
1578 nmg.clear();
1579 g_dontThrottleNetmasks.setState(nmg);
1580
1581 string ret = "Cleared list of nameserver addresses that may not be throttled";
1582 g_log<<Logger::Warning<<ret<<", requested via control channel"<<endl;
1583 return ret + "\n";
1584 }
1585
1586 std::vector<Netmask> toRemove;
1587 while (begin != end) {
1588 try {
1589 if (*begin == "*") {
1590 return "Please don't mix '*' with other netmasks, nothing removed\n";
1591 }
1592 auto n = Netmask(*begin);
1593 toRemove.push_back(n);
1594 }
1595 catch(const std::exception &e) {
1596 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
1597 }
1598 catch(const PDNSException &e) {
1599 return "Problem parsing '" + *begin + "': "+ e.reason + ", nothing added\n";
1600 }
1601 begin++;
1602 }
1603
1604 string ret = "Removed";
1605 bool first = true;
1606 auto dnt = g_dontThrottleNetmasks.getCopy();
1607 for (const auto &mask : toRemove) {
1608 if (!first) {
1609 ret += ",";
1610 }
1611 first = false;
1612 ret += " " + mask.toString();
1613 dnt.deleteMask(mask);
1614 }
1615
1616 g_dontThrottleNetmasks.setState(dnt);
1617
1618 ret += " from the list of nameservers that may not be throttled";
1619 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1620 return ret + "\n";
1621 }
1622
1623
1624 string RecursorControlParser::getAnswer(const string& question, RecursorControlParser::func_t** command)
1625 {
1626 *command=nop;
1627 vector<string> words;
1628 stringtok(words, question);
1629
1630 if(words.empty())
1631 return "invalid command\n";
1632
1633 string cmd=toLower(words[0]);
1634 vector<string>::const_iterator begin=words.begin()+1, end=words.end();
1635
1636 // should probably have a smart dispatcher here, like auth has
1637 if(cmd=="help")
1638 return
1639 "add-dont-throttle-names [N...] add names that are not allowed to be throttled\n"
1640 "add-dont-throttle-netmasks [N...]\n"
1641 " add netmasks that are not allowed to be throttled\n"
1642 "add-nta DOMAIN [REASON] add a Negative Trust Anchor for DOMAIN with the comment REASON\n"
1643 "add-ta DOMAIN DSRECORD add a Trust Anchor for DOMAIN with data DSRECORD\n"
1644 "current-queries show currently active queries\n"
1645 "clear-dont-throttle-names [N...] remove names that are not allowed to be throttled. If N is '*', remove all\n"
1646 "clear-dont-throttle-netmasks [N...]\n"
1647 " remove netmasks that are not allowed to be throttled. If N is '*', remove all\n"
1648 "clear-nta [DOMAIN]... Clear the Negative Trust Anchor for DOMAINs, if no DOMAIN is specified, remove all\n"
1649 "clear-ta [DOMAIN]... Clear the Trust Anchor for DOMAINs\n"
1650 "dump-cache <filename> dump cache contents to the named file\n"
1651 "dump-edns [status] <filename> dump EDNS status to the named file\n"
1652 "dump-nsspeeds <filename> dump nsspeeds statistics to the named file\n"
1653 "dump-rpz <zone name> <filename> dump the content of a RPZ zone to the named file\n"
1654 "dump-throttlemap <filename> dump the contents of the throttle map to the named file\n"
1655 "dump-failedservers <filename> dump the failed servers to the named file\n"
1656 "get [key1] [key2] .. get specific statistics\n"
1657 "get-all get all statistics\n"
1658 "get-dont-throttle-names get the list of names that are not allowed to be throttled\n"
1659 "get-dont-throttle-netmasks get the list of netmasks that are not allowed to be throttled\n"
1660 "get-ntas get all configured Negative Trust Anchors\n"
1661 "get-tas get all configured Trust Anchors\n"
1662 "get-parameter [key1] [key2] .. get configuration parameters\n"
1663 "get-qtypelist get QType statistics\n"
1664 " notice: queries from cache aren't being counted yet\n"
1665 "help get this list\n"
1666 "ping check that all threads are alive\n"
1667 "quit stop the recursor daemon\n"
1668 "quit-nicely stop the recursor daemon nicely\n"
1669 "reload-acls reload ACLS\n"
1670 "reload-lua-script [filename] (re)load Lua script\n"
1671 "reload-lua-config [filename] (re)load Lua configuration file\n"
1672 "reload-zones reload all auth and forward zones\n"
1673 "set-ecs-minimum-ttl value set ecs-minimum-ttl-override\n"
1674 "set-max-cache-entries value set new maximum cache size\n"
1675 "set-max-packetcache-entries val set new maximum packet cache size\n"
1676 "set-minimum-ttl value set minimum-ttl-override\n"
1677 "set-carbon-server set a carbon server for telemetry\n"
1678 "set-dnssec-log-bogus SETTING enable (SETTING=yes) or disable (SETTING=no) logging of DNSSEC validation failures\n"
1679 "trace-regex [regex] emit resolution trace for matching queries (empty regex to clear trace)\n"
1680 "top-largeanswer-remotes show top remotes receiving large answers\n"
1681 "top-queries show top queries\n"
1682 "top-pub-queries show top queries grouped by public suffix list\n"
1683 "top-remotes show top remotes\n"
1684 "top-timeouts show top downstream timeouts\n"
1685 "top-servfail-queries show top queries receiving servfail answers\n"
1686 "top-bogus-queries show top queries validating as bogus\n"
1687 "top-pub-servfail-queries show top queries receiving servfail answers grouped by public suffix list\n"
1688 "top-pub-bogus-queries show top queries validating as bogus grouped by public suffix list\n"
1689 "top-servfail-remotes show top remotes receiving servfail answers\n"
1690 "top-bogus-remotes show top remotes receiving bogus answers\n"
1691 "unload-lua-script unload Lua script\n"
1692 "version return Recursor version number\n"
1693 "wipe-cache domain0 [domain1] .. wipe domain data from cache\n";
1694
1695 if(cmd=="get-all")
1696 return getAllStats();
1697
1698 if(cmd=="get")
1699 return doGet(begin, end);
1700
1701 if(cmd=="get-parameter")
1702 return doGetParameter(begin, end);
1703
1704 if(cmd=="quit") {
1705 *command=&doExit;
1706 return "bye\n";
1707 }
1708
1709 if(cmd=="version") {
1710 return getPDNSVersion()+"\n";
1711 }
1712
1713 if(cmd=="quit-nicely") {
1714 *command=&doExitNicely;
1715 return "bye nicely\n";
1716 }
1717
1718 if(cmd=="dump-cache")
1719 return doDumpCache(begin, end);
1720
1721 if(cmd=="dump-ednsstatus" || cmd=="dump-edns")
1722 return doDumpEDNSStatus(begin, end);
1723
1724 if(cmd=="dump-nsspeeds")
1725 return doDumpNSSpeeds(begin, end);
1726
1727 if(cmd=="dump-failedservers")
1728 return doDumpFailedServers(begin, end);
1729
1730 if(cmd=="dump-rpz") {
1731 return doDumpRPZ(begin, end);
1732 }
1733
1734 if(cmd=="dump-throttlemap")
1735 return doDumpThrottleMap(begin, end);
1736
1737 if(cmd=="wipe-cache" || cmd=="flushname")
1738 return doWipeCache(begin, end);
1739
1740 if(cmd=="reload-lua-script")
1741 return doQueueReloadLuaScript(begin, end);
1742
1743 if(cmd=="reload-lua-config") {
1744 if(begin != end)
1745 ::arg().set("lua-config-file") = *begin;
1746
1747 try {
1748 luaConfigDelayedThreads delayedLuaThreads;
1749 loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads);
1750 startLuaConfigDelayedThreads(delayedLuaThreads, g_luaconfs.getCopy().generation);
1751 g_log<<Logger::Warning<<"Reloaded Lua configuration file '"<<::arg()["lua-config-file"]<<"', requested via control channel"<<endl;
1752 return "Reloaded Lua configuration file '"+::arg()["lua-config-file"]+"'\n";
1753 }
1754 catch(std::exception& e) {
1755 return "Unable to load Lua script from '"+::arg()["lua-config-file"]+"': "+e.what()+"\n";
1756 }
1757 catch(const PDNSException& e) {
1758 return "Unable to load Lua script from '"+::arg()["lua-config-file"]+"': "+e.reason+"\n";
1759 }
1760 }
1761
1762 if(cmd=="set-carbon-server")
1763 return doSetCarbonServer(begin, end);
1764
1765 if(cmd=="trace-regex")
1766 return doTraceRegex(begin, end);
1767
1768 if(cmd=="unload-lua-script") {
1769 vector<string> empty;
1770 empty.push_back(string());
1771 return doQueueReloadLuaScript(empty.begin(), empty.end());
1772 }
1773
1774 if(cmd=="reload-acls") {
1775 if(!::arg()["chroot"].empty()) {
1776 g_log<<Logger::Error<<"Unable to reload ACL when chroot()'ed, requested via control channel"<<endl;
1777 return "Unable to reload ACL when chroot()'ed, please restart\n";
1778 }
1779
1780 try {
1781 parseACLs();
1782 }
1783 catch(std::exception& e)
1784 {
1785 g_log<<Logger::Error<<"Reloading ACLs failed (Exception: "<<e.what()<<")"<<endl;
1786 return e.what() + string("\n");
1787 }
1788 catch(PDNSException& ae)
1789 {
1790 g_log<<Logger::Error<<"Reloading ACLs failed (PDNSException: "<<ae.reason<<")"<<endl;
1791 return ae.reason + string("\n");
1792 }
1793 return "ok\n";
1794 }
1795
1796
1797 if(cmd=="top-remotes")
1798 return doGenericTopRemotes(pleaseGetRemotes);
1799
1800 if(cmd=="top-queries")
1801 return doGenericTopQueries(pleaseGetQueryRing);
1802
1803 if(cmd=="top-pub-queries")
1804 return doGenericTopQueries(pleaseGetQueryRing, getRegisteredName);
1805
1806 if(cmd=="top-servfail-queries")
1807 return doGenericTopQueries(pleaseGetServfailQueryRing);
1808
1809 if(cmd=="top-pub-servfail-queries")
1810 return doGenericTopQueries(pleaseGetServfailQueryRing, getRegisteredName);
1811
1812 if(cmd=="top-bogus-queries")
1813 return doGenericTopQueries(pleaseGetBogusQueryRing);
1814
1815 if(cmd=="top-pub-bogus-queries")
1816 return doGenericTopQueries(pleaseGetBogusQueryRing, getRegisteredName);
1817
1818
1819 if(cmd=="top-servfail-remotes")
1820 return doGenericTopRemotes(pleaseGetServfailRemotes);
1821
1822 if(cmd=="top-bogus-remotes")
1823 return doGenericTopRemotes(pleaseGetBogusRemotes);
1824
1825 if(cmd=="top-largeanswer-remotes")
1826 return doGenericTopRemotes(pleaseGetLargeAnswerRemotes);
1827
1828 if(cmd=="top-timeouts")
1829 return doGenericTopRemotes(pleaseGetTimeouts);
1830
1831
1832 if(cmd=="current-queries")
1833 return doCurrentQueries();
1834
1835 if(cmd=="ping") {
1836 return broadcastAccFunction<string>(nopFunction);
1837 }
1838
1839 if(cmd=="reload-zones") {
1840 if(!::arg()["chroot"].empty()) {
1841 g_log<<Logger::Error<<"Unable to reload zones and forwards when chroot()'ed, requested via control channel"<<endl;
1842 return "Unable to reload zones and forwards when chroot()'ed, please restart\n";
1843 }
1844 return reloadAuthAndForwards();
1845 }
1846
1847 if(cmd=="set-ecs-minimum-ttl") {
1848 return setMinimumECSTTL(begin, end);
1849 }
1850
1851 if(cmd=="set-max-cache-entries") {
1852 return setMaxCacheEntries(begin, end);
1853 }
1854 if(cmd=="set-max-packetcache-entries") {
1855 return setMaxPacketCacheEntries(begin, end);
1856 }
1857
1858 if(cmd=="set-minimum-ttl") {
1859 return setMinimumTTL(begin, end);
1860 }
1861
1862 if(cmd=="get-qtypelist") {
1863 return g_rs.getQTypeReport();
1864 }
1865
1866 if(cmd=="add-nta") {
1867 return doAddNTA(begin, end);
1868 }
1869
1870 if(cmd=="clear-nta") {
1871 return doClearNTA(begin, end);
1872 }
1873
1874 if(cmd=="get-ntas") {
1875 return getNTAs();
1876 }
1877
1878 if(cmd=="add-ta") {
1879 return doAddTA(begin, end);
1880 }
1881
1882 if(cmd=="clear-ta") {
1883 return doClearTA(begin, end);
1884 }
1885
1886 if(cmd=="get-tas") {
1887 return getTAs();
1888 }
1889
1890 if (cmd=="set-dnssec-log-bogus")
1891 return doSetDnssecLogBogus(begin, end);
1892
1893 if (cmd == "get-dont-throttle-names") {
1894 return getDontThrottleNames();
1895 }
1896
1897 if (cmd == "get-dont-throttle-netmasks") {
1898 return getDontThrottleNetmasks();
1899 }
1900
1901 if (cmd == "add-dont-throttle-names") {
1902 return addDontThrottleNames(begin, end);
1903 }
1904
1905 if (cmd == "add-dont-throttle-netmasks") {
1906 return addDontThrottleNetmasks(begin, end);
1907 }
1908
1909 if (cmd == "clear-dont-throttle-names") {
1910 return clearDontThrottleNames(begin, end);
1911 }
1912
1913 if (cmd == "clear-dont-throttle-netmasks") {
1914 return clearDontThrottleNetmasks(begin, end);
1915 }
1916
1917 return "Unknown command '"+cmd+"', try 'help'\n";
1918 }