main.c 43 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

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

53 54
#include <dlz/dlz_dlopen_driver.h>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	exit(1);
}

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

196
static void
David Lawrence's avatar
David Lawrence committed
197
assertion_failed(const char *file, int line, isc_assertiontype_t type,
Evan Hunt's avatar
Evan Hunt committed
198 199
		 const char *cond) {
	void *tracebuf[BACKTRACE_MAXFRAME];
200
	int nframes;
201
	isc_result_t result;
Evan Hunt's avatar
Evan Hunt committed
202
	const char *logsuffix = "";
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
			      "%s:%d: %s(%s) failed%s", file, line,
			      isc_assertion_typetotext(type), cond, logsuffix);
		if (result == ISC_R_SUCCESS) {
225 226 227 228 229 230 231 232 233 234
#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++) {
235 236 237 238
				isc_log_write(
					named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
					NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
					"#%d %p in ??", i, tracebuf[i]);
239
			}
240
#endif /* HAVE_BACKTRACE_SYMBOLS */
241
		}
242 243
		isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
			      NAMED_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
244
			      "exiting (due to assertion failure)");
245
	} else {
246 247
		fprintf(stderr, "%s:%d: %s(%s) failed\n", file, line,
			isc_assertion_typetotext(type), cond);
248 249 250
		fflush(stderr);
	}

251
	if (named_g_coreok) {
252
		abort();
253
	}
254 255 256
	exit(1);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

425
static struct flag_def {
Evan Hunt's avatar
Evan Hunt committed
426
	const char *name;
427
	unsigned int value;
Evan Hunt's avatar
Evan Hunt committed
428
	bool negate;
429 430 431 432 433 434 435 436 437 438 439
} 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 } };
440 441

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

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

475
	if (clear) {
476
		*ret = 0;
477
	}
478 479
}

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

490 491 492
	printf("%s %s%s%s <id:%s>\n", named_g_product, named_g_version,
	       (*named_g_description != '\0') ? " " : "", named_g_description,
	       named_g_srcid);
493 494 495 496 497 498

	if (!verbose) {
		return;
	}

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

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

550 551 552 553 554 555 556 557 558 559 560 561 562 563
	/*
	 * 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");
	}

564 565 566 567 568
	/*
	 * Print default configuration paths.
	 */
	printf("default paths:\n");
	printf("  named configuration:  %s\n", named_g_conffile);
569
	printf("  rndc configuration:   %s\n", rndcconf);
570 571 572 573
	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);
574 575 576 577 578 579 580 581 582 583 584 585 586 587
#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 */
588 589
}

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

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

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

700
static void
Evan Hunt's avatar
Evan Hunt committed
701 702 703
parse_command_line(int argc, char *argv[]) {
	int ch;
	int port;
704
	const char *p;
705

706 707
	save_command_line(argc, argv);

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