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