]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rec_channel_rec.cc
Merge pull request #8777 from omoerbeek/rec-wip-qname-vs-ds
[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, uint16_t qtype)
398 {
399 return new uint64_t(t_RC->doWipeCache(canon, subtree, qtype));
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 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, 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 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 #ifdef __linux__
1166 addGetStat("cpu-iowait", boost::bind(getCPUIOWait, string()));
1167 addGetStat("cpu-steal", boost::bind(getCPUSteal, string()));
1168 #endif
1169
1170 for(unsigned int n=0; n < g_numThreads; ++n)
1171 addGetStat("cpu-msec-thread-"+std::to_string(n), boost::bind(&doGetThreadCPUMsec, n));
1172
1173 #ifdef MALLOC_TRACE
1174 addGetStat("memory-allocs", boost::bind(&MallocTracer::getAllocs, g_mtracer, string()));
1175 addGetStat("memory-alloc-flux", boost::bind(&MallocTracer::getAllocFlux, g_mtracer, string()));
1176 addGetStat("memory-allocated", boost::bind(&MallocTracer::getTotAllocated, g_mtracer, string()));
1177 #endif
1178
1179 addGetStat("dnssec-validations", &g_stats.dnssecValidations);
1180 addGetStat("dnssec-result-insecure", &g_stats.dnssecResults[Insecure]);
1181 addGetStat("dnssec-result-secure", &g_stats.dnssecResults[Secure]);
1182 addGetStat("dnssec-result-bogus", &g_stats.dnssecResults[Bogus]);
1183 addGetStat("dnssec-result-indeterminate", &g_stats.dnssecResults[Indeterminate]);
1184 addGetStat("dnssec-result-nta", &g_stats.dnssecResults[NTA]);
1185
1186 addGetStat("policy-result-noaction", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NoAction]);
1187 addGetStat("policy-result-drop", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Drop]);
1188 addGetStat("policy-result-nxdomain", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NXDOMAIN]);
1189 addGetStat("policy-result-nodata", &g_stats.policyResults[DNSFilterEngine::PolicyKind::NODATA]);
1190 addGetStat("policy-result-truncate", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Truncate]);
1191 addGetStat("policy-result-custom", &g_stats.policyResults[DNSFilterEngine::PolicyKind::Custom]);
1192
1193 addGetStat("rebalanced-queries", &g_stats.rebalancedQueries);
1194
1195 /* make sure that the ECS stats are properly initialized */
1196 SyncRes::clearECSStats();
1197 for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize4.size(); idx++) {
1198 const std::string name = "ecs-v4-response-bits-" + std::to_string(idx + 1);
1199 addGetStat(name, &(SyncRes::s_ecsResponsesBySubnetSize4.at(idx)));
1200 }
1201 for (size_t idx = 0; idx < SyncRes::s_ecsResponsesBySubnetSize6.size(); idx++) {
1202 const std::string name = "ecs-v6-response-bits-" + std::to_string(idx + 1);
1203 addGetStat(name, &(SyncRes::s_ecsResponsesBySubnetSize6.at(idx)));
1204 }
1205 }
1206
1207 void doExitGeneric(bool nicely)
1208 {
1209 g_log<<Logger::Error<<"Exiting on user request"<<endl;
1210 extern RecursorControlChannel s_rcc;
1211 s_rcc.~RecursorControlChannel();
1212
1213 extern string s_pidfname;
1214 if(!s_pidfname.empty())
1215 unlink(s_pidfname.c_str()); // we can at least try..
1216 if(nicely) {
1217 RecursorControlChannel::stop = 1;
1218 } else {
1219 _exit(1);
1220 }
1221 }
1222
1223 void doExit()
1224 {
1225 doExitGeneric(false);
1226 }
1227
1228 void doExitNicely()
1229 {
1230 doExitGeneric(true);
1231 }
1232
1233 vector<pair<DNSName, uint16_t> >* pleaseGetQueryRing()
1234 {
1235 typedef pair<DNSName,uint16_t> query_t;
1236 vector<query_t >* ret = new vector<query_t>();
1237 if(!t_queryring)
1238 return ret;
1239 ret->reserve(t_queryring->size());
1240
1241 for(const query_t& q : *t_queryring) {
1242 ret->push_back(q);
1243 }
1244 return ret;
1245 }
1246 vector<pair<DNSName,uint16_t> >* pleaseGetServfailQueryRing()
1247 {
1248 typedef pair<DNSName,uint16_t> query_t;
1249 vector<query_t>* ret = new vector<query_t>();
1250 if(!t_servfailqueryring)
1251 return ret;
1252 ret->reserve(t_servfailqueryring->size());
1253 for(const query_t& q : *t_servfailqueryring) {
1254 ret->push_back(q);
1255 }
1256 return ret;
1257 }
1258 vector<pair<DNSName,uint16_t> >* pleaseGetBogusQueryRing()
1259 {
1260 typedef pair<DNSName,uint16_t> query_t;
1261 vector<query_t>* ret = new vector<query_t>();
1262 if(!t_bogusqueryring)
1263 return ret;
1264 ret->reserve(t_bogusqueryring->size());
1265 for(const query_t& q : *t_bogusqueryring) {
1266 ret->push_back(q);
1267 }
1268 return ret;
1269 }
1270
1271
1272
1273 typedef boost::function<vector<ComboAddress>*()> pleaseremotefunc_t;
1274 typedef boost::function<vector<pair<DNSName,uint16_t> >*()> pleasequeryfunc_t;
1275
1276 vector<ComboAddress>* pleaseGetRemotes()
1277 {
1278 vector<ComboAddress>* ret = new vector<ComboAddress>();
1279 if(!t_remotes)
1280 return ret;
1281
1282 ret->reserve(t_remotes->size());
1283 for(const ComboAddress& ca : *t_remotes) {
1284 ret->push_back(ca);
1285 }
1286 return ret;
1287 }
1288
1289 vector<ComboAddress>* pleaseGetServfailRemotes()
1290 {
1291 vector<ComboAddress>* ret = new vector<ComboAddress>();
1292 if(!t_servfailremotes)
1293 return ret;
1294 ret->reserve(t_servfailremotes->size());
1295 for(const ComboAddress& ca : *t_servfailremotes) {
1296 ret->push_back(ca);
1297 }
1298 return ret;
1299 }
1300
1301 vector<ComboAddress>* pleaseGetBogusRemotes()
1302 {
1303 vector<ComboAddress>* ret = new vector<ComboAddress>();
1304 if(!t_bogusremotes)
1305 return ret;
1306 ret->reserve(t_bogusremotes->size());
1307 for(const ComboAddress& ca : *t_bogusremotes) {
1308 ret->push_back(ca);
1309 }
1310 return ret;
1311 }
1312
1313 vector<ComboAddress>* pleaseGetLargeAnswerRemotes()
1314 {
1315 vector<ComboAddress>* ret = new vector<ComboAddress>();
1316 if(!t_largeanswerremotes)
1317 return ret;
1318 ret->reserve(t_largeanswerremotes->size());
1319 for(const ComboAddress& ca : *t_largeanswerremotes) {
1320 ret->push_back(ca);
1321 }
1322 return ret;
1323 }
1324
1325 vector<ComboAddress>* pleaseGetTimeouts()
1326 {
1327 vector<ComboAddress>* ret = new vector<ComboAddress>();
1328 if(!t_timeouts)
1329 return ret;
1330 ret->reserve(t_timeouts->size());
1331 for(const ComboAddress& ca : *t_timeouts) {
1332 ret->push_back(ca);
1333 }
1334 return ret;
1335 }
1336
1337 string doGenericTopRemotes(pleaseremotefunc_t func)
1338 {
1339 typedef map<ComboAddress, int, ComboAddress::addressOnlyLessThan> counts_t;
1340 counts_t counts;
1341
1342 vector<ComboAddress> remotes=broadcastAccFunction<vector<ComboAddress> >(func);
1343
1344 unsigned int total=0;
1345 for(const ComboAddress& ca : remotes) {
1346 total++;
1347 counts[ca]++;
1348 }
1349
1350 typedef std::multimap<int, ComboAddress> rcounts_t;
1351 rcounts_t rcounts;
1352
1353 for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
1354 rcounts.insert(make_pair(-i->second, i->first));
1355
1356 ostringstream ret;
1357 ret<<"Over last "<<total<<" entries:\n";
1358 format fmt("%.02f%%\t%s\n");
1359 int limit=0, accounted=0;
1360 if(total) {
1361 for(rcounts_t::const_iterator i=rcounts.begin(); i != rcounts.end() && limit < 20; ++i, ++limit) {
1362 ret<< fmt % (-100.0*i->first/total) % i->second.toString();
1363 accounted+= -i->first;
1364 }
1365 ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest";
1366 }
1367 return ret.str();
1368 }
1369
1370 // XXX DNSName Pain - this function should benefit from native DNSName methods
1371 DNSName getRegisteredName(const DNSName& dom)
1372 {
1373 auto parts=dom.getRawLabels();
1374 if(parts.size()<=2)
1375 return dom;
1376 reverse(parts.begin(), parts.end());
1377 for(string& str : parts) { str=toLower(str); };
1378
1379 // uk co migweb
1380 string last;
1381 while(!parts.empty()) {
1382 if(parts.size()==1 || binary_search(g_pubs.begin(), g_pubs.end(), parts)) {
1383
1384 string ret=last;
1385 if(!ret.empty())
1386 ret+=".";
1387
1388 for(auto p = parts.crbegin(); p != parts.crend(); ++p) {
1389 ret+=(*p)+".";
1390 }
1391 return DNSName(ret);
1392 }
1393
1394 last=parts[parts.size()-1];
1395 parts.resize(parts.size()-1);
1396 }
1397 return DNSName("??");
1398 }
1399
1400 static DNSName nopFilter(const DNSName& name)
1401 {
1402 return name;
1403 }
1404
1405 string doGenericTopQueries(pleasequeryfunc_t func, boost::function<DNSName(const DNSName&)> filter=nopFilter)
1406 {
1407 typedef pair<DNSName,uint16_t> query_t;
1408 typedef map<query_t, int> counts_t;
1409 counts_t counts;
1410 vector<query_t> queries=broadcastAccFunction<vector<query_t> >(func);
1411
1412 unsigned int total=0;
1413 for(const query_t& q : queries) {
1414 total++;
1415 counts[make_pair(filter(q.first),q.second)]++;
1416 }
1417
1418 typedef std::multimap<int, query_t> rcounts_t;
1419 rcounts_t rcounts;
1420
1421 for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
1422 rcounts.insert(make_pair(-i->second, i->first));
1423
1424 ostringstream ret;
1425 ret<<"Over last "<<total<<" entries:\n";
1426 format fmt("%.02f%%\t%s\n");
1427 int limit=0, accounted=0;
1428 if(total) {
1429 for(rcounts_t::const_iterator i=rcounts.begin(); i != rcounts.end() && limit < 20; ++i, ++limit) {
1430 ret<< fmt % (-100.0*i->first/total) % (i->second.first.toLogString()+"|"+DNSRecordContent::NumberToType(i->second.second));
1431 accounted+= -i->first;
1432 }
1433 ret<< '\n' << fmt % (100.0*(total-accounted)/total) % "rest";
1434 }
1435
1436
1437 return ret.str();
1438 }
1439
1440 static string* nopFunction()
1441 {
1442 return new string("pong\n");
1443 }
1444
1445 static string getDontThrottleNames() {
1446 auto dtn = g_dontThrottleNames.getLocal();
1447 return dtn->toString() + "\n";
1448 }
1449
1450 static string getDontThrottleNetmasks() {
1451 auto dtn = g_dontThrottleNetmasks.getLocal();
1452 return dtn->toString() + "\n";
1453 }
1454
1455 template<typename T>
1456 static string addDontThrottleNames(T begin, T end) {
1457 if (begin == end) {
1458 return "No names specified, keeping existing list\n";
1459 }
1460 vector<DNSName> toAdd;
1461 while (begin != end) {
1462 try {
1463 auto d = DNSName(*begin);
1464 toAdd.push_back(d);
1465 }
1466 catch(const std::exception &e) {
1467 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
1468 }
1469 begin++;
1470 }
1471
1472 string ret = "Added";
1473 auto dnt = g_dontThrottleNames.getCopy();
1474 bool first = true;
1475 for (auto const &d : toAdd) {
1476 if (!first) {
1477 ret += ",";
1478 }
1479 first = false;
1480 ret += " " + d.toLogString();
1481 dnt.add(d);
1482 }
1483
1484 g_dontThrottleNames.setState(std::move(dnt));
1485
1486 ret += " to the list of nameservers that may not be throttled";
1487 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1488 return ret + "\n";
1489 }
1490
1491 template<typename T>
1492 static string addDontThrottleNetmasks(T begin, T end) {
1493 if (begin == end) {
1494 return "No netmasks specified, keeping existing list\n";
1495 }
1496 vector<Netmask> toAdd;
1497 while (begin != end) {
1498 try {
1499 auto n = Netmask(*begin);
1500 toAdd.push_back(n);
1501 }
1502 catch(const std::exception &e) {
1503 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
1504 }
1505 catch(const PDNSException &e) {
1506 return "Problem parsing '" + *begin + "': "+ e.reason + ", nothing added\n";
1507 }
1508 begin++;
1509 }
1510
1511 string ret = "Added";
1512 auto dnt = g_dontThrottleNetmasks.getCopy();
1513 bool first = true;
1514 for (auto const &t : toAdd) {
1515 if (!first) {
1516 ret += ",";
1517 }
1518 first = false;
1519 ret += " " + t.toString();
1520 dnt.addMask(t);
1521 }
1522
1523 g_dontThrottleNetmasks.setState(std::move(dnt));
1524
1525 ret += " to the list of nameserver netmasks that may not be throttled";
1526 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1527 return ret + "\n";
1528 }
1529
1530 template<typename T>
1531 static string clearDontThrottleNames(T begin, T end) {
1532 if(begin == end)
1533 return "No names specified, doing nothing.\n";
1534
1535 if (begin + 1 == end && *begin == "*"){
1536 SuffixMatchNode smn;
1537 g_dontThrottleNames.setState(std::move(smn));
1538 string ret = "Cleared list of nameserver names that may not be throttled";
1539 g_log<<Logger::Warning<<ret<<", requested via control channel"<<endl;
1540 return ret + "\n";
1541 }
1542
1543 vector<DNSName> toRemove;
1544 while (begin != end) {
1545 try {
1546 if (*begin == "*") {
1547 return "Please don't mix '*' with other names, nothing removed\n";
1548 }
1549 toRemove.push_back(DNSName(*begin));
1550 }
1551 catch (const std::exception &e) {
1552 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing removed\n";
1553 }
1554 begin++;
1555 }
1556
1557 string ret = "Removed";
1558 bool first = true;
1559 auto dnt = g_dontThrottleNames.getCopy();
1560 for (const auto &name : toRemove) {
1561 if (!first) {
1562 ret += ",";
1563 }
1564 first = false;
1565 ret += " " + name.toLogString();
1566 dnt.remove(name);
1567 }
1568
1569 g_dontThrottleNames.setState(std::move(dnt));
1570
1571 ret += " from the list of nameservers that may not be throttled";
1572 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1573 return ret + "\n";
1574 }
1575
1576 template<typename T>
1577 static string clearDontThrottleNetmasks(T begin, T end) {
1578 if(begin == end)
1579 return "No netmasks specified, doing nothing.\n";
1580
1581 if (begin + 1 == end && *begin == "*"){
1582 auto nmg = g_dontThrottleNetmasks.getCopy();
1583 nmg.clear();
1584 g_dontThrottleNetmasks.setState(std::move(nmg));
1585
1586 string ret = "Cleared list of nameserver addresses that may not be throttled";
1587 g_log<<Logger::Warning<<ret<<", requested via control channel"<<endl;
1588 return ret + "\n";
1589 }
1590
1591 std::vector<Netmask> toRemove;
1592 while (begin != end) {
1593 try {
1594 if (*begin == "*") {
1595 return "Please don't mix '*' with other netmasks, nothing removed\n";
1596 }
1597 auto n = Netmask(*begin);
1598 toRemove.push_back(n);
1599 }
1600 catch(const std::exception &e) {
1601 return "Problem parsing '" + *begin + "': "+ e.what() + ", nothing added\n";
1602 }
1603 catch(const PDNSException &e) {
1604 return "Problem parsing '" + *begin + "': "+ e.reason + ", nothing added\n";
1605 }
1606 begin++;
1607 }
1608
1609 string ret = "Removed";
1610 bool first = true;
1611 auto dnt = g_dontThrottleNetmasks.getCopy();
1612 for (const auto &mask : toRemove) {
1613 if (!first) {
1614 ret += ",";
1615 }
1616 first = false;
1617 ret += " " + mask.toString();
1618 dnt.deleteMask(mask);
1619 }
1620
1621 g_dontThrottleNetmasks.setState(std::move(dnt));
1622
1623 ret += " from the list of nameservers that may not be throttled";
1624 g_log<<Logger::Info<<ret<<", requested via control channel"<<endl;
1625 return ret + "\n";
1626 }
1627
1628
1629 string RecursorControlParser::getAnswer(const string& question, RecursorControlParser::func_t** command)
1630 {
1631 *command=nop;
1632 vector<string> words;
1633 stringtok(words, question);
1634
1635 if(words.empty())
1636 return "invalid command\n";
1637
1638 string cmd=toLower(words[0]);
1639 vector<string>::const_iterator begin=words.begin()+1, end=words.end();
1640
1641 // should probably have a smart dispatcher here, like auth has
1642 if(cmd=="help")
1643 return
1644 "add-dont-throttle-names [N...] add names that are not allowed to be throttled\n"
1645 "add-dont-throttle-netmasks [N...]\n"
1646 " add netmasks that are not allowed to be throttled\n"
1647 "add-nta DOMAIN [REASON] add a Negative Trust Anchor for DOMAIN with the comment REASON\n"
1648 "add-ta DOMAIN DSRECORD add a Trust Anchor for DOMAIN with data DSRECORD\n"
1649 "current-queries show currently active queries\n"
1650 "clear-dont-throttle-names [N...] remove names that are not allowed to be throttled. If N is '*', remove all\n"
1651 "clear-dont-throttle-netmasks [N...]\n"
1652 " remove netmasks that are not allowed to be throttled. If N is '*', remove all\n"
1653 "clear-nta [DOMAIN]... Clear the Negative Trust Anchor for DOMAINs, if no DOMAIN is specified, remove all\n"
1654 "clear-ta [DOMAIN]... Clear the Trust Anchor for DOMAINs\n"
1655 "dump-cache <filename> dump cache contents to the named file\n"
1656 "dump-edns [status] <filename> dump EDNS status to the named file\n"
1657 "dump-nsspeeds <filename> dump nsspeeds statistics to the named file\n"
1658 "dump-rpz <zone name> <filename> dump the content of a RPZ zone to the named file\n"
1659 "dump-throttlemap <filename> dump the contents of the throttle map to the named file\n"
1660 "dump-failedservers <filename> dump the failed servers to the named file\n"
1661 "get [key1] [key2] .. get specific statistics\n"
1662 "get-all get all statistics\n"
1663 "get-dont-throttle-names get the list of names that are not allowed to be throttled\n"
1664 "get-dont-throttle-netmasks get the list of netmasks that are not allowed to be throttled\n"
1665 "get-ntas get all configured Negative Trust Anchors\n"
1666 "get-tas get all configured Trust Anchors\n"
1667 "get-parameter [key1] [key2] .. get configuration parameters\n"
1668 "get-qtypelist get QType statistics\n"
1669 " notice: queries from cache aren't being counted yet\n"
1670 "help get this list\n"
1671 "ping check that all threads are alive\n"
1672 "quit stop the recursor daemon\n"
1673 "quit-nicely stop the recursor daemon nicely\n"
1674 "reload-acls reload ACLS\n"
1675 "reload-lua-script [filename] (re)load Lua script\n"
1676 "reload-lua-config [filename] (re)load Lua configuration file\n"
1677 "reload-zones reload all auth and forward zones\n"
1678 "set-ecs-minimum-ttl value set ecs-minimum-ttl-override\n"
1679 "set-max-cache-entries value set new maximum cache size\n"
1680 "set-max-packetcache-entries val set new maximum packet cache size\n"
1681 "set-minimum-ttl value set minimum-ttl-override\n"
1682 "set-carbon-server set a carbon server for telemetry\n"
1683 "set-dnssec-log-bogus SETTING enable (SETTING=yes) or disable (SETTING=no) logging of DNSSEC validation failures\n"
1684 "trace-regex [regex] emit resolution trace for matching queries (empty regex to clear trace)\n"
1685 "top-largeanswer-remotes show top remotes receiving large answers\n"
1686 "top-queries show top queries\n"
1687 "top-pub-queries show top queries grouped by public suffix list\n"
1688 "top-remotes show top remotes\n"
1689 "top-timeouts show top downstream timeouts\n"
1690 "top-servfail-queries show top queries receiving servfail answers\n"
1691 "top-bogus-queries show top queries validating as bogus\n"
1692 "top-pub-servfail-queries show top queries receiving servfail answers grouped by public suffix list\n"
1693 "top-pub-bogus-queries show top queries validating as bogus grouped by public suffix list\n"
1694 "top-servfail-remotes show top remotes receiving servfail answers\n"
1695 "top-bogus-remotes show top remotes receiving bogus answers\n"
1696 "unload-lua-script unload Lua script\n"
1697 "version return Recursor version number\n"
1698 "wipe-cache domain0 [domain1] .. wipe domain data from cache\n"
1699 "wipe-cache-typed type domain0 [domain1] .. wipe domain data with qtype from cache\n";
1700
1701 if(cmd=="get-all")
1702 return getAllStats();
1703
1704 if(cmd=="get")
1705 return doGet(begin, end);
1706
1707 if(cmd=="get-parameter")
1708 return doGetParameter(begin, end);
1709
1710 if(cmd=="quit") {
1711 *command=&doExit;
1712 return "bye\n";
1713 }
1714
1715 if(cmd=="version") {
1716 return getPDNSVersion()+"\n";
1717 }
1718
1719 if(cmd=="quit-nicely") {
1720 *command=&doExitNicely;
1721 return "bye nicely\n";
1722 }
1723
1724 if(cmd=="dump-cache")
1725 return doDumpCache(begin, end);
1726
1727 if(cmd=="dump-ednsstatus" || cmd=="dump-edns")
1728 return doDumpEDNSStatus(begin, end);
1729
1730 if(cmd=="dump-nsspeeds")
1731 return doDumpNSSpeeds(begin, end);
1732
1733 if(cmd=="dump-failedservers")
1734 return doDumpFailedServers(begin, end);
1735
1736 if(cmd=="dump-rpz") {
1737 return doDumpRPZ(begin, end);
1738 }
1739
1740 if(cmd=="dump-throttlemap")
1741 return doDumpThrottleMap(begin, end);
1742
1743 if(cmd=="wipe-cache" || cmd=="flushname")
1744 return doWipeCache(begin, end, 0xffff);
1745
1746 if(cmd=="wipe-cache-typed") {
1747 uint16_t qtype = QType::chartocode(begin->c_str());
1748 ++begin;
1749 return doWipeCache(begin, end, qtype);
1750 }
1751
1752 if(cmd=="reload-lua-script")
1753 return doQueueReloadLuaScript(begin, end);
1754
1755 if(cmd=="reload-lua-config") {
1756 if(begin != end)
1757 ::arg().set("lua-config-file") = *begin;
1758
1759 try {
1760 luaConfigDelayedThreads delayedLuaThreads;
1761 loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads);
1762 startLuaConfigDelayedThreads(delayedLuaThreads, g_luaconfs.getCopy().generation);
1763 g_log<<Logger::Warning<<"Reloaded Lua configuration file '"<<::arg()["lua-config-file"]<<"', requested via control channel"<<endl;
1764 return "Reloaded Lua configuration file '"+::arg()["lua-config-file"]+"'\n";
1765 }
1766 catch(std::exception& e) {
1767 return "Unable to load Lua script from '"+::arg()["lua-config-file"]+"': "+e.what()+"\n";
1768 }
1769 catch(const PDNSException& e) {
1770 return "Unable to load Lua script from '"+::arg()["lua-config-file"]+"': "+e.reason+"\n";
1771 }
1772 }
1773
1774 if(cmd=="set-carbon-server")
1775 return doSetCarbonServer(begin, end);
1776
1777 if(cmd=="trace-regex")
1778 return doTraceRegex(begin, end);
1779
1780 if(cmd=="unload-lua-script") {
1781 vector<string> empty;
1782 empty.push_back(string());
1783 return doQueueReloadLuaScript(empty.begin(), empty.end());
1784 }
1785
1786 if(cmd=="reload-acls") {
1787 if(!::arg()["chroot"].empty()) {
1788 g_log<<Logger::Error<<"Unable to reload ACL when chroot()'ed, requested via control channel"<<endl;
1789 return "Unable to reload ACL when chroot()'ed, please restart\n";
1790 }
1791
1792 try {
1793 parseACLs();
1794 }
1795 catch(std::exception& e)
1796 {
1797 g_log<<Logger::Error<<"Reloading ACLs failed (Exception: "<<e.what()<<")"<<endl;
1798 return e.what() + string("\n");
1799 }
1800 catch(PDNSException& ae)
1801 {
1802 g_log<<Logger::Error<<"Reloading ACLs failed (PDNSException: "<<ae.reason<<")"<<endl;
1803 return ae.reason + string("\n");
1804 }
1805 return "ok\n";
1806 }
1807
1808
1809 if(cmd=="top-remotes")
1810 return doGenericTopRemotes(pleaseGetRemotes);
1811
1812 if(cmd=="top-queries")
1813 return doGenericTopQueries(pleaseGetQueryRing);
1814
1815 if(cmd=="top-pub-queries")
1816 return doGenericTopQueries(pleaseGetQueryRing, getRegisteredName);
1817
1818 if(cmd=="top-servfail-queries")
1819 return doGenericTopQueries(pleaseGetServfailQueryRing);
1820
1821 if(cmd=="top-pub-servfail-queries")
1822 return doGenericTopQueries(pleaseGetServfailQueryRing, getRegisteredName);
1823
1824 if(cmd=="top-bogus-queries")
1825 return doGenericTopQueries(pleaseGetBogusQueryRing);
1826
1827 if(cmd=="top-pub-bogus-queries")
1828 return doGenericTopQueries(pleaseGetBogusQueryRing, getRegisteredName);
1829
1830
1831 if(cmd=="top-servfail-remotes")
1832 return doGenericTopRemotes(pleaseGetServfailRemotes);
1833
1834 if(cmd=="top-bogus-remotes")
1835 return doGenericTopRemotes(pleaseGetBogusRemotes);
1836
1837 if(cmd=="top-largeanswer-remotes")
1838 return doGenericTopRemotes(pleaseGetLargeAnswerRemotes);
1839
1840 if(cmd=="top-timeouts")
1841 return doGenericTopRemotes(pleaseGetTimeouts);
1842
1843
1844 if(cmd=="current-queries")
1845 return doCurrentQueries();
1846
1847 if(cmd=="ping") {
1848 return broadcastAccFunction<string>(nopFunction);
1849 }
1850
1851 if(cmd=="reload-zones") {
1852 if(!::arg()["chroot"].empty()) {
1853 g_log<<Logger::Error<<"Unable to reload zones and forwards when chroot()'ed, requested via control channel"<<endl;
1854 return "Unable to reload zones and forwards when chroot()'ed, please restart\n";
1855 }
1856 return reloadAuthAndForwards();
1857 }
1858
1859 if(cmd=="set-ecs-minimum-ttl") {
1860 return setMinimumECSTTL(begin, end);
1861 }
1862
1863 if(cmd=="set-max-cache-entries") {
1864 return setMaxCacheEntries(begin, end);
1865 }
1866 if(cmd=="set-max-packetcache-entries") {
1867 return setMaxPacketCacheEntries(begin, end);
1868 }
1869
1870 if(cmd=="set-minimum-ttl") {
1871 return setMinimumTTL(begin, end);
1872 }
1873
1874 if(cmd=="get-qtypelist") {
1875 return g_rs.getQTypeReport();
1876 }
1877
1878 if(cmd=="add-nta") {
1879 return doAddNTA(begin, end);
1880 }
1881
1882 if(cmd=="clear-nta") {
1883 return doClearNTA(begin, end);
1884 }
1885
1886 if(cmd=="get-ntas") {
1887 return getNTAs();
1888 }
1889
1890 if(cmd=="add-ta") {
1891 return doAddTA(begin, end);
1892 }
1893
1894 if(cmd=="clear-ta") {
1895 return doClearTA(begin, end);
1896 }
1897
1898 if(cmd=="get-tas") {
1899 return getTAs();
1900 }
1901
1902 if (cmd=="set-dnssec-log-bogus")
1903 return doSetDnssecLogBogus(begin, end);
1904
1905 if (cmd == "get-dont-throttle-names") {
1906 return getDontThrottleNames();
1907 }
1908
1909 if (cmd == "get-dont-throttle-netmasks") {
1910 return getDontThrottleNetmasks();
1911 }
1912
1913 if (cmd == "add-dont-throttle-names") {
1914 return addDontThrottleNames(begin, end);
1915 }
1916
1917 if (cmd == "add-dont-throttle-netmasks") {
1918 return addDontThrottleNetmasks(begin, end);
1919 }
1920
1921 if (cmd == "clear-dont-throttle-names") {
1922 return clearDontThrottleNames(begin, end);
1923 }
1924
1925 if (cmd == "clear-dont-throttle-netmasks") {
1926 return clearDontThrottleNetmasks(begin, end);
1927 }
1928
1929 return "Unknown command '"+cmd+"', try 'help'\n";
1930 }