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