summaryrefslogtreecommitdiffstats
path: root/bin/named/main.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 18:37:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-05 18:37:14 +0000
commitea648e70a989cca190cd7403fe892fd2dcc290b4 (patch)
treee2b6b1c647da68b0d4d66082835e256eb30970e8 /bin/named/main.c
parentInitial commit. (diff)
downloadbind9-ea648e70a989cca190cd7403fe892fd2dcc290b4.tar.xz
bind9-ea648e70a989cca190cd7403fe892fd2dcc290b4.zip
Adding upstream version 1:9.11.5.P4+dfsg.upstream/1%9.11.5.P4+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bin/named/main.c')
-rw-r--r--bin/named/main.c1543
1 files changed, 1543 insertions, 0 deletions
diff --git a/bin/named/main.c b/bin/named/main.c
new file mode 100644
index 0000000..8cec1ad
--- /dev/null
+++ b/bin/named/main.c
@@ -0,0 +1,1543 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/app.h>
+#include <isc/backtrace.h>
+#include <isc/commandline.h>
+#include <isc/dir.h>
+#include <isc/entropy.h>
+#include <isc/file.h>
+#include <isc/hash.h>
+#include <isc/httpd.h>
+#include <isc/os.h>
+#include <isc/platform.h>
+#include <isc/print.h>
+#include <isc/resource.h>
+#include <isc/stdio.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <isccc/result.h>
+
+#include <dns/dispatch.h>
+#include <dns/dyndb.h>
+#include <dns/name.h>
+#include <dns/result.h>
+#include <dns/resolver.h>
+#include <dns/view.h>
+
+#include <dst/result.h>
+#ifdef PKCS11CRYPTO
+#include <pk11/result.h>
+#endif
+
+#include <dlz/dlz_dlopen_driver.h>
+
+#ifdef HAVE_GPERFTOOLS_PROFILER
+#include <gperftools/profiler.h>
+#endif
+
+
+/*
+ * Defining NS_MAIN provides storage declarations (rather than extern)
+ * for variables in named/globals.h.
+ */
+#define NS_MAIN 1
+
+#include <named/builtin.h>
+#include <named/control.h>
+#include <named/fuzz.h>
+#include <named/globals.h> /* Explicit, though named/log.h includes it. */
+#include <named/interfacemgr.h>
+#include <named/log.h>
+#include <named/os.h>
+#include <named/server.h>
+#include <named/lwresd.h>
+#include <named/main.h>
+#include <named/seccomp.h>
+#ifdef HAVE_LIBSCF
+#include <named/ns_smf_globals.h>
+#endif
+
+#ifdef OPENSSL
+#include <openssl/opensslv.h>
+#include <openssl/crypto.h>
+#endif
+#ifdef HAVE_LIBXML2
+#include <libxml/xmlversion.h>
+#endif
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+/*
+ * Include header files for database drivers here.
+ */
+/* #include "xxdb.h" */
+
+#ifdef CONTRIB_DLZ
+/*
+ * Include contributed DLZ drivers if appropriate.
+ */
+#include <dlz/dlz_drivers.h>
+#endif
+
+/*
+ * The maximum number of stack frames to dump on assertion failure.
+ */
+#ifndef BACKTRACE_MAXFRAME
+#define BACKTRACE_MAXFRAME 128
+#endif
+
+LIBISC_EXTERNAL_DATA extern int isc_dscp_check_value;
+LIBDNS_EXTERNAL_DATA extern unsigned int dns_zone_mkey_hour;
+LIBDNS_EXTERNAL_DATA extern unsigned int dns_zone_mkey_day;
+LIBDNS_EXTERNAL_DATA extern unsigned int dns_zone_mkey_month;
+
+static bool want_stats = false;
+static char program_name[ISC_DIR_NAMEMAX] = "named";
+static char absolute_conffile[ISC_DIR_PATHMAX];
+static char saved_command_line[512];
+static char version[512];
+static unsigned int maxsocks = 0;
+static int maxudp = 0;
+
+void
+ns_main_earlywarning(const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ if (ns_g_lctx != NULL) {
+ isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_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
+ns_main_earlyfatal(const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ if (ns_g_lctx != NULL) {
+ isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ format, args);
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_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);
+}
+
+ISC_PLATFORM_NORETURN_PRE static void
+assertion_failed(const char *file, int line, isc_assertiontype_t type,
+ const char *cond) ISC_PLATFORM_NORETURN_POST;
+
+static void
+assertion_failed(const char *file, int line, isc_assertiontype_t type,
+ const char *cond)
+{
+ void *tracebuf[BACKTRACE_MAXFRAME];
+ int i, nframes;
+ isc_result_t result;
+ const char *logsuffix = "";
+ const char *fname;
+
+ /*
+ * Handle assertion failures.
+ */
+
+ if (ns_g_lctx != NULL) {
+ /*
+ * Reset the assertion callback in case it is the log
+ * routines causing the assertion.
+ */
+ isc_assertion_setcallback(NULL);
+
+ result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
+ &nframes);
+ if (result == ISC_R_SUCCESS && nframes > 0)
+ logsuffix = ", back trace";
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ "%s:%d: %s(%s) failed%s", file, line,
+ isc_assertion_typetotext(type), cond, logsuffix);
+ if (result == ISC_R_SUCCESS) {
+ for (i = 0; i < nframes; i++) {
+ unsigned long offset;
+
+ fname = NULL;
+ result = isc_backtrace_getsymbol(tracebuf[i],
+ &fname,
+ &offset);
+ if (result == ISC_R_SUCCESS) {
+ isc_log_write(ns_g_lctx,
+ NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN,
+ ISC_LOG_CRITICAL,
+ "#%d %p in %s()+0x%lx", i,
+ tracebuf[i], fname,
+ offset);
+ } else {
+ isc_log_write(ns_g_lctx,
+ NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN,
+ ISC_LOG_CRITICAL,
+ "#%d %p in ??", i,
+ tracebuf[i]);
+ }
+ }
+ }
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_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 (ns_g_coreok)
+ abort();
+ exit(1);
+}
+
+ISC_PLATFORM_NORETURN_PRE static void
+library_fatal_error(const char *file, int line, const char *format,
+ va_list args)
+ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
+
+static void
+library_fatal_error(const char *file, int line, const char *format,
+ va_list args)
+{
+ /*
+ * Handle isc_error_fatal() calls from our libraries.
+ */
+
+ if (ns_g_lctx != NULL) {
+ /*
+ * Reset the error callback in case it is the log
+ * routines causing the assertion.
+ */
+ isc_error_setfatal(NULL);
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ "%s:%d: fatal error:", file, line);
+ isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ format, args);
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
+ "exiting (due to fatal error in library)");
+ } else {
+ fprintf(stderr, "%s:%d: fatal error: ", file, line);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+
+ if (ns_g_coreok)
+ abort();
+ exit(1);
+}
+
+static void
+library_unexpected_error(const char *file, int line, const char *format,
+ va_list args) ISC_FORMAT_PRINTF(3, 0);
+
+static void
+library_unexpected_error(const char *file, int line, const char *format,
+ va_list args)
+{
+ /*
+ * Handle isc_error_unexpected() calls from our libraries.
+ */
+
+ if (ns_g_lctx != NULL) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
+ "%s:%d: unexpected error:", file, line);
+ isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
+ format, args);
+ } else {
+ fprintf(stderr, "%s:%d: fatal error: ", file, line);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+}
+
+static void
+lwresd_usage(void) {
+ fprintf(stderr,
+ "usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] "
+ "[-d debuglevel] [-f|-g]\n"
+ " [-i pidfile] [-n number_of_cpus] "
+ "[-p port] [-P listen-port]\n"
+ " [-s] [-S sockets] [-t chrootdir] [-u username] "
+ "[-U listeners]\n"
+ " [-m {usage|trace|record|size|mctx}]\n"
+ "usage: lwresd [-v|-V]\n");
+}
+
+static void
+usage(void) {
+ if (ns_g_lwresdonly) {
+ lwresd_usage();
+ return;
+ }
+ fprintf(stderr,
+ "usage: named [-4|-6] [-c conffile] [-d debuglevel] "
+ "[-E engine] [-f|-g]\n"
+ " [-n number_of_cpus] [-p port] [-s] "
+ "[-S sockets] [-t chrootdir]\n"
+ " [-u username] [-U listeners] "
+ "[-m {usage|trace|record|size|mctx}]\n"
+ "usage: named [-v|-V]\n");
+}
+
+static void
+save_command_line(int argc, char *argv[]) {
+ int i;
+ char *src;
+ char *dst;
+ char *eob;
+ const char truncated[] = "...";
+ bool quoted = false;
+
+ dst = saved_command_line;
+ eob = saved_command_line + sizeof(saved_command_line);
+
+ for (i = 1; i < argc && dst < eob; i++) {
+ *dst++ = ' ';
+
+ src = argv[i];
+ while (*src != '\0' && dst < eob) {
+ /*
+ * This won't perfectly produce a shell-independent
+ * pastable command line in all circumstances, but
+ * comes close, and for practical purposes will
+ * nearly always be fine.
+ */
+ if (quoted || isalnum(*src & 0xff) ||
+ *src == '-' || *src == '_' ||
+ *src == '.' || *src == '/') {
+ *dst++ = *src++;
+ quoted = false;
+ } else {
+ *dst++ = '\\';
+ quoted = true;
+ }
+ }
+ }
+
+ INSIST(sizeof(saved_command_line) >= sizeof(truncated));
+
+ if (dst == eob)
+ strcpy(eob - sizeof(truncated), truncated);
+ else
+ *dst = '\0';
+}
+
+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')
+ ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
+ if (tmp < 0 || tmp != ltmp)
+ ns_main_earlyfatal("%s '%s' out of range", desc, arg);
+ return (tmp);
+}
+
+static struct flag_def {
+ const char *name;
+ unsigned int value;
+} mem_debug_flags[] = {
+ { "none", 0},
+ { "trace", ISC_MEM_DEBUGTRACE },
+ { "record", ISC_MEM_DEBUGRECORD },
+ { "usage", ISC_MEM_DEBUGUSAGE },
+ { "size", ISC_MEM_DEBUGSIZE },
+ { "mctx", ISC_MEM_DEBUGCTX },
+ { NULL, 0 }
+};
+
+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;
+ *ret |= def->value;
+ goto found;
+ }
+ }
+ ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
+ found:
+ if (clear || (*end == '\0'))
+ break;
+ arg = end + 1;
+ }
+
+ if (clear)
+ *ret = 0;
+}
+
+static void
+parse_fuzz_arg(void) {
+ if (!strncmp(isc_commandline_argument, "client:", 7)) {
+ ns_g_fuzz_named_addr = isc_commandline_argument + 7;
+ ns_g_fuzz_type = ns_fuzz_client;
+ } else if (!strncmp(isc_commandline_argument, "tcp:", 4)) {
+ ns_g_fuzz_named_addr = isc_commandline_argument + 4;
+ ns_g_fuzz_type = ns_fuzz_tcpclient;
+ } else if (!strncmp(isc_commandline_argument, "resolver:", 9)) {
+ ns_g_fuzz_named_addr = isc_commandline_argument + 9;
+ ns_g_fuzz_type = ns_fuzz_resolver;
+ } else if (!strncmp(isc_commandline_argument, "http:", 5)) {
+ ns_g_fuzz_named_addr = isc_commandline_argument + 5;
+ ns_g_fuzz_type = ns_fuzz_http;
+ } else if (!strncmp(isc_commandline_argument, "rndc:", 5)) {
+ ns_g_fuzz_named_addr = isc_commandline_argument + 5;
+ ns_g_fuzz_type = ns_fuzz_rndc;
+ } else {
+ ns_main_earlyfatal("unknown fuzzing type '%s'",
+ isc_commandline_argument);
+ }
+}
+
+static void
+parse_T_opt(char *option) {
+ const char *p;
+ /*
+ * force the server to behave (or misbehave) in
+ * specified ways for testing purposes.
+ *
+ * clienttest: make clients single shot with their
+ * own memory context.
+ * delay=xxxx: delay client responses by xxxx ms to
+ * simulate remote servers.
+ * dscp=x: check that dscp values are as
+ * expected and assert otherwise.
+ */
+ if (!strcmp(option, "clienttest")) {
+ ns_g_clienttest = true;
+ } else if (!strncmp(option, "delay=", 6)) {
+ ns_g_delay = atoi(option + 6);
+ } else if (!strcmp(option, "dropedns")) {
+ ns_g_dropedns = true;
+ } else if (!strncmp(option, "dscp=", 5)) {
+ isc_dscp_check_value = atoi(option + 5);
+ } else if (!strcmp(option, "fixedlocal")) {
+ ns_g_fixedlocal = true;
+ } else if (!strcmp(option, "keepstderr")) {
+ ns_g_keepstderr = true;
+ } else if (!strcmp(option, "noaa")) {
+ ns_g_noaa = true;
+ } else if (!strcmp(option, "noedns")) {
+ ns_g_noedns = true;
+ } else if (!strcmp(option, "nonearest")) {
+ ns_g_nonearest = true;
+ } else if (!strcmp(option, "nosoa")) {
+ ns_g_nosoa = true;
+ } else if (!strcmp(option, "nosyslog")) {
+ ns_g_nosyslog = true;
+ } else if (!strcmp(option, "notcp")) {
+ ns_g_notcp = true;
+ } else if (!strcmp(option, "maxudp512")) {
+ maxudp = 512;
+ } else if (!strcmp(option, "maxudp1460")) {
+ maxudp = 1460;
+ } else if (!strncmp(option, "maxudp=", 7)) {
+ maxudp = atoi(option + 7);
+ } else if (!strncmp(option, "mkeytimers=", 11)) {
+ p = strtok(option + 11, "/");
+ if (p == NULL) {
+ ns_main_earlyfatal("bad mkeytimer");
+ }
+
+ dns_zone_mkey_hour = atoi(p);
+ if (dns_zone_mkey_hour == 0) {
+ ns_main_earlyfatal("bad mkeytimer");
+ }
+
+ p = strtok(NULL, "/");
+ 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)
+ ns_main_earlyfatal("bad mkeytimer");
+
+ p = strtok(NULL, "/");
+ 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) {
+ ns_main_earlyfatal("bad mkeytimer");
+ }
+ } else if (!strcmp(option, "sigvalinsecs")) {
+ ns_g_sigvalinsecs = true;
+ } else if (!strncmp(option, "tat=", 4)) {
+ ns_g_tat_interval = atoi(option + 4);
+ } else {
+ fprintf(stderr, "unknown -T flag '%s\n", option);
+ }
+}
+
+static void
+parse_command_line(int argc, char *argv[]) {
+ int ch;
+ int port;
+ const char *p;
+
+ save_command_line(argc, argv);
+
+ /*
+ * NS_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, NS_MAIN_ARGS)) != -1) {
+ switch (ch) {
+ case '4':
+ if (ns_g_disable4)
+ ns_main_earlyfatal("cannot specify -4 and -6");
+ if (isc_net_probeipv4() != ISC_R_SUCCESS)
+ ns_main_earlyfatal("IPv4 not supported by OS");
+ isc_net_disableipv6();
+ ns_g_disable6 = true;
+ break;
+ case '6':
+ if (ns_g_disable6)
+ ns_main_earlyfatal("cannot specify -4 and -6");
+ if (isc_net_probeipv6() != ISC_R_SUCCESS)
+ ns_main_earlyfatal("IPv6 not supported by OS");
+ isc_net_disableipv4();
+ ns_g_disable4 = true;
+ break;
+ case 'A':
+ parse_fuzz_arg();
+ break;
+ case 'c':
+ ns_g_conffile = isc_commandline_argument;
+ lwresd_g_conffile = isc_commandline_argument;
+ if (lwresd_g_useresolvconf)
+ ns_main_earlyfatal("cannot specify -c and -C");
+ ns_g_conffileset = true;
+ break;
+ case 'C':
+ lwresd_g_resolvconffile = isc_commandline_argument;
+ if (ns_g_conffileset)
+ ns_main_earlyfatal("cannot specify -c and -C");
+ lwresd_g_useresolvconf = true;
+ break;
+ case 'd':
+ ns_g_debuglevel = parse_int(isc_commandline_argument,
+ "debug level");
+ break;
+ case 'D':
+ /* Descriptive comment for 'ps'. */
+ break;
+ case 'E':
+ ns_g_engine = isc_commandline_argument;
+ break;
+ case 'f':
+ ns_g_foreground = true;
+ break;
+ case 'g':
+ ns_g_foreground = true;
+ ns_g_logstderr = true;
+ break;
+ /* XXXBEW -i should be removed */
+ case 'i':
+ lwresd_g_defaultpidfile = isc_commandline_argument;
+ break;
+ case 'l':
+ ns_g_lwresdonly = true;
+ break;
+ case 'L':
+ ns_g_logfile = isc_commandline_argument;
+ break;
+ case 'M':
+ if (strcmp(isc_commandline_argument, "external") == 0)
+ isc_mem_defaultflags = 0;
+ break;
+ case 'm':
+ set_flags(isc_commandline_argument, mem_debug_flags,
+ &isc_mem_debugging);
+ break;
+ case 'N': /* Deprecated. */
+ case 'n':
+ ns_g_cpus = parse_int(isc_commandline_argument,
+ "number of cpus");
+ if (ns_g_cpus == 0)
+ ns_g_cpus = 1;
+ break;
+ case 'p':
+ port = parse_int(isc_commandline_argument, "port");
+ if (port < 1 || port > 65535)
+ ns_main_earlyfatal("port '%s' out of range",
+ isc_commandline_argument);
+ ns_g_port = port;
+ break;
+ /* XXXBEW Should -P be removed? */
+ case 'P':
+ port = parse_int(isc_commandline_argument, "port");
+ if (port < 1 || port > 65535)
+ ns_main_earlyfatal("port '%s' out of range",
+ isc_commandline_argument);
+ lwresd_g_listenport = port;
+ break;
+ case 's':
+ /* XXXRTH temporary syntax */
+ want_stats = true;
+ break;
+ case 'S':
+ maxsocks = parse_int(isc_commandline_argument,
+ "max number of sockets");
+ break;
+ case 't':
+ /* XXXJAB should we make a copy? */
+ ns_g_chrootdir = isc_commandline_argument;
+ break;
+ case 'T': /* NOT DOCUMENTED */
+ parse_T_opt(isc_commandline_argument);
+ break;
+ case 'U':
+ ns_g_udpdisp = parse_int(isc_commandline_argument,
+ "number of UDP listeners "
+ "per interface");
+ break;
+ case 'u':
+ ns_g_username = isc_commandline_argument;
+ break;
+ case 'v':
+ printf("%s %s%s%s <id:%s>\n",
+ ns_g_product, ns_g_version,
+ (*ns_g_description != '\0') ? " " : "",
+ ns_g_description, ns_g_srcid);
+ exit(0);
+ case 'V':
+ printf("%s %s%s%s <id:%s>\n", ns_g_product, ns_g_version,
+ (*ns_g_description != '\0') ? " " : "",
+ ns_g_description, ns_g_srcid);
+ printf("running on %s\n", ns_os_uname());
+ printf("built by %s with %s\n",
+ ns_g_builder, ns_g_configargs);
+#ifdef __clang__
+ printf("compiled by CLANG %s\n", __VERSION__);
+#else
+#if defined(__ICC) || defined(__INTEL_COMPILER)
+ printf("compiled by ICC %s\n", __VERSION__);
+#else
+#ifdef __GNUC__
+ printf("compiled by GCC %s\n", __VERSION__);
+#endif
+#endif
+#endif
+#ifdef _MSC_VER
+ printf("compiled by MSVC %d\n", _MSC_VER);
+#endif
+#ifdef __SUNPRO_C
+ printf("compiled by Solaris Studio %x\n", __SUNPRO_C);
+#endif
+#ifdef OPENSSL
+ 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
+ printf("linked to OpenSSL version: %s\n",
+ SSLeay_version(SSLEAY_VERSION));
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
+#endif
+#ifdef HAVE_LIBXML2
+ printf("compiled with libxml2 version: %s\n",
+ LIBXML_DOTTED_VERSION);
+ printf("linked to libxml2 version: %s\n",
+ xmlParserVersion);
+#endif
+#if defined(HAVE_JSON) && defined(JSON_C_VERSION)
+ printf("compiled with libjson-c version: %s\n",
+ JSON_C_VERSION);
+ printf("linked to libjson-c version: %s\n",
+ json_c_version());
+#endif
+#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
+#ifdef ISC_PLATFORM_USETHREADS
+ printf("threads support is enabled\n");
+#else
+ printf("threads support is disabled\n");
+#endif
+ exit(0);
+ case 'x':
+ /* Obsolete. No longer in use. Ignore. */
+ break;
+ case 'X':
+ ns_g_forcelock = true;
+ if (strcasecmp(isc_commandline_argument, "none") != 0)
+ ns_g_defaultlockfile = isc_commandline_argument;
+ else
+ ns_g_defaultlockfile = NULL;
+ break;
+ case 'F':
+ /* Reserved for FIPS mode */
+ /* FALLTHROUGH */
+ case '?':
+ usage();
+ if (isc_commandline_option == '?')
+ exit(0);
+ p = strchr(NS_MAIN_ARGS, isc_commandline_option);
+ if (p == NULL || *++p != ':')
+ ns_main_earlyfatal("unknown option '-%c'",
+ isc_commandline_option);
+ else
+ ns_main_earlyfatal("option '-%c' requires "
+ "an argument",
+ isc_commandline_option);
+ /* FALLTHROUGH */
+ default:
+ ns_main_earlyfatal("parsing options returned %d", ch);
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+ POST(argv);
+
+ if (argc > 0) {
+ usage();
+ ns_main_earlyfatal("extra command line arguments");
+ }
+}
+
+static isc_result_t
+create_managers(void) {
+ isc_result_t result;
+ unsigned int socks;
+
+ INSIST(ns_g_cpus_detected > 0);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ if (ns_g_cpus == 0)
+ ns_g_cpus = ns_g_cpus_detected;
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+ ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
+ ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s",
+ ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
+#else
+ ns_g_cpus = 1;
+#endif
+#ifdef WIN32
+ ns_g_udpdisp = 1;
+#else
+ if (ns_g_udpdisp == 0) {
+ if (ns_g_cpus_detected == 1)
+ ns_g_udpdisp = 1;
+ else
+ ns_g_udpdisp = ns_g_cpus_detected - 1;
+ }
+ if (ns_g_udpdisp > ns_g_cpus)
+ ns_g_udpdisp = ns_g_cpus;
+#endif
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+ ISC_LOG_INFO, "using %u UDP listener%s per interface",
+ ns_g_udpdisp, ns_g_udpdisp == 1 ? "" : "s");
+#endif
+
+ result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_taskmgr_create() failed: %s",
+ isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_timermgr_create() failed: %s",
+ isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_socketmgr_create() failed: %s",
+ isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+ isc__socketmgr_maxudp(ns_g_socketmgr, maxudp);
+ result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks);
+ if (result == ISC_R_SUCCESS) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_SERVER,
+ ISC_LOG_INFO, "using up to %u sockets", socks);
+ }
+
+ result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_entropy_create() failed: %s",
+ isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
+ if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_hash_create() failed: %s",
+ isc_result_totext(result));
+ return (ISC_R_UNEXPECTED);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+destroy_managers(void) {
+ ns_lwresd_shutdown();
+
+ /*
+ * isc_taskmgr_destroy() will block until all tasks have exited,
+ */
+ isc_taskmgr_destroy(&ns_g_taskmgr);
+ isc_timermgr_destroy(&ns_g_timermgr);
+ isc_socketmgr_destroy(&ns_g_socketmgr);
+
+ /*
+ * isc_hash_destroy() cannot be called as long as a resolver may be
+ * running. Calling this after isc_taskmgr_destroy() ensures the
+ * call is safe.
+ */
+ isc_hash_destroy();
+}
+
+static void
+dump_symboltable(void) {
+ int i;
+ isc_result_t result;
+ const char *fname;
+ const void *addr;
+
+ if (isc__backtrace_nsymbols == 0)
+ return;
+
+ if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99)))
+ return;
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_DEBUG(99), "Symbol table:");
+
+ for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) {
+ addr = NULL;
+ fname = NULL;
+ result = isc_backtrace_getsymbolfromindex(i, &addr, &fname);
+ if (result == ISC_R_SUCCESS) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
+ "[%d] %p %s", i, addr, fname);
+ }
+ }
+}
+
+#ifdef HAVE_LIBSECCOMP
+static void
+setup_seccomp() {
+ scmp_filter_ctx ctx;
+ unsigned int i;
+ int ret;
+
+ /* Make sure the lists are in sync */
+ INSIST((sizeof(scmp_syscalls) / sizeof(int)) ==
+ (sizeof(scmp_syscall_names) / sizeof(const char *)));
+
+ ctx = seccomp_init(SCMP_ACT_KILL);
+ if (ctx == NULL) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
+ "libseccomp activation failed");
+ return;
+ }
+
+ for (i = 0 ; i < sizeof(scmp_syscalls)/sizeof(*(scmp_syscalls)); i++) {
+ ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
+ scmp_syscalls[i], 0);
+ if (ret < 0)
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
+ "libseccomp rule failed: %s",
+ scmp_syscall_names[i]);
+
+ else
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(9),
+ "added libseccomp rule: %s",
+ scmp_syscall_names[i]);
+ }
+
+ ret = seccomp_load(ctx);
+ if (ret < 0) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
+ "libseccomp unable to load filter");
+ } else {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "libseccomp sandboxing active");
+ }
+
+ /*
+ * Release filter in ctx. Filters already loaded are not
+ * affected.
+ */
+ seccomp_release(ctx);
+}
+#endif /* HAVE_LIBSECCOMP */
+
+static void
+setup(void) {
+ isc_result_t result;
+ isc_resourcevalue_t old_openfiles;
+#ifdef HAVE_LIBSCF
+ char *instance = NULL;
+#endif
+
+ /*
+ * 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.
+ */
+ ns_os_inituserinfo(ns_g_username);
+
+ /*
+ * Initialize time conversion information
+ */
+ ns_os_tzset();
+
+ ns_os_opendevnull();
+
+#ifdef HAVE_LIBSCF
+ /* Check if named is under smf control, before chroot. */
+ result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
+ /* We don't care about instance, just check if we got one. */
+ if (result == ISC_R_SUCCESS)
+ ns_smf_got_instance = 1;
+ else
+ ns_smf_got_instance = 0;
+ if (instance != NULL)
+ isc_mem_free(ns_g_mctx, instance);
+#endif /* HAVE_LIBSCF */
+
+#ifdef PATH_RANDOMDEV
+ /*
+ * Initialize system's random device as fallback entropy source
+ * if running chroot'ed.
+ */
+ if (ns_g_chrootdir != NULL) {
+ result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("isc_entropy_create() failed: %s",
+ isc_result_totext(result));
+
+ result = isc_entropy_createfilesource(ns_g_fallbackentropy,
+ PATH_RANDOMDEV);
+ if (result != ISC_R_SUCCESS) {
+ ns_main_earlywarning("could not open pre-chroot "
+ "entropy source %s: %s",
+ PATH_RANDOMDEV,
+ isc_result_totext(result));
+ isc_entropy_detach(&ns_g_fallbackentropy);
+ }
+ }
+#endif
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Check for the number of cpu's before ns_os_chroot().
+ */
+ ns_g_cpus_detected = isc_os_ncpus();
+#endif
+
+ ns_os_chroot(ns_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.)
+ */
+ ns_os_minprivs();
+
+ result = ns_log_init((ns_g_username != NULL));
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("ns_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 (!ns_g_foreground)
+ ns_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)
+ ns_main_earlyfatal("isc_app_start() failed: %s",
+ isc_result_totext(result));
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE, "starting %s %s%s%s <id:%s>",
+ ns_g_product, ns_g_version,
+ *ns_g_description ? " " : "", ns_g_description,
+ ns_g_srcid);
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE, "running on %s", ns_os_uname());
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE, "running as: %s%s",
+ program_name, saved_command_line);
+#ifdef __clang__
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by CLANG %s", __VERSION__);
+#else
+#if defined(__ICC) || defined(__INTEL_COMPILER)
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by ICC %s", __VERSION__);
+#else
+#ifdef __GNUC__
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by GCC %s", __VERSION__);
+#endif
+#endif
+#endif
+#ifdef _MSC_VER
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by MSVC %d", _MSC_VER);
+#endif
+#ifdef __SUNPRO_C
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled by Solaris Studio %x", __SUNPRO_C);
+#endif
+#ifdef OPENSSL
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_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(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to OpenSSL version: %s",
+ OpenSSL_version(OPENSSL_VERSION));
+#else
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to OpenSSL version: %s",
+ SSLeay_version(SSLEAY_VERSION));
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
+#endif
+#ifdef HAVE_LIBXML2
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled with libxml2 version: %s",
+ LIBXML_DOTTED_VERSION);
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to libxml2 version: %s", xmlParserVersion);
+#endif
+#if defined(HAVE_JSON) && defined(JSON_C_VERSION)
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled with libjson-c version: %s", JSON_C_VERSION);
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to libjson-c version: %s", json_c_version());
+#endif
+#if defined(HAVE_ZLIB) && defined(ZLIB_VERSION)
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "compiled with zlib version: %s", ZLIB_VERSION);
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "linked to zlib version: %s", zlibVersion());
+#endif
+#ifdef ISC_PLATFORM_USETHREADS
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "threads support is enabled");
+#else
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "threads support is disabled");
+#endif
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE,
+ "----------------------------------------------------");
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE,
+ "BIND 9 is maintained by Internet Systems Consortium,");
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE,
+ "Inc. (ISC), a non-profit 501(c)(3) public-benefit ");
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE,
+ "corporation. Support and training for BIND 9 are ");
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE,
+ "available at https://www.isc.org/support");
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE,
+ "----------------------------------------------------");
+
+ dump_symboltable();
+
+ /*
+ * Get the initial resource limits.
+ */
+ (void)isc_resource_getlimit(isc_resource_stacksize,
+ &ns_g_initstacksize);
+ (void)isc_resource_getlimit(isc_resource_datasize,
+ &ns_g_initdatasize);
+ (void)isc_resource_getlimit(isc_resource_coresize,
+ &ns_g_initcoresize);
+ (void)isc_resource_getlimit(isc_resource_openfiles,
+ &ns_g_initopenfiles);
+
+ /*
+ * System resources cannot effectively be tuned on some systems.
+ * Raise the limit in such cases for safety.
+ */
+ old_openfiles = ns_g_initopenfiles;
+ ns_os_adjustnofile();
+ (void)isc_resource_getlimit(isc_resource_openfiles,
+ &ns_g_initopenfiles);
+ if (old_openfiles != ns_g_initopenfiles) {
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+ NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
+ "adjusted limit on open files from "
+ "%" PRIu64 " to "
+ "%" PRIu64,
+ old_openfiles, ns_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(ns_g_conffile)) {
+ result = isc_file_absolutepath(ns_g_conffile,
+ absolute_conffile,
+ sizeof(absolute_conffile));
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("could not construct absolute path "
+ "of configuration file: %s",
+ isc_result_totext(result));
+ ns_g_conffile = absolute_conffile;
+ }
+
+ /*
+ * Record the server's startup time.
+ */
+ result = isc_time_now(&ns_g_boottime);
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("isc_time_now() failed: %s",
+ isc_result_totext(result));
+
+ result = create_managers();
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("create_managers() failed: %s",
+ isc_result_totext(result));
+
+ ns_builtin_init();
+
+ /*
+ * Add calls to register sdb drivers here.
+ */
+ /* xxdb_init(); */
+
+#ifdef ISC_DLZ_DLOPEN
+ /*
+ * Register the DLZ "dlopen" driver.
+ */
+ result = dlz_dlopen_init(ns_g_mctx);
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("dlz_dlopen_init() failed: %s",
+ isc_result_totext(result));
+#endif
+
+#if CONTRIB_DLZ
+ /*
+ * Register any other contributed DLZ drivers.
+ */
+ result = dlz_drivers_init();
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("dlz_drivers_init() failed: %s",
+ isc_result_totext(result));
+#endif
+
+ ns_server_create(ns_g_mctx, &ns_g_server);
+
+#ifdef HAVE_LIBSECCOMP
+ setup_seccomp();
+#endif /* HAVE_LIBSECCOMP */
+}
+
+static void
+cleanup(void) {
+ destroy_managers();
+
+ if (ns_g_mapped != NULL)
+ dns_acl_detach(&ns_g_mapped);
+
+ ns_server_destroy(&ns_g_server);
+
+ isc_entropy_detach(&ns_g_entropy);
+ if (ns_g_fallbackentropy != NULL)
+ isc_entropy_detach(&ns_g_fallbackentropy);
+
+ ns_builtin_deinit();
+
+ /*
+ * Add calls to unregister sdb drivers here.
+ */
+ /* xxdb_clear(); */
+
+#ifdef CONTRIB_DLZ
+ /*
+ * Unregister contributed DLZ drivers.
+ */
+ dlz_drivers_clear();
+#endif
+#ifdef ISC_DLZ_DLOPEN
+ /*
+ * Unregister "dlopen" DLZ driver.
+ */
+ dlz_dlopen_clear();
+#endif
+
+ dns_name_destroy();
+
+ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
+ ISC_LOG_NOTICE, "exiting");
+ ns_log_shutdown();
+}
+
+static char *memstats = NULL;
+
+void
+ns_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
+ns_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(__FILE__, __LINE__,
+ "scf_handle_create() failed: %s",
+ scf_strerror(scf_error()));
+ return (ISC_R_FAILURE);
+ }
+
+ if (scf_handle_bind(h) == -1) {
+ if (debug)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "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(__FILE__, __LINE__,
+ "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(__FILE__, __LINE__,
+ "ns_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(__FILE__, __LINE__,
+ "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_GPERFTOOLS_PROFILER
+ (void) ProfilerStart(NULL);
+#endif
+
+ /*
+ * Record version in core image.
+ * strings named.core | grep "named version:"
+ */
+ strlcat(version,
+#if defined(NO_VERSION_DATE) || !defined(__DATE__)
+ "named version: BIND " VERSION " <" SRCID ">",
+#else
+ "named version: BIND " VERSION " <" SRCID "> (" __DATE__ ")",
+#endif
+ sizeof(version));
+ result = isc_file_progname(*argv, program_name, sizeof(program_name));
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("program name too long");
+
+ if (strcmp(program_name, "lwresd") == 0)
+ ns_g_lwresdonly = true;
+
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("failed to build internal symbol table");
+
+ isc_assertion_setcallback(assertion_failed);
+ isc_error_setfatal(library_fatal_error);
+ isc_error_setunexpected(library_unexpected_error);
+
+ ns_os_init(program_name);
+
+ dns_result_register();
+ dst_result_register();
+ isccc_result_register();
+#ifdef PKCS11CRYPTO
+ pk11_result_register();
+#endif
+
+ parse_command_line(argc, argv);
+
+#ifdef ENABLE_AFL
+ if (ns_g_fuzz_type != ns_fuzz_none) {
+ named_fuzz_setup();
+ }
+
+ if (ns_g_fuzz_type == ns_fuzz_resolver) {
+ dns_resolver_setfuzzing();
+ } else if (ns_g_fuzz_type == ns_fuzz_http) {
+ isc_httpd_setfinishhook(named_fuzz_notify);
+ }
+#endif
+ /*
+ * Warn about common configuration error.
+ */
+ if (ns_g_chrootdir != NULL) {
+ int len = strlen(ns_g_chrootdir);
+ if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 &&
+ (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\'))
+ ns_main_earlywarning("config filename (-c %s) contains "
+ "chroot path (-t %s)",
+ ns_g_conffile, ns_g_chrootdir);
+ }
+
+ result = isc_mem_create(0, 0, &ns_g_mctx);
+ if (result != ISC_R_SUCCESS)
+ ns_main_earlyfatal("isc_mem_create() failed: %s",
+ isc_result_totext(result));
+ isc_mem_setname(ns_g_mctx, "main", NULL);
+
+ setup();
+
+ /*
+ * Start things running and then wait for a shutdown request
+ * or reload.
+ */
+ do {
+ result = isc_app_run();
+
+ if (result == ISC_R_RELOAD) {
+ ns_server_reloadwanted(ns_g_server);
+ } else if (result != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_app_run(): %s",
+ isc_result_totext(result));
+ /*
+ * Force exit.
+ */
+ result = ISC_R_SUCCESS;
+ }
+ } while (result != ISC_R_SUCCESS);
+
+#ifdef HAVE_LIBSCF
+ if (ns_smf_want_disable == 1) {
+ result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
+ if (result == ISC_R_SUCCESS && instance != NULL) {
+ if (smf_disable_instance(instance, 0) != 0)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "smf_disable_instance() "
+ "failed for %s : %s",
+ instance,
+ scf_strerror(scf_error()));
+ }
+ if (instance != NULL)
+ isc_mem_free(ns_g_mctx, instance);
+ }
+#endif /* HAVE_LIBSCF */
+
+ cleanup();
+
+ if (want_stats) {
+ isc_mem_stats(ns_g_mctx, stdout);
+ isc_mutex_stats(stdout);
+ }
+
+ if (ns_g_memstatistics && memstats != NULL) {
+ FILE *fp = NULL;
+ result = isc_stdio_open(memstats, "w", &fp);
+ if (result == ISC_R_SUCCESS) {
+ isc_mem_stats(ns_g_mctx, fp);
+ isc_mutex_stats(fp);
+ (void) isc_stdio_close(fp);
+ }
+ }
+ isc_mem_destroy(&ns_g_mctx);
+ isc_mem_checkdestroyed(stderr);
+
+ ns_main_setmemstats(NULL);
+
+ isc_app_finish();
+
+ ns_os_closedevnull();
+
+ ns_os_shutdown();
+
+#ifdef HAVE_GPERFTOOLS_PROFILER
+ ProfilerStop();
+#endif
+
+ return (0);
+}