main.c 37.8 KB
Newer Older
Bob Halley's avatar
add  
Bob Halley committed
1
/*
2
 * Copyright (C) 1999-2017  Internet Systems Consortium, Inc. ("ISC")
3
 *
4 5 6
 * 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/.
Bob Halley's avatar
add  
Bob Halley committed
7 8
 */

9
/*! \file */
David Lawrence's avatar
David Lawrence committed
10

Bob Halley's avatar
add  
Bob Halley committed
11 12
#include <config.h>

13
#include <ctype.h>
Bob Halley's avatar
add  
Bob Halley committed
14
#include <stdlib.h>
15
#include <string.h>
Bob Halley's avatar
add  
Bob Halley committed
16 17

#include <isc/app.h>
18
#include <isc/backtrace.h>
19
#include <isc/commandline.h>
20
#include <isc/dir.h>
21
#include <isc/entropy.h>
22
#include <isc/file.h>
23
#include <isc/hash.h>
24
#include <isc/httpd.h>
25
#include <isc/os.h>
26
#include <isc/platform.h>
27
#include <isc/print.h>
28
#include <isc/resource.h>
29
#include <isc/stdio.h>
30
#include <isc/string.h>
Bob Halley's avatar
add  
Bob Halley committed
31 32
#include <isc/task.h>
#include <isc/timer.h>
Bob Halley's avatar
Bob Halley committed
33
#include <isc/util.h>
Bob Halley's avatar
add  
Bob Halley committed
34

35 36
#include <isccc/result.h>

37
#include <dns/dispatch.h>
Evan Hunt's avatar
Evan Hunt committed
38
#include <dns/dyndb.h>
39
#include <dns/name.h>
40
#include <dns/result.h>
41
#include <dns/resolver.h>
David Lawrence's avatar
David Lawrence committed
42
#include <dns/view.h>
Bob Halley's avatar
add  
Bob Halley committed
43

44
#include <dst/result.h>
45 46 47
#ifdef PKCS11CRYPTO
#include <pk11/result.h>
#endif
48

49 50
#include <dlz/dlz_dlopen_driver.h>

51 52 53 54
#ifdef HAVE_GPERFTOOLS_PROFILER
#include <gperftools/profiler.h>
#endif

55

56
/*
57
 * Defining NAMED_MAIN provides storage declarations (rather than extern)
58 59
 * for variables in named/globals.h.
 */
60 61 62
#define NAMED_MAIN 1

#include <ns/interfacemgr.h>
Bob Halley's avatar
add  
Bob Halley committed
63

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

76 77
#ifdef OPENSSL
#include <openssl/opensslv.h>
78
#include <openssl/crypto.h>
79 80 81 82
#endif
#ifdef HAVE_LIBXML2
#include <libxml/xmlversion.h>
#endif
83 84 85
#ifdef HAVE_ZLIB
#include <zlib.h>
#endif
86 87 88
/*
 * Include header files for database drivers here.
 */
89
/* #include "xxdb.h" */
90

91
#ifdef CONTRIB_DLZ
92
/*
93
 * Include contributed DLZ drivers if appropriate.
94 95 96 97
 */
#include <dlz/dlz_drivers.h>
#endif

98 99 100 101 102 103 104
/*
 * The maximum number of stack frames to dump on assertion failure.
 */
#ifndef BACKTRACE_MAXFRAME
#define BACKTRACE_MAXFRAME 128
#endif

105 106 107 108
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;
Evan Hunt's avatar
Evan Hunt committed
109

David Lawrence's avatar
David Lawrence committed
110
static isc_boolean_t	want_stats = ISC_FALSE;
111 112
static char		program_name[ISC_DIR_NAMEMAX] = "named";
static char		absolute_conffile[ISC_DIR_PATHMAX];
113 114
static char		saved_command_line[512];
static char		version[512];
115
static unsigned int	maxsocks = 0;
116
static int		maxudp = 0;
Bob Halley's avatar
add  
Bob Halley committed
117

118 119 120 121 122 123 124 125 126 127 128
/*
 * -T options:
 */
static isc_boolean_t clienttest = ISC_FALSE;
static isc_boolean_t dropedns = ISC_FALSE;
static isc_boolean_t noedns = ISC_FALSE;
static isc_boolean_t nosoa = ISC_FALSE;
static isc_boolean_t noaa = ISC_FALSE;
static unsigned int delay = 0;
static isc_boolean_t nonearest = ISC_FALSE;
static isc_boolean_t notcp = ISC_FALSE;
129
static isc_boolean_t fixedlocal = ISC_FALSE;
130 131 132 133 134 135 136

/*
 * -4 and -6
 */
static isc_boolean_t disable6 = ISC_FALSE;
static isc_boolean_t disable4 = ISC_FALSE;

137
void
138
named_main_earlywarning(const char *format, ...) {
139 140 141
	va_list args;

	va_start(args, format);
142 143 144
	if (named_g_lctx != NULL) {
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_WARNING,
145 146 147 148 149 150 151 152 153 154
			       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
155
void
156
named_main_earlyfatal(const char *format, ...) {
Bob Halley's avatar
add  
Bob Halley committed
157 158 159
	va_list args;

	va_start(args, format);
160 161 162
	if (named_g_lctx != NULL) {
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
163
			       format, args);
164 165
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
Bob Halley's avatar
Bob Halley committed
166
			       "exiting (due to early fatal error)");
167
	} else {
168
		fprintf(stderr, "%s: ", program_name);
169 170
		vfprintf(stderr, format, args);
		fprintf(stderr, "\n");
171
		fflush(stderr);
172
	}
Bob Halley's avatar
add  
Bob Halley committed
173 174 175 176 177
	va_end(args);

	exit(1);
}

Francis Dupont's avatar
Francis Dupont committed
178 179 180 181
ISC_PLATFORM_NORETURN_PRE static void
assertion_failed(const char *file, int line, isc_assertiontype_t type,
		 const char *cond) ISC_PLATFORM_NORETURN_POST;

182
static void
David Lawrence's avatar
David Lawrence committed
183 184 185
assertion_failed(const char *file, int line, isc_assertiontype_t type,
		 const char *cond)
{
186 187 188 189 190 191
	void *tracebuf[BACKTRACE_MAXFRAME];
	int i, nframes;
	isc_result_t result;
	const char *logsuffix = "";
	const char *fname;

192 193 194 195
	/*
	 * Handle assertion failures.
	 */

196
	if (named_g_lctx != NULL) {
197
		/*
Francis Dupont's avatar
Francis Dupont committed
198
		 * Reset the assertion callback in case it is the log
199 200 201 202
		 * routines causing the assertion.
		 */
		isc_assertion_setcallback(NULL);

203 204 205 206
		result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
						&nframes);
		if (result == ISC_R_SUCCESS && nframes > 0)
			logsuffix = ", back trace";
207 208
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
209 210 211 212 213 214 215 216 217 218 219
			      "%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) {
220 221 222
					isc_log_write(named_g_lctx,
						      NAMED_LOGCATEGORY_GENERAL,
						      NAMED_LOGMODULE_MAIN,
223 224 225 226 227
						      ISC_LOG_CRITICAL,
						      "#%d %p in %s()+0x%lx", i,
						      tracebuf[i], fname,
						      offset);
				} else {
228 229 230
					isc_log_write(named_g_lctx,
						      NAMED_LOGCATEGORY_GENERAL,
						      NAMED_LOGMODULE_MAIN,
231 232 233 234 235 236
						      ISC_LOG_CRITICAL,
						      "#%d %p in ??", i,
						      tracebuf[i]);
				}
			}
		}
237 238
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
239
			      "exiting (due to assertion failure)");
240 241 242 243 244 245
	} else {
		fprintf(stderr, "%s:%d: %s(%s) failed\n",
			file, line, isc_assertion_typetotext(type), cond);
		fflush(stderr);
	}

246
	if (named_g_coreok)
247 248 249 250
		abort();
	exit(1);
}

Francis Dupont's avatar
Francis Dupont committed
251
ISC_PLATFORM_NORETURN_PRE static void
252
library_fatal_error(const char *file, int line, const char *format,
Francis Dupont's avatar
Francis Dupont committed
253 254
		    va_list args)
ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
255

256
static void
David Lawrence's avatar
David Lawrence committed
257 258 259
library_fatal_error(const char *file, int line, const char *format,
		    va_list args)
{
260 261 262 263
	/*
	 * Handle isc_error_fatal() calls from our libraries.
	 */

264
	if (named_g_lctx != NULL) {
265 266 267 268 269 270
		/*
		 * Reset the error callback in case it is the log
		 * routines causing the assertion.
		 */
		isc_error_setfatal(NULL);

271 272
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
273
			      "%s:%d: fatal error:", file, line);
274 275
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
276
			       format, args);
277 278
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
279 280 281 282 283 284 285 286
			      "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);
	}

287
	if (named_g_coreok)
288 289 290 291
		abort();
	exit(1);
}

292 293 294 295
static void
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args) ISC_FORMAT_PRINTF(3, 0);

296
static void
David Lawrence's avatar
David Lawrence committed
297 298 299
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args)
{
300 301 302 303
	/*
	 * Handle isc_error_unexpected() calls from our libraries.
	 */

304 305 306
	if (named_g_lctx != NULL) {
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR,
307
			      "%s:%d: unexpected error:", file, line);
308 309
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR,
310 311 312 313 314 315 316 317 318
			       format, args);
	} else {
		fprintf(stderr, "%s:%d: fatal error: ", file, line);
		vfprintf(stderr, format, args);
		fprintf(stderr, "\n");
		fflush(stderr);
	}
}

Bob Halley's avatar
add  
Bob Halley committed
319 320 321
static void
usage(void) {
	fprintf(stderr,
Mark Andrews's avatar
Mark Andrews committed
322
		"usage: named [-4|-6] [-c conffile] [-d debuglevel] "
Francis Dupont's avatar
Francis Dupont committed
323 324
		"[-E engine] [-f|-g]\n"
		"             [-n number_of_cpus] [-p port] [-s] "
Mark Andrews's avatar
Mark Andrews committed
325 326 327 328
		"[-S sockets] [-t chrootdir]\n"
		"             [-u username] [-U listeners] "
		"[-m {usage|trace|record|size|mctx}]\n"
		"usage: named [-v|-V]\n");
Bob Halley's avatar
add  
Bob Halley committed
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 360 361 362 363 364 365 366 367 368 369 370 371 372 373
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';
}

374 375 376 377 378 379
static int
parse_int(char *arg, const char *desc) {
	char *endp;
	int tmp;
	long int ltmp;

380
	ltmp = strtol(arg, &endp, 10);
381 382
	tmp = (int) ltmp;
	if (*endp != '\0')
383
		named_main_earlyfatal("%s '%s' must be numeric", desc, arg);
384
	if (tmp < 0 || tmp != ltmp)
385
		named_main_earlyfatal("%s '%s' out of range", desc, arg);
386 387 388
	return (tmp);
}

389 390 391
static struct flag_def {
	const char *name;
	unsigned int value;
392
	isc_boolean_t negate;
393
} mem_debug_flags[] = {
394 395 396 397 398 399 400 401 402 403 404 405
	{ "none", 0, ISC_FALSE },
	{ "trace",  ISC_MEM_DEBUGTRACE, ISC_FALSE },
	{ "record", ISC_MEM_DEBUGRECORD, ISC_FALSE },
	{ "usage", ISC_MEM_DEBUGUSAGE, ISC_FALSE },
	{ "size", ISC_MEM_DEBUGSIZE, ISC_FALSE },
	{ "mctx", ISC_MEM_DEBUGCTX, ISC_FALSE },
	{ NULL, 0, ISC_FALSE }
}, mem_context_flags[] = {
	{ "external", ISC_MEMFLAG_INTERNAL, ISC_TRUE },
	{ "fill", ISC_MEMFLAG_FILL, ISC_FALSE },
	{ "nofill", ISC_MEMFLAG_FILL, ISC_TRUE },
	{ NULL, 0, ISC_FALSE }
406 407 408 409
};

static void
set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
410 411
	isc_boolean_t clear = ISC_FALSE;

412 413 414
	for (;;) {
		const struct flag_def *def;
		const char *end = strchr(arg, ',');
Mark Andrews's avatar
Mark Andrews committed
415
		int arglen;
416 417
		if (end == NULL)
			end = arg + strlen(arg);
418
		arglen = (int)(end - arg);
419
		for (def = defs; def->name != NULL; def++) {
Mark Andrews's avatar
Mark Andrews committed
420 421
			if (arglen == (int)strlen(def->name) &&
			    memcmp(arg, def->name, arglen) == 0) {
422 423
				if (def->value == 0)
					clear = ISC_TRUE;
424 425 426 427
				if (def->negate)
					*ret &= ~(def->value);
				else
					*ret |= def->value;
428 429 430
				goto found;
			}
		}
431
		named_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
432
	 found:
433
		if (clear || (*end == '\0'))
434 435 436
			break;
		arg = end + 1;
	}
437 438 439

	if (clear)
		*ret = 0;
440 441
}

442 443 444
static void
parse_fuzz_arg(void) {
	if (!strncmp(isc_commandline_argument, "client:", 7)) {
445 446
		named_g_fuzz_addr = isc_commandline_argument + 7;
		named_g_fuzz_type = isc_fuzz_client;
447
	} else if (!strncmp(isc_commandline_argument, "tcp:", 4)) {
448 449
		named_g_fuzz_addr = isc_commandline_argument + 4;
		named_g_fuzz_type = isc_fuzz_tcpclient;
450
	} else if (!strncmp(isc_commandline_argument, "resolver:", 9)) {
451 452
		named_g_fuzz_addr = isc_commandline_argument + 9;
		named_g_fuzz_type = isc_fuzz_resolver;
453
	} else if (!strncmp(isc_commandline_argument, "http:", 5)) {
454 455
		named_g_fuzz_addr = isc_commandline_argument + 5;
		named_g_fuzz_type = isc_fuzz_http;
456
	} else if (!strncmp(isc_commandline_argument, "rndc:", 5)) {
457 458
		named_g_fuzz_addr = isc_commandline_argument + 5;
		named_g_fuzz_type = isc_fuzz_rndc;
459
	} else {
460
		named_main_earlyfatal("unknown fuzzing type '%s'",
461 462 463 464
				   isc_commandline_argument);
	}
}

465
static void
Bob Halley's avatar
add  
Bob Halley committed
466 467
parse_command_line(int argc, char *argv[]) {
	int ch;
468
	int port;
469
	const char *p;
470

471 472
	save_command_line(argc, argv);

473
	/*
474
	 * NAMED_MAIN_ARGS is defined in main.h, so that it can be used
475 476
	 * both by named and by ntservice hooks.
	 */
477
	isc_commandline_errprint = ISC_FALSE;
478 479 480
	while ((ch = isc_commandline_parse(argc, argv,
					   NAMED_MAIN_ARGS)) != -1)
	{
Bob Halley's avatar
add  
Bob Halley committed
481
		switch (ch) {
482
		case '4':
483 484 485
			if (disable4)
				named_main_earlyfatal("cannot specify "
						      "-4 and -6");
486
			if (isc_net_probeipv4() != ISC_R_SUCCESS)
487 488
				named_main_earlyfatal("IPv4 not supported "
						      "by OS");
489
			isc_net_disableipv6();
490
			disable6 = ISC_TRUE;
491 492
			break;
		case '6':
493 494 495
			if (disable6)
				named_main_earlyfatal("cannot specify "
						      "-4 and -6");
496
			if (isc_net_probeipv6() != ISC_R_SUCCESS)
497 498
				named_main_earlyfatal("IPv6 not supported "
						      "by OS");
499
			isc_net_disableipv4();
500
			disable4 = ISC_TRUE;
501
			break;
502 503 504
		case 'A':
			parse_fuzz_arg();
			break;
Bob Halley's avatar
add  
Bob Halley committed
505
		case 'c':
506 507
			named_g_conffile = isc_commandline_argument;
			named_g_conffileset = ISC_TRUE;
Bob Halley's avatar
add  
Bob Halley committed
508
			break;
Bob Halley's avatar
Bob Halley committed
509
		case 'd':
510 511
			named_g_debuglevel = parse_int(isc_commandline_argument,
						       "debug level");
Bob Halley's avatar
Bob Halley committed
512
			break;
513 514 515
		case 'D':
			/* Descriptive comment for 'ps'. */
			break;
Francis Dupont's avatar
Francis Dupont committed
516
		case 'E':
517
			named_g_engine = isc_commandline_argument;
Francis Dupont's avatar
Francis Dupont committed
518
			break;
519
		case 'f':
520
			named_g_foreground = ISC_TRUE;
521
			break;
522
		case 'g':
523 524
			named_g_foreground = ISC_TRUE;
			named_g_logstderr = ISC_TRUE;
525
			break;
526
		case 'L':
527
			named_g_logfile = isc_commandline_argument;
528
			break;
529
		case 'M':
530 531
			set_flags(isc_commandline_argument, mem_context_flags,
				  &isc_mem_defaultflags);
532
			break;
533 534 535 536
		case 'm':
			set_flags(isc_commandline_argument, mem_debug_flags,
				  &isc_mem_debugging);
			break;
537 538
		case 'N': /* Deprecated. */
		case 'n':
539
			named_g_cpus = parse_int(isc_commandline_argument,
540
					      "number of cpus");
541 542
			if (named_g_cpus == 0)
				named_g_cpus = 1;
Bob Halley's avatar
add  
Bob Halley committed
543
			break;
Bob Halley's avatar
Bob Halley committed
544
		case 'p':
545
			port = parse_int(isc_commandline_argument, "port");
546
			if (port < 1 || port > 65535)
547
				named_main_earlyfatal("port '%s' out of range",
548
						   isc_commandline_argument);
549
			named_g_port = port;
550
			break;
Bob Halley's avatar
add  
Bob Halley committed
551 552 553 554
		case 's':
			/* XXXRTH temporary syntax */
			want_stats = ISC_TRUE;
			break;
555 556 557 558
		case 'S':
			maxsocks = parse_int(isc_commandline_argument,
					     "max number of sockets");
			break;
559
		case 't':
560
			/* XXXJAB should we make a copy? */
561
			named_g_chrootdir = isc_commandline_argument;
562
			break;
Mark Andrews's avatar
Mark Andrews committed
563
		case 'T':	/* NOT DOCUMENTED */
564
			/*
Evan Hunt's avatar
Evan Hunt committed
565 566 567
			 * force the server to behave (or misbehave) in
			 * specified ways for testing purposes.
			 *
568 569
			 * clienttest: make clients single shot with their
			 * 	       own memory context.
570 571
			 * delay=xxxx: delay client responses by xxxx ms to
			 *	       simulate remote servers.
Evan Hunt's avatar
Evan Hunt committed
572 573
			 * dscp=x:     check that dscp values are as
			 * 	       expected and assert otherwise.
574
			 */
575
			if (!strcmp(isc_commandline_argument, "clienttest"))
576
				clienttest = ISC_TRUE;
577
			else if (!strcmp(isc_commandline_argument, "nosoa"))
578
				nosoa = ISC_TRUE;
579
			else if (!strcmp(isc_commandline_argument, "noaa"))
580 581 582
				noaa = ISC_TRUE;
			else if (!strcmp(isc_commandline_argument,
					 "maxudp512"))
583
				maxudp = 512;
584 585
			else if (!strcmp(isc_commandline_argument,
					 "maxudp1460"))
586
				maxudp = 1460;
587
			else if (!strcmp(isc_commandline_argument, "dropedns"))
588
				dropedns = ISC_TRUE;
589
			else if (!strcmp(isc_commandline_argument, "noedns"))
590
				noedns = ISC_TRUE;
591 592 593
			else if (!strncmp(isc_commandline_argument,
					  "maxudp=", 7))
				maxudp = atoi(isc_commandline_argument + 7);
594 595
			else if (!strncmp(isc_commandline_argument,
					  "delay=", 6))
596
				delay = atoi(isc_commandline_argument + 6);
597
			else if (!strcmp(isc_commandline_argument, "nosyslog"))
598
				named_g_nosyslog = ISC_TRUE;
599
			else if (!strcmp(isc_commandline_argument, "nonearest"))
600
				nonearest = ISC_TRUE;
Evan Hunt's avatar
Evan Hunt committed
601 602 603
			else if (!strncmp(isc_commandline_argument, "dscp=", 5))
				isc_dscp_check_value =
					   atoi(isc_commandline_argument + 5);
Evan Hunt's avatar
Evan Hunt committed
604 605 606 607 608
			else if (!strncmp(isc_commandline_argument,
					  "mkeytimers=", 11))
			{
				p = strtok(isc_commandline_argument + 11, "/");
				if (p == NULL)
609
					named_main_earlyfatal("bad mkeytimer");
Evan Hunt's avatar
Evan Hunt committed
610 611
				dns_zone_mkey_hour = atoi(p);
				if (dns_zone_mkey_hour == 0)
612
					named_main_earlyfatal("bad mkeytimer");
Evan Hunt's avatar
Evan Hunt committed
613 614 615 616 617 618 619 620 621 622 623

				p = strtok(NULL, "/");
				if (p == NULL) {
					dns_zone_mkey_day =
						(24 * dns_zone_mkey_hour);
					dns_zone_mkey_month =
						(30 * dns_zone_mkey_day);
					break;
				}
				dns_zone_mkey_day = atoi(p);
				if (dns_zone_mkey_day < dns_zone_mkey_hour)
624
					named_main_earlyfatal("bad mkeytimer");
Evan Hunt's avatar
Evan Hunt committed
625 626 627 628 629 630 631 632 633

				p = strtok(NULL, "/");
				if (p == NULL) {
					dns_zone_mkey_month =
						(30 * dns_zone_mkey_day);
					break;
				}
				dns_zone_mkey_month = atoi(p);
				if (dns_zone_mkey_month < dns_zone_mkey_day)
634
					named_main_earlyfatal("bad mkeytimer");
Evan Hunt's avatar
Evan Hunt committed
635
			} else if (!strcmp(isc_commandline_argument, "notcp"))
636
				notcp = ISC_TRUE;
637
			else if (!strncmp(isc_commandline_argument, "tat=", 4))
638
			{
639
				named_g_tat_interval =
640
					   atoi(isc_commandline_argument + 4);
641
			} else if (!strcmp(isc_commandline_argument,
642
					 "keepstderr"))
643
			{
644
				named_g_keepstderr = ISC_TRUE;
645 646 647 648 649
			} else if (!strcmp(isc_commandline_argument,
					   "fixedlocal"))
			{
				fixedlocal = ISC_TRUE;
			} else {
650 651
				fprintf(stderr, "unknown -T flag '%s\n",
					isc_commandline_argument);
652
			}
653
			break;
654
		case 'U':
655 656 657
			named_g_udpdisp = parse_int(isc_commandline_argument,
						    "number of UDP listeners "
						    "per interface");
658
			break;
659
		case 'u':
660
			named_g_username = isc_commandline_argument;
661
			break;
662
		case 'v':
Evan Hunt's avatar
Evan Hunt committed
663
			printf("%s %s%s%s <id:%s>\n",
664 665 666
			       named_g_product, named_g_version,
			       (*named_g_description != '\0') ? " " : "",
			       named_g_description, named_g_srcid);
667
			exit(0);
668
		case 'V':
669 670 671 672 673
			printf("%s %s%s%s <id:%s>\n",
			       named_g_product, named_g_version,
			       (*named_g_description != '\0') ? " " : "",
			       named_g_description, named_g_srcid);
			printf("running on %s\n", named_os_uname());
Evan Hunt's avatar
Evan Hunt committed
674
			printf("built by %s with %s\n",
675
			       named_g_builder, named_g_configargs);
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
#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
693
#ifdef OPENSSL
694
			printf("compiled with OpenSSL version: %s\n",
695
			       OPENSSL_VERSION_TEXT);
696 697
#if !defined(LIBRESSL_VERSION_NUMBER) && \
    OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 or higher */
698 699 700 701
			printf("linked to OpenSSL version: %s\n",
			       OpenSSL_version(OPENSSL_VERSION));

#else
702 703
			printf("linked to OpenSSL version: %s\n",
			       SSLeay_version(SSLEAY_VERSION));
704
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
705 706
#endif
#ifdef HAVE_LIBXML2
707
			printf("compiled with libxml2 version: %s\n",
708
			       LIBXML_DOTTED_VERSION);
709 710
			printf("linked to libxml2 version: %s\n",
			       xmlParserVersion);
Evan Hunt's avatar
Evan Hunt committed
711
#endif
712
#if defined(HAVE_JSON) && defined(JSON_C_VERSION)
Evan Hunt's avatar
Evan Hunt committed
713 714 715 716
			printf("compiled with libjson-c version: %s\n",
			       JSON_C_VERSION);
			printf("linked to libjson-c version: %s\n",
			       json_c_version());
717
#endif
718 719 720 721 722 723
#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
724 725 726 727
#ifdef ISC_PLATFORM_USETHREADS
			printf("threads support is enabled\n");
#else
			printf("threads support is disabled\n");
728
#endif
729
			exit(0);
730 731 732 733
		case 'x':
			/* Obsolete. No longer in use. Ignore. */
			break;
		case 'X':
734
			named_g_forcelock = ISC_TRUE;
735
			if (strcasecmp(isc_commandline_argument, "none") != 0)
736 737
				named_g_defaultlockfile =
					isc_commandline_argument;
738
			else
739
				named_g_defaultlockfile = NULL;
740
			break;
Francis Dupont's avatar
Francis Dupont committed
741 742 743
		case 'F':
			/* Reserved for FIPS mode */
			/* FALLTHROUGH */
744
		case '?':
745
			usage();
746 747
			if (isc_commandline_option == '?')
				exit(0);
748
			p = strchr(NAMED_MAIN_ARGS, isc_commandline_option);
749
			if (p == NULL || *++p != ':')
750
				named_main_earlyfatal("unknown option '-%c'",
751 752
						   isc_commandline_option);
			else
753
				named_main_earlyfatal("option '-%c' requires "
754 755
						   "an argument",
						   isc_commandline_option);
Francis Dupont's avatar
Francis Dupont committed
756
			/* FALLTHROUGH */
Bob Halley's avatar
add  
Bob Halley committed
757
		default:
758 759
			named_main_earlyfatal("parsing options returned %d",
					      ch);
Bob Halley's avatar
add  
Bob Halley committed
760 761 762
		}
	}

763 764
	argc -= isc_commandline_index;
	argv += isc_commandline_index;
765
	POST(argv);
Bob Halley's avatar
add  
Bob Halley committed
766

767
	if (argc > 0) {
Bob Halley's avatar
add  
Bob Halley committed
768
		usage();
769
		named_main_earlyfatal("extra command line arguments");
Bob Halley's avatar
add  
Bob Halley committed
770 771 772 773
	}
}

static isc_result_t
774
create_managers(void) {
Bob Halley's avatar
add  
Bob Halley committed
775
	isc_result_t result;
776
	unsigned int socks;
Bob Halley's avatar
add  
Bob Halley committed
777

778
	INSIST(named_g_cpus_detected > 0);
779

780
#ifdef ISC_PLATFORM_USETHREADS
781 782 783 784 785 786 787 788
	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");
789
#else
790
	named_g_cpus = 1;
791
#endif
792
#ifdef WIN32
793
	named_g_udpdisp = 1;
794
#else
795 796 797
	if (named_g_udpdisp == 0) {
		if (named_g_cpus_detected == 1)
			named_g_udpdisp = 1;
Evan Hunt's avatar
Evan Hunt committed
798
		else
799
			named_g_udpdisp = named_g_cpus_detected - 1;
Evan Hunt's avatar
Evan Hunt committed
800
	}
801 802
	if (named_g_udpdisp > named_g_cpus)
		named_g_udpdisp = named_g_cpus;
803
#endif
804
#ifdef ISC_PLATFORM_USETHREADS
805 806 807 808
	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");
809
#endif
810

811 812
	result = isc_taskmgr_create(named_g_mctx, named_g_cpus, 0,
				    &named_g_taskmgr);
Bob Halley's avatar
add  
Bob Halley committed
813 814
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
Mark Andrews's avatar
Mark Andrews committed
815
				 "isc_taskmgr_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
816 817 818 819
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

820
	result = isc_timermgr_create(named_g_mctx, &named_g_timermgr);
Bob Halley's avatar
add  
Bob Halley committed
821 822
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
Mark Andrews's avatar
Mark Andrews committed
823
				 "isc_timermgr_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
824 825 826 827
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

828 829
	result = isc_socketmgr_create2(named_g_mctx, &named_g_socketmgr,
				       maxsocks);
Bob Halley's avatar
add  
Bob Halley committed
830 831
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
832
				 "isc_socketmgr_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
833 834 835
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}
836 837
	isc__socketmgr_maxudp(named_g_socketmgr, maxudp);
	result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &socks);
838
	if (result == ISC_R_SUCCESS) {
839 840
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_SERVER,
841 842
			      ISC_LOG_INFO, "using up to %u sockets", socks);
	}
Bob Halley's avatar
add  
Bob Halley committed
843