]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/receiver.cc
fix for guardian crashing or possibly blocking in case of a badly timed crash of...
[thirdparty/pdns.git] / pdns / receiver.cc
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
e8d78143 3 Copyright (C) 2002 - 2008 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
22dc646a
BH
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
ea44d9d3 8
12c86877
BH
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
06bd9ccf 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 18*/
e8d78143 19#include "packetcache.hh"
da44c9ea 20
12c86877
BH
21#include <cstdio>
22#include <signal.h>
23#include <cstring>
24#include <cstdlib>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <iostream>
30#include <string>
31#include <sys/stat.h>
32#include <unistd.h>
33#include <sys/time.h>
34#include <sys/types.h>
35#include <sys/wait.h>
36#include <errno.h>
37#include <pthread.h>
38#include <unistd.h>
39#include <sys/mman.h>
40#include <fcntl.h>
41#include <fstream>
040712e0 42#include <boost/algorithm/string.hpp>
12c86877
BH
43
44#include "config.h"
45#include "dns.hh"
46#include "dnsbackend.hh"
47#include "ueberbackend.hh"
48#include "dnspacket.hh"
49#include "nameserver.hh"
50#include "distributor.hh"
51#include "logger.hh"
52#include "arguments.hh"
53#include "packethandler.hh"
54#include "statbag.hh"
55#include "tcpreceiver.hh"
12c86877
BH
56#include "ws.hh"
57#include "misc.hh"
58#include "dynlistener.hh"
59#include "dynhandler.hh"
60#include "communicator.hh"
61#include "dnsproxy.hh"
731f58b8 62#include "utility.hh"
12c86877 63#include "common_startup.hh"
02116dff 64#include "dnsrecords.hh"
12c86877 65
040712e0 66
12c86877
BH
67time_t s_starttime;
68
69string s_programname="pdns"; // used in packethandler.cc
70
c4ac5865 71const char *funnytext=
12c86877
BH
72"*****************************************************************************\n"\
73"Ok, you just ran pdns_server through 'strings' hoping to find funny messages.\n"\
74"Well, you found one. \n"\
75"Two ions are flying through their particle accelerator, says the one to the\n"
76"other 'I think I've lost an electron!' \n"\
77"So the other one says, 'Are you sure?'. 'YEAH! I'M POSITIVE!'\n"\
78" the pdns crew - pdns@powerdns.com\n"
79"*****************************************************************************\n";
80
81
82// start (sys)logging
83
84/** \var Logger L
85\brief All logging is done via L, a Logger instance
86*/
87
88
89/**
90\file receiver.cc
91\brief The main loop of powerdns
92
93This file is where it all happens - main is here, as are the two pivotal threads qthread() and athread()
94*/
95
96void daemonize(void)
97{
98 if(fork())
99 exit(0); // bye bye
100
101 setsid();
102
dd8b6bd1 103 int i=open("/dev/null",O_RDWR); /* open stdin */
11a2091b
BH
104 if(i < 0)
105 L<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
106 else {
107 dup2(i,0); /* stdin */
108 dup2(i,1); /* stderr */
109 dup2(i,2); /* stderr */
110 close(i);
111 }
12c86877
BH
112}
113
12c86877 114static int cpid;
12c86877
BH
115static void takedown(int i)
116{
117 if(cpid) {
118 L<<Logger::Error<<"Guardian is killed, taking down children with us"<<endl;
119 kill(cpid,SIGKILL);
120 exit(1);
121 }
122}
123
124static void writePid(void)
125{
e8d78143 126 string fname=::arg()["socket-dir"]+"/"+s_programname+".pid";
12c86877
BH
127 ofstream of(fname.c_str());
128 if(of)
129 of<<getpid()<<endl;
130 else
131 L<<Logger::Error<<"Requested to write pid for "<<getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl;
132}
133
aced0e6c
BH
134int g_fd1[2], g_fd2[2];
135FILE *g_fp;
136pthread_mutex_t g_guardian_lock = PTHREAD_MUTEX_INITIALIZER;
12c86877
BH
137
138static string DLRestHandler(const vector<string>&parts, pid_t ppid)
139{
140 string line;
141
142 for(vector<string>::const_iterator i=parts.begin();i!=parts.end();++i) {
143 if(i!=parts.begin())
144 line.append(1,' ');
145 line.append(*i);
146 }
147 line.append(1,'\n');
148
aced0e6c
BH
149 Lock l(&g_guardian_lock);
150
151 try {
152 writen2(g_fd1[1],line.c_str(),line.size()+1);
153 }
154 catch(AhuException &ae) {
155 return "Error communicating with instance: "+ae.reason;
156 }
12c86877 157 char mesg[512];
20ca8e7d 158 string response;
aced0e6c 159 while(fgets(mesg,sizeof(mesg),g_fp)) {
20ca8e7d
BH
160 if(*mesg=='\n')
161 break;
162 response+=mesg;
163 }
040712e0 164 boost::trim_right(response);
20ca8e7d 165 return response;
12c86877
BH
166}
167
168static string DLCycleHandler(const vector<string>&parts, pid_t ppid)
169{
aced0e6c
BH
170 kill(cpid, SIGKILL); // why?
171 kill(cpid, SIGKILL); // why?
88def049 172 sleep(1);
12c86877
BH
173 return "ok";
174}
175
176static int guardian(int argc, char **argv)
177{
178 if(isGuarded(argv))
179 return 0;
180
181 int infd=0, outfd=1;
182
183 DynListener dlg(s_programname);
184 dlg.registerFunc("QUIT",&DLQuitHandler);
185 dlg.registerFunc("CYCLE",&DLCycleHandler);
186 dlg.registerFunc("PING",&DLPingHandler);
187 dlg.registerFunc("STATUS",&DLStatusHandler);
188 dlg.registerRestFunc(&DLRestHandler);
189 dlg.go();
190 string progname=argv[0];
191
192 bool first=true;
193 cpid=0;
194
aced0e6c
BH
195 pthread_mutex_lock(&g_guardian_lock);
196
12c86877
BH
197 for(;;) {
198 int pid;
199 setStatus("Launching child");
aced0e6c
BH
200
201 if(pipe(g_fd1)<0 || pipe(g_fd2)<0) {
12c86877
BH
202 L<<Logger::Critical<<"Unable to open pipe for coprocess: "<<strerror(errno)<<endl;
203 exit(1);
204 }
205
aced0e6c
BH
206 if(!(g_fp=fdopen(g_fd2[0],"r"))) {
207 L<<Logger::Critical<<"Unable to associate a file pointer with pipe: "<<stringerror()<<endl;
208 exit(1);
209 }
210 setbuf(g_fp,0); // no buffering please, confuses select
211
12c86877
BH
212 if(!(pid=fork())) { // child
213 signal(SIGTERM, SIG_DFL);
214
215 signal(SIGHUP, SIG_DFL);
216 signal(SIGUSR1, SIG_DFL);
217 signal(SIGUSR2, SIG_DFL);
218
219 char **const newargv=new char*[argc+2];
220 int n;
221
e8d78143
BH
222 if(::arg()["config-name"]!="") {
223 progname+="-"+::arg()["config-name"];
224 L<<Logger::Error<<"Virtual configuration name: "<<::arg()["config-name"]<<endl;
12c86877
BH
225 }
226
227 newargv[0]=strdup(const_cast<char *>((progname+"-instance").c_str()));
228 for(n=1;n<argc;n++) {
229 newargv[n]=argv[n];
230 }
231 newargv[n]=0;
232
233 L<<Logger::Error<<"Guardian is launching an instance"<<endl;
aced0e6c
BH
234 close(g_fd1[1]);
235 fclose(g_fp); // this closes g_fd2[0] for us
12c86877 236
aced0e6c
BH
237 if(g_fd1[0]!= infd) {
238 dup2(g_fd1[0], infd);
239 close(g_fd1[0]);
12c86877
BH
240 }
241
aced0e6c
BH
242 if(g_fd2[1]!= outfd) {
243 dup2(g_fd2[1], outfd);
244 close(g_fd2[1]);
12c86877 245 }
c1663439
BH
246 if(execvp(argv[0], newargv)<0) {
247 L<<Logger::Error<<"Unable to execvp '"<<argv[0]<<"': "<<strerror(errno)<<endl;
12c86877
BH
248 char **p=newargv;
249 while(*p)
250 L<<Logger::Error<<*p++<<endl;
251
252 exit(1);
253 }
c1663439 254 L<<Logger::Error<<"execvp returned!!"<<endl;
12c86877
BH
255 // never reached
256 }
257 else if(pid>0) { // parent
aced0e6c
BH
258 close(g_fd1[0]);
259 close(g_fd2[1]);
12c86877
BH
260
261 if(first) {
262 first=false;
263 signal(SIGTERM, takedown);
264
265 signal(SIGHUP, SIG_IGN);
266 signal(SIGUSR1, SIG_IGN);
267 signal(SIGUSR2, SIG_IGN);
268
269 writePid();
270 }
aced0e6c 271 pthread_mutex_unlock(&g_guardian_lock);
12c86877
BH
272 int status;
273 cpid=pid;
274 for(;;) {
275 int ret=waitpid(pid,&status,WNOHANG);
276
277 if(ret<0) {
278 L<<Logger::Error<<"In guardian loop, waitpid returned error: "<<strerror(errno)<<endl;
279 L<<Logger::Error<<"Dying"<<endl;
280 exit(1);
281 }
282 else if(ret) // something exited
283 break;
284 else { // child is alive
285 // execute some kind of ping here
286 if(DLQuitPlease())
aced0e6c 287 takedown(1); // needs a parameter..
12c86877
BH
288 setStatus("Child running on pid "+itoa(pid));
289 sleep(1);
290 }
291 }
aced0e6c
BH
292
293 pthread_mutex_lock(&g_guardian_lock);
294 close(g_fd1[1]);
295 fclose(g_fp);
296 g_fp=0;
12c86877
BH
297
298 if(WIFEXITED(status)) {
299 int ret=WEXITSTATUS(status);
300
301 if(ret==99) {
302 L<<Logger::Error<<"Child requested a stop, exiting"<<endl;
303 exit(1);
304 }
305 setStatus("Child died with code "+itoa(ret));
306 L<<Logger::Error<<"Our pdns instance exited with code "<<ret<<endl;
307 L<<Logger::Error<<"Respawning"<<endl;
308
309 sleep(1);
310 continue;
311 }
312 if(WIFSIGNALED(status)) {
313 int sig=WTERMSIG(status);
314 setStatus("Child died because of signal "+itoa(sig));
315 L<<Logger::Error<<"Our pdns instance ("<<pid<<") exited after signal "<<sig<<endl;
316#ifdef WCOREDUMP
317 if(WCOREDUMP(status))
318 L<<Logger::Error<<"Dumped core"<<endl;
319#endif
320
321 L<<Logger::Error<<"Respawning"<<endl;
322 sleep(1);
323 continue;
324 }
325 L<<Logger::Error<<"No clue what happened! Respawning"<<endl;
326 }
327 else {
328 L<<Logger::Error<<"Unable to fork: "<<strerror(errno)<<endl;
329 exit(1);
330 }
331 }
332}
333
334static void UNIX_declareArguments()
335{
336 static char pietje[128]="!@@SYSCONFDIR@@:";
e8d78143 337 ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=
12c86877
BH
338 strcmp(pietje+1,"@@SYSCONFDIR@@:") ? pietje+strlen("@@SYSCONFDIR@@:")+1 : SYSCONFDIR;
339
e8d78143
BH
340 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
341 ::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR;
342 ::arg().set("module-dir","Default directory for modules")=LIBDIR;
343 ::arg().set("chroot","If set, chroot to this directory for more security")="";
344 ::arg().set("logging-facility","Log under a specific facility")="";
345 ::arg().set("daemon","Operate as a daemon")="no";
12c86877
BH
346
347}
348
349static void loadModules()
350{
e8d78143 351 if(!::arg()["load-modules"].empty()) {
12c86877
BH
352 vector<string>modules;
353
e8d78143 354 stringtok(modules,::arg()["load-modules"],",");
12c86877
BH
355
356 for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i) {
357 bool res;
358 const string &module=*i;
359
360 if(module.find(".")==string::npos)
e8d78143 361 res=UeberBackend::loadmodule(::arg()["module-dir"]+"/lib"+module+"backend.so");
12c86877
BH
362 else if(module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) // absolute or current path
363 res=UeberBackend::loadmodule(module);
364 else
e8d78143 365 res=UeberBackend::loadmodule(::arg()["module-dir"]+"/"+module);
12c86877
BH
366
367 if(res==false) {
731f58b8 368 L<<Logger::Error<<"receiver unable to load module "<<module<<endl;
12c86877
BH
369 exit(1);
370 }
371 }
372 }
373}
374
375
376
377#ifdef __linux__
378#include <execinfo.h>
379static void tbhandler(int num)
380{
381 L<<Logger::Critical<<"Got a signal "<<num<<", attempting to print trace: "<<endl;
382 void *array[20]; //only care about last 17 functions (3 taken with tracing support)
383 size_t size;
384 char **strings;
385 size_t i;
386
387 size = backtrace (array, 20);
388 strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work
389
390 for (i = 0; i < size; i++) //skip useless functions
391 L<<Logger::Error<<strings[i]<<endl;
392
393
394 signal(SIGABRT, SIG_DFL);
395 abort();//hopefully will give core
396
397}
398#endif
399
400//! The main function of pdns, the pdns process
401int main(int argc, char **argv)
402{
02116dff
BH
403 reportAllTypes(); // init MOADNSParser
404
12c86877
BH
405 s_programname="pdns";
406 s_starttime=time(0);
407
408#ifdef __linux__
409 signal(SIGSEGV,tbhandler);
410 signal(SIGFPE,tbhandler);
411 signal(SIGABRT,tbhandler);
412 signal(SIGILL,tbhandler);
413#endif
414
415
416 L.toConsole(Logger::Warning);
417 try {
418 declareArguments();
419 UNIX_declareArguments();
420
e8d78143 421 ::arg().laxParse(argc,argv); // do a lax parse
12c86877 422
e8d78143
BH
423 if(::arg()["config-name"]!="")
424 s_programname+="-"+::arg()["config-name"];
12c86877
BH
425
426 (void)theL(s_programname);
427
e8d78143 428 string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
12c86877
BH
429 cleanSlashes(configname);
430
e8d78143
BH
431 if(!::arg().mustDo("config") && !::arg().mustDo("no-config")) // "config" == print a configuration file
432 ::arg().laxFile(configname.c_str());
12c86877 433
e8d78143
BH
434 ::arg().laxParse(argc,argv); // reparse so the commandline still wins
435 if(!::arg()["logging-facility"].empty()) {
436 boost::optional<int> val=logFacilityToLOG(::arg().asNum("logging-facility") );
6e2514e4
BH
437 if(val)
438 theL().setFacility(*val);
439 else
e8d78143 440 L<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
12c86877
BH
441 }
442
e8d78143
BH
443 L.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
444 L.toConsole((Logger::Urgency)(::arg().asNum("loglevel")));
12c86877 445
e8d78143
BH
446 if(::arg().mustDo("help") || ::arg().mustDo("config")) {
447 ::arg().set("daemon")="no";
448 ::arg().set("guardian")="no";
12c86877
BH
449 }
450
e8d78143
BH
451 if(::arg().mustDo("guardian") && !isGuarded(argv)) {
452 if(::arg().mustDo("daemon")) {
12c86877
BH
453 L.toConsole(Logger::Critical);
454 daemonize();
455 }
456 guardian(argc, argv);
457 // never get here, guardian will reinvoke process
458 cerr<<"Um, we did get here!"<<endl;
459 }
45fdd612 460
e8d78143 461 if(::arg().mustDo("version")) {
45fdd612
BH
462 cerr<<"Version: "VERSION", compiled on "<<__DATE__", "__TIME__;
463#ifdef __GNUC__
464 cerr<<" with gcc version "<<__VERSION__;
465#endif
466 cout<<endl;
467 exit(99);
468 }
12c86877
BH
469
470 // we really need to do work - either standalone or as an instance
471
a28a204a
BH
472 seedRandom(::arg()["entropy-source"]);
473
12c86877 474 loadModules();
e8d78143 475 BackendMakers().launch(::arg()["launch"]); // vrooooom!
f4137d84 476
e8d78143 477 if(!::arg().getCommands().empty()) {
49daa3cd
BH
478 cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl;
479 exit(99);
480 }
f4137d84 481
e8d78143 482 if(::arg().mustDo("help")) {
12c86877 483 cerr<<"syntax:"<<endl<<endl;
e8d78143 484 cerr<<::arg().helpstring(::arg()["help"])<<endl;
12c86877
BH
485 exit(99);
486 }
487
e8d78143
BH
488 if(::arg().mustDo("config")) {
489 cout<<::arg().configstring()<<endl;
12c86877
BH
490 exit(99);
491 }
492
e8d78143 493 if(::arg().mustDo("list-modules")) {
12c86877
BH
494 vector<string>modules=BackendMakers().getModules();
495 cerr<<"Modules available:"<<endl;
496 for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i)
497 cout<<*i<<endl;
498
499 exit(99);
500 }
da44c9ea 501
e8d78143 502 if(!::arg().asNum("local-port")) {
da44c9ea
BH
503 L<<Logger::Error<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl;
504 exit(99); // this isn't going to fix itself either
505 }
12c86877
BH
506 if(!BackendMakers().numLauncheable()) {
507 L<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl;
da44c9ea 508 exit(99); // this isn't going to fix itself either
12c86877 509 }
e8d78143 510 if(::arg().mustDo("daemon")) {
12c86877
BH
511 L.toConsole(Logger::None);
512 if(!isGuarded(argv))
513 daemonize();
514 }
515
7f7b8d55
BH
516 if(::arg()["server-id"].empty()) {
517 char tmp[128];
518 gethostname(tmp, sizeof(tmp)-1);
519 ::arg().set("server-id")=tmp;
520 }
521
12c86877
BH
522 if(isGuarded(argv)) {
523 L<<Logger::Warning<<"This is a guarded instance of pdns"<<endl;
524 dl=new DynListener; // listens on stdin
525 }
526 else {
527 L<<Logger::Warning<<"This is a standalone pdns"<<endl;
528
e8d78143 529 if(::arg().mustDo("control-console"))
12c86877
BH
530 dl=new DynListener();
531 else
532 dl=new DynListener(s_programname);
533
534 writePid();
535 }
040712e0
BH
536 DynListener::registerFunc("SHOW",&DLShowHandler);
537 DynListener::registerFunc("RPING",&DLPingHandler);
538 DynListener::registerFunc("QUIT",&DLRQuitHandler);
539 DynListener::registerFunc("UPTIME",&DLUptimeHandler);
540 DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler);
541 DynListener::registerFunc("NOTIFY",&DLNotifyHandler);
542 DynListener::registerFunc("RELOAD",&DLReloadHandler);
543 DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler);
544 DynListener::registerFunc("VERSION",&DLVersionHandler);
545 DynListener::registerFunc("PURGE",&DLPurgeHandler);
546 DynListener::registerFunc("CCOUNTS",&DLCCHandler);
547 DynListener::registerFunc("SET",&DLSettingsHandler);
548 DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler);
549
550 if(!::arg()["tcp-control-address"].empty()) {
551 DynListener* dlTCP=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
552 dlTCP->go();
553 }
12c86877 554
12c86877 555 // reparse, with error checking
e8d78143
BH
556 if(!::arg().mustDo("no-config"))
557 ::arg().file(configname.c_str());
558 ::arg().parse(argc,argv);
12c86877
BH
559 UeberBackend::go();
560 N=new UDPNameserver; // this fails when we are not root, throws exception
561
e8d78143 562 if(!::arg().mustDo("disable-tcp"))
12c86877
BH
563 TN=new TCPNameserver;
564 }
565 catch(const ArgException &A) {
566 L<<Logger::Error<<"Fatal error: "<<A.reason<<endl;
567 exit(1);
568 }
569
570 declareStats();
571 DLOG(L<<Logger::Warning<<"Verbose logging in effect"<<endl);
572
dadeea4d 573 L<<Logger::Warning<<"PowerDNS "<<VERSION<<" (C) 2001-2008 PowerDNS.COM BV ("<<__DATE__", "__TIME__;
45fdd612
BH
574#ifdef __GNUC__
575 L<<", gcc "__VERSION__;
576#endif // add other compilers here
577 L<<") starting up"<<endl;
12c86877
BH
578
579 L<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
580 "This is free software, and you are welcome to redistribute it "
581 "according to the terms of the GPL version 2."<<endl;
582
583
584 try {
585
586 mainthread();
587 }
588 catch(AhuException &AE) {
e8d78143 589 if(!::arg().mustDo("daemon"))
12c86877
BH
590 cerr<<"Exiting because: "<<AE.reason<<endl;
591 L<<Logger::Error<<"Exiting because: "<<AE.reason<<endl;
592 }
adc10f99 593 catch(std::exception &e) {
e8d78143 594 if(!::arg().mustDo("daemon"))
12c86877
BH
595 cerr<<"Exiting because of STL error: "<<e.what()<<endl;
596 L<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl;
597 }
598 catch(...) {
599 cerr<<"Uncaught exception of unknown type - sorry"<<endl;
600 }
601
602 exit(1);
603
604}
605
606