1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 /*! \file */
13
14 #include <errno.h>
15 #include <stdbool.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18
19 #include <isc/attributes.h>
20 #include <isc/commandline.h>
21 #include <isc/dir.h>
22 #include <isc/hash.h>
23 #include <isc/log.h>
24 #include <isc/mem.h>
25 #include <isc/print.h>
26 #include <isc/result.h>
27 #include <isc/string.h>
28 #include <isc/util.h>
29
30 #include <dns/db.h>
31 #include <dns/fixedname.h>
32 #include <dns/log.h>
33 #include <dns/name.h>
34 #include <dns/rdataclass.h>
35 #include <dns/rootns.h>
36 #include <dns/zone.h>
37
38 #include <isccfg/grammar.h>
39 #include <isccfg/namedconf.h>
40
41 #include <bind9/check.h>
42
43 #include "check-tool.h"
44
45 static const char *program = "named-checkconf";
46
47 static bool loadplugins = true;
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 ISC_NORETURN static void
60 usage(void);
61
62 static void
usage(void)63 usage(void) {
64 fprintf(stderr,
65 "usage: %s [-chijlvz] [-p [-x]] [-t directory] "
66 "[named.conf]\n",
67 program);
68 exit(1);
69 }
70
71 /*% directory callback */
72 static isc_result_t
directory_callback(const char * clausename,const cfg_obj_t * obj,void * arg)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
get_maps(const cfg_obj_t ** maps,const char * name,const cfg_obj_t ** obj)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
get_checknames(const cfg_obj_t ** maps,const cfg_obj_t ** obj)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
configure_hint(const char * zfile,const char * zclass,isc_mem_t * mctx)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 DE_CONST(zclass, r.base);
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
configure_zone(const char * vclass,const char * view,const cfg_obj_t * zconfig,const cfg_obj_t * vconfig,const cfg_obj_t * config,isc_mem_t * mctx,bool list)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 && strcmp("rbt", cfg_obj_asstring(dbobj)) != 0 &&
248 strcmp("rbt64", 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 slave?
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 INSIST(0);
308 ISC_UNREACHABLE();
309 }
310 } else {
311 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
312 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
313 }
314
315 obj = NULL;
316 if (get_maps(maps, "check-mx", &obj)) {
317 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
318 zone_options |= DNS_ZONEOPT_CHECKMX;
319 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
320 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
321 zone_options |= DNS_ZONEOPT_CHECKMX;
322 zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
323 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
324 zone_options &= ~DNS_ZONEOPT_CHECKMX;
325 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
326 } else {
327 INSIST(0);
328 ISC_UNREACHABLE();
329 }
330 } else {
331 zone_options |= DNS_ZONEOPT_CHECKMX;
332 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
333 }
334
335 obj = NULL;
336 if (get_maps(maps, "check-integrity", &obj)) {
337 if (cfg_obj_asboolean(obj)) {
338 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
339 } else {
340 zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
341 }
342 } else {
343 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
344 }
345
346 obj = NULL;
347 if (get_maps(maps, "check-mx-cname", &obj)) {
348 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
349 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
350 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
351 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
352 zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
353 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
354 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
355 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
356 zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
357 } else {
358 INSIST(0);
359 ISC_UNREACHABLE();
360 }
361 } else {
362 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
363 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
364 }
365
366 obj = NULL;
367 if (get_maps(maps, "check-srv-cname", &obj)) {
368 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
369 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
370 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
371 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
372 zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
373 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
374 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
375 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
376 zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
377 } else {
378 INSIST(0);
379 ISC_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 INSIST(0);
403 ISC_UNREACHABLE();
404 }
405 } else {
406 zone_options |= DNS_ZONEOPT_CHECKSPF;
407 }
408
409 obj = NULL;
410 if (get_checknames(maps, &obj)) {
411 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
412 zone_options |= DNS_ZONEOPT_CHECKNAMES;
413 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
414 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
415 zone_options |= DNS_ZONEOPT_CHECKNAMES;
416 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
417 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
418 zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
419 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
420 } else {
421 INSIST(0);
422 ISC_UNREACHABLE();
423 }
424 } else {
425 zone_options |= DNS_ZONEOPT_CHECKNAMES;
426 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
427 }
428
429 masterformat = dns_masterformat_text;
430 fmtobj = NULL;
431 if (get_maps(maps, "masterfile-format", &fmtobj)) {
432 const char *masterformatstr = cfg_obj_asstring(fmtobj);
433 if (strcasecmp(masterformatstr, "text") == 0) {
434 masterformat = dns_masterformat_text;
435 } else if (strcasecmp(masterformatstr, "raw") == 0) {
436 masterformat = dns_masterformat_raw;
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 isc_result_totext(result));
454 }
455 return (result);
456 }
457
458 /*% configure a view */
459 static isc_result_t
configure_view(const char * vclass,const char * view,const cfg_obj_t * config,const cfg_obj_t * vconfig,isc_mem_t * mctx,bool list)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
config_getclass(const cfg_obj_t * classobj,dns_rdataclass_t defclass,dns_rdataclass_t * classp)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
load_zones_fromconfig(const cfg_obj_t * config,isc_mem_t * mctx,bool list_zones)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
output(void * closure,const char * text,int textlen)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
main(int argc,char ** argv)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 break;
612 default:
613 break;
614 }
615 }
616 isc_commandline_reset = true;
617
618 isc_mem_create(&mctx);
619
620 while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) {
621 switch (c) {
622 case 'c':
623 loadplugins = false;
624 break;
625
626 case 'd':
627 debug++;
628 break;
629
630 case 'i':
631 nodeprecate = true;
632 break;
633
634 case 'j':
635 nomerge = false;
636 break;
637
638 case 'l':
639 list_zones = true;
640 break;
641
642 case 'm':
643 break;
644
645 case 't':
646 result = isc_dir_chroot(isc_commandline_argument);
647 if (result != ISC_R_SUCCESS) {
648 fprintf(stderr, "isc_dir_chroot: %s\n",
649 isc_result_totext(result));
650 exit(1);
651 }
652 break;
653
654 case 'p':
655 print = true;
656 break;
657
658 case 'v':
659 printf("%s\n", PACKAGE_VERSION);
660 exit(0);
661
662 case 'x':
663 flags |= CFG_PRINTER_XKEY;
664 break;
665
666 case 'z':
667 load_zones = true;
668 docheckmx = false;
669 docheckns = false;
670 dochecksrv = false;
671 break;
672
673 case '?':
674 if (isc_commandline_option != '?') {
675 fprintf(stderr, "%s: invalid argument -%c\n",
676 program, isc_commandline_option);
677 }
678 /* FALLTHROUGH */
679 case 'h':
680 usage();
681
682 default:
683 fprintf(stderr, "%s: unhandled option -%c\n", program,
684 isc_commandline_option);
685 exit(1);
686 }
687 }
688
689 if (((flags & CFG_PRINTER_XKEY) != 0) && !print) {
690 fprintf(stderr, "%s: -x cannot be used without -p\n", program);
691 exit(1);
692 }
693 if (print && list_zones) {
694 fprintf(stderr, "%s: -l cannot be used with -p\n", program);
695 exit(1);
696 }
697
698 if (isc_commandline_index + 1 < argc) {
699 usage();
700 }
701 if (argv[isc_commandline_index] != NULL) {
702 conffile = argv[isc_commandline_index];
703 }
704 if (conffile == NULL || conffile[0] == '\0') {
705 conffile = NAMED_CONFFILE;
706 }
707
708 RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
709
710 RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
711
712 if (nodeprecate) {
713 cfg_parser_setflags(parser, CFG_PCTX_NODEPRECATED, true);
714 }
715 cfg_parser_setcallback(parser, directory_callback, NULL);
716
717 if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
718 ISC_R_SUCCESS)
719 {
720 exit(1);
721 }
722
723 result = bind9_check_namedconf(config, loadplugins, logc, mctx);
724 if (result != ISC_R_SUCCESS) {
725 exit_status = 1;
726 }
727
728 if (result == ISC_R_SUCCESS && (load_zones || list_zones)) {
729 result = load_zones_fromconfig(config, mctx, list_zones);
730 if (result != ISC_R_SUCCESS) {
731 exit_status = 1;
732 }
733 }
734
735 if (print && exit_status == 0) {
736 cfg_printx(config, flags, output, NULL);
737 }
738 cfg_obj_destroy(parser, &config);
739
740 cfg_parser_destroy(&parser);
741
742 isc_log_destroy(&logc);
743
744 isc_mem_destroy(&mctx);
745
746 return (exit_status);
747 }
748