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