1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 /*! \file */
13
14 #include <config.h>
15
16 #include <ctype.h>
17 #include <inttypes.h>
18 #include <stdbool.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include <isc/app.h>
23 #include <isc/backtrace.h>
24 #include <isc/commandline.h>
25 #include <isc/dir.h>
26 #include <isc/entropy.h>
27 #include <isc/file.h>
28 #include <isc/hash.h>
29 #include <isc/httpd.h>
30 #include <isc/os.h>
31 #include <isc/platform.h>
32 #include <isc/print.h>
33 #include <isc/resource.h>
34 #include <isc/stdio.h>
35 #include <isc/string.h>
36 #include <isc/task.h>
37 #include <isc/timer.h>
38 #include <isc/util.h>
39
40 #include <isccc/result.h>
41
42 #include <dns/dispatch.h>
43 #include <dns/dyndb.h>
44 #include <dns/name.h>
45 #include <dns/result.h>
46 #include <dns/resolver.h>
47 #include <dns/view.h>
48
49 #include <dst/result.h>
50 #ifdef PKCS11CRYPTO
51 #include <pk11/result.h>
52 #endif
53
54 #include <dlz/dlz_dlopen_driver.h>
55
56 #ifdef HAVE_GPERFTOOLS_PROFILER
57 #include <gperftools/profiler.h>
58 #endif
59
60 #ifdef HAVE_GEOIP2
61 #include <maxminddb.h>
62 #endif
63
64 /*
65 * Defining NS_MAIN provides storage declarations (rather than extern)
66 * for variables in named/globals.h.
67 */
68 #define NS_MAIN 1
69
70 #include <named/builtin.h>
71 #include <named/config.h>
72 #include <named/control.h>
73 #include <named/fuzz.h>
74 #include <named/globals.h> /* Explicit, though named/log.h includes it. */
75 #include <named/interfacemgr.h>
76 #include <named/log.h>
77 #include <named/os.h>
78 #include <named/server.h>
79 #include <named/lwresd.h>
80 #include <named/main.h>
81 #include <named/seccomp.h>
82 #ifdef HAVE_LIBSCF
83 #include <named/ns_smf_globals.h>
84 #endif
85
86 #ifdef OPENSSL
87 #include <openssl/opensslv.h>
88 #include <openssl/crypto.h>
89 #endif
90 #ifdef HAVE_LIBXML2
91 #include <libxml/xmlversion.h>
92 #endif
93 #ifdef HAVE_ZLIB
94 #include <zlib.h>
95 #endif
96 /*
97 * Include header files for database drivers here.
98 */
99 /* #include "xxdb.h" */
100
101 #ifdef CONTRIB_DLZ
102 /*
103 * Include contributed DLZ drivers if appropriate.
104 */
105 #include <dlz/dlz_drivers.h>
106 #endif
107
108 /*
109 * The maximum number of stack frames to dump on assertion failure.
110 */
111 #ifndef BACKTRACE_MAXFRAME
112 #define BACKTRACE_MAXFRAME 128
113 #endif
114
115 LIBISC_EXTERNAL_DATA extern int isc_dscp_check_value;
116 LIBDNS_EXTERNAL_DATA extern unsigned int dns_zone_mkey_hour;
117 LIBDNS_EXTERNAL_DATA extern unsigned int dns_zone_mkey_day;
118 LIBDNS_EXTERNAL_DATA extern unsigned int dns_zone_mkey_month;
119
120 static bool want_stats = false;
121 static char program_name[NAME_MAX] = "named";
122 static char absolute_conffile[PATH_MAX];
123 static char saved_command_line[512];
124 static char version[512];
125 static unsigned int maxsocks = 0;
126 static int maxudp = 0;
127
128 void
ns_main_earlywarning(const char * format,...)129 ns_main_earlywarning(const char *format, ...) {
130 va_list args;
131
132 va_start(args, format);
133 if (ns_g_lctx != NULL) {
134 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
135 NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
136 format, args);
137 } else {
138 fprintf(stderr, "%s: ", program_name);
139 vfprintf(stderr, format, args);
140 fprintf(stderr, "\n");
141 fflush(stderr);
142 }
143 va_end(args);
144 }
145
146 void
ns_main_earlyfatal(const char * format,...)147 ns_main_earlyfatal(const char *format, ...) {
148 va_list args;
149
150 va_start(args, format);
151 if (ns_g_lctx != NULL) {
152 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
153 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
154 format, args);
155 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
156 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
157 "exiting (due to early fatal error)");
158 } else {
159 fprintf(stderr, "%s: ", program_name);
160 vfprintf(stderr, format, args);
161 fprintf(stderr, "\n");
162 fflush(stderr);
163 }
164 va_end(args);
165
166 exit(1);
167 }
168
169 ISC_PLATFORM_NORETURN_PRE static void
170 assertion_failed(const char *file, int line, isc_assertiontype_t type,
171 const char *cond) ISC_PLATFORM_NORETURN_POST;
172
173 static void
assertion_failed(const char * file,int line,isc_assertiontype_t type,const char * cond)174 assertion_failed(const char *file, int line, isc_assertiontype_t type,
175 const char *cond)
176 {
177 void *tracebuf[BACKTRACE_MAXFRAME];
178 int i, nframes;
179 isc_result_t result;
180 const char *logsuffix = "";
181 const char *fname;
182
183 /*
184 * Handle assertion failures.
185 */
186
187 if (ns_g_lctx != NULL) {
188 /*
189 * Reset the assertion callback in case it is the log
190 * routines causing the assertion.
191 */
192 isc_assertion_setcallback(NULL);
193
194 result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
195 &nframes);
196 if (result == ISC_R_SUCCESS && nframes > 0)
197 logsuffix = ", back trace";
198 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
199 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
200 "%s:%d: %s(%s) failed%s", file, line,
201 isc_assertion_typetotext(type), cond, logsuffix);
202 if (result == ISC_R_SUCCESS) {
203 for (i = 0; i < nframes; i++) {
204 unsigned long offset;
205
206 fname = NULL;
207 result = isc_backtrace_getsymbol(tracebuf[i],
208 &fname,
209 &offset);
210 if (result == ISC_R_SUCCESS) {
211 isc_log_write(ns_g_lctx,
212 NS_LOGCATEGORY_GENERAL,
213 NS_LOGMODULE_MAIN,
214 ISC_LOG_CRITICAL,
215 "#%d %p in %s()+0x%lx", i,
216 tracebuf[i], fname,
217 offset);
218 } else {
219 isc_log_write(ns_g_lctx,
220 NS_LOGCATEGORY_GENERAL,
221 NS_LOGMODULE_MAIN,
222 ISC_LOG_CRITICAL,
223 "#%d %p in ??", i,
224 tracebuf[i]);
225 }
226 }
227 }
228 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
229 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
230 "exiting (due to assertion failure)");
231 } else {
232 fprintf(stderr, "%s:%d: %s(%s) failed\n",
233 file, line, isc_assertion_typetotext(type), cond);
234 fflush(stderr);
235 }
236
237 if (ns_g_coreok)
238 abort();
239 exit(1);
240 }
241
242 ISC_PLATFORM_NORETURN_PRE static void
243 library_fatal_error(const char *file, int line, const char *format,
244 va_list args)
245 ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
246
247 static void
library_fatal_error(const char * file,int line,const char * format,va_list args)248 library_fatal_error(const char *file, int line, const char *format,
249 va_list args)
250 {
251 /*
252 * Handle isc_error_fatal() calls from our libraries.
253 */
254
255 if (ns_g_lctx != NULL) {
256 /*
257 * Reset the error callback in case it is the log
258 * routines causing the assertion.
259 */
260 isc_error_setfatal(NULL);
261
262 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
263 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
264 "%s:%d: fatal error:", file, line);
265 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
266 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
267 format, args);
268 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
269 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
270 "exiting (due to fatal error in library)");
271 } else {
272 fprintf(stderr, "%s:%d: fatal error: ", file, line);
273 vfprintf(stderr, format, args);
274 fprintf(stderr, "\n");
275 fflush(stderr);
276 }
277
278 if (ns_g_coreok)
279 abort();
280 exit(1);
281 }
282
283 static void
284 library_unexpected_error(const char *file, int line, const char *format,
285 va_list args) ISC_FORMAT_PRINTF(3, 0);
286
287 static void
library_unexpected_error(const char * file,int line,const char * format,va_list args)288 library_unexpected_error(const char *file, int line, const char *format,
289 va_list args)
290 {
291 /*
292 * Handle isc_error_unexpected() calls from our libraries.
293 */
294
295 if (ns_g_lctx != NULL) {
296 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
297 NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
298 "%s:%d: unexpected error:", file, line);
299 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
300 NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
301 format, args);
302 } else {
303 fprintf(stderr, "%s:%d: fatal error: ", file, line);
304 vfprintf(stderr, format, args);
305 fprintf(stderr, "\n");
306 fflush(stderr);
307 }
308 }
309
310 static void
lwresd_usage(void)311 lwresd_usage(void) {
312 fprintf(stderr,
313 "usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] "
314 "[-d debuglevel] [-f|-g]\n"
315 " [-i pidfile] [-n number_of_cpus] "
316 "[-p port] [-P listen-port]\n"
317 " [-s] [-S sockets] [-t chrootdir] [-u username] "
318 "[-U listeners]\n"
319 " [-m {usage|trace|record|size|mctx}]\n"
320 "usage: lwresd [-v|-V]\n");
321 }
322
323 static void
usage(void)324 usage(void) {
325 if (ns_g_lwresdonly) {
326 lwresd_usage();
327 return;
328 }
329 fprintf(stderr,
330 "usage: named [-4|-6] [-c conffile] [-d debuglevel] "
331 "[-E engine] [-f|-g]\n"
332 " [-n number_of_cpus] [-p port] [-s] "
333 "[-S sockets] [-t chrootdir]\n"
334 " [-u username] [-U listeners] "
335 "[-m {usage|trace|record|size|mctx}]\n"
336 "usage: named [-v|-V]\n");
337 }
338
339 static void
save_command_line(int argc,char * argv[])340 save_command_line(int argc, char *argv[]) {
341 int i;
342 char *src;
343 char *dst;
344 char *eob;
345 const char truncated[] = "...";
346 bool quoted = false;
347
348 dst = saved_command_line;
349 eob = saved_command_line + sizeof(saved_command_line);
350
351 for (i = 1; i < argc && dst < eob; i++) {
352 *dst++ = ' ';
353
354 src = argv[i];
355 while (*src != '\0' && dst < eob) {
356 /*
357 * This won't perfectly produce a shell-independent
358 * pastable command line in all circumstances, but
359 * comes close, and for practical purposes will
360 * nearly always be fine.
361 */
362 if (quoted || isalnum(*src & 0xff) ||
363 *src == ',' || *src == '-' || *src == '_' ||
364 *src == '.' || *src == '/') {
365 *dst++ = *src++;
366 quoted = false;
367 } else {
368 *dst++ = '\\';
369 quoted = true;
370 }
371 }
372 }
373
374 INSIST(sizeof(saved_command_line) >= sizeof(truncated));
375
376 if (dst == eob)
377 strcpy(eob - sizeof(truncated), truncated);
378 else
379 *dst = '\0';
380 }
381
382 static int
parse_int(char * arg,const char * desc)383 parse_int(char *arg, const char *desc) {
384 char *endp;
385 int tmp;
386 long int ltmp;
387
388 ltmp = strtol(arg, &endp, 10);
389 tmp = (int) ltmp;
390 if (*endp != '\0')
391 ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
392 if (tmp < 0 || tmp != ltmp)
393 ns_main_earlyfatal("%s '%s' out of range", desc, arg);
394 return (tmp);
395 }
396
397 static struct flag_def {
398 const char *name;
399 unsigned int value;
400 } mem_debug_flags[] = {
401 { "none", 0},
402 { "trace", ISC_MEM_DEBUGTRACE },
403 { "record", ISC_MEM_DEBUGRECORD },
404 { "usage", ISC_MEM_DEBUGUSAGE },
405 { "size", ISC_MEM_DEBUGSIZE },
406 { "mctx", ISC_MEM_DEBUGCTX },
407 { NULL, 0 }
408 };
409
410 static void
set_flags(const char * arg,struct flag_def * defs,unsigned int * ret)411 set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
412 bool clear = false;
413
414 for (;;) {
415 const struct flag_def *def;
416 const char *end = strchr(arg, ',');
417 int arglen;
418 if (end == NULL)
419 end = arg + strlen(arg);
420 arglen = (int)(end - arg);
421 for (def = defs; def->name != NULL; def++) {
422 if (arglen == (int)strlen(def->name) &&
423 memcmp(arg, def->name, arglen) == 0) {
424 if (def->value == 0)
425 clear = true;
426 *ret |= def->value;
427 goto found;
428 }
429 }
430 ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
431 found:
432 if (clear || (*end == '\0'))
433 break;
434 arg = end + 1;
435 }
436
437 if (clear)
438 *ret = 0;
439 }
440
441 static void
printversion(bool verbose)442 printversion(bool verbose) {
443 char rndcconf[PATH_MAX], *dot = NULL;
444 isc_mem_t *mctx = NULL;
445 cfg_parser_t *parser = NULL;
446 cfg_obj_t *config = NULL;
447 const cfg_obj_t *defaults = NULL, *obj = NULL;
448
449 printf("%s %s%s%s <id:%s>\n",
450 ns_g_product, ns_g_version,
451 (*ns_g_description != '\0') ? " " : "",
452 ns_g_description, ns_g_srcid);
453
454 if (!verbose) {
455 return;
456 }
457 printf("running on %s\n", ns_os_uname());
458 printf("built by %s with %s\n", ns_g_builder, ns_g_configargs);
459 #ifdef __clang__
460 printf("compiled by CLANG %s\n", __VERSION__);
461 #else
462 #if defined(__ICC) || defined(__INTEL_COMPILER)
463 printf("compiled by ICC %s\n", __VERSION__);
464 #else
465 #ifdef __GNUC__
466 printf("compiled by GCC %s\n", __VERSION__);
467 #endif
468 #endif
469 #endif
470 #ifdef _MSC_VER
471 printf("compiled by MSVC %d\n", _MSC_VER);
472 #endif
473 #ifdef __SUNPRO_C
474 printf("compiled by Solaris Studio %x\n", __SUNPRO_C);
475 #endif
476 #ifdef OPENSSL
477 printf("compiled with OpenSSL version: %s\n", OPENSSL_VERSION_TEXT);
478 #if !defined(LIBRESSL_VERSION_NUMBER) && \
479 OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 or higher */
480 printf("linked to OpenSSL version: %s\n",
481 OpenSSL_version(OPENSSL_VERSION));
482 #else
483 printf("linked to OpenSSL version: %s\n",
484 SSLeay_version(SSLEAY_VERSION));
485 #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
486 #endif
487 #ifdef HAVE_LIBXML2
488 printf("compiled with libxml2 version: %s\n", LIBXML_DOTTED_VERSION);
489 printf("linked to libxml2 version: %s\n", xmlParserVersion);
490 #endif
491 #if defined(HAVE_JSON) && defined(JSON_C_VERSION)
492 printf("compiled with libjson-c version: %s\n", JSON_C_VERSION);
493 printf("linked to libjson-c version: %s\n", json_c_version());
494 #endif
495 #if defined(HAVE_ZLIB) && defined(ZLIB_VERSION)
496 printf("compiled with zlib version: %s\n", ZLIB_VERSION);
497 printf("linked to zlib version: %s\n", zlibVersion());
498 #endif
499 #if defined(HAVE_GEOIP2)
500 /* Unfortunately, no version define on link time */
501 printf("linked to maxminddb version: %s\n",
502 MMDB_lib_version());
503 #endif
504 #if defined(HAVE_DNSTAP)
505 printf("compiled with protobuf-c version: %s\n",
506 PROTOBUF_C_VERSION);
507 printf("linked to protobuf-c version: %s\n",
508 protobuf_c_version());
509 #endif
510 #ifdef ISC_PLATFORM_USETHREADS
511 printf("threads support is enabled\n");
512 #else
513 printf("threads support is disabled\n");
514 #endif
515
516 /*
517 * The default rndc.conf and rndc.key paths are in the same
518 * directory, but named only has rndc.key defined internally.
519 * We construct the rndc.conf path from it. (We could use
520 * NAMED_SYSCONFDIR here but the result would look wrong on
521 * Windows.)
522 */
523 strlcpy(rndcconf, ns_g_keyfile, sizeof(rndcconf));
524 dot = strrchr(rndcconf, '.');
525 if (dot != NULL) {
526 size_t len = dot - rndcconf + 1;
527 snprintf(dot + 1, PATH_MAX - len, "conf");
528 }
529
530 #define RTC(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
531 RTC(isc_mem_create(0, 0, &mctx));
532 RTC(cfg_parser_create(mctx, ns_g_lctx, &parser));
533 RTC(ns_config_parsedefaults(parser, &config));
534 RTC(cfg_map_get(config, "options", &defaults));
535
536 /*
537 * Print default configuration paths.
538 */
539 printf("\n");
540 printf("default paths:\n");
541 printf(" named configuration: %s\n", ns_g_conffile);
542 printf(" rndc configuration: %s\n", rndcconf);
543 RTC(cfg_map_get(defaults, "bindkeys-file", &obj));
544 printf(" DNSSEC root key: %s\n", cfg_obj_asstring(obj));
545 printf(" nsupdate session key: %s\n", ns_g_defaultsessionkeyfile);
546 printf(" named PID file: %s\n", ns_g_defaultpidfile);
547 printf(" named lock file: %s\n", ns_g_defaultlockfile);
548 #if defined(HAVE_GEOIP2)
549 obj = NULL;
550 RTC(cfg_map_get(defaults, "geoip-directory", &obj));
551 if (cfg_obj_isstring(obj)) {
552 printf(" geoip-directory: %s\n", cfg_obj_asstring(obj));
553 }
554 #endif /* HAVE_GEOIP2 */
555 cfg_obj_destroy(parser, &config);
556 cfg_parser_destroy(&parser);
557 isc_mem_detach(&mctx);
558 }
559
560 static void
parse_fuzz_arg(void)561 parse_fuzz_arg(void) {
562 if (!strncmp(isc_commandline_argument, "client:", 7)) {
563 ns_g_fuzz_named_addr = isc_commandline_argument + 7;
564 ns_g_fuzz_type = ns_fuzz_client;
565 } else if (!strncmp(isc_commandline_argument, "tcp:", 4)) {
566 ns_g_fuzz_named_addr = isc_commandline_argument + 4;
567 ns_g_fuzz_type = ns_fuzz_tcpclient;
568 } else if (!strncmp(isc_commandline_argument, "resolver:", 9)) {
569 ns_g_fuzz_named_addr = isc_commandline_argument + 9;
570 ns_g_fuzz_type = ns_fuzz_resolver;
571 } else if (!strncmp(isc_commandline_argument, "http:", 5)) {
572 ns_g_fuzz_named_addr = isc_commandline_argument + 5;
573 ns_g_fuzz_type = ns_fuzz_http;
574 } else if (!strncmp(isc_commandline_argument, "rndc:", 5)) {
575 ns_g_fuzz_named_addr = isc_commandline_argument + 5;
576 ns_g_fuzz_type = ns_fuzz_rndc;
577 } else {
578 ns_main_earlyfatal("unknown fuzzing type '%s'",
579 isc_commandline_argument);
580 }
581 }
582
583 static void
parse_T_opt(char * option)584 parse_T_opt(char *option) {
585 const char *p;
586 /*
587 * force the server to behave (or misbehave) in
588 * specified ways for testing purposes.
589 *
590 * clienttest: make clients single shot with their
591 * own memory context.
592 * delay=xxxx: delay client responses by xxxx ms to
593 * simulate remote servers.
594 * dscp=x: check that dscp values are as
595 * expected and assert otherwise.
596 */
597 if (!strcmp(option, "clienttest")) {
598 ns_g_clienttest = true;
599 } else if (!strncmp(option, "delay=", 6)) {
600 ns_g_delay = atoi(option + 6);
601 } else if (!strcmp(option, "dropedns")) {
602 ns_g_dropedns = true;
603 } else if (!strncmp(option, "dscp=", 5)) {
604 isc_dscp_check_value = atoi(option + 5);
605 } else if (!strcmp(option, "ednsformerr")) {
606 ns_g_ednsformerr = true;
607 } else if (!strcmp(option, "ednsnotimp")) {
608 ns_g_ednsnotimp = true;
609 } else if (!strcmp(option, "ednsrefused")) {
610 ns_g_ednsrefused = true;
611 } else if (!strcmp(option, "fixedlocal")) {
612 ns_g_fixedlocal = true;
613 } else if (!strcmp(option, "keepstderr")) {
614 ns_g_keepstderr = true;
615 } else if (!strcmp(option, "noaa")) {
616 ns_g_noaa = true;
617 } else if (!strcmp(option, "noedns")) {
618 ns_g_noedns = true;
619 } else if (!strcmp(option, "nonearest")) {
620 ns_g_nonearest = true;
621 } else if (!strcmp(option, "nosoa")) {
622 ns_g_nosoa = true;
623 } else if (!strcmp(option, "nosyslog")) {
624 ns_g_nosyslog = true;
625 } else if (!strcmp(option, "notcp")) {
626 ns_g_notcp = true;
627 } else if (!strcmp(option, "maxudp512")) {
628 maxudp = 512;
629 } else if (!strcmp(option, "maxudp1460")) {
630 maxudp = 1460;
631 } else if (!strncmp(option, "maxudp=", 7)) {
632 maxudp = atoi(option + 7);
633 if (maxudp <= 0) {
634 ns_main_earlyfatal("bad maxudp");
635 }
636 } else if (!strncmp(option, "mkeytimers=", 11)) {
637 p = strtok(option + 11, "/");
638 if (p == NULL) {
639 ns_main_earlyfatal("bad mkeytimer");
640 }
641
642 dns_zone_mkey_hour = atoi(p);
643 if (dns_zone_mkey_hour == 0) {
644 ns_main_earlyfatal("bad mkeytimer");
645 }
646
647 p = strtok(NULL, "/");
648 if (p == NULL) {
649 dns_zone_mkey_day = (24 * dns_zone_mkey_hour);
650 dns_zone_mkey_month = (30 * dns_zone_mkey_day);
651 return;
652 }
653
654 dns_zone_mkey_day = atoi(p);
655 if (dns_zone_mkey_day < dns_zone_mkey_hour)
656 ns_main_earlyfatal("bad mkeytimer");
657
658 p = strtok(NULL, "/");
659 if (p == NULL) {
660 dns_zone_mkey_month = (30 * dns_zone_mkey_day);
661 return;
662 }
663
664 dns_zone_mkey_month = atoi(p);
665 if (dns_zone_mkey_month < dns_zone_mkey_day) {
666 ns_main_earlyfatal("bad mkeytimer");
667 }
668 } else if (!strcmp(option, "sigvalinsecs")) {
669 ns_g_sigvalinsecs = true;
670 } else if (!strncmp(option, "tat=", 4)) {
671 ns_g_tat_interval = atoi(option + 4);
672 } else {
673 fprintf(stderr, "unknown -T flag '%s'\n", option);
674 }
675 }
676
677 static void
parse_command_line(int argc,char * argv[])678 parse_command_line(int argc, char *argv[]) {
679 int ch;
680 int port;
681 const char *p;
682
683 save_command_line(argc, argv);
684
685 /*
686 * NS_MAIN_ARGS is defined in main.h, so that it can be used
687 * both by named and by ntservice hooks.
688 */
689 isc_commandline_errprint = false;
690 while ((ch = isc_commandline_parse(argc, argv, NS_MAIN_ARGS)) != -1) {
691 switch (ch) {
692 case '4':
693 if (ns_g_disable4)
694 ns_main_earlyfatal("cannot specify -4 and -6");
695 if (isc_net_probeipv4() != ISC_R_SUCCESS)
696 ns_main_earlyfatal("IPv4 not supported by OS");
697 isc_net_disableipv6();
698 ns_g_disable6 = true;
699 break;
700 case '6':
701 if (ns_g_disable6)
702 ns_main_earlyfatal("cannot specify -4 and -6");
703 if (isc_net_probeipv6() != ISC_R_SUCCESS)
704 ns_main_earlyfatal("IPv6 not supported by OS");
705 isc_net_disableipv4();
706 ns_g_disable4 = true;
707 break;
708 case 'A':
709 parse_fuzz_arg();
710 break;
711 case 'c':
712 ns_g_conffile = isc_commandline_argument;
713 lwresd_g_conffile = isc_commandline_argument;
714 if (lwresd_g_useresolvconf)
715 ns_main_earlyfatal("cannot specify -c and -C");
716 ns_g_conffileset = true;
717 break;
718 case 'C':
719 lwresd_g_resolvconffile = isc_commandline_argument;
720 if (ns_g_conffileset)
721 ns_main_earlyfatal("cannot specify -c and -C");
722 lwresd_g_useresolvconf = true;
723 break;
724 case 'd':
725 ns_g_debuglevel = parse_int(isc_commandline_argument,
726 "debug level");
727 break;
728 case 'D':
729 /* Descriptive comment for 'ps'. */
730 break;
731 case 'E':
732 ns_g_engine = isc_commandline_argument;
733 break;
734 case 'f':
735 ns_g_foreground = true;
736 break;
737 case 'g':
738 ns_g_foreground = true;
739 ns_g_logstderr = true;
740 break;
741 /* XXXBEW -i should be removed */
742 case 'i':
743 lwresd_g_defaultpidfile = isc_commandline_argument;
744 break;
745 case 'l':
746 ns_g_lwresdonly = true;
747 break;
748 case 'L':
749 ns_g_logfile = isc_commandline_argument;
750 break;
751 case 'M':
752 if (strcmp(isc_commandline_argument, "external") == 0)
753 isc_mem_defaultflags = 0;
754 break;
755 case 'm':
756 set_flags(isc_commandline_argument, mem_debug_flags,
757 &isc_mem_debugging);
758 break;
759 case 'N': /* Deprecated. */
760 case 'n':
761 ns_g_cpus = parse_int(isc_commandline_argument,
762 "number of cpus");
763 if (ns_g_cpus == 0)
764 ns_g_cpus = 1;
765 break;
766 case 'p':
767 port = parse_int(isc_commandline_argument, "port");
768 if (port < 1 || port > 65535)
769 ns_main_earlyfatal("port '%s' out of range",
770 isc_commandline_argument);
771 ns_g_port = port;
772 break;
773 /* XXXBEW Should -P be removed? */
774 case 'P':
775 port = parse_int(isc_commandline_argument, "port");
776 if (port < 1 || port > 65535)
777 ns_main_earlyfatal("port '%s' out of range",
778 isc_commandline_argument);
779 lwresd_g_listenport = port;
780 break;
781 case 's':
782 /* XXXRTH temporary syntax */
783 want_stats = true;
784 break;
785 case 'S':
786 maxsocks = parse_int(isc_commandline_argument,
787 "max number of sockets");
788 break;
789 case 't':
790 /* XXXJAB should we make a copy? */
791 ns_g_chrootdir = isc_commandline_argument;
792 break;
793 case 'T': /* NOT DOCUMENTED */
794 parse_T_opt(isc_commandline_argument);
795 break;
796 case 'U':
797 ns_g_udpdisp = parse_int(isc_commandline_argument,
798 "number of UDP listeners "
799 "per interface");
800 break;
801 case 'u':
802 ns_g_username = isc_commandline_argument;
803 break;
804 case 'v':
805 printversion(false);
806 exit(0);
807 case 'V':
808 printversion(true);
809 exit(0);
810 case 'x':
811 /* Obsolete. No longer in use. Ignore. */
812 break;
813 case 'X':
814 ns_g_forcelock = true;
815 if (strcasecmp(isc_commandline_argument, "none") != 0)
816 ns_g_defaultlockfile = isc_commandline_argument;
817 else
818 ns_g_defaultlockfile = NULL;
819 break;
820 case 'F':
821 /* Reserved for FIPS mode */
822 /* FALLTHROUGH */
823 case '?':
824 usage();
825 if (isc_commandline_option == '?')
826 exit(0);
827 p = strchr(NS_MAIN_ARGS, isc_commandline_option);
828 if (p == NULL || *++p != ':')
829 ns_main_earlyfatal("unknown option '-%c'",
830 isc_commandline_option);
831 else
832 ns_main_earlyfatal("option '-%c' requires "
833 "an argument",
834 isc_commandline_option);
835 /* FALLTHROUGH */
836 default:
837 ns_main_earlyfatal("parsing options returned %d", ch);
838 }
839 }
840
841 argc -= isc_commandline_index;
842 argv += isc_commandline_index;
843 POST(argv);
844
845 if (argc > 0) {
846 usage();
847 ns_main_earlyfatal("extra command line arguments");
848 }
849 }
850
851 static isc_result_t
create_managers(void)852 create_managers(void) {
853 isc_result_t result;
854 unsigned int socks;
855
856 INSIST(ns_g_cpus_detected > 0);
857
858 #ifdef ISC_PLATFORM_USETHREADS
859 if (ns_g_cpus == 0)
860 ns_g_cpus = ns_g_cpus_detected;
861 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
862 ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
863 ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s",
864 ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
865 #else
866 ns_g_cpus = 1;
867 #endif
868 #ifdef WIN32
869 ns_g_udpdisp = 1;
870 #else
871 if (ns_g_udpdisp == 0) {
872 if (ns_g_cpus_detected == 1)
873 ns_g_udpdisp = 1;
874 else
875 ns_g_udpdisp = ns_g_cpus_detected - 1;
876 }
877 if (ns_g_udpdisp > ns_g_cpus)
878 ns_g_udpdisp = ns_g_cpus;
879 #endif
880 #ifdef ISC_PLATFORM_USETHREADS
881 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
882 ISC_LOG_INFO, "using %u UDP listener%s per interface",
883 ns_g_udpdisp, ns_g_udpdisp == 1 ? "" : "s");
884 #endif
885
886 result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
887 if (result != ISC_R_SUCCESS) {
888 UNEXPECTED_ERROR(__FILE__, __LINE__,
889 "isc_taskmgr_create() failed: %s",
890 isc_result_totext(result));
891 return (ISC_R_UNEXPECTED);
892 }
893
894 result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
895 if (result != ISC_R_SUCCESS) {
896 UNEXPECTED_ERROR(__FILE__, __LINE__,
897 "isc_timermgr_create() failed: %s",
898 isc_result_totext(result));
899 return (ISC_R_UNEXPECTED);
900 }
901
902 result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks);
903 if (result != ISC_R_SUCCESS) {
904 UNEXPECTED_ERROR(__FILE__, __LINE__,
905 "isc_socketmgr_create() failed: %s",
906 isc_result_totext(result));
907 return (ISC_R_UNEXPECTED);
908 }
909 isc__socketmgr_maxudp(ns_g_socketmgr, maxudp);
910 result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks);
911 if (result == ISC_R_SUCCESS) {
912 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
913 NS_LOGMODULE_SERVER,
914 ISC_LOG_INFO, "using up to %u sockets", socks);
915 }
916
917 result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
918 if (result != ISC_R_SUCCESS) {
919 UNEXPECTED_ERROR(__FILE__, __LINE__,
920 "isc_entropy_create() failed: %s",
921 isc_result_totext(result));
922 return (ISC_R_UNEXPECTED);
923 }
924
925 result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
926 if (result != ISC_R_SUCCESS) {
927 UNEXPECTED_ERROR(__FILE__, __LINE__,
928 "isc_hash_create() failed: %s",
929 isc_result_totext(result));
930 return (ISC_R_UNEXPECTED);
931 }
932
933 return (ISC_R_SUCCESS);
934 }
935
936 static void
destroy_managers(void)937 destroy_managers(void) {
938 ns_lwresd_shutdown();
939
940 /*
941 * isc_taskmgr_destroy() will block until all tasks have exited,
942 */
943 isc_taskmgr_destroy(&ns_g_taskmgr);
944 isc_timermgr_destroy(&ns_g_timermgr);
945 isc_socketmgr_destroy(&ns_g_socketmgr);
946
947 /*
948 * isc_hash_destroy() cannot be called as long as a resolver may be
949 * running. Calling this after isc_taskmgr_destroy() ensures the
950 * call is safe.
951 */
952 isc_hash_destroy();
953 }
954
955 static void
dump_symboltable(void)956 dump_symboltable(void) {
957 int i;
958 isc_result_t result;
959 const char *fname;
960 const void *addr;
961
962 if (isc__backtrace_nsymbols == 0)
963 return;
964
965 if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99)))
966 return;
967
968 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
969 ISC_LOG_DEBUG(99), "Symbol table:");
970
971 for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) {
972 addr = NULL;
973 fname = NULL;
974 result = isc_backtrace_getsymbolfromindex(i, &addr, &fname);
975 if (result == ISC_R_SUCCESS) {
976 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
977 NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
978 "[%d] %p %s", i, addr, fname);
979 }
980 }
981 }
982
983 #ifdef HAVE_LIBSECCOMP
984 static void
setup_seccomp()985 setup_seccomp() {
986 scmp_filter_ctx ctx;
987 unsigned int i;
988 int ret;
989
990 /* Make sure the lists are in sync */
991 INSIST((sizeof(scmp_syscalls) / sizeof(int)) ==
992 (sizeof(scmp_syscall_names) / sizeof(const char *)));
993
994 ctx = seccomp_init(SCMP_ACT_KILL);
995 if (ctx == NULL) {
996 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
997 NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
998 "libseccomp activation failed");
999 return;
1000 }
1001
1002 for (i = 0 ; i < sizeof(scmp_syscalls)/sizeof(*(scmp_syscalls)); i++) {
1003 ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
1004 scmp_syscalls[i], 0);
1005 if (ret < 0)
1006 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1007 NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
1008 "libseccomp rule failed: %s",
1009 scmp_syscall_names[i]);
1010
1011 else
1012 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1013 NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(9),
1014 "added libseccomp rule: %s",
1015 scmp_syscall_names[i]);
1016 }
1017
1018 ret = seccomp_load(ctx);
1019 if (ret < 0) {
1020 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1021 NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
1022 "libseccomp unable to load filter");
1023 } else {
1024 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1025 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1026 "libseccomp sandboxing active");
1027 }
1028
1029 /*
1030 * Release filter in ctx. Filters already loaded are not
1031 * affected.
1032 */
1033 seccomp_release(ctx);
1034 }
1035 #endif /* HAVE_LIBSECCOMP */
1036
1037 static void
setup(void)1038 setup(void) {
1039 isc_result_t result;
1040 isc_resourcevalue_t old_openfiles;
1041 #ifdef HAVE_LIBSCF
1042 char *instance = NULL;
1043 #endif
1044
1045 /*
1046 * Get the user and group information before changing the root
1047 * directory, so the administrator does not need to keep a copy
1048 * of the user and group databases in the chroot'ed environment.
1049 */
1050 ns_os_inituserinfo(ns_g_username);
1051
1052 /*
1053 * Initialize time conversion information
1054 */
1055 ns_os_tzset();
1056
1057 ns_os_opendevnull();
1058
1059 #ifdef HAVE_LIBSCF
1060 /* Check if named is under smf control, before chroot. */
1061 result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
1062 /* We don't care about instance, just check if we got one. */
1063 if (result == ISC_R_SUCCESS)
1064 ns_smf_got_instance = 1;
1065 else
1066 ns_smf_got_instance = 0;
1067 if (instance != NULL)
1068 isc_mem_free(ns_g_mctx, instance);
1069 #endif /* HAVE_LIBSCF */
1070
1071 #ifdef PATH_RANDOMDEV
1072 /*
1073 * Initialize system's random device as fallback entropy source
1074 * if running chroot'ed.
1075 */
1076 if (ns_g_chrootdir != NULL) {
1077 result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
1078 if (result != ISC_R_SUCCESS)
1079 ns_main_earlyfatal("isc_entropy_create() failed: %s",
1080 isc_result_totext(result));
1081
1082 result = isc_entropy_createfilesource(ns_g_fallbackentropy,
1083 PATH_RANDOMDEV);
1084 if (result != ISC_R_SUCCESS) {
1085 ns_main_earlywarning("could not open pre-chroot "
1086 "entropy source %s: %s",
1087 PATH_RANDOMDEV,
1088 isc_result_totext(result));
1089 isc_entropy_detach(&ns_g_fallbackentropy);
1090 }
1091 }
1092 #endif
1093
1094 #ifdef ISC_PLATFORM_USETHREADS
1095 /*
1096 * Check for the number of cpu's before ns_os_chroot().
1097 */
1098 ns_g_cpus_detected = isc_os_ncpus();
1099 #endif
1100
1101 ns_os_chroot(ns_g_chrootdir);
1102
1103 /*
1104 * For operating systems which have a capability mechanism, now
1105 * is the time to switch to minimal privs and change our user id.
1106 * On traditional UNIX systems, this call will be a no-op, and we
1107 * will change the user ID after reading the config file the first
1108 * time. (We need to read the config file to know which possibly
1109 * privileged ports to bind() to.)
1110 */
1111 ns_os_minprivs();
1112
1113 result = ns_log_init((ns_g_username != NULL));
1114 if (result != ISC_R_SUCCESS)
1115 ns_main_earlyfatal("ns_log_init() failed: %s",
1116 isc_result_totext(result));
1117
1118 /*
1119 * Now is the time to daemonize (if we're not running in the
1120 * foreground). We waited until now because we wanted to get
1121 * a valid logging context setup. We cannot daemonize any later,
1122 * because calling create_managers() will create threads, which
1123 * would be lost after fork().
1124 */
1125 if (!ns_g_foreground)
1126 ns_os_daemonize();
1127
1128 /*
1129 * We call isc_app_start() here as some versions of FreeBSD's fork()
1130 * destroys all the signal handling it sets up.
1131 */
1132 result = isc_app_start();
1133 if (result != ISC_R_SUCCESS)
1134 ns_main_earlyfatal("isc_app_start() failed: %s",
1135 isc_result_totext(result));
1136
1137 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1138 ISC_LOG_NOTICE, "starting %s %s%s%s <id:%s>",
1139 ns_g_product, ns_g_version,
1140 *ns_g_description ? " " : "", ns_g_description,
1141 ns_g_srcid);
1142
1143 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1144 ISC_LOG_NOTICE, "running on %s", ns_os_uname());
1145
1146 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1147 ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
1148
1149 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1150 ISC_LOG_NOTICE, "running as: %s%s",
1151 program_name, saved_command_line);
1152 #ifdef __clang__
1153 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1154 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1155 "compiled by CLANG %s", __VERSION__);
1156 #else
1157 #if defined(__ICC) || defined(__INTEL_COMPILER)
1158 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1159 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1160 "compiled by ICC %s", __VERSION__);
1161 #else
1162 #ifdef __GNUC__
1163 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1164 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1165 "compiled by GCC %s", __VERSION__);
1166 #endif
1167 #endif
1168 #endif
1169 #ifdef _MSC_VER
1170 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1171 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1172 "compiled by MSVC %d", _MSC_VER);
1173 #endif
1174 #ifdef __SUNPRO_C
1175 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1176 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1177 "compiled by Solaris Studio %x", __SUNPRO_C);
1178 #endif
1179 #ifdef OPENSSL
1180 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1181 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1182 "compiled with OpenSSL version: %s",
1183 OPENSSL_VERSION_TEXT);
1184 #if !defined(LIBRESSL_VERSION_NUMBER) && \
1185 OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 or higher */
1186 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1187 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1188 "linked to OpenSSL version: %s",
1189 OpenSSL_version(OPENSSL_VERSION));
1190 #else
1191 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1192 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1193 "linked to OpenSSL version: %s",
1194 SSLeay_version(SSLEAY_VERSION));
1195 #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
1196 #endif
1197 #ifdef HAVE_LIBXML2
1198 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1199 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1200 "compiled with libxml2 version: %s",
1201 LIBXML_DOTTED_VERSION);
1202 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1203 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1204 "linked to libxml2 version: %s", xmlParserVersion);
1205 #endif
1206 #if defined(HAVE_JSON) && defined(JSON_C_VERSION)
1207 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1208 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1209 "compiled with libjson-c version: %s", JSON_C_VERSION);
1210 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1211 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1212 "linked to libjson-c version: %s", json_c_version());
1213 #endif
1214 #if defined(HAVE_ZLIB) && defined(ZLIB_VERSION)
1215 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1216 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1217 "compiled with zlib version: %s", ZLIB_VERSION);
1218 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1219 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1220 "linked to zlib version: %s", zlibVersion());
1221 #endif
1222 #ifdef ISC_PLATFORM_USETHREADS
1223 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1224 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1225 "threads support is enabled");
1226 #else
1227 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1228 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1229 "threads support is disabled");
1230 #endif
1231
1232 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1233 ISC_LOG_NOTICE,
1234 "----------------------------------------------------");
1235 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1236 ISC_LOG_NOTICE,
1237 "BIND 9 is maintained by Internet Systems Consortium,");
1238 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1239 ISC_LOG_NOTICE,
1240 "Inc. (ISC), a non-profit 501(c)(3) public-benefit ");
1241 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1242 ISC_LOG_NOTICE,
1243 "corporation. Support and training for BIND 9 are ");
1244 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1245 ISC_LOG_NOTICE,
1246 "available at https://www.isc.org/support");
1247 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1248 ISC_LOG_NOTICE,
1249 "----------------------------------------------------");
1250
1251 dump_symboltable();
1252
1253 /*
1254 * Get the initial resource limits.
1255 */
1256 (void)isc_resource_getlimit(isc_resource_stacksize,
1257 &ns_g_initstacksize);
1258 (void)isc_resource_getlimit(isc_resource_datasize,
1259 &ns_g_initdatasize);
1260 (void)isc_resource_getlimit(isc_resource_coresize,
1261 &ns_g_initcoresize);
1262 (void)isc_resource_getlimit(isc_resource_openfiles,
1263 &ns_g_initopenfiles);
1264
1265 /*
1266 * System resources cannot effectively be tuned on some systems.
1267 * Raise the limit in such cases for safety.
1268 */
1269 old_openfiles = ns_g_initopenfiles;
1270 ns_os_adjustnofile();
1271 (void)isc_resource_getlimit(isc_resource_openfiles,
1272 &ns_g_initopenfiles);
1273 if (old_openfiles != ns_g_initopenfiles) {
1274 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1275 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1276 "adjusted limit on open files from "
1277 "%" PRIu64 " to "
1278 "%" PRIu64,
1279 old_openfiles, ns_g_initopenfiles);
1280 }
1281
1282 /*
1283 * If the named configuration filename is relative, prepend the current
1284 * directory's name before possibly changing to another directory.
1285 */
1286 if (! isc_file_isabsolute(ns_g_conffile)) {
1287 result = isc_file_absolutepath(ns_g_conffile,
1288 absolute_conffile,
1289 sizeof(absolute_conffile));
1290 if (result != ISC_R_SUCCESS)
1291 ns_main_earlyfatal("could not construct absolute path "
1292 "of configuration file: %s",
1293 isc_result_totext(result));
1294 ns_g_conffile = absolute_conffile;
1295 }
1296
1297 /*
1298 * Record the server's startup time.
1299 */
1300 result = isc_time_now(&ns_g_boottime);
1301 if (result != ISC_R_SUCCESS)
1302 ns_main_earlyfatal("isc_time_now() failed: %s",
1303 isc_result_totext(result));
1304
1305 result = create_managers();
1306 if (result != ISC_R_SUCCESS)
1307 ns_main_earlyfatal("create_managers() failed: %s",
1308 isc_result_totext(result));
1309
1310 ns_builtin_init();
1311
1312 /*
1313 * Add calls to register sdb drivers here.
1314 */
1315 /* xxdb_init(); */
1316
1317 #ifdef ISC_DLZ_DLOPEN
1318 /*
1319 * Register the DLZ "dlopen" driver.
1320 */
1321 result = dlz_dlopen_init(ns_g_mctx);
1322 if (result != ISC_R_SUCCESS)
1323 ns_main_earlyfatal("dlz_dlopen_init() failed: %s",
1324 isc_result_totext(result));
1325 #endif
1326
1327 #if CONTRIB_DLZ
1328 /*
1329 * Register any other contributed DLZ drivers.
1330 */
1331 result = dlz_drivers_init();
1332 if (result != ISC_R_SUCCESS)
1333 ns_main_earlyfatal("dlz_drivers_init() failed: %s",
1334 isc_result_totext(result));
1335 #endif
1336
1337 ns_server_create(ns_g_mctx, &ns_g_server);
1338
1339 #ifdef HAVE_LIBSECCOMP
1340 setup_seccomp();
1341 #endif /* HAVE_LIBSECCOMP */
1342 }
1343
1344 static void
cleanup(void)1345 cleanup(void) {
1346 destroy_managers();
1347
1348 if (ns_g_mapped != NULL)
1349 dns_acl_detach(&ns_g_mapped);
1350
1351 ns_server_destroy(&ns_g_server);
1352
1353 isc_entropy_detach(&ns_g_entropy);
1354 if (ns_g_fallbackentropy != NULL)
1355 isc_entropy_detach(&ns_g_fallbackentropy);
1356
1357 ns_builtin_deinit();
1358
1359 /*
1360 * Add calls to unregister sdb drivers here.
1361 */
1362 /* xxdb_clear(); */
1363
1364 #ifdef CONTRIB_DLZ
1365 /*
1366 * Unregister contributed DLZ drivers.
1367 */
1368 dlz_drivers_clear();
1369 #endif
1370 #ifdef ISC_DLZ_DLOPEN
1371 /*
1372 * Unregister "dlopen" DLZ driver.
1373 */
1374 dlz_dlopen_clear();
1375 #endif
1376
1377 dns_name_destroy();
1378
1379 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1380 ISC_LOG_NOTICE, "exiting");
1381 ns_log_shutdown();
1382 }
1383
1384 static char *memstats = NULL;
1385
1386 void
ns_main_setmemstats(const char * filename)1387 ns_main_setmemstats(const char *filename) {
1388 /*
1389 * Caller has to ensure locking.
1390 */
1391
1392 if (memstats != NULL) {
1393 free(memstats);
1394 memstats = NULL;
1395 }
1396
1397 if (filename == NULL)
1398 return;
1399
1400 memstats = strdup(filename);
1401 }
1402
1403 #ifdef HAVE_LIBSCF
1404 /*
1405 * Get FMRI for the named process.
1406 */
1407 isc_result_t
ns_smf_get_instance(char ** ins_name,int debug,isc_mem_t * mctx)1408 ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
1409 scf_handle_t *h = NULL;
1410 int namelen;
1411 char *instance;
1412
1413 REQUIRE(ins_name != NULL && *ins_name == NULL);
1414
1415 if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
1416 if (debug)
1417 UNEXPECTED_ERROR(__FILE__, __LINE__,
1418 "scf_handle_create() failed: %s",
1419 scf_strerror(scf_error()));
1420 return (ISC_R_FAILURE);
1421 }
1422
1423 if (scf_handle_bind(h) == -1) {
1424 if (debug)
1425 UNEXPECTED_ERROR(__FILE__, __LINE__,
1426 "scf_handle_bind() failed: %s",
1427 scf_strerror(scf_error()));
1428 scf_handle_destroy(h);
1429 return (ISC_R_FAILURE);
1430 }
1431
1432 if ((namelen = scf_myname(h, NULL, 0)) == -1) {
1433 if (debug)
1434 UNEXPECTED_ERROR(__FILE__, __LINE__,
1435 "scf_myname() failed: %s",
1436 scf_strerror(scf_error()));
1437 scf_handle_destroy(h);
1438 return (ISC_R_FAILURE);
1439 }
1440
1441 if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
1442 UNEXPECTED_ERROR(__FILE__, __LINE__,
1443 "ns_smf_get_instance memory "
1444 "allocation failed: %s",
1445 isc_result_totext(ISC_R_NOMEMORY));
1446 scf_handle_destroy(h);
1447 return (ISC_R_FAILURE);
1448 }
1449
1450 if (scf_myname(h, instance, namelen + 1) == -1) {
1451 if (debug)
1452 UNEXPECTED_ERROR(__FILE__, __LINE__,
1453 "scf_myname() failed: %s",
1454 scf_strerror(scf_error()));
1455 scf_handle_destroy(h);
1456 isc_mem_free(mctx, instance);
1457 return (ISC_R_FAILURE);
1458 }
1459
1460 scf_handle_destroy(h);
1461 *ins_name = instance;
1462 return (ISC_R_SUCCESS);
1463 }
1464 #endif /* HAVE_LIBSCF */
1465
1466 /* main entry point, possibly hooked */
1467
1468 int
main(int argc,char * argv[])1469 main(int argc, char *argv[]) {
1470 isc_result_t result;
1471 #ifdef HAVE_LIBSCF
1472 char *instance = NULL;
1473 #endif
1474
1475 #ifdef HAVE_GPERFTOOLS_PROFILER
1476 (void) ProfilerStart(NULL);
1477 #endif
1478
1479 #ifdef WIN32
1480 /*
1481 * Prevent unbuffered I/O from crippling named performance on Windows
1482 * when it is logging to stderr (e.g. in system tests). Use full
1483 * buffering (_IOFBF) as line buffering (_IOLBF) is unavailable on
1484 * Windows and fflush() is called anyway after each log message gets
1485 * written to the default stderr logging channels created by libisc.
1486 */
1487 setvbuf(stderr, NULL, _IOFBF, BUFSIZ);
1488 #endif
1489
1490 #ifdef HAVE_LIBXML2
1491 xmlInitThreads();
1492 #endif /* HAVE_LIBXML2 */
1493
1494 /*
1495 * Record version in core image.
1496 * strings named.core | grep "named version:"
1497 */
1498 strlcat(version,
1499 #if defined(NO_VERSION_DATE) || !defined(__DATE__)
1500 "named version: BIND " VERSION " <" SRCID ">",
1501 #else
1502 "named version: BIND " VERSION " <" SRCID "> (" __DATE__ ")",
1503 #endif
1504 sizeof(version));
1505 result = isc_file_progname(*argv, program_name, sizeof(program_name));
1506 if (result != ISC_R_SUCCESS)
1507 ns_main_earlyfatal("program name too long");
1508
1509 if (strcmp(program_name, "lwresd") == 0)
1510 ns_g_lwresdonly = true;
1511
1512 isc_assertion_setcallback(assertion_failed);
1513 isc_error_setfatal(library_fatal_error);
1514 isc_error_setunexpected(library_unexpected_error);
1515
1516 ns_os_init(program_name);
1517
1518 dns_result_register();
1519 dst_result_register();
1520 isccc_result_register();
1521 #ifdef PKCS11CRYPTO
1522 pk11_result_register();
1523 #endif
1524
1525 parse_command_line(argc, argv);
1526
1527 #ifdef ENABLE_AFL
1528 if (ns_g_fuzz_type != ns_fuzz_none) {
1529 named_fuzz_setup();
1530 }
1531
1532 if (ns_g_fuzz_type == ns_fuzz_resolver) {
1533 dns_resolver_setfuzzing();
1534 } else if (ns_g_fuzz_type == ns_fuzz_http) {
1535 isc_httpd_setfinishhook(named_fuzz_notify);
1536 }
1537 #endif
1538 /*
1539 * Warn about common configuration error.
1540 */
1541 if (ns_g_chrootdir != NULL) {
1542 int len = strlen(ns_g_chrootdir);
1543 if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 &&
1544 (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\'))
1545 ns_main_earlywarning("config filename (-c %s) contains "
1546 "chroot path (-t %s)",
1547 ns_g_conffile, ns_g_chrootdir);
1548 }
1549
1550 result = isc_mem_create(0, 0, &ns_g_mctx);
1551 if (result != ISC_R_SUCCESS)
1552 ns_main_earlyfatal("isc_mem_create() failed: %s",
1553 isc_result_totext(result));
1554 isc_mem_setname(ns_g_mctx, "main", NULL);
1555
1556 setup();
1557
1558 /*
1559 * Start things running and then wait for a shutdown request
1560 * or reload.
1561 */
1562 do {
1563 result = isc_app_run();
1564
1565 if (result == ISC_R_RELOAD) {
1566 ns_server_reloadwanted(ns_g_server);
1567 } else if (result != ISC_R_SUCCESS) {
1568 UNEXPECTED_ERROR(__FILE__, __LINE__,
1569 "isc_app_run(): %s",
1570 isc_result_totext(result));
1571 /*
1572 * Force exit.
1573 */
1574 result = ISC_R_SUCCESS;
1575 }
1576 } while (result != ISC_R_SUCCESS);
1577
1578 #ifdef HAVE_LIBSCF
1579 if (ns_smf_want_disable == 1) {
1580 result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
1581 if (result == ISC_R_SUCCESS && instance != NULL) {
1582 if (smf_disable_instance(instance, 0) != 0)
1583 UNEXPECTED_ERROR(__FILE__, __LINE__,
1584 "smf_disable_instance() "
1585 "failed for %s : %s",
1586 instance,
1587 scf_strerror(scf_error()));
1588 }
1589 if (instance != NULL)
1590 isc_mem_free(ns_g_mctx, instance);
1591 }
1592 #endif /* HAVE_LIBSCF */
1593
1594 cleanup();
1595
1596 if (want_stats) {
1597 isc_mem_stats(ns_g_mctx, stdout);
1598 isc_mutex_stats(stdout);
1599 }
1600
1601 if (ns_g_memstatistics && memstats != NULL) {
1602 FILE *fp = NULL;
1603 result = isc_stdio_open(memstats, "w", &fp);
1604 if (result == ISC_R_SUCCESS) {
1605 isc_mem_stats(ns_g_mctx, fp);
1606 isc_mutex_stats(fp);
1607 (void) isc_stdio_close(fp);
1608 }
1609 }
1610 isc_mem_destroy(&ns_g_mctx);
1611 isc_mem_checkdestroyed(stderr);
1612
1613 ns_main_setmemstats(NULL);
1614
1615 isc_app_finish();
1616
1617 ns_os_closedevnull();
1618
1619 ns_os_shutdown();
1620
1621 #ifdef HAVE_LIBXML2
1622 xmlCleanupThreads();
1623 #endif /* HAVE_LIBXML2 */
1624
1625 #ifdef HAVE_GPERFTOOLS_PROFILER
1626 ProfilerStop();
1627 #endif
1628
1629 return (0);
1630 }
1631