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