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