1 /* $NetBSD: named-checkconf.c,v 1.11 2015/07/08 17:28:54 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004-2007, 2009-2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2002 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: named-checkconf.c,v 1.56 2011/03/12 04:59:46 tbox Exp */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <errno.h> 27 #include <stdlib.h> 28 #include <stdio.h> 29 30 #include <isc/commandline.h> 31 #include <isc/dir.h> 32 #include <isc/entropy.h> 33 #include <isc/hash.h> 34 #include <isc/log.h> 35 #include <isc/mem.h> 36 #include <isc/result.h> 37 #include <isc/string.h> 38 #include <isc/util.h> 39 40 #include <isccfg/namedconf.h> 41 42 #include <bind9/check.h> 43 44 #include <dns/db.h> 45 #include <dns/fixedname.h> 46 #include <dns/log.h> 47 #include <dns/name.h> 48 #include <dns/rdataclass.h> 49 #include <dns/result.h> 50 #include <dns/rootns.h> 51 #include <dns/zone.h> 52 53 #include "check-tool.h" 54 55 static const char *program = "named-checkconf"; 56 57 isc_log_t *logc = NULL; 58 59 #define CHECK(r)\ 60 do { \ 61 result = (r); \ 62 if (result != ISC_R_SUCCESS) \ 63 goto cleanup; \ 64 } while (/*CONSTCOND*/0) 65 66 /*% usage */ 67 ISC_PLATFORM_NORETURN_PRE static void 68 usage(void) ISC_PLATFORM_NORETURN_POST; 69 70 static void 71 usage(void) { 72 fprintf(stderr, "usage: %s [-h] [-j] [-p] [-v] [-z] [-t directory] " 73 "[named.conf]\n", program); 74 exit(1); 75 } 76 77 /*% directory callback */ 78 static isc_result_t 79 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { 80 isc_result_t result; 81 const char *directory; 82 83 REQUIRE(strcasecmp("directory", clausename) == 0); 84 85 UNUSED(arg); 86 UNUSED(clausename); 87 88 /* 89 * Change directory. 90 */ 91 directory = cfg_obj_asstring(obj); 92 result = isc_dir_chdir(directory); 93 if (result != ISC_R_SUCCESS) { 94 cfg_obj_log(obj, logc, ISC_LOG_ERROR, 95 "change directory to '%s' failed: %s\n", 96 directory, isc_result_totext(result)); 97 return (result); 98 } 99 100 return (ISC_R_SUCCESS); 101 } 102 103 static isc_boolean_t 104 get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) { 105 int i; 106 for (i = 0;; i++) { 107 if (maps[i] == NULL) 108 return (ISC_FALSE); 109 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) 110 return (ISC_TRUE); 111 } 112 } 113 114 static isc_boolean_t 115 get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) { 116 const cfg_listelt_t *element; 117 const cfg_obj_t *checknames; 118 const cfg_obj_t *type; 119 const cfg_obj_t *value; 120 isc_result_t result; 121 int i; 122 123 for (i = 0;; i++) { 124 if (maps[i] == NULL) 125 return (ISC_FALSE); 126 checknames = NULL; 127 result = cfg_map_get(maps[i], "check-names", &checknames); 128 if (result != ISC_R_SUCCESS) 129 continue; 130 if (checknames != NULL && !cfg_obj_islist(checknames)) { 131 *obj = checknames; 132 return (ISC_TRUE); 133 } 134 for (element = cfg_list_first(checknames); 135 element != NULL; 136 element = cfg_list_next(element)) { 137 value = cfg_listelt_value(element); 138 type = cfg_tuple_get(value, "type"); 139 if (strcasecmp(cfg_obj_asstring(type), "master") != 0) 140 continue; 141 *obj = cfg_tuple_get(value, "mode"); 142 return (ISC_TRUE); 143 } 144 } 145 } 146 147 static isc_result_t 148 configure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) { 149 isc_result_t result; 150 dns_db_t *db = NULL; 151 dns_rdataclass_t rdclass; 152 isc_textregion_t r; 153 154 if (zfile == NULL) 155 return (ISC_R_FAILURE); 156 157 DE_CONST(zclass, r.base); 158 r.length = strlen(zclass); 159 result = dns_rdataclass_fromtext(&rdclass, &r); 160 if (result != ISC_R_SUCCESS) 161 return (result); 162 163 result = dns_rootns_create(mctx, rdclass, zfile, &db); 164 if (result != ISC_R_SUCCESS) 165 return (result); 166 167 dns_db_detach(&db); 168 return (ISC_R_SUCCESS); 169 } 170 171 /*% configure the zone */ 172 static isc_result_t 173 configure_zone(const char *vclass, const char *view, 174 const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, 175 const cfg_obj_t *config, isc_mem_t *mctx) 176 { 177 int i = 0; 178 isc_result_t result; 179 const char *zclass; 180 const char *zname; 181 const char *zfile = NULL; 182 const cfg_obj_t *maps[4]; 183 const cfg_obj_t *mastersobj = NULL; 184 const cfg_obj_t *zoptions = NULL; 185 const cfg_obj_t *classobj = NULL; 186 const cfg_obj_t *typeobj = NULL; 187 const cfg_obj_t *fileobj = NULL; 188 const cfg_obj_t *dlzobj = NULL; 189 const cfg_obj_t *dbobj = NULL; 190 const cfg_obj_t *obj = NULL; 191 const cfg_obj_t *fmtobj = NULL; 192 dns_masterformat_t masterformat; 193 dns_ttl_t maxttl = 0; 194 195 zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS; 196 197 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 198 classobj = cfg_tuple_get(zconfig, "class"); 199 if (!cfg_obj_isstring(classobj)) 200 zclass = vclass; 201 else 202 zclass = cfg_obj_asstring(classobj); 203 204 zoptions = cfg_tuple_get(zconfig, "options"); 205 maps[i++] = zoptions; 206 if (vconfig != NULL) 207 maps[i++] = cfg_tuple_get(vconfig, "options"); 208 if (config != NULL) { 209 cfg_map_get(config, "options", &obj); 210 if (obj != NULL) 211 maps[i++] = obj; 212 } 213 maps[i] = NULL; 214 215 cfg_map_get(zoptions, "type", &typeobj); 216 if (typeobj == NULL) 217 return (ISC_R_FAILURE); 218 219 /* 220 * Skip checks when using an alternate data source. 221 */ 222 cfg_map_get(zoptions, "database", &dbobj); 223 if (dbobj != NULL && 224 strcmp("rbt", cfg_obj_asstring(dbobj)) != 0 && 225 strcmp("rbt64", cfg_obj_asstring(dbobj)) != 0) 226 return (ISC_R_SUCCESS); 227 228 cfg_map_get(zoptions, "dlz", &dlzobj); 229 if (dlzobj != NULL) 230 return (ISC_R_SUCCESS); 231 232 cfg_map_get(zoptions, "file", &fileobj); 233 if (fileobj != NULL) 234 zfile = cfg_obj_asstring(fileobj); 235 236 /* 237 * Check hints files for hint zones. 238 * Skip loading checks for any type other than 239 * master and redirect 240 */ 241 if (strcasecmp(cfg_obj_asstring(typeobj), "hint") == 0) 242 return (configure_hint(zfile, zclass, mctx)); 243 else if ((strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) && 244 (strcasecmp(cfg_obj_asstring(typeobj), "redirect") != 0)) 245 return (ISC_R_SUCCESS); 246 247 /* 248 * Is the redirect zone configured as a slave? 249 */ 250 if (strcasecmp(cfg_obj_asstring(typeobj), "redirect") == 0) { 251 cfg_map_get(zoptions, "masters", &mastersobj); 252 if (mastersobj != NULL) 253 return (ISC_R_SUCCESS); 254 } 255 256 if (zfile == NULL) 257 return (ISC_R_FAILURE); 258 259 obj = NULL; 260 if (get_maps(maps, "check-dup-records", &obj)) { 261 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { 262 zone_options |= DNS_ZONEOPT_CHECKDUPRR; 263 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL; 264 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { 265 zone_options |= DNS_ZONEOPT_CHECKDUPRR; 266 zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL; 267 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { 268 zone_options &= ~DNS_ZONEOPT_CHECKDUPRR; 269 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL; 270 } else 271 INSIST(0); 272 } else { 273 zone_options |= DNS_ZONEOPT_CHECKDUPRR; 274 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL; 275 } 276 277 obj = NULL; 278 if (get_maps(maps, "check-mx", &obj)) { 279 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { 280 zone_options |= DNS_ZONEOPT_CHECKMX; 281 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; 282 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { 283 zone_options |= DNS_ZONEOPT_CHECKMX; 284 zone_options |= DNS_ZONEOPT_CHECKMXFAIL; 285 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { 286 zone_options &= ~DNS_ZONEOPT_CHECKMX; 287 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; 288 } else 289 INSIST(0); 290 } else { 291 zone_options |= DNS_ZONEOPT_CHECKMX; 292 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL; 293 } 294 295 obj = NULL; 296 if (get_maps(maps, "check-integrity", &obj)) { 297 if (cfg_obj_asboolean(obj)) 298 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; 299 else 300 zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY; 301 } else 302 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY; 303 304 obj = NULL; 305 if (get_maps(maps, "check-mx-cname", &obj)) { 306 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { 307 zone_options |= DNS_ZONEOPT_WARNMXCNAME; 308 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; 309 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { 310 zone_options &= ~DNS_ZONEOPT_WARNMXCNAME; 311 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; 312 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { 313 zone_options |= DNS_ZONEOPT_WARNMXCNAME; 314 zone_options |= DNS_ZONEOPT_IGNOREMXCNAME; 315 } else 316 INSIST(0); 317 } else { 318 zone_options |= DNS_ZONEOPT_WARNMXCNAME; 319 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME; 320 } 321 322 obj = NULL; 323 if (get_maps(maps, "check-srv-cname", &obj)) { 324 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { 325 zone_options |= DNS_ZONEOPT_WARNSRVCNAME; 326 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; 327 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { 328 zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME; 329 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; 330 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { 331 zone_options |= DNS_ZONEOPT_WARNSRVCNAME; 332 zone_options |= DNS_ZONEOPT_IGNORESRVCNAME; 333 } else 334 INSIST(0); 335 } else { 336 zone_options |= DNS_ZONEOPT_WARNSRVCNAME; 337 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME; 338 } 339 340 obj = NULL; 341 if (get_maps(maps, "check-sibling", &obj)) { 342 if (cfg_obj_asboolean(obj)) 343 zone_options |= DNS_ZONEOPT_CHECKSIBLING; 344 else 345 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING; 346 } 347 348 obj = NULL; 349 if (get_maps(maps, "check-spf", &obj)) { 350 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { 351 zone_options |= DNS_ZONEOPT_CHECKSPF; 352 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { 353 zone_options &= ~DNS_ZONEOPT_CHECKSPF; 354 } else 355 INSIST(0); 356 } else { 357 zone_options |= DNS_ZONEOPT_CHECKSPF; 358 } 359 360 obj = NULL; 361 if (get_checknames(maps, &obj)) { 362 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { 363 zone_options |= DNS_ZONEOPT_CHECKNAMES; 364 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; 365 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { 366 zone_options |= DNS_ZONEOPT_CHECKNAMES; 367 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL; 368 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { 369 zone_options &= ~DNS_ZONEOPT_CHECKNAMES; 370 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL; 371 } else 372 INSIST(0); 373 } else { 374 zone_options |= DNS_ZONEOPT_CHECKNAMES; 375 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL; 376 } 377 378 masterformat = dns_masterformat_text; 379 fmtobj = NULL; 380 if (get_maps(maps, "masterfile-format", &fmtobj)) { 381 const char *masterformatstr = cfg_obj_asstring(fmtobj); 382 if (strcasecmp(masterformatstr, "text") == 0) 383 masterformat = dns_masterformat_text; 384 else if (strcasecmp(masterformatstr, "raw") == 0) 385 masterformat = dns_masterformat_raw; 386 else if (strcasecmp(masterformatstr, "map") == 0) 387 masterformat = dns_masterformat_map; 388 else 389 INSIST(0); 390 } 391 392 obj = NULL; 393 if (get_maps(maps, "max-zone-ttl", &obj)) { 394 maxttl = cfg_obj_asuint32(obj); 395 zone_options2 |= DNS_ZONEOPT2_CHECKTTL; 396 } 397 398 result = load_zone(mctx, zname, zfile, masterformat, 399 zclass, maxttl, NULL); 400 if (result != ISC_R_SUCCESS) 401 fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass, 402 dns_result_totext(result)); 403 return (result); 404 } 405 406 /*% configure a view */ 407 static isc_result_t 408 configure_view(const char *vclass, const char *view, const cfg_obj_t *config, 409 const cfg_obj_t *vconfig, isc_mem_t *mctx) 410 { 411 const cfg_listelt_t *element; 412 const cfg_obj_t *voptions; 413 const cfg_obj_t *zonelist; 414 isc_result_t result = ISC_R_SUCCESS; 415 isc_result_t tresult; 416 417 voptions = NULL; 418 if (vconfig != NULL) 419 voptions = cfg_tuple_get(vconfig, "options"); 420 421 zonelist = NULL; 422 if (voptions != NULL) 423 (void)cfg_map_get(voptions, "zone", &zonelist); 424 else 425 (void)cfg_map_get(config, "zone", &zonelist); 426 427 for (element = cfg_list_first(zonelist); 428 element != NULL; 429 element = cfg_list_next(element)) 430 { 431 const cfg_obj_t *zconfig = cfg_listelt_value(element); 432 tresult = configure_zone(vclass, view, zconfig, vconfig, 433 config, mctx); 434 if (tresult != ISC_R_SUCCESS) 435 result = tresult; 436 } 437 return (result); 438 } 439 440 441 /*% load zones from the configuration */ 442 static isc_result_t 443 load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx) { 444 const cfg_listelt_t *element; 445 const cfg_obj_t *classobj; 446 const cfg_obj_t *views; 447 const cfg_obj_t *vconfig; 448 const char *vclass; 449 isc_result_t result = ISC_R_SUCCESS; 450 isc_result_t tresult; 451 452 views = NULL; 453 454 (void)cfg_map_get(config, "view", &views); 455 for (element = cfg_list_first(views); 456 element != NULL; 457 element = cfg_list_next(element)) 458 { 459 const char *vname; 460 461 vclass = "IN"; 462 vconfig = cfg_listelt_value(element); 463 if (vconfig != NULL) { 464 classobj = cfg_tuple_get(vconfig, "class"); 465 if (cfg_obj_isstring(classobj)) 466 vclass = cfg_obj_asstring(classobj); 467 } 468 vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name")); 469 tresult = configure_view(vclass, vname, config, vconfig, mctx); 470 if (tresult != ISC_R_SUCCESS) 471 result = tresult; 472 } 473 474 if (views == NULL) { 475 tresult = configure_view("IN", "_default", config, NULL, mctx); 476 if (tresult != ISC_R_SUCCESS) 477 result = tresult; 478 } 479 return (result); 480 } 481 482 static void 483 output(void *closure, const char *text, int textlen) { 484 UNUSED(closure); 485 if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) { 486 perror("fwrite"); 487 exit(1); 488 } 489 } 490 491 /*% The main processing routine */ 492 int 493 main(int argc, char **argv) { 494 int c; 495 cfg_parser_t *parser = NULL; 496 cfg_obj_t *config = NULL; 497 const char *conffile = NULL; 498 isc_mem_t *mctx = NULL; 499 isc_result_t result; 500 int exit_status = 0; 501 isc_entropy_t *ectx = NULL; 502 isc_boolean_t load_zones = ISC_FALSE; 503 isc_boolean_t print = ISC_FALSE; 504 unsigned int flags = 0; 505 506 isc__mem_register(); 507 isc_commandline_errprint = ISC_FALSE; 508 509 /* 510 * Process memory debugging argument first. 511 */ 512 #define CMDLINE_FLAGS "dhjm:t:pvxz" 513 while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { 514 switch (c) { 515 case 'm': 516 if (strcasecmp(isc_commandline_argument, "record") == 0) 517 isc_mem_debugging |= ISC_MEM_DEBUGRECORD; 518 if (strcasecmp(isc_commandline_argument, "trace") == 0) 519 isc_mem_debugging |= ISC_MEM_DEBUGTRACE; 520 if (strcasecmp(isc_commandline_argument, "usage") == 0) 521 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; 522 if (strcasecmp(isc_commandline_argument, "size") == 0) 523 isc_mem_debugging |= ISC_MEM_DEBUGSIZE; 524 if (strcasecmp(isc_commandline_argument, "mctx") == 0) 525 isc_mem_debugging |= ISC_MEM_DEBUGCTX; 526 break; 527 default: 528 break; 529 } 530 } 531 isc_commandline_reset = ISC_TRUE; 532 533 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); 534 535 while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) { 536 switch (c) { 537 case 'd': 538 debug++; 539 break; 540 541 case 'j': 542 nomerge = ISC_FALSE; 543 break; 544 545 case 'm': 546 break; 547 548 case 't': 549 result = isc_dir_chroot(isc_commandline_argument); 550 if (result != ISC_R_SUCCESS) { 551 fprintf(stderr, "isc_dir_chroot: %s\n", 552 isc_result_totext(result)); 553 exit(1); 554 } 555 break; 556 557 case 'p': 558 print = ISC_TRUE; 559 break; 560 561 case 'v': 562 printf(VERSION "\n"); 563 exit(0); 564 565 case 'x': 566 flags |= CFG_PRINTER_XKEY; 567 break; 568 569 case 'z': 570 load_zones = ISC_TRUE; 571 docheckmx = ISC_FALSE; 572 docheckns = ISC_FALSE; 573 dochecksrv = ISC_FALSE; 574 break; 575 576 case '?': 577 if (isc_commandline_option != '?') 578 fprintf(stderr, "%s: invalid argument -%c\n", 579 program, isc_commandline_option); 580 /* FALLTHROUGH */ 581 case 'h': 582 usage(); 583 584 default: 585 fprintf(stderr, "%s: unhandled option -%c\n", 586 program, isc_commandline_option); 587 exit(1); 588 } 589 } 590 591 if (((flags & CFG_PRINTER_XKEY) != 0) && !print) { 592 fprintf(stderr, "%s: -x cannot be used without -p\n", program); 593 exit(1); 594 } 595 596 if (isc_commandline_index + 1 < argc) 597 usage(); 598 if (argv[isc_commandline_index] != NULL) 599 conffile = argv[isc_commandline_index]; 600 if (conffile == NULL || conffile[0] == '\0') 601 conffile = NAMED_CONFFILE; 602 603 #ifdef _WIN32 604 InitSockets(); 605 #endif 606 607 RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS); 608 609 RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS); 610 RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE) 611 == ISC_R_SUCCESS); 612 613 dns_result_register(); 614 615 RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS); 616 617 cfg_parser_setcallback(parser, directory_callback, NULL); 618 619 if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) != 620 ISC_R_SUCCESS) 621 exit(1); 622 623 result = bind9_check_namedconf(config, logc, mctx); 624 if (result != ISC_R_SUCCESS) 625 exit_status = 1; 626 627 if (result == ISC_R_SUCCESS && load_zones) { 628 result = load_zones_fromconfig(config, mctx); 629 if (result != ISC_R_SUCCESS) 630 exit_status = 1; 631 } 632 633 if (print && exit_status == 0) 634 cfg_printx(config, flags, output, NULL); 635 cfg_obj_destroy(parser, &config); 636 637 cfg_parser_destroy(&parser); 638 639 dns_name_destroy(); 640 641 isc_log_destroy(&logc); 642 643 isc_hash_destroy(); 644 isc_entropy_detach(&ectx); 645 646 isc_mem_destroy(&mctx); 647 648 #ifdef _WIN32 649 DestroySockets(); 650 #endif 651 652 return (exit_status); 653 } 654