main.c 42.8 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>
19
#include <uv.h>
Bob Halley's avatar
add  
Bob Halley committed
20 21

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

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

48
#include <dst/result.h>
49

50
#include <isccc/result.h>
Ondřej Surý's avatar
Ondřej Surý committed
51
#if USE_PKCS11
52
#include <pk11/result.h>
53
#endif /* if USE_PKCS11 */
54

55 56
#include <dlz/dlz_dlopen_driver.h>

57 58
#ifdef HAVE_GPERFTOOLS_PROFILER
#include <gperftools/profiler.h>
59
#endif /* ifdef HAVE_GPERFTOOLS_PROFILER */
60

61 62 63
#ifdef HAVE_JSON_C
#include <json_c_version.h>
#endif /* HAVE_JSON_C */
64

65 66
#ifdef HAVE_GEOIP2
#include <maxminddb.h>
67
#endif /* ifdef HAVE_GEOIP2 */
68

69
/*
70
 * Defining NAMED_MAIN provides storage declarations (rather than extern)
71 72
 * for variables in named/globals.h.
 */
73 74 75
#define NAMED_MAIN 1

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

77
#include <named/builtin.h>
78
#include <named/config.h>
79
#include <named/control.h>
80
#include <named/fuzz.h>
81
#include <named/globals.h> /* Explicit, though named/log.h includes it. */
82
#include <named/log.h>
83
#include <named/main.h>
Bob Halley's avatar
Bob Halley committed
84
#include <named/os.h>
Bob Halley's avatar
add  
Bob Halley committed
85
#include <named/server.h>
86
#ifdef HAVE_LIBSCF
87
#include <named/smf_globals.h>
88
#endif /* ifdef HAVE_LIBSCF */
Bob Halley's avatar
add  
Bob Halley committed
89

90
#include <openssl/crypto.h>
91
#include <openssl/opensslv.h>
92
#ifdef HAVE_LIBXML2
93
#include <libxml/parser.h>
94
#include <libxml/xmlversion.h>
95
#endif /* ifdef HAVE_LIBXML2 */
96 97
#ifdef HAVE_ZLIB
#include <zlib.h>
98
#endif /* ifdef HAVE_ZLIB */
99 100 101
/*
 * Include header files for database drivers here.
 */
102
/* #include "xxdb.h" */
103

104
#ifdef CONTRIB_DLZ
105
/*
106
 * Include contributed DLZ drivers if appropriate.
107 108
 */
#include <dlz/dlz_drivers.h>
109
#endif /* ifdef CONTRIB_DLZ */
110

111 112 113 114 115
/*
 * The maximum number of stack frames to dump on assertion failure.
 */
#ifndef BACKTRACE_MAXFRAME
#define BACKTRACE_MAXFRAME 128
116
#endif /* ifndef BACKTRACE_MAXFRAME */
117

Evan Hunt's avatar
Evan Hunt committed
118
LIBISC_EXTERNAL_DATA extern int isc_dscp_check_value;
119 120 121
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
122

Evan Hunt's avatar
Evan Hunt committed
123 124 125 126 127 128
static bool want_stats = false;
static char program_name[NAME_MAX] = "named";
static char absolute_conffile[PATH_MAX];
static char saved_command_line[4096] = { 0 };
static char ellipsis[5] = { 0 };
static char version[512];
129
static unsigned int maxsocks = 0;
Evan Hunt's avatar
Evan Hunt committed
130
static int maxudp = 0;
Bob Halley's avatar
add  
Bob Halley committed
131

132 133 134
/*
 * -T options:
 */
135
static bool dropedns = false;
136 137 138 139
static bool ednsformerr = false;
static bool ednsnotimp = false;
static bool ednsrefused = false;
static bool fixedlocal = false;
140
static bool noaa = false;
141
static bool noedns = false;
142
static bool nonearest = false;
143
static bool nosoa = false;
144 145
static bool notcp = false;
static bool sigvalinsecs = false;
146 147 148 149

/*
 * -4 and -6
 */
150 151
static bool disable6 = false;
static bool disable4 = false;
152

153
void
Evan Hunt's avatar
Evan Hunt committed
154
named_main_earlywarning(const char *format, ...) {
155 156 157
	va_list args;

	va_start(args, format);
158 159
	if (named_g_lctx != NULL) {
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
160 161
			       NAMED_LOGMODULE_MAIN, ISC_LOG_WARNING, format,
			       args);
162 163 164 165 166 167 168 169 170
	} 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
171
void
Evan Hunt's avatar
Evan Hunt committed
172
named_main_earlyfatal(const char *format, ...) {
Bob Halley's avatar
add  
Bob Halley committed
173 174 175
	va_list args;

	va_start(args, format);
176 177
	if (named_g_lctx != NULL) {
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
178 179
			       NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL, format,
			       args);
180
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
181 182
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
			      "exiting (due to early fatal error)");
183
	} else {
184
		fprintf(stderr, "%s: ", program_name);
185 186
		vfprintf(stderr, format, args);
		fprintf(stderr, "\n");
187
		fflush(stderr);
188
	}
Bob Halley's avatar
add  
Bob Halley committed
189 190 191 192 193
	va_end(args);

	exit(1);
}

194
ISC_NORETURN static void
Francis Dupont's avatar
Francis Dupont committed
195
assertion_failed(const char *file, int line, isc_assertiontype_t type,
196
		 const char *cond);
Francis Dupont's avatar
Francis Dupont committed
197

198
static void
David Lawrence's avatar
David Lawrence committed
199
assertion_failed(const char *file, int line, isc_assertiontype_t type,
Evan Hunt's avatar
Evan Hunt committed
200 201
		 const char *cond) {
	void *tracebuf[BACKTRACE_MAXFRAME];
202
	int nframes;
203
	isc_result_t result;
Evan Hunt's avatar
Evan Hunt committed
204
	const char *logsuffix = "";
205

206 207 208 209
	/*
	 * Handle assertion failures.
	 */

210
	if (named_g_lctx != NULL) {
211
		/*
Francis Dupont's avatar
Francis Dupont committed
212
		 * Reset the assertion callback in case it is the log
213 214 215 216
		 * routines causing the assertion.
		 */
		isc_assertion_setcallback(NULL);

217 218
		result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
						&nframes);
219
		if (result == ISC_R_SUCCESS && nframes > 0) {
220
			logsuffix = ", back trace";
221
		}
222 223
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
224 225 226
			      "%s:%d: %s(%s) failed%s", file, line,
			      isc_assertion_typetotext(type), cond, logsuffix);
		if (result == ISC_R_SUCCESS) {
227 228 229 230 231 232 233 234 235 236
#if HAVE_BACKTRACE_SYMBOLS
			char **strs = backtrace_symbols(tracebuf, nframes);
			for (int i = 0; i < nframes; i++) {
				isc_log_write(named_g_lctx,
					      NAMED_LOGCATEGORY_GENERAL,
					      NAMED_LOGMODULE_MAIN,
					      ISC_LOG_CRITICAL, "%s", strs[i]);
			}
#else  /* HAVE_BACKTRACE_SYMBOLS */
			for (int i = 0; i < nframes; i++) {
237 238 239 240
				isc_log_write(
					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
					NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
					"#%d %p in ??", i, tracebuf[i]);
241
			}
242
#endif /* HAVE_BACKTRACE_SYMBOLS */
243
		}
244 245
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
246
			      "exiting (due to assertion failure)");
247
	} else {
248 249
		fprintf(stderr, "%s:%d: %s(%s) failed\n", file, line,
			isc_assertion_typetotext(type), cond);
250 251 252
		fflush(stderr);
	}

253
	if (named_g_coreok) {
254
		abort();
255
	}
256 257 258
	exit(1);
}

259
ISC_NORETURN static void
260
library_fatal_error(const char *file, int line, const char *format,
261
		    va_list args) ISC_FORMAT_PRINTF(3, 0);
262

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

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

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

293
	if (named_g_coreok) {
294
		abort();
295
	}
296 297 298
	exit(1);
}

Ondřej Surý's avatar
Ondřej Surý committed
299 300 301
static void
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args) ISC_FORMAT_PRINTF(3, 0);
302

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

310 311 312
	if (named_g_lctx != NULL) {
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR,
313
			      "%s:%d: unexpected error:", file, line);
314
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
315 316
			       NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR, format,
			       args);
317 318 319 320 321 322 323 324
	} 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
325
static void
Evan Hunt's avatar
Evan Hunt committed
326
usage(void) {
327 328 329 330 331 332 333
	fprintf(stderr, "usage: named [-4|-6] [-c conffile] [-d debuglevel] "
			"[-E engine] [-f|-g]\n"
			"             [-n number_of_cpus] [-p port] [-s] "
			"[-S sockets] [-t chrootdir]\n"
			"             [-u username] [-U listeners] "
			"[-m {usage|trace|record|size|mctx}]\n"
			"usage: named [-v|-V]\n");
Bob Halley's avatar
add  
Bob Halley committed
334 335
}

336
static void
Evan Hunt's avatar
Evan Hunt committed
337 338
save_command_line(int argc, char *argv[]) {
	int i;
339 340
	char *dst = saved_command_line;
	char *eob = saved_command_line + sizeof(saved_command_line) - 1;
341
	char *rollback = dst;
342 343

	for (i = 1; i < argc && dst < eob; i++) {
344
		char *src = argv[i];
Evan Hunt's avatar
Evan Hunt committed
345
		bool quoted = false;
346 347

		rollback = dst;
348 349 350
		*dst++ = ' ';

		while (*src != '\0' && dst < eob) {
351 352 353
			if (isalnum(*(unsigned char *)src) || *src == ',' ||
			    *src == '-' || *src == '_' || *src == '.' ||
			    *src == '/')
Evan Hunt's avatar
Evan Hunt committed
354
			{
355
				*dst++ = *src++;
356
			} else if (isprint(*(unsigned char *)src)) {
357 358 359
				if (dst + 2 >= eob) {
					goto add_ellipsis;
				}
360
				*dst++ = '\\';
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
				*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];
Evan Hunt's avatar
Evan Hunt committed
383 384
					int c = snprintf(tmp, sizeof(tmp),
							 "\\%03o", *src++);
385 386 387 388 389 390
					if (dst + c >= eob) {
						goto add_ellipsis;
					}
					memmove(dst, tmp, c);
					dst += c;
				}
391 392
			}
		}
393 394 395 396 397 398 399
		if (quoted) {
			if (dst == eob) {
				goto add_ellipsis;
			}
			*dst++ = '\'';
		}
	}
400

401 402 403 404 405 406 407
	if (dst < eob) {
		return;
	}
add_ellipsis:
	dst = rollback;
	*dst = '\0';
	strlcpy(ellipsis, " ...", sizeof(ellipsis));
408 409
}

410
static int
Evan Hunt's avatar
Evan Hunt committed
411 412 413
parse_int(char *arg, const char *desc) {
	char *endp;
	int tmp;
414 415
	long int ltmp;

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

427
static struct flag_def {
Evan Hunt's avatar
Evan Hunt committed
428
	const char *name;
429
	unsigned int value;
Evan Hunt's avatar
Evan Hunt committed
430
	bool negate;
431 432 433 434 435 436 437 438 439 440 441
} mem_debug_flags[] = { { "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 } },
  mem_context_flags[] = { { "external", ISC_MEMFLAG_INTERNAL, true },
			  { "fill", ISC_MEMFLAG_FILL, false },
			  { "nofill", ISC_MEMFLAG_FILL, true },
			  { NULL, 0, false } };
442 443

static void
Evan Hunt's avatar
Evan Hunt committed
444
set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
445
	bool clear = false;
446

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

477
	if (clear) {
478
		*ret = 0;
479
	}
480 481
}

482
static void
Evan Hunt's avatar
Evan Hunt committed
483
printversion(bool verbose) {
484
	char rndcconf[PATH_MAX], *dot = NULL;
485
#if defined(HAVE_GEOIP2)
Evan Hunt's avatar
Evan Hunt committed
486 487 488
	isc_mem_t *mctx = NULL;
	cfg_parser_t *parser = NULL;
	cfg_obj_t *config = NULL;
489
	const cfg_obj_t *defaults = NULL, *obj = NULL;
490
#endif /* if defined(HAVE_GEOIP2) */
491

492 493
	printf("%s%s <id:%s>\n", PACKAGE_STRING, PACKAGE_DESCRIPTION,
	       PACKAGE_SRCID);
494 495 496 497 498 499

	if (!verbose) {
		return;
	}

	printf("running on %s\n", named_os_uname());
500
	printf("built by %s with %s\n", PACKAGE_BUILDER, PACKAGE_CONFIGARGS);
501 502
#ifdef __clang__
	printf("compiled by CLANG %s\n", __VERSION__);
503
#else /* ifdef __clang__ */
504 505
#if defined(__ICC) || defined(__INTEL_COMPILER)
	printf("compiled by ICC %s\n", __VERSION__);
506
#else /* if defined(__ICC) || defined(__INTEL_COMPILER) */
507 508
#ifdef __GNUC__
	printf("compiled by GCC %s\n", __VERSION__);
509 510 511
#endif /* ifdef __GNUC__ */
#endif /* if defined(__ICC) || defined(__INTEL_COMPILER) */
#endif /* ifdef __clang__ */
512 513
#ifdef _MSC_VER
	printf("compiled by MSVC %d\n", _MSC_VER);
514
#endif /* ifdef _MSC_VER */
515 516
#ifdef __SUNPRO_C
	printf("compiled by Solaris Studio %x\n", __SUNPRO_C);
517
#endif /* ifdef __SUNPRO_C */
518
	printf("compiled with OpenSSL version: %s\n", OPENSSL_VERSION_TEXT);
519
#if !defined(LIBRESSL_VERSION_NUMBER) && \
520
	OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 or higher */
521 522 523
	printf("linked to OpenSSL version: %s\n",
	       OpenSSL_version(OPENSSL_VERSION));

524 525
#else  /* if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= \
	* 0x10100000L */
526 527 528
	printf("linked to OpenSSL version: %s\n",
	       SSLeay_version(SSLEAY_VERSION));
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
529 530 531
	printf("compiled with libuv version: %d.%d.%d\n", UV_VERSION_MAJOR,
	       UV_VERSION_MINOR, UV_VERSION_PATCH);
	printf("linked to libuv version: %s\n", uv_version_string());
532
#ifdef HAVE_LIBXML2
533 534
	printf("compiled with libxml2 version: %s\n", LIBXML_DOTTED_VERSION);
	printf("linked to libxml2 version: %s\n", xmlParserVersion);
535
#endif /* ifdef HAVE_LIBXML2 */
536
#if defined(HAVE_JSON_C)
537 538
	printf("compiled with json-c version: %s\n", JSON_C_VERSION);
	printf("linked to json-c version: %s\n", json_c_version());
539
#endif /* if defined(HAVE_JSON_C) */
540
#if defined(HAVE_ZLIB) && defined(ZLIB_VERSION)
541 542
	printf("compiled with zlib version: %s\n", ZLIB_VERSION);
	printf("linked to zlib version: %s\n", zlibVersion());
543
#endif /* if defined(HAVE_ZLIB) && defined(ZLIB_VERSION) */
544 545
#if defined(HAVE_GEOIP2)
	/* Unfortunately, no version define on link time */
546
	printf("linked to maxminddb version: %s\n", MMDB_lib_version());
547
#endif /* if defined(HAVE_GEOIP2) */
Petr Menšík's avatar
Petr Menšík committed
548
#if defined(HAVE_DNSTAP)
549 550
	printf("compiled with protobuf-c version: %s\n", PROTOBUF_C_VERSION);
	printf("linked to protobuf-c version: %s\n", protobuf_c_version());
551
#endif /* if defined(HAVE_DNSTAP) */
552 553
	printf("threads support is enabled\n\n");

554 555 556 557 558 559 560 561 562 563 564 565 566 567
	/*
	 * 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");
	}

568 569 570 571 572
	/*
	 * Print default configuration paths.
	 */
	printf("default paths:\n");
	printf("  named configuration:  %s\n", named_g_conffile);
573
	printf("  rndc configuration:   %s\n", rndcconf);
574 575 576 577
	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);
578 579 580 581 582 583 584 585 586 587 588 589 590 591
#if defined(HAVE_GEOIP2)
#define RTC(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
	isc_mem_create(&mctx);
	RTC(cfg_parser_create(mctx, named_g_lctx, &parser));
	RTC(named_config_parsedefaults(parser, &config));
	RTC(cfg_map_get(config, "options", &defaults));
	RTC(cfg_map_get(defaults, "geoip-directory", &obj));
	if (cfg_obj_isstring(obj)) {
		printf("  geoip-directory:      %s\n", cfg_obj_asstring(obj));
	}
	cfg_obj_destroy(parser, &config);
	cfg_parser_destroy(&parser);
	isc_mem_detach(&mctx);
#endif /* HAVE_GEOIP2 */
592 593
}

594
static void
Evan Hunt's avatar
Evan Hunt committed
595
parse_fuzz_arg(void) {
596
	if (!strncmp(isc_commandline_argument, "client:", 7)) {
597 598
		named_g_fuzz_addr = isc_commandline_argument + 7;
		named_g_fuzz_type = isc_fuzz_client;
599
	} else if (!strncmp(isc_commandline_argument, "tcp:", 4)) {
600 601
		named_g_fuzz_addr = isc_commandline_argument + 4;
		named_g_fuzz_type = isc_fuzz_tcpclient;
602
	} else if (!strncmp(isc_commandline_argument, "resolver:", 9)) {
603 604
		named_g_fuzz_addr = isc_commandline_argument + 9;
		named_g_fuzz_type = isc_fuzz_resolver;
605
	} else if (!strncmp(isc_commandline_argument, "http:", 5)) {
606 607
		named_g_fuzz_addr = isc_commandline_argument + 5;
		named_g_fuzz_type = isc_fuzz_http;
608
	} else if (!strncmp(isc_commandline_argument, "rndc:", 5)) {
609 610
		named_g_fuzz_addr = isc_commandline_argument + 5;
		named_g_fuzz_type = isc_fuzz_rndc;
611
	} else {
612
		named_main_earlyfatal("unknown fuzzing type '%s'",
613
				      isc_commandline_argument);
614 615 616
	}
}

617
static void
Evan Hunt's avatar
Evan Hunt committed
618
parse_T_opt(char *option) {
619
	const char *p;
Evan Hunt's avatar
Evan Hunt committed
620
	char *last = NULL;
621 622 623 624 625 626
	/*
	 * force the server to behave (or misbehave) in
	 * specified ways for testing purposes.
	 * dscp=x:     check that dscp values are as
	 * 	       expected and assert otherwise.
	 */
627
	if (!strcmp(option, "dropedns")) {
628
		dropedns = true;
629 630
	} else if (!strncmp(option, "dscp=", 5)) {
		isc_dscp_check_value = atoi(option + 5);
631 632 633 634 635 636
	} else if (!strcmp(option, "ednsformerr")) {
		ednsformerr = true;
	} else if (!strcmp(option, "ednsnotimp")) {
		ednsnotimp = true;
	} else if (!strcmp(option, "ednsrefused")) {
		ednsrefused = true;
637
	} else if (!strcmp(option, "fixedlocal")) {
638
		fixedlocal = true;
639
	} else if (!strcmp(option, "keepstderr")) {
640
		named_g_keepstderr = true;
641
	} else if (!strcmp(option, "noaa")) {
642
		noaa = true;
643
	} else if (!strcmp(option, "noedns")) {
644
		noedns = true;
645
	} else if (!strcmp(option, "nonearest")) {
646
		nonearest = true;
647
	} else if (!strcmp(option, "nosoa")) {
648
		nosoa = true;
649
	} else if (!strcmp(option, "nosyslog")) {
650
		named_g_nosyslog = true;
651
	} else if (!strcmp(option, "notcp")) {
652
		notcp = true;
653 654 655 656 657 658
	} else if (!strcmp(option, "maxudp512")) {
		maxudp = 512;
	} else if (!strcmp(option, "maxudp1460")) {
		maxudp = 1460;
	} else if (!strncmp(option, "maxudp=", 7)) {
		maxudp = atoi(option + 7);
Mark Andrews's avatar
Mark Andrews committed
659 660 661
		if (maxudp <= 0) {
			named_main_earlyfatal("bad maxudp");
		}
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
	} 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);
681
		if (dns_zone_mkey_day < dns_zone_mkey_hour) {
682
			named_main_earlyfatal("bad mkeytimer");
683
		}
684 685 686 687 688 689 690 691 692 693 694

		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
695
	} else if (!strcmp(option, "sigvalinsecs")) {
696
		sigvalinsecs = true;
697 698 699
	} else if (!strncmp(option, "tat=", 4)) {
		named_g_tat_interval = atoi(option + 4);
	} else {
700
		fprintf(stderr, "unknown -T flag '%s'\n", option);
701 702 703
	}
}

704
static void
Evan Hunt's avatar
Evan Hunt committed
705 706 707
parse_command_line(int argc, char *argv[]) {
	int ch;
	int port;
708
	const char *p;
709

710 711
	save_command_line(argc, argv);

712
	/*
713
	 * NAMED_MAIN_ARGS is defined in main.h, so that it can be used
714 715
	 * both by named and by ntservice hooks.
	 */
716
	isc_commandline_errprint = false;
Evan Hunt's avatar
Evan Hunt committed
717 718
	while ((ch = isc_commandline_parse(argc, argv, NAMED_MAIN_ARGS)) != -1)
	{
Bob Halley's avatar
add  
Bob Halley committed
719
		switch (ch) {
720
		case '4':
721
			if (disable4) {
722 723
				named_main_earlyfatal("cannot specify "
						      "-4 and -6");
724 725
			}
			if (isc_net_probeipv4() != ISC_R_SUCCESS) {
726 727
				named_main_earlyfatal("IPv4 not supported "
						      "by OS");
728
			}
729
			isc_net_disableipv6();
730
			disable6 = true;
731 732
			break;
		case '6':
733
			if (disable6) {
734 735
				named_main_earlyfatal("cannot specify "
						      "-4 and -6");
736 737
			}
			if (isc_net_probeipv6() != ISC_R_SUCCESS) {
738 739
				named_main_earlyfatal("IPv6 not supported "
						      "by OS");
740
			}
741
			isc_net_disableipv4();
742
			disable4 = true;
743
			break;
744 745 746
		case 'A':
			parse_fuzz_arg();
			break;
Bob Halley's avatar
add  
Bob Halley committed
747
		case 'c':
748
			named_g_conffile = isc_commandline_argument;
749
			named_g_conffileset = true;
Bob Halley's avatar
add  
Bob Halley committed
750
			break;
Bob Halley's avatar
Bob Halley committed
751
		case 'd':
752
			named_g_debuglevel = parse_int(isc_commandline_argument,
753 754
						       "debug "
						       "level");
Bob Halley's avatar
Bob Halley committed
755
			break;
756 757 758
		case 'D':
			/* Descriptive comment for 'ps'. */
			break;
Francis Dupont's avatar
Francis Dupont committed
759
		case 'E':
760
			named_g_engine = isc_commandline_argument;
Francis Dupont's avatar
Francis Dupont committed
761
			break;
762
		case 'f':
763
			named_g_foreground = true;
764
			break;
765
		case 'g':
766 767
			named_g_foreground = true;
			named_g_logstderr = true;
768
			break;
769
		case 'L':
770
			named_g_logfile = isc_commandline_argument;
771
			break;
772
		case 'M':
773 774
			set_flags(isc_commandline_argument, mem_context_flags,
				  &isc_mem_defaultflags);
775
			break;
776 777 778 779
		case 'm':
			set_flags(isc_commandline_argument, mem_debug_flags,
				  &isc_mem_debugging);
			break;
780 781
		case 'N': /* Deprecated. */
		case 'n':
782 783
			named_g_cpus = parse_int(isc_commandline_argument,
						 "number of cpus");
784
			if (named_g_cpus == 0) {
785
				named_g_cpus = 1;
786
			}
Bob Halley's avatar
add  
Bob Halley committed
787
			break;
Bob Halley's avatar
Bob Halley committed
788
		case 'p':
789
			port = parse_int(isc_commandline_argument, "port");
790
			if (port < 1 || port > 65535) {
791
				named_main_earlyfatal("port '%s' out of range",
792
						      isc_commandline_argument);
793
			}
794
			named_g_port = port;
795
			break;
Bob Halley's avatar
add  
Bob Halley committed
796 797
		case 's':
			/* XXXRTH temporary syntax */
798
			want_stats = true;
Bob Halley's avatar
add  
Bob Halley committed
799
			break;
800
		case 'S':
801 802
			maxsocks = parse_int(isc_commandline_argument,
					     "max number of sockets");
803
			break;
804
		case 't':
805
			/* XXXJAB should we make a copy? */
806
			named_g_chrootdir = isc_commandline_argument;
807
			break;
808
		case 'T': /* NOT DOCUMENTED */
809
			parse_T_opt(isc_commandline_argument);
810
			break;
811
		case 'U':
812 813 814
			named_g_udpdisp = parse_int(isc_commandline_argument,
						    "number of UDP listeners "
						    "per interface");
815
			break;