etc/services - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / bin / check / named-checkconf.c
blob3741428c3592bf8a125864020c623d45b3483507
1 /* $NetBSD: named-checkconf.c,v 1.11 2015/07/08 17:28:54 christos Exp $ */
3 /*
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 */
22 /*! \file */
24 #include <config.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <stdio.h>
30 #include <isc/commandline.h>
31 #include <isc/dir.h>
32 #include <isc/entropy.h>
33 #include <isc/hash.h>
34 #include <isc/log.h>
35 #include <isc/mem.h>
36 #include <isc/result.h>
37 #include <isc/string.h>
38 #include <isc/util.h>
40 #include <isccfg/namedconf.h>
42 #include <bind9/check.h>
44 #include <dns/db.h>
45 #include <dns/fixedname.h>
46 #include <dns/log.h>
47 #include <dns/name.h>
48 #include <dns/rdataclass.h>
49 #include <dns/result.h>
50 #include <dns/rootns.h>
51 #include <dns/zone.h>
53 #include "check-tool.h"
55 static const char *program = "named-checkconf";
57 isc_log_t *logc = NULL;
59 #define CHECK(r)\
60 do { \
61 result = (r); \
62 if (result != ISC_R_SUCCESS) \
63 goto cleanup; \
64 } while (/*CONSTCOND*/0)
66 /*% usage */
67 ISC_PLATFORM_NORETURN_PRE static void
68 usage(void) ISC_PLATFORM_NORETURN_POST;
70 static void
71 usage(void) {
72 fprintf(stderr, "usage: %s [-h] [-j] [-p] [-v] [-z] [-t directory] "
73 "[named.conf]\n", program);
74 exit(1);
77 /*% directory callback */
78 static isc_result_t
79 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
80 isc_result_t result;
81 const char *directory;
83 REQUIRE(strcasecmp("directory", clausename) == 0);
85 UNUSED(arg);
86 UNUSED(clausename);
89 * Change directory.
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));
97 return (result);
100 return (ISC_R_SUCCESS);
103 static isc_boolean_t
104 get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
105 int i;
106 for (i = 0;; i++) {
107 if (maps[i] == NULL)
108 return (ISC_FALSE);
109 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
110 return (ISC_TRUE);
114 static isc_boolean_t
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;
123 for (i = 0;; i++) {
124 if (maps[i] == NULL)
125 return (ISC_FALSE);
126 checknames = NULL;
127 result = cfg_map_get(maps[i], "check-names", &checknames);
128 if (result != ISC_R_SUCCESS)
129 continue;
130 if (checknames != NULL && !cfg_obj_islist(checknames)) {
131 *obj = checknames;
132 return (ISC_TRUE);
134 for (element = cfg_list_first(checknames);
135 element != NULL;
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)
140 continue;
141 *obj = cfg_tuple_get(value, "mode");
142 return (ISC_TRUE);
147 static isc_result_t
148 configure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) {
149 isc_result_t result;
150 dns_db_t *db = NULL;
151 dns_rdataclass_t rdclass;
152 isc_textregion_t r;
154 if (zfile == NULL)
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)
161 return (result);
163 result = dns_rootns_create(mctx, rdclass, zfile, &db);
164 if (result != ISC_R_SUCCESS)
165 return (result);
167 dns_db_detach(&db);
168 return (ISC_R_SUCCESS);
171 /*% configure the zone */
172 static isc_result_t
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)
177 int i = 0;
178 isc_result_t result;
179 const char *zclass;
180 const char *zname;
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))
200 zclass = vclass;
201 else
202 zclass = cfg_obj_asstring(classobj);
204 zoptions = cfg_tuple_get(zconfig, "options");
205 maps[i++] = zoptions;
206 if (vconfig != NULL)
207 maps[i++] = cfg_tuple_get(vconfig, "options");
208 if (config != NULL) {
209 cfg_map_get(config, "options", &obj);
210 if (obj != NULL)
211 maps[i++] = obj;
213 maps[i] = NULL;
215 cfg_map_get(zoptions, "type", &typeobj);
216 if (typeobj == NULL)
217 return (ISC_R_FAILURE);
220 * Skip checks when using an alternate data source.
222 cfg_map_get(zoptions, "database", &dbobj);
223 if (dbobj != NULL &&
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);
229 if (dlzobj != NULL)
230 return (ISC_R_SUCCESS);
232 cfg_map_get(zoptions, "file", &fileobj);
233 if (fileobj != NULL)
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);
256 if (zfile == NULL)
257 return (ISC_R_FAILURE);
259 obj = NULL;
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;
270 } else
271 INSIST(0);
272 } else {
273 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
274 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
277 obj = NULL;
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;
288 } else
289 INSIST(0);
290 } else {
291 zone_options |= DNS_ZONEOPT_CHECKMX;
292 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
295 obj = NULL;
296 if (get_maps(maps, "check-integrity", &obj)) {
297 if (cfg_obj_asboolean(obj))
298 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
299 else
300 zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
301 } else
302 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
304 obj = NULL;
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;
315 } else
316 INSIST(0);
317 } else {
318 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
319 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
322 obj = NULL;
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;
333 } else
334 INSIST(0);
335 } else {
336 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
337 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
340 obj = NULL;
341 if (get_maps(maps, "check-sibling", &obj)) {
342 if (cfg_obj_asboolean(obj))
343 zone_options |= DNS_ZONEOPT_CHECKSIBLING;
344 else
345 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
348 obj = NULL;
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;
354 } else
355 INSIST(0);
356 } else {
357 zone_options |= DNS_ZONEOPT_CHECKSPF;
360 obj = NULL;
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;
371 } else
372 INSIST(0);
373 } else {
374 zone_options |= DNS_ZONEOPT_CHECKNAMES;
375 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
378 masterformat = dns_masterformat_text;
379 fmtobj = NULL;
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;
388 else
389 INSIST(0);
392 obj = NULL;
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));
403 return (result);
406 /*% configure a view */
407 static isc_result_t
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;
417 voptions = NULL;
418 if (vconfig != NULL)
419 voptions = cfg_tuple_get(vconfig, "options");
421 zonelist = NULL;
422 if (voptions != NULL)
423 (void)cfg_map_get(voptions, "zone", &zonelist);
424 else
425 (void)cfg_map_get(config, "zone", &zonelist);
427 for (element = cfg_list_first(zonelist);
428 element != NULL;
429 element = cfg_list_next(element))
431 const cfg_obj_t *zconfig = cfg_listelt_value(element);
432 tresult = configure_zone(vclass, view, zconfig, vconfig,
433 config, mctx);
434 if (tresult != ISC_R_SUCCESS)
435 result = tresult;
437 return (result);
441 /*% load zones from the configuration */
442 static isc_result_t
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;
448 const char *vclass;
449 isc_result_t result = ISC_R_SUCCESS;
450 isc_result_t tresult;
452 views = NULL;
454 (void)cfg_map_get(config, "view", &views);
455 for (element = cfg_list_first(views);
456 element != NULL;
457 element = cfg_list_next(element))
459 const char *vname;
461 vclass = "IN";
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)
471 result = tresult;
474 if (views == NULL) {
475 tresult = configure_view("IN", "_default", config, NULL, mctx);
476 if (tresult != ISC_R_SUCCESS)
477 result = tresult;
479 return (result);
482 static void
483 output(void *closure, const char *text, int textlen) {
484 UNUSED(closure);
485 if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) {
486 perror("fwrite");
487 exit(1);
491 /*% The main processing routine */
493 main(int argc, char **argv) {
494 int c;
495 cfg_parser_t *parser = NULL;
496 cfg_obj_t *config = NULL;
497 const char *conffile = NULL;
498 isc_mem_t *mctx = NULL;
499 isc_result_t result;
500 int exit_status = 0;
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;
506 isc__mem_register();
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) {
514 switch (c) {
515 case 'm':
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;
526 break;
527 default:
528 break;
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) {
536 switch (c) {
537 case 'd':
538 debug++;
539 break;
541 case 'j':
542 nomerge = ISC_FALSE;
543 break;
545 case 'm':
546 break;
548 case 't':
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));
553 exit(1);
555 break;
557 case 'p':
558 print = ISC_TRUE;
559 break;
561 case 'v':
562 printf(VERSION "\n");
563 exit(0);
565 case 'x':
566 flags |= CFG_PRINTER_XKEY;
567 break;
569 case 'z':
570 load_zones = ISC_TRUE;
571 docheckmx = ISC_FALSE;
572 docheckns = ISC_FALSE;
573 dochecksrv = ISC_FALSE;
574 break;
576 case '?':
577 if (isc_commandline_option != '?')
578 fprintf(stderr, "%s: invalid argument -%c\n",
579 program, isc_commandline_option);
580 /* FALLTHROUGH */
581 case 'h':
582 usage();
584 default:
585 fprintf(stderr, "%s: unhandled option -%c\n",
586 program, isc_commandline_option);
587 exit(1);
591 if (((flags & CFG_PRINTER_XKEY) != 0) && !print) {
592 fprintf(stderr, "%s: -x cannot be used without -p\n", program);
593 exit(1);
596 if (isc_commandline_index + 1 < argc)
597 usage();
598 if (argv[isc_commandline_index] != NULL)
599 conffile = argv[isc_commandline_index];
600 if (conffile == NULL || conffile[0] == '\0')
601 conffile = NAMED_CONFFILE;
603 #ifdef _WIN32
604 InitSockets();
605 #endif
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)
611 == ISC_R_SUCCESS);
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) !=
620 ISC_R_SUCCESS)
621 exit(1);
623 result = bind9_check_namedconf(config, logc, mctx);
624 if (result != ISC_R_SUCCESS)
625 exit_status = 1;
627 if (result == ISC_R_SUCCESS && load_zones) {
628 result = load_zones_fromconfig(config, mctx);
629 if (result != ISC_R_SUCCESS)
630 exit_status = 1;
633 if (print && exit_status == 0)
634 cfg_printx(config, flags, output, NULL);
635 cfg_obj_destroy(parser, &config);
637 cfg_parser_destroy(&parser);
639 dns_name_destroy();
641 isc_log_destroy(&logc);
643 isc_hash_destroy();
644 isc_entropy_detach(&ectx);
646 isc_mem_destroy(&mctx);
648 #ifdef _WIN32
649 DestroySockets();
650 #endif
652 return (exit_status);