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