| 1 | /* |
|---|
| 2 | PowerDNS Versatile Database Driven Nameserver |
|---|
| 3 | Copyright (C) 2002 - 2011 PowerDNS.COM BV |
|---|
| 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 version 2 |
|---|
| 7 | as published by the Free Software Foundation |
|---|
| 8 | |
|---|
| 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|---|
| 18 | */ |
|---|
| 19 | #include "packetcache.hh" |
|---|
| 20 | |
|---|
| 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> |
|---|
| 42 | #include <boost/algorithm/string.hpp> |
|---|
| 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" |
|---|
| 56 | #include "ws.hh" |
|---|
| 57 | #include "misc.hh" |
|---|
| 58 | #include "dynlistener.hh" |
|---|
| 59 | #include "dynhandler.hh" |
|---|
| 60 | #include "communicator.hh" |
|---|
| 61 | #include "dnsproxy.hh" |
|---|
| 62 | #include "utility.hh" |
|---|
| 63 | #include "common_startup.hh" |
|---|
| 64 | #include "dnsrecords.hh" |
|---|
| 65 | |
|---|
| 66 | |
|---|
| 67 | time_t s_starttime; |
|---|
| 68 | |
|---|
| 69 | string s_programname="pdns"; // used in packethandler.cc |
|---|
| 70 | |
|---|
| 71 | const char *funnytext= |
|---|
| 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 | |
|---|
| 93 | This file is where it all happens - main is here, as are the two pivotal threads qthread() and athread() |
|---|
| 94 | */ |
|---|
| 95 | |
|---|
| 96 | void daemonize(void) |
|---|
| 97 | { |
|---|
| 98 | if(fork()) |
|---|
| 99 | exit(0); // bye bye |
|---|
| 100 | |
|---|
| 101 | setsid(); |
|---|
| 102 | |
|---|
| 103 | int i=open("/dev/null",O_RDWR); /* open stdin */ |
|---|
| 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 | } |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | static int cpid; |
|---|
| 115 | static 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 | |
|---|
| 124 | static 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 | |
|---|
| 134 | int g_fd1[2], g_fd2[2]; |
|---|
| 135 | FILE *g_fp; |
|---|
| 136 | pthread_mutex_t g_guardian_lock = PTHREAD_MUTEX_INITIALIZER; |
|---|
| 137 | |
|---|
| 138 | static 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 | |
|---|
| 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 | } |
|---|
| 157 | char mesg[512]; |
|---|
| 158 | string response; |
|---|
| 159 | while(fgets(mesg,sizeof(mesg),g_fp)) { |
|---|
| 160 | if(*mesg=='\n') |
|---|
| 161 | break; |
|---|
| 162 | response+=mesg; |
|---|
| 163 | } |
|---|
| 164 | boost::trim_right(response); |
|---|
| 165 | return response; |
|---|
| 166 | } |
|---|
| 167 | |
|---|
| 168 | static string DLCycleHandler(const vector<string>&parts, pid_t ppid) |
|---|
| 169 | { |
|---|
| 170 | kill(cpid, SIGKILL); // why? |
|---|
| 171 | kill(cpid, SIGKILL); // why? |
|---|
| 172 | sleep(1); |
|---|
| 173 | return "ok"; |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | static 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, "quit daemon"); |
|---|
| 185 | dlg.registerFunc("CYCLE",&DLCycleHandler, "restart instance"); |
|---|
| 186 | dlg.registerFunc("PING",&DLPingHandler, "ping guardian"); |
|---|
| 187 | dlg.registerFunc("STATUS",&DLStatusHandler, "get instance status from guardian"); |
|---|
| 188 | dlg.registerRestFunc(&DLRestHandler); |
|---|
| 189 | dlg.go(); |
|---|
| 190 | string progname=argv[0]; |
|---|
| 191 | |
|---|
| 192 | bool first=true; |
|---|
| 193 | cpid=0; |
|---|
| 194 | |
|---|
| 195 | pthread_mutex_lock(&g_guardian_lock); |
|---|
| 196 | |
|---|
| 197 | for(;;) { |
|---|
| 198 | int pid; |
|---|
| 199 | setStatus("Launching child"); |
|---|
| 200 | |
|---|
| 201 | if(pipe(g_fd1)<0 || pipe(g_fd2)<0) { |
|---|
| 202 | L<<Logger::Critical<<"Unable to open pipe for coprocess: "<<strerror(errno)<<endl; |
|---|
| 203 | exit(1); |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 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 | |
|---|
| 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 | |
|---|
| 222 | if(::arg()["config-name"]!="") { |
|---|
| 223 | progname+="-"+::arg()["config-name"]; |
|---|
| 224 | L<<Logger::Error<<"Virtual configuration name: "<<::arg()["config-name"]<<endl; |
|---|
| 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; |
|---|
| 234 | close(g_fd1[1]); |
|---|
| 235 | fclose(g_fp); // this closes g_fd2[0] for us |
|---|
| 236 | |
|---|
| 237 | if(g_fd1[0]!= infd) { |
|---|
| 238 | dup2(g_fd1[0], infd); |
|---|
| 239 | close(g_fd1[0]); |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | if(g_fd2[1]!= outfd) { |
|---|
| 243 | dup2(g_fd2[1], outfd); |
|---|
| 244 | close(g_fd2[1]); |
|---|
| 245 | } |
|---|
| 246 | if(execvp(argv[0], newargv)<0) { |
|---|
| 247 | L<<Logger::Error<<"Unable to execvp '"<<argv[0]<<"': "<<strerror(errno)<<endl; |
|---|
| 248 | char **p=newargv; |
|---|
| 249 | while(*p) |
|---|
| 250 | L<<Logger::Error<<*p++<<endl; |
|---|
| 251 | |
|---|
| 252 | exit(1); |
|---|
| 253 | } |
|---|
| 254 | L<<Logger::Error<<"execvp returned!!"<<endl; |
|---|
| 255 | // never reached |
|---|
| 256 | } |
|---|
| 257 | else if(pid>0) { // parent |
|---|
| 258 | close(g_fd1[0]); |
|---|
| 259 | close(g_fd2[1]); |
|---|
| 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 | } |
|---|
| 271 | pthread_mutex_unlock(&g_guardian_lock); |
|---|
| 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()) |
|---|
| 287 | takedown(1); // needs a parameter.. |
|---|
| 288 | setStatus("Child running on pid "+itoa(pid)); |
|---|
| 289 | sleep(1); |
|---|
| 290 | } |
|---|
| 291 | } |
|---|
| 292 | |
|---|
| 293 | pthread_mutex_lock(&g_guardian_lock); |
|---|
| 294 | close(g_fd1[1]); |
|---|
| 295 | fclose(g_fp); |
|---|
| 296 | g_fp=0; |
|---|
| 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 | |
|---|
| 334 | static void UNIX_declareArguments() |
|---|
| 335 | { |
|---|
| 336 | ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=SYSCONFDIR; |
|---|
| 337 | ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")=""; |
|---|
| 338 | ::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR; |
|---|
| 339 | ::arg().set("module-dir","Default directory for modules")=LIBDIR; |
|---|
| 340 | ::arg().set("chroot","If set, chroot to this directory for more security")=""; |
|---|
| 341 | ::arg().set("logging-facility","Log under a specific facility")=""; |
|---|
| 342 | ::arg().set("daemon","Operate as a daemon")="no"; |
|---|
| 343 | |
|---|
| 344 | } |
|---|
| 345 | |
|---|
| 346 | static void loadModules() |
|---|
| 347 | { |
|---|
| 348 | if(!::arg()["load-modules"].empty()) { |
|---|
| 349 | vector<string>modules; |
|---|
| 350 | |
|---|
| 351 | stringtok(modules,::arg()["load-modules"],","); |
|---|
| 352 | |
|---|
| 353 | for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i) { |
|---|
| 354 | bool res; |
|---|
| 355 | const string &module=*i; |
|---|
| 356 | |
|---|
| 357 | if(module.find(".")==string::npos) |
|---|
| 358 | res=UeberBackend::loadmodule(::arg()["module-dir"]+"/lib"+module+"backend.so"); |
|---|
| 359 | else if(module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) // absolute or current path |
|---|
| 360 | res=UeberBackend::loadmodule(module); |
|---|
| 361 | else |
|---|
| 362 | res=UeberBackend::loadmodule(::arg()["module-dir"]+"/"+module); |
|---|
| 363 | |
|---|
| 364 | if(res==false) { |
|---|
| 365 | L<<Logger::Error<<"receiver unable to load module "<<module<<endl; |
|---|
| 366 | exit(1); |
|---|
| 367 | } |
|---|
| 368 | } |
|---|
| 369 | } |
|---|
| 370 | } |
|---|
| 371 | |
|---|
| 372 | |
|---|
| 373 | |
|---|
| 374 | #ifdef __linux__ |
|---|
| 375 | #include <execinfo.h> |
|---|
| 376 | static void tbhandler(int num) |
|---|
| 377 | { |
|---|
| 378 | L<<Logger::Critical<<"Got a signal "<<num<<", attempting to print trace: "<<endl; |
|---|
| 379 | void *array[20]; //only care about last 17 functions (3 taken with tracing support) |
|---|
| 380 | size_t size; |
|---|
| 381 | char **strings; |
|---|
| 382 | size_t i; |
|---|
| 383 | |
|---|
| 384 | size = backtrace (array, 20); |
|---|
| 385 | strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work |
|---|
| 386 | |
|---|
| 387 | for (i = 0; i < size; i++) //skip useless functions |
|---|
| 388 | L<<Logger::Error<<strings[i]<<endl; |
|---|
| 389 | |
|---|
| 390 | |
|---|
| 391 | signal(SIGABRT, SIG_DFL); |
|---|
| 392 | abort();//hopefully will give core |
|---|
| 393 | |
|---|
| 394 | } |
|---|
| 395 | #endif |
|---|
| 396 | |
|---|
| 397 | //! The main function of pdns, the pdns process |
|---|
| 398 | int main(int argc, char **argv) |
|---|
| 399 | { |
|---|
| 400 | reportAllTypes(); // init MOADNSParser |
|---|
| 401 | |
|---|
| 402 | s_programname="pdns"; |
|---|
| 403 | s_starttime=time(0); |
|---|
| 404 | |
|---|
| 405 | #ifdef __linux__ |
|---|
| 406 | signal(SIGSEGV,tbhandler); |
|---|
| 407 | signal(SIGFPE,tbhandler); |
|---|
| 408 | signal(SIGABRT,tbhandler); |
|---|
| 409 | signal(SIGILL,tbhandler); |
|---|
| 410 | #endif |
|---|
| 411 | |
|---|
| 412 | |
|---|
| 413 | L.toConsole(Logger::Warning); |
|---|
| 414 | try { |
|---|
| 415 | declareArguments(); |
|---|
| 416 | UNIX_declareArguments(); |
|---|
| 417 | |
|---|
| 418 | ::arg().laxParse(argc,argv); // do a lax parse |
|---|
| 419 | |
|---|
| 420 | if(::arg().mustDo("version")) { |
|---|
| 421 | cerr<<"Version: "VERSION", compiled on "<<__DATE__", "__TIME__; |
|---|
| 422 | #ifdef __GNUC__ |
|---|
| 423 | cerr<<" with gcc version "<<__VERSION__; |
|---|
| 424 | #endif |
|---|
| 425 | cout<<endl; |
|---|
| 426 | exit(99); |
|---|
| 427 | } |
|---|
| 428 | |
|---|
| 429 | if(::arg()["config-name"]!="") |
|---|
| 430 | s_programname+="-"+::arg()["config-name"]; |
|---|
| 431 | |
|---|
| 432 | (void)theL(s_programname); |
|---|
| 433 | |
|---|
| 434 | string configname=::arg()["config-dir"]+"/"+s_programname+".conf"; |
|---|
| 435 | cleanSlashes(configname); |
|---|
| 436 | |
|---|
| 437 | if(!::arg().mustDo("config") && !::arg().mustDo("no-config")) // "config" == print a configuration file |
|---|
| 438 | ::arg().laxFile(configname.c_str()); |
|---|
| 439 | |
|---|
| 440 | ::arg().laxParse(argc,argv); // reparse so the commandline still wins |
|---|
| 441 | if(!::arg()["logging-facility"].empty()) { |
|---|
| 442 | int val=logFacilityToLOG(::arg().asNum("logging-facility") ); |
|---|
| 443 | if(val >= 0) |
|---|
| 444 | theL().setFacility(val); |
|---|
| 445 | else |
|---|
| 446 | L<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl; |
|---|
| 447 | } |
|---|
| 448 | |
|---|
| 449 | L.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel"))); |
|---|
| 450 | L.toConsole((Logger::Urgency)(::arg().asNum("loglevel"))); |
|---|
| 451 | |
|---|
| 452 | if(::arg().mustDo("help") || ::arg().mustDo("config")) { |
|---|
| 453 | ::arg().set("daemon")="no"; |
|---|
| 454 | ::arg().set("guardian")="no"; |
|---|
| 455 | } |
|---|
| 456 | |
|---|
| 457 | if(::arg().mustDo("guardian") && !isGuarded(argv)) { |
|---|
| 458 | if(::arg().mustDo("daemon")) { |
|---|
| 459 | L.toConsole(Logger::Critical); |
|---|
| 460 | daemonize(); |
|---|
| 461 | } |
|---|
| 462 | guardian(argc, argv); |
|---|
| 463 | // never get here, guardian will reinvoke process |
|---|
| 464 | cerr<<"Um, we did get here!"<<endl; |
|---|
| 465 | } |
|---|
| 466 | |
|---|
| 467 | |
|---|
| 468 | // we really need to do work - either standalone or as an instance |
|---|
| 469 | |
|---|
| 470 | seedRandom(::arg()["entropy-source"]); |
|---|
| 471 | |
|---|
| 472 | loadModules(); |
|---|
| 473 | BackendMakers().launch(::arg()["launch"]); // vrooooom! |
|---|
| 474 | |
|---|
| 475 | if(!::arg().getCommands().empty()) { |
|---|
| 476 | cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl; |
|---|
| 477 | exit(99); |
|---|
| 478 | } |
|---|
| 479 | |
|---|
| 480 | if(::arg().mustDo("help")) { |
|---|
| 481 | cerr<<"syntax:"<<endl<<endl; |
|---|
| 482 | cerr<<::arg().helpstring(::arg()["help"])<<endl; |
|---|
| 483 | exit(99); |
|---|
| 484 | } |
|---|
| 485 | |
|---|
| 486 | if(::arg().mustDo("config")) { |
|---|
| 487 | cout<<::arg().configstring()<<endl; |
|---|
| 488 | exit(99); |
|---|
| 489 | } |
|---|
| 490 | |
|---|
| 491 | if(::arg().mustDo("list-modules")) { |
|---|
| 492 | vector<string>modules=BackendMakers().getModules(); |
|---|
| 493 | cerr<<"Modules available:"<<endl; |
|---|
| 494 | for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i) |
|---|
| 495 | cout<<*i<<endl; |
|---|
| 496 | |
|---|
| 497 | exit(99); |
|---|
| 498 | } |
|---|
| 499 | |
|---|
| 500 | if(::arg().mustDo("fancy-records")) { |
|---|
| 501 | reportFancyTypes(); |
|---|
| 502 | } |
|---|
| 503 | |
|---|
| 504 | if(!::arg().asNum("local-port")) { |
|---|
| 505 | L<<Logger::Error<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl; |
|---|
| 506 | exit(99); // this isn't going to fix itself either |
|---|
| 507 | } |
|---|
| 508 | if(!BackendMakers().numLauncheable()) { |
|---|
| 509 | L<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl; |
|---|
| 510 | exit(99); // this isn't going to fix itself either |
|---|
| 511 | } |
|---|
| 512 | if(::arg().mustDo("daemon")) { |
|---|
| 513 | L.toConsole(Logger::None); |
|---|
| 514 | if(!isGuarded(argv)) |
|---|
| 515 | daemonize(); |
|---|
| 516 | } |
|---|
| 517 | |
|---|
| 518 | if(::arg()["server-id"].empty()) { |
|---|
| 519 | char tmp[128]; |
|---|
| 520 | gethostname(tmp, sizeof(tmp)-1); |
|---|
| 521 | ::arg().set("server-id")=tmp; |
|---|
| 522 | } |
|---|
| 523 | |
|---|
| 524 | if(isGuarded(argv)) { |
|---|
| 525 | L<<Logger::Warning<<"This is a guarded instance of pdns"<<endl; |
|---|
| 526 | dl=new DynListener; // listens on stdin |
|---|
| 527 | } |
|---|
| 528 | else { |
|---|
| 529 | L<<Logger::Warning<<"This is a standalone pdns"<<endl; |
|---|
| 530 | |
|---|
| 531 | if(::arg().mustDo("control-console")) |
|---|
| 532 | dl=new DynListener(); |
|---|
| 533 | else |
|---|
| 534 | dl=new DynListener(s_programname); |
|---|
| 535 | |
|---|
| 536 | writePid(); |
|---|
| 537 | } |
|---|
| 538 | DynListener::registerFunc("SHOW",&DLShowHandler, "show a specific statistic or * to get a list", "<statistic>"); |
|---|
| 539 | DynListener::registerFunc("RPING",&DLPingHandler, "ping instance"); |
|---|
| 540 | DynListener::registerFunc("QUIT",&DLRQuitHandler, "quit daemon"); |
|---|
| 541 | DynListener::registerFunc("UPTIME",&DLUptimeHandler, "get instance uptime"); |
|---|
| 542 | DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler, "notify host for specific domain", "<domain> <host>"); |
|---|
| 543 | DynListener::registerFunc("NOTIFY",&DLNotifyHandler, "queue a notification", "<domain>"); |
|---|
| 544 | DynListener::registerFunc("RELOAD",&DLReloadHandler, "reload all zones"); |
|---|
| 545 | DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler, "discover any new zones"); |
|---|
| 546 | DynListener::registerFunc("VERSION",&DLVersionHandler, "get instance version"); |
|---|
| 547 | DynListener::registerFunc("PURGE",&DLPurgeHandler, "purge entries from packet cache", "[<record>]"); |
|---|
| 548 | DynListener::registerFunc("CCOUNTS",&DLCCHandler, "get cache statistics"); |
|---|
| 549 | DynListener::registerFunc("SET",&DLSettingsHandler, "set config variables", "<var> <value>"); |
|---|
| 550 | DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler, "retrieve slave domain", "<domain>"); |
|---|
| 551 | |
|---|
| 552 | if(!::arg()["tcp-control-address"].empty()) { |
|---|
| 553 | DynListener* dlTCP=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port"))); |
|---|
| 554 | dlTCP->go(); |
|---|
| 555 | } |
|---|
| 556 | |
|---|
| 557 | // reparse, with error checking |
|---|
| 558 | if(!::arg().mustDo("no-config")) |
|---|
| 559 | ::arg().file(configname.c_str()); |
|---|
| 560 | ::arg().parse(argc,argv); |
|---|
| 561 | UeberBackend::go(); |
|---|
| 562 | N=new UDPNameserver; // this fails when we are not root, throws exception |
|---|
| 563 | |
|---|
| 564 | if(!::arg().mustDo("disable-tcp")) |
|---|
| 565 | TN=new TCPNameserver; |
|---|
| 566 | } |
|---|
| 567 | catch(const ArgException &A) { |
|---|
| 568 | L<<Logger::Error<<"Fatal error: "<<A.reason<<endl; |
|---|
| 569 | exit(1); |
|---|
| 570 | } |
|---|
| 571 | |
|---|
| 572 | declareStats(); |
|---|
| 573 | DLOG(L<<Logger::Warning<<"Verbose logging in effect"<<endl); |
|---|
| 574 | |
|---|
| 575 | L<<Logger::Warning<<"PowerDNS "<<VERSION<<" (C) 2001-2012 PowerDNS.COM BV ("<<__DATE__", "__TIME__; |
|---|
| 576 | #ifdef __GNUC__ |
|---|
| 577 | L<<", gcc "__VERSION__; |
|---|
| 578 | #endif // add other compilers here |
|---|
| 579 | L<<") starting up"<<endl; |
|---|
| 580 | |
|---|
| 581 | L<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. " |
|---|
| 582 | "This is free software, and you are welcome to redistribute it " |
|---|
| 583 | "according to the terms of the GPL version 2."<<endl; |
|---|
| 584 | |
|---|
| 585 | |
|---|
| 586 | try { |
|---|
| 587 | |
|---|
| 588 | mainthread(); |
|---|
| 589 | } |
|---|
| 590 | catch(AhuException &AE) { |
|---|
| 591 | if(!::arg().mustDo("daemon")) |
|---|
| 592 | cerr<<"Exiting because: "<<AE.reason<<endl; |
|---|
| 593 | L<<Logger::Error<<"Exiting because: "<<AE.reason<<endl; |
|---|
| 594 | } |
|---|
| 595 | catch(std::exception &e) { |
|---|
| 596 | if(!::arg().mustDo("daemon")) |
|---|
| 597 | cerr<<"Exiting because of STL error: "<<e.what()<<endl; |
|---|
| 598 | L<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl; |
|---|
| 599 | } |
|---|
| 600 | catch(...) { |
|---|
| 601 | cerr<<"Uncaught exception of unknown type - sorry"<<endl; |
|---|
| 602 | } |
|---|
| 603 | |
|---|
| 604 | exit(1); |
|---|
| 605 | |
|---|
| 606 | } |
|---|
| 607 | |
|---|
| 608 | |
|---|