Home | History | Annotate | Line # | Download | only in check
named-checkconf.c revision 1.1.1.4
      1 /*	$NetBSD: named-checkconf.c,v 1.1.1.4 2020/05/24 19:36:29 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * This Source Code Form is subject to the terms of the Mozilla Public
      7  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  *
     10  * See the COPYRIGHT file distributed with this work for additional
     11  * information regarding copyright ownership.
     12  */
     13 
     14 /*! \file */
     15 
     16 #include <errno.h>
     17 #include <stdbool.h>
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 
     21 #include <isc/commandline.h>
     22 #include <isc/dir.h>
     23 #include <isc/hash.h>
     24 #include <isc/log.h>
     25 #include <isc/mem.h>
     26 #include <isc/print.h>
     27 #include <isc/result.h>
     28 #include <isc/string.h>
     29 #include <isc/util.h>
     30 
     31 #include <dns/db.h>
     32 #include <dns/fixedname.h>
     33 #include <dns/log.h>
     34 #include <dns/name.h>
     35 #include <dns/rdataclass.h>
     36 #include <dns/result.h>
     37 #include <dns/rootns.h>
     38 #include <dns/zone.h>
     39 
     40 #include <isccfg/grammar.h>
     41 #include <isccfg/namedconf.h>
     42 
     43 #include <bind9/check.h>
     44 
     45 #include "check-tool.h"
     46 
     47 static const char *program = "named-checkconf";
     48 
     49 static bool loadplugins = true;
     50 
     51 isc_log_t *logc = NULL;
     52 
     53 #define CHECK(r)                             \
     54 	do {                                 \
     55 		result = (r);                \
     56 		if (result != ISC_R_SUCCESS) \
     57 			goto cleanup;        \
     58 	} while (0)
     59 
     60 /*% usage */
     61 ISC_PLATFORM_NORETURN_PRE static void
     62 usage(void) ISC_PLATFORM_NORETURN_POST;
     63 
     64 static void
     65 usage(void) {
     66 	fprintf(stderr,
     67 		"usage: %s [-chijlvz] [-p [-x]] [-t directory] "
     68 		"[named.conf]\n",
     69 		program);
     70 	exit(1);
     71 }
     72 
     73 /*% directory callback */
     74 static isc_result_t
     75 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
     76 	isc_result_t result;
     77 	const char *directory;
     78 
     79 	REQUIRE(strcasecmp("directory", clausename) == 0);
     80 
     81 	UNUSED(arg);
     82 	UNUSED(clausename);
     83 
     84 	/*
     85 	 * Change directory.
     86 	 */
     87 	directory = cfg_obj_asstring(obj);
     88 	result = isc_dir_chdir(directory);
     89 	if (result != ISC_R_SUCCESS) {
     90 		cfg_obj_log(obj, logc, ISC_LOG_ERROR,
     91 			    "change directory to '%s' failed: %s\n", directory,
     92 			    isc_result_totext(result));
     93 		return (result);
     94 	}
     95 
     96 	return (ISC_R_SUCCESS);
     97 }
     98 
     99 static bool
    100 get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
    101 	int i;
    102 	for (i = 0;; i++) {
    103 		if (maps[i] == NULL) {
    104 			return (false);
    105 		}
    106 		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) {
    107 			return (true);
    108 		}
    109 	}
    110 }
    111 
    112 static bool
    113 get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) {
    114 	const cfg_listelt_t *element;
    115 	const cfg_obj_t *checknames;
    116 	const cfg_obj_t *type;
    117 	const cfg_obj_t *value;
    118 	isc_result_t result;
    119 	int i;
    120 
    121 	for (i = 0;; i++) {
    122 		if (maps[i] == NULL) {
    123 			return (false);
    124 		}
    125 		checknames = NULL;
    126 		result = cfg_map_get(maps[i], "check-names", &checknames);
    127 		if (result != ISC_R_SUCCESS) {
    128 			continue;
    129 		}
    130 		if (checknames != NULL && !cfg_obj_islist(checknames)) {
    131 			*obj = checknames;
    132 			return (true);
    133 		}
    134 		for (element = cfg_list_first(checknames); element != NULL;
    135 		     element = cfg_list_next(element))
    136 		{
    137 			value = cfg_listelt_value(element);
    138 			type = cfg_tuple_get(value, "type");
    139 			if ((strcasecmp(cfg_obj_asstring(type), "primary") !=
    140 			     0) &&
    141 			    (strcasecmp(cfg_obj_asstring(type), "master") != 0))
    142 			{
    143 				continue;
    144 			}
    145 			*obj = cfg_tuple_get(value, "mode");
    146 			return (true);
    147 		}
    148 	}
    149 }
    150 
    151 static isc_result_t
    152 configure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) {
    153 	isc_result_t result;
    154 	dns_db_t *db = NULL;
    155 	dns_rdataclass_t rdclass;
    156 	isc_textregion_t r;
    157 
    158 	if (zfile == NULL) {
    159 		return (ISC_R_FAILURE);
    160 	}
    161 
    162 	DE_CONST(zclass, r.base);
    163 	r.length = strlen(zclass);
    164 	result = dns_rdataclass_fromtext(&rdclass, &r);
    165 	if (result != ISC_R_SUCCESS) {
    166 		return (result);
    167 	}
    168 
    169 	result = dns_rootns_create(mctx, rdclass, zfile, &db);
    170 	if (result != ISC_R_SUCCESS) {
    171 		return (result);
    172 	}
    173 
    174 	dns_db_detach(&db);
    175 	return (ISC_R_SUCCESS);
    176 }
    177 
    178 /*% configure the zone */
    179 static isc_result_t
    180 configure_zone(const char *vclass, const char *view, const cfg_obj_t *zconfig,
    181 	       const cfg_obj_t *vconfig, const cfg_obj_t *config,
    182 	       isc_mem_t *mctx, bool list) {
    183 	int i = 0;
    184 	isc_result_t result;
    185 	const char *zclass;
    186 	const char *zname;
    187 	const char *zfile = NULL;
    188 	const cfg_obj_t *maps[4];
    189 	const cfg_obj_t *mastersobj = NULL;
    190 	const cfg_obj_t *inviewobj = NULL;
    191 	const cfg_obj_t *zoptions = NULL;
    192 	const cfg_obj_t *classobj = NULL;
    193 	const cfg_obj_t *typeobj = NULL;
    194 	const cfg_obj_t *fileobj = NULL;
    195 	const cfg_obj_t *dlzobj = NULL;
    196 	const cfg_obj_t *dbobj = NULL;
    197 	const cfg_obj_t *obj = NULL;
    198 	const cfg_obj_t *fmtobj = NULL;
    199 	dns_masterformat_t masterformat;
    200 	dns_ttl_t maxttl = 0;
    201 
    202 	zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;
    203 
    204 	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
    205 	classobj = cfg_tuple_get(zconfig, "class");
    206 	if (!cfg_obj_isstring(classobj)) {
    207 		zclass = vclass;
    208 	} else {
    209 		zclass = cfg_obj_asstring(classobj);
    210 	}
    211 
    212 	zoptions = cfg_tuple_get(zconfig, "options");
    213 	maps[i++] = zoptions;
    214 	if (vconfig != NULL) {
    215 		maps[i++] = cfg_tuple_get(vconfig, "options");
    216 	}
    217 	if (config != NULL) {
    218 		cfg_map_get(config, "options", &obj);
    219 		if (obj != NULL) {
    220 			maps[i++] = obj;
    221 		}
    222 	}
    223 	maps[i] = NULL;
    224 
    225 	cfg_map_get(zoptions, "in-view", &inviewobj);
    226 	if (inviewobj != NULL && list) {
    227 		const char *inview = cfg_obj_asstring(inviewobj);
    228 		printf("%s %s %s in-view %s\n", zname, zclass, view, inview);
    229 	}
    230 	if (inviewobj != NULL) {
    231 		return (ISC_R_SUCCESS);
    232 	}
    233 
    234 	cfg_map_get(zoptions, "type", &typeobj);
    235 	if (typeobj == NULL) {
    236 		return (ISC_R_FAILURE);
    237 	}
    238 
    239 	if (list) {
    240 		const char *ztype = cfg_obj_asstring(typeobj);
    241 		printf("%s %s %s %s\n", zname, zclass, view, ztype);
    242 		return (ISC_R_SUCCESS);
    243 	}
    244 
    245 	/*
    246 	 * Skip checks when using an alternate data source.
    247 	 */
    248 	cfg_map_get(zoptions, "database", &dbobj);
    249 	if (dbobj != NULL && strcmp("rbt", cfg_obj_asstring(dbobj)) != 0 &&
    250 	    strcmp("rbt64", cfg_obj_asstring(dbobj)) != 0)
    251 	{
    252 		return (ISC_R_SUCCESS);
    253 	}
    254 
    255 	cfg_map_get(zoptions, "dlz", &dlzobj);
    256 	if (dlzobj != NULL) {
    257 		return (ISC_R_SUCCESS);
    258 	}
    259 
    260 	cfg_map_get(zoptions, "file", &fileobj);
    261 	if (fileobj != NULL) {
    262 		zfile = cfg_obj_asstring(fileobj);
    263 	}
    264 
    265 	/*
    266 	 * Check hints files for hint zones.
    267 	 * Skip loading checks for any type other than
    268 	 * master and redirect
    269 	 */
    270 	if (strcasecmp(cfg_obj_asstring(typeobj), "hint") == 0) {
    271 		return (configure_hint(zfile, zclass, mctx));
    272 	} else if ((strcasecmp(cfg_obj_asstring(typeobj), "primary") != 0) &&
    273 		   (strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) &&
    274 		   (strcasecmp(cfg_obj_asstring(typeobj), "redirect") != 0))
    275 	{
    276 		return (ISC_R_SUCCESS);
    277 	}
    278 
    279 	/*
    280 	 * Is the redirect zone configured as a slave?
    281 	 */
    282 	if (strcasecmp(cfg_obj_asstring(typeobj), "redirect") == 0) {
    283 		cfg_map_get(zoptions, "masters", &mastersobj);
    284 		if (mastersobj != NULL) {
    285 			return (ISC_R_SUCCESS);
    286 		}
    287 	}
    288 
    289 	if (zfile == NULL) {
    290 		return (ISC_R_FAILURE);
    291 	}
    292 
    293 	obj = NULL;
    294 	if (get_maps(maps, "check-dup-records", &obj)) {
    295 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    296 			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
    297 			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
    298 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    299 			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
    300 			zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL;
    301 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    302 			zone_options &= ~DNS_ZONEOPT_CHECKDUPRR;
    303 			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
    304 		} else {
    305 			INSIST(0);
    306 			ISC_UNREACHABLE();
    307 		}
    308 	} else {
    309 		zone_options |= DNS_ZONEOPT_CHECKDUPRR;
    310 		zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
    311 	}
    312 
    313 	obj = NULL;
    314 	if (get_maps(maps, "check-mx", &obj)) {
    315 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    316 			zone_options |= DNS_ZONEOPT_CHECKMX;
    317 			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
    318 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    319 			zone_options |= DNS_ZONEOPT_CHECKMX;
    320 			zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
    321 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    322 			zone_options &= ~DNS_ZONEOPT_CHECKMX;
    323 			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
    324 		} else {
    325 			INSIST(0);
    326 			ISC_UNREACHABLE();
    327 		}
    328 	} else {
    329 		zone_options |= DNS_ZONEOPT_CHECKMX;
    330 		zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
    331 	}
    332 
    333 	obj = NULL;
    334 	if (get_maps(maps, "check-integrity", &obj)) {
    335 		if (cfg_obj_asboolean(obj)) {
    336 			zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
    337 		} else {
    338 			zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
    339 		}
    340 	} else {
    341 		zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
    342 	}
    343 
    344 	obj = NULL;
    345 	if (get_maps(maps, "check-mx-cname", &obj)) {
    346 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    347 			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
    348 			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
    349 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    350 			zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
    351 			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
    352 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    353 			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
    354 			zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
    355 		} else {
    356 			INSIST(0);
    357 			ISC_UNREACHABLE();
    358 		}
    359 	} else {
    360 		zone_options |= DNS_ZONEOPT_WARNMXCNAME;
    361 		zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
    362 	}
    363 
    364 	obj = NULL;
    365 	if (get_maps(maps, "check-srv-cname", &obj)) {
    366 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    367 			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
    368 			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
    369 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    370 			zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
    371 			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
    372 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    373 			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
    374 			zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
    375 		} else {
    376 			INSIST(0);
    377 			ISC_UNREACHABLE();
    378 		}
    379 	} else {
    380 		zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
    381 		zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
    382 	}
    383 
    384 	obj = NULL;
    385 	if (get_maps(maps, "check-sibling", &obj)) {
    386 		if (cfg_obj_asboolean(obj)) {
    387 			zone_options |= DNS_ZONEOPT_CHECKSIBLING;
    388 		} else {
    389 			zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
    390 		}
    391 	}
    392 
    393 	obj = NULL;
    394 	if (get_maps(maps, "check-spf", &obj)) {
    395 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    396 			zone_options |= DNS_ZONEOPT_CHECKSPF;
    397 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    398 			zone_options &= ~DNS_ZONEOPT_CHECKSPF;
    399 		} else {
    400 			INSIST(0);
    401 			ISC_UNREACHABLE();
    402 		}
    403 	} else {
    404 		zone_options |= DNS_ZONEOPT_CHECKSPF;
    405 	}
    406 
    407 	obj = NULL;
    408 	if (get_checknames(maps, &obj)) {
    409 		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
    410 			zone_options |= DNS_ZONEOPT_CHECKNAMES;
    411 			zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
    412 		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
    413 			zone_options |= DNS_ZONEOPT_CHECKNAMES;
    414 			zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
    415 		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
    416 			zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
    417 			zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
    418 		} else {
    419 			INSIST(0);
    420 			ISC_UNREACHABLE();
    421 		}
    422 	} else {
    423 		zone_options |= DNS_ZONEOPT_CHECKNAMES;
    424 		zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
    425 	}
    426 
    427 	masterformat = dns_masterformat_text;
    428 	fmtobj = NULL;
    429 	if (get_maps(maps, "masterfile-format", &fmtobj)) {
    430 		const char *masterformatstr = cfg_obj_asstring(fmtobj);
    431 		if (strcasecmp(masterformatstr, "text") == 0) {
    432 			masterformat = dns_masterformat_text;
    433 		} else if (strcasecmp(masterformatstr, "raw") == 0) {
    434 			masterformat = dns_masterformat_raw;
    435 		} else if (strcasecmp(masterformatstr, "map") == 0) {
    436 			masterformat = dns_masterformat_map;
    437 		} else {
    438 			INSIST(0);
    439 			ISC_UNREACHABLE();
    440 		}
    441 	}
    442 
    443 	obj = NULL;
    444 	if (get_maps(maps, "max-zone-ttl", &obj)) {
    445 		maxttl = cfg_obj_asduration(obj);
    446 		zone_options |= DNS_ZONEOPT_CHECKTTL;
    447 	}
    448 
    449 	result = load_zone(mctx, zname, zfile, masterformat, zclass, maxttl,
    450 			   NULL);
    451 	if (result != ISC_R_SUCCESS) {
    452 		fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
    453 			dns_result_totext(result));
    454 	}
    455 	return (result);
    456 }
    457 
    458 /*% configure a view */
    459 static isc_result_t
    460 configure_view(const char *vclass, const char *view, const cfg_obj_t *config,
    461 	       const cfg_obj_t *vconfig, isc_mem_t *mctx, bool list) {
    462 	const cfg_listelt_t *element;
    463 	const cfg_obj_t *voptions;
    464 	const cfg_obj_t *zonelist;
    465 	isc_result_t result = ISC_R_SUCCESS;
    466 	isc_result_t tresult;
    467 
    468 	voptions = NULL;
    469 	if (vconfig != NULL) {
    470 		voptions = cfg_tuple_get(vconfig, "options");
    471 	}
    472 
    473 	zonelist = NULL;
    474 	if (voptions != NULL) {
    475 		(void)cfg_map_get(voptions, "zone", &zonelist);
    476 	} else {
    477 		(void)cfg_map_get(config, "zone", &zonelist);
    478 	}
    479 
    480 	for (element = cfg_list_first(zonelist); element != NULL;
    481 	     element = cfg_list_next(element))
    482 	{
    483 		const cfg_obj_t *zconfig = cfg_listelt_value(element);
    484 		tresult = configure_zone(vclass, view, zconfig, vconfig, config,
    485 					 mctx, list);
    486 		if (tresult != ISC_R_SUCCESS) {
    487 			result = tresult;
    488 		}
    489 	}
    490 	return (result);
    491 }
    492 
    493 static isc_result_t
    494 config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
    495 		dns_rdataclass_t *classp) {
    496 	isc_textregion_t r;
    497 
    498 	if (!cfg_obj_isstring(classobj)) {
    499 		*classp = defclass;
    500 		return (ISC_R_SUCCESS);
    501 	}
    502 	DE_CONST(cfg_obj_asstring(classobj), r.base);
    503 	r.length = strlen(r.base);
    504 	return (dns_rdataclass_fromtext(classp, &r));
    505 }
    506 
    507 /*% load zones from the configuration */
    508 static isc_result_t
    509 load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx,
    510 		      bool list_zones) {
    511 	const cfg_listelt_t *element;
    512 	const cfg_obj_t *views;
    513 	const cfg_obj_t *vconfig;
    514 	isc_result_t result = ISC_R_SUCCESS;
    515 	isc_result_t tresult;
    516 
    517 	views = NULL;
    518 
    519 	(void)cfg_map_get(config, "view", &views);
    520 	for (element = cfg_list_first(views); element != NULL;
    521 	     element = cfg_list_next(element))
    522 	{
    523 		const cfg_obj_t *classobj;
    524 		dns_rdataclass_t viewclass;
    525 		const char *vname;
    526 		char buf[sizeof("CLASS65535")];
    527 
    528 		vconfig = cfg_listelt_value(element);
    529 		if (vconfig == NULL) {
    530 			continue;
    531 		}
    532 
    533 		classobj = cfg_tuple_get(vconfig, "class");
    534 		tresult = config_getclass(classobj, dns_rdataclass_in,
    535 					  &viewclass);
    536 		if (tresult != ISC_R_SUCCESS) {
    537 			CHECK(tresult);
    538 		}
    539 
    540 		if (dns_rdataclass_ismeta(viewclass)) {
    541 			CHECK(ISC_R_FAILURE);
    542 		}
    543 
    544 		dns_rdataclass_format(viewclass, buf, sizeof(buf));
    545 		vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
    546 		tresult = configure_view(buf, vname, config, vconfig, mctx,
    547 					 list_zones);
    548 		if (tresult != ISC_R_SUCCESS) {
    549 			result = tresult;
    550 		}
    551 	}
    552 
    553 	if (views == NULL) {
    554 		tresult = configure_view("IN", "_default", config, NULL, mctx,
    555 					 list_zones);
    556 		if (tresult != ISC_R_SUCCESS) {
    557 			result = tresult;
    558 		}
    559 	}
    560 
    561 cleanup:
    562 	return (result);
    563 }
    564 
    565 static void
    566 output(void *closure, const char *text, int textlen) {
    567 	UNUSED(closure);
    568 	if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) {
    569 		perror("fwrite");
    570 		exit(1);
    571 	}
    572 }
    573 
    574 /*% The main processing routine */
    575 int
    576 main(int argc, char **argv) {
    577 	int c;
    578 	cfg_parser_t *parser = NULL;
    579 	cfg_obj_t *config = NULL;
    580 	const char *conffile = NULL;
    581 	isc_mem_t *mctx = NULL;
    582 	isc_result_t result;
    583 	int exit_status = 0;
    584 	bool load_zones = false;
    585 	bool list_zones = false;
    586 	bool print = false;
    587 	bool nodeprecate = false;
    588 	unsigned int flags = 0;
    589 
    590 	isc_commandline_errprint = false;
    591 
    592 	/*
    593 	 * Process memory debugging argument first.
    594 	 */
    595 #define CMDLINE_FLAGS "cdhijlm:t:pvxz"
    596 	while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
    597 		switch (c) {
    598 		case 'm':
    599 			if (strcasecmp(isc_commandline_argument, "record") == 0)
    600 			{
    601 				isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
    602 			}
    603 			if (strcasecmp(isc_commandline_argument, "trace") == 0)
    604 			{
    605 				isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
    606 			}
    607 			if (strcasecmp(isc_commandline_argument, "usage") == 0)
    608 			{
    609 				isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
    610 			}
    611 			if (strcasecmp(isc_commandline_argument, "size") == 0) {
    612 				isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
    613 			}
    614 			if (strcasecmp(isc_commandline_argument, "mctx") == 0) {
    615 				isc_mem_debugging |= ISC_MEM_DEBUGCTX;
    616 			}
    617 			break;
    618 		default:
    619 			break;
    620 		}
    621 	}
    622 	isc_commandline_reset = true;
    623 
    624 	isc_mem_create(&mctx);
    625 
    626 	while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) {
    627 		switch (c) {
    628 		case 'c':
    629 			loadplugins = false;
    630 			break;
    631 
    632 		case 'd':
    633 			debug++;
    634 			break;
    635 
    636 		case 'i':
    637 			nodeprecate = true;
    638 			break;
    639 
    640 		case 'j':
    641 			nomerge = false;
    642 			break;
    643 
    644 		case 'l':
    645 			list_zones = true;
    646 			break;
    647 
    648 		case 'm':
    649 			break;
    650 
    651 		case 't':
    652 			result = isc_dir_chroot(isc_commandline_argument);
    653 			if (result != ISC_R_SUCCESS) {
    654 				fprintf(stderr, "isc_dir_chroot: %s\n",
    655 					isc_result_totext(result));
    656 				exit(1);
    657 			}
    658 			break;
    659 
    660 		case 'p':
    661 			print = true;
    662 			break;
    663 
    664 		case 'v':
    665 			printf(VERSION "\n");
    666 			exit(0);
    667 
    668 		case 'x':
    669 			flags |= CFG_PRINTER_XKEY;
    670 			break;
    671 
    672 		case 'z':
    673 			load_zones = true;
    674 			docheckmx = false;
    675 			docheckns = false;
    676 			dochecksrv = false;
    677 			break;
    678 
    679 		case '?':
    680 			if (isc_commandline_option != '?') {
    681 				fprintf(stderr, "%s: invalid argument -%c\n",
    682 					program, isc_commandline_option);
    683 			}
    684 		/* FALLTHROUGH */
    685 		case 'h':
    686 			usage();
    687 
    688 		default:
    689 			fprintf(stderr, "%s: unhandled option -%c\n", program,
    690 				isc_commandline_option);
    691 			exit(1);
    692 		}
    693 	}
    694 
    695 	if (((flags & CFG_PRINTER_XKEY) != 0) && !print) {
    696 		fprintf(stderr, "%s: -x cannot be used without -p\n", program);
    697 		exit(1);
    698 	}
    699 	if (print && list_zones) {
    700 		fprintf(stderr, "%s: -l cannot be used with -p\n", program);
    701 		exit(1);
    702 	}
    703 
    704 	if (isc_commandline_index + 1 < argc) {
    705 		usage();
    706 	}
    707 	if (argv[isc_commandline_index] != NULL) {
    708 		conffile = argv[isc_commandline_index];
    709 	}
    710 	if (conffile == NULL || conffile[0] == '\0') {
    711 		conffile = NAMED_CONFFILE;
    712 	}
    713 
    714 #ifdef _WIN32
    715 	InitSockets();
    716 #endif /* ifdef _WIN32 */
    717 
    718 	RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
    719 
    720 	dns_result_register();
    721 
    722 	RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
    723 
    724 	if (nodeprecate) {
    725 		cfg_parser_setflags(parser, CFG_PCTX_NODEPRECATED, true);
    726 	}
    727 	cfg_parser_setcallback(parser, directory_callback, NULL);
    728 
    729 	if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
    730 	    ISC_R_SUCCESS)
    731 	{
    732 		exit(1);
    733 	}
    734 
    735 	result = bind9_check_namedconf(config, loadplugins, logc, mctx);
    736 	if (result != ISC_R_SUCCESS) {
    737 		exit_status = 1;
    738 	}
    739 
    740 	if (result == ISC_R_SUCCESS && (load_zones || list_zones)) {
    741 		result = load_zones_fromconfig(config, mctx, list_zones);
    742 		if (result != ISC_R_SUCCESS) {
    743 			exit_status = 1;
    744 		}
    745 	}
    746 
    747 	if (print && exit_status == 0) {
    748 		cfg_printx(config, flags, output, NULL);
    749 	}
    750 	cfg_obj_destroy(parser, &config);
    751 
    752 	cfg_parser_destroy(&parser);
    753 
    754 	isc_log_destroy(&logc);
    755 
    756 	isc_mem_destroy(&mctx);
    757 
    758 #ifdef _WIN32
    759 	DestroySockets();
    760 #endif /* ifdef _WIN32 */
    761 
    762 	return (exit_status);
    763 }
    764