4 * Copyright (C) 2004-2007, 2009 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.51 2009/12/04 21:09:32 marka 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>
44 #include <dns/fixedname.h>
47 #include <dns/result.h>
50 #include "check-tool.h"
52 static const char *program
= "named-checkconf";
54 isc_log_t
*logc
= NULL
;
59 if (result != ISC_R_SUCCESS) \
64 ISC_PLATFORM_NORETURN_PRE
static void
65 usage(void) ISC_PLATFORM_NORETURN_POST
;
69 fprintf(stderr
, "usage: %s [-h] [-j] [-v] [-z] [-t directory] "
70 "[named.conf]\n", program
);
74 /*% directory callback */
76 directory_callback(const char *clausename
, const cfg_obj_t
*obj
, void *arg
) {
78 const char *directory
;
80 REQUIRE(strcasecmp("directory", clausename
) == 0);
88 directory
= cfg_obj_asstring(obj
);
89 result
= isc_dir_chdir(directory
);
90 if (result
!= ISC_R_SUCCESS
) {
91 cfg_obj_log(obj
, logc
, ISC_LOG_ERROR
,
92 "change directory to '%s' failed: %s\n",
93 directory
, isc_result_totext(result
));
97 return (ISC_R_SUCCESS
);
101 get_maps(const cfg_obj_t
**maps
, const char *name
, const cfg_obj_t
**obj
) {
106 if (cfg_map_get(maps
[i
], name
, obj
) == ISC_R_SUCCESS
)
112 get_checknames(const cfg_obj_t
**maps
, const cfg_obj_t
**obj
) {
113 const cfg_listelt_t
*element
;
114 const cfg_obj_t
*checknames
;
115 const cfg_obj_t
*type
;
116 const cfg_obj_t
*value
;
124 result
= cfg_map_get(maps
[i
], "check-names", &checknames
);
125 if (result
!= ISC_R_SUCCESS
)
127 if (checknames
!= NULL
&& !cfg_obj_islist(checknames
)) {
131 for (element
= cfg_list_first(checknames
);
133 element
= cfg_list_next(element
)) {
134 value
= cfg_listelt_value(element
);
135 type
= cfg_tuple_get(value
, "type");
136 if (strcasecmp(cfg_obj_asstring(type
), "master") != 0)
138 *obj
= cfg_tuple_get(value
, "mode");
145 config_get(const cfg_obj_t
**maps
, const char *name
, const cfg_obj_t
**obj
) {
150 return (ISC_R_NOTFOUND
);
151 if (cfg_map_get(maps
[i
], name
, obj
) == ISC_R_SUCCESS
)
152 return (ISC_R_SUCCESS
);
156 /*% configure the zone */
158 configure_zone(const char *vclass
, const char *view
,
159 const cfg_obj_t
*zconfig
, const cfg_obj_t
*vconfig
,
160 const cfg_obj_t
*config
, isc_mem_t
*mctx
)
167 const cfg_obj_t
*maps
[4];
168 const cfg_obj_t
*zoptions
= NULL
;
169 const cfg_obj_t
*classobj
= NULL
;
170 const cfg_obj_t
*typeobj
= NULL
;
171 const cfg_obj_t
*fileobj
= NULL
;
172 const cfg_obj_t
*dbobj
= NULL
;
173 const cfg_obj_t
*obj
= NULL
;
174 const cfg_obj_t
*fmtobj
= NULL
;
175 dns_masterformat_t masterformat
;
177 zone_options
= DNS_ZONEOPT_CHECKNS
| DNS_ZONEOPT_MANYERRORS
;
179 zname
= cfg_obj_asstring(cfg_tuple_get(zconfig
, "name"));
180 classobj
= cfg_tuple_get(zconfig
, "class");
181 if (!cfg_obj_isstring(classobj
))
184 zclass
= cfg_obj_asstring(classobj
);
186 zoptions
= cfg_tuple_get(zconfig
, "options");
187 maps
[i
++] = zoptions
;
189 maps
[i
++] = cfg_tuple_get(vconfig
, "options");
190 if (config
!= NULL
) {
191 cfg_map_get(config
, "options", &obj
);
197 cfg_map_get(zoptions
, "type", &typeobj
);
199 return (ISC_R_FAILURE
);
200 if (strcasecmp(cfg_obj_asstring(typeobj
), "master") != 0)
201 return (ISC_R_SUCCESS
);
202 cfg_map_get(zoptions
, "database", &dbobj
);
204 return (ISC_R_SUCCESS
);
205 cfg_map_get(zoptions
, "file", &fileobj
);
207 return (ISC_R_FAILURE
);
208 zfile
= cfg_obj_asstring(fileobj
);
211 if (get_maps(maps
, "check-dup-records", &obj
)) {
212 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
213 zone_options
|= DNS_ZONEOPT_CHECKDUPRR
;
214 zone_options
&= ~DNS_ZONEOPT_CHECKDUPRRFAIL
;
215 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
216 zone_options
|= DNS_ZONEOPT_CHECKDUPRR
;
217 zone_options
|= DNS_ZONEOPT_CHECKDUPRRFAIL
;
218 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
219 zone_options
&= ~DNS_ZONEOPT_CHECKDUPRR
;
220 zone_options
&= ~DNS_ZONEOPT_CHECKDUPRRFAIL
;
224 zone_options
|= DNS_ZONEOPT_CHECKDUPRR
;
225 zone_options
&= ~DNS_ZONEOPT_CHECKDUPRRFAIL
;
229 if (get_maps(maps
, "check-mx", &obj
)) {
230 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
231 zone_options
|= DNS_ZONEOPT_CHECKMX
;
232 zone_options
&= ~DNS_ZONEOPT_CHECKMXFAIL
;
233 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
234 zone_options
|= DNS_ZONEOPT_CHECKMX
;
235 zone_options
|= DNS_ZONEOPT_CHECKMXFAIL
;
236 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
237 zone_options
&= ~DNS_ZONEOPT_CHECKMX
;
238 zone_options
&= ~DNS_ZONEOPT_CHECKMXFAIL
;
242 zone_options
|= DNS_ZONEOPT_CHECKMX
;
243 zone_options
&= ~DNS_ZONEOPT_CHECKMXFAIL
;
247 if (get_maps(maps
, "check-integrity", &obj
)) {
248 if (cfg_obj_asboolean(obj
))
249 zone_options
|= DNS_ZONEOPT_CHECKINTEGRITY
;
251 zone_options
&= ~DNS_ZONEOPT_CHECKINTEGRITY
;
253 zone_options
|= DNS_ZONEOPT_CHECKINTEGRITY
;
256 if (get_maps(maps
, "check-mx-cname", &obj
)) {
257 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
258 zone_options
|= DNS_ZONEOPT_WARNMXCNAME
;
259 zone_options
&= ~DNS_ZONEOPT_IGNOREMXCNAME
;
260 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
261 zone_options
&= ~DNS_ZONEOPT_WARNMXCNAME
;
262 zone_options
&= ~DNS_ZONEOPT_IGNOREMXCNAME
;
263 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
264 zone_options
|= DNS_ZONEOPT_WARNMXCNAME
;
265 zone_options
|= DNS_ZONEOPT_IGNOREMXCNAME
;
269 zone_options
|= DNS_ZONEOPT_WARNMXCNAME
;
270 zone_options
&= ~DNS_ZONEOPT_IGNOREMXCNAME
;
274 if (get_maps(maps
, "check-srv-cname", &obj
)) {
275 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
276 zone_options
|= DNS_ZONEOPT_WARNSRVCNAME
;
277 zone_options
&= ~DNS_ZONEOPT_IGNORESRVCNAME
;
278 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
279 zone_options
&= ~DNS_ZONEOPT_WARNSRVCNAME
;
280 zone_options
&= ~DNS_ZONEOPT_IGNORESRVCNAME
;
281 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
282 zone_options
|= DNS_ZONEOPT_WARNSRVCNAME
;
283 zone_options
|= DNS_ZONEOPT_IGNORESRVCNAME
;
287 zone_options
|= DNS_ZONEOPT_WARNSRVCNAME
;
288 zone_options
&= ~DNS_ZONEOPT_IGNORESRVCNAME
;
292 if (get_maps(maps
, "check-sibling", &obj
)) {
293 if (cfg_obj_asboolean(obj
))
294 zone_options
|= DNS_ZONEOPT_CHECKSIBLING
;
296 zone_options
&= ~DNS_ZONEOPT_CHECKSIBLING
;
300 if (get_checknames(maps
, &obj
)) {
301 if (strcasecmp(cfg_obj_asstring(obj
), "warn") == 0) {
302 zone_options
|= DNS_ZONEOPT_CHECKNAMES
;
303 zone_options
&= ~DNS_ZONEOPT_CHECKNAMESFAIL
;
304 } else if (strcasecmp(cfg_obj_asstring(obj
), "fail") == 0) {
305 zone_options
|= DNS_ZONEOPT_CHECKNAMES
;
306 zone_options
|= DNS_ZONEOPT_CHECKNAMESFAIL
;
307 } else if (strcasecmp(cfg_obj_asstring(obj
), "ignore") == 0) {
308 zone_options
&= ~DNS_ZONEOPT_CHECKNAMES
;
309 zone_options
&= ~DNS_ZONEOPT_CHECKNAMESFAIL
;
313 zone_options
|= DNS_ZONEOPT_CHECKNAMES
;
314 zone_options
|= DNS_ZONEOPT_CHECKNAMESFAIL
;
317 masterformat
= dns_masterformat_text
;
319 result
= config_get(maps
, "masterfile-format", &fmtobj
);
320 if (result
== ISC_R_SUCCESS
) {
321 const char *masterformatstr
= cfg_obj_asstring(fmtobj
);
322 if (strcasecmp(masterformatstr
, "text") == 0)
323 masterformat
= dns_masterformat_text
;
324 else if (strcasecmp(masterformatstr
, "raw") == 0)
325 masterformat
= dns_masterformat_raw
;
330 result
= load_zone(mctx
, zname
, zfile
, masterformat
, zclass
, NULL
);
331 if (result
!= ISC_R_SUCCESS
)
332 fprintf(stderr
, "%s/%s/%s: %s\n", view
, zname
, zclass
,
333 dns_result_totext(result
));
337 /*% configure a view */
339 configure_view(const char *vclass
, const char *view
, const cfg_obj_t
*config
,
340 const cfg_obj_t
*vconfig
, isc_mem_t
*mctx
)
342 const cfg_listelt_t
*element
;
343 const cfg_obj_t
*voptions
;
344 const cfg_obj_t
*zonelist
;
345 isc_result_t result
= ISC_R_SUCCESS
;
346 isc_result_t tresult
;
350 voptions
= cfg_tuple_get(vconfig
, "options");
353 if (voptions
!= NULL
)
354 (void)cfg_map_get(voptions
, "zone", &zonelist
);
356 (void)cfg_map_get(config
, "zone", &zonelist
);
358 for (element
= cfg_list_first(zonelist
);
360 element
= cfg_list_next(element
))
362 const cfg_obj_t
*zconfig
= cfg_listelt_value(element
);
363 tresult
= configure_zone(vclass
, view
, zconfig
, vconfig
,
365 if (tresult
!= ISC_R_SUCCESS
)
372 /*% load zones from the configuration */
374 load_zones_fromconfig(const cfg_obj_t
*config
, isc_mem_t
*mctx
) {
375 const cfg_listelt_t
*element
;
376 const cfg_obj_t
*classobj
;
377 const cfg_obj_t
*views
;
378 const cfg_obj_t
*vconfig
;
380 isc_result_t result
= ISC_R_SUCCESS
;
381 isc_result_t tresult
;
385 (void)cfg_map_get(config
, "view", &views
);
386 for (element
= cfg_list_first(views
);
388 element
= cfg_list_next(element
))
393 vconfig
= cfg_listelt_value(element
);
394 if (vconfig
!= NULL
) {
395 classobj
= cfg_tuple_get(vconfig
, "class");
396 if (cfg_obj_isstring(classobj
))
397 vclass
= cfg_obj_asstring(classobj
);
399 vname
= cfg_obj_asstring(cfg_tuple_get(vconfig
, "name"));
400 tresult
= configure_view(vclass
, vname
, config
, vconfig
, mctx
);
401 if (tresult
!= ISC_R_SUCCESS
)
406 tresult
= configure_view("IN", "_default", config
, NULL
, mctx
);
407 if (tresult
!= ISC_R_SUCCESS
)
414 output(void *closure
, const char *text
, int textlen
) {
416 if (fwrite(text
, 1, textlen
, stdout
) != (size_t)textlen
) {
422 /*% The main processing routine */
424 main(int argc
, char **argv
) {
426 cfg_parser_t
*parser
= NULL
;
427 cfg_obj_t
*config
= NULL
;
428 const char *conffile
= NULL
;
429 isc_mem_t
*mctx
= NULL
;
432 isc_entropy_t
*ectx
= NULL
;
433 isc_boolean_t load_zones
= ISC_FALSE
;
434 isc_boolean_t print
= ISC_FALSE
;
436 isc_commandline_errprint
= ISC_FALSE
;
438 while ((c
= isc_commandline_parse(argc
, argv
, "dhjt:pvz")) != EOF
) {
449 result
= isc_dir_chroot(isc_commandline_argument
);
450 if (result
!= ISC_R_SUCCESS
) {
451 fprintf(stderr
, "isc_dir_chroot: %s\n",
452 isc_result_totext(result
));
462 printf(VERSION
"\n");
466 load_zones
= ISC_TRUE
;
467 docheckmx
= ISC_FALSE
;
468 docheckns
= ISC_FALSE
;
469 dochecksrv
= ISC_FALSE
;
473 if (isc_commandline_option
!= '?')
474 fprintf(stderr
, "%s: invalid argument -%c\n",
475 program
, isc_commandline_option
);
480 fprintf(stderr
, "%s: unhandled option -%c\n",
481 program
, isc_commandline_option
);
486 if (isc_commandline_index
+ 1 < argc
)
488 if (argv
[isc_commandline_index
] != NULL
)
489 conffile
= argv
[isc_commandline_index
];
490 if (conffile
== NULL
|| conffile
[0] == '\0')
491 conffile
= NAMED_CONFFILE
;
493 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx
) == ISC_R_SUCCESS
);
495 RUNTIME_CHECK(setup_logging(mctx
, stdout
, &logc
) == ISC_R_SUCCESS
);
497 RUNTIME_CHECK(isc_entropy_create(mctx
, &ectx
) == ISC_R_SUCCESS
);
498 RUNTIME_CHECK(isc_hash_create(mctx
, ectx
, DNS_NAME_MAXWIRE
)
501 dns_result_register();
503 RUNTIME_CHECK(cfg_parser_create(mctx
, logc
, &parser
) == ISC_R_SUCCESS
);
505 cfg_parser_setcallback(parser
, directory_callback
, NULL
);
507 if (cfg_parse_file(parser
, conffile
, &cfg_type_namedconf
, &config
) !=
511 result
= bind9_check_namedconf(config
, logc
, mctx
);
512 if (result
!= ISC_R_SUCCESS
)
515 if (result
== ISC_R_SUCCESS
&& load_zones
) {
516 result
= load_zones_fromconfig(config
, mctx
);
517 if (result
!= ISC_R_SUCCESS
)
521 if (print
&& exit_status
== 0)
522 cfg_print(config
, output
, NULL
);
523 cfg_obj_destroy(parser
, &config
);
525 cfg_parser_destroy(&parser
);
529 isc_log_destroy(&logc
);
532 isc_entropy_detach(&ectx
);
534 isc_mem_destroy(&mctx
);
536 return (exit_status
);