2 * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: check.c,v 1.37.6.32 2005/11/03 23:08:41 marka Exp $ */
25 #include <isc/buffer.h>
28 #include <isc/netaddr.h>
29 #include <isc/parseint.h>
30 #include <isc/region.h>
31 #include <isc/result.h>
32 #include <isc/sockaddr.h>
33 #include <isc/symtab.h>
36 #include <dns/fixedname.h>
37 #include <dns/rdataclass.h>
38 #include <dns/rdatatype.h>
39 #include <dns/secalg.h>
41 #include <isccfg/cfg.h>
43 #include <bind9/check.h>
46 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
49 isc_mem_free(userarg, key);
53 check_orderent(cfg_obj_t *ent, isc_log_t *logctx) {
54 isc_result_t result = ISC_R_SUCCESS;
57 dns_fixedname_t fixed;
59 dns_rdataclass_t rdclass;
60 dns_rdatatype_t rdtype;
64 dns_fixedname_init(&fixed);
65 obj = cfg_tuple_get(ent, "class");
66 if (cfg_obj_isstring(obj)) {
68 DE_CONST(cfg_obj_asstring(obj), r.base);
69 r.length = strlen(r.base);
70 tresult = dns_rdataclass_fromtext(&rdclass, &r);
71 if (tresult != ISC_R_SUCCESS) {
72 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
73 "rrset-order: invalid class '%s'",
75 result = ISC_R_FAILURE;
79 obj = cfg_tuple_get(ent, "type");
80 if (cfg_obj_isstring(obj)) {
82 DE_CONST(cfg_obj_asstring(obj), r.base);
83 r.length = strlen(r.base);
84 tresult = dns_rdatatype_fromtext(&rdtype, &r);
85 if (tresult != ISC_R_SUCCESS) {
86 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
87 "rrset-order: invalid type '%s'",
89 result = ISC_R_FAILURE;
93 obj = cfg_tuple_get(ent, "name");
94 if (cfg_obj_isstring(obj)) {
95 str = cfg_obj_asstring(obj);
96 isc_buffer_init(&b, str, strlen(str));
97 isc_buffer_add(&b, strlen(str));
98 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
99 dns_rootname, ISC_FALSE, NULL);
100 if (tresult != ISC_R_SUCCESS) {
101 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
102 "rrset-order: invalid name '%s'", str);
103 result = ISC_R_FAILURE;
107 obj = cfg_tuple_get(ent, "order");
108 if (!cfg_obj_isstring(obj) ||
109 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
110 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
111 "rrset-order: keyword 'order' missing");
112 result = ISC_R_FAILURE;
115 obj = cfg_tuple_get(ent, "ordering");
116 if (!cfg_obj_isstring(obj)) {
117 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
118 "rrset-order: missing ordering");
119 result = ISC_R_FAILURE;
120 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
121 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
122 "rrset-order: order 'fixed' not fully implemented");
123 } else if (/* strcasecmp(cfg_obj_asstring(obj), "fixed") != 0 && */
124 strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
125 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
126 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
127 "rrset-order: invalid order '%s'",
128 cfg_obj_asstring(obj));
129 result = ISC_R_FAILURE;
135 check_order(cfg_obj_t *options, isc_log_t *logctx) {
136 isc_result_t result = ISC_R_SUCCESS;
137 isc_result_t tresult;
138 cfg_listelt_t *element;
139 cfg_obj_t *obj = NULL;
141 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
144 for (element = cfg_list_first(obj);
146 element = cfg_list_next(element))
148 tresult = check_orderent(cfg_listelt_value(element), logctx);
149 if (tresult != ISC_R_SUCCESS)
156 check_dual_stack(cfg_obj_t *options, isc_log_t *logctx) {
157 cfg_listelt_t *element;
158 cfg_obj_t *alternates = NULL;
162 dns_fixedname_t fixed;
165 isc_result_t result = ISC_R_SUCCESS;
166 isc_result_t tresult;
168 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
170 if (alternates == NULL)
171 return (ISC_R_SUCCESS);
173 obj = cfg_tuple_get(alternates, "port");
174 if (cfg_obj_isuint32(obj)) {
175 isc_uint32_t val = cfg_obj_asuint32(obj);
176 if (val > ISC_UINT16_MAX) {
177 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
178 "port '%u' out of range", val);
179 result = ISC_R_FAILURE;
182 obj = cfg_tuple_get(alternates, "addresses");
183 for (element = cfg_list_first(obj);
185 element = cfg_list_next(element)) {
186 value = cfg_listelt_value(element);
187 if (cfg_obj_issockaddr(value))
189 obj = cfg_tuple_get(value, "name");
190 str = cfg_obj_asstring(obj);
191 isc_buffer_init(&buffer, str, strlen(str));
192 isc_buffer_add(&buffer, strlen(str));
193 dns_fixedname_init(&fixed);
194 name = dns_fixedname_name(&fixed);
195 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
197 if (tresult != ISC_R_SUCCESS) {
198 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
199 "bad name '%s'", str);
200 result = ISC_R_FAILURE;
202 obj = cfg_tuple_get(value, "port");
203 if (cfg_obj_isuint32(obj)) {
204 isc_uint32_t val = cfg_obj_asuint32(obj);
205 if (val > ISC_UINT16_MAX) {
206 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
207 "port '%u' out of range", val);
208 result = ISC_R_FAILURE;
216 check_forward(cfg_obj_t *options, isc_log_t *logctx) {
217 cfg_obj_t *forward = NULL;
218 cfg_obj_t *forwarders = NULL;
220 (void)cfg_map_get(options, "forward", &forward);
221 (void)cfg_map_get(options, "forwarders", &forwarders);
223 if (forward != NULL && forwarders == NULL) {
224 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
225 "no matching 'forwarders' statement");
226 return (ISC_R_FAILURE);
228 return (ISC_R_SUCCESS);
232 disabled_algorithms(cfg_obj_t *disabled, isc_log_t *logctx) {
233 isc_result_t result = ISC_R_SUCCESS;
234 isc_result_t tresult;
235 cfg_listelt_t *element;
238 dns_fixedname_t fixed;
242 dns_fixedname_init(&fixed);
243 name = dns_fixedname_name(&fixed);
244 obj = cfg_tuple_get(disabled, "name");
245 str = cfg_obj_asstring(obj);
246 isc_buffer_init(&b, str, strlen(str));
247 isc_buffer_add(&b, strlen(str));
248 tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
249 if (tresult != ISC_R_SUCCESS) {
250 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
251 "bad domain name '%s'", str);
255 obj = cfg_tuple_get(disabled, "algorithms");
257 for (element = cfg_list_first(obj);
259 element = cfg_list_next(element))
263 isc_result_t tresult;
265 r.base = cfg_obj_asstring(cfg_listelt_value(element));
266 r.length = strlen(r.base);
268 tresult = dns_secalg_fromtext(&alg, &r);
269 if (tresult != ISC_R_SUCCESS) {
271 result = isc_parse_uint8(&ui, r.base, 10);
273 if (tresult != ISC_R_SUCCESS) {
274 cfg_obj_log(cfg_listelt_value(element), logctx,
275 ISC_LOG_ERROR, "invalid algorithm");
283 nameexist(cfg_obj_t *obj, const char *name, int value, isc_symtab_t *symtab,
284 const char *fmt, isc_log_t *logctx, isc_mem_t *mctx)
290 isc_symvalue_t symvalue;
292 key = isc_mem_strdup(mctx, name);
294 return (ISC_R_NOMEMORY);
295 symvalue.as_pointer = obj;
296 result = isc_symtab_define(symtab, key, value, symvalue,
297 isc_symexists_reject);
298 if (result == ISC_R_EXISTS) {
299 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
300 &symvalue) == ISC_R_SUCCESS);
301 file = cfg_obj_file(symvalue.as_pointer);
302 line = cfg_obj_line(symvalue.as_pointer);
305 file = "<unknown file>";
306 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
307 isc_mem_free(mctx, key);
308 result = ISC_R_EXISTS;
309 } else if (result != ISC_R_SUCCESS) {
310 isc_mem_free(mctx, key);
316 mustbesecure(cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
320 char namebuf[DNS_NAME_FORMATSIZE];
322 dns_fixedname_t fixed;
325 isc_result_t result = ISC_R_SUCCESS;
327 dns_fixedname_init(&fixed);
328 name = dns_fixedname_name(&fixed);
329 obj = cfg_tuple_get(secure, "name");
330 str = cfg_obj_asstring(obj);
331 isc_buffer_init(&b, str, strlen(str));
332 isc_buffer_add(&b, strlen(str));
333 result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
334 if (result != ISC_R_SUCCESS) {
335 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
336 "bad domain name '%s'", str);
338 dns_name_format(name, namebuf, sizeof(namebuf));
339 result = nameexist(secure, namebuf, 1, symtab,
340 "dnssec-must-be-secure '%s': already "
341 "exists previous definition: %s:%u",
354 check_options(cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
355 isc_result_t result = ISC_R_SUCCESS;
356 isc_result_t tresult;
358 cfg_obj_t *obj = NULL;
359 cfg_listelt_t *element;
360 isc_symtab_t *symtab = NULL;
362 static intervaltable intervals[] = {
363 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
364 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
365 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
366 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
367 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
368 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
369 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
370 { "sig-validity-interval", 86400, 10 * 366 }, /* 10 years */
371 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
375 * Check that fields specified in units of time other than seconds
376 * have reasonable values.
378 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
381 (void)cfg_map_get(options, intervals[i].name, &obj);
384 val = cfg_obj_asuint32(obj);
385 if (val > intervals[i].max) {
386 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
387 "%s '%u' is out of range (0..%u)",
388 intervals[i].name, val,
390 result = ISC_R_RANGE;
391 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
392 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
393 "%s '%d' is out of range",
394 intervals[i].name, val);
395 result = ISC_R_RANGE;
399 (void)cfg_map_get(options, "preferred-glue", &obj);
402 str = cfg_obj_asstring(obj);
403 if (strcasecmp(str, "a") != 0 &&
404 strcasecmp(str, "aaaa") != 0 &&
405 strcasecmp(str, "none") != 0)
406 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
407 "preferred-glue unexpected value '%s'",
411 (void)cfg_map_get(options, "root-delegation-only", &obj);
413 if (!cfg_obj_isvoid(obj)) {
414 cfg_listelt_t *element;
417 dns_fixedname_t fixed;
421 dns_fixedname_init(&fixed);
422 name = dns_fixedname_name(&fixed);
423 for (element = cfg_list_first(obj);
425 element = cfg_list_next(element)) {
426 exclude = cfg_listelt_value(element);
427 str = cfg_obj_asstring(exclude);
428 isc_buffer_init(&b, str, strlen(str));
429 isc_buffer_add(&b, strlen(str));
430 tresult = dns_name_fromtext(name, &b,
433 if (tresult != ISC_R_SUCCESS) {
434 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
435 "bad domain name '%s'",
444 * Set supported DNSSEC algorithms.
447 (void)cfg_map_get(options, "disable-algorithms", &obj);
449 for (element = cfg_list_first(obj);
451 element = cfg_list_next(element))
453 obj = cfg_listelt_value(element);
454 tresult = disabled_algorithms(obj, logctx);
455 if (tresult != ISC_R_SUCCESS)
461 * Check the DLV zone name.
464 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
466 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
468 if (tresult != ISC_R_SUCCESS)
470 for (element = cfg_list_first(obj);
472 element = cfg_list_next(element))
474 dns_fixedname_t fixedname;
479 obj = cfg_listelt_value(element);
481 dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
482 dns_fixedname_init(&fixedname);
483 name = dns_fixedname_name(&fixedname);
484 isc_buffer_init(&b, dlv, strlen(dlv));
485 isc_buffer_add(&b, strlen(dlv));
486 tresult = dns_name_fromtext(name, &b, dns_rootname,
488 if (tresult != ISC_R_SUCCESS) {
489 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
490 "bad domain name '%s'", dlv);
493 if (symtab != NULL) {
494 tresult = nameexist(obj, dlv, 1, symtab,
495 "dnssec-lookaside '%s': "
496 "already exists previous "
499 if (tresult != ISC_R_SUCCESS &&
500 result == ISC_R_SUCCESS)
504 * XXXMPA to be removed when multiple lookaside
505 * namespaces are supported.
507 if (!dns_name_equal(dns_rootname, name)) {
508 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
509 "dnssec-lookaside '%s': "
510 "non-root not yet supported", dlv);
511 if (result == ISC_R_SUCCESS)
512 result = ISC_R_FAILURE;
514 dlv = cfg_obj_asstring(cfg_tuple_get(obj,
516 dns_fixedname_init(&fixedname);
517 isc_buffer_init(&b, dlv, strlen(dlv));
518 isc_buffer_add(&b, strlen(dlv));
519 tresult = dns_name_fromtext(name, &b, dns_rootname,
521 if (tresult != ISC_R_SUCCESS) {
522 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
523 "bad domain name '%s'", dlv);
524 if (result == ISC_R_SUCCESS)
529 isc_symtab_destroy(&symtab);
533 * Check dnssec-must-be-secure.
536 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
538 isc_symtab_t *symtab = NULL;
539 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
541 if (tresult != ISC_R_SUCCESS)
543 for (element = cfg_list_first(obj);
545 element = cfg_list_next(element))
547 obj = cfg_listelt_value(element);
548 tresult = mustbesecure(obj, symtab, logctx, mctx);
549 if (tresult != ISC_R_SUCCESS)
553 isc_symtab_destroy(&symtab);
560 get_masters_def(cfg_obj_t *cctx, char *name, cfg_obj_t **ret) {
562 cfg_obj_t *masters = NULL;
565 result = cfg_map_get(cctx, "masters", &masters);
566 if (result != ISC_R_SUCCESS)
568 for (elt = cfg_list_first(masters);
570 elt = cfg_list_next(elt)) {
572 const char *listname;
574 list = cfg_listelt_value(elt);
575 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
577 if (strcasecmp(listname, name) == 0) {
579 return (ISC_R_SUCCESS);
582 return (ISC_R_NOTFOUND);
586 validate_masters(cfg_obj_t *obj, cfg_obj_t *config, isc_uint32_t *countp,
587 isc_log_t *logctx, isc_mem_t *mctx)
589 isc_result_t result = ISC_R_SUCCESS;
590 isc_result_t tresult;
591 isc_uint32_t count = 0;
592 isc_symtab_t *symtab = NULL;
593 isc_symvalue_t symvalue;
594 cfg_listelt_t *element;
595 cfg_listelt_t **stack = NULL;
596 isc_uint32_t stackcount = 0, pushed = 0;
599 REQUIRE(countp != NULL);
600 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
601 if (result != ISC_R_SUCCESS) {
607 list = cfg_tuple_get(obj, "addresses");
608 element = cfg_list_first(list);
612 element = cfg_list_next(element))
618 addr = cfg_tuple_get(cfg_listelt_value(element),
620 key = cfg_tuple_get(cfg_listelt_value(element), "key");
622 if (cfg_obj_issockaddr(addr)) {
626 if (!cfg_obj_isvoid(key)) {
627 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
628 "unexpected token '%s'",
629 cfg_obj_asstring(key));
630 if (result == ISC_R_SUCCESS)
631 result = ISC_R_FAILURE;
633 listname = cfg_obj_asstring(addr);
634 symvalue.as_pointer = addr;
635 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
636 isc_symexists_reject);
637 if (tresult == ISC_R_EXISTS)
639 tresult = get_masters_def(config, listname, &obj);
640 if (tresult != ISC_R_SUCCESS) {
641 if (result == ISC_R_SUCCESS)
643 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
644 "unable to find masters list '%s'",
649 if (stackcount == pushed) {
651 isc_uint32_t newlen = stackcount + 16;
652 size_t newsize, oldsize;
654 newsize = newlen * sizeof(*stack);
655 oldsize = stackcount * sizeof(*stack);
656 new = isc_mem_get(mctx, newsize);
659 if (stackcount != 0) {
660 memcpy(new, stack, oldsize);
661 isc_mem_put(mctx, stack, oldsize);
666 stack[pushed++] = cfg_list_next(element);
670 element = stack[--pushed];
675 isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
676 isc_symtab_destroy(&symtab);
685 #define FORWARDZONE 16
686 #define DELEGATIONZONE 32
694 check_zoneconf(cfg_obj_t *zconfig, cfg_obj_t *config, isc_symtab_t *symtab,
695 dns_rdataclass_t defclass, isc_log_t *logctx, isc_mem_t *mctx)
701 cfg_obj_t *obj = NULL;
702 isc_result_t result = ISC_R_SUCCESS;
703 isc_result_t tresult;
705 dns_rdataclass_t zclass;
706 dns_fixedname_t fixedname;
709 static optionstable options[] = {
710 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE },
711 { "allow-notify", SLAVEZONE },
712 { "allow-transfer", MASTERZONE | SLAVEZONE },
713 { "notify", MASTERZONE | SLAVEZONE },
714 { "also-notify", MASTERZONE | SLAVEZONE },
715 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
716 { "delegation-only", HINTZONE | STUBZONE },
717 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
718 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
719 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
720 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
721 { "notify-source", MASTERZONE | SLAVEZONE },
722 { "notify-source-v6", MASTERZONE | SLAVEZONE },
723 { "transfer-source", SLAVEZONE | STUBZONE },
724 { "transfer-source-v6", SLAVEZONE | STUBZONE },
725 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
726 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
727 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
728 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
729 { "max-retry-time", SLAVEZONE | STUBZONE },
730 { "min-retry-time", SLAVEZONE | STUBZONE },
731 { "max-refresh-time", SLAVEZONE | STUBZONE },
732 { "min-refresh-time", SLAVEZONE | STUBZONE },
733 { "sig-validity-interval", MASTERZONE },
734 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
735 { "allow-update", MASTERZONE },
736 { "allow-update-forwarding", SLAVEZONE },
737 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
738 { "ixfr-base", MASTERZONE | SLAVEZONE },
739 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
740 { "masters", SLAVEZONE | STUBZONE },
741 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
742 { "update-policy", MASTERZONE },
743 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
744 { "key-directory", MASTERZONE },
747 static optionstable dialups[] = {
748 { "notify", MASTERZONE | SLAVEZONE },
749 { "notify-passive", SLAVEZONE },
750 { "refresh", SLAVEZONE | STUBZONE },
751 { "passive", SLAVEZONE | STUBZONE },
754 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
756 zoptions = cfg_tuple_get(zconfig, "options");
759 (void)cfg_map_get(zoptions, "type", &obj);
761 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
762 "zone '%s': type not present", zname);
763 return (ISC_R_FAILURE);
766 typestr = cfg_obj_asstring(obj);
767 if (strcasecmp(typestr, "master") == 0)
769 else if (strcasecmp(typestr, "slave") == 0)
771 else if (strcasecmp(typestr, "stub") == 0)
773 else if (strcasecmp(typestr, "forward") == 0)
775 else if (strcasecmp(typestr, "hint") == 0)
777 else if (strcasecmp(typestr, "delegation-only") == 0)
778 ztype = DELEGATIONZONE;
780 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
781 "zone '%s': invalid type %s",
783 return (ISC_R_FAILURE);
786 obj = cfg_tuple_get(zconfig, "class");
787 if (cfg_obj_isstring(obj)) {
790 DE_CONST(cfg_obj_asstring(obj), r.base);
791 r.length = strlen(r.base);
792 result = dns_rdataclass_fromtext(&zclass, &r);
793 if (result != ISC_R_SUCCESS) {
794 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
795 "zone '%s': invalid class %s",
797 return (ISC_R_FAILURE);
799 if (zclass != defclass) {
800 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
801 "zone '%s': class '%s' does not "
802 "match view/default class",
804 return (ISC_R_FAILURE);
809 * Look for an already existing zone.
810 * We need to make this cannonical as isc_symtab_define()
811 * deals with strings.
813 dns_fixedname_init(&fixedname);
814 isc_buffer_init(&b, zname, strlen(zname));
815 isc_buffer_add(&b, strlen(zname));
816 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
817 dns_rootname, ISC_TRUE, NULL);
818 if (result != ISC_R_SUCCESS) {
819 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
820 "zone '%s': is not a valid name", zname);
821 tresult = ISC_R_FAILURE;
823 char namebuf[DNS_NAME_FORMATSIZE];
825 dns_name_format(dns_fixedname_name(&fixedname),
826 namebuf, sizeof(namebuf));
827 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
828 symtab, "zone '%s': already exists "
829 "previous definition: %s:%u", logctx, mctx);
830 if (tresult != ISC_R_SUCCESS)
835 * Look for inappropriate options for the given zone type.
837 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
839 if ((options[i].allowed & ztype) == 0 &&
840 cfg_map_get(zoptions, options[i].name, &obj) ==
843 if (strcmp(options[i].name, "allow-update") != 0 ||
844 ztype != SLAVEZONE) {
845 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
846 "option '%s' is not allowed "
848 options[i].name, typestr, zname);
849 result = ISC_R_FAILURE;
851 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
852 "option '%s' is not allowed "
854 options[i].name, typestr, zname);
859 * Slave & stub zones must have a "masters" field.
861 if (ztype == SLAVEZONE || ztype == STUBZONE) {
863 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
864 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
865 "zone '%s': missing 'masters' entry",
867 result = ISC_R_FAILURE;
870 tresult = validate_masters(obj, config, &count,
872 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
874 if (tresult == ISC_R_SUCCESS && count == 0) {
875 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
876 "zone '%s': empty 'masters' entry",
878 result = ISC_R_FAILURE;
884 * Master zones can't have both "allow-update" and "update-policy".
886 if (ztype == MASTERZONE) {
887 isc_result_t res1, res2;
889 res1 = cfg_map_get(zoptions, "allow-update", &obj);
891 res2 = cfg_map_get(zoptions, "update-policy", &obj);
892 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
893 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
894 "zone '%s': 'allow-update' is ignored "
895 "when 'update-policy' is present",
897 result = ISC_R_FAILURE;
902 * Check the excessively complicated "dialup" option.
904 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
905 cfg_obj_t *dialup = NULL;
906 (void)cfg_map_get(zoptions, "dialup", &dialup);
907 if (dialup != NULL && cfg_obj_isstring(dialup)) {
908 char *str = cfg_obj_asstring(dialup);
910 i < sizeof(dialups) / sizeof(dialups[0]);
913 if (strcasecmp(dialups[i].name, str) != 0)
915 if ((dialups[i].allowed & ztype) == 0) {
916 cfg_obj_log(obj, logctx,
918 "dialup type '%s' is not "
921 str, typestr, zname);
922 result = ISC_R_FAILURE;
926 if (i == sizeof(dialups) / sizeof(dialups[0])) {
927 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
928 "invalid dialup type '%s' in zone "
930 result = ISC_R_FAILURE;
936 * Check that forwarding is reasonable.
938 if (check_forward(zoptions, logctx) != ISC_R_SUCCESS)
939 result = ISC_R_FAILURE;
942 * Check various options.
944 tresult = check_options(zoptions, logctx, mctx);
945 if (tresult != ISC_R_SUCCESS)
949 * If the zone type is rbt/rbt64 then master/hint zones
950 * require file clauses.
953 tresult = cfg_map_get(zoptions, "database", &obj);
954 if (tresult == ISC_R_NOTFOUND ||
955 (tresult == ISC_R_SUCCESS &&
956 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
957 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
959 tresult = cfg_map_get(zoptions, "file", &obj);
960 if (tresult != ISC_R_SUCCESS &&
961 (ztype == MASTERZONE || ztype == HINTZONE)) {
962 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
963 "zone '%s': missing 'file' entry",
973 bind9_check_key(cfg_obj_t *key, isc_log_t *logctx) {
974 cfg_obj_t *algobj = NULL;
975 cfg_obj_t *secretobj = NULL;
976 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
978 (void)cfg_map_get(key, "algorithm", &algobj);
979 (void)cfg_map_get(key, "secret", &secretobj);
980 if (secretobj == NULL || algobj == NULL) {
981 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
982 "key '%s' must have both 'secret' and "
983 "'algorithm' defined",
985 return (ISC_R_FAILURE);
987 return (ISC_R_SUCCESS);
991 check_keylist(cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) {
992 isc_result_t result = ISC_R_SUCCESS;
993 isc_result_t tresult;
994 cfg_listelt_t *element;
996 for (element = cfg_list_first(keys);
998 element = cfg_list_next(element))
1000 cfg_obj_t *key = cfg_listelt_value(element);
1001 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1002 isc_symvalue_t symvalue;
1004 symvalue.as_pointer = key;
1005 tresult = isc_symtab_define(symtab, keyname, 1,
1006 symvalue, isc_symexists_reject);
1007 if (tresult == ISC_R_EXISTS) {
1011 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1012 1, &symvalue) == ISC_R_SUCCESS);
1013 file = cfg_obj_file(symvalue.as_pointer);
1014 line = cfg_obj_line(symvalue.as_pointer);
1017 file = "<unknown file>";
1018 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1019 "key '%s': already exists "
1020 "previous definition: %s:%u",
1021 keyname, file, line);
1023 } else if (tresult != ISC_R_SUCCESS)
1026 tresult = bind9_check_key(key, logctx);
1027 if (tresult != ISC_R_SUCCESS)
1034 check_servers(cfg_obj_t *servers, isc_log_t *logctx) {
1035 isc_result_t result = ISC_R_SUCCESS;
1036 cfg_listelt_t *e1, *e2;
1038 isc_sockaddr_t *s1, *s2;
1043 isc_buffer_t target;
1045 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1046 v1 = cfg_listelt_value(e1);
1047 s1 = cfg_obj_assockaddr(cfg_map_getname(v1));
1049 if (isc_sockaddr_pf(s1) == AF_INET)
1050 xfr = "transfer-source-v6";
1052 xfr = "transfer-source";
1053 (void)cfg_map_get(v1, xfr, &ts);
1055 isc_netaddr_fromsockaddr(&na, s1);
1056 isc_buffer_init(&target, buf, sizeof(buf) - 1);
1057 RUNTIME_CHECK(isc_netaddr_totext(&na, &target)
1059 buf[isc_buffer_usedlength(&target)] = '\0';
1060 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1061 "server '%s': %s not valid", buf, xfr);
1062 result = ISC_R_FAILURE;
1065 while ((e2 = cfg_list_next(e2)) != NULL) {
1066 v2 = cfg_listelt_value(e2);
1067 s2 = cfg_obj_assockaddr(cfg_map_getname(v2));
1068 if (isc_sockaddr_eqaddr(s1, s2)) {
1069 const char *file = cfg_obj_file(v1);
1070 unsigned int line = cfg_obj_line(v1);
1073 file = "<unknown file>";
1075 isc_netaddr_fromsockaddr(&na, s2);
1076 isc_buffer_init(&target, buf, sizeof(buf) - 1);
1077 RUNTIME_CHECK(isc_netaddr_totext(&na, &target)
1079 buf[isc_buffer_usedlength(&target)] = '\0';
1081 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1082 "server '%s': already exists "
1083 "previous definition: %s:%u",
1085 result = ISC_R_FAILURE;
1093 check_viewconf(cfg_obj_t *config, cfg_obj_t *vconfig, dns_rdataclass_t vclass,
1094 isc_log_t *logctx, isc_mem_t *mctx)
1096 cfg_obj_t *servers = NULL;
1097 cfg_obj_t *zones = NULL;
1098 cfg_obj_t *keys = NULL;
1099 cfg_listelt_t *element;
1100 isc_symtab_t *symtab = NULL;
1101 isc_result_t result = ISC_R_SUCCESS;
1102 isc_result_t tresult = ISC_R_SUCCESS;
1105 * Check that all zone statements are syntactically correct and
1106 * there are no duplicate zones.
1108 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1109 ISC_FALSE, &symtab);
1110 if (tresult != ISC_R_SUCCESS)
1111 return (ISC_R_NOMEMORY);
1113 if (vconfig != NULL)
1114 (void)cfg_map_get(vconfig, "zone", &zones);
1116 (void)cfg_map_get(config, "zone", &zones);
1118 for (element = cfg_list_first(zones);
1120 element = cfg_list_next(element))
1122 isc_result_t tresult;
1123 cfg_obj_t *zone = cfg_listelt_value(element);
1125 tresult = check_zoneconf(zone, config, symtab, vclass,
1127 if (tresult != ISC_R_SUCCESS)
1128 result = ISC_R_FAILURE;
1131 isc_symtab_destroy(&symtab);
1134 * Check that all key statements are syntactically correct and
1135 * there are no duplicate keys.
1137 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1138 if (tresult != ISC_R_SUCCESS)
1139 return (ISC_R_NOMEMORY);
1141 (void)cfg_map_get(config, "key", &keys);
1142 tresult = check_keylist(keys, symtab, logctx);
1143 if (tresult == ISC_R_EXISTS)
1144 result = ISC_R_FAILURE;
1145 else if (tresult != ISC_R_SUCCESS) {
1146 isc_symtab_destroy(&symtab);
1150 if (vconfig != NULL) {
1152 (void)cfg_map_get(vconfig, "key", &keys);
1153 tresult = check_keylist(keys, symtab, logctx);
1154 if (tresult == ISC_R_EXISTS)
1155 result = ISC_R_FAILURE;
1156 else if (tresult != ISC_R_SUCCESS) {
1157 isc_symtab_destroy(&symtab);
1162 isc_symtab_destroy(&symtab);
1165 * Check that forwarding is reasonable.
1167 if (vconfig == NULL) {
1168 cfg_obj_t *options = NULL;
1169 (void)cfg_map_get(config, "options", &options);
1170 if (options != NULL)
1171 if (check_forward(options, logctx) != ISC_R_SUCCESS)
1172 result = ISC_R_FAILURE;
1174 if (check_forward(vconfig, logctx) != ISC_R_SUCCESS)
1175 result = ISC_R_FAILURE;
1178 * Check that dual-stack-servers is reasonable.
1180 if (vconfig == NULL) {
1181 cfg_obj_t *options = NULL;
1182 (void)cfg_map_get(config, "options", &options);
1183 if (options != NULL)
1184 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1185 result = ISC_R_FAILURE;
1187 if (check_dual_stack(vconfig, logctx) != ISC_R_SUCCESS)
1188 result = ISC_R_FAILURE;
1192 * Check that rrset-order is reasonable.
1194 if (vconfig != NULL) {
1195 if (check_order(vconfig, logctx) != ISC_R_SUCCESS)
1196 result = ISC_R_FAILURE;
1199 if (vconfig != NULL) {
1200 (void)cfg_map_get(vconfig, "server", &servers);
1201 if (servers != NULL &&
1202 check_servers(servers, logctx) != ISC_R_SUCCESS)
1203 result = ISC_R_FAILURE;
1206 if (vconfig != NULL)
1207 tresult = check_options(vconfig, logctx, mctx);
1209 tresult = check_options(config, logctx, mctx);
1210 if (tresult != ISC_R_SUCCESS)
1218 bind9_check_namedconf(cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) {
1219 cfg_obj_t *options = NULL;
1220 cfg_obj_t *servers = NULL;
1221 cfg_obj_t *views = NULL;
1222 cfg_obj_t *acls = NULL;
1223 cfg_obj_t *kals = NULL;
1225 cfg_listelt_t *velement;
1226 isc_result_t result = ISC_R_SUCCESS;
1227 isc_result_t tresult;
1228 isc_symtab_t *symtab = NULL;
1230 static const char *builtin[] = { "localhost", "localnets",
1233 (void)cfg_map_get(config, "options", &options);
1235 if (options != NULL &&
1236 check_options(options, logctx, mctx) != ISC_R_SUCCESS)
1237 result = ISC_R_FAILURE;
1239 (void)cfg_map_get(config, "server", &servers);
1240 if (servers != NULL &&
1241 check_servers(servers, logctx) != ISC_R_SUCCESS)
1242 result = ISC_R_FAILURE;
1244 if (options != NULL &&
1245 check_order(options, logctx) != ISC_R_SUCCESS)
1246 result = ISC_R_FAILURE;
1248 (void)cfg_map_get(config, "view", &views);
1250 if (views != NULL && options != NULL)
1251 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1252 result = ISC_R_FAILURE;
1254 if (views == NULL) {
1255 if (check_viewconf(config, NULL, dns_rdataclass_in,
1256 logctx, mctx) != ISC_R_SUCCESS)
1257 result = ISC_R_FAILURE;
1259 cfg_obj_t *zones = NULL;
1261 (void)cfg_map_get(config, "zone", &zones);
1262 if (zones != NULL) {
1263 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
1264 "when using 'view' statements, "
1265 "all zones must be in views");
1266 result = ISC_R_FAILURE;
1270 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1271 if (tresult != ISC_R_SUCCESS)
1273 for (velement = cfg_list_first(views);
1275 velement = cfg_list_next(velement))
1277 cfg_obj_t *view = cfg_listelt_value(velement);
1278 cfg_obj_t *vname = cfg_tuple_get(view, "name");
1279 cfg_obj_t *voptions = cfg_tuple_get(view, "options");
1280 cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
1281 dns_rdataclass_t vclass = dns_rdataclass_in;
1282 isc_result_t tresult = ISC_R_SUCCESS;
1283 const char *key = cfg_obj_asstring(vname);
1284 isc_symvalue_t symvalue;
1286 if (cfg_obj_isstring(vclassobj)) {
1289 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
1290 r.length = strlen(r.base);
1291 tresult = dns_rdataclass_fromtext(&vclass, &r);
1292 if (tresult != ISC_R_SUCCESS)
1293 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
1294 "view '%s': invalid class %s",
1295 cfg_obj_asstring(vname), r.base);
1297 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
1298 symvalue.as_pointer = view;
1299 tresult = isc_symtab_define(symtab, key, vclass,
1301 isc_symexists_reject);
1302 if (tresult == ISC_R_EXISTS) {
1305 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
1306 vclass, &symvalue) == ISC_R_SUCCESS);
1307 file = cfg_obj_file(symvalue.as_pointer);
1308 line = cfg_obj_line(symvalue.as_pointer);
1309 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1310 "view '%s': already exists "
1311 "previous definition: %s:%u",
1314 } else if (result != ISC_R_SUCCESS) {
1316 } else if ((strcasecmp(key, "_bind") == 0 &&
1317 vclass == dns_rdataclass_ch) ||
1318 (strcasecmp(key, "_default") == 0 &&
1319 vclass == dns_rdataclass_in)) {
1320 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1321 "attempt to redefine builtin view "
1323 result = ISC_R_EXISTS;
1326 if (tresult == ISC_R_SUCCESS)
1327 tresult = check_viewconf(config, voptions,
1328 vclass, logctx, mctx);
1329 if (tresult != ISC_R_SUCCESS)
1330 result = ISC_R_FAILURE;
1333 isc_symtab_destroy(&symtab);
1335 if (views != NULL && options != NULL) {
1337 tresult = cfg_map_get(options, "cache-file", &obj);
1338 if (tresult == ISC_R_SUCCESS) {
1339 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1340 "'cache-file' cannot be a global "
1341 "option if views are present");
1342 result = ISC_R_FAILURE;
1346 tresult = cfg_map_get(config, "acl", &acls);
1347 if (tresult == ISC_R_SUCCESS) {
1349 cfg_listelt_t *elt2;
1350 const char *aclname;
1352 for (elt = cfg_list_first(acls);
1354 elt = cfg_list_next(elt)) {
1355 cfg_obj_t *acl = cfg_listelt_value(elt);
1358 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
1360 i < sizeof(builtin) / sizeof(builtin[0]);
1362 if (strcasecmp(aclname, builtin[i]) == 0) {
1363 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
1364 "attempt to redefine "
1367 result = ISC_R_FAILURE;
1371 for (elt2 = cfg_list_next(elt);
1373 elt2 = cfg_list_next(elt2)) {
1374 cfg_obj_t *acl2 = cfg_listelt_value(elt2);
1376 name = cfg_obj_asstring(cfg_tuple_get(acl2,
1378 if (strcasecmp(aclname, name) == 0) {
1379 const char *file = cfg_obj_file(acl);
1380 unsigned int line = cfg_obj_line(acl);
1383 file = "<unknown file>";
1385 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
1386 "attempt to redefine "
1387 "acl '%s' previous "
1388 "definition: %s:%u",
1390 result = ISC_R_FAILURE;
1396 tresult = cfg_map_get(config, "kal", &kals);
1397 if (tresult == ISC_R_SUCCESS) {
1399 cfg_listelt_t *elt2;
1400 const char *aclname;
1402 for (elt = cfg_list_first(kals);
1404 elt = cfg_list_next(elt)) {
1405 cfg_obj_t *acl = cfg_listelt_value(elt);
1407 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
1409 for (elt2 = cfg_list_next(elt);
1411 elt2 = cfg_list_next(elt2)) {
1412 cfg_obj_t *acl2 = cfg_listelt_value(elt2);
1414 name = cfg_obj_asstring(cfg_tuple_get(acl2,
1416 if (strcasecmp(aclname, name) == 0) {
1417 const char *file = cfg_obj_file(acl);
1418 unsigned int line = cfg_obj_line(acl);
1421 file = "<unknown file>";
1423 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
1424 "attempt to redefine "
1425 "kal '%s' previous "
1426 "definition: %s:%u",
1428 result = ISC_R_FAILURE;