2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
25 #include "packetcache.hh"
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
40 #include <sys/types.h>
48 #include <boost/algorithm/string.hpp>
52 #include "opensslsigners.hh"
55 #include "dnsbackend.hh"
56 #include "ueberbackend.hh"
57 #include "dnspacket.hh"
58 #include "nameserver.hh"
59 #include "distributor.hh"
61 #include "arguments.hh"
62 #include "packethandler.hh"
64 #include "tcpreceiver.hh"
66 #include "dynlistener.hh"
67 #include "dynhandler.hh"
68 #include "communicator.hh"
69 #include "dnsproxy.hh"
71 #include "common_startup.hh"
72 #include "dnsrecords.hh"
77 string s_programname
="pdns"; // used in packethandler.cc
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";
93 \brief All logging is done via L, a Logger instance
99 \brief The main loop of powerdns
101 This file is where it all happens - main is here, as are the two pivotal threads qthread() and athread()
111 int i
=open("/dev/null",O_RDWR
); /* open stdin */
113 L
<<Logger::Critical
<<"Unable to open /dev/null: "<<stringerror()<<endl
;
115 dup2(i
,0); /* stdin */
116 dup2(i
,1); /* stderr */
117 dup2(i
,2); /* stderr */
123 static void takedown(int i
)
126 L
<<Logger::Error
<<"Guardian is killed, taking down children with us"<<endl
;
132 static void writePid(void)
134 if(!::arg().mustDo("write-pid"))
137 string fname
=::arg()["socket-dir"];
138 if (::arg()["socket-dir"].empty()) {
139 if (::arg()["chroot"].empty())
140 fname
= LOCALSTATEDIR
;
142 fname
= ::arg()["chroot"] + "/";
143 } else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) {
144 fname
= ::arg()["chroot"] + ::arg()["socket-dir"];
147 fname
+= + "/" + s_programname
+ ".pid";
148 ofstream
of(fname
.c_str());
152 L
<<Logger::Error
<<"Writing pid for "<<getpid()<<" to "<<fname
<<" failed: "<<strerror(errno
)<<endl
;
155 int g_fd1
[2], g_fd2
[2];
157 pthread_mutex_t g_guardian_lock
= PTHREAD_MUTEX_INITIALIZER
;
159 // The next two methods are not in dynhandler.cc because they use a few items declared in this file.
160 static string
DLCycleHandler(const vector
<string
>&parts
, pid_t ppid
)
162 kill(cpid
, SIGKILL
); // why?
163 kill(cpid
, SIGKILL
); // why?
168 static string
DLRestHandler(const vector
<string
>&parts
, pid_t ppid
)
172 for(vector
<string
>::const_iterator i
=parts
.begin();i
!=parts
.end();++i
) {
179 Lock
l(&g_guardian_lock
);
182 writen2(g_fd1
[1],line
.c_str(),line
.size()+1);
184 catch(PDNSException
&ae
) {
185 return "Error communicating with instance: "+ae
.reason
;
189 while(fgets(mesg
,sizeof(mesg
),g_fp
)) {
194 boost::trim_right(response
);
200 static int guardian(int argc
, char **argv
)
207 DynListener
dlg(s_programname
);
208 dlg
.registerFunc("QUIT",&DLQuitHandler
, "quit daemon");
209 dlg
.registerFunc("CYCLE",&DLCycleHandler
, "restart instance");
210 dlg
.registerFunc("PING",&DLPingHandler
, "ping guardian");
211 dlg
.registerFunc("STATUS",&DLStatusHandler
, "get instance status from guardian");
212 dlg
.registerRestFunc(&DLRestHandler
);
214 string progname
=argv
[0];
219 pthread_mutex_lock(&g_guardian_lock
);
223 setStatus("Launching child");
225 if(pipe(g_fd1
)<0 || pipe(g_fd2
)<0) {
226 L
<<Logger::Critical
<<"Unable to open pipe for coprocess: "<<strerror(errno
)<<endl
;
230 if(!(g_fp
=fdopen(g_fd2
[0],"r"))) {
231 L
<<Logger::Critical
<<"Unable to associate a file pointer with pipe: "<<stringerror()<<endl
;
234 setbuf(g_fp
,0); // no buffering please, confuses select
236 if(!(pid
=fork())) { // child
237 signal(SIGTERM
, SIG_DFL
);
239 signal(SIGHUP
, SIG_DFL
);
240 signal(SIGUSR1
, SIG_DFL
);
241 signal(SIGUSR2
, SIG_DFL
);
243 char **const newargv
=new char*[argc
+2];
246 if(::arg()["config-name"]!="") {
247 progname
+="-"+::arg()["config-name"];
248 L
<<Logger::Error
<<"Virtual configuration name: "<<::arg()["config-name"]<<endl
;
251 newargv
[0]=strdup(const_cast<char *>((progname
+"-instance").c_str()));
252 for(n
=1;n
<argc
;n
++) {
257 L
<<Logger::Error
<<"Guardian is launching an instance"<<endl
;
259 fclose(g_fp
); // this closes g_fd2[0] for us
261 if(g_fd1
[0]!= infd
) {
262 dup2(g_fd1
[0], infd
);
266 if(g_fd2
[1]!= outfd
) {
267 dup2(g_fd2
[1], outfd
);
270 if(execvp(argv
[0], newargv
)<0) {
271 L
<<Logger::Error
<<"Unable to execvp '"<<argv
[0]<<"': "<<strerror(errno
)<<endl
;
274 L
<<Logger::Error
<<*p
++<<endl
;
278 L
<<Logger::Error
<<"execvp returned!!"<<endl
;
281 else if(pid
>0) { // parent
287 signal(SIGTERM
, takedown
);
289 signal(SIGHUP
, SIG_IGN
);
290 signal(SIGUSR1
, SIG_IGN
);
291 signal(SIGUSR2
, SIG_IGN
);
295 pthread_mutex_unlock(&g_guardian_lock
);
299 int ret
=waitpid(pid
,&status
,WNOHANG
);
302 L
<<Logger::Error
<<"In guardian loop, waitpid returned error: "<<strerror(errno
)<<endl
;
303 L
<<Logger::Error
<<"Dying"<<endl
;
306 else if(ret
) // something exited
308 else { // child is alive
309 // execute some kind of ping here
311 takedown(1); // needs a parameter..
312 setStatus("Child running on pid "+itoa(pid
));
317 pthread_mutex_lock(&g_guardian_lock
);
322 if(WIFEXITED(status
)) {
323 int ret
=WEXITSTATUS(status
);
326 L
<<Logger::Error
<<"Child requested a stop, exiting"<<endl
;
329 setStatus("Child died with code "+itoa(ret
));
330 L
<<Logger::Error
<<"Our pdns instance exited with code "<<ret
<<", respawning"<<endl
;
335 if(WIFSIGNALED(status
)) {
336 int sig
=WTERMSIG(status
);
337 setStatus("Child died because of signal "+itoa(sig
));
338 L
<<Logger::Error
<<"Our pdns instance ("<<pid
<<") exited after signal "<<sig
<<endl
;
340 if(WCOREDUMP(status
))
341 L
<<Logger::Error
<<"Dumped core"<<endl
;
344 L
<<Logger::Error
<<"Respawning"<<endl
;
348 L
<<Logger::Error
<<"No clue what happened! Respawning"<<endl
;
351 L
<<Logger::Error
<<"Unable to fork: "<<strerror(errno
)<<endl
;
357 static void UNIX_declareArguments()
359 ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=SYSCONFDIR
;
360 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
361 ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR
+" when unset and not chrooted" )="";
362 ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR
;
363 ::arg().set("chroot","If set, chroot to this directory for more security")="";
364 ::arg().set("logging-facility","Log under a specific facility")="";
365 ::arg().set("daemon","Operate as a daemon")="no";
368 static void loadModules()
370 if(!::arg()["load-modules"].empty()) {
371 vector
<string
>modules
;
373 stringtok(modules
,::arg()["load-modules"],", ");
375 for(vector
<string
>::const_iterator i
=modules
.begin();i
!=modules
.end();++i
) {
377 const string
&module
=*i
;
379 if(module
.find(".")==string::npos
)
380 res
=UeberBackend::loadmodule(::arg()["module-dir"]+"/lib"+module
+"backend.so");
381 else if(module
[0]=='/' || (module
[0]=='.' && module
[1]=='/') || (module
[0]=='.' && module
[1]=='.')) // absolute or current path
382 res
=UeberBackend::loadmodule(module
);
384 res
=UeberBackend::loadmodule(::arg()["module-dir"]+"/"+module
);
387 L
<<Logger::Error
<<"Receiver unable to load module "<<module
<<endl
;
395 #include <execinfo.h>
396 static void tbhandler(int num
)
398 L
<<Logger::Critical
<<"Got a signal "<<num
<<", attempting to print trace: "<<endl
;
399 void *array
[20]; //only care about last 17 functions (3 taken with tracing support)
404 size
= backtrace (array
, 20);
405 strings
= backtrace_symbols (array
, size
); //Need -rdynamic gcc (linker) flag for this to work
407 for (i
= 0; i
< size
; i
++) //skip useless functions
408 L
<<Logger::Error
<<strings
[i
]<<endl
;
411 signal(SIGABRT
, SIG_DFL
);
412 abort();//hopefully will give core
417 //! The main function of pdns, the pdns process
418 int main(int argc
, char **argv
)
420 versionSetProduct(ProductAuthoritative
);
421 reportAllTypes(); // init MOADNSParser
423 s_programname
="pdns";
427 signal(SIGSEGV
,tbhandler
);
428 signal(SIGFPE
,tbhandler
);
429 signal(SIGABRT
,tbhandler
);
430 signal(SIGILL
,tbhandler
);
434 std::ios_base::sync_with_stdio(false);
437 L
.toConsole(Logger::Warning
);
440 UNIX_declareArguments();
442 ::arg().laxParse(argc
,argv
); // do a lax parse
444 if(::arg().mustDo("version")) {
445 showProductVersion();
446 showBuildConfiguration();
450 if(::arg()["config-name"]!="")
451 s_programname
+="-"+::arg()["config-name"];
453 (void)theL(s_programname
);
455 string configname
=::arg()["config-dir"]+"/"+s_programname
+".conf";
456 cleanSlashes(configname
);
458 if(!::arg().mustDo("config") && !::arg().mustDo("no-config")) // "config" == print a configuration file
459 ::arg().laxFile(configname
.c_str());
461 ::arg().laxParse(argc
,argv
); // reparse so the commandline still wins
462 if(!::arg()["logging-facility"].empty()) {
463 int val
=logFacilityToLOG(::arg().asNum("logging-facility") );
465 theL().setFacility(val
);
467 L
<<Logger::Error
<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl
;
470 L
.setLoglevel((Logger::Urgency
)(::arg().asNum("loglevel")));
471 L
.disableSyslog(::arg().mustDo("disable-syslog"));
472 L
.toConsole((Logger::Urgency
)(::arg().asNum("loglevel")));
474 if(::arg().mustDo("help") || ::arg().mustDo("config")) {
475 ::arg().set("daemon")="no";
476 ::arg().set("guardian")="no";
479 if(::arg().mustDo("guardian") && !isGuarded(argv
)) {
480 if(::arg().mustDo("daemon")) {
481 L
.toConsole(Logger::Critical
);
484 guardian(argc
, argv
);
485 // never get here, guardian will reinvoke process
486 cerr
<<"Um, we did get here!"<<endl
;
490 // we really need to do work - either standalone or as an instance
493 if(!::arg().mustDo("traceback-handler")) {
494 L
<<Logger::Warning
<<"Disabling traceback handler"<<endl
;
495 signal(SIGSEGV
,SIG_DFL
);
496 signal(SIGFPE
,SIG_DFL
);
497 signal(SIGABRT
,SIG_DFL
);
498 signal(SIGILL
,SIG_DFL
);
502 seedRandom(::arg()["entropy-source"]);
504 #ifdef HAVE_LIBSODIUM
505 if (sodium_init() == -1) {
506 cerr
<<"Unable to initialize sodium crypto library"<<endl
;
511 openssl_thread_setup();
515 BackendMakers().launch(::arg()["launch"]); // vrooooom!
517 if(!::arg().getCommands().empty()) {
518 cerr
<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl
;
522 if(::arg().mustDo("help")) {
523 cout
<<"syntax:"<<endl
<<endl
;
524 cout
<<::arg().helpstring(::arg()["help"])<<endl
;
528 if(::arg().mustDo("config")) {
529 cout
<<::arg().configstring()<<endl
;
533 if(::arg().mustDo("list-modules")) {
534 auto modules
= BackendMakers().getModules();
535 cout
<<"Modules available:"<<endl
;
536 for(const auto& m
: modules
)
542 if(!::arg().asNum("local-port")) {
543 L
<<Logger::Error
<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl
;
544 exit(99); // this isn't going to fix itself either
546 if(!BackendMakers().numLauncheable()) {
547 L
<<Logger::Error
<<"Unable to launch, no backends configured for querying"<<endl
;
548 exit(99); // this isn't going to fix itself either
550 if(::arg().mustDo("daemon")) {
551 L
.toConsole(Logger::None
);
556 if(isGuarded(argv
)) {
557 L
<<Logger::Warning
<<"This is a guarded instance of pdns"<<endl
;
558 dl
=new DynListener
; // listens on stdin
561 L
<<Logger::Warning
<<"This is a standalone pdns"<<endl
;
563 if(::arg().mustDo("control-console"))
564 dl
=new DynListener();
566 dl
=new DynListener(s_programname
);
570 DynListener::registerFunc("SHOW",&DLShowHandler
, "show a specific statistic or * to get a list", "<statistic>");
571 DynListener::registerFunc("RPING",&DLPingHandler
, "ping instance");
572 DynListener::registerFunc("QUIT",&DLRQuitHandler
, "quit daemon");
573 DynListener::registerFunc("UPTIME",&DLUptimeHandler
, "get instance uptime");
574 DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler
, "notify host for specific domain", "<domain> <host>");
575 DynListener::registerFunc("NOTIFY",&DLNotifyHandler
, "queue a notification", "<domain>");
576 DynListener::registerFunc("RELOAD",&DLReloadHandler
, "reload all zones");
577 DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler
, "discover any new zones");
578 DynListener::registerFunc("VERSION",&DLVersionHandler
, "get instance version");
579 DynListener::registerFunc("PURGE",&DLPurgeHandler
, "purge entries from packet cache", "[<record>]");
580 DynListener::registerFunc("CCOUNTS",&DLCCHandler
, "get cache statistics");
581 DynListener::registerFunc("QTYPES", &DLQTypesHandler
, "get QType statistics");
582 DynListener::registerFunc("RESPSIZES", &DLRSizesHandler
, "get histogram of response sizes");
583 DynListener::registerFunc("REMOTES", &DLRemotesHandler
, "get top remotes");
584 DynListener::registerFunc("SET",&DLSettingsHandler
, "set config variables", "<var> <value>");
585 DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler
, "retrieve slave domain", "<domain>");
586 DynListener::registerFunc("CURRENT-CONFIG",&DLCurrentConfigHandler
, "retrieve the current configuration");
587 DynListener::registerFunc("LIST-ZONES",&DLListZones
, "show list of zones", "[master|slave|native]");
588 DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin
, "Login to a PKCS#11 token", "<module> <slot> <pin>");
590 if(!::arg()["tcp-control-address"].empty()) {
591 DynListener
* dlTCP
=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
595 // reparse, with error checking
596 if(!::arg().mustDo("no-config"))
597 ::arg().file(configname
.c_str());
598 ::arg().parse(argc
,argv
);
600 if(::arg()["server-id"].empty()) {
602 gethostname(tmp
, sizeof(tmp
)-1);
603 ::arg().set("server-id")=tmp
;
607 N
=std::make_shared
<UDPNameserver
>(); // this fails when we are not root, throws exception
608 g_udpReceivers
.push_back(N
);
610 size_t rthreads
= ::arg().asNum("receiver-threads", 1);
611 if (rthreads
> 1 && N
->canReusePort()) {
612 g_udpReceivers
.resize(rthreads
);
614 for (size_t idx
= 1; idx
< rthreads
; idx
++) {
616 g_udpReceivers
[idx
] = std::make_shared
<UDPNameserver
>(true);
618 catch(const PDNSException
& e
) {
619 L
<<Logger::Error
<<"Unable to reuse port, falling back to original bind"<<endl
;
625 if(!::arg().mustDo("disable-tcp"))
626 TN
=new TCPNameserver
;
628 catch(const ArgException
&A
) {
629 L
<<Logger::Error
<<"Fatal error: "<<A
.reason
<<endl
;
634 DLOG(L
<<Logger::Warning
<<"Verbose logging in effect"<<endl
);
636 showProductVersion();
641 catch(PDNSException
&AE
) {
642 if(!::arg().mustDo("daemon"))
643 cerr
<<"Exiting because: "<<AE
.reason
<<endl
;
644 L
<<Logger::Error
<<"Exiting because: "<<AE
.reason
<<endl
;
646 catch(std::exception
&e
) {
647 if(!::arg().mustDo("daemon"))
648 cerr
<<"Exiting because of STL error: "<<e
.what()<<endl
;
649 L
<<Logger::Error
<<"Exiting because of STL error: "<<e
.what()<<endl
;
652 cerr
<<"Uncaught exception of unknown type - sorry"<<endl
;