summaryrefslogtreecommitdiffstats
path: root/bin/named/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/named/main.c')
-rw-r--r--bin/named/main.c1663
1 files changed, 1663 insertions, 0 deletions
diff --git a/bin/named/main.c b/bin/named/main.c
new file mode 100644
index 0000000..154e17e
--- /dev/null
+++ b/bin/named/main.c
@@ -0,0 +1,1663 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <uv.h>
+
+#ifdef HAVE_DNSTAP
+#include <protobuf-c/protobuf-c.h>
+#endif
+
+#include <isc/app.h>
+#include <isc/attributes.h>
+#include <isc/backtrace.h>
+#include <isc/commandline.h>
+#include <isc/dir.h>
+#include <isc/file.h>
+#include <isc/hash.h>
+#include <isc/httpd.h>
+#include <isc/managers.h>
+#include <isc/netmgr.h>
+#include <isc/os.h>
+#include <isc/print.h>
+#include <isc/resource.h>
+#include <isc/result.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/dispatch.h>
+#include <dns/dyndb.h>
+#include <dns/name.h>
+#include <dns/resolver.h>
+#include <dns/view.h>
+
+#include <dlz/dlz_dlopen_driver.h>
+
+#ifdef HAVE_GPERFTOOLS_PROFILER
+#include <gperftools/profiler.h>
+#endif /* ifdef HAVE_GPERFTOOLS_PROFILER */
+
+#ifdef HAVE_JSON_C
+#include <json_c_version.h>
+#endif /* HAVE_JSON_C */
+
+#ifdef HAVE_GEOIP2
+#include <maxminddb.h>
+#endif /* ifdef HAVE_GEOIP2 */
+
+/*
+ * Defining NAMED_MAIN provides storage declarations (rather than extern)
+ * for variables in named/globals.h.
+ */
+#define NAMED_MAIN 1
+
+#include <ns/interfacemgr.h>
+
+#include <named/builtin.h>
+#include <named/config.h>
+#include <named/control.h>
+#include <named/fuzz.h>
+#include <named/globals.h> /* Explicit, though named/log.h includes it. */
+#include <named/log.h>
+#include <named/main.h>
+#include <named/os.h>
+#include <named/server.h>
+#ifdef HAVE_LIBSCF
+#include <named/smf_globals.h>
+#endif /* ifdef HAVE_LIBSCF */
+
+#include <openssl/crypto.h>
+#include <openssl/opensslv.h>
+#ifdef HAVE_LIBXML2
+#include <libxml/parser.h>
+#include <libxml/xmlversion.h>
+#endif /* ifdef HAVE_LIBXML2 */
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif /* ifdef HAVE_ZLIB */
+#ifdef HAVE_LIBNGHTTP2
+#include <nghttp2/nghttp2.h>
+#endif
+/*
+ * Include header files for database drivers here.
+ */
+/* #include "xxdb.h" */
+
+/*
+ * The maximum number of stack frames to dump on assertion failure.
+ */
+#ifndef BACKTRACE_MAXFRAME
+#define BACKTRACE_MAXFRAME 128
+#endif /* ifndef BACKTRACE_MAXFRAME */
+
+extern unsigned int dns_zone_mkey_hour;
+extern unsigned int dns_zone_mkey_day;
+extern unsigned int dns_zone_mkey_month;
+
+static bool want_stats = false;
+static char program_name[NAME_MAX] = "named";
+static char absolute_conffile[PATH_MAX];
+static char saved_command_line[4096] = { 0 };
+static char ellipsis[5] = { 0 };
+static char version[512];
+static int maxudp = 0;
+
+/*
+ * -T options:
+ */
+static bool dropedns = false;
+static bool ednsformerr = false;
+static bool ednsnotimp = false;
+static bool ednsrefused = false;
+static bool fixedlocal = false;
+static bool noaa = false;
+static bool noedns = false;
+static bool nonearest = false;
+static bool nosoa = false;
+static bool notcp = false;
+static bool sigvalinsecs = false;
+static bool transferinsecs = false;
+static bool transferslowly = false;
+static bool transferstuck = false;
+
+/*
+ * -4 and -6
+ */
+static bool disable6 = false;
+static bool disable4 = false;
+
+void
+named_main_earlywarning(const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ if (named_g_lctx != NULL) {
+ isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_WARNING, format,
+ args);
+ } else {
+ fprintf(stderr, "%s: ", program_name);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+ va_end(args);
+}
+
+void
+named_main_earlyfatal(const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ if (named_g_lctx != NULL) {
+ isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, format,
+ args);
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ "exiting (due to early fatal error)");
+ } else {
+ fprintf(stderr, "%s: ", program_name);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+ va_end(args);
+
+ exit(1);
+}
+
+noreturn static void
+assertion_failed(const char *file, int line, isc_assertiontype_t type,
+ const char *cond);
+
+static void
+assertion_failed(const char *file, int line, isc_assertiontype_t type,
+ const char *cond) {
+ void *tracebuf[BACKTRACE_MAXFRAME];
+ int nframes;
+
+ /*
+ * Handle assertion failures.
+ */
+
+ if (named_g_lctx != NULL) {
+ /*
+ * Reset the assertion callback in case it is the log
+ * routines causing the assertion.
+ */
+ isc_assertion_setcallback(NULL);
+
+ nframes = isc_backtrace(tracebuf, BACKTRACE_MAXFRAME);
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ "%s:%d: %s(%s) failed%s", file, line,
+ isc_assertion_typetotext(type), cond,
+ (nframes > 0) ? ", back trace" : "");
+ if (nframes > 0) {
+ char **strs = isc_backtrace_symbols(tracebuf, nframes);
+ if (strs != NULL) {
+ for (int i = 0; i < nframes; i++) {
+ isc_log_write(named_g_lctx,
+ NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN,
+ ISC_LOG_CRITICAL, "%s",
+ strs[i]);
+ }
+ }
+ }
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ "exiting (due to assertion failure)");
+ } else {
+ fprintf(stderr, "%s:%d: %s(%s) failed\n", file, line,
+ isc_assertion_typetotext(type), cond);
+ fflush(stderr);
+ }
+
+ if (named_g_coreok) {
+ abort();
+ }
+ exit(1);
+}
+
+noreturn static void
+library_fatal_error(const char *file, int line, const char *func,
+ const char *format, va_list args) ISC_FORMAT_PRINTF(3, 0);
+
+static void
+library_fatal_error(const char *file, int line, const char *func,
+ const char *format, va_list args) {
+ /*
+ * Handle isc_error_fatal() calls from our libraries.
+ */
+
+ if (named_g_lctx != NULL) {
+ /*
+ * Reset the error callback in case it is the log
+ * routines causing the assertion.
+ */
+ isc_error_setfatal(NULL);
+
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ "%s:%d:%s(): fatal error: ", file, line, func);
+ isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, format,
+ args);
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ "exiting (due to fatal error in library)");
+ } else {
+ fprintf(stderr, "%s:%d:%s(): fatal error: ", file, line, func);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+
+ if (named_g_coreok) {
+ abort();
+ }
+ exit(1);
+}
+
+static void
+library_unexpected_error(const char *file, int line, const char *func,
+ const char *format, va_list args)
+ ISC_FORMAT_PRINTF(3, 0);
+
+static void
+library_unexpected_error(const char *file, int line, const char *func,
+ const char *format, va_list args) {
+ /*
+ * Handle isc_error_unexpected() calls from our libraries.
+ */
+
+ if (named_g_lctx != NULL) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR,
+ "%s:%d:%s(): unexpected error: ", file, line,
+ func);
+ isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR, format,
+ args);
+ } else {
+ fprintf(stderr, "%s:%d:%s(): fatal error: ", file, line, func);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+}
+
+static void
+usage(void) {
+ fprintf(stderr, "usage: named [-4|-6] [-c conffile] [-d debuglevel] "
+ "[-D comment] [-E engine]\n"
+ " [-f|-g] [-L logfile] [-n number_of_cpus] "
+ "[-p port] [-s]\n"
+ " [-S sockets] [-t chrootdir] [-u "
+ "username] [-U listeners]\n"
+ " [-X lockfile] [-m "
+ "{usage|trace|record|size|mctx}]\n"
+ " [-M fill|nofill]\n"
+ "usage: named [-v|-V|-C]\n");
+}
+
+static void
+save_command_line(int argc, char *argv[]) {
+ int i;
+ char *dst = saved_command_line;
+ char *eob = saved_command_line + sizeof(saved_command_line) - 1;
+ char *rollback = dst;
+
+ for (i = 1; i < argc && dst < eob; i++) {
+ char *src = argv[i];
+ bool quoted = false;
+
+ rollback = dst;
+ *dst++ = ' ';
+
+ while (*src != '\0' && dst < eob) {
+ if (isalnum(*(unsigned char *)src) || *src == ',' ||
+ *src == '-' || *src == '_' || *src == '.' ||
+ *src == '/')
+ {
+ *dst++ = *src++;
+ } else if (isprint(*(unsigned char *)src)) {
+ if (dst + 2 >= eob) {
+ goto add_ellipsis;
+ }
+ *dst++ = '\\';
+ *dst++ = *src++;
+ } else {
+ /*
+ * Control character found in the input,
+ * quote the whole arg and restart
+ */
+ if (!quoted) {
+ dst = rollback;
+ src = argv[i];
+
+ if (dst + 3 >= eob) {
+ goto add_ellipsis;
+ }
+
+ *dst++ = ' ';
+ *dst++ = '$';
+ *dst++ = '\'';
+
+ quoted = true;
+ continue;
+ } else {
+ char tmp[5];
+ int c = snprintf(tmp, sizeof(tmp),
+ "\\%03o", *src++);
+ if (dst + c >= eob) {
+ goto add_ellipsis;
+ }
+ memmove(dst, tmp, c);
+ dst += c;
+ }
+ }
+ }
+ if (quoted) {
+ if (dst == eob) {
+ goto add_ellipsis;
+ }
+ *dst++ = '\'';
+ }
+ }
+
+ if (dst < eob) {
+ return;
+ }
+add_ellipsis:
+ dst = rollback;
+ *dst = '\0';
+ strlcpy(ellipsis, " ...", sizeof(ellipsis));
+}
+
+static int
+parse_int(char *arg, const char *desc) {
+ char *endp;
+ int tmp;
+ long int ltmp;
+
+ ltmp = strtol(arg, &endp, 10);
+ tmp = (int)ltmp;
+ if (*endp != '\0') {
+ named_main_earlyfatal("%s '%s' must be numeric", desc, arg);
+ }
+ if (tmp < 0 || tmp != ltmp) {
+ named_main_earlyfatal("%s '%s' out of range", desc, arg);
+ }
+ return (tmp);
+}
+
+static struct flag_def {
+ const char *name;
+ unsigned int value;
+ bool negate;
+} mem_debug_flags[] = { { "none", 0, false },
+ { "trace", ISC_MEM_DEBUGTRACE, false },
+ { "record", ISC_MEM_DEBUGRECORD, false },
+ { "usage", ISC_MEM_DEBUGUSAGE, false },
+ { NULL, 0, false } },
+ mem_context_flags[] = { { "fill", ISC_MEMFLAG_FILL, false },
+ { "nofill", ISC_MEMFLAG_FILL, true },
+ { NULL, 0, false } };
+
+static void
+set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
+ bool clear = false;
+
+ for (;;) {
+ const struct flag_def *def;
+ const char *end = strchr(arg, ',');
+ int arglen;
+ if (end == NULL) {
+ end = arg + strlen(arg);
+ }
+ arglen = (int)(end - arg);
+ for (def = defs; def->name != NULL; def++) {
+ if (arglen == (int)strlen(def->name) &&
+ memcmp(arg, def->name, arglen) == 0)
+ {
+ if (def->value == 0) {
+ clear = true;
+ }
+ if (def->negate) {
+ *ret &= ~(def->value);
+ } else {
+ *ret |= def->value;
+ }
+ goto found;
+ }
+ }
+ named_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
+ found:
+ if (clear || (*end == '\0')) {
+ break;
+ }
+ arg = end + 1;
+ }
+
+ if (clear) {
+ *ret = 0;
+ }
+}
+
+static void
+list_dnssec_algorithms(isc_buffer_t *b) {
+ for (dst_algorithm_t i = DST_ALG_UNKNOWN; i < DST_MAX_ALGS; i++) {
+ if (i == DST_ALG_DH || i == DST_ALG_GSSAPI ||
+ (i >= DST_ALG_HMAC_FIRST && i <= DST_ALG_HMAC_LAST))
+ {
+ continue;
+ }
+ if (dst_algorithm_supported(i)) {
+ isc_buffer_putstr(b, " ");
+ (void)dns_secalg_totext(i, b);
+ }
+ }
+}
+
+static void
+list_ds_algorithms(isc_buffer_t *b) {
+ for (size_t i = 0; i < 256; i++) {
+ if (dst_ds_digest_supported(i)) {
+ isc_buffer_putstr(b, " ");
+ (void)dns_dsdigest_totext(i, b);
+ }
+ }
+}
+
+static void
+list_hmac_algorithms(isc_buffer_t *b) {
+ isc_buffer_t sb = *b;
+ for (dst_algorithm_t i = DST_ALG_HMAC_FIRST; i <= DST_ALG_HMAC_LAST;
+ i++)
+ {
+ if (i == DST_ALG_GSSAPI) {
+ continue;
+ }
+ if (dst_algorithm_supported(i)) {
+ isc_buffer_putstr(b, " ");
+ isc_buffer_putstr(b, dst_hmac_algorithm_totext(i));
+ }
+ }
+ for (unsigned char *s = isc_buffer_used(&sb); s != isc_buffer_used(b);
+ s++)
+ {
+ *s = toupper(*s);
+ }
+}
+
+static void
+logit(isc_buffer_t *b) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, "%.*s",
+ (int)isc_buffer_usedlength(b),
+ (char *)isc_buffer_base(b));
+}
+
+static void
+printit(isc_buffer_t *b) {
+ printf("%.*s\n", (int)isc_buffer_usedlength(b),
+ (char *)isc_buffer_base(b));
+}
+
+static void
+format_supported_algorithms(void (*emit)(isc_buffer_t *b)) {
+ isc_buffer_t b;
+ char buf[512];
+
+ isc_buffer_init(&b, buf, sizeof(buf));
+ isc_buffer_putstr(&b, "DNSSEC algorithms:");
+ list_dnssec_algorithms(&b);
+ (*emit)(&b);
+
+ isc_buffer_init(&b, buf, sizeof(buf));
+ isc_buffer_putstr(&b, "DS algorithms:");
+ list_ds_algorithms(&b);
+ (*emit)(&b);
+
+ isc_buffer_init(&b, buf, sizeof(buf));
+ isc_buffer_putstr(&b, "HMAC algorithms:");
+ list_hmac_algorithms(&b);
+ (*emit)(&b);
+
+ isc_buffer_init(&b, buf, sizeof(buf));
+ isc_buffer_printf(&b, "TKEY mode 2 support (Diffie-Hellman): %s",
+ (dst_algorithm_supported(DST_ALG_DH) &&
+ dst_algorithm_supported(DST_ALG_HMACMD5))
+ ? "yes"
+ : "non");
+ (*emit)(&b);
+
+ isc_buffer_init(&b, buf, sizeof(buf));
+ isc_buffer_printf(&b, "TKEY mode 3 support (GSS-API): %s",
+ dst_algorithm_supported(DST_ALG_GSSAPI) ? "yes"
+ : "no");
+ (*emit)(&b);
+}
+
+static void
+printversion(bool verbose) {
+ char rndcconf[PATH_MAX], *dot = NULL;
+ isc_mem_t *mctx = NULL;
+ isc_result_t result;
+ isc_buffer_t b;
+ char buf[512];
+#if defined(HAVE_GEOIP2)
+ cfg_parser_t *parser = NULL;
+ cfg_obj_t *config = NULL;
+ const cfg_obj_t *defaults = NULL, *obj = NULL;
+#endif /* if defined(HAVE_GEOIP2) */
+
+ printf("%s%s <id:%s>\n", PACKAGE_STRING, PACKAGE_DESCRIPTION,
+ PACKAGE_SRCID);
+
+ if (!verbose) {
+ return;
+ }
+
+ printf("running on %s\n", named_os_uname());
+ printf("built by %s with %s\n", PACKAGE_BUILDER, PACKAGE_CONFIGARGS);
+#ifdef __clang__
+ printf("compiled by CLANG %s\n", __VERSION__);
+#else /* ifdef __clang__ */
+#if defined(__ICC) || defined(__INTEL_COMPILER)
+ printf("compiled by ICC %s\n", __VERSION__);
+#else /* if defined(__ICC) || defined(__INTEL_COMPILER) */
+#ifdef __GNUC__
+ printf("compiled by GCC %s\n", __VERSION__);
+#endif /* ifdef __GNUC__ */
+#endif /* if defined(__ICC) || defined(__INTEL_COMPILER) */
+#endif /* ifdef __clang__ */
+#ifdef _MSC_VER
+ printf("compiled by MSVC %d\n", _MSC_VER);
+#endif /* ifdef _MSC_VER */
+#ifdef __SUNPRO_C
+ printf("compiled by Solaris Studio %x\n", __SUNPRO_C);
+#endif /* ifdef __SUNPRO_C */
+ printf("compiled with OpenSSL version: %s\n", OPENSSL_VERSION_TEXT);
+#if !defined(LIBRESSL_VERSION_NUMBER) && \
+ OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 or higher */
+ printf("linked to OpenSSL version: %s\n",
+ OpenSSL_version(OPENSSL_VERSION));
+
+#else /* if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= \
+ * 0x10100000L */
+ printf("linked to OpenSSL version: %s\n",
+ SSLeay_version(SSLEAY_VERSION));
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
+ printf("compiled with libuv version: %d.%d.%d\n", UV_VERSION_MAJOR,
+ UV_VERSION_MINOR, UV_VERSION_PATCH);
+ printf("linked to libuv version: %s\n", uv_version_string());
+#if HAVE_LIBNGHTTP2
+ nghttp2_info *nginfo = NULL;
+ printf("compiled with libnghttp2 version: %s\n", NGHTTP2_VERSION);
+ nginfo = nghttp2_version(1);
+ printf("linked to libnghttp2 version: %s\n", nginfo->version_str);
+#endif
+#ifdef HAVE_LIBXML2
+ printf("compiled with libxml2 version: %s\n", LIBXML_DOTTED_VERSION);
+ printf("linked to libxml2 version: %s\n", xmlParserVersion);
+#endif /* ifdef HAVE_LIBXML2 */
+#if defined(HAVE_JSON_C)
+ printf("compiled with json-c version: %s\n", JSON_C_VERSION);
+ printf("linked to json-c version: %s\n", json_c_version());
+#endif /* if defined(HAVE_JSON_C) */
+#if defined(HAVE_ZLIB) && defined(ZLIB_VERSION)
+ printf("compiled with zlib version: %s\n", ZLIB_VERSION);
+ printf("linked to zlib version: %s\n", zlibVersion());
+#endif /* if defined(HAVE_ZLIB) && defined(ZLIB_VERSION) */
+#if defined(HAVE_GEOIP2)
+ /* Unfortunately, no version define on link time */
+ printf("linked to maxminddb version: %s\n", MMDB_lib_version());
+#endif /* if defined(HAVE_GEOIP2) */
+#if defined(HAVE_DNSTAP)
+ printf("compiled with protobuf-c version: %s\n", PROTOBUF_C_VERSION);
+ printf("linked to protobuf-c version: %s\n", protobuf_c_version());
+#endif /* if defined(HAVE_DNSTAP) */
+ printf("threads support is enabled\n");
+
+ isc_mem_create(&mctx);
+ result = dst_lib_init(mctx, named_g_engine);
+ if (result == ISC_R_SUCCESS) {
+ isc_buffer_init(&b, buf, sizeof(buf));
+ format_supported_algorithms(printit);
+ printf("\n");
+ dst_lib_destroy();
+ } else {
+ printf("DST initialization failure: %s\n",
+ isc_result_totext(result));
+ }
+
+ /*
+ * The default rndc.conf and rndc.key paths are in the same
+ * directory, but named only has rndc.key defined internally.
+ * We construct the rndc.conf path from it.
+ */
+ strlcpy(rndcconf, named_g_keyfile, sizeof(rndcconf));
+ dot = strrchr(rndcconf, '.');
+ if (dot != NULL) {
+ size_t len = dot - rndcconf + 1;
+ snprintf(dot + 1, PATH_MAX - len, "conf");
+ }
+
+ /*
+ * Print default configuration paths.
+ */
+ printf("default paths:\n");
+ printf(" named configuration: %s\n", named_g_conffile);
+ printf(" rndc configuration: %s\n", rndcconf);
+ printf(" DNSSEC root key: %s\n", named_g_defaultbindkeys);
+ printf(" nsupdate session key: %s\n", named_g_defaultsessionkeyfile);
+ printf(" named PID file: %s\n", named_g_defaultpidfile);
+ printf(" named lock file: %s\n", named_g_defaultlockfile);
+#if defined(HAVE_GEOIP2)
+#define RTC(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
+ RTC(cfg_parser_create(mctx, named_g_lctx, &parser));
+ RTC(named_config_parsedefaults(parser, &config));
+ RTC(cfg_map_get(config, "options", &defaults));
+ RTC(cfg_map_get(defaults, "geoip-directory", &obj));
+ if (cfg_obj_isstring(obj)) {
+ printf(" geoip-directory: %s\n", cfg_obj_asstring(obj));
+ }
+ cfg_obj_destroy(parser, &config);
+ cfg_parser_destroy(&parser);
+ isc_mem_detach(&mctx);
+#endif /* HAVE_GEOIP2 */
+}
+
+static void
+parse_fuzz_arg(void) {
+ if (!strncmp(isc_commandline_argument, "client:", 7)) {
+ named_g_fuzz_addr = isc_commandline_argument + 7;
+ named_g_fuzz_type = isc_fuzz_client;
+ } else if (!strncmp(isc_commandline_argument, "tcp:", 4)) {
+ named_g_fuzz_addr = isc_commandline_argument + 4;
+ named_g_fuzz_type = isc_fuzz_tcpclient;
+ } else if (!strncmp(isc_commandline_argument, "resolver:", 9)) {
+ named_g_fuzz_addr = isc_commandline_argument + 9;
+ named_g_fuzz_type = isc_fuzz_resolver;
+ } else if (!strncmp(isc_commandline_argument, "http:", 5)) {
+ named_g_fuzz_addr = isc_commandline_argument + 5;
+ named_g_fuzz_type = isc_fuzz_http;
+ } else if (!strncmp(isc_commandline_argument, "rndc:", 5)) {
+ named_g_fuzz_addr = isc_commandline_argument + 5;
+ named_g_fuzz_type = isc_fuzz_rndc;
+ } else {
+ named_main_earlyfatal("unknown fuzzing type '%s'",
+ isc_commandline_argument);
+ }
+}
+
+static void
+parse_T_opt(char *option) {
+ const char *p;
+ char *last = NULL;
+ /*
+ * force the server to behave (or misbehave) in
+ * specified ways for testing purposes.
+ */
+ if (!strcmp(option, "dropedns")) {
+ dropedns = true;
+ } else if (!strcmp(option, "ednsformerr")) {
+ ednsformerr = true;
+ } else if (!strcmp(option, "ednsnotimp")) {
+ ednsnotimp = true;
+ } else if (!strcmp(option, "ednsrefused")) {
+ ednsrefused = true;
+ } else if (!strcmp(option, "fixedlocal")) {
+ fixedlocal = true;
+ } else if (!strcmp(option, "keepstderr")) {
+ named_g_keepstderr = true;
+ } else if (!strcmp(option, "noaa")) {
+ noaa = true;
+ } else if (!strcmp(option, "noedns")) {
+ noedns = true;
+ } else if (!strcmp(option, "nonearest")) {
+ nonearest = true;
+ } else if (!strcmp(option, "nosoa")) {
+ nosoa = true;
+ } else if (!strcmp(option, "nosyslog")) {
+ named_g_nosyslog = true;
+ } else if (!strcmp(option, "notcp")) {
+ notcp = true;
+ } else if (!strncmp(option, "maxcachesize=", 13)) {
+ named_g_maxcachesize = atoi(option + 13);
+ } else if (!strcmp(option, "maxudp512")) {
+ maxudp = 512;
+ } else if (!strcmp(option, "maxudp1460")) {
+ maxudp = 1460;
+ } else if (!strncmp(option, "maxudp=", 7)) {
+ maxudp = atoi(option + 7);
+ if (maxudp <= 0) {
+ named_main_earlyfatal("bad maxudp");
+ }
+ } else if (!strncmp(option, "mkeytimers=", 11)) {
+ p = strtok_r(option + 11, "/", &last);
+ if (p == NULL) {
+ named_main_earlyfatal("bad mkeytimer");
+ }
+
+ dns_zone_mkey_hour = atoi(p);
+ if (dns_zone_mkey_hour == 0) {
+ named_main_earlyfatal("bad mkeytimer");
+ }
+
+ p = strtok_r(NULL, "/", &last);
+ if (p == NULL) {
+ dns_zone_mkey_day = (24 * dns_zone_mkey_hour);
+ dns_zone_mkey_month = (30 * dns_zone_mkey_day);
+ return;
+ }
+
+ dns_zone_mkey_day = atoi(p);
+ if (dns_zone_mkey_day < dns_zone_mkey_hour) {
+ named_main_earlyfatal("bad mkeytimer");
+ }
+
+ p = strtok_r(NULL, "/", &last);
+ if (p == NULL) {
+ dns_zone_mkey_month = (30 * dns_zone_mkey_day);
+ return;
+ }
+
+ dns_zone_mkey_month = atoi(p);
+ if (dns_zone_mkey_month < dns_zone_mkey_day) {
+ named_main_earlyfatal("bad mkeytimer");
+ }
+ } else if (!strcmp(option, "sigvalinsecs")) {
+ sigvalinsecs = true;
+ } else if (!strcmp(option, "transferinsecs")) {
+ transferinsecs = true;
+ } else if (!strcmp(option, "transferslowly")) {
+ transferslowly = true;
+ } else if (!strcmp(option, "transferstuck")) {
+ transferstuck = true;
+ } else if (!strncmp(option, "tat=", 4)) {
+ named_g_tat_interval = atoi(option + 4);
+ } else {
+ fprintf(stderr, "unknown -T flag '%s'\n", option);
+ }
+}
+
+static void
+parse_port(char *arg) {
+ enum { DNSPORT, TLSPORT, HTTPSPORT, HTTPPORT } ptype = DNSPORT;
+ char *value = arg;
+ int port;
+
+ if (strncmp(arg, "dns=", 4) == 0) {
+ value = arg + 4;
+ } else if (strncmp(arg, "tls=", 4) == 0) {
+ value = arg + 4;
+ ptype = TLSPORT;
+ } else if (strncmp(arg, "https=", 6) == 0) {
+ value = arg + 6;
+ ptype = HTTPSPORT;
+ } else if (strncmp(arg, "http=", 5) == 0) {
+ value = arg + 6;
+ ptype = HTTPPORT;
+ }
+
+ port = parse_int(value, "port");
+ if (port < 1 || port > 65535) {
+ named_main_earlyfatal("port '%s' out of range", value);
+ }
+
+ switch (ptype) {
+ case DNSPORT:
+ named_g_port = port;
+ break;
+ case TLSPORT:
+ named_g_tlsport = port;
+ break;
+ case HTTPSPORT:
+ named_g_httpsport = port;
+ break;
+ case HTTPPORT:
+ named_g_httpport = port;
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+static void
+parse_command_line(int argc, char *argv[]) {
+ int ch;
+ const char *p;
+
+ save_command_line(argc, argv);
+
+ /*
+ * NAMED_MAIN_ARGS is defined in main.h, so that it can be used
+ * both by named and by ntservice hooks.
+ */
+ isc_commandline_errprint = false;
+ while ((ch = isc_commandline_parse(argc, argv, NAMED_MAIN_ARGS)) != -1)
+ {
+ switch (ch) {
+ case '4':
+ if (disable4) {
+ named_main_earlyfatal("cannot specify "
+ "-4 and -6");
+ }
+ if (isc_net_probeipv4() != ISC_R_SUCCESS) {
+ named_main_earlyfatal("IPv4 not supported "
+ "by OS");
+ }
+ isc_net_disableipv6();
+ disable6 = true;
+ break;
+ case '6':
+ if (disable6) {
+ named_main_earlyfatal("cannot specify "
+ "-4 and -6");
+ }
+ if (isc_net_probeipv6() != ISC_R_SUCCESS) {
+ named_main_earlyfatal("IPv6 not supported "
+ "by OS");
+ }
+ isc_net_disableipv4();
+ disable4 = true;
+ break;
+ case 'A':
+ parse_fuzz_arg();
+ break;
+ case 'c':
+ named_g_conffile = isc_commandline_argument;
+ named_g_conffileset = true;
+ break;
+ case 'C':
+ printf("# Built-in default values. "
+ "This is NOT the run-time configuration!\n");
+ printf("%s", named_config_getdefault());
+ exit(0);
+ case 'd':
+ named_g_debuglevel = parse_int(isc_commandline_argument,
+ "debug "
+ "level");
+ break;
+ case 'D':
+ /* Descriptive comment for 'ps'. */
+ break;
+ case 'E':
+ named_g_engine = isc_commandline_argument;
+ break;
+ case 'f':
+ named_g_foreground = true;
+ break;
+ case 'g':
+ named_g_foreground = true;
+ named_g_logstderr = true;
+ break;
+ case 'L':
+ named_g_logfile = isc_commandline_argument;
+ break;
+ case 'M':
+ set_flags(isc_commandline_argument, mem_context_flags,
+ &isc_mem_defaultflags);
+ break;
+ case 'm':
+ set_flags(isc_commandline_argument, mem_debug_flags,
+ &isc_mem_debugging);
+ break;
+ case 'N': /* Deprecated. */
+ case 'n':
+ named_g_cpus = parse_int(isc_commandline_argument,
+ "number of cpus");
+ if (named_g_cpus == 0) {
+ named_g_cpus = 1;
+ }
+ break;
+ case 'p':
+ parse_port(isc_commandline_argument);
+ break;
+ case 's':
+ /* XXXRTH temporary syntax */
+ want_stats = true;
+ break;
+ case 'S':
+ /* Formerly maxsocks */
+ break;
+ case 't':
+ /* XXXJAB should we make a copy? */
+ named_g_chrootdir = isc_commandline_argument;
+ break;
+ case 'T': /* NOT DOCUMENTED */
+ parse_T_opt(isc_commandline_argument);
+ break;
+ case 'U':
+ named_g_udpdisp = parse_int(isc_commandline_argument,
+ "number of UDP listeners "
+ "per interface");
+ break;
+ case 'u':
+ named_g_username = isc_commandline_argument;
+ break;
+ case 'v':
+ printversion(false);
+ exit(0);
+ case 'V':
+ printversion(true);
+ exit(0);
+ case 'x':
+ /* Obsolete. No longer in use. Ignore. */
+ break;
+ case 'X':
+ named_g_forcelock = true;
+ if (strcasecmp(isc_commandline_argument, "none") != 0) {
+ named_g_defaultlockfile =
+ isc_commandline_argument;
+ } else {
+ named_g_defaultlockfile = NULL;
+ }
+ break;
+ case 'F':
+ /* Reserved for FIPS mode */
+ FALLTHROUGH;
+ case '?':
+ usage();
+ if (isc_commandline_option == '?') {
+ exit(0);
+ }
+ p = strchr(NAMED_MAIN_ARGS, isc_commandline_option);
+ if (p == NULL || *++p != ':') {
+ named_main_earlyfatal("unknown option '-%c'",
+ isc_commandline_option);
+ } else {
+ named_main_earlyfatal("option '-%c' requires "
+ "an argument",
+ isc_commandline_option);
+ }
+ FALLTHROUGH;
+ default:
+ named_main_earlyfatal("parsing options returned %d",
+ ch);
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+ POST(argv);
+
+ if (argc > 0) {
+ usage();
+ named_main_earlyfatal("extra command line arguments");
+ }
+}
+
+static isc_result_t
+create_managers(void) {
+ isc_result_t result;
+
+ INSIST(named_g_cpus_detected > 0);
+
+ if (named_g_cpus == 0) {
+ named_g_cpus = named_g_cpus_detected;
+ }
+ isc_log_write(
+ named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
+ ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
+ named_g_cpus_detected, named_g_cpus_detected == 1 ? "" : "s",
+ named_g_cpus, named_g_cpus == 1 ? "" : "s");
+ if (named_g_udpdisp == 0) {
+ named_g_udpdisp = named_g_cpus_detected;
+ }
+ if (named_g_udpdisp > named_g_cpus) {
+ named_g_udpdisp = named_g_cpus;
+ }
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
+ "using %u UDP listener%s per interface", named_g_udpdisp,
+ named_g_udpdisp == 1 ? "" : "s");
+
+ result = isc_managers_create(named_g_mctx, named_g_cpus,
+ 0 /* quantum */, &named_g_netmgr,
+ &named_g_taskmgr, &named_g_timermgr);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
+ isc_nm_maxudp(named_g_netmgr, maxudp);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+destroy_managers(void) {
+ isc_managers_destroy(&named_g_netmgr, &named_g_taskmgr,
+ &named_g_timermgr);
+}
+
+static void
+setup(void) {
+ isc_result_t result;
+ isc_resourcevalue_t old_openfiles;
+ ns_server_t *sctx;
+#ifdef HAVE_LIBSCF
+ char *instance = NULL;
+#endif /* ifdef HAVE_LIBSCF */
+
+ /*
+ * Get the user and group information before changing the root
+ * directory, so the administrator does not need to keep a copy
+ * of the user and group databases in the chroot'ed environment.
+ */
+ named_os_inituserinfo(named_g_username);
+
+ /*
+ * Initialize time conversion information
+ */
+ named_os_tzset();
+
+ named_os_opendevnull();
+
+#ifdef HAVE_LIBSCF
+ /* Check if named is under smf control, before chroot. */
+ result = named_smf_get_instance(&instance, 0, named_g_mctx);
+ /* We don't care about instance, just check if we got one. */
+ if (result == ISC_R_SUCCESS) {
+ named_smf_got_instance = 1;
+ } else {
+ named_smf_got_instance = 0;
+ }
+ if (instance != NULL) {
+ isc_mem_free(named_g_mctx, instance);
+ }
+#endif /* HAVE_LIBSCF */
+
+ /*
+ * Check for the number of cpu's before named_os_chroot().
+ */
+ named_g_cpus_detected = isc_os_ncpus();
+
+ named_os_chroot(named_g_chrootdir);
+
+ /*
+ * For operating systems which have a capability mechanism, now
+ * is the time to switch to minimal privs and change our user id.
+ * On traditional UNIX systems, this call will be a no-op, and we
+ * will change the user ID after reading the config file the first
+ * time. (We need to read the config file to know which possibly
+ * privileged ports to bind() to.)
+ */
+ named_os_minprivs();
+
+ result = named_log_init(named_g_username != NULL);
+ if (result != ISC_R_SUCCESS) {
+ named_main_earlyfatal("named_log_init() failed: %s",
+ isc_result_totext(result));
+ }
+
+ /*
+ * Now is the time to daemonize (if we're not running in the
+ * foreground). We waited until now because we wanted to get
+ * a valid logging context setup. We cannot daemonize any later,
+ * because calling create_managers() will create threads, which
+ * would be lost after fork().
+ */
+ if (!named_g_foreground) {
+ named_os_daemonize();
+ }
+
+ /*
+ * We call isc_app_start() here as some versions of FreeBSD's fork()
+ * destroys all the signal handling it sets up.
+ */
+ result = isc_app_start();
+ if (result != ISC_R_SUCCESS) {
+ named_main_earlyfatal("isc_app_start() failed: %s",
+ isc_result_totext(result));
+ }
+
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "starting %s%s <id:%s>", PACKAGE_STRING,
+ PACKAGE_DESCRIPTION, PACKAGE_SRCID);
+
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, "running on %s",
+ named_os_uname());
+
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, "built with %s",
+ PACKAGE_CONFIGARGS);
+
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "running as: %s%s%s", program_name, saved_command_line,
+ ellipsis);
+#ifdef __clang__
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by CLANG %s", __VERSION__);
+#else /* ifdef __clang__ */
+#if defined(__ICC) || defined(__INTEL_COMPILER)
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by ICC %s", __VERSION__);
+#else /* if defined(__ICC) || defined(__INTEL_COMPILER) */
+#ifdef __GNUC__
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by GCC %s", __VERSION__);
+#endif /* ifdef __GNUC__ */
+#endif /* if defined(__ICC) || defined(__INTEL_COMPILER) */
+#endif /* ifdef __clang__ */
+#ifdef _MSC_VER
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by MSVC %d", _MSC_VER);
+#endif /* ifdef _MSC_VER */
+#ifdef __SUNPRO_C
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by Solaris Studio %x", __SUNPRO_C);
+#endif /* ifdef __SUNPRO_C */
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled with OpenSSL version: %s",
+ OPENSSL_VERSION_TEXT);
+#if !defined(LIBRESSL_VERSION_NUMBER) && \
+ OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 or higher */
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to OpenSSL version: %s",
+ OpenSSL_version(OPENSSL_VERSION));
+#else /* if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= \
+ * 0x10100000L */
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to OpenSSL version: %s",
+ SSLeay_version(SSLEAY_VERSION));
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled with libuv version: %d.%d.%d", UV_VERSION_MAJOR,
+ UV_VERSION_MINOR, UV_VERSION_PATCH);
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to libuv version: %s", uv_version_string());
+#ifdef HAVE_LIBXML2
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled with libxml2 version: %s",
+ LIBXML_DOTTED_VERSION);
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to libxml2 version: %s", xmlParserVersion);
+#endif /* ifdef HAVE_LIBXML2 */
+#if defined(HAVE_JSON_C)
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled with json-c version: %s", JSON_C_VERSION);
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to json-c version: %s", json_c_version());
+#endif /* if defined(HAVE_JSON_C) */
+#if defined(HAVE_ZLIB) && defined(ZLIB_VERSION)
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled with zlib version: %s", ZLIB_VERSION);
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to zlib version: %s", zlibVersion());
+#endif /* if defined(HAVE_ZLIB) && defined(ZLIB_VERSION) */
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "----------------------------------------------------");
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "BIND 9 is maintained by Internet Systems Consortium,");
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "Inc. (ISC), a non-profit 501(c)(3) public-benefit ");
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "corporation. Support and training for BIND 9 are ");
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "available at https://www.isc.org/support");
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "----------------------------------------------------");
+
+ /*
+ * Get the initial resource limits.
+ */
+ RUNTIME_CHECK(isc_resource_getlimit(isc_resource_stacksize,
+ &named_g_initstacksize) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_resource_getlimit(isc_resource_datasize,
+ &named_g_initdatasize) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_resource_getlimit(isc_resource_coresize,
+ &named_g_initcoresize) ==
+ ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_resource_getlimit(isc_resource_openfiles,
+ &named_g_initopenfiles) ==
+ ISC_R_SUCCESS);
+
+ /*
+ * System resources cannot effectively be tuned on some systems.
+ * Raise the limit in such cases for safety.
+ */
+ old_openfiles = named_g_initopenfiles;
+ named_os_adjustnofile();
+ RUNTIME_CHECK(isc_resource_getlimit(isc_resource_openfiles,
+ &named_g_initopenfiles) ==
+ ISC_R_SUCCESS);
+ if (old_openfiles != named_g_initopenfiles) {
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "adjusted limit on open files from "
+ "%" PRIu64 " to "
+ "%" PRIu64,
+ old_openfiles, named_g_initopenfiles);
+ }
+
+ /*
+ * If the named configuration filename is relative, prepend the current
+ * directory's name before possibly changing to another directory.
+ */
+ if (!isc_file_isabsolute(named_g_conffile)) {
+ result = isc_file_absolutepath(named_g_conffile,
+ absolute_conffile,
+ sizeof(absolute_conffile));
+ if (result != ISC_R_SUCCESS) {
+ named_main_earlyfatal("could not construct "
+ "absolute path "
+ "of configuration file: %s",
+ isc_result_totext(result));
+ }
+ named_g_conffile = absolute_conffile;
+ }
+
+ /*
+ * Record the server's startup time.
+ */
+ result = isc_time_now(&named_g_boottime);
+ if (result != ISC_R_SUCCESS) {
+ named_main_earlyfatal("isc_time_now() failed: %s",
+ isc_result_totext(result));
+ }
+
+ result = create_managers();
+ if (result != ISC_R_SUCCESS) {
+ named_main_earlyfatal("create_managers() failed: %s",
+ isc_result_totext(result));
+ }
+
+ named_builtin_init();
+
+ /*
+ * Add calls to register sdb drivers here.
+ */
+ /* xxdb_init(); */
+
+ /*
+ * Register the DLZ "dlopen" driver.
+ */
+ result = dlz_dlopen_init(named_g_mctx);
+ if (result != ISC_R_SUCCESS) {
+ named_main_earlyfatal("dlz_dlopen_init() failed: %s",
+ isc_result_totext(result));
+ }
+
+ named_server_create(named_g_mctx, &named_g_server);
+ ENSURE(named_g_server != NULL);
+ sctx = named_g_server->sctx;
+
+ /*
+ * Report supported algorithms now that dst_lib_init() has
+ * been called via named_server_create().
+ */
+ format_supported_algorithms(logit);
+
+ /*
+ * Modify server context according to command line options
+ */
+ if (disable4) {
+ ns_server_setoption(sctx, NS_SERVER_DISABLE4, true);
+ }
+ if (disable6) {
+ ns_server_setoption(sctx, NS_SERVER_DISABLE6, true);
+ }
+ if (dropedns) {
+ ns_server_setoption(sctx, NS_SERVER_DROPEDNS, true);
+ }
+ if (ednsformerr) { /* STD13 server */
+ ns_server_setoption(sctx, NS_SERVER_EDNSFORMERR, true);
+ }
+ if (ednsnotimp) {
+ ns_server_setoption(sctx, NS_SERVER_EDNSNOTIMP, true);
+ }
+ if (ednsrefused) {
+ ns_server_setoption(sctx, NS_SERVER_EDNSREFUSED, true);
+ }
+ if (fixedlocal) {
+ ns_server_setoption(sctx, NS_SERVER_FIXEDLOCAL, true);
+ }
+ if (noaa) {
+ ns_server_setoption(sctx, NS_SERVER_NOAA, true);
+ }
+ if (noedns) {
+ ns_server_setoption(sctx, NS_SERVER_NOEDNS, true);
+ }
+ if (nonearest) {
+ ns_server_setoption(sctx, NS_SERVER_NONEAREST, true);
+ }
+ if (nosoa) {
+ ns_server_setoption(sctx, NS_SERVER_NOSOA, true);
+ }
+ if (notcp) {
+ ns_server_setoption(sctx, NS_SERVER_NOTCP, true);
+ }
+ if (sigvalinsecs) {
+ ns_server_setoption(sctx, NS_SERVER_SIGVALINSECS, true);
+ }
+ if (transferinsecs) {
+ ns_server_setoption(sctx, NS_SERVER_TRANSFERINSECS, true);
+ }
+ if (transferslowly) {
+ ns_server_setoption(sctx, NS_SERVER_TRANSFERSLOWLY, true);
+ }
+ if (transferstuck) {
+ ns_server_setoption(sctx, NS_SERVER_TRANSFERSTUCK, true);
+ }
+}
+
+static void
+cleanup(void) {
+ destroy_managers();
+
+ if (named_g_mapped != NULL) {
+ dns_acl_detach(&named_g_mapped);
+ }
+
+ named_server_destroy(&named_g_server);
+
+ named_builtin_deinit();
+
+ /*
+ * Add calls to unregister sdb drivers here.
+ */
+ /* xxdb_clear(); */
+
+ /*
+ * Unregister "dlopen" DLZ driver.
+ */
+ dlz_dlopen_clear();
+
+ isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+ NAMED_LOGMODULE_MAIN, ISC_LOG_NOTICE, "exiting");
+ named_log_shutdown();
+}
+
+static char *memstats = NULL;
+
+void
+named_main_setmemstats(const char *filename) {
+ /*
+ * Caller has to ensure locking.
+ */
+
+ if (memstats != NULL) {
+ free(memstats);
+ memstats = NULL;
+ }
+
+ if (filename == NULL) {
+ return;
+ }
+
+ memstats = strdup(filename);
+}
+
+#ifdef HAVE_LIBSCF
+/*
+ * Get FMRI for the named process.
+ */
+isc_result_t
+named_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
+ scf_handle_t *h = NULL;
+ int namelen;
+ char *instance;
+
+ REQUIRE(ins_name != NULL && *ins_name == NULL);
+
+ if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
+ if (debug) {
+ UNEXPECTED_ERROR("scf_handle_create() failed: %s",
+ scf_strerror(scf_error()));
+ }
+ return (ISC_R_FAILURE);
+ }
+
+ if (scf_handle_bind(h) == -1) {
+ if (debug) {
+ UNEXPECTED_ERROR("scf_handle_bind() failed: %s",
+ scf_strerror(scf_error()));
+ }
+ scf_handle_destroy(h);
+ return (ISC_R_FAILURE);
+ }
+
+ if ((namelen = scf_myname(h, NULL, 0)) == -1) {
+ if (debug) {
+ UNEXPECTED_ERROR("scf_myname() failed: %s",
+ scf_strerror(scf_error()));
+ }
+ scf_handle_destroy(h);
+ return (ISC_R_FAILURE);
+ }
+
+ if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
+ UNEXPECTED_ERROR("named_smf_get_instance memory "
+ "allocation failed: %s",
+ isc_result_totext(ISC_R_NOMEMORY));
+ scf_handle_destroy(h);
+ return (ISC_R_FAILURE);
+ }
+
+ if (scf_myname(h, instance, namelen + 1) == -1) {
+ if (debug) {
+ UNEXPECTED_ERROR("scf_myname() failed: %s",
+ scf_strerror(scf_error()));
+ }
+ scf_handle_destroy(h);
+ isc_mem_free(mctx, instance);
+ return (ISC_R_FAILURE);
+ }
+
+ scf_handle_destroy(h);
+ *ins_name = instance;
+ return (ISC_R_SUCCESS);
+}
+#endif /* HAVE_LIBSCF */
+
+/* main entry point, possibly hooked */
+
+int
+main(int argc, char *argv[]) {
+ isc_result_t result;
+#ifdef HAVE_LIBSCF
+ char *instance = NULL;
+#endif /* ifdef HAVE_LIBSCF */
+
+#ifdef HAVE_GPERFTOOLS_PROFILER
+ (void)ProfilerStart(NULL);
+#endif /* ifdef HAVE_GPERFTOOLS_PROFILER */
+
+#ifdef HAVE_LIBXML2
+ xmlInitParser();
+#endif /* HAVE_LIBXML2 */
+
+ /*
+ * Technically, this call is superfluous because on startup of the main
+ * program, the portable "C" locale is selected by default. This
+ * explicit call here is for a reference that the BIND 9 code base is
+ * not locale aware and the locale MUST be set to "C" (or "POSIX") when
+ * calling any BIND 9 library code. If you are calling external
+ * libraries that use locale, such calls must be wrapped into
+ * setlocale(LC_ALL, ""); before the call and setlocale(LC_ALL, "C");
+ * after the call, and no BIND 9 library calls must be made in between.
+ */
+ setlocale(LC_ALL, "C");
+
+ /*
+ * Record version in core image.
+ * strings named.core | grep "named version:"
+ */
+ strlcat(version,
+#if defined(NO_VERSION_DATE) || !defined(__DATE__)
+ "named version: BIND " PACKAGE_VERSION " <" PACKAGE_SRCID ">",
+#else
+ "named version: BIND " PACKAGE_VERSION " <" PACKAGE_SRCID
+ "> (" __DATE__ ")",
+#endif
+ sizeof(version));
+ result = isc_file_progname(*argv, program_name, sizeof(program_name));
+ if (result != ISC_R_SUCCESS) {
+ named_main_earlyfatal("program name too long");
+ }
+
+ isc_assertion_setcallback(assertion_failed);
+ isc_error_setfatal(library_fatal_error);
+ isc_error_setunexpected(library_unexpected_error);
+
+ named_os_init(program_name);
+
+ parse_command_line(argc, argv);
+
+#ifdef ENABLE_AFL
+ if (named_g_fuzz_type != isc_fuzz_none) {
+ named_fuzz_setup();
+ }
+
+ if (named_g_fuzz_type == isc_fuzz_resolver) {
+ dns_resolver_setfuzzing();
+ } else if (named_g_fuzz_type == isc_fuzz_http) {
+ isc_httpd_setfinishhook(named_fuzz_notify);
+ }
+#endif /* ifdef ENABLE_AFL */
+ /*
+ * Warn about common configuration error.
+ */
+ if (named_g_chrootdir != NULL) {
+ int len = strlen(named_g_chrootdir);
+ if (strncmp(named_g_chrootdir, named_g_conffile, len) == 0 &&
+ (named_g_conffile[len] == '/' ||
+ named_g_conffile[len] == '\\'))
+ {
+ named_main_earlywarning("config filename (-c %s) "
+ "contains chroot path (-t %s)",
+ named_g_conffile,
+ named_g_chrootdir);
+ }
+ }
+
+ isc_mem_create(&named_g_mctx);
+ isc_mem_setname(named_g_mctx, "main");
+
+ setup();
+ INSIST(named_g_server != NULL);
+
+ /*
+ * Start things running and then wait for a shutdown request
+ * or reload.
+ */
+ do {
+ result = isc_app_run();
+
+ if (result == ISC_R_RELOAD) {
+ named_server_reloadwanted(named_g_server);
+ } else if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR("isc_app_run(): %s",
+ isc_result_totext(result));
+ /*
+ * Force exit.
+ */
+ result = ISC_R_SUCCESS;
+ }
+ } while (result != ISC_R_SUCCESS);
+
+#ifdef HAVE_LIBSCF
+ if (named_smf_want_disable == 1) {
+ result = named_smf_get_instance(&instance, 1, named_g_mctx);
+ if (result == ISC_R_SUCCESS && instance != NULL) {
+ if (smf_disable_instance(instance, 0) != 0) {
+ UNEXPECTED_ERROR("smf_disable_instance() "
+ "failed for %s : %s",
+ instance,
+ scf_strerror(scf_error()));
+ }
+ }
+ if (instance != NULL) {
+ isc_mem_free(named_g_mctx, instance);
+ }
+ }
+#endif /* HAVE_LIBSCF */
+
+ cleanup();
+
+ if (want_stats) {
+ isc_mem_stats(named_g_mctx, stdout);
+ }
+
+ if (named_g_memstatistics && memstats != NULL) {
+ FILE *fp = NULL;
+ result = isc_stdio_open(memstats, "w", &fp);
+ if (result == ISC_R_SUCCESS) {
+ isc_mem_stats(named_g_mctx, fp);
+ (void)isc_stdio_close(fp);
+ }
+ }
+ isc_mem_destroy(&named_g_mctx);
+ isc_mem_checkdestroyed(stderr);
+
+ named_main_setmemstats(NULL);
+
+ isc_app_finish();
+
+ named_os_closedevnull();
+
+ named_os_shutdown();
+
+#ifdef HAVE_LIBXML2
+ xmlCleanupParser();
+#endif /* HAVE_LIBXML2 */
+
+#ifdef HAVE_GPERFTOOLS_PROFILER
+ ProfilerStop();
+#endif /* ifdef HAVE_GPERFTOOLS_PROFILER */
+
+ return (0);
+}