1 /* $NetBSD: named-checkconf.c,v 1.11 2015/07/08 17:28:54 christos Exp $ */
4 * Copyright (C) 2004-2007, 2009-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: named-checkconf.c,v 1.56 2011/03/12 04:59:46 tbox Exp */
30 #include <isc/commandline.h>
32 #include <isc/entropy.h>
36 #include <isc/result.h>
37 #include <isc/string.h>
40 #include <isccfg/namedconf.h>
42 #include <bind9/check.h>
45 #include <dns/fixedname.h>
48 #include <dns/rdataclass.h>
49 #include <dns/result.h>
50 #include <dns/rootns.h>
53 #include "check-tool.h"
55 static const char *program
= "named-checkconf";
57 isc_log_t
*logc
= NULL
;
62 if (result != ISC_R_SUCCESS) \
64 } while (/*CONSTCOND*/0)
67 ISC_PLATFORM_NORETURN_PRE
static void
68 usage(void) ISC_PLATFORM_NORETURN_POST
;
72 fprintf(stderr
, "usage: %s [-h] [-j] [-p] [-v] [-z] [-t directory] "
73 "[named.conf]\n", program
);
77 /*% directory callback */
79 directory_callback(const char *clausename
, const cfg_obj_t
*obj
, void *arg
) {
81 const char *directory
;
83 REQUIRE(strcasecmp("directory", clausename
) == 0);
91 directory
= cfg_obj_asstring(obj
);
92 result
= isc_dir_chdir(directory
);
93 if (result
!= ISC_R_SUCCESS
) {
94 cfg_obj_log(obj
, logc
, ISC_LOG_ERROR
,
95 "change directory to '%s' failed: %s\n",
96 directory
, isc_result_totext(result
));
100 return (ISC_R_SUCCESS
);
104 get_maps(const cfg_obj_t
**maps
, const char *name
, const cfg_obj_t
**obj
) {
109 if (cfg_map_get(maps
[i
], name
, obj
) == ISC_R_SUCCESS
)
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
;
127 result
= cfg_map_get(maps
[i
], "check-names", &checknames
);
128 if (result
!= ISC_R_SUCCESS
)
130 if (checknames
!= NULL
&& !cfg_obj_islist(checknames
)) {
134 for (element
= cfg_list_first(checknames
);
136 element
= cfg_list_next(element
)) {
137 value
= cfg_listelt_value(element
);
138 type
= cfg_tuple_get(value
, "type");
139 if (strcasecmp(cfg_obj_asstring(type
), "master") != 0)
141 *obj
= cfg_tuple_get(value
, "mode");
148 configure_hint(const char *zfile
, const char *zclass
, isc_mem_t
*mctx
) {
151 dns_rdataclass_t rdclass
;
155 return (ISC_R_FAILURE
);
157 DE_CONST(zclass
, r
.base
);
158 r
.length
= strlen(zclass
);
159 result
= dns_rdataclass_fromtext(&rdclass
, &r
);
160 if (result
!= ISC_R_SUCCESS
)
163 result
= dns_rootns_create(mctx
, rdclass
, zfile
, &db
);
164 if (result
!= ISC_R_SUCCESS
)
168 return (ISC_R_SUCCESS
);
171 /*% configure the zone */
173 configure_zone(const char *vclass
, const char *view
,
174 const cfg_obj_t
*zconfig
, const cfg_obj_t
*vconfig
,
175 const cfg_obj_t
*config
, isc_mem_t
*mctx
)
181 const char *zfile
= NULL
;
182 const cfg_obj_t
*maps
[4];
183 const cfg_obj_t
*mastersobj
= NULL
;
184 const cfg_obj_t
*zoptions
= NULL
;
185 const cfg_obj_t
*classobj
= NULL
;
186 const cfg_obj_t
*typeobj
= NULL
;
187 const cfg_obj_t
*fileobj
= NULL
;
188 const cfg_obj_t
*dlzobj
= NULL
;
189 const cfg_obj_t
*dbobj
= NULL
;
190 const cfg_obj_t
*obj
= NULL
;
191 const cfg_obj_t
*fmtobj
= NULL
;
192 dns_masterformat_t masterformat
;
193 dns_ttl_t maxttl
= 0;
195 zone_options
= DNS_ZONEOPT_CHECKNS
| DNS_ZONEOPT_MANYERRORS
;
197 zname
= cfg_obj_asstring(cfg_tuple_get(zconfig
, "name"));
198 classobj
= cfg_tuple_get(zconfig
, "class");
199 if (!cfg_obj_isstring(classobj
))
202 zclass
= cfg_obj_asstring(classobj
);
204 zoptions
= cfg_tuple_get(zconfig
, "options");
205 maps
[i
++] = zoptions
;
207 maps
[i
++] = cfg_tuple_get(vconfig
, "options");
208 if (config
!= NULL
) {
209 cfg_map_get(config
, "options", &obj
);
215 cfg_map_get(zoptions
, "type", &typeobj
);
217 return (ISC_R_FAILURE
);
220 * Skip checks when using an alternate data source.
222 cfg_map_get(zoptions
, "database", &dbobj
);
224 strcmp("rbt", cfg_obj_asstring(dbobj
)) != 0 &&
225 strcmp("rbt64", cfg_obj_asstring(dbobj
)) != 0)
226 return (ISC_R_SUCCESS
);
228 cfg_map_get(zoptions
, "dlz", &dlzobj
);
230 return (ISC_R_SUCCESS
);
232 cfg_map_get(zoptions
, "file", &fileobj
);
234 zfile
= cfg_obj_asstring(fileobj
);
237 * Check hints files for hint zones.
238 * Skip loading checks for any type other than
239 * master and redirect
241 if (strcasecmp(cfg_obj_asstring(typeobj
), "hint") == 0)
242 return (configure_hint(zfile
, zclass
, mctx
));
243 else if ((strcasecmp(cfg_obj_asstring(typeobj
), "master") != 0) &&
244 (strcasecmp(cfg_obj_asstring(typeobj
), "redirect") != 0))
245 return (ISC_R_SUCCESS
);
248 * Is the redirect zone configured as a slave?
250 if (strcasecmp(cfg_obj_asstring(typeobj
), "redirect") == 0) {
251 cfg_map_get(zoptions
, "masters", &mastersobj
);
252 if (mastersobj
!= NULL
)
253 return (ISC_R_SUCCESS
);
257 return (ISC_R_FAILURE
);
260 if (get_maps(maps
, "check-dup-records", &obj
)) {
261 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
262 zone_options
|= DNS_ZONEOPT_CHECKDUPRR
;
263 zone_options
&= ~DNS_ZONEOPT_CHECKDUPRRFAIL
;
264 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
265 zone_options
|= DNS_ZONEOPT_CHECKDUPRR
;
266 zone_options
|= DNS_ZONEOPT_CHECKDUPRRFAIL
;
267 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
268 zone_options
&= ~DNS_ZONEOPT_CHECKDUPRR
;
269 zone_options
&= ~DNS_ZONEOPT_CHECKDUPRRFAIL
;
273 zone_options
|= DNS_ZONEOPT_CHECKDUPRR
;
274 zone_options
&= ~DNS_ZONEOPT_CHECKDUPRRFAIL
;
278 if (get_maps(maps
, "check-mx", &obj
)) {
279 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
280 zone_options
|= DNS_ZONEOPT_CHECKMX
;
281 zone_options
&= ~DNS_ZONEOPT_CHECKMXFAIL
;
282 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
283 zone_options
|= DNS_ZONEOPT_CHECKMX
;
284 zone_options
|= DNS_ZONEOPT_CHECKMXFAIL
;
285 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
286 zone_options
&= ~DNS_ZONEOPT_CHECKMX
;
287 zone_options
&= ~DNS_ZONEOPT_CHECKMXFAIL
;
291 zone_options
|= DNS_ZONEOPT_CHECKMX
;
292 zone_options
&= ~DNS_ZONEOPT_CHECKMXFAIL
;
296 if (get_maps(maps
, "check-integrity", &obj
)) {
297 if (cfg_obj_asboolean(obj
))
298 zone_options
|= DNS_ZONEOPT_CHECKINTEGRITY
;
300 zone_options
&= ~DNS_ZONEOPT_CHECKINTEGRITY
;
302 zone_options
|= DNS_ZONEOPT_CHECKINTEGRITY
;
305 if (get_maps(maps
, "check-mx-cname", &obj
)) {
306 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
307 zone_options
|= DNS_ZONEOPT_WARNMXCNAME
;
308 zone_options
&= ~DNS_ZONEOPT_IGNOREMXCNAME
;
309 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
310 zone_options
&= ~DNS_ZONEOPT_WARNMXCNAME
;
311 zone_options
&= ~DNS_ZONEOPT_IGNOREMXCNAME
;
312 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
313 zone_options
|= DNS_ZONEOPT_WARNMXCNAME
;
314 zone_options
|= DNS_ZONEOPT_IGNOREMXCNAME
;
318 zone_options
|= DNS_ZONEOPT_WARNMXCNAME
;
319 zone_options
&= ~DNS_ZONEOPT_IGNOREMXCNAME
;
323 if (get_maps(maps
, "check-srv-cname", &obj
)) {
324 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
325 zone_options
|= DNS_ZONEOPT_WARNSRVCNAME
;
326 zone_options
&= ~DNS_ZONEOPT_IGNORESRVCNAME
;
327 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
328 zone_options
&= ~DNS_ZONEOPT_WARNSRVCNAME
;
329 zone_options
&= ~DNS_ZONEOPT_IGNORESRVCNAME
;
330 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
331 zone_options
|= DNS_ZONEOPT_WARNSRVCNAME
;
332 zone_options
|= DNS_ZONEOPT_IGNORESRVCNAME
;
336 zone_options
|= DNS_ZONEOPT_WARNSRVCNAME
;
337 zone_options
&= ~DNS_ZONEOPT_IGNORESRVCNAME
;
341 if (get_maps(maps
, "check-sibling", &obj
)) {
342 if (cfg_obj_asboolean(obj
))
343 zone_options
|= DNS_ZONEOPT_CHECKSIBLING
;
345 zone_options
&= ~DNS_ZONEOPT_CHECKSIBLING
;
349 if (get_maps(maps
, "check-spf", &obj
)) {
350 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
351 zone_options
|= DNS_ZONEOPT_CHECKSPF
;
352 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
353 zone_options
&= ~DNS_ZONEOPT_CHECKSPF
;
357 zone_options
|= DNS_ZONEOPT_CHECKSPF
;
361 if (get_checknames(maps
, &obj
)) {
362 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
363 zone_options
|= DNS_ZONEOPT_CHECKNAMES
;
364 zone_options
&= ~DNS_ZONEOPT_CHECKNAMESFAIL
;
365 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
366 zone_options
|= DNS_ZONEOPT_CHECKNAMES
;
367 zone_options
|= DNS_ZONEOPT_CHECKNAMESFAIL
;
368 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
369 zone_options
&= ~DNS_ZONEOPT_CHECKNAMES
;
370 zone_options
&= ~DNS_ZONEOPT_CHECKNAMESFAIL
;
374 zone_options
|= DNS_ZONEOPT_CHECKNAMES
;
375 zone_options
|= DNS_ZONEOPT_CHECKNAMESFAIL
;
378 masterformat
= dns_masterformat_text
;
380 if (get_maps(maps
, "masterfile-format", &fmtobj
)) {
381 const char *masterformatstr
= cfg_obj_asstring(fmtobj
);
382 if (strcasecmp(masterformatstr
, "text") == 0)
383 masterformat
= dns_masterformat_text
;
384 else if (strcasecmp(masterformatstr
, "raw") == 0)
385 masterformat
= dns_masterformat_raw
;
386 else if (strcasecmp(masterformatstr
, "map") == 0)
387 masterformat
= dns_masterformat_map
;
393 if (get_maps(maps
, "max-zone-ttl", &obj
)) {
394 maxttl
= cfg_obj_asuint32(obj
);
395 zone_options2
|= DNS_ZONEOPT2_CHECKTTL
;
398 result
= load_zone(mctx
, zname
, zfile
, masterformat
,
399 zclass
, maxttl
, NULL
);
400 if (result
!= ISC_R_SUCCESS
)
401 fprintf(stderr
, "%s/%s/%s: %s\n", view
, zname
, zclass
,
402 dns_result_totext(result
));
406 /*% configure a view */
408 configure_view(const char *vclass
, const char *view
, const cfg_obj_t
*config
,
409 const cfg_obj_t
*vconfig
, isc_mem_t
*mctx
)
411 const cfg_listelt_t
*element
;
412 const cfg_obj_t
*voptions
;
413 const cfg_obj_t
*zonelist
;
414 isc_result_t result
= ISC_R_SUCCESS
;
415 isc_result_t tresult
;
419 voptions
= cfg_tuple_get(vconfig
, "options");
422 if (voptions
!= NULL
)
423 (void)cfg_map_get(voptions
, "zone", &zonelist
);
425 (void)cfg_map_get(config
, "zone", &zonelist
);
427 for (element
= cfg_list_first(zonelist
);
429 element
= cfg_list_next(element
))
431 const cfg_obj_t
*zconfig
= cfg_listelt_value(element
);
432 tresult
= configure_zone(vclass
, view
, zconfig
, vconfig
,
434 if (tresult
!= ISC_R_SUCCESS
)
441 /*% load zones from the configuration */
443 load_zones_fromconfig(const cfg_obj_t
*config
, isc_mem_t
*mctx
) {
444 const cfg_listelt_t
*element
;
445 const cfg_obj_t
*classobj
;
446 const cfg_obj_t
*views
;
447 const cfg_obj_t
*vconfig
;
449 isc_result_t result
= ISC_R_SUCCESS
;
450 isc_result_t tresult
;
454 (void)cfg_map_get(config
, "view", &views
);
455 for (element
= cfg_list_first(views
);
457 element
= cfg_list_next(element
))
462 vconfig
= cfg_listelt_value(element
);
463 if (vconfig
!= NULL
) {
464 classobj
= cfg_tuple_get(vconfig
, "class");
465 if (cfg_obj_isstring(classobj
))
466 vclass
= cfg_obj_asstring(classobj
);
468 vname
= cfg_obj_asstring(cfg_tuple_get(vconfig
, "name"));
469 tresult
= configure_view(vclass
, vname
, config
, vconfig
, mctx
);
470 if (tresult
!= ISC_R_SUCCESS
)
475 tresult
= configure_view("IN", "_default", config
, NULL
, mctx
);
476 if (tresult
!= ISC_R_SUCCESS
)
483 output(void *closure
, const char *text
, int textlen
) {
485 if (fwrite(text
, 1, textlen
, stdout
) != (size_t)textlen
) {
491 /*% The main processing routine */
493 main(int argc
, char **argv
) {
495 cfg_parser_t
*parser
= NULL
;
496 cfg_obj_t
*config
= NULL
;
497 const char *conffile
= NULL
;
498 isc_mem_t
*mctx
= NULL
;
501 isc_entropy_t
*ectx
= NULL
;
502 isc_boolean_t load_zones
= ISC_FALSE
;
503 isc_boolean_t print
= ISC_FALSE
;
504 unsigned int flags
= 0;
507 isc_commandline_errprint
= ISC_FALSE
;
510 * Process memory debugging argument first.
512 #define CMDLINE_FLAGS "dhjm:t:pvxz"
513 while ((c
= isc_commandline_parse(argc
, argv
, CMDLINE_FLAGS
)) != -1) {
516 if (strcasecmp(isc_commandline_argument
, "record") == 0)
517 isc_mem_debugging
|= ISC_MEM_DEBUGRECORD
;
518 if (strcasecmp(isc_commandline_argument
, "trace") == 0)
519 isc_mem_debugging
|= ISC_MEM_DEBUGTRACE
;
520 if (strcasecmp(isc_commandline_argument
, "usage") == 0)
521 isc_mem_debugging
|= ISC_MEM_DEBUGUSAGE
;
522 if (strcasecmp(isc_commandline_argument
, "size") == 0)
523 isc_mem_debugging
|= ISC_MEM_DEBUGSIZE
;
524 if (strcasecmp(isc_commandline_argument
, "mctx") == 0)
525 isc_mem_debugging
|= ISC_MEM_DEBUGCTX
;
531 isc_commandline_reset
= ISC_TRUE
;
533 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx
) == ISC_R_SUCCESS
);
535 while ((c
= isc_commandline_parse(argc
, argv
, CMDLINE_FLAGS
)) != EOF
) {
549 result
= isc_dir_chroot(isc_commandline_argument
);
550 if (result
!= ISC_R_SUCCESS
) {
551 fprintf(stderr
, "isc_dir_chroot: %s\n",
552 isc_result_totext(result
));
562 printf(VERSION
"\n");
566 flags
|= CFG_PRINTER_XKEY
;
570 load_zones
= ISC_TRUE
;
571 docheckmx
= ISC_FALSE
;
572 docheckns
= ISC_FALSE
;
573 dochecksrv
= ISC_FALSE
;
577 if (isc_commandline_option
!= '?')
578 fprintf(stderr
, "%s: invalid argument -%c\n",
579 program
, isc_commandline_option
);
585 fprintf(stderr
, "%s: unhandled option -%c\n",
586 program
, isc_commandline_option
);
591 if (((flags
& CFG_PRINTER_XKEY
) != 0) && !print
) {
592 fprintf(stderr
, "%s: -x cannot be used without -p\n", program
);
596 if (isc_commandline_index
+ 1 < argc
)
598 if (argv
[isc_commandline_index
] != NULL
)
599 conffile
= argv
[isc_commandline_index
];
600 if (conffile
== NULL
|| conffile
[0] == '\0')
601 conffile
= NAMED_CONFFILE
;
607 RUNTIME_CHECK(setup_logging(mctx
, stdout
, &logc
) == ISC_R_SUCCESS
);
609 RUNTIME_CHECK(isc_entropy_create(mctx
, &ectx
) == ISC_R_SUCCESS
);
610 RUNTIME_CHECK(isc_hash_create(mctx
, ectx
, DNS_NAME_MAXWIRE
)
613 dns_result_register();
615 RUNTIME_CHECK(cfg_parser_create(mctx
, logc
, &parser
) == ISC_R_SUCCESS
);
617 cfg_parser_setcallback(parser
, directory_callback
, NULL
);
619 if (cfg_parse_file(parser
, conffile
, &cfg_type_namedconf
, &config
) !=
623 result
= bind9_check_namedconf(config
, logc
, mctx
);
624 if (result
!= ISC_R_SUCCESS
)
627 if (result
== ISC_R_SUCCESS
&& load_zones
) {
628 result
= load_zones_fromconfig(config
, mctx
);
629 if (result
!= ISC_R_SUCCESS
)
633 if (print
&& exit_status
== 0)
634 cfg_printx(config
, flags
, output
, NULL
);
635 cfg_obj_destroy(parser
, &config
);
637 cfg_parser_destroy(&parser
);
641 isc_log_destroy(&logc
);
644 isc_entropy_detach(&ectx
);
646 isc_mem_destroy(&mctx
);
652 return (exit_status
);