]>
Commit | Line | Data |
---|---|---|
12c86877 | 1 | /* |
6edbf68a PL |
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 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
e8d78143 | 25 | #include "packetcache.hh" |
da44c9ea | 26 | |
12c86877 BH |
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> | |
040712e0 | 48 | #include <boost/algorithm/string.hpp> |
d4f29089 KM |
49 | #ifdef HAVE_LIBSODIUM |
50 | #include <sodium.h> | |
51 | #endif | |
7581a35b | 52 | #include "opensslsigners.hh" |
12c86877 | 53 | |
12c86877 BH |
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" | |
12c86877 BH |
65 | #include "misc.hh" |
66 | #include "dynlistener.hh" | |
67 | #include "dynhandler.hh" | |
68 | #include "communicator.hh" | |
69 | #include "dnsproxy.hh" | |
731f58b8 | 70 | #include "utility.hh" |
12c86877 | 71 | #include "common_startup.hh" |
02116dff | 72 | #include "dnsrecords.hh" |
ba1a571d | 73 | #include "version.hh" |
12c86877 | 74 | |
8340b048 RG |
75 | #ifdef HAVE_LUA_RECORDS |
76 | #include "minicurl.hh" | |
77 | #endif /* HAVE_LUA_RECORDS */ | |
78 | ||
12c86877 BH |
79 | time_t s_starttime; |
80 | ||
81 | string s_programname="pdns"; // used in packethandler.cc | |
82 | ||
c4ac5865 | 83 | const char *funnytext= |
12c86877 BH |
84 | "*****************************************************************************\n"\ |
85 | "Ok, you just ran pdns_server through 'strings' hoping to find funny messages.\n"\ | |
86 | "Well, you found one. \n"\ | |
87 | "Two ions are flying through their particle accelerator, says the one to the\n" | |
88 | "other 'I think I've lost an electron!' \n"\ | |
89 | "So the other one says, 'Are you sure?'. 'YEAH! I'M POSITIVE!'\n"\ | |
90 | " the pdns crew - pdns@powerdns.com\n" | |
91 | "*****************************************************************************\n"; | |
92 | ||
93 | ||
94 | // start (sys)logging | |
95 | ||
12c86877 BH |
96 | |
97 | /** | |
98 | \file receiver.cc | |
99 | \brief The main loop of powerdns | |
100 | ||
101 | This file is where it all happens - main is here, as are the two pivotal threads qthread() and athread() | |
102 | */ | |
103 | ||
050e6877 | 104 | static void daemonize(void) |
12c86877 BH |
105 | { |
106 | if(fork()) | |
107 | exit(0); // bye bye | |
108 | ||
109 | setsid(); | |
110 | ||
dd8b6bd1 | 111 | int i=open("/dev/null",O_RDWR); /* open stdin */ |
11a2091b | 112 | if(i < 0) |
e6a9dde5 | 113 | g_log<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl; |
11a2091b BH |
114 | else { |
115 | dup2(i,0); /* stdin */ | |
116 | dup2(i,1); /* stderr */ | |
117 | dup2(i,2); /* stderr */ | |
118 | close(i); | |
119 | } | |
12c86877 BH |
120 | } |
121 | ||
12c86877 | 122 | static int cpid; |
12c86877 BH |
123 | static void takedown(int i) |
124 | { | |
125 | if(cpid) { | |
e6a9dde5 | 126 | g_log<<Logger::Error<<"Guardian is killed, taking down children with us"<<endl; |
882ca9d9 KM |
127 | kill(cpid,SIGKILL); |
128 | exit(0); | |
12c86877 BH |
129 | } |
130 | } | |
131 | ||
132 | static void writePid(void) | |
133 | { | |
191f2e47 | 134 | if(!::arg().mustDo("write-pid")) |
135 | return; | |
136 | ||
f0f3f0b0 PL |
137 | string fname=::arg()["socket-dir"]; |
138 | if (::arg()["socket-dir"].empty()) { | |
139 | if (::arg()["chroot"].empty()) | |
2dfe5b32 | 140 | fname = std::string(LOCALSTATEDIR) + "/pdns"; |
f0f3f0b0 PL |
141 | else |
142 | fname = ::arg()["chroot"] + "/"; | |
143 | } else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) { | |
144 | fname = ::arg()["chroot"] + ::arg()["socket-dir"]; | |
145 | } | |
146 | ||
147 | fname += + "/" + s_programname + ".pid"; | |
12c86877 BH |
148 | ofstream of(fname.c_str()); |
149 | if(of) | |
150 | of<<getpid()<<endl; | |
151 | else | |
04360367 | 152 | g_log<<Logger::Error<<"Writing pid for "<<getpid()<<" to "<<fname<<" failed: "<<stringerror()<<endl; |
12c86877 BH |
153 | } |
154 | ||
aced0e6c BH |
155 | int g_fd1[2], g_fd2[2]; |
156 | FILE *g_fp; | |
157 | pthread_mutex_t g_guardian_lock = PTHREAD_MUTEX_INITIALIZER; | |
12c86877 | 158 | |
64bcb6be RA |
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) | |
161 | { | |
882ca9d9 KM |
162 | kill(cpid, SIGKILL); // why? |
163 | kill(cpid, SIGKILL); // why? | |
64bcb6be RA |
164 | sleep(1); |
165 | return "ok"; | |
166 | } | |
167 | ||
12c86877 BH |
168 | static string DLRestHandler(const vector<string>&parts, pid_t ppid) |
169 | { | |
170 | string line; | |
171 | ||
172 | for(vector<string>::const_iterator i=parts.begin();i!=parts.end();++i) { | |
173 | if(i!=parts.begin()) | |
174 | line.append(1,' '); | |
175 | line.append(*i); | |
176 | } | |
177 | line.append(1,'\n'); | |
178 | ||
aced0e6c BH |
179 | Lock l(&g_guardian_lock); |
180 | ||
181 | try { | |
182 | writen2(g_fd1[1],line.c_str(),line.size()+1); | |
183 | } | |
3f81d239 | 184 | catch(PDNSException &ae) { |
aced0e6c BH |
185 | return "Error communicating with instance: "+ae.reason; |
186 | } | |
12c86877 | 187 | char mesg[512]; |
20ca8e7d | 188 | string response; |
aced0e6c | 189 | while(fgets(mesg,sizeof(mesg),g_fp)) { |
188b28bd | 190 | if(*mesg=='\0') |
20ca8e7d BH |
191 | break; |
192 | response+=mesg; | |
193 | } | |
040712e0 | 194 | boost::trim_right(response); |
20ca8e7d | 195 | return response; |
12c86877 BH |
196 | } |
197 | ||
64bcb6be | 198 | |
12c86877 BH |
199 | |
200 | static int guardian(int argc, char **argv) | |
201 | { | |
202 | if(isGuarded(argv)) | |
203 | return 0; | |
204 | ||
205 | int infd=0, outfd=1; | |
206 | ||
207 | DynListener dlg(s_programname); | |
3c90953e PD |
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"); | |
12c86877 BH |
212 | dlg.registerRestFunc(&DLRestHandler); |
213 | dlg.go(); | |
214 | string progname=argv[0]; | |
215 | ||
216 | bool first=true; | |
882ca9d9 | 217 | cpid=0; |
12c86877 | 218 | |
aced0e6c BH |
219 | pthread_mutex_lock(&g_guardian_lock); |
220 | ||
12c86877 BH |
221 | for(;;) { |
222 | int pid; | |
223 | setStatus("Launching child"); | |
aced0e6c BH |
224 | |
225 | if(pipe(g_fd1)<0 || pipe(g_fd2)<0) { | |
04360367 | 226 | g_log<<Logger::Critical<<"Unable to open pipe for coprocess: "<<stringerror()<<endl; |
12c86877 BH |
227 | exit(1); |
228 | } | |
229 | ||
aced0e6c | 230 | if(!(g_fp=fdopen(g_fd2[0],"r"))) { |
e6a9dde5 | 231 | g_log<<Logger::Critical<<"Unable to associate a file pointer with pipe: "<<stringerror()<<endl; |
aced0e6c BH |
232 | exit(1); |
233 | } | |
234 | setbuf(g_fp,0); // no buffering please, confuses select | |
235 | ||
12c86877 | 236 | if(!(pid=fork())) { // child |
882ca9d9 KM |
237 | signal(SIGTERM, SIG_DFL); |
238 | ||
12c86877 BH |
239 | signal(SIGHUP, SIG_DFL); |
240 | signal(SIGUSR1, SIG_DFL); | |
241 | signal(SIGUSR2, SIG_DFL); | |
242 | ||
243 | char **const newargv=new char*[argc+2]; | |
244 | int n; | |
245 | ||
e8d78143 | 246 | if(::arg()["config-name"]!="") { |
4957a608 | 247 | progname+="-"+::arg()["config-name"]; |
e6a9dde5 | 248 | g_log<<Logger::Error<<"Virtual configuration name: "<<::arg()["config-name"]<<endl; |
12c86877 BH |
249 | } |
250 | ||
251 | newargv[0]=strdup(const_cast<char *>((progname+"-instance").c_str())); | |
252 | for(n=1;n<argc;n++) { | |
4957a608 | 253 | newargv[n]=argv[n]; |
12c86877 BH |
254 | } |
255 | newargv[n]=0; | |
256 | ||
e6a9dde5 | 257 | g_log<<Logger::Error<<"Guardian is launching an instance"<<endl; |
aced0e6c BH |
258 | close(g_fd1[1]); |
259 | fclose(g_fp); // this closes g_fd2[0] for us | |
12c86877 | 260 | |
aced0e6c | 261 | if(g_fd1[0]!= infd) { |
4957a608 BH |
262 | dup2(g_fd1[0], infd); |
263 | close(g_fd1[0]); | |
12c86877 BH |
264 | } |
265 | ||
aced0e6c | 266 | if(g_fd2[1]!= outfd) { |
4957a608 BH |
267 | dup2(g_fd2[1], outfd); |
268 | close(g_fd2[1]); | |
12c86877 | 269 | } |
c1663439 | 270 | if(execvp(argv[0], newargv)<0) { |
04360367 | 271 | g_log<<Logger::Error<<"Unable to execvp '"<<argv[0]<<"': "<<stringerror()<<endl; |
4957a608 BH |
272 | char **p=newargv; |
273 | while(*p) | |
e6a9dde5 | 274 | g_log<<Logger::Error<<*p++<<endl; |
12c86877 | 275 | |
4957a608 | 276 | exit(1); |
12c86877 | 277 | } |
e6a9dde5 | 278 | g_log<<Logger::Error<<"execvp returned!!"<<endl; |
12c86877 BH |
279 | // never reached |
280 | } | |
281 | else if(pid>0) { // parent | |
aced0e6c BH |
282 | close(g_fd1[0]); |
283 | close(g_fd2[1]); | |
12c86877 BH |
284 | |
285 | if(first) { | |
4957a608 | 286 | first=false; |
882ca9d9 KM |
287 | signal(SIGTERM, takedown); |
288 | ||
4957a608 BH |
289 | signal(SIGHUP, SIG_IGN); |
290 | signal(SIGUSR1, SIG_IGN); | |
291 | signal(SIGUSR2, SIG_IGN); | |
12c86877 | 292 | |
4957a608 | 293 | writePid(); |
12c86877 | 294 | } |
aced0e6c | 295 | pthread_mutex_unlock(&g_guardian_lock); |
12c86877 BH |
296 | int status; |
297 | cpid=pid; | |
298 | for(;;) { | |
4957a608 BH |
299 | int ret=waitpid(pid,&status,WNOHANG); |
300 | ||
301 | if(ret<0) { | |
04360367 | 302 | g_log<<Logger::Error<<"In guardian loop, waitpid returned error: "<<stringerror()<<endl; |
e6a9dde5 | 303 | g_log<<Logger::Error<<"Dying"<<endl; |
4957a608 BH |
304 | exit(1); |
305 | } | |
306 | else if(ret) // something exited | |
307 | break; | |
308 | else { // child is alive | |
309 | // execute some kind of ping here | |
310 | if(DLQuitPlease()) | |
311 | takedown(1); // needs a parameter.. | |
312 | setStatus("Child running on pid "+itoa(pid)); | |
313 | sleep(1); | |
314 | } | |
12c86877 | 315 | } |
aced0e6c BH |
316 | |
317 | pthread_mutex_lock(&g_guardian_lock); | |
318 | close(g_fd1[1]); | |
319 | fclose(g_fp); | |
320 | g_fp=0; | |
12c86877 BH |
321 | |
322 | if(WIFEXITED(status)) { | |
4957a608 BH |
323 | int ret=WEXITSTATUS(status); |
324 | ||
325 | if(ret==99) { | |
e6a9dde5 | 326 | g_log<<Logger::Error<<"Child requested a stop, exiting"<<endl; |
4957a608 BH |
327 | exit(1); |
328 | } | |
329 | setStatus("Child died with code "+itoa(ret)); | |
e6a9dde5 | 330 | g_log<<Logger::Error<<"Our pdns instance exited with code "<<ret<<", respawning"<<endl; |
4957a608 | 331 | |
882ca9d9 KM |
332 | sleep(1); |
333 | continue; | |
12c86877 BH |
334 | } |
335 | if(WIFSIGNALED(status)) { | |
4957a608 BH |
336 | int sig=WTERMSIG(status); |
337 | setStatus("Child died because of signal "+itoa(sig)); | |
e6a9dde5 | 338 | g_log<<Logger::Error<<"Our pdns instance ("<<pid<<") exited after signal "<<sig<<endl; |
12c86877 | 339 | #ifdef WCOREDUMP |
4957a608 | 340 | if(WCOREDUMP(status)) |
e6a9dde5 | 341 | g_log<<Logger::Error<<"Dumped core"<<endl; |
12c86877 BH |
342 | #endif |
343 | ||
e6a9dde5 | 344 | g_log<<Logger::Error<<"Respawning"<<endl; |
882ca9d9 KM |
345 | sleep(1); |
346 | continue; | |
12c86877 | 347 | } |
e6a9dde5 | 348 | g_log<<Logger::Error<<"No clue what happened! Respawning"<<endl; |
12c86877 BH |
349 | } |
350 | else { | |
04360367 | 351 | g_log<<Logger::Error<<"Unable to fork: "<<stringerror()<<endl; |
12c86877 BH |
352 | exit(1); |
353 | } | |
354 | } | |
355 | } | |
356 | ||
331d3d27 | 357 | #if defined(__GLIBC__) && !defined(__UCLIBC__) |
12c86877 BH |
358 | #include <execinfo.h> |
359 | static void tbhandler(int num) | |
360 | { | |
e6a9dde5 | 361 | g_log<<Logger::Critical<<"Got a signal "<<num<<", attempting to print trace: "<<endl; |
12c86877 BH |
362 | void *array[20]; //only care about last 17 functions (3 taken with tracing support) |
363 | size_t size; | |
364 | char **strings; | |
365 | size_t i; | |
366 | ||
367 | size = backtrace (array, 20); | |
368 | strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work | |
369 | ||
370 | for (i = 0; i < size; i++) //skip useless functions | |
e6a9dde5 | 371 | g_log<<Logger::Error<<strings[i]<<endl; |
12c86877 BH |
372 | |
373 | ||
374 | signal(SIGABRT, SIG_DFL); | |
375 | abort();//hopefully will give core | |
376 | ||
377 | } | |
378 | #endif | |
379 | ||
380 | //! The main function of pdns, the pdns process | |
381 | int main(int argc, char **argv) | |
ba1a571d | 382 | { |
3e135495 | 383 | versionSetProduct(ProductAuthoritative); |
02116dff BH |
384 | reportAllTypes(); // init MOADNSParser |
385 | ||
12c86877 BH |
386 | s_programname="pdns"; |
387 | s_starttime=time(0); | |
388 | ||
331d3d27 | 389 | #if defined(__GLIBC__) && !defined(__UCLIBC__) |
12c86877 BH |
390 | signal(SIGSEGV,tbhandler); |
391 | signal(SIGFPE,tbhandler); | |
392 | signal(SIGABRT,tbhandler); | |
393 | signal(SIGILL,tbhandler); | |
394 | #endif | |
395 | ||
35b9a6ff | 396 | std::ios_base::sync_with_stdio(false); |
12c86877 | 397 | |
e6a9dde5 | 398 | g_log.toConsole(Logger::Warning); |
12c86877 BH |
399 | try { |
400 | declareArguments(); | |
c4db07b7 | 401 | |
e8d78143 | 402 | ::arg().laxParse(argc,argv); // do a lax parse |
12c86877 | 403 | |
c4db07b7 | 404 | if(::arg().mustDo("version")) { |
ba1a571d | 405 | showProductVersion(); |
3613a51c | 406 | showBuildConfiguration(); |
c4db07b7 PD |
407 | exit(99); |
408 | } | |
409 | ||
e8d78143 BH |
410 | if(::arg()["config-name"]!="") |
411 | s_programname+="-"+::arg()["config-name"]; | |
12c86877 | 412 | |
e6a9dde5 | 413 | g_log.setName(s_programname); |
12c86877 | 414 | |
e8d78143 | 415 | string configname=::arg()["config-dir"]+"/"+s_programname+".conf"; |
12c86877 BH |
416 | cleanSlashes(configname); |
417 | ||
8c360f20 | 418 | if(::arg()["config"] != "default" && !::arg().mustDo("no-config")) // "config" == print a configuration file |
e8d78143 | 419 | ::arg().laxFile(configname.c_str()); |
12c86877 | 420 | |
e8d78143 BH |
421 | ::arg().laxParse(argc,argv); // reparse so the commandline still wins |
422 | if(!::arg()["logging-facility"].empty()) { | |
f8499e52 BH |
423 | int val=logFacilityToLOG(::arg().asNum("logging-facility") ); |
424 | if(val >= 0) | |
e6a9dde5 | 425 | g_log.setFacility(val); |
6e2514e4 | 426 | else |
e6a9dde5 | 427 | g_log<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl; |
12c86877 BH |
428 | } |
429 | ||
e6a9dde5 PL |
430 | g_log.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel"))); |
431 | g_log.disableSyslog(::arg().mustDo("disable-syslog")); | |
432 | g_log.setTimestamps(::arg().mustDo("log-timestamp")); | |
433 | g_log.toConsole((Logger::Urgency)(::arg().asNum("loglevel"))); | |
12c86877 | 434 | |
e8d78143 BH |
435 | if(::arg().mustDo("help") || ::arg().mustDo("config")) { |
436 | ::arg().set("daemon")="no"; | |
437 | ::arg().set("guardian")="no"; | |
12c86877 BH |
438 | } |
439 | ||
e8d78143 BH |
440 | if(::arg().mustDo("guardian") && !isGuarded(argv)) { |
441 | if(::arg().mustDo("daemon")) { | |
e6a9dde5 | 442 | g_log.toConsole(Logger::Critical); |
4957a608 | 443 | daemonize(); |
12c86877 BH |
444 | } |
445 | guardian(argc, argv); | |
446 | // never get here, guardian will reinvoke process | |
447 | cerr<<"Um, we did get here!"<<endl; | |
448 | } | |
45fdd612 | 449 | |
12c86877 BH |
450 | |
451 | // we really need to do work - either standalone or as an instance | |
5488e86b | 452 | |
331d3d27 | 453 | #if defined(__GLIBC__) && !defined(__UCLIBC__) |
5488e86b | 454 | if(!::arg().mustDo("traceback-handler")) { |
e6a9dde5 | 455 | g_log<<Logger::Warning<<"Disabling traceback handler"<<endl; |
5488e86b PD |
456 | signal(SIGSEGV,SIG_DFL); |
457 | signal(SIGFPE,SIG_DFL); | |
458 | signal(SIGABRT,SIG_DFL); | |
459 | signal(SIGILL,SIG_DFL); | |
460 | } | |
461 | #endif | |
462 | ||
d4f29089 KM |
463 | #ifdef HAVE_LIBSODIUM |
464 | if (sodium_init() == -1) { | |
465 | cerr<<"Unable to initialize sodium crypto library"<<endl; | |
466 | exit(99); | |
467 | } | |
468 | #endif | |
7581a35b | 469 | |
7581a35b KM |
470 | openssl_thread_setup(); |
471 | openssl_seed(); | |
e97cb679 AT |
472 | /* setup rng */ |
473 | dns_random_init(); | |
7581a35b | 474 | |
8340b048 RG |
475 | #ifdef HAVE_LUA_RECORDS |
476 | MiniCurl::init(); | |
477 | #endif /* HAVE_LUA_RECORDS */ | |
478 | ||
d4168b30 CHB |
479 | if(!::arg()["load-modules"].empty()) { |
480 | vector<string> modules; | |
481 | ||
482 | stringtok(modules,::arg()["load-modules"], ", "); | |
483 | if (!UeberBackend::loadModules(modules, ::arg()["module-dir"])) { | |
484 | exit(1); | |
485 | } | |
486 | } | |
487 | ||
e8d78143 | 488 | BackendMakers().launch(::arg()["launch"]); // vrooooom! |
f4137d84 | 489 | |
e8d78143 | 490 | if(!::arg().getCommands().empty()) { |
94ea3c7b PL |
491 | cerr<<"Fatal: non-option"; |
492 | if (::arg().getCommands().size() > 1) { | |
493 | cerr<<"s"; | |
494 | } | |
495 | cerr<<" ("; | |
496 | bool first = true; | |
497 | for (auto const c : ::arg().getCommands()) { | |
498 | if (!first) { | |
499 | cerr<<", "; | |
500 | } | |
501 | first = false; | |
502 | cerr<<c; | |
503 | } | |
504 | cerr<<") on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl; | |
49daa3cd BH |
505 | exit(99); |
506 | } | |
f4137d84 | 507 | |
e8d78143 | 508 | if(::arg().mustDo("help")) { |
ff5ba4f9 WA |
509 | cout<<"syntax:"<<endl<<endl; |
510 | cout<<::arg().helpstring(::arg()["help"])<<endl; | |
511 | exit(0); | |
12c86877 BH |
512 | } |
513 | ||
e8d78143 | 514 | if(::arg().mustDo("config")) { |
8864bdf6 KM |
515 | string config = ::arg()["config"]; |
516 | if (config == "default") { | |
517 | cout<<::arg().configstring(false, true); | |
518 | } else if (config == "diff") { | |
519 | cout<<::arg().configstring(true, false); | |
8c360f20 KM |
520 | } else if (config == "check") { |
521 | try { | |
522 | if(!::arg().mustDo("no-config")) | |
523 | ::arg().file(configname.c_str()); | |
524 | ::arg().parse(argc,argv); | |
525 | exit(0); | |
526 | } | |
527 | catch(const ArgException &A) { | |
528 | cerr<<"Fatal error: "<<A.reason<<endl; | |
529 | exit(1); | |
530 | } | |
8864bdf6 KM |
531 | } else { |
532 | cout<<::arg().configstring(true, true); | |
533 | } | |
70463abb | 534 | exit(0); |
12c86877 BH |
535 | } |
536 | ||
e8d78143 | 537 | if(::arg().mustDo("list-modules")) { |
44ac5977 | 538 | auto modules = BackendMakers().getModules(); |
539 | cout<<"Modules available:"<<endl; | |
540 | for(const auto& m : modules) | |
541 | cout<< m <<endl; | |
12c86877 | 542 | |
44ac5977 | 543 | _exit(99); |
12c86877 | 544 | } |
da44c9ea | 545 | |
e8d78143 | 546 | if(!::arg().asNum("local-port")) { |
e6a9dde5 | 547 | g_log<<Logger::Error<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl; |
da44c9ea BH |
548 | exit(99); // this isn't going to fix itself either |
549 | } | |
12c86877 | 550 | if(!BackendMakers().numLauncheable()) { |
e6a9dde5 | 551 | g_log<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl; |
da44c9ea | 552 | exit(99); // this isn't going to fix itself either |
12c86877 | 553 | } |
e8d78143 | 554 | if(::arg().mustDo("daemon")) { |
e6a9dde5 | 555 | g_log.toConsole(Logger::None); |
12c86877 | 556 | if(!isGuarded(argv)) |
4957a608 | 557 | daemonize(); |
12c86877 BH |
558 | } |
559 | ||
560 | if(isGuarded(argv)) { | |
e6a9dde5 | 561 | g_log<<Logger::Warning<<"This is a guarded instance of pdns"<<endl; |
c2826d2e | 562 | dl=make_unique<DynListener>(); // listens on stdin |
12c86877 BH |
563 | } |
564 | else { | |
e6a9dde5 | 565 | g_log<<Logger::Warning<<"This is a standalone pdns"<<endl; |
12c86877 | 566 | |
e8d78143 | 567 | if(::arg().mustDo("control-console")) |
c2826d2e | 568 | dl=make_unique<DynListener>(); |
12c86877 | 569 | else |
c2826d2e | 570 | dl=std::unique_ptr<DynListener>(new DynListener(s_programname)); |
12c86877 BH |
571 | |
572 | writePid(); | |
573 | } | |
3c90953e PD |
574 | DynListener::registerFunc("SHOW",&DLShowHandler, "show a specific statistic or * to get a list", "<statistic>"); |
575 | DynListener::registerFunc("RPING",&DLPingHandler, "ping instance"); | |
576 | DynListener::registerFunc("QUIT",&DLRQuitHandler, "quit daemon"); | |
577 | DynListener::registerFunc("UPTIME",&DLUptimeHandler, "get instance uptime"); | |
578 | DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler, "notify host for specific domain", "<domain> <host>"); | |
579 | DynListener::registerFunc("NOTIFY",&DLNotifyHandler, "queue a notification", "<domain>"); | |
580 | DynListener::registerFunc("RELOAD",&DLReloadHandler, "reload all zones"); | |
581 | DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler, "discover any new zones"); | |
582 | DynListener::registerFunc("VERSION",&DLVersionHandler, "get instance version"); | |
583 | DynListener::registerFunc("PURGE",&DLPurgeHandler, "purge entries from packet cache", "[<record>]"); | |
584 | DynListener::registerFunc("CCOUNTS",&DLCCHandler, "get cache statistics"); | |
ba7244a5 | 585 | DynListener::registerFunc("QTYPES", &DLQTypesHandler, "get QType statistics"); |
93698ef3 PD |
586 | DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes"); |
587 | DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes"); | |
3c90953e PD |
588 | DynListener::registerFunc("SET",&DLSettingsHandler, "set config variables", "<var> <value>"); |
589 | DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler, "retrieve slave domain", "<domain>"); | |
8864bdf6 | 590 | DynListener::registerFunc("CURRENT-CONFIG",&DLCurrentConfigHandler, "retrieve the current configuration", "[diff|default]"); |
cd76677f | 591 | DynListener::registerFunc("LIST-ZONES",&DLListZones, "show list of zones", "[master|slave|native]"); |
24e0b305 | 592 | DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin, "Login to a PKCS#11 token", "<module> <slot> <pin>"); |
040712e0 BH |
593 | |
594 | if(!::arg()["tcp-control-address"].empty()) { | |
595 | DynListener* dlTCP=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port"))); | |
596 | dlTCP->go(); | |
597 | } | |
12c86877 | 598 | |
12c86877 | 599 | // reparse, with error checking |
e8d78143 BH |
600 | if(!::arg().mustDo("no-config")) |
601 | ::arg().file(configname.c_str()); | |
602 | ::arg().parse(argc,argv); | |
5bc3abe7 PD |
603 | |
604 | if(::arg()["server-id"].empty()) { | |
605 | char tmp[128]; | |
a6fbcb6e PL |
606 | if(gethostname(tmp, sizeof(tmp)-1) == 0) { |
607 | ::arg().set("server-id")=tmp; | |
608 | } else { | |
04360367 | 609 | g_log<<Logger::Warning<<"Unable to get the hostname, NSID and id.server values will be empty: "<<stringerror()<<endl; |
a6fbcb6e | 610 | } |
5bc3abe7 PD |
611 | } |
612 | ||
12c86877 | 613 | UeberBackend::go(); |
12f224ab RG |
614 | N=std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception |
615 | g_udpReceivers.push_back(N); | |
616 | ||
617 | size_t rthreads = ::arg().asNum("receiver-threads", 1); | |
618 | if (rthreads > 1 && N->canReusePort()) { | |
619 | g_udpReceivers.resize(rthreads); | |
620 | ||
621 | for (size_t idx = 1; idx < rthreads; idx++) { | |
622 | try { | |
623 | g_udpReceivers[idx] = std::make_shared<UDPNameserver>(true); | |
624 | } | |
625 | catch(const PDNSException& e) { | |
e6a9dde5 | 626 | g_log<<Logger::Error<<"Unable to reuse port, falling back to original bind"<<endl; |
12f224ab RG |
627 | break; |
628 | } | |
629 | } | |
630 | } | |
631 | ||
8c98b341 | 632 | TN = make_unique<TCPNameserver>(); |
12c86877 BH |
633 | } |
634 | catch(const ArgException &A) { | |
e6a9dde5 | 635 | g_log<<Logger::Error<<"Fatal error: "<<A.reason<<endl; |
12c86877 BH |
636 | exit(1); |
637 | } | |
638 | ||
639 | declareStats(); | |
f3245c8c OM |
640 | S.blacklist("special-memory-usage"); |
641 | ||
e6a9dde5 | 642 | DLOG(g_log<<Logger::Warning<<"Verbose logging in effect"<<endl); |
12c86877 | 643 | |
ba1a571d | 644 | showProductVersion(); |
12c86877 BH |
645 | |
646 | try { | |
12c86877 BH |
647 | mainthread(); |
648 | } | |
3f81d239 | 649 | catch(PDNSException &AE) { |
e8d78143 | 650 | if(!::arg().mustDo("daemon")) |
12c86877 | 651 | cerr<<"Exiting because: "<<AE.reason<<endl; |
e6a9dde5 | 652 | g_log<<Logger::Error<<"Exiting because: "<<AE.reason<<endl; |
12c86877 | 653 | } |
adc10f99 | 654 | catch(std::exception &e) { |
e8d78143 | 655 | if(!::arg().mustDo("daemon")) |
12c86877 | 656 | cerr<<"Exiting because of STL error: "<<e.what()<<endl; |
e6a9dde5 | 657 | g_log<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl; |
12c86877 BH |
658 | } |
659 | catch(...) { | |
660 | cerr<<"Uncaught exception of unknown type - sorry"<<endl; | |
661 | } | |
662 | ||
663 | exit(1); | |
664 | ||
665 | } | |
666 | ||
667 |