]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/receiver.cc
Merge pull request #5842 from pieterlexis/log-timestamps
[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 time_t s_starttime;
76
77 string s_programname="pdns"; // used in packethandler.cc
78
79 const char *funnytext=
80 "*****************************************************************************\n"\
81 "Ok, you just ran pdns_server through 'strings' hoping to find funny messages.\n"\
82 "Well, you found one. \n"\
83 "Two ions are flying through their particle accelerator, says the one to the\n"
84 "other 'I think I've lost an electron!' \n"\
85 "So the other one says, 'Are you sure?'. 'YEAH! I'M POSITIVE!'\n"\
86 " the pdns crew - pdns@powerdns.com\n"
87 "*****************************************************************************\n";
88
89
90 // start (sys)logging
91
92 /** \var Logger L
93 \brief All logging is done via L, a Logger instance
94 */
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 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 L<<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 L<<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 = LOCALSTATEDIR;
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 L<<Logger::Error<<"Writing pid for "<<getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl;
153 }
154
155 int g_fd1[2], g_fd2[2];
156 FILE *g_fp;
157 pthread_mutex_t g_guardian_lock = PTHREAD_MUTEX_INITIALIZER;
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 Lock 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 pthread_mutex_lock(&g_guardian_lock);
220
221 for(;;) {
222 int pid;
223 setStatus("Launching child");
224
225 if(pipe(g_fd1)<0 || pipe(g_fd2)<0) {
226 L<<Logger::Critical<<"Unable to open pipe for coprocess: "<<strerror(errno)<<endl;
227 exit(1);
228 }
229
230 if(!(g_fp=fdopen(g_fd2[0],"r"))) {
231 L<<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 L<<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 L<<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 L<<Logger::Error<<"Unable to execvp '"<<argv[0]<<"': "<<strerror(errno)<<endl;
272 char **p=newargv;
273 while(*p)
274 L<<Logger::Error<<*p++<<endl;
275
276 exit(1);
277 }
278 L<<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 pthread_mutex_unlock(&g_guardian_lock);
296 int status;
297 cpid=pid;
298 for(;;) {
299 int ret=waitpid(pid,&status,WNOHANG);
300
301 if(ret<0) {
302 L<<Logger::Error<<"In guardian loop, waitpid returned error: "<<strerror(errno)<<endl;
303 L<<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 pthread_mutex_lock(&g_guardian_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 L<<Logger::Error<<"Child requested a stop, exiting"<<endl;
327 exit(1);
328 }
329 setStatus("Child died with code "+itoa(ret));
330 L<<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 L<<Logger::Error<<"Our pdns instance ("<<pid<<") exited after signal "<<sig<<endl;
339 #ifdef WCOREDUMP
340 if(WCOREDUMP(status))
341 L<<Logger::Error<<"Dumped core"<<endl;
342 #endif
343
344 L<<Logger::Error<<"Respawning"<<endl;
345 sleep(1);
346 continue;
347 }
348 L<<Logger::Error<<"No clue what happened! Respawning"<<endl;
349 }
350 else {
351 L<<Logger::Error<<"Unable to fork: "<<strerror(errno)<<endl;
352 exit(1);
353 }
354 }
355 }
356
357 static void UNIX_declareArguments()
358 {
359 ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=SYSCONFDIR;
360 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
361 ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR+" when unset and not chrooted" )="";
362 ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR;
363 ::arg().set("chroot","If set, chroot to this directory for more security")="";
364 ::arg().set("logging-facility","Log under a specific facility")="";
365 ::arg().set("daemon","Operate as a daemon")="no";
366 }
367
368 static void loadModules()
369 {
370 if(!::arg()["load-modules"].empty()) {
371 vector<string>modules;
372
373 stringtok(modules,::arg()["load-modules"],", ");
374
375 for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i) {
376 bool res;
377 const string &module=*i;
378
379 if(module.find(".")==string::npos)
380 res=UeberBackend::loadmodule(::arg()["module-dir"]+"/lib"+module+"backend.so");
381 else if(module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) // absolute or current path
382 res=UeberBackend::loadmodule(module);
383 else
384 res=UeberBackend::loadmodule(::arg()["module-dir"]+"/"+module);
385
386 if(res==false) {
387 L<<Logger::Error<<"Receiver unable to load module "<<module<<endl;
388 exit(1);
389 }
390 }
391 }
392 }
393
394 #ifdef __GLIBC__
395 #include <execinfo.h>
396 static void tbhandler(int num)
397 {
398 L<<Logger::Critical<<"Got a signal "<<num<<", attempting to print trace: "<<endl;
399 void *array[20]; //only care about last 17 functions (3 taken with tracing support)
400 size_t size;
401 char **strings;
402 size_t i;
403
404 size = backtrace (array, 20);
405 strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work
406
407 for (i = 0; i < size; i++) //skip useless functions
408 L<<Logger::Error<<strings[i]<<endl;
409
410
411 signal(SIGABRT, SIG_DFL);
412 abort();//hopefully will give core
413
414 }
415 #endif
416
417 //! The main function of pdns, the pdns process
418 int main(int argc, char **argv)
419 {
420 versionSetProduct(ProductAuthoritative);
421 reportAllTypes(); // init MOADNSParser
422
423 s_programname="pdns";
424 s_starttime=time(0);
425
426 #ifdef __GLIBC__
427 signal(SIGSEGV,tbhandler);
428 signal(SIGFPE,tbhandler);
429 signal(SIGABRT,tbhandler);
430 signal(SIGILL,tbhandler);
431 #endif
432
433 std::ios_base::sync_with_stdio(false);
434
435 L.toConsole(Logger::Warning);
436 try {
437 declareArguments();
438 UNIX_declareArguments();
439
440 ::arg().laxParse(argc,argv); // do a lax parse
441
442 if(::arg().mustDo("version")) {
443 showProductVersion();
444 showBuildConfiguration();
445 exit(99);
446 }
447
448 if(::arg()["config-name"]!="")
449 s_programname+="-"+::arg()["config-name"];
450
451 (void)theL(s_programname);
452
453 string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
454 cleanSlashes(configname);
455
456 if(!::arg().mustDo("config") && !::arg().mustDo("no-config")) // "config" == print a configuration file
457 ::arg().laxFile(configname.c_str());
458
459 ::arg().laxParse(argc,argv); // reparse so the commandline still wins
460 if(!::arg()["logging-facility"].empty()) {
461 int val=logFacilityToLOG(::arg().asNum("logging-facility") );
462 if(val >= 0)
463 theL().setFacility(val);
464 else
465 L<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
466 }
467
468 L.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
469 L.disableSyslog(::arg().mustDo("disable-syslog"));
470 L.setTimestamps(::arg().mustDo("log-timestamp"));
471 L.toConsole((Logger::Urgency)(::arg().asNum("loglevel")));
472
473 if(::arg().mustDo("help") || ::arg().mustDo("config")) {
474 ::arg().set("daemon")="no";
475 ::arg().set("guardian")="no";
476 }
477
478 if(::arg().mustDo("guardian") && !isGuarded(argv)) {
479 if(::arg().mustDo("daemon")) {
480 L.toConsole(Logger::Critical);
481 daemonize();
482 }
483 guardian(argc, argv);
484 // never get here, guardian will reinvoke process
485 cerr<<"Um, we did get here!"<<endl;
486 }
487
488
489 // we really need to do work - either standalone or as an instance
490
491 #ifdef __GLIBC__
492 if(!::arg().mustDo("traceback-handler")) {
493 L<<Logger::Warning<<"Disabling traceback handler"<<endl;
494 signal(SIGSEGV,SIG_DFL);
495 signal(SIGFPE,SIG_DFL);
496 signal(SIGABRT,SIG_DFL);
497 signal(SIGILL,SIG_DFL);
498 }
499 #endif
500
501 seedRandom(::arg()["entropy-source"]);
502
503 #ifdef HAVE_LIBSODIUM
504 if (sodium_init() == -1) {
505 cerr<<"Unable to initialize sodium crypto library"<<endl;
506 exit(99);
507 }
508 #endif
509
510 openssl_thread_setup();
511 openssl_seed();
512
513 loadModules();
514 BackendMakers().launch(::arg()["launch"]); // vrooooom!
515
516 if(!::arg().getCommands().empty()) {
517 cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl;
518 exit(99);
519 }
520
521 if(::arg().mustDo("help")) {
522 cout<<"syntax:"<<endl<<endl;
523 cout<<::arg().helpstring(::arg()["help"])<<endl;
524 exit(0);
525 }
526
527 if(::arg().mustDo("config")) {
528 cout<<::arg().configstring()<<endl;
529 exit(0);
530 }
531
532 if(::arg().mustDo("list-modules")) {
533 auto modules = BackendMakers().getModules();
534 cout<<"Modules available:"<<endl;
535 for(const auto& m : modules)
536 cout<< m <<endl;
537
538 _exit(99);
539 }
540
541 if(!::arg().asNum("local-port")) {
542 L<<Logger::Error<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl;
543 exit(99); // this isn't going to fix itself either
544 }
545 if(!BackendMakers().numLauncheable()) {
546 L<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl;
547 exit(99); // this isn't going to fix itself either
548 }
549 if(::arg().mustDo("daemon")) {
550 L.toConsole(Logger::None);
551 if(!isGuarded(argv))
552 daemonize();
553 }
554
555 if(isGuarded(argv)) {
556 L<<Logger::Warning<<"This is a guarded instance of pdns"<<endl;
557 dl=new DynListener; // listens on stdin
558 }
559 else {
560 L<<Logger::Warning<<"This is a standalone pdns"<<endl;
561
562 if(::arg().mustDo("control-console"))
563 dl=new DynListener();
564 else
565 dl=new DynListener(s_programname);
566
567 writePid();
568 }
569 DynListener::registerFunc("SHOW",&DLShowHandler, "show a specific statistic or * to get a list", "<statistic>");
570 DynListener::registerFunc("RPING",&DLPingHandler, "ping instance");
571 DynListener::registerFunc("QUIT",&DLRQuitHandler, "quit daemon");
572 DynListener::registerFunc("UPTIME",&DLUptimeHandler, "get instance uptime");
573 DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler, "notify host for specific domain", "<domain> <host>");
574 DynListener::registerFunc("NOTIFY",&DLNotifyHandler, "queue a notification", "<domain>");
575 DynListener::registerFunc("RELOAD",&DLReloadHandler, "reload all zones");
576 DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler, "discover any new zones");
577 DynListener::registerFunc("VERSION",&DLVersionHandler, "get instance version");
578 DynListener::registerFunc("PURGE",&DLPurgeHandler, "purge entries from packet cache", "[<record>]");
579 DynListener::registerFunc("CCOUNTS",&DLCCHandler, "get cache statistics");
580 DynListener::registerFunc("QTYPES", &DLQTypesHandler, "get QType statistics");
581 DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes");
582 DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes");
583 DynListener::registerFunc("SET",&DLSettingsHandler, "set config variables", "<var> <value>");
584 DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler, "retrieve slave domain", "<domain>");
585 DynListener::registerFunc("CURRENT-CONFIG",&DLCurrentConfigHandler, "retrieve the current configuration");
586 DynListener::registerFunc("LIST-ZONES",&DLListZones, "show list of zones", "[master|slave|native]");
587 DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin, "Login to a PKCS#11 token", "<module> <slot> <pin>");
588
589 if(!::arg()["tcp-control-address"].empty()) {
590 DynListener* dlTCP=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
591 dlTCP->go();
592 }
593
594 // reparse, with error checking
595 if(!::arg().mustDo("no-config"))
596 ::arg().file(configname.c_str());
597 ::arg().parse(argc,argv);
598
599 if(::arg()["server-id"].empty()) {
600 char tmp[128];
601 gethostname(tmp, sizeof(tmp)-1);
602 ::arg().set("server-id")=tmp;
603 }
604
605 UeberBackend::go();
606 N=std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception
607 g_udpReceivers.push_back(N);
608
609 size_t rthreads = ::arg().asNum("receiver-threads", 1);
610 if (rthreads > 1 && N->canReusePort()) {
611 g_udpReceivers.resize(rthreads);
612
613 for (size_t idx = 1; idx < rthreads; idx++) {
614 try {
615 g_udpReceivers[idx] = std::make_shared<UDPNameserver>(true);
616 }
617 catch(const PDNSException& e) {
618 L<<Logger::Error<<"Unable to reuse port, falling back to original bind"<<endl;
619 break;
620 }
621 }
622 }
623
624 if(!::arg().mustDo("disable-tcp"))
625 TN=new TCPNameserver;
626 }
627 catch(const ArgException &A) {
628 L<<Logger::Error<<"Fatal error: "<<A.reason<<endl;
629 exit(1);
630 }
631
632 declareStats();
633 DLOG(L<<Logger::Warning<<"Verbose logging in effect"<<endl);
634
635 showProductVersion();
636
637 try {
638 mainthread();
639 }
640 catch(PDNSException &AE) {
641 if(!::arg().mustDo("daemon"))
642 cerr<<"Exiting because: "<<AE.reason<<endl;
643 L<<Logger::Error<<"Exiting because: "<<AE.reason<<endl;
644 }
645 catch(std::exception &e) {
646 if(!::arg().mustDo("daemon"))
647 cerr<<"Exiting because of STL error: "<<e.what()<<endl;
648 L<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl;
649 }
650 catch(...) {
651 cerr<<"Uncaught exception of unknown type - sorry"<<endl;
652 }
653
654 exit(1);
655
656 }
657
658