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

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

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;
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
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
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,
198 199 200
		 const char *cond) {
	void *tracebuf[BACKTRACE_MAXFRAME];
	int i, nframes;
201
	isc_result_t result;
202 203
	const char *logsuffix = "";
	const char *fname;
204

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

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

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

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

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

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

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

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

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

306 307 308
static void
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args) ISC_FORMAT_PRINTF(3, 0);
309

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	if (!verbose) {
		return;
	}

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

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

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

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

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

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

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

708
static void
709 710 711
parse_command_line(int argc, char *argv[]) {
	int ch;
	int port;
712
	const char *p;
713

714 715
	save_command_line(argc, argv);

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