main.c 31.4 KB
Newer Older
Bob Halley's avatar
add  
Bob Halley committed
1
/*
Tinderbox User's avatar
Tinderbox User committed
2
 * Copyright (C) 2004-2013  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
Bob Halley's avatar
add  
Bob Halley committed
6 7
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
Bob Halley's avatar
add  
Bob Halley committed
16 17
 */

Automatic Updater's avatar
Automatic Updater committed
18
/* $Id: main.c,v 1.187 2012/02/06 23:46:44 tbox Exp $ */
19 20

/*! \file */
David Lawrence's avatar
David Lawrence committed
21

Bob Halley's avatar
add  
Bob Halley committed
22 23
#include <config.h>

24
#include <ctype.h>
Bob Halley's avatar
add  
Bob Halley committed
25
#include <stdlib.h>
26
#include <string.h>
Bob Halley's avatar
add  
Bob Halley committed
27 28

#include <isc/app.h>
29
#include <isc/backtrace.h>
30
#include <isc/commandline.h>
31
#include <isc/dir.h>
32
#include <isc/entropy.h>
33
#include <isc/file.h>
34
#include <isc/hash.h>
35
#include <isc/os.h>
36
#include <isc/platform.h>
37
#include <isc/print.h>
38
#include <isc/resource.h>
39
#include <isc/stdio.h>
40
#include <isc/string.h>
Bob Halley's avatar
add  
Bob Halley committed
41 42
#include <isc/task.h>
#include <isc/timer.h>
Bob Halley's avatar
Bob Halley committed
43
#include <isc/util.h>
Bob Halley's avatar
add  
Bob Halley committed
44

45 46
#include <isccc/result.h>

47
#include <dns/dispatch.h>
48
#include <dns/name.h>
49
#include <dns/result.h>
David Lawrence's avatar
David Lawrence committed
50
#include <dns/view.h>
Bob Halley's avatar
add  
Bob Halley committed
51

52 53
#include <dst/result.h>

54 55
#include <dlz/dlz_dlopen_driver.h>

56
/*
57
 * Defining NS_MAIN provides storage declarations (rather than extern)
58 59
 * for variables in named/globals.h.
 */
60
#define NS_MAIN 1
Bob Halley's avatar
add  
Bob Halley committed
61

62
#include <named/builtin.h>
63
#include <named/control.h>
64
#include <named/globals.h>	/* Explicit, though named/log.h includes it. */
Bob Halley's avatar
add  
Bob Halley committed
65
#include <named/interfacemgr.h>
66
#include <named/log.h>
Bob Halley's avatar
Bob Halley committed
67
#include <named/os.h>
Bob Halley's avatar
add  
Bob Halley committed
68
#include <named/server.h>
69
#include <named/lwresd.h>
Bob Halley's avatar
Bob Halley committed
70
#include <named/main.h>
71 72 73
#ifdef HAVE_LIBSCF
#include <named/ns_smf_globals.h>
#endif
Bob Halley's avatar
add  
Bob Halley committed
74

75 76 77 78 79 80
#ifdef OPENSSL
#include <openssl/opensslv.h>
#endif
#ifdef HAVE_LIBXML2
#include <libxml/xmlversion.h>
#endif
81 82 83
/*
 * Include header files for database drivers here.
 */
84
/* #include "xxdb.h" */
85

86
#ifdef CONTRIB_DLZ
87
/*
88
 * Include contributed DLZ drivers if appropriate.
89 90 91 92
 */
#include <dlz/dlz_drivers.h>
#endif

93 94 95 96 97 98 99
/*
 * The maximum number of stack frames to dump on assertion failure.
 */
#ifndef BACKTRACE_MAXFRAME
#define BACKTRACE_MAXFRAME 128
#endif

Evan Hunt's avatar
Evan Hunt committed
100 101
extern int isc_dscp_check_value;

David Lawrence's avatar
David Lawrence committed
102
static isc_boolean_t	want_stats = ISC_FALSE;
103 104
static char		program_name[ISC_DIR_NAMEMAX] = "named";
static char		absolute_conffile[ISC_DIR_PATHMAX];
105 106
static char		saved_command_line[512];
static char		version[512];
107
static unsigned int	maxsocks = 0;
108
static int		maxudp = 0;
Bob Halley's avatar
add  
Bob Halley committed
109

110
void
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
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);
}

Bob Halley's avatar
Bob Halley committed
128 129
void
ns_main_earlyfatal(const char *format, ...) {
Bob Halley's avatar
add  
Bob Halley committed
130 131 132
	va_list args;

	va_start(args, format);
133 134 135 136
	if (ns_g_lctx != NULL) {
		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
			       format, args);
Bob Halley's avatar
Bob Halley committed
137 138 139
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
			       "exiting (due to early fatal error)");
140
	} else {
141
		fprintf(stderr, "%s: ", program_name);
142 143
		vfprintf(stderr, format, args);
		fprintf(stderr, "\n");
144
		fflush(stderr);
145
	}
Bob Halley's avatar
add  
Bob Halley committed
146 147 148 149 150
	va_end(args);

	exit(1);
}

Francis Dupont's avatar
Francis Dupont committed
151 152 153 154
ISC_PLATFORM_NORETURN_PRE static void
assertion_failed(const char *file, int line, isc_assertiontype_t type,
		 const char *cond) ISC_PLATFORM_NORETURN_POST;

155
static void
David Lawrence's avatar
David Lawrence committed
156 157 158
assertion_failed(const char *file, int line, isc_assertiontype_t type,
		 const char *cond)
{
159 160 161 162 163 164
	void *tracebuf[BACKTRACE_MAXFRAME];
	int i, nframes;
	isc_result_t result;
	const char *logsuffix = "";
	const char *fname;

165 166 167 168 169
	/*
	 * Handle assertion failures.
	 */

	if (ns_g_lctx != NULL) {
170
		/*
Francis Dupont's avatar
Francis Dupont committed
171
		 * Reset the assertion callback in case it is the log
172 173 174 175
		 * routines causing the assertion.
		 */
		isc_assertion_setcallback(NULL);

176 177 178 179
		result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
						&nframes);
		if (result == ISC_R_SUCCESS && nframes > 0)
			logsuffix = ", back trace";
180 181
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
			      "%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]);
				}
			}
		}
210
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
211
			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
212
			      "exiting (due to assertion failure)");
213 214 215 216 217 218 219 220 221 222 223
	} 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);
}

Francis Dupont's avatar
Francis Dupont committed
224
ISC_PLATFORM_NORETURN_PRE static void
225
library_fatal_error(const char *file, int line, const char *format,
Francis Dupont's avatar
Francis Dupont committed
226 227
		    va_list args)
ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
228

229
static void
David Lawrence's avatar
David Lawrence committed
230 231 232
library_fatal_error(const char *file, int line, const char *format,
		    va_list args)
{
233 234 235 236 237
	/*
	 * Handle isc_error_fatal() calls from our libraries.
	 */

	if (ns_g_lctx != NULL) {
238 239 240 241 242 243
		/*
		 * Reset the error callback in case it is the log
		 * routines causing the assertion.
		 */
		isc_error_setfatal(NULL);

244 245
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
246
			      "%s:%d: fatal error:", file, line);
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
		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);
}

265 266 267 268
static void
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args) ISC_FORMAT_PRINTF(3, 0);

269
static void
David Lawrence's avatar
David Lawrence committed
270 271 272
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args)
{
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
	/*
	 * 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);
	}
}

292 293 294
static void
lwresd_usage(void) {
	fprintf(stderr,
Mark Andrews's avatar
Mark Andrews committed
295 296 297
		"usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] "
		"[-d debuglevel]\n"
		"              [-f|-g] [-n number_of_cpus] [-p port] "
298
		"[-P listen-port] [-s]\n"
Mark Andrews's avatar
Mark Andrews committed
299
		"              [-t chrootdir] [-u username] [-i pidfile]\n"
300
		"              [-m {usage|trace|record|size|mctx}]\n");
301 302
}

Bob Halley's avatar
add  
Bob Halley committed
303 304
static void
usage(void) {
305 306 307 308
	if (ns_g_lwresdonly) {
		lwresd_usage();
		return;
	}
Bob Halley's avatar
add  
Bob Halley committed
309
	fprintf(stderr,
Mark Andrews's avatar
Mark Andrews committed
310
		"usage: named [-4|-6] [-c conffile] [-d debuglevel] "
Francis Dupont's avatar
Francis Dupont committed
311 312 313
		"[-E engine] [-f|-g]\n"
		"             [-n number_of_cpus] [-p port] [-s] "
		"[-t chrootdir] [-u username]\n"
314
		"             [-m {usage|trace|record|size|mctx}]\n");
Bob Halley's avatar
add  
Bob Halley committed
315 316
}

317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
static void
save_command_line(int argc, char *argv[]) {
	int i;
	char *src;
	char *dst;
	char *eob;
	const char truncated[] = "...";
	isc_boolean_t quoted = ISC_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 = ISC_FALSE;
			} else {
				*dst++ = '\\';
				quoted = ISC_TRUE;
			}
		}
	}

	INSIST(sizeof(saved_command_line) >= sizeof(truncated));

	if (dst == eob)
		strcpy(eob - sizeof(truncated), truncated);
	else
		*dst = '\0';
}

360 361 362 363 364 365
static int
parse_int(char *arg, const char *desc) {
	char *endp;
	int tmp;
	long int ltmp;

366
	ltmp = strtol(arg, &endp, 10);
367 368 369 370 371 372 373 374
	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);
}

375 376 377 378 379 380
static struct flag_def {
	const char *name;
	unsigned int value;
} mem_debug_flags[] = {
	{ "trace",  ISC_MEM_DEBUGTRACE },
	{ "record", ISC_MEM_DEBUGRECORD },
Mark Andrews's avatar
Mark Andrews committed
381
	{ "usage", ISC_MEM_DEBUGUSAGE },
382 383
	{ "size", ISC_MEM_DEBUGSIZE },
	{ "mctx", ISC_MEM_DEBUGCTX },
384 385 386 387 388 389 390 391
	{ NULL, 0 }
};

static void
set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
	for (;;) {
		const struct flag_def *def;
		const char *end = strchr(arg, ',');
Mark Andrews's avatar
Mark Andrews committed
392
		int arglen;
393 394
		if (end == NULL)
			end = arg + strlen(arg);
395
		arglen = (int)(end - arg);
396
		for (def = defs; def->name != NULL; def++) {
Mark Andrews's avatar
Mark Andrews committed
397 398
			if (arglen == (int)strlen(def->name) &&
			    memcmp(arg, def->name, arglen) == 0) {
399 400 401 402
				*ret |= def->value;
				goto found;
			}
		}
Mark Andrews's avatar
Mark Andrews committed
403
		ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
404 405 406 407 408 409 410
	 found:
		if (*end == '\0')
			break;
		arg = end + 1;
	}
}

411
static void
Bob Halley's avatar
add  
Bob Halley committed
412 413
parse_command_line(int argc, char *argv[]) {
	int ch;
414
	int port;
415 416
	isc_boolean_t disable6 = ISC_FALSE;
	isc_boolean_t disable4 = ISC_FALSE;
417

418 419
	save_command_line(argc, argv);

420
	/* PLEASE keep options synchronized when main is hooked! */
421
	isc_commandline_errprint = ISC_FALSE;
422
	while ((ch = isc_commandline_parse(argc, argv,
423
					   "46c:C:d:D:E:fFgi:lm:n:N:p:P:"
424
					   "sS:t:T:U:u:vVx:")) != -1) {
Bob Halley's avatar
add  
Bob Halley committed
425
		switch (ch) {
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
		case '4':
			if (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();
			disable6 = ISC_TRUE;
			break;
		case '6':
			if (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();
			disable4 = ISC_TRUE;
			break;
Bob Halley's avatar
add  
Bob Halley committed
442
		case 'c':
443
			ns_g_conffile = isc_commandline_argument;
444
			lwresd_g_conffile = isc_commandline_argument;
445 446 447
			if (lwresd_g_useresolvconf)
				ns_main_earlyfatal("cannot specify -c and -C");
			ns_g_conffileset = ISC_TRUE;
448 449 450
			break;
		case 'C':
			lwresd_g_resolvconffile = isc_commandline_argument;
451 452
			if (ns_g_conffileset)
				ns_main_earlyfatal("cannot specify -c and -C");
453
			lwresd_g_useresolvconf = ISC_TRUE;
Bob Halley's avatar
add  
Bob Halley committed
454
			break;
Bob Halley's avatar
Bob Halley committed
455
		case 'd':
456 457
			ns_g_debuglevel = parse_int(isc_commandline_argument,
						    "debug level");
Bob Halley's avatar
Bob Halley committed
458
			break;
459 460 461
		case 'D':
			/* Descriptive comment for 'ps'. */
			break;
Francis Dupont's avatar
Francis Dupont committed
462 463 464
		case 'E':
			ns_g_engine = isc_commandline_argument;
			break;
465 466 467
		case 'f':
			ns_g_foreground = ISC_TRUE;
			break;
468 469 470 471
		case 'g':
			ns_g_foreground = ISC_TRUE;
			ns_g_logstderr = ISC_TRUE;
			break;
472 473 474 475 476 477 478
		/* XXXBEW -i should be removed */
		case 'i':
			lwresd_g_defaultpidfile = isc_commandline_argument;
			break;
		case 'l':
			ns_g_lwresdonly = ISC_TRUE;
			break;
479 480 481 482
		case 'm':
			set_flags(isc_commandline_argument, mem_debug_flags,
				  &isc_mem_debugging);
			break;
483 484
		case 'N': /* Deprecated. */
		case 'n':
485 486
			ns_g_cpus = parse_int(isc_commandline_argument,
					      "number of cpus");
Bob Halley's avatar
add  
Bob Halley committed
487 488 489
			if (ns_g_cpus == 0)
				ns_g_cpus = 1;
			break;
Bob Halley's avatar
Bob Halley committed
490
		case 'p':
491
			port = parse_int(isc_commandline_argument, "port");
492
			if (port < 1 || port > 65535)
493
				ns_main_earlyfatal("port '%s' out of range",
494 495
						   isc_commandline_argument);
			ns_g_port = port;
Bob Halley's avatar
Bob Halley committed
496
			break;
497 498 499 500 501 502 503 504
		/* 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;
Bob Halley's avatar
add  
Bob Halley committed
505 506 507 508
		case 's':
			/* XXXRTH temporary syntax */
			want_stats = ISC_TRUE;
			break;
509 510 511 512
		case 'S':
			maxsocks = parse_int(isc_commandline_argument,
					     "max number of sockets");
			break;
513
		case 't':
514
			/* XXXJAB should we make a copy? */
515 516
			ns_g_chrootdir = isc_commandline_argument;
			break;
Mark Andrews's avatar
Mark Andrews committed
517
		case 'T':	/* NOT DOCUMENTED */
518
			/*
Evan Hunt's avatar
Evan Hunt committed
519 520 521
			 * force the server to behave (or misbehave) in
			 * specified ways for testing purposes.
			 *
522 523
			 * clienttest: make clients single shot with their
			 * 	       own memory context.
524 525
			 * delay=xxxx: delay client responses by xxxx ms to
			 *	       simulate remote servers.
Evan Hunt's avatar
Evan Hunt committed
526 527
			 * dscp=x:     check that dscp values are as
			 * 	       expected and assert otherwise.
528
			 */
529
			if (!strcmp(isc_commandline_argument, "clienttest"))
530
				ns_g_clienttest = ISC_TRUE;
531 532
			else if (!strcmp(isc_commandline_argument, "nosoa"))
				ns_g_nosoa = ISC_TRUE;
533 534
			else if (!strcmp(isc_commandline_argument, "noaa"))
				ns_g_noaa = ISC_TRUE;
535 536 537 538
			else if (!strcmp(isc_commandline_argument, "maxudp512"))
				maxudp = 512;
			else if (!strcmp(isc_commandline_argument, "maxudp1460"))
				maxudp = 1460;
539 540 541 542 543 544 545
			else if (!strcmp(isc_commandline_argument, "dropedns"))
				ns_g_dropedns = ISC_TRUE;
			else if (!strcmp(isc_commandline_argument, "noedns"))
				ns_g_noedns = ISC_TRUE;
			else if (!strncmp(isc_commandline_argument,
					  "maxudp=", 7))
				maxudp = atoi(isc_commandline_argument + 7);
546 547 548
			else if (!strncmp(isc_commandline_argument,
					  "delay=", 6))
				ns_g_delay = atoi(isc_commandline_argument + 6);
549 550
			else if (!strcmp(isc_commandline_argument, "nosyslog"))
				ns_g_nosyslog = ISC_TRUE;
551 552
			else if (!strcmp(isc_commandline_argument, "nonearest"))
				ns_g_nonearest = ISC_TRUE;
Evan Hunt's avatar
Evan Hunt committed
553 554 555
			else if (!strncmp(isc_commandline_argument, "dscp=", 5))
				isc_dscp_check_value =
					   atoi(isc_commandline_argument + 5);
556 557 558 559
			else
				fprintf(stderr, "unknown -T flag '%s\n",
					isc_commandline_argument);
			break;
560 561 562 563 564
		case 'U':
			ns_g_udpdisp = parse_int(isc_commandline_argument,
						 "number of UDP listeners "
						 "per interface");
			break;
565 566 567
		case 'u':
			ns_g_username = isc_commandline_argument;
			break;
568
		case 'v':
Evan Hunt's avatar
Evan Hunt committed
569 570 571 572
			printf("%s %s", ns_g_product, ns_g_version);
			if (*ns_g_description != 0)
				printf(" %s", ns_g_description);
			printf("\n");
573
			exit(0);
574
		case 'V':
Evan Hunt's avatar
Evan Hunt committed
575 576 577
			printf("%s %s", ns_g_product, ns_g_version);
			if (*ns_g_description != 0)
				printf(" %s", ns_g_description);
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
			printf(" <id:%s> built by %s with %s\n", ns_g_srcid,
			       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
597 598 599 600 601 602 603 604
#ifdef OPENSSL
			printf("using OpenSSL version: %s\n",
			       OPENSSL_VERSION_TEXT);
#endif
#ifdef HAVE_LIBXML2
			printf("using libxml2 version: %s\n",
			       LIBXML_DOTTED_VERSION);
#endif
605
			exit(0);
Francis Dupont's avatar
Francis Dupont committed
606 607 608
		case 'F':
			/* Reserved for FIPS mode */
			/* FALLTHROUGH */
609
		case '?':
610
			usage();
611 612
			if (isc_commandline_option == '?')
				exit(0);
613
			ns_main_earlyfatal("unknown option '-%c'",
614
					   isc_commandline_option);
Francis Dupont's avatar
Francis Dupont committed
615
			/* FALLTHROUGH */
Bob Halley's avatar
add  
Bob Halley committed
616
		default:
Bob Halley's avatar
Bob Halley committed
617
			ns_main_earlyfatal("parsing options returned %d", ch);
Bob Halley's avatar
add  
Bob Halley committed
618 619 620
		}
	}

621 622
	argc -= isc_commandline_index;
	argv += isc_commandline_index;
623
	POST(argv);
Bob Halley's avatar
add  
Bob Halley committed
624

625
	if (argc > 0) {
Bob Halley's avatar
add  
Bob Halley committed
626
		usage();
Bob Halley's avatar
Bob Halley committed
627
		ns_main_earlyfatal("extra command line arguments");
Bob Halley's avatar
add  
Bob Halley committed
628 629 630 631
	}
}

static isc_result_t
632
create_managers(void) {
Bob Halley's avatar
add  
Bob Halley committed
633
	isc_result_t result;
634
	unsigned int socks;
Bob Halley's avatar
add  
Bob Halley committed
635

636
#ifdef ISC_PLATFORM_USETHREADS
637
	if (ns_g_cpus == 0)
638
		ns_g_cpus = ns_g_cpus_detected;
639 640
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
		      ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
641
		      ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s",
642
		      ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
643 644 645
#else
	ns_g_cpus = 1;
#endif
646 647 648
#ifdef WIN32
	ns_g_udpdisp = 1;
#else
Evan Hunt's avatar
Evan Hunt committed
649 650 651 652 653 654 655 656
	if (ns_g_udpdisp == 0) {
		if (ns_g_cpus_detected == 1)
			ns_g_udpdisp = 1;
		else if (ns_g_cpus_detected < 4)
			ns_g_udpdisp = 2;
		else
			ns_g_udpdisp = ns_g_cpus_detected / 2;
	}
657
	if (ns_g_udpdisp > ns_g_cpus)
658
		ns_g_udpdisp = ns_g_cpus;
659
#endif
660 661 662 663
	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");

Bob Halley's avatar
add  
Bob Halley committed
664 665 666
	result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
Mark Andrews's avatar
Mark Andrews committed
667
				 "isc_taskmgr_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
668 669 670 671 672 673 674
				 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__,
Mark Andrews's avatar
Mark Andrews committed
675
				 "isc_timermgr_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
676 677 678 679
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

680
	result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks);
Bob Halley's avatar
add  
Bob Halley committed
681 682
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
683
				 "isc_socketmgr_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
684 685 686
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}
687
	isc__socketmgr_maxudp(ns_g_socketmgr, maxudp);
688 689 690 691 692 693
	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);
	}
Bob Halley's avatar
add  
Bob Halley committed
694

695
	result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
696 697
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
698
				 "isc_entropy_create() failed: %s",
699 700 701 702
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

703 704 705 706 707 708 709 710
	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);
	}

Bob Halley's avatar
add  
Bob Halley committed
711 712 713 714 715
	return (ISC_R_SUCCESS);
}

static void
destroy_managers(void) {
716 717
	ns_lwresd_shutdown();

718
	isc_entropy_detach(&ns_g_entropy);
719 720 721
	if (ns_g_fallbackentropy != NULL)
		isc_entropy_detach(&ns_g_fallbackentropy);

Bob Halley's avatar
add  
Bob Halley committed
722
	/*
Andreas Gustafsson's avatar
Andreas Gustafsson committed
723
	 * isc_taskmgr_destroy() will block until all tasks have exited,
Bob Halley's avatar
add  
Bob Halley committed
724 725 726 727
	 */
	isc_taskmgr_destroy(&ns_g_taskmgr);
	isc_timermgr_destroy(&ns_g_timermgr);
	isc_socketmgr_destroy(&ns_g_socketmgr);
728 729 730 731 732 733 734

	/*
	 * 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();
Bob Halley's avatar
add  
Bob Halley committed
735 736
}

737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
static void
dump_symboltable() {
	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);
		}
	}
}

Bob Halley's avatar
add  
Bob Halley committed
765
static void
766
setup(void) {
Bob Halley's avatar
add  
Bob Halley committed
767
	isc_result_t result;
768
	isc_resourcevalue_t old_openfiles;
769 770 771
#ifdef HAVE_LIBSCF
	char *instance = NULL;
#endif
Bob Halley's avatar
add  
Bob Halley committed
772

773 774 775 776 777 778 779
	/*
	 * 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);

780 781 782 783 784
	/*
	 * Initialize time conversion information
	 */
	ns_os_tzset();

785 786
	ns_os_opendevnull();

787 788 789 790 791 792 793 794 795
#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)
796
		isc_mem_free(ns_g_mctx, instance);
797 798
#endif /* HAVE_LIBSCF */

799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
#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
821 822 823 824 825 826 827

#ifdef ISC_PLATFORM_USETHREADS
	/*
	 * Check for the number of cpu's before ns_os_chroot().
	 */
	ns_g_cpus_detected = isc_os_ncpus();
#endif
828

829 830
	ns_os_chroot(ns_g_chrootdir);

Bob Halley's avatar
Bob Halley committed
831 832 833 834 835 836 837 838
	/*
	 * 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.)
	 */
839
	ns_os_minprivs();
Bob Halley's avatar
Bob Halley committed
840

841
	result = ns_log_init(ISC_TF(ns_g_username != NULL));
842
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
843 844
		ns_main_earlyfatal("ns_log_init() failed: %s",
				   isc_result_totext(result));
845

Bob Halley's avatar
Bob Halley committed
846 847 848 849 850 851 852
	/*
	 * 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().
	 */
853 854
	if (!ns_g_foreground)
		ns_os_daemonize();
Bob Halley's avatar
Bob Halley committed
855

856 857 858 859 860 861 862 863 864
	/*
	 * 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));

865
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
Tinderbox User's avatar
Tinderbox User committed
866
		      ISC_LOG_NOTICE, "starting %s %s%s", ns_g_product,
867
		      ns_g_version, saved_command_line);
Bob Halley's avatar
add  
Bob Halley committed
868

869 870 871
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
		      ISC_LOG_NOTICE, "built with %s", ns_g_configargs);

872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
	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,
		      "----------------------------------------------------");

891 892
	dump_symboltable();

893 894 895
	/*
	 * Get the initial resource limits.
	 */
896 897 898 899 900 901 902 903
	(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);
904

905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
	/*
	 * 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 "
			      "%" ISC_PRINT_QUADFORMAT "u to "
			      "%" ISC_PRINT_QUADFORMAT "u",
			      old_openfiles, ns_g_initopenfiles);
	}

922 923 924 925 926
	/*
	 * 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)) {
927 928 929
		result = isc_file_absolutepath(ns_g_conffile,
					       absolute_conffile,
					       sizeof(absolute_conffile));
930
		if (result != ISC_R_SUCCESS)
931 932
			ns_main_earlyfatal("could not construct absolute path "
					   "of configuration file: %s",
933
					   isc_result_totext(result));
934 935 936
		ns_g_conffile = absolute_conffile;
	}

937 938 939 940 941 942 943 944
	/*
	 * 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));

Bob Halley's avatar
add  
Bob Halley committed
945 946
	result = create_managers();
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
947 948
		ns_main_earlyfatal("create_managers() failed: %s",
				   isc_result_totext(result));
Bob Halley's avatar
add  
Bob Halley committed
949

950 951
	ns_builtin_init();

952 953 954
	/*
	 * Add calls to register sdb drivers here.
	 */
955
	/* xxdb_init(); */
956

957 958 959 960 961 962 963 964 965 966 967
#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
968
	/*
969
	 * Register any other contributed DLZ drivers.
970 971 972 973 974 975 976
	 */
	result = dlz_drivers_init();
	if (result != ISC_R_SUCCESS)
		ns_main_earlyfatal("dlz_drivers_init() failed: %s",
				   isc_result_totext(result));
#endif

977
	ns_server_create(ns_g_mctx, &ns_g_server);
Bob Halley's avatar
add  
Bob Halley committed
978 979 980
}

static void
981
cleanup(void) {
Bob Halley's avatar
add  
Bob Halley committed
982
	destroy_managers();
983

984
	ns_server_destroy(&ns_g_server);
985

986 987
	ns_builtin_deinit();

988 989 990
	/*
	 * Add calls to unregister sdb drivers here.
	 */
991
	/* xxdb_clear(); */
992

993
#ifdef CONTRIB_DLZ
994
	/*
995
	 * Unregister contributed DLZ drivers.
996 997 998
	 */
	dlz_drivers_clear();
#endif
999 1000 1001 1002 1003 1004
#ifdef ISC_DLZ_DLOPEN
	/*
	 * Unregister "dlopen" DLZ driver.
	 */
	dlz_dlopen_clear();
#endif
1005

1006 1007
	dns_name_destroy();

1008
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
Bob Halley's avatar
Bob Halley committed
1009
		      ISC_LOG_NOTICE, "exiting");
1010
	ns_log_shutdown();
Bob Halley's avatar
add  
Bob Halley committed
1011 1012
}

1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
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 = malloc(strlen(filename) + 1);
	if (memstats)
		strcpy(memstats, filename);
}

1032 1033