named-checkconf.c revision 1.1.1.7 1 /* $NetBSD: named-checkconf.c,v 1.1.1.7 2023/01/25 20:36:34 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/commandline.h>
24 #include <isc/dir.h>
25 #include <isc/hash.h>
26 #include <isc/log.h>
27 #include <isc/mem.h>
28 #include <isc/print.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/result.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
49 static const char *program = "named-checkconf";
50
51 static bool loadplugins = true;
52
53 isc_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 */
63 ISC_PLATFORM_NORETURN_PRE static void
64 usage(void) ISC_PLATFORM_NORETURN_POST;
65
66 static void
67 usage(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 */
76 static isc_result_t
77 directory_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
101 static bool
102 get_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
114 static bool
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 (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
153 static isc_result_t
154 configure_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 */
181 static isc_result_t
182 configure_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 slave?
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 if (strcasecmp(masterformatstr, "map") == 0) {
447 masterformat = dns_masterformat_map;
448 } else {
449 UNREACHABLE();
450 }
451 }
452
453 obj = NULL;
454 if (get_maps(maps, "max-zone-ttl", &obj)) {
455 maxttl = cfg_obj_asduration(obj);
456 zone_options |= DNS_ZONEOPT_CHECKTTL;
457 }
458
459 result = load_zone(mctx, zname, zfile, masterformat, zclass, maxttl,
460 NULL);
461 if (result != ISC_R_SUCCESS) {
462 fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
463 dns_result_totext(result));
464 }
465 return (result);
466 }
467
468 /*% configure a view */
469 static isc_result_t
470 configure_view(const char *vclass, const char *view, const cfg_obj_t *config,
471 const cfg_obj_t *vconfig, isc_mem_t *mctx, bool list) {
472 const cfg_listelt_t *element;
473 const cfg_obj_t *voptions;
474 const cfg_obj_t *zonelist;
475 isc_result_t result = ISC_R_SUCCESS;
476 isc_result_t tresult;
477
478 voptions = NULL;
479 if (vconfig != NULL) {
480 voptions = cfg_tuple_get(vconfig, "options");
481 }
482
483 zonelist = NULL;
484 if (voptions != NULL) {
485 (void)cfg_map_get(voptions, "zone", &zonelist);
486 } else {
487 (void)cfg_map_get(config, "zone", &zonelist);
488 }
489
490 for (element = cfg_list_first(zonelist); element != NULL;
491 element = cfg_list_next(element))
492 {
493 const cfg_obj_t *zconfig = cfg_listelt_value(element);
494 tresult = configure_zone(vclass, view, zconfig, vconfig, config,
495 mctx, list);
496 if (tresult != ISC_R_SUCCESS) {
497 result = tresult;
498 }
499 }
500 return (result);
501 }
502
503 static isc_result_t
504 config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
505 dns_rdataclass_t *classp) {
506 isc_textregion_t r;
507
508 if (!cfg_obj_isstring(classobj)) {
509 *classp = defclass;
510 return (ISC_R_SUCCESS);
511 }
512 DE_CONST(cfg_obj_asstring(classobj), r.base);
513 r.length = strlen(r.base);
514 return (dns_rdataclass_fromtext(classp, &r));
515 }
516
517 /*% load zones from the configuration */
518 static isc_result_t
519 load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx,
520 bool list_zones) {
521 const cfg_listelt_t *element;
522 const cfg_obj_t *views;
523 const cfg_obj_t *vconfig;
524 isc_result_t result = ISC_R_SUCCESS;
525 isc_result_t tresult;
526
527 views = NULL;
528
529 (void)cfg_map_get(config, "view", &views);
530 for (element = cfg_list_first(views); element != NULL;
531 element = cfg_list_next(element))
532 {
533 const cfg_obj_t *classobj;
534 dns_rdataclass_t viewclass;
535 const char *vname;
536 char buf[sizeof("CLASS65535")];
537
538 vconfig = cfg_listelt_value(element);
539 if (vconfig == NULL) {
540 continue;
541 }
542
543 classobj = cfg_tuple_get(vconfig, "class");
544 tresult = config_getclass(classobj, dns_rdataclass_in,
545 &viewclass);
546 if (tresult != ISC_R_SUCCESS) {
547 CHECK(tresult);
548 }
549
550 if (dns_rdataclass_ismeta(viewclass)) {
551 CHECK(ISC_R_FAILURE);
552 }
553
554 dns_rdataclass_format(viewclass, buf, sizeof(buf));
555 vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
556 tresult = configure_view(buf, vname, config, vconfig, mctx,
557 list_zones);
558 if (tresult != ISC_R_SUCCESS) {
559 result = tresult;
560 }
561 }
562
563 if (views == NULL) {
564 tresult = configure_view("IN", "_default", config, NULL, mctx,
565 list_zones);
566 if (tresult != ISC_R_SUCCESS) {
567 result = tresult;
568 }
569 }
570
571 cleanup:
572 return (result);
573 }
574
575 static void
576 output(void *closure, const char *text, int textlen) {
577 UNUSED(closure);
578 if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) {
579 perror("fwrite");
580 exit(1);
581 }
582 }
583
584 /*% The main processing routine */
585 int
586 main(int argc, char **argv) {
587 int c;
588 cfg_parser_t *parser = NULL;
589 cfg_obj_t *config = NULL;
590 const char *conffile = NULL;
591 isc_mem_t *mctx = NULL;
592 isc_result_t result;
593 int exit_status = 0;
594 bool load_zones = false;
595 bool list_zones = false;
596 bool print = false;
597 bool nodeprecate = false;
598 unsigned int flags = 0;
599
600 isc_commandline_errprint = false;
601
602 /*
603 * Process memory debugging argument first.
604 */
605 #define CMDLINE_FLAGS "cdhijlm:t:pvxz"
606 while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
607 switch (c) {
608 case 'm':
609 if (strcasecmp(isc_commandline_argument, "record") == 0)
610 {
611 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
612 }
613 if (strcasecmp(isc_commandline_argument, "trace") == 0)
614 {
615 isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
616 }
617 if (strcasecmp(isc_commandline_argument, "usage") == 0)
618 {
619 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
620 }
621 if (strcasecmp(isc_commandline_argument, "size") == 0) {
622 isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
623 }
624 if (strcasecmp(isc_commandline_argument, "mctx") == 0) {
625 isc_mem_debugging |= ISC_MEM_DEBUGCTX;
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 'c':
639 loadplugins = false;
640 break;
641
642 case 'd':
643 debug++;
644 break;
645
646 case 'i':
647 nodeprecate = true;
648 break;
649
650 case 'j':
651 nomerge = false;
652 break;
653
654 case 'l':
655 list_zones = true;
656 break;
657
658 case 'm':
659 break;
660
661 case 't':
662 result = isc_dir_chroot(isc_commandline_argument);
663 if (result != ISC_R_SUCCESS) {
664 fprintf(stderr, "isc_dir_chroot: %s\n",
665 isc_result_totext(result));
666 exit(1);
667 }
668 break;
669
670 case 'p':
671 print = true;
672 break;
673
674 case 'v':
675 printf(VERSION "\n");
676 exit(0);
677
678 case 'x':
679 flags |= CFG_PRINTER_XKEY;
680 break;
681
682 case 'z':
683 load_zones = true;
684 docheckmx = false;
685 docheckns = false;
686 dochecksrv = false;
687 break;
688
689 case '?':
690 if (isc_commandline_option != '?') {
691 fprintf(stderr, "%s: invalid argument -%c\n",
692 program, isc_commandline_option);
693 }
694 FALLTHROUGH;
695 case 'h':
696 usage();
697
698 default:
699 fprintf(stderr, "%s: unhandled option -%c\n", program,
700 isc_commandline_option);
701 exit(1);
702 }
703 }
704
705 if (((flags & CFG_PRINTER_XKEY) != 0) && !print) {
706 fprintf(stderr, "%s: -x cannot be used without -p\n", program);
707 exit(1);
708 }
709 if (print && list_zones) {
710 fprintf(stderr, "%s: -l cannot be used with -p\n", program);
711 exit(1);
712 }
713
714 if (isc_commandline_index + 1 < argc) {
715 usage();
716 }
717 if (argv[isc_commandline_index] != NULL) {
718 conffile = argv[isc_commandline_index];
719 }
720 if (conffile == NULL || conffile[0] == '\0') {
721 conffile = NAMED_CONFFILE;
722 }
723
724 #ifdef _WIN32
725 InitSockets();
726 #endif /* ifdef _WIN32 */
727
728 RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
729
730 dns_result_register();
731
732 RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
733
734 if (nodeprecate) {
735 cfg_parser_setflags(parser, CFG_PCTX_NODEPRECATED, true);
736 }
737 cfg_parser_setcallback(parser, directory_callback, NULL);
738
739 if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
740 ISC_R_SUCCESS)
741 {
742 exit(1);
743 }
744
745 result = bind9_check_namedconf(config, loadplugins, logc, mctx);
746 if (result != ISC_R_SUCCESS) {
747 exit_status = 1;
748 }
749
750 if (result == ISC_R_SUCCESS && (load_zones || list_zones)) {
751 result = load_zones_fromconfig(config, mctx, list_zones);
752 if (result != ISC_R_SUCCESS) {
753 exit_status = 1;
754 }
755 }
756
757 if (print && exit_status == 0) {
758 cfg_printx(config, flags, output, NULL);
759 }
760 cfg_obj_destroy(parser, &config);
761
762 cfg_parser_destroy(&parser);
763
764 isc_log_destroy(&logc);
765
766 isc_mem_destroy(&mctx);
767
768 #ifdef _WIN32
769 DestroySockets();
770 #endif /* ifdef _WIN32 */
771
772 return (exit_status);
773 }
774