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