]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/receiver.cc
Merge pull request #9084 from pieterlexis/dnsdist_latency_prometheus_help
[thirdparty/pdns.git] / pdns / receiver.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "packetcache.hh"
26
27 #include <cstdio>
28 #include <signal.h>
29 #include <cstring>
30 #include <cstdlib>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <iostream>
36 #include <string>
37 #include <sys/stat.h>
38 #include <unistd.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42 #include <errno.h>
43 #include <pthread.h>
44 #include <unistd.h>
45 #include <sys/mman.h>
46 #include <fcntl.h>
47 #include <fstream>
48 #include <boost/algorithm/string.hpp>
49 #ifdef HAVE_LIBSODIUM
50 #include <sodium.h>
51 #endif
52 #include "opensslsigners.hh"
53
54 #include "dns.hh"
55 #include "dnsbackend.hh"
56 #include "ueberbackend.hh"
57 #include "dnspacket.hh"
58 #include "nameserver.hh"
59 #include "distributor.hh"
60 #include "logger.hh"
61 #include "arguments.hh"
62 #include "packethandler.hh"
63 #include "statbag.hh"
64 #include "tcpreceiver.hh"
65 #include "misc.hh"
66 #include "dynlistener.hh"
67 #include "dynhandler.hh"
68 #include "communicator.hh"
69 #include "dnsproxy.hh"
70 #include "utility.hh"
71 #include "common_startup.hh"
72 #include "dnsrecords.hh"
73 #include "version.hh"
74
75 #ifdef HAVE_LUA_RECORDS
76 #include "minicurl.hh"
77 #endif /* HAVE_LUA_RECORDS */
78
79 time_t s_starttime;
80
81 string s_programname="pdns"; // used in packethandler.cc
82
83 const char *funnytext=
84 "*****************************************************************************\n"\
85 "Ok, you just ran pdns_server through 'strings' hoping to find funny messages.\n"\
86 "Well, you found one. \n"\
87 "Two ions are flying through their particle accelerator, says the one to the\n"
88 "other 'I think I've lost an electron!' \n"\
89 "So the other one says, 'Are you sure?'. 'YEAH! I'M POSITIVE!'\n"\
90 " the pdns crew - pdns@powerdns.com\n"
91 "*****************************************************************************\n";
92
93
94 // start (sys)logging
95
96
97 /**
98 \file receiver.cc
99 \brief The main loop of powerdns
100
101 This file is where it all happens - main is here, as are the two pivotal threads qthread() and athread()
102 */
103
104 static void daemonize(void)
105 {
106 if(fork())
107 exit(0); // bye bye
108
109 setsid();
110
111 int i=open("/dev/null",O_RDWR); /* open stdin */
112 if(i < 0)
113 g_log<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
114 else {
115 dup2(i,0); /* stdin */
116 dup2(i,1); /* stderr */
117 dup2(i,2); /* stderr */
118 close(i);
119 }
120 }
121
122 static int cpid;
123 static void takedown(int i)
124 {
125 if(cpid) {
126 g_log<<Logger::Error<<"Guardian is killed, taking down children with us"<<endl;
127 kill(cpid,SIGKILL);
128 exit(0);
129 }
130 }
131
132 static void writePid(void)
133 {
134 if(!::arg().mustDo("write-pid"))
135 return;
136
137 string fname=::arg()["socket-dir"];
138 if (::arg()["socket-dir"].empty()) {
139 if (::arg()["chroot"].empty())
140 fname = std::string(LOCALSTATEDIR) + "/pdns";
141 else
142 fname = ::arg()["chroot"] + "/";
143 } else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) {
144 fname = ::arg()["chroot"] + ::arg()["socket-dir"];
145 }
146
147 fname += + "/" + s_programname + ".pid";
148 ofstream of(fname.c_str());
149 if(of)
150 of<<getpid()<<endl;
151 else
152 g_log<<Logger::Error<<"Writing pid for "<<getpid()<<" to "<<fname<<" failed: "<<stringerror()<<endl;
153 }
154
155 int g_fd1[2], g_fd2[2];
156 FILE *g_fp;
157 std::mutex g_guardian_lock;
158
159 // The next two methods are not in dynhandler.cc because they use a few items declared in this file.
160 static string DLCycleHandler(const vector<string>&parts, pid_t ppid)
161 {
162 kill(cpid, SIGKILL); // why?
163 kill(cpid, SIGKILL); // why?
164 sleep(1);
165 return "ok";
166 }
167
168 static string DLRestHandler(const vector<string>&parts, pid_t ppid)
169 {
170 string line;
171
172 for(vector<string>::const_iterator i=parts.begin();i!=parts.end();++i) {
173 if(i!=parts.begin())
174 line.append(1,' ');
175 line.append(*i);
176 }
177 line.append(1,'\n');
178
179 std::lock_guard<std::mutex> l(g_guardian_lock);
180
181 try {
182 writen2(g_fd1[1],line.c_str(),line.size()+1);
183 }
184 catch(PDNSException &ae) {
185 return "Error communicating with instance: "+ae.reason;
186 }
187 char mesg[512];
188 string response;
189 while(fgets(mesg,sizeof(mesg),g_fp)) {
190 if(*mesg=='\0')
191 break;
192 response+=mesg;
193 }
194 boost::trim_right(response);
195 return response;
196 }
197
198
199
200 static int guardian(int argc, char **argv)
201 {
202 if(isGuarded(argv))
203 return 0;
204
205 int infd=0, outfd=1;
206
207 DynListener dlg(s_programname);
208 dlg.registerFunc("QUIT",&DLQuitHandler, "quit daemon");
209 dlg.registerFunc("CYCLE",&DLCycleHandler, "restart instance");
210 dlg.registerFunc("PING",&DLPingHandler, "ping guardian");
211 dlg.registerFunc("STATUS",&DLStatusHandler, "get instance status from guardian");
212 dlg.registerRestFunc(&DLRestHandler);
213 dlg.go();
214 string progname=argv[0];
215
216 bool first=true;
217 cpid=0;
218
219 g_guardian_lock.lock();
220
221 for(;;) {
222 int pid;
223 setStatus("Launching child");
224
225 if(pipe(g_fd1)<0 || pipe(g_fd2)<0) {
226 g_log<<Logger::Critical<<"Unable to open pipe for coprocess: "<<stringerror()<<endl;
227 exit(1);
228 }
229
230 if(!(g_fp=fdopen(g_fd2[0],"r"))) {
231 g_log<<Logger::Critical<<"Unable to associate a file pointer with pipe: "<<stringerror()<<endl;
232 exit(1);
233 }
234 setbuf(g_fp,0); // no buffering please, confuses select
235
236 if(!(pid=fork())) { // child
237 signal(SIGTERM, SIG_DFL);
238
239 signal(SIGHUP, SIG_DFL);
240 signal(SIGUSR1, SIG_DFL);
241 signal(SIGUSR2, SIG_DFL);
242
243 char **const newargv=new char*[argc+2];
244 int n;
245
246 if(::arg()["config-name"]!="") {
247 progname+="-"+::arg()["config-name"];
248 g_log<<Logger::Error<<"Virtual configuration name: "<<::arg()["config-name"]<<endl;
249 }
250
251 newargv[0]=strdup(const_cast<char *>((progname+"-instance").c_str()));
252 for(n=1;n<argc;n++) {
253 newargv[n]=argv[n];
254 }
255 newargv[n]=0;
256
257 g_log<<Logger::Error<<"Guardian is launching an instance"<<endl;
258 close(g_fd1[1]);
259 fclose(g_fp); // this closes g_fd2[0] for us
260
261 if(g_fd1[0]!= infd) {
262 dup2(g_fd1[0], infd);
263 close(g_fd1[0]);
264 }
265
266 if(g_fd2[1]!= outfd) {
267 dup2(g_fd2[1], outfd);
268 close(g_fd2[1]);
269 }
270 if(execvp(argv[0], newargv)<0) {
271 g_log<<Logger::Error<<"Unable to execvp '"<<argv[0]<<"': "<<stringerror()<<endl;
272 char **p=newargv;
273 while(*p)
274 g_log<<Logger::Error<<*p++<<endl;
275
276 exit(1);
277 }
278 g_log<<Logger::Error<<"execvp returned!!"<<endl;
279 // never reached
280 }
281 else if(pid>0) { // parent
282 close(g_fd1[0]);
283 close(g_fd2[1]);
284
285 if(first) {
286 first=false;
287 signal(SIGTERM, takedown);
288
289 signal(SIGHUP, SIG_IGN);
290 signal(SIGUSR1, SIG_IGN);
291 signal(SIGUSR2, SIG_IGN);
292
293 writePid();
294 }
295 g_guardian_lock.unlock();
296 int status;
297 cpid=pid;
298 for(;;) {
299 int ret=waitpid(pid,&status,WNOHANG);
300
301 if(ret<0) {
302 g_log<<Logger::Error<<"In guardian loop, waitpid returned error: "<<stringerror()<<endl;
303 g_log<<Logger::Error<<"Dying"<<endl;
304 exit(1);
305 }
306 else if(ret) // something exited
307 break;
308 else { // child is alive
309 // execute some kind of ping here
310 if(DLQuitPlease())
311 takedown(1); // needs a parameter..
312 setStatus("Child running on pid "+itoa(pid));
313 sleep(1);
314 }
315 }
316
317 g_guardian_lock.lock();
318 close(g_fd1[1]);
319 fclose(g_fp);
320 g_fp=0;
321
322 if(WIFEXITED(status)) {
323 int ret=WEXITSTATUS(status);
324
325 if(ret==99) {
326 g_log<<Logger::Error<<"Child requested a stop, exiting"<<endl;
327 exit(1);
328 }
329 setStatus("Child died with code "+itoa(ret));
330 g_log<<Logger::Error<<"Our pdns instance exited with code "<<ret<<", respawning"<<endl;
331
332 sleep(1);
333 continue;
334 }
335 if(WIFSIGNALED(status)) {
336 int sig=WTERMSIG(status);
337 setStatus("Child died because of signal "+itoa(sig));
338 g_log<<Logger::Error<<"Our pdns instance ("<<pid<<") exited after signal "<<sig<<endl;
339 #ifdef WCOREDUMP
340 if(WCOREDUMP(status))
341 g_log<<Logger::Error<<"Dumped core"<<endl;
342 #endif
343
344 g_log<<Logger::Error<<"Respawning"<<endl;
345 sleep(1);
346 continue;
347 }
348 g_log<<Logger::Error<<"No clue what happened! Respawning"<<endl;
349 }
350 else {
351 g_log<<Logger::Error<<"Unable to fork: "<<stringerror()<<endl;
352 exit(1);
353 }
354 }
355 }
356
357 #if defined(__GLIBC__) && !defined(__UCLIBC__)
358 #include <execinfo.h>
359 static void tbhandler(int num)
360 {
361 g_log<<Logger::Critical<<"Got a signal "<<num<<", attempting to print trace: "<<endl;
362 void *array[20]; //only care about last 17 functions (3 taken with tracing support)
363 size_t size;
364 char **strings;
365 size_t i;
366
367 size = backtrace (array, 20);
368 strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work
369
370 for (i = 0; i < size; i++) //skip useless functions
371 g_log<<Logger::Error<<strings[i]<<endl;
372
373
374 signal(SIGABRT, SIG_DFL);
375 abort();//hopefully will give core
376
377 }
378 #endif
379
380 //! The main function of pdns, the pdns process
381 int main(int argc, char **argv)
382 {
383 versionSetProduct(ProductAuthoritative);
384 reportAllTypes(); // init MOADNSParser
385
386 s_programname="pdns";
387 s_starttime=time(0);
388
389 #if defined(__GLIBC__) && !defined(__UCLIBC__)
390 signal(SIGSEGV,tbhandler);
391 signal(SIGFPE,tbhandler);
392 signal(SIGABRT,tbhandler);
393 signal(SIGILL,tbhandler);
394 #endif
395
396 std::ios_base::sync_with_stdio(false);
397
398 g_log.toConsole(Logger::Warning);
399 try {
400 declareArguments();
401
402 ::arg().laxParse(argc,argv); // do a lax parse
403
404 if(::arg().mustDo("version")) {
405 showProductVersion();
406 showBuildConfiguration();
407 exit(99);
408 }
409
410 if(::arg()["config-name"]!="")
411 s_programname+="-"+::arg()["config-name"];
412
413 g_log.setName(s_programname);
414
415 string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
416 cleanSlashes(configname);
417
418 if(::arg()["config"] != "default" && !::arg().mustDo("no-config")) // "config" == print a configuration file
419 ::arg().laxFile(configname.c_str());
420
421 ::arg().laxParse(argc,argv); // reparse so the commandline still wins
422 if(!::arg()["logging-facility"].empty()) {
423 int val=logFacilityToLOG(::arg().asNum("logging-facility") );
424 if(val >= 0)
425 g_log.setFacility(val);
426 else
427 g_log<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
428 }
429
430 g_log.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
431 g_log.disableSyslog(::arg().mustDo("disable-syslog"));
432 g_log.setTimestamps(::arg().mustDo("log-timestamp"));
433 g_log.toConsole((Logger::Urgency)(::arg().asNum("loglevel")));
434
435 if(::arg().mustDo("help") || ::arg().mustDo("config")) {
436 ::arg().set("daemon")="no";
437 ::arg().set("guardian")="no";
438 }
439
440 if(::arg().mustDo("guardian") && !isGuarded(argv)) {
441 if(::arg().mustDo("daemon")) {
442 g_log.toConsole(Logger::Critical);
443 daemonize();
444 }
445 guardian(argc, argv);
446 // never get here, guardian will reinvoke process
447 cerr<<"Um, we did get here!"<<endl;
448 }
449
450
451 // we really need to do work - either standalone or as an instance
452
453 #if defined(__GLIBC__) && !defined(__UCLIBC__)
454 if(!::arg().mustDo("traceback-handler")) {
455 g_log<<Logger::Warning<<"Disabling traceback handler"<<endl;
456 signal(SIGSEGV,SIG_DFL);
457 signal(SIGFPE,SIG_DFL);
458 signal(SIGABRT,SIG_DFL);
459 signal(SIGILL,SIG_DFL);
460 }
461 #endif
462
463 #ifdef HAVE_LIBSODIUM
464 if (sodium_init() == -1) {
465 cerr<<"Unable to initialize sodium crypto library"<<endl;
466 exit(99);
467 }
468 #endif
469
470 openssl_thread_setup();
471 openssl_seed();
472 /* setup rng */
473 dns_random_init();
474
475 #ifdef HAVE_LUA_RECORDS
476 MiniCurl::init();
477 #endif /* HAVE_LUA_RECORDS */
478
479 if(!::arg()["load-modules"].empty()) {
480 vector<string> modules;
481
482 stringtok(modules,::arg()["load-modules"], ", ");
483 if (!UeberBackend::loadModules(modules, ::arg()["module-dir"])) {
484 exit(1);
485 }
486 }
487
488 BackendMakers().launch(::arg()["launch"]); // vrooooom!
489
490 if(!::arg().getCommands().empty()) {
491 cerr<<"Fatal: non-option";
492 if (::arg().getCommands().size() > 1) {
493 cerr<<"s";
494 }
495 cerr<<" (";
496 bool first = true;
497 for (auto const c : ::arg().getCommands()) {
498 if (!first) {
499 cerr<<", ";
500 }
501 first = false;
502 cerr<<c;
503 }
504 cerr<<") on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl;
505 exit(99);
506 }
507
508 if(::arg().mustDo("help")) {
509 cout<<"syntax:"<<endl<<endl;
510 cout<<::arg().helpstring(::arg()["help"])<<endl;
511 exit(0);
512 }
513
514 if(::arg().mustDo("config")) {
515 string config = ::arg()["config"];
516 if (config == "default") {
517 cout<<::arg().configstring(false, true);
518 } else if (config == "diff") {
519 cout<<::arg().configstring(true, false);
520 } else if (config == "check") {
521 try {
522 if(!::arg().mustDo("no-config"))
523 ::arg().file(configname.c_str());
524 ::arg().parse(argc,argv);
525 exit(0);
526 }
527 catch(const ArgException &A) {
528 cerr<<"Fatal error: "<<A.reason<<endl;
529 exit(1);
530 }
531 } else {
532 cout<<::arg().configstring(true, true);
533 }
534 exit(0);
535 }
536
537 if(::arg().mustDo("list-modules")) {
538 auto modules = BackendMakers().getModules();
539 cout<<"Modules available:"<<endl;
540 for(const auto& m : modules)
541 cout<< m <<endl;
542
543 _exit(99);
544 }
545
546 if(!::arg().asNum("local-port")) {
547 g_log<<Logger::Error<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl;
548 exit(99); // this isn't going to fix itself either
549 }
550 if(!BackendMakers().numLauncheable()) {
551 g_log<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl;
552 exit(99); // this isn't going to fix itself either
553 }
554 if(::arg().mustDo("daemon")) {
555 g_log.toConsole(Logger::None);
556 if(!isGuarded(argv))
557 daemonize();
558 }
559
560 if(isGuarded(argv)) {
561 g_log<<Logger::Warning<<"This is a guarded instance of pdns"<<endl;
562 dl=make_unique<DynListener>(); // listens on stdin
563 }
564 else {
565 g_log<<Logger::Warning<<"This is a standalone pdns"<<endl;
566
567 if(::arg().mustDo("control-console"))
568 dl=make_unique<DynListener>();
569 else
570 dl=std::unique_ptr<DynListener>(new DynListener(s_programname));
571
572 writePid();
573 }
574 DynListener::registerFunc("SHOW",&DLShowHandler, "show a specific statistic or * to get a list", "<statistic>");
575 DynListener::registerFunc("RPING",&DLPingHandler, "ping instance");
576 DynListener::registerFunc("QUIT",&DLRQuitHandler, "quit daemon");
577 DynListener::registerFunc("UPTIME",&DLUptimeHandler, "get instance uptime");
578 DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler, "notify host for specific domain", "<domain> <host>");
579 DynListener::registerFunc("NOTIFY",&DLNotifyHandler, "queue a notification", "<domain>");
580 DynListener::registerFunc("RELOAD",&DLReloadHandler, "reload all zones");
581 DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler, "discover any new zones");
582 DynListener::registerFunc("VERSION",&DLVersionHandler, "get instance version");
583 DynListener::registerFunc("PURGE",&DLPurgeHandler, "purge entries from packet cache", "[<record>]");
584 DynListener::registerFunc("CCOUNTS",&DLCCHandler, "get cache statistics");
585 DynListener::registerFunc("QTYPES", &DLQTypesHandler, "get QType statistics");
586 DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes");
587 DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes");
588 DynListener::registerFunc("SET",&DLSettingsHandler, "set config variables", "<var> <value>");
589 DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler, "retrieve slave domain", "<domain>");
590 DynListener::registerFunc("CURRENT-CONFIG",&DLCurrentConfigHandler, "retrieve the current configuration", "[diff|default]");
591 DynListener::registerFunc("LIST-ZONES",&DLListZones, "show list of zones", "[master|slave|native]");
592 DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin, "Login to a PKCS#11 token", "<module> <slot> <pin>");
593
594 if(!::arg()["tcp-control-address"].empty()) {
595 DynListener* dlTCP=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
596 dlTCP->go();
597 }
598
599 // reparse, with error checking
600 if(!::arg().mustDo("no-config"))
601 ::arg().file(configname.c_str());
602 ::arg().parse(argc,argv);
603
604 if(::arg()["server-id"].empty()) {
605 char tmp[128];
606 if(gethostname(tmp, sizeof(tmp)-1) == 0) {
607 ::arg().set("server-id")=tmp;
608 } else {
609 g_log<<Logger::Warning<<"Unable to get the hostname, NSID and id.server values will be empty: "<<stringerror()<<endl;
610 }
611 }
612
613 UeberBackend::go();
614 N=std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception
615 g_udpReceivers.push_back(N);
616
617 size_t rthreads = ::arg().asNum("receiver-threads", 1);
618 if (rthreads > 1 && N->canReusePort()) {
619 g_udpReceivers.resize(rthreads);
620
621 for (size_t idx = 1; idx < rthreads; idx++) {
622 try {
623 g_udpReceivers[idx] = std::make_shared<UDPNameserver>(true);
624 }
625 catch(const PDNSException& e) {
626 g_log<<Logger::Error<<"Unable to reuse port, falling back to original bind"<<endl;
627 break;
628 }
629 }
630 }
631
632 TN = make_unique<TCPNameserver>();
633 }
634 catch(const ArgException &A) {
635 g_log<<Logger::Error<<"Fatal error: "<<A.reason<<endl;
636 exit(1);
637 }
638
639 declareStats();
640 S.blacklist("special-memory-usage");
641
642 DLOG(g_log<<Logger::Warning<<"Verbose logging in effect"<<endl);
643
644 showProductVersion();
645
646 try {
647 mainthread();
648 }
649 catch(PDNSException &AE) {
650 if(!::arg().mustDo("daemon"))
651 cerr<<"Exiting because: "<<AE.reason<<endl;
652 g_log<<Logger::Error<<"Exiting because: "<<AE.reason<<endl;
653 }
654 catch(std::exception &e) {
655 if(!::arg().mustDo("daemon"))
656 cerr<<"Exiting because of STL error: "<<e.what()<<endl;
657 g_log<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl;
658 }
659 catch(...) {
660 cerr<<"Uncaught exception of unknown type - sorry"<<endl;
661 }
662
663 exit(1);
664
665 }
666
667