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