main.c 43.9 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/hp.h>
27
#include <isc/httpd.h>
28
#include <isc/netmgr.h>
29
#include <isc/os.h>
30
#include <isc/platform.h>
31
#include <isc/print.h>
32
#include <isc/resource.h>
33
#include <isc/stdio.h>
34
#include <isc/string.h>
Bob Halley's avatar
add  
Bob Halley committed
35 36
#include <isc/task.h>
#include <isc/timer.h>
Bob Halley's avatar
Bob Halley committed
37
#include <isc/util.h>
Bob Halley's avatar
add  
Bob Halley committed
38

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/resolver.h>
43
#include <dns/result.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>
47
#include <isccc/result.h>
Ondřej Surý's avatar
Ondřej Surý committed
48
#if USE_PKCS11
49
#include <pk11/result.h>
50
#endif /* if USE_PKCS11 */
51

52 53
#include <dlz/dlz_dlopen_driver.h>

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

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

62 63
#ifdef HAVE_GEOIP2
#include <maxminddb.h>
64
#endif /* ifdef HAVE_GEOIP2 */
65

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

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

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

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

101
#ifdef CONTRIB_DLZ
102
/*
103
 * Include contributed DLZ drivers if appropriate.
104 105
 */
#include <dlz/dlz_drivers.h>
106
#endif /* ifdef CONTRIB_DLZ */
107

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

Evan Hunt's avatar
Evan Hunt committed
115
LIBISC_EXTERNAL_DATA extern int isc_dscp_check_value;
116 117 118
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
119

Evan Hunt's avatar
Evan Hunt committed
120 121 122 123 124 125
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];
126
static unsigned int maxsocks = 0;
Evan Hunt's avatar
Evan Hunt committed
127
static int maxudp = 0;
Bob Halley's avatar
add  
Bob Halley committed
128

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

/*
 * -4 and -6
 */
147 148
static bool disable6 = false;
static bool disable4 = false;
149

150
void
Evan Hunt's avatar
Evan Hunt committed
151
named_main_earlywarning(const char *format, ...) {
152 153 154
	va_list args;

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

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

	exit(1);
}

Francis Dupont's avatar
Francis Dupont committed
191 192 193 194
ISC_PLATFORM_NORETURN_PRE static void
assertion_failed(const char *file, int line, isc_assertiontype_t type,
		 const char *cond) ISC_PLATFORM_NORETURN_POST;

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

204 205 206 207
	/*
	 * Handle assertion failures.
	 */

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

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

258
	if (named_g_coreok) {
259
		abort();
260
	}
261 262 263
	exit(1);
}

Francis Dupont's avatar
Francis Dupont committed
264
ISC_PLATFORM_NORETURN_PRE static void
265
library_fatal_error(const char *file, int line, const char *format,
Francis Dupont's avatar
Francis Dupont committed
266
		    va_list args)
267
	ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
268

269
static void
David Lawrence's avatar
David Lawrence committed
270
library_fatal_error(const char *file, int line, const char *format,
Evan Hunt's avatar
Evan Hunt committed
271
		    va_list args) {
272 273 274 275
	/*
	 * Handle isc_error_fatal() calls from our libraries.
	 */

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

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

299
	if (named_g_coreok) {
300
		abort();
301
	}
302 303 304
	exit(1);
}

Evan Hunt's avatar
Evan Hunt committed
305 306 307
static void library_unexpected_error(const char *file, int line,
				     const char *format, va_list args)
	ISC_FORMAT_PRINTF(3, 0);
308

309
static void
David Lawrence's avatar
David Lawrence committed
310
library_unexpected_error(const char *file, int line, const char *format,
Evan Hunt's avatar
Evan Hunt committed
311
			 va_list args) {
312 313 314 315
	/*
	 * Handle isc_error_unexpected() calls from our libraries.
	 */

316 317 318
	if (named_g_lctx != NULL) {
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR,
319
			      "%s:%d: unexpected error:", file, line);
320
		isc_log_vwrite(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
321 322
			       NAMED_LOGMODULE_MAIN, ISC_LOG_ERROR, format,
			       args);
323 324 325 326 327 328 329 330
	} 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
331
static void
Evan Hunt's avatar
Evan Hunt committed
332
usage(void) {
333 334 335 336 337 338 339
	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
340 341
}

342
static void
Evan Hunt's avatar
Evan Hunt committed
343 344
save_command_line(int argc, char *argv[]) {
	int i;
345 346
	char *dst = saved_command_line;
	char *eob = saved_command_line + sizeof(saved_command_line) - 1;
347
	char *rollback = dst;
348 349

	for (i = 1; i < argc && dst < eob; i++) {
350
		char *src = argv[i];
Evan Hunt's avatar
Evan Hunt committed
351
		bool quoted = false;
352 353

		rollback = dst;
354 355 356
		*dst++ = ' ';

		while (*src != '\0' && dst < eob) {
357
			if (isalnum(*src) || *src == ',' || *src == '-' ||
Evan Hunt's avatar
Evan Hunt committed
358 359
			    *src == '_' || *src == '.' || *src == '/')
			{
360
				*dst++ = *src++;
361 362 363 364
			} else if (isprint(*src)) {
				if (dst + 2 >= eob) {
					goto add_ellipsis;
				}
365
				*dst++ = '\\';
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
				*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
388 389
					int c = snprintf(tmp, sizeof(tmp),
							 "\\%03o", *src++);
390 391 392 393 394 395
					if (dst + c >= eob) {
						goto add_ellipsis;
					}
					memmove(dst, tmp, c);
					dst += c;
				}
396 397
			}
		}
398 399 400 401 402 403 404
		if (quoted) {
			if (dst == eob) {
				goto add_ellipsis;
			}
			*dst++ = '\'';
		}
	}
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
static int
Evan Hunt's avatar
Evan Hunt committed
416 417 418
parse_int(char *arg, const char *desc) {
	char *endp;
	int tmp;
419 420
	long int ltmp;

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

432
static struct flag_def {
Evan Hunt's avatar
Evan Hunt committed
433
	const char *name;
434
	unsigned int value;
Evan Hunt's avatar
Evan Hunt committed
435
	bool negate;
436 437 438 439 440 441 442 443 444 445 446
} 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 } };
447 448

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

452 453
	for (;;) {
		const struct flag_def *def;
Evan Hunt's avatar
Evan Hunt committed
454 455
		const char *end = strchr(arg, ',');
		int arglen;
456
		if (end == NULL) {
457
			end = arg + strlen(arg);
458
		}
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
				}
				if (def->negate) {
467
					*ret &= ~(def->value);
468
				} else {
469
					*ret |= def->value;
470
				}
471 472 473
				goto found;
			}
		}
474
		named_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
475
	found:
476
		if (clear || (*end == '\0')) {
477
			break;
478
		}
479 480
		arg = end + 1;
	}
481

482
	if (clear) {
483
		*ret = 0;
484
	}
485 486
}

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

497 498 499
	printf("%s %s%s%s <id:%s>\n", named_g_product, named_g_version,
	       (*named_g_description != '\0') ? " " : "", named_g_description,
	       named_g_srcid);
500 501 502 503 504 505

	if (!verbose) {
		return;
	}

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

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

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

571 572 573 574 575
	/*
	 * Print default configuration paths.
	 */
	printf("default paths:\n");
	printf("  named configuration:  %s\n", named_g_conffile);
576
	printf("  rndc configuration:   %s\n", rndcconf);
577 578 579 580
	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);
581 582 583 584 585 586 587 588 589 590 591 592 593 594
#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 */
595 596
}

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

620
static void
Evan Hunt's avatar
Evan Hunt committed
621
parse_T_opt(char *option) {
622
	const char *p;
Evan Hunt's avatar
Evan Hunt committed
623
	char *last = NULL;
624 625 626 627 628 629
	/*
	 * 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.
	 */
630
	if (!strcmp(option, "dropedns")) {
631
		dropedns = true;
632 633
	} else if (!strncmp(option, "dscp=", 5)) {
		isc_dscp_check_value = atoi(option + 5);
634 635 636 637 638 639
	} else if (!strcmp(option, "ednsformerr")) {
		ednsformerr = true;
	} else if (!strcmp(option, "ednsnotimp")) {
		ednsnotimp = true;
	} else if (!strcmp(option, "ednsrefused")) {
		ednsrefused = true;
640
	} else if (!strcmp(option, "fixedlocal")) {
641
		fixedlocal = true;
642
	} else if (!strcmp(option, "keepstderr")) {
643
		named_g_keepstderr = true;
644
	} else if (!strcmp(option, "noaa")) {
645
		noaa = true;
646
	} else if (!strcmp(option, "noedns")) {
647
		noedns = true;
648
	} else if (!strcmp(option, "nonearest")) {
649
		nonearest = true;
650
	} else if (!strcmp(option, "nosoa")) {
651
		nosoa = true;
652
	} else if (!strcmp(option, "nosyslog")) {
653
		named_g_nosyslog = true;
654
	} else if (!strcmp(option, "notcp")) {
655
		notcp = true;
656 657 658 659 660 661
	} 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
662 663 664
		if (maxudp <= 0) {
			named_main_earlyfatal("bad maxudp");
		}
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
	} 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);
684
		if (dns_zone_mkey_day < dns_zone_mkey_hour) {
685
			named_main_earlyfatal("bad mkeytimer");
686
		}
687 688 689 690 691 692 693 694 695 696 697

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

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

713 714
	save_command_line(argc, argv);

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