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