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