main.c 40.1 KB
Newer Older
Bob Halley's avatar
add    
Bob Halley committed
1
/*
2
 * Copyright (C) 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/.
7
8
9
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
Bob Halley's avatar
add    
Bob Halley committed
10
11
 */

12
/*! \file */
David Lawrence's avatar
David Lawrence committed
13

14
#include <ctype.h>
15
#include <inttypes.h>
16
#include <stdbool.h>
Bob Halley's avatar
add    
Bob Halley committed
17
#include <stdlib.h>
18
#include <string.h>
Bob Halley's avatar
add    
Bob Halley committed
19
20

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

37
38
#include <isccc/result.h>

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

46
#include <dst/result.h>
Ondřej Surý's avatar
Ondřej Surý committed
47
#if USE_PKCS11
48
49
#include <pk11/result.h>
#endif
50

51
52
#include <dlz/dlz_dlopen_driver.h>

53
54
55
56
#ifdef HAVE_GPERFTOOLS_PROFILER
#include <gperftools/profiler.h>
#endif

57
58
59
#ifdef HAVE_JSON_C
#include <json_c_version.h>
#endif /* HAVE_JSON_C */
60

61
/*
62
 * Defining NAMED_MAIN provides storage declarations (rather than extern)
63
64
 * for variables in named/globals.h.
 */
65
66
67
#define NAMED_MAIN 1

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

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

81
#include <openssl/opensslv.h>
82
#include <openssl/crypto.h>
83
84
#ifdef HAVE_LIBXML2
#include <libxml/xmlversion.h>
85
#include <libxml/parser.h>
86
#endif
87
88
89
#ifdef HAVE_ZLIB
#include <zlib.h>
#endif
90
91
92
/*
 * Include header files for database drivers here.
 */
93
/* #include "xxdb.h" */
94

95
#ifdef CONTRIB_DLZ
96
/*
97
 * Include contributed DLZ drivers if appropriate.
98
99
100
101
 */
#include <dlz/dlz_drivers.h>
#endif

102
103
104
105
106
107
108
/*
 * The maximum number of stack frames to dump on assertion failure.
 */
#ifndef BACKTRACE_MAXFRAME
#define BACKTRACE_MAXFRAME 128
#endif

109
110
111
112
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
113

114
static bool	want_stats = false;
Ondřej Surý's avatar
Ondřej Surý committed
115
116
static char		program_name[NAME_MAX] = "named";
static char		absolute_conffile[PATH_MAX];
117
118
static char		saved_command_line[8192] =  { 0 };
static char		ellipsis[5] = { 0 };
119
static char		version[512];
120
static unsigned int	maxsocks = 0;
121
static int		maxudp = 0;
Bob Halley's avatar
add    
Bob Halley committed
122

123
124
125
/*
 * -T options:
 */
126
127
static bool clienttest = false;
static bool dropedns = false;
128
129
130
131
static bool ednsformerr = false;
static bool ednsnotimp = false;
static bool ednsrefused = false;
static bool fixedlocal = false;
132
static bool noaa = false;
133
static bool noedns = false;
134
static bool nonearest = false;
135
static bool nosoa = false;
136
137
static bool notcp = false;
static bool sigvalinsecs = false;
138
static unsigned int delay = 0;
139
140
141
142

/*
 * -4 and -6
 */
143
144
static bool disable6 = false;
static bool disable4 = false;
145

146
void
147
named_main_earlywarning(const char *format, ...) {
148
149
150
	va_list args;

	va_start(args, format);
151
152
153
	if (named_g_lctx != NULL) {
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_WARNING,
154
155
156
157
158
159
160
161
162
163
			       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
164
void
165
named_main_earlyfatal(const char *format, ...) {
Bob Halley's avatar
add    
Bob Halley committed
166
167
168
	va_list args;

	va_start(args, format);
169
170
171
	if (named_g_lctx != NULL) {
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
172
			       format, args);
173
174
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
Bob Halley's avatar
Bob Halley committed
175
			       "exiting (due to early fatal error)");
176
	} else {
177
		fprintf(stderr, "%s: ", program_name);
178
179
		vfprintf(stderr, format, args);
		fprintf(stderr, "\n");
180
		fflush(stderr);
181
	}
Bob Halley's avatar
add    
Bob Halley committed
182
183
184
185
186
	va_end(args);

	exit(1);
}

Francis Dupont's avatar
Francis Dupont committed
187
188
189
190
ISC_PLATFORM_NORETURN_PRE static void
assertion_failed(const char *file, int line, isc_assertiontype_t type,
		 const char *cond) ISC_PLATFORM_NORETURN_POST;

191
static void
David Lawrence's avatar
David Lawrence committed
192
193
194
assertion_failed(const char *file, int line, isc_assertiontype_t type,
		 const char *cond)
{
195
196
197
198
199
200
	void *tracebuf[BACKTRACE_MAXFRAME];
	int i, nframes;
	isc_result_t result;
	const char *logsuffix = "";
	const char *fname;

201
202
203
204
	/*
	 * Handle assertion failures.
	 */

205
	if (named_g_lctx != NULL) {
206
		/*
Francis Dupont's avatar
Francis Dupont committed
207
		 * Reset the assertion callback in case it is the log
208
209
210
211
		 * routines causing the assertion.
		 */
		isc_assertion_setcallback(NULL);

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

255
	if (named_g_coreok)
256
257
258
259
		abort();
	exit(1);
}

Francis Dupont's avatar
Francis Dupont committed
260
ISC_PLATFORM_NORETURN_PRE static void
261
library_fatal_error(const char *file, int line, const char *format,
Francis Dupont's avatar
Francis Dupont committed
262
263
		    va_list args)
ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
264

265
static void
David Lawrence's avatar
David Lawrence committed
266
267
268
library_fatal_error(const char *file, int line, const char *format,
		    va_list args)
{
269
270
271
272
	/*
	 * Handle isc_error_fatal() calls from our libraries.
	 */

273
	if (named_g_lctx != NULL) {
274
275
276
277
278
279
		/*
		 * Reset the error callback in case it is the log
		 * routines causing the assertion.
		 */
		isc_error_setfatal(NULL);

280
281
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
282
			      "%s:%d: fatal error:", file, line);
283
284
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
285
			       format, args);
286
287
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
288
289
290
291
292
293
294
295
			      "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);
	}

296
	if (named_g_coreok)
297
298
299
300
		abort();
	exit(1);
}

301
302
303
304
static void
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args) ISC_FORMAT_PRINTF(3, 0);

305
static void
David Lawrence's avatar
David Lawrence committed
306
307
308
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args)
{
309
310
311
312
	/*
	 * Handle isc_error_unexpected() calls from our libraries.
	 */

313
314
315
	if (named_g_lctx != NULL) {
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR,
316
			      "%s:%d: unexpected error:", file, line);
317
318
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			       NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR,
319
320
321
322
323
324
325
326
327
			       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
328
329
330
static void
usage(void) {
	fprintf(stderr,
Mark Andrews's avatar
Mark Andrews committed
331
		"usage: named [-4|-6] [-c conffile] [-d debuglevel] "
Francis Dupont's avatar
Francis Dupont committed
332
333
		"[-E engine] [-f|-g]\n"
		"             [-n number_of_cpus] [-p port] [-s] "
Mark Andrews's avatar
Mark Andrews committed
334
335
336
337
		"[-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
338
339
}

340
341
342
static void
save_command_line(int argc, char *argv[]) {
	int i;
343
344
	char *dst = saved_command_line;
	char *eob = saved_command_line + sizeof(saved_command_line) - 1;
345
	char *rollback = dst;
346
347

	for (i = 1; i < argc && dst < eob; i++) {
348
349
350
351
		char *src = argv[i];
		bool quoted = false;

		rollback = dst;
352
353
354
		*dst++ = ' ';

		while (*src != '\0' && dst < eob) {
355
			if (isalnum(*src) || *src == ',' ||
356
			    *src == '-' || *src == '_' ||
357
358
			    *src == '.' || *src == '/')
			{
359
				*dst++ = *src++;
360
361
362
363
			} else if (isprint(*src)) {
				if (dst + 2 >= eob) {
					goto add_ellipsis;
				}
364
				*dst++ = '\\';
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
				*dst++ = *src++;
			} else {
				/*
				 * Control character found in the input,
				 * quote the whole arg and restart
				 */
				if (!quoted) {
					dst = rollback;
					src = argv[i];

					if (dst + 3 >= eob) {
						goto add_ellipsis;
					}

					*dst++ = ' ';
					*dst++ = '$';
					*dst++ = '\'';

					quoted = true;
					continue;
				} else {
					char tmp[5];
					int c = snprintf(tmp, sizeof(tmp),
							 "\\%03o", *src++);
					if (dst + c >= eob) {
						goto add_ellipsis;
					}
					memmove(dst, tmp, c);
					dst += c;
				}
395
396
			}
		}
397
398
399
400
401
402
		if (quoted) {
			if (dst == eob) {
				goto add_ellipsis;
			}
			*dst++ = '\'';
		}
403

404
	}
405

406
407
408
409
410
411
412
	if (dst < eob) {
		return;
	}
add_ellipsis:
	dst = rollback;
	*dst = '\0';
	strlcpy(ellipsis, " ...", sizeof(ellipsis));
413
414
}

415
416
417
418
419
420
static int
parse_int(char *arg, const char *desc) {
	char *endp;
	int tmp;
	long int ltmp;

421
	ltmp = strtol(arg, &endp, 10);
422
423
	tmp = (int) ltmp;
	if (*endp != '\0')
424
		named_main_earlyfatal("%s '%s' must be numeric", desc, arg);
425
	if (tmp < 0 || tmp != ltmp)
426
		named_main_earlyfatal("%s '%s' out of range", desc, arg);
427
428
429
	return (tmp);
}

430
431
432
static struct flag_def {
	const char *name;
	unsigned int value;
433
	bool negate;
434
} mem_debug_flags[] = {
435
436
437
438
439
440
441
	{ "none", 0, false },
	{ "trace",  ISC_MEM_DEBUGTRACE, false },
	{ "record", ISC_MEM_DEBUGRECORD, false },
	{ "usage", ISC_MEM_DEBUGUSAGE, false },
	{ "size", ISC_MEM_DEBUGSIZE, false },
	{ "mctx", ISC_MEM_DEBUGCTX, false },
	{ NULL, 0, false }
442
}, mem_context_flags[] = {
443
444
445
446
	{ "external", ISC_MEMFLAG_INTERNAL, true },
	{ "fill", ISC_MEMFLAG_FILL, false },
	{ "nofill", ISC_MEMFLAG_FILL, true },
	{ NULL, 0, false }
447
448
449
450
};

static void
set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
451
	bool clear = false;
452

453
454
455
	for (;;) {
		const struct flag_def *def;
		const char *end = strchr(arg, ',');
Mark Andrews's avatar
Mark Andrews committed
456
		int arglen;
457
458
		if (end == NULL)
			end = arg + strlen(arg);
459
		arglen = (int)(end - arg);
460
		for (def = defs; def->name != NULL; def++) {
Mark Andrews's avatar
Mark Andrews committed
461
462
			if (arglen == (int)strlen(def->name) &&
			    memcmp(arg, def->name, arglen) == 0) {
463
				if (def->value == 0)
464
					clear = true;
465
466
467
468
				if (def->negate)
					*ret &= ~(def->value);
				else
					*ret |= def->value;
469
470
471
				goto found;
			}
		}
472
		named_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
473
	 found:
474
		if (clear || (*end == '\0'))
475
476
477
			break;
		arg = end + 1;
	}
478
479
480

	if (clear)
		*ret = 0;
481
482
}

483
484
static void
printversion(bool verbose) {
485
486
	char rndcconf[PATH_MAX], *dot = NULL;

487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
	printf("%s %s%s%s <id:%s>\n",
	       named_g_product, named_g_version,
	       (*named_g_description != '\0') ? " " : "",
	       named_g_description, named_g_srcid);

	if (!verbose) {
		return;
	}

	printf("running on %s\n", named_os_uname());
	printf("built by %s with %s\n",
	       named_g_builder, named_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
	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 */
#ifdef HAVE_LIBXML2
	printf("compiled with libxml2 version: %s\n",
	       LIBXML_DOTTED_VERSION);
	printf("linked to libxml2 version: %s\n",
	       xmlParserVersion);
#endif
533
534
#if defined(HAVE_JSON_C)
	printf("compiled with json-c version: %s\n",
535
	       JSON_C_VERSION);
536
	printf("linked to json-c version: %s\n",
537
538
539
540
541
542
543
544
545
546
	       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
	printf("threads support is enabled\n\n");

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561

	/*
	 * The default rndc.conf and rndc.key paths are in the same
	 * directory, but named only has rndc.key defined internally.
	 * We construct the rndc.conf path from it. (We could use
	 * NAMED_SYSCONFDIR here but the result would look wrong on
	 * Windows.)
	 */
	strlcpy(rndcconf, named_g_keyfile, sizeof(rndcconf));
	dot = strrchr(rndcconf, '.');
	if (dot != NULL) {
		size_t len = dot - rndcconf + 1;
		snprintf(dot + 1, PATH_MAX - len, "conf");
	}

562
563
564
565
566
	/*
	 * Print default configuration paths.
	 */
	printf("default paths:\n");
	printf("  named configuration:  %s\n", named_g_conffile);
567
	printf("  rndc configuration:   %s\n", rndcconf);
568
569
570
571
572
573
574
	printf("  DNSSEC root key:      %s\n", named_g_defaultbindkeys);
	printf("  nsupdate session key: %s\n", named_g_defaultsessionkeyfile);
	printf("  named PID file:       %s\n", named_g_defaultpidfile);
	printf("  named lock file:      %s\n", named_g_defaultlockfile);

}

575
576
577
static void
parse_fuzz_arg(void) {
	if (!strncmp(isc_commandline_argument, "client:", 7)) {
578
579
		named_g_fuzz_addr = isc_commandline_argument + 7;
		named_g_fuzz_type = isc_fuzz_client;
580
	} else if (!strncmp(isc_commandline_argument, "tcp:", 4)) {
581
582
		named_g_fuzz_addr = isc_commandline_argument + 4;
		named_g_fuzz_type = isc_fuzz_tcpclient;
583
	} else if (!strncmp(isc_commandline_argument, "resolver:", 9)) {
584
585
		named_g_fuzz_addr = isc_commandline_argument + 9;
		named_g_fuzz_type = isc_fuzz_resolver;
586
	} else if (!strncmp(isc_commandline_argument, "http:", 5)) {
587
588
		named_g_fuzz_addr = isc_commandline_argument + 5;
		named_g_fuzz_type = isc_fuzz_http;
589
	} else if (!strncmp(isc_commandline_argument, "rndc:", 5)) {
590
591
		named_g_fuzz_addr = isc_commandline_argument + 5;
		named_g_fuzz_type = isc_fuzz_rndc;
592
	} else {
593
		named_main_earlyfatal("unknown fuzzing type '%s'",
594
595
596
597
				   isc_commandline_argument);
	}
}

598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
static void
parse_T_opt(char *option) {
	const char *p;
	char *last = NULL;
	/*
	 * force the server to behave (or misbehave) in
	 * specified ways for testing purposes.
	 *
	 * 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")) {
614
		clienttest = true;
615
616
617
	} else if (!strncmp(option, "delay=", 6)) {
		delay = atoi(option + 6);
	} else if (!strcmp(option, "dropedns")) {
618
		dropedns = true;
619
620
	} else if (!strncmp(option, "dscp=", 5)) {
		isc_dscp_check_value = atoi(option + 5);
621
622
623
624
625
626
	} else if (!strcmp(option, "ednsformerr")) {
		ednsformerr = true;
	} else if (!strcmp(option, "ednsnotimp")) {
		ednsnotimp = true;
	} else if (!strcmp(option, "ednsrefused")) {
		ednsrefused = true;
627
	} else if (!strcmp(option, "fixedlocal")) {
628
		fixedlocal = true;
629
	} else if (!strcmp(option, "keepstderr")) {
630
		named_g_keepstderr = true;
631
	} else if (!strcmp(option, "noaa")) {
632
		noaa = true;
633
	} else if (!strcmp(option, "noedns")) {
634
		noedns = true;
635
	} else if (!strcmp(option, "nonearest")) {
636
		nonearest = true;
637
	} else if (!strcmp(option, "nosoa")) {
638
		nosoa = true;
639
	} else if (!strcmp(option, "nosyslog")) {
640
		named_g_nosyslog = true;
641
	} else if (!strcmp(option, "notcp")) {
642
		notcp = true;
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
	} 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_r(option + 11, "/", &last);
		if (p == NULL) {
			named_main_earlyfatal("bad mkeytimer");
		}

		dns_zone_mkey_hour = atoi(p);
		if (dns_zone_mkey_hour == 0) {
			named_main_earlyfatal("bad mkeytimer");
		}

		p = strtok_r(NULL, "/", &last);
		if (p == NULL) {
			dns_zone_mkey_day = (24 * dns_zone_mkey_hour);
			dns_zone_mkey_month = (30 * dns_zone_mkey_day);
			return;
		}

		dns_zone_mkey_day = atoi(p);
		if (dns_zone_mkey_day < dns_zone_mkey_hour)
			named_main_earlyfatal("bad mkeytimer");

		p = strtok_r(NULL, "/", &last);
		if (p == NULL) {
			dns_zone_mkey_month = (30 * dns_zone_mkey_day);
			return;
		}

		dns_zone_mkey_month = atoi(p);
		if (dns_zone_mkey_month < dns_zone_mkey_day) {
			named_main_earlyfatal("bad mkeytimer");
		}
Mark Andrews's avatar
Mark Andrews committed
681
	} else if (!strcmp(option, "sigvalinsecs")) {
682
		sigvalinsecs = true;
683
684
685
	} else if (!strncmp(option, "tat=", 4)) {
		named_g_tat_interval = atoi(option + 4);
	} else {
686
		fprintf(stderr, "unknown -T flag '%s'\n", option);
687
688
689
	}
}

690
static void
Bob Halley's avatar
add    
Bob Halley committed
691
692
parse_command_line(int argc, char *argv[]) {
	int ch;
693
	int port;
694
	const char *p;
695

696
697
	save_command_line(argc, argv);

698
	/*
699
	 * NAMED_MAIN_ARGS is defined in main.h, so that it can be used
700
701
	 * both by named and by ntservice hooks.
	 */
702
	isc_commandline_errprint = false;
703
704
705
	while ((ch = isc_commandline_parse(argc, argv,
					   NAMED_MAIN_ARGS)) != -1)
	{
Bob Halley's avatar
add    
Bob Halley committed
706
		switch (ch) {
707
		case '4':
708
709
710
			if (disable4)
				named_main_earlyfatal("cannot specify "
						      "-4 and -6");
711
			if (isc_net_probeipv4() != ISC_R_SUCCESS)
712
713
				named_main_earlyfatal("IPv4 not supported "
						      "by OS");
714
			isc_net_disableipv6();
715
			disable6 = true;
716
717
			break;
		case '6':
718
719
720
			if (disable6)
				named_main_earlyfatal("cannot specify "
						      "-4 and -6");
721
			if (isc_net_probeipv6() != ISC_R_SUCCESS)
722
723
				named_main_earlyfatal("IPv6 not supported "
						      "by OS");
724
			isc_net_disableipv4();
725
			disable4 = true;
726
			break;
727
728
729
		case 'A':
			parse_fuzz_arg();
			break;
Bob Halley's avatar
add    
Bob Halley committed
730
		case 'c':
731
			named_g_conffile = isc_commandline_argument;
732
			named_g_conffileset = true;
Bob Halley's avatar
add    
Bob Halley committed
733
			break;
Bob Halley's avatar
Bob Halley committed
734
		case 'd':
735
736
			named_g_debuglevel = parse_int(isc_commandline_argument,
						       "debug level");
Bob Halley's avatar
Bob Halley committed
737
			break;
738
739
740
		case 'D':
			/* Descriptive comment for 'ps'. */
			break;
Francis Dupont's avatar
Francis Dupont committed
741
		case 'E':
742
			named_g_engine = isc_commandline_argument;
Francis Dupont's avatar
Francis Dupont committed
743
			break;
744
		case 'f':
745
			named_g_foreground = true;
746
			break;
747
		case 'g':
748
749
			named_g_foreground = true;
			named_g_logstderr = true;
750
			break;
751
		case 'L':
752
			named_g_logfile = isc_commandline_argument;
753
			break;
754
		case 'M':
755
756
			set_flags(isc_commandline_argument, mem_context_flags,
				  &isc_mem_defaultflags);
757
			break;
758
759
760
761
		case 'm':
			set_flags(isc_commandline_argument, mem_debug_flags,
				  &isc_mem_debugging);
			break;
762
763
		case 'N': /* Deprecated. */
		case 'n':
764
			named_g_cpus = parse_int(isc_commandline_argument,
765
					      "number of cpus");
766
767
			if (named_g_cpus == 0)
				named_g_cpus = 1;
Bob Halley's avatar
add    
Bob Halley committed
768
			break;
Bob Halley's avatar
Bob Halley committed
769
		case 'p':
770
			port = parse_int(isc_commandline_argument, "port");
771
			if (port < 1 || port > 65535)
772
				named_main_earlyfatal("port '%s' out of range",
773
						   isc_commandline_argument);
774
			named_g_port = port;
775
			break;
Bob Halley's avatar
add    
Bob Halley committed
776
777
		case 's':
			/* XXXRTH temporary syntax */
778
			want_stats = true;
Bob Halley's avatar
add    
Bob Halley committed
779
			break;
780
781
782
783
		case 'S':
			maxsocks = parse_int(isc_commandline_argument,
					     "max number of sockets");
			break;
784
		case 't':
785
			/* XXXJAB should we make a copy? */
786
			named_g_chrootdir = isc_commandline_argument;
787
			break;
Mark Andrews's avatar
Mark Andrews committed
788
		case 'T':	/* NOT DOCUMENTED */
789
			parse_T_opt(isc_commandline_argument);
790
			break;
791
		case 'U':
792
793
794
			named_g_udpdisp = parse_int(isc_commandline_argument,
						    "number of UDP listeners "
						    "per interface");
795
			break;
796
		case 'u':
797
			named_g_username = isc_commandline_argument;
798
			break;
799
		case 'v':
800
			printversion(false);
801
			exit(0);
802
		case 'V':
803
			printversion(true);
804
			exit(0);
805
806
807
808
		case 'x':
			/* Obsolete. No longer in use. Ignore. */
			break;
		case 'X':
809
			named_g_forcelock = true;
810
			if (strcasecmp(isc_commandline_argument, "none") != 0)
811
812
				named_g_defaultlockfile =
					isc_commandline_argument;
813
			else
814
				named_g_defaultlockfile = NULL;
815
			break;
Francis Dupont's avatar
Francis Dupont committed
816
817
818
		case 'F':
			/* Reserved for FIPS mode */
			/* FALLTHROUGH */
819
		case '?':
820
			usage();
821
822
			if (isc_commandline_option == '?')
				exit(0);
823
			p = strchr(NAMED_MAIN_ARGS, isc_commandline_option);
824
			if (p == NULL || *++p != ':')
825
				named_main_earlyfatal("unknown option '-%c'",
826
827
						   isc_commandline_option);
			else
828
				named_main_earlyfatal("option '-%c' requires "
829
830
						   "an argument",
						   isc_commandline_option);
Francis Dupont's avatar
Francis Dupont committed
831
			/* FALLTHROUGH */
Bob Halley's avatar
add    
Bob Halley committed
832
		default:
833
834
			named_main_earlyfatal("parsing options returned %d",
					      ch);
Bob Halley's avatar
add    
Bob Halley committed
835
836
837
		}
	}

838
839
	argc -= isc_commandline_index;
	argv += isc_commandline_index;
840
	POST(argv);
Bob Halley's avatar
add    
Bob Halley committed
841

842
	if (argc > 0) {
Bob Halley's avatar
add    
Bob Halley committed
843
		usage();
844
		named_main_earlyfatal("extra command line arguments");
Bob Halley's avatar
add    
Bob Halley committed
845
846
847
848
	}
}

static isc_result_t
849
create_managers(void) {
Bob Halley's avatar
add    
Bob Halley committed
850
	isc_result_t result;
851
	unsigned int socks;
Bob Halley's avatar
add    
Bob Halley committed
852

853
	INSIST(named_g_cpus_detected > 0);
854

855
856
857
858
859
860
861
862
	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");
863
#ifdef WIN32
864
	named_g_udpdisp = 1;
865
#else
866
	if (named_g_udpdisp == 0) {
867
		named_g_udpdisp = named_g_cpus_detected;
Evan Hunt's avatar
Evan Hunt committed
868
	}
869
870
	if (named_g_udpdisp > named_g_cpus)
		named_g_udpdisp = named_g_cpus;
871
#endif
872
873
874
875
	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");
876

877
878
	result = isc_taskmgr_create(named_g_mctx, named_g_cpus, 0,
				    &named_g_taskmgr);
Bob Halley's avatar
add    
Bob Halley committed
879
880
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
Mark Andrews's avatar
Mark Andrews committed
881
				 "isc_taskmgr_create() failed: %s",
Bob Halley's avatar
add    
Bob Halley committed
882
883
884
885
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

886
	result = isc_timermgr_create(named_g_mctx, &named_g_timermgr);
Bob Halley's avatar
add    
Bob Halley committed
887
888
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
Mark Andrews's avatar
Mark Andrews committed
889
				 "isc_timermgr_create() failed: %s",
Bob Halley's avatar
add    
Bob Halley committed
890
891
892
893
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

894
	result = isc_socketmgr_create2(named_g_mctx, &named_g_socketmgr,
895
				       maxsocks, named_g_cpus);
Bob Halley's avatar
add    
Bob Halley committed
896
897
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
898
				 "isc_socketmgr_create() failed: %s",
Bob Halley's avatar
add    
Bob Halley committed
899
900
901
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}
902
	isc_socketmgr_maxudp(named_g_socketmgr, maxudp);
903
	result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &socks);
904
	if (result == ISC_R_SUCCESS) {
905
906
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_SERVER,
907
908
			      ISC_LOG_INFO, "using up to %u sockets", socks);
	}
Bob Halley's avatar
add    
Bob Halley committed
909
910
911
912
913
914
915

	return (ISC_R_SUCCESS);
}

static void
destroy_managers(void) {
	/*
Andreas Gustafsson's avatar
Andreas Gustafsson committed
916
	 * isc_taskmgr_destroy() will block until all tasks have exited,
Bob Halley's avatar
add    
Bob Halley committed
917
	 */
918
919
920
	isc_taskmgr_destroy(&named_g_taskmgr);
	isc_timermgr_destroy(&named_g_timermgr);
	isc_socketmgr_destroy(&named_g_socketmgr);
Bob Halley's avatar
add    
Bob Halley committed
921
922
}

923
static void
924
dump_symboltable(void) {
925
926
927
928
929
930
931
932
	int i;
	isc_result_t result;
	const char *fname;
	const void *addr;

	if (isc__backtrace_nsymbols == 0)
		return;

933
	if (!isc_log_wouldlog(named_g_lctx, ISC_LOG_DEBUG(99)))
934
935
		return;

936
937
938
	isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
		      NAMED_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
		      "Symbol table:");
939
940
941
942
943
944

	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) {
945
946
			isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
				      NAMED_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
947
948
949
950
951
				      "[%d] %p %s", i, addr, fname);
		}
	}
}

Bob Halley's avatar
add    
Bob Halley committed
952
static void
953
setup(void) {
Bob Halley's avatar
add    
Bob Halley committed
954
	isc_result_t result;
955
	isc_resourcevalue_t old_openfiles;
956
	ns_server_t *sctx;
957
958
959
#ifdef HAVE_LIBSCF
	char *instance = NULL;
#endif
Bob Halley's avatar
add    
Bob Halley committed
960

961
962
963
964
965
	/*
	 * 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.
	 */
966
	named_os_inituserinfo(named_g_username);
967

968
969
970
	/*
	 * Initialize time conversion information
	 */
971
	named_os_tzset();
972

973
	named_os_opendevnull();
974

975
976
#ifdef HAVE_LIBSCF
	/* Check if named is under smf control, before chroot. */
977
	result = named_smf_get_instance(&instance, 0, named_g_mctx);
978
979
	/* We don't care about instance, just check if we got one. */
	if (result == ISC_R_SUCCESS)
980
		named_smf_got_instance = 1;
981