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