]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/receiver.cc
Merge pull request #6472 from setharnold/patch-5
[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
93 /**
94 \file receiver.cc
95 \brief The main loop of powerdns
96
97 This file is where it all happens - main is here, as are the two pivotal threads qthread() and athread()
98 */
99
100 void daemonize(void)
101 {
102 if(fork())
103 exit(0); // bye bye
104
105 setsid();
106
107 int i=open("/dev/null",O_RDWR); /* open stdin */
108 if(i < 0)
109 g_log<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
110 else {
111 dup2(i,0); /* stdin */
112 dup2(i,1); /* stderr */
113 dup2(i,2); /* stderr */
114 close(i);
115 }
116 }
117
118 static int cpid;
119 static void takedown(int i)
120 {
121 if(cpid) {
122 g_log<<Logger::Error<<"Guardian is killed, taking down children with us"<<endl;
123 kill(cpid,SIGKILL);
124 exit(0);
125 }
126 }
127
128 static void writePid(void)
129 {
130 if(!::arg().mustDo("write-pid"))
131 return;
132
133 string fname=::arg()["socket-dir"];
134 if (::arg()["socket-dir"].empty()) {
135 if (::arg()["chroot"].empty())
136 fname = LOCALSTATEDIR;
137 else
138 fname = ::arg()["chroot"] + "/";
139 } else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) {
140 fname = ::arg()["chroot"] + ::arg()["socket-dir"];
141 }
142
143 fname += + "/" + s_programname + ".pid";
144 ofstream of(fname.c_str());
145 if(of)
146 of<<getpid()<<endl;
147 else
148 g_log<<Logger::Error<<"Writing pid for "<<getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl;
149 }
150
151 int g_fd1[2], g_fd2[2];
152 FILE *g_fp;
153 pthread_mutex_t g_guardian_lock = PTHREAD_MUTEX_INITIALIZER;
154
155 // The next two methods are not in dynhandler.cc because they use a few items declared in this file.
156 static string DLCycleHandler(const vector<string>&parts, pid_t ppid)
157 {
158 kill(cpid, SIGKILL); // why?
159 kill(cpid, SIGKILL); // why?
160 sleep(1);
161 return "ok";
162 }
163
164 static string DLRestHandler(const vector<string>&parts, pid_t ppid)
165 {
166 string line;
167
168 for(vector<string>::const_iterator i=parts.begin();i!=parts.end();++i) {
169 if(i!=parts.begin())
170 line.append(1,' ');
171 line.append(*i);
172 }
173 line.append(1,'\n');
174
175 Lock l(&g_guardian_lock);
176
177 try {
178 writen2(g_fd1[1],line.c_str(),line.size()+1);
179 }
180 catch(PDNSException &ae) {
181 return "Error communicating with instance: "+ae.reason;
182 }
183 char mesg[512];
184 string response;
185 while(fgets(mesg,sizeof(mesg),g_fp)) {
186 if(*mesg=='\0')
187 break;
188 response+=mesg;
189 }
190 boost::trim_right(response);
191 return response;
192 }
193
194
195
196 static int guardian(int argc, char **argv)
197 {
198 if(isGuarded(argv))
199 return 0;
200
201 int infd=0, outfd=1;
202
203 DynListener dlg(s_programname);
204 dlg.registerFunc("QUIT",&DLQuitHandler, "quit daemon");
205 dlg.registerFunc("CYCLE",&DLCycleHandler, "restart instance");
206 dlg.registerFunc("PING",&DLPingHandler, "ping guardian");
207 dlg.registerFunc("STATUS",&DLStatusHandler, "get instance status from guardian");
208 dlg.registerRestFunc(&DLRestHandler);
209 dlg.go();
210 string progname=argv[0];
211
212 bool first=true;
213 cpid=0;
214
215 pthread_mutex_lock(&g_guardian_lock);
216
217 for(;;) {
218 int pid;
219 setStatus("Launching child");
220
221 if(pipe(g_fd1)<0 || pipe(g_fd2)<0) {
222 g_log<<Logger::Critical<<"Unable to open pipe for coprocess: "<<strerror(errno)<<endl;
223 exit(1);
224 }
225
226 if(!(g_fp=fdopen(g_fd2[0],"r"))) {
227 g_log<<Logger::Critical<<"Unable to associate a file pointer with pipe: "<<stringerror()<<endl;
228 exit(1);
229 }
230 setbuf(g_fp,0); // no buffering please, confuses select
231
232 if(!(pid=fork())) { // child
233 signal(SIGTERM, SIG_DFL);
234
235 signal(SIGHUP, SIG_DFL);
236 signal(SIGUSR1, SIG_DFL);
237 signal(SIGUSR2, SIG_DFL);
238
239 char **const newargv=new char*[argc+2];
240 int n;
241
242 if(::arg()["config-name"]!="") {
243 progname+="-"+::arg()["config-name"];
244 g_log<<Logger::Error<<"Virtual configuration name: "<<::arg()["config-name"]<<endl;
245 }
246
247 newargv[0]=strdup(const_cast<char *>((progname+"-instance").c_str()));
248 for(n=1;n<argc;n++) {
249 newargv[n]=argv[n];
250 }
251 newargv[n]=0;
252
253 g_log<<Logger::Error<<"Guardian is launching an instance"<<endl;
254 close(g_fd1[1]);
255 fclose(g_fp); // this closes g_fd2[0] for us
256
257 if(g_fd1[0]!= infd) {
258 dup2(g_fd1[0], infd);
259 close(g_fd1[0]);
260 }
261
262 if(g_fd2[1]!= outfd) {
263 dup2(g_fd2[1], outfd);
264 close(g_fd2[1]);
265 }
266 if(execvp(argv[0], newargv)<0) {
267 g_log<<Logger::Error<<"Unable to execvp '"<<argv[0]<<"': "<<strerror(errno)<<endl;
268 char **p=newargv;
269 while(*p)
270 g_log<<Logger::Error<<*p++<<endl;
271
272 exit(1);
273 }
274 g_log<<Logger::Error<<"execvp returned!!"<<endl;
275 // never reached
276 }
277 else if(pid>0) { // parent
278 close(g_fd1[0]);
279 close(g_fd2[1]);
280
281 if(first) {
282 first=false;
283 signal(SIGTERM, takedown);
284
285 signal(SIGHUP, SIG_IGN);
286 signal(SIGUSR1, SIG_IGN);
287 signal(SIGUSR2, SIG_IGN);
288
289 writePid();
290 }
291 pthread_mutex_unlock(&g_guardian_lock);
292 int status;
293 cpid=pid;
294 for(;;) {
295 int ret=waitpid(pid,&status,WNOHANG);
296
297 if(ret<0) {
298 g_log<<Logger::Error<<"In guardian loop, waitpid returned error: "<<strerror(errno)<<endl;
299 g_log<<Logger::Error<<"Dying"<<endl;
300 exit(1);
301 }
302 else if(ret) // something exited
303 break;
304 else { // child is alive
305 // execute some kind of ping here
306 if(DLQuitPlease())
307 takedown(1); // needs a parameter..
308 setStatus("Child running on pid "+itoa(pid));
309 sleep(1);
310 }
311 }
312
313 pthread_mutex_lock(&g_guardian_lock);
314 close(g_fd1[1]);
315 fclose(g_fp);
316 g_fp=0;
317
318 if(WIFEXITED(status)) {
319 int ret=WEXITSTATUS(status);
320
321 if(ret==99) {
322 g_log<<Logger::Error<<"Child requested a stop, exiting"<<endl;
323 exit(1);
324 }
325 setStatus("Child died with code "+itoa(ret));
326 g_log<<Logger::Error<<"Our pdns instance exited with code "<<ret<<", respawning"<<endl;
327
328 sleep(1);
329 continue;
330 }
331 if(WIFSIGNALED(status)) {
332 int sig=WTERMSIG(status);
333 setStatus("Child died because of signal "+itoa(sig));
334 g_log<<Logger::Error<<"Our pdns instance ("<<pid<<") exited after signal "<<sig<<endl;
335 #ifdef WCOREDUMP
336 if(WCOREDUMP(status))
337 g_log<<Logger::Error<<"Dumped core"<<endl;
338 #endif
339
340 g_log<<Logger::Error<<"Respawning"<<endl;
341 sleep(1);
342 continue;
343 }
344 g_log<<Logger::Error<<"No clue what happened! Respawning"<<endl;
345 }
346 else {
347 g_log<<Logger::Error<<"Unable to fork: "<<strerror(errno)<<endl;
348 exit(1);
349 }
350 }
351 }
352
353 static void UNIX_declareArguments()
354 {
355 ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=SYSCONFDIR;
356 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
357 ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR+" when unset and not chrooted" )="";
358 ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR;
359 ::arg().set("chroot","If set, chroot to this directory for more security")="";
360 ::arg().set("logging-facility","Log under a specific facility")="";
361 ::arg().set("daemon","Operate as a daemon")="no";
362 }
363
364 static void loadModules()
365 {
366 if(!::arg()["load-modules"].empty()) {
367 vector<string>modules;
368
369 stringtok(modules,::arg()["load-modules"],", ");
370
371 for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i) {
372 bool res;
373 const string &module=*i;
374
375 if(module.find(".")==string::npos)
376 res=UeberBackend::loadmodule(::arg()["module-dir"]+"/lib"+module+"backend.so");
377 else if(module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) // absolute or current path
378 res=UeberBackend::loadmodule(module);
379 else
380 res=UeberBackend::loadmodule(::arg()["module-dir"]+"/"+module);
381
382 if(res==false) {
383 g_log<<Logger::Error<<"Receiver unable to load module "<<module<<endl;
384 exit(1);
385 }
386 }
387 }
388 }
389
390 #ifdef __GLIBC__
391 #include <execinfo.h>
392 static void tbhandler(int num)
393 {
394 g_log<<Logger::Critical<<"Got a signal "<<num<<", attempting to print trace: "<<endl;
395 void *array[20]; //only care about last 17 functions (3 taken with tracing support)
396 size_t size;
397 char **strings;
398 size_t i;
399
400 size = backtrace (array, 20);
401 strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work
402
403 for (i = 0; i < size; i++) //skip useless functions
404 g_log<<Logger::Error<<strings[i]<<endl;
405
406
407 signal(SIGABRT, SIG_DFL);
408 abort();//hopefully will give core
409
410 }
411 #endif
412
413 //! The main function of pdns, the pdns process
414 int main(int argc, char **argv)
415 {
416 versionSetProduct(ProductAuthoritative);
417 reportAllTypes(); // init MOADNSParser
418
419 s_programname="pdns";
420 s_starttime=time(0);
421
422 #ifdef __GLIBC__
423 signal(SIGSEGV,tbhandler);
424 signal(SIGFPE,tbhandler);
425 signal(SIGABRT,tbhandler);
426 signal(SIGILL,tbhandler);
427 #endif
428
429 std::ios_base::sync_with_stdio(false);
430
431 g_log.toConsole(Logger::Warning);
432 try {
433 declareArguments();
434 UNIX_declareArguments();
435
436 ::arg().laxParse(argc,argv); // do a lax parse
437
438 if(::arg().mustDo("version")) {
439 showProductVersion();
440 showBuildConfiguration();
441 exit(99);
442 }
443
444 if(::arg()["config-name"]!="")
445 s_programname+="-"+::arg()["config-name"];
446
447 g_log.setName(s_programname);
448
449 string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
450 cleanSlashes(configname);
451
452 if(!::arg().mustDo("config") && !::arg().mustDo("no-config")) // "config" == print a configuration file
453 ::arg().laxFile(configname.c_str());
454
455 ::arg().laxParse(argc,argv); // reparse so the commandline still wins
456 if(!::arg()["logging-facility"].empty()) {
457 int val=logFacilityToLOG(::arg().asNum("logging-facility") );
458 if(val >= 0)
459 g_log.setFacility(val);
460 else
461 g_log<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
462 }
463
464 g_log.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
465 g_log.disableSyslog(::arg().mustDo("disable-syslog"));
466 g_log.setTimestamps(::arg().mustDo("log-timestamp"));
467 g_log.toConsole((Logger::Urgency)(::arg().asNum("loglevel")));
468
469 if(::arg().mustDo("help") || ::arg().mustDo("config")) {
470 ::arg().set("daemon")="no";
471 ::arg().set("guardian")="no";
472 }
473
474 if(::arg().mustDo("guardian") && !isGuarded(argv)) {
475 if(::arg().mustDo("daemon")) {
476 g_log.toConsole(Logger::Critical);
477 daemonize();
478 }
479 guardian(argc, argv);
480 // never get here, guardian will reinvoke process
481 cerr<<"Um, we did get here!"<<endl;
482 }
483
484
485 // we really need to do work - either standalone or as an instance
486
487 #ifdef __GLIBC__
488 if(!::arg().mustDo("traceback-handler")) {
489 g_log<<Logger::Warning<<"Disabling traceback handler"<<endl;
490 signal(SIGSEGV,SIG_DFL);
491 signal(SIGFPE,SIG_DFL);
492 signal(SIGABRT,SIG_DFL);
493 signal(SIGILL,SIG_DFL);
494 }
495 #endif
496
497 #ifdef HAVE_LIBSODIUM
498 if (sodium_init() == -1) {
499 cerr<<"Unable to initialize sodium crypto library"<<endl;
500 exit(99);
501 }
502 #endif
503
504 openssl_thread_setup();
505 openssl_seed();
506 /* setup rng */
507 dns_random_init();
508
509 loadModules();
510 BackendMakers().launch(::arg()["launch"]); // vrooooom!
511
512 if(!::arg().getCommands().empty()) {
513 cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl;
514 exit(99);
515 }
516
517 if(::arg().mustDo("help")) {
518 cout<<"syntax:"<<endl<<endl;
519 cout<<::arg().helpstring(::arg()["help"])<<endl;
520 exit(0);
521 }
522
523 if(::arg().mustDo("config")) {
524 cout<<::arg().configstring()<<endl;
525 exit(0);
526 }
527
528 if(::arg().mustDo("list-modules")) {
529 auto modules = BackendMakers().getModules();
530 cout<<"Modules available:"<<endl;
531 for(const auto& m : modules)
532 cout<< m <<endl;
533
534 _exit(99);
535 }
536
537 if(!::arg().asNum("local-port")) {
538 g_log<<Logger::Error<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl;
539 exit(99); // this isn't going to fix itself either
540 }
541 if(!BackendMakers().numLauncheable()) {
542 g_log<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl;
543 exit(99); // this isn't going to fix itself either
544 }
545 if(::arg().mustDo("daemon")) {
546 g_log.toConsole(Logger::None);
547 if(!isGuarded(argv))
548 daemonize();
549 }
550
551 if(isGuarded(argv)) {
552 g_log<<Logger::Warning<<"This is a guarded instance of pdns"<<endl;
553 dl=new DynListener; // listens on stdin
554 }
555 else {
556 g_log<<Logger::Warning<<"This is a standalone pdns"<<endl;
557
558 if(::arg().mustDo("control-console"))
559 dl=new DynListener();
560 else
561 dl=new DynListener(s_programname);
562
563 writePid();
564 }
565 DynListener::registerFunc("SHOW",&DLShowHandler, "show a specific statistic or * to get a list", "<statistic>");
566 DynListener::registerFunc("RPING",&DLPingHandler, "ping instance");
567 DynListener::registerFunc("QUIT",&DLRQuitHandler, "quit daemon");
568 DynListener::registerFunc("UPTIME",&DLUptimeHandler, "get instance uptime");
569 DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler, "notify host for specific domain", "<domain> <host>");
570 DynListener::registerFunc("NOTIFY",&DLNotifyHandler, "queue a notification", "<domain>");
571 DynListener::registerFunc("RELOAD",&DLReloadHandler, "reload all zones");
572 DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler, "discover any new zones");
573 DynListener::registerFunc("VERSION",&DLVersionHandler, "get instance version");
574 DynListener::registerFunc("PURGE",&DLPurgeHandler, "purge entries from packet cache", "[<record>]");
575 DynListener::registerFunc("CCOUNTS",&DLCCHandler, "get cache statistics");
576 DynListener::registerFunc("QTYPES", &DLQTypesHandler, "get QType statistics");
577 DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes");
578 DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes");
579 DynListener::registerFunc("SET",&DLSettingsHandler, "set config variables", "<var> <value>");
580 DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler, "retrieve slave domain", "<domain>");
581 DynListener::registerFunc("CURRENT-CONFIG",&DLCurrentConfigHandler, "retrieve the current configuration");
582 DynListener::registerFunc("LIST-ZONES",&DLListZones, "show list of zones", "[master|slave|native]");
583 DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin, "Login to a PKCS#11 token", "<module> <slot> <pin>");
584
585 if(!::arg()["tcp-control-address"].empty()) {
586 DynListener* dlTCP=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
587 dlTCP->go();
588 }
589
590 // reparse, with error checking
591 if(!::arg().mustDo("no-config"))
592 ::arg().file(configname.c_str());
593 ::arg().parse(argc,argv);
594
595 if(::arg()["server-id"].empty()) {
596 char tmp[128];
597 gethostname(tmp, sizeof(tmp)-1);
598 ::arg().set("server-id")=tmp;
599 }
600
601 UeberBackend::go();
602 N=std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception
603 g_udpReceivers.push_back(N);
604
605 size_t rthreads = ::arg().asNum("receiver-threads", 1);
606 if (rthreads > 1 && N->canReusePort()) {
607 g_udpReceivers.resize(rthreads);
608
609 for (size_t idx = 1; idx < rthreads; idx++) {
610 try {
611 g_udpReceivers[idx] = std::make_shared<UDPNameserver>(true);
612 }
613 catch(const PDNSException& e) {
614 g_log<<Logger::Error<<"Unable to reuse port, falling back to original bind"<<endl;
615 break;
616 }
617 }
618 }
619
620 if(!::arg().mustDo("disable-tcp"))
621 TN=new TCPNameserver;
622 }
623 catch(const ArgException &A) {
624 g_log<<Logger::Error<<"Fatal error: "<<A.reason<<endl;
625 exit(1);
626 }
627
628 declareStats();
629 DLOG(g_log<<Logger::Warning<<"Verbose logging in effect"<<endl);
630
631 showProductVersion();
632
633 try {
634 mainthread();
635 }
636 catch(PDNSException &AE) {
637 if(!::arg().mustDo("daemon"))
638 cerr<<"Exiting because: "<<AE.reason<<endl;
639 g_log<<Logger::Error<<"Exiting because: "<<AE.reason<<endl;
640 }
641 catch(std::exception &e) {
642 if(!::arg().mustDo("daemon"))
643 cerr<<"Exiting because of STL error: "<<e.what()<<endl;
644 g_log<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl;
645 }
646 catch(...) {
647 cerr<<"Uncaught exception of unknown type - sorry"<<endl;
648 }
649
650 exit(1);
651
652 }
653
654