]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/receiver.cc
Merge pull request #6653 from mind04/entsfrom-glue
[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 #ifdef __GLIBC__
365 #include <execinfo.h>
366 static void tbhandler(int num)
367 {
368 g_log<<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 g_log<<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
388 int main(int argc, char **argv)
389 {
390 versionSetProduct(ProductAuthoritative);
391 reportAllTypes(); // init MOADNSParser
392
393 s_programname="pdns";
394 s_starttime=time(0);
395
396 #ifdef __GLIBC__
397 signal(SIGSEGV,tbhandler);
398 signal(SIGFPE,tbhandler);
399 signal(SIGABRT,tbhandler);
400 signal(SIGILL,tbhandler);
401 #endif
402
403 std::ios_base::sync_with_stdio(false);
404
405 g_log.toConsole(Logger::Warning);
406 try {
407 declareArguments();
408 UNIX_declareArguments();
409
410 ::arg().laxParse(argc,argv); // do a lax parse
411
412 if(::arg().mustDo("version")) {
413 showProductVersion();
414 showBuildConfiguration();
415 exit(99);
416 }
417
418 if(::arg()["config-name"]!="")
419 s_programname+="-"+::arg()["config-name"];
420
421 g_log.setName(s_programname);
422
423 string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
424 cleanSlashes(configname);
425
426 if(!::arg().mustDo("config") && !::arg().mustDo("no-config")) // "config" == print a configuration file
427 ::arg().laxFile(configname.c_str());
428
429 ::arg().laxParse(argc,argv); // reparse so the commandline still wins
430 if(!::arg()["logging-facility"].empty()) {
431 int val=logFacilityToLOG(::arg().asNum("logging-facility") );
432 if(val >= 0)
433 g_log.setFacility(val);
434 else
435 g_log<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
436 }
437
438 g_log.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
439 g_log.disableSyslog(::arg().mustDo("disable-syslog"));
440 g_log.setTimestamps(::arg().mustDo("log-timestamp"));
441 g_log.toConsole((Logger::Urgency)(::arg().asNum("loglevel")));
442
443 if(::arg().mustDo("help") || ::arg().mustDo("config")) {
444 ::arg().set("daemon")="no";
445 ::arg().set("guardian")="no";
446 }
447
448 if(::arg().mustDo("guardian") && !isGuarded(argv)) {
449 if(::arg().mustDo("daemon")) {
450 g_log.toConsole(Logger::Critical);
451 daemonize();
452 }
453 guardian(argc, argv);
454 // never get here, guardian will reinvoke process
455 cerr<<"Um, we did get here!"<<endl;
456 }
457
458
459 // we really need to do work - either standalone or as an instance
460
461 #ifdef __GLIBC__
462 if(!::arg().mustDo("traceback-handler")) {
463 g_log<<Logger::Warning<<"Disabling traceback handler"<<endl;
464 signal(SIGSEGV,SIG_DFL);
465 signal(SIGFPE,SIG_DFL);
466 signal(SIGABRT,SIG_DFL);
467 signal(SIGILL,SIG_DFL);
468 }
469 #endif
470
471 #ifdef HAVE_LIBSODIUM
472 if (sodium_init() == -1) {
473 cerr<<"Unable to initialize sodium crypto library"<<endl;
474 exit(99);
475 }
476 #endif
477
478 openssl_thread_setup();
479 openssl_seed();
480 /* setup rng */
481 dns_random_init();
482
483 if(!::arg()["load-modules"].empty()) {
484 vector<string> modules;
485
486 stringtok(modules,::arg()["load-modules"], ", ");
487 if (!UeberBackend::loadModules(modules, ::arg()["module-dir"])) {
488 exit(1);
489 }
490 }
491
492 BackendMakers().launch(::arg()["launch"]); // vrooooom!
493
494 if(!::arg().getCommands().empty()) {
495 cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl;
496 exit(99);
497 }
498
499 if(::arg().mustDo("help")) {
500 cout<<"syntax:"<<endl<<endl;
501 cout<<::arg().helpstring(::arg()["help"])<<endl;
502 exit(0);
503 }
504
505 if(::arg().mustDo("config")) {
506 cout<<::arg().configstring()<<endl;
507 exit(0);
508 }
509
510 if(::arg().mustDo("list-modules")) {
511 auto modules = BackendMakers().getModules();
512 cout<<"Modules available:"<<endl;
513 for(const auto& m : modules)
514 cout<< m <<endl;
515
516 _exit(99);
517 }
518
519 if(!::arg().asNum("local-port")) {
520 g_log<<Logger::Error<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl;
521 exit(99); // this isn't going to fix itself either
522 }
523 if(!BackendMakers().numLauncheable()) {
524 g_log<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl;
525 exit(99); // this isn't going to fix itself either
526 }
527 if(::arg().mustDo("daemon")) {
528 g_log.toConsole(Logger::None);
529 if(!isGuarded(argv))
530 daemonize();
531 }
532
533 if(isGuarded(argv)) {
534 g_log<<Logger::Warning<<"This is a guarded instance of pdns"<<endl;
535 dl=new DynListener; // listens on stdin
536 }
537 else {
538 g_log<<Logger::Warning<<"This is a standalone pdns"<<endl;
539
540 if(::arg().mustDo("control-console"))
541 dl=new DynListener();
542 else
543 dl=new DynListener(s_programname);
544
545 writePid();
546 }
547 DynListener::registerFunc("SHOW",&DLShowHandler, "show a specific statistic or * to get a list", "<statistic>");
548 DynListener::registerFunc("RPING",&DLPingHandler, "ping instance");
549 DynListener::registerFunc("QUIT",&DLRQuitHandler, "quit daemon");
550 DynListener::registerFunc("UPTIME",&DLUptimeHandler, "get instance uptime");
551 DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler, "notify host for specific domain", "<domain> <host>");
552 DynListener::registerFunc("NOTIFY",&DLNotifyHandler, "queue a notification", "<domain>");
553 DynListener::registerFunc("RELOAD",&DLReloadHandler, "reload all zones");
554 DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler, "discover any new zones");
555 DynListener::registerFunc("VERSION",&DLVersionHandler, "get instance version");
556 DynListener::registerFunc("PURGE",&DLPurgeHandler, "purge entries from packet cache", "[<record>]");
557 DynListener::registerFunc("CCOUNTS",&DLCCHandler, "get cache statistics");
558 DynListener::registerFunc("QTYPES", &DLQTypesHandler, "get QType statistics");
559 DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes");
560 DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes");
561 DynListener::registerFunc("SET",&DLSettingsHandler, "set config variables", "<var> <value>");
562 DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler, "retrieve slave domain", "<domain>");
563 DynListener::registerFunc("CURRENT-CONFIG",&DLCurrentConfigHandler, "retrieve the current configuration");
564 DynListener::registerFunc("LIST-ZONES",&DLListZones, "show list of zones", "[master|slave|native]");
565 DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin, "Login to a PKCS#11 token", "<module> <slot> <pin>");
566
567 if(!::arg()["tcp-control-address"].empty()) {
568 DynListener* dlTCP=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
569 dlTCP->go();
570 }
571
572 // reparse, with error checking
573 if(!::arg().mustDo("no-config"))
574 ::arg().file(configname.c_str());
575 ::arg().parse(argc,argv);
576
577 if(::arg()["server-id"].empty()) {
578 char tmp[128];
579 gethostname(tmp, sizeof(tmp)-1);
580 ::arg().set("server-id")=tmp;
581 }
582
583 UeberBackend::go();
584 N=std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception
585 g_udpReceivers.push_back(N);
586
587 size_t rthreads = ::arg().asNum("receiver-threads", 1);
588 if (rthreads > 1 && N->canReusePort()) {
589 g_udpReceivers.resize(rthreads);
590
591 for (size_t idx = 1; idx < rthreads; idx++) {
592 try {
593 g_udpReceivers[idx] = std::make_shared<UDPNameserver>(true);
594 }
595 catch(const PDNSException& e) {
596 g_log<<Logger::Error<<"Unable to reuse port, falling back to original bind"<<endl;
597 break;
598 }
599 }
600 }
601
602 if(!::arg().mustDo("disable-tcp"))
603 TN=new TCPNameserver;
604 }
605 catch(const ArgException &A) {
606 g_log<<Logger::Error<<"Fatal error: "<<A.reason<<endl;
607 exit(1);
608 }
609
610 declareStats();
611 DLOG(g_log<<Logger::Warning<<"Verbose logging in effect"<<endl);
612
613 showProductVersion();
614
615 try {
616 mainthread();
617 }
618 catch(PDNSException &AE) {
619 if(!::arg().mustDo("daemon"))
620 cerr<<"Exiting because: "<<AE.reason<<endl;
621 g_log<<Logger::Error<<"Exiting because: "<<AE.reason<<endl;
622 }
623 catch(std::exception &e) {
624 if(!::arg().mustDo("daemon"))
625 cerr<<"Exiting because of STL error: "<<e.what()<<endl;
626 g_log<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl;
627 }
628 catch(...) {
629 cerr<<"Uncaught exception of unknown type - sorry"<<endl;
630 }
631
632 exit(1);
633
634 }
635
636