named-checkconf.c revision 1.1.1.4 1 /* $NetBSD: named-checkconf.c,v 1.1.1.4 2020/05/24 19:36:29 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14 /*! \file */
15
16 #include <errno.h>
17 #include <stdbool.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20
21 #include <isc/commandline.h>
22 #include <isc/dir.h>
23 #include <isc/hash.h>
24 #include <isc/log.h>
25 #include <isc/mem.h>
26 #include <isc/print.h>
27 #include <isc/result.h>
28 #include <isc/string.h>
29 #include <isc/util.h>
30
31 #include <dns/db.h>
32 #include <dns/fixedname.h>
33 #include <dns/log.h>
34 #include <dns/name.h>
35 #include <dns/rdataclass.h>
36 #include <dns/result.h>
37 #include <dns/rootns.h>
38 #include <dns/zone.h>
39
40 #include <isccfg/grammar.h>
41 #include <isccfg/namedconf.h>
42
43 #include <bind9/check.h>
44
45 #include "check-tool.h"
46
47 static const char *program = "named-checkconf";
48
49 static bool loadplugins = true;
50
51 isc_log_t *logc = NULL;
52
53 #define CHECK(r) \
54 do { \
55 result = (r); \
56 if (result != ISC_R_SUCCESS) \
57 goto cleanup; \
58 } while (0)
59
60 /*% usage */
61 ISC_PLATFORM_NORETURN_PRE static void
62 usage(void) ISC_PLATFORM_NORETURN_POST;
63
64 static void
65 usage(void) {
66 fprintf(stderr,
67 "usage: %s [-chijlvz] [-p [-x]] [-t directory] "
68 "[named.conf]\n",
69 program);
70 exit(1);
71 }
72
73 /*% directory callback */
74 static isc_result_t
75 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
76 isc_result_t result;
77 const char *directory;
78
79 REQUIRE(strcasecmp("directory", clausename) == 0);
80
81 UNUSED(arg);
82 UNUSED(clausename);
83
84 /*
85 * Change directory.
86 */
87 directory = cfg_obj_asstring(obj);
88 result = isc_dir_chdir(directory);
89 if (result != ISC_R_SUCCESS) {
90 cfg_obj_log(obj, logc, ISC_LOG_ERROR,
91 "change directory to '%s' failed: %s\n", directory,
92 isc_result_totext(result));
93 return (result);
94 }
95
96 return (ISC_R_SUCCESS);
97 }
98
99 static bool
100 get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
101 int i;
102 for (i = 0;; i++) {
103 if (maps[i] == NULL) {
104 return (false);
105 }
106 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) {
107 return (true);
108 }
109 }
110 }
111
112 static bool
113 get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) {
114 const cfg_listelt_t *element;
115 const cfg_obj_t *checknames;
116 const cfg_obj_t *type;
117 const cfg_obj_t *value;
118 isc_result_t result;
119 int i;
120
121 for (i = 0;; i++) {
122 if (maps[i] == NULL) {
123 return (false);
124 }
125 checknames = NULL;
126 result = cfg_map_get(maps[i], "check-names", &checknames);
127 if (result != ISC_R_SUCCESS) {
128 continue;
129 }
130 if (checknames != NULL && !cfg_obj_islist(checknames)) {
131 *obj = checknames;
132 return (true);
133 }
134 for (element = cfg_list_first(checknames); element != NULL;
135 element = cfg_list_next(element))
136 {
137 value = cfg_listelt_value(element);
138 type = cfg_tuple_get(value, "type");
139 if ((strcasecmp(cfg_obj_asstring(type), "primary") !=
140 0) &&
141 (strcasecmp(cfg_obj_asstring(type), "master") != 0))
142 {
143 continue;
144 }
145 *obj = cfg_tuple_get(value, "mode");
146 return (true);
147 }
148 }
149 }
150
151 static isc_result_t
152 configure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) {
153 isc_result_t result;
154 dns_db_t *db = NULL;
155 dns_rdataclass_t rdclass;
156 isc_textregion_t r;
157
158 if (zfile == NULL) {
159 return (ISC_R_FAILURE);
160 }
161
162 DE_CONST(zclass, r.base);
163 r.length = strlen(zclass);
164 result = dns_rdataclass_fromtext(&rdclass, &r);
165 if (result != ISC_R_SUCCESS) {
166 return (result);
167 }
168
169 result = dns_rootns_create(mctx, rdclass, zfile, &db);
170 if (result != ISC_R_SUCCESS) {
171 return (result);
172 }
173
174 dns_db_detach(&db);
175 return (ISC_R_SUCCESS);
176 }
177
178 /*% configure the zone */
179 static isc_result_t
180 configure_zone(const char *vclass, const char *view, const cfg_obj_t *zconfig,
181 const cfg_obj_t *vconfig, const cfg_obj_t *config,
182 isc_mem_t *mctx, bool list) {
183 int i = 0;
184 isc_result_t result;
185 const char *zclass;
186 const char *zname;
187 const char *zfile = NULL;
188 const cfg_obj_t *maps[4];
189 const cfg_obj_t *mastersobj = NULL;
190 const cfg_obj_t *inviewobj = NULL;
191 const cfg_obj_t *zoptions = NULL;
192 const cfg_obj_t *classobj = NULL;
193 const cfg_obj_t *typeobj = NULL;
194 const cfg_obj_t *fileobj = NULL;
195 const cfg_obj_t *dlzobj = NULL;
196 const cfg_obj_t *dbobj = NULL;
197 const cfg_obj_t *obj = NULL;
198 const cfg_obj_t *fmtobj = NULL;
199 dns_masterformat_t masterformat;
200 dns_ttl_t maxttl = 0;
201
202 zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;
203
204 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
205 classobj = cfg_tuple_get(zconfig, "class");
206 if (!cfg_obj_isstring(classobj)) {
207 zclass = vclass;
208 } else {
209 zclass = cfg_obj_asstring(classobj);
210 }
211
212 zoptions = cfg_tuple_get(zconfig, "options");
213 maps[i++] = zoptions;
214 if (vconfig != NULL) {
215 maps[i++] = cfg_tuple_get(vconfig, "options");
216 }
217 if (config != NULL) {
218 cfg_map_get(config, "options", &obj);
219 if (obj != NULL) {
220 maps[i++] = obj;
221 }
222 }
223 maps[i] = NULL;
224
225 cfg_map_get(zoptions, "in-view", &inviewobj);
226 if (inviewobj != NULL && list) {
227 const char *inview = cfg_obj_asstring(inviewobj);
228 printf("%s %s %s in-view %s\n", zname, zclass, view, inview);
229 }
230 if (inviewobj != NULL) {
231 return (ISC_R_SUCCESS);
232 }
233
234 cfg_map_get(zoptions, "type", &typeobj);
235 if (typeobj == NULL) {
236 return (ISC_R_FAILURE);
237 }
238
239 if (list) {
240 const char *ztype = cfg_obj_asstring(typeobj);
241 printf("%s %s %s %s\n", zname, zclass, view, ztype);
242 return (ISC_R_SUCCESS);
243 }
244
245 /*
246 * Skip checks when using an alternate data source.
247 */
248 cfg_map_get(zoptions, "database", &dbobj);
249 if (dbobj != NULL && strcmp("rbt", cfg_obj_asstring(dbobj)) != 0 &&
250 strcmp("rbt64", cfg_obj_asstring(dbobj)) != 0)
251 {
252 return (ISC_R_SUCCESS);
253 }
254
255 cfg_map_get(zoptions, "dlz", &dlzobj);
256 if (dlzobj != NULL) {
257 return (ISC_R_SUCCESS);
258 }
259
260 cfg_map_get(zoptions, "file", &fileobj);
261 if (fileobj != NULL) {
262 zfile = cfg_obj_asstring(fileobj);
263 }
264
265 /*
266 * Check hints files for hint zones.
267 * Skip loading checks for any type other than
268 * master and redirect
269 */
270 if (strcasecmp(cfg_obj_asstring(typeobj), "hint") == 0) {
271 return (configure_hint(zfile, zclass, mctx));
272 } else if ((strcasecmp(cfg_obj_asstring(typeobj), "primary") != 0) &&
273 (strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) &&
274 (strcasecmp(cfg_obj_asstring(typeobj), "redirect") != 0))
275 {
276 return (ISC_R_SUCCESS);
277 }
278
279 /*
280 * Is the redirect zone configured as a slave?
281 */
282 if (strcasecmp(cfg_obj_asstring(typeobj), "redirect") == 0) {
283 cfg_map_get(zoptions, "masters", &mastersobj);
284 if (mastersobj != NULL) {
285 return (ISC_R_SUCCESS);
286 }
287 }
288
289 if (zfile == NULL) {
290 return (ISC_R_FAILURE);
291 }
292
293 obj = NULL;
294 if (get_maps(maps, "check-dup-records", &obj)) {
295 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
296 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
297 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
298 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
299 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
300 zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL;
301 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
302 zone_options &= ~DNS_ZONEOPT_CHECKDUPRR;
303 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
304 } else {
305 INSIST(0);
306 ISC_UNREACHABLE();
307 }
308 } else {
309 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
310 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
311 }
312
313 obj = NULL;
314 if (get_maps(maps, "check-mx", &obj)) {
315 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
316 zone_options |= DNS_ZONEOPT_CHECKMX;
317 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
318 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
319 zone_options |= DNS_ZONEOPT_CHECKMX;
320 zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
321 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
322 zone_options &= ~DNS_ZONEOPT_CHECKMX;
323 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
324 } else {
325 INSIST(0);
326 ISC_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 INSIST(0);
357 ISC_UNREACHABLE();
358 }
359 } else {
360 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
361 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
362 }
363
364 obj = NULL;
365 if (get_maps(maps, "check-srv-cname", &obj)) {
366 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
367 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
368 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
369 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
370 zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
371 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
372 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
373 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
374 zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
375 } else {
376 INSIST(0);
377 ISC_UNREACHABLE();
378 }
379 } else {
380 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
381 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
382 }
383
384 obj = NULL;
385 if (get_maps(maps, "check-sibling", &obj)) {
386 if (cfg_obj_asboolean(obj)) {
387 zone_options |= DNS_ZONEOPT_CHECKSIBLING;
388 } else {
389 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
390 }
391 }
392
393 obj = NULL;
394 if (get_maps(maps, "check-spf", &obj)) {
395 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
396 zone_options |= DNS_ZONEOPT_CHECKSPF;
397 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
398 zone_options &= ~DNS_ZONEOPT_CHECKSPF;
399 } else {
400 INSIST(0);
401 ISC_UNREACHABLE();
402 }
403 } else {
404 zone_options |= DNS_ZONEOPT_CHECKSPF;
405 }
406
407 obj = NULL;
408 if (get_checknames(maps, &obj)) {
409 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
410 zone_options |= DNS_ZONEOPT_CHECKNAMES;
411 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
412 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
413 zone_options |= DNS_ZONEOPT_CHECKNAMES;
414 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
415 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
416 zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
417 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
418 } else {
419 INSIST(0);
420 ISC_UNREACHABLE();
421 }
422 } else {
423 zone_options |= DNS_ZONEOPT_CHECKNAMES;
424 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
425 }
426
427 masterformat = dns_masterformat_text;
428 fmtobj = NULL;
429 if (get_maps(maps, "masterfile-format", &fmtobj)) {
430 const char *masterformatstr = cfg_obj_asstring(fmtobj);
431 if (strcasecmp(masterformatstr, "text") == 0) {
432 masterformat = dns_masterformat_text;
433 } else if (strcasecmp(masterformatstr, "raw") == 0) {
434 masterformat = dns_masterformat_raw;
435 } else if (strcasecmp(masterformatstr, "map") == 0) {
436 masterformat = dns_masterformat_map;
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 dns_result_totext(result));
454 }
455 return (result);
456 }
457
458 /*% configure a view */
459 static isc_result_t
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
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
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
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
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 if (strcasecmp(isc_commandline_argument, "size") == 0) {
612 isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
613 }
614 if (strcasecmp(isc_commandline_argument, "mctx") == 0) {
615 isc_mem_debugging |= ISC_MEM_DEBUGCTX;
616 }
617 break;
618 default:
619 break;
620 }
621 }
622 isc_commandline_reset = true;
623
624 isc_mem_create(&mctx);
625
626 while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) {
627 switch (c) {
628 case 'c':
629 loadplugins = false;
630 break;
631
632 case 'd':
633 debug++;
634 break;
635
636 case 'i':
637 nodeprecate = true;
638 break;
639
640 case 'j':
641 nomerge = false;
642 break;
643
644 case 'l':
645 list_zones = true;
646 break;
647
648 case 'm':
649 break;
650
651 case 't':
652 result = isc_dir_chroot(isc_commandline_argument);
653 if (result != ISC_R_SUCCESS) {
654 fprintf(stderr, "isc_dir_chroot: %s\n",
655 isc_result_totext(result));
656 exit(1);
657 }
658 break;
659
660 case 'p':
661 print = true;
662 break;
663
664 case 'v':
665 printf(VERSION "\n");
666 exit(0);
667
668 case 'x':
669 flags |= CFG_PRINTER_XKEY;
670 break;
671
672 case 'z':
673 load_zones = true;
674 docheckmx = false;
675 docheckns = false;
676 dochecksrv = false;
677 break;
678
679 case '?':
680 if (isc_commandline_option != '?') {
681 fprintf(stderr, "%s: invalid argument -%c\n",
682 program, isc_commandline_option);
683 }
684 /* FALLTHROUGH */
685 case 'h':
686 usage();
687
688 default:
689 fprintf(stderr, "%s: unhandled option -%c\n", program,
690 isc_commandline_option);
691 exit(1);
692 }
693 }
694
695 if (((flags & CFG_PRINTER_XKEY) != 0) && !print) {
696 fprintf(stderr, "%s: -x cannot be used without -p\n", program);
697 exit(1);
698 }
699 if (print && list_zones) {
700 fprintf(stderr, "%s: -l cannot be used with -p\n", program);
701 exit(1);
702 }
703
704 if (isc_commandline_index + 1 < argc) {
705 usage();
706 }
707 if (argv[isc_commandline_index] != NULL) {
708 conffile = argv[isc_commandline_index];
709 }
710 if (conffile == NULL || conffile[0] == '\0') {
711 conffile = NAMED_CONFFILE;
712 }
713
714 #ifdef _WIN32
715 InitSockets();
716 #endif /* ifdef _WIN32 */
717
718 RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
719
720 dns_result_register();
721
722 RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
723
724 if (nodeprecate) {
725 cfg_parser_setflags(parser, CFG_PCTX_NODEPRECATED, true);
726 }
727 cfg_parser_setcallback(parser, directory_callback, NULL);
728
729 if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
730 ISC_R_SUCCESS)
731 {
732 exit(1);
733 }
734
735 result = bind9_check_namedconf(config, loadplugins, logc, mctx);
736 if (result != ISC_R_SUCCESS) {
737 exit_status = 1;
738 }
739
740 if (result == ISC_R_SUCCESS && (load_zones || list_zones)) {
741 result = load_zones_fromconfig(config, mctx, list_zones);
742 if (result != ISC_R_SUCCESS) {
743 exit_status = 1;
744 }
745 }
746
747 if (print && exit_status == 0) {
748 cfg_printx(config, flags, output, NULL);
749 }
750 cfg_obj_destroy(parser, &config);
751
752 cfg_parser_destroy(&parser);
753
754 isc_log_destroy(&logc);
755
756 isc_mem_destroy(&mctx);
757
758 #ifdef _WIN32
759 DestroySockets();
760 #endif /* ifdef _WIN32 */
761
762 return (exit_status);
763 }
764