2 * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.125.14.6 2011-06-17 07:04:31 each Exp $ */
26 #include <isc/base64.h>
27 #include <isc/buffer.h>
30 #include <isc/netaddr.h>
31 #include <isc/parseint.h>
32 #include <isc/region.h>
33 #include <isc/result.h>
34 #include <isc/sockaddr.h>
35 #include <isc/string.h>
36 #include <isc/symtab.h>
40 #include <dns/fixedname.h>
41 #include <dns/rdataclass.h>
42 #include <dns/rdatatype.h>
43 #include <dns/secalg.h>
47 #include <isccfg/aclconf.h>
48 #include <isccfg/cfg.h>
50 #include <bind9/check.h>
53 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
56 isc_mem_free(userarg, key);
60 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
61 isc_result_t result = ISC_R_SUCCESS;
64 dns_fixedname_t fixed;
66 dns_rdataclass_t rdclass;
67 dns_rdatatype_t rdtype;
71 dns_fixedname_init(&fixed);
72 obj = cfg_tuple_get(ent, "class");
73 if (cfg_obj_isstring(obj)) {
75 DE_CONST(cfg_obj_asstring(obj), r.base);
76 r.length = strlen(r.base);
77 tresult = dns_rdataclass_fromtext(&rdclass, &r);
78 if (tresult != ISC_R_SUCCESS) {
79 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
80 "rrset-order: invalid class '%s'",
82 result = ISC_R_FAILURE;
86 obj = cfg_tuple_get(ent, "type");
87 if (cfg_obj_isstring(obj)) {
89 DE_CONST(cfg_obj_asstring(obj), r.base);
90 r.length = strlen(r.base);
91 tresult = dns_rdatatype_fromtext(&rdtype, &r);
92 if (tresult != ISC_R_SUCCESS) {
93 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
94 "rrset-order: invalid type '%s'",
96 result = ISC_R_FAILURE;
100 obj = cfg_tuple_get(ent, "name");
101 if (cfg_obj_isstring(obj)) {
102 str = cfg_obj_asstring(obj);
103 isc_buffer_init(&b, str, strlen(str));
104 isc_buffer_add(&b, strlen(str));
105 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
106 dns_rootname, 0, NULL);
107 if (tresult != ISC_R_SUCCESS) {
108 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
109 "rrset-order: invalid name '%s'", str);
110 result = ISC_R_FAILURE;
114 obj = cfg_tuple_get(ent, "order");
115 if (!cfg_obj_isstring(obj) ||
116 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
117 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
118 "rrset-order: keyword 'order' missing");
119 result = ISC_R_FAILURE;
122 obj = cfg_tuple_get(ent, "ordering");
123 if (!cfg_obj_isstring(obj)) {
124 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
125 "rrset-order: missing ordering");
126 result = ISC_R_FAILURE;
127 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
128 #if !DNS_RDATASET_FIXED
129 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
130 "rrset-order: order 'fixed' was disabled at "
133 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
134 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
135 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
136 "rrset-order: invalid order '%s'",
137 cfg_obj_asstring(obj));
138 result = ISC_R_FAILURE;
144 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
145 isc_result_t result = ISC_R_SUCCESS;
146 isc_result_t tresult;
147 const cfg_listelt_t *element;
148 const cfg_obj_t *obj = NULL;
150 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
153 for (element = cfg_list_first(obj);
155 element = cfg_list_next(element))
157 tresult = check_orderent(cfg_listelt_value(element), logctx);
158 if (tresult != ISC_R_SUCCESS)
165 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
166 const cfg_listelt_t *element;
167 const cfg_obj_t *alternates = NULL;
168 const cfg_obj_t *value;
169 const cfg_obj_t *obj;
171 dns_fixedname_t fixed;
174 isc_result_t result = ISC_R_SUCCESS;
175 isc_result_t tresult;
177 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
179 if (alternates == NULL)
180 return (ISC_R_SUCCESS);
182 obj = cfg_tuple_get(alternates, "port");
183 if (cfg_obj_isuint32(obj)) {
184 isc_uint32_t val = cfg_obj_asuint32(obj);
185 if (val > ISC_UINT16_MAX) {
186 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
187 "port '%u' out of range", val);
188 result = ISC_R_FAILURE;
191 obj = cfg_tuple_get(alternates, "addresses");
192 for (element = cfg_list_first(obj);
194 element = cfg_list_next(element)) {
195 value = cfg_listelt_value(element);
196 if (cfg_obj_issockaddr(value))
198 obj = cfg_tuple_get(value, "name");
199 str = cfg_obj_asstring(obj);
200 isc_buffer_init(&buffer, str, strlen(str));
201 isc_buffer_add(&buffer, strlen(str));
202 dns_fixedname_init(&fixed);
203 name = dns_fixedname_name(&fixed);
204 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
206 if (tresult != ISC_R_SUCCESS) {
207 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
208 "bad name '%s'", str);
209 result = ISC_R_FAILURE;
211 obj = cfg_tuple_get(value, "port");
212 if (cfg_obj_isuint32(obj)) {
213 isc_uint32_t val = cfg_obj_asuint32(obj);
214 if (val > ISC_UINT16_MAX) {
215 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
216 "port '%u' out of range", val);
217 result = ISC_R_FAILURE;
225 check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
228 const cfg_obj_t *forward = NULL;
229 const cfg_obj_t *forwarders = NULL;
231 (void)cfg_map_get(options, "forward", &forward);
232 (void)cfg_map_get(options, "forwarders", &forwarders);
234 if (forwarders != NULL && global != NULL) {
235 const char *file = cfg_obj_file(global);
236 unsigned int line = cfg_obj_line(global);
237 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
238 "forwarders declared in root zone and "
239 "in general configuration: %s:%u",
241 return (ISC_R_FAILURE);
243 if (forward != NULL && forwarders == NULL) {
244 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
245 "no matching 'forwarders' statement");
246 return (ISC_R_FAILURE);
248 return (ISC_R_SUCCESS);
252 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
253 isc_result_t result = ISC_R_SUCCESS;
254 isc_result_t tresult;
255 const cfg_listelt_t *element;
258 dns_fixedname_t fixed;
260 const cfg_obj_t *obj;
262 dns_fixedname_init(&fixed);
263 name = dns_fixedname_name(&fixed);
264 obj = cfg_tuple_get(disabled, "name");
265 str = cfg_obj_asstring(obj);
266 isc_buffer_init(&b, str, strlen(str));
267 isc_buffer_add(&b, strlen(str));
268 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
269 if (tresult != ISC_R_SUCCESS) {
270 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
271 "bad domain name '%s'", str);
275 obj = cfg_tuple_get(disabled, "algorithms");
277 for (element = cfg_list_first(obj);
279 element = cfg_list_next(element))
283 isc_result_t tresult;
285 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
286 r.length = strlen(r.base);
288 tresult = dns_secalg_fromtext(&alg, &r);
289 if (tresult != ISC_R_SUCCESS) {
291 result = isc_parse_uint8(&ui, r.base, 10);
293 if (tresult != ISC_R_SUCCESS) {
294 cfg_obj_log(cfg_listelt_value(element), logctx,
295 ISC_LOG_ERROR, "invalid algorithm '%s'",
304 nameexist(const cfg_obj_t *obj, const char *name, int value,
305 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
312 isc_symvalue_t symvalue;
314 key = isc_mem_strdup(mctx, name);
316 return (ISC_R_NOMEMORY);
317 symvalue.as_cpointer = obj;
318 result = isc_symtab_define(symtab, key, value, symvalue,
319 isc_symexists_reject);
320 if (result == ISC_R_EXISTS) {
321 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
322 &symvalue) == ISC_R_SUCCESS);
323 file = cfg_obj_file(symvalue.as_cpointer);
324 line = cfg_obj_line(symvalue.as_cpointer);
327 file = "<unknown file>";
328 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
329 isc_mem_free(mctx, key);
330 result = ISC_R_EXISTS;
331 } else if (result != ISC_R_SUCCESS) {
332 isc_mem_free(mctx, key);
338 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
341 const cfg_obj_t *obj;
342 char namebuf[DNS_NAME_FORMATSIZE];
344 dns_fixedname_t fixed;
347 isc_result_t result = ISC_R_SUCCESS;
349 dns_fixedname_init(&fixed);
350 name = dns_fixedname_name(&fixed);
351 obj = cfg_tuple_get(secure, "name");
352 str = cfg_obj_asstring(obj);
353 isc_buffer_init(&b, str, strlen(str));
354 isc_buffer_add(&b, strlen(str));
355 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
356 if (result != ISC_R_SUCCESS) {
357 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
358 "bad domain name '%s'", str);
360 dns_name_format(name, namebuf, sizeof(namebuf));
361 result = nameexist(secure, namebuf, 1, symtab,
362 "dnssec-must-be-secure '%s': already "
363 "exists previous definition: %s:%u",
370 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
371 const cfg_obj_t *voptions, const cfg_obj_t *config,
372 isc_log_t *logctx, isc_mem_t *mctx)
375 const cfg_obj_t *aclobj = NULL;
376 const cfg_obj_t *options;
377 dns_acl_t *acl = NULL;
379 if (zconfig != NULL) {
380 options = cfg_tuple_get(zconfig, "options");
381 cfg_map_get(options, aclname, &aclobj);
383 if (voptions != NULL && aclobj == NULL)
384 cfg_map_get(voptions, aclname, &aclobj);
385 if (config != NULL && aclobj == NULL) {
387 cfg_map_get(config, "options", &options);
389 cfg_map_get(options, aclname, &aclobj);
392 return (ISC_R_SUCCESS);
393 result = cfg_acl_fromconfig(aclobj, config, logctx,
394 actx, mctx, 0, &acl);
396 dns_acl_detach(&acl);
401 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
402 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
404 isc_result_t result = ISC_R_SUCCESS, tresult;
407 static const char *acls[] = { "allow-query", "allow-query-on",
408 "allow-query-cache", "allow-query-cache-on",
409 "blackhole", "match-clients", "match-destinations",
410 "sortlist", "filter-aaaa", NULL };
412 while (acls[i] != NULL) {
413 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
415 if (tresult != ISC_R_SUCCESS)
421 static const unsigned char zeros[16];
424 check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
425 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
427 isc_result_t result = ISC_R_SUCCESS;
428 const cfg_obj_t *dns64 = NULL;
429 const cfg_obj_t *options;
430 const cfg_listelt_t *element;
431 const cfg_obj_t *map, *obj;
432 isc_netaddr_t na, sa;
433 unsigned int prefixlen;
437 static const char *acls[] = { "client", "exclude", "mapped", NULL};
439 if (voptions != NULL)
440 cfg_map_get(voptions, "dns64", &dns64);
441 if (config != NULL && dns64 == NULL) {
443 cfg_map_get(config, "options", &options);
445 cfg_map_get(options, "dns64", &dns64);
448 return (ISC_R_SUCCESS);
450 for (element = cfg_list_first(dns64);
452 element = cfg_list_next(element))
454 map = cfg_listelt_value(element);
455 obj = cfg_map_getname(map);
457 cfg_obj_asnetprefix(obj, &na, &prefixlen);
458 if (na.family != AF_INET6) {
459 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
460 "dns64 requires a IPv6 prefix");
461 result = ISC_R_FAILURE;
465 if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
466 prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
467 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
468 "bad prefix length %u [32/40/48/56/64/96]",
470 result = ISC_R_FAILURE;
474 for (i = 0; acls[i] != NULL; i++) {
476 (void)cfg_map_get(map, acls[i], &obj);
478 dns_acl_t *acl = NULL;
479 isc_result_t tresult;
481 tresult = cfg_acl_fromconfig(obj, config,
485 dns_acl_detach(&acl);
486 if (tresult != ISC_R_SUCCESS)
492 (void)cfg_map_get(map, "suffix", &obj);
494 isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
495 if (sa.family != AF_INET6) {
496 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
497 "dns64 requires a IPv6 suffix");
498 result = ISC_R_FAILURE;
501 nbytes = prefixlen / 8 + 4;
502 if (prefixlen >= 32 && prefixlen <= 64)
504 if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
505 char netaddrbuf[ISC_NETADDR_FORMATSIZE];
506 isc_netaddr_format(&sa, netaddrbuf,
508 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
509 "bad suffix '%s' leading "
510 "%u octets not zeros",
512 result = ISC_R_FAILURE;
522 * Check allow-recursion and allow-recursion-on acls, and also log a
523 * warning if they're inconsistent with the "recursion" option.
526 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
527 const char *viewname, const cfg_obj_t *config,
528 isc_log_t *logctx, isc_mem_t *mctx)
530 const cfg_obj_t *options, *aclobj, *obj = NULL;
531 dns_acl_t *acl = NULL;
532 isc_result_t result = ISC_R_SUCCESS, tresult;
533 isc_boolean_t recursion;
534 const char *forview = " for view ";
537 static const char *acls[] = { "allow-recursion", "allow-recursion-on",
540 if (voptions != NULL)
541 cfg_map_get(voptions, "recursion", &obj);
542 if (obj == NULL && config != NULL) {
544 cfg_map_get(config, "options", &options);
546 cfg_map_get(options, "recursion", &obj);
549 recursion = ISC_TRUE;
551 recursion = cfg_obj_asboolean(obj);
553 if (viewname == NULL) {
558 for (i = 0; acls[i] != NULL; i++) {
559 aclobj = options = NULL;
562 if (voptions != NULL)
563 cfg_map_get(voptions, acls[i], &aclobj);
564 if (config != NULL && aclobj == NULL) {
566 cfg_map_get(config, "options", &options);
568 cfg_map_get(options, acls[i], &aclobj);
573 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
574 actx, mctx, 0, &acl);
576 if (tresult != ISC_R_SUCCESS)
582 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
583 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
584 "both \"recursion no;\" and "
586 acls[i], forview, viewname);
590 dns_acl_detach(&acl);
597 check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
598 const char *viewname, const cfg_obj_t *config,
599 isc_log_t *logctx, isc_mem_t *mctx)
601 const cfg_obj_t *options, *aclobj, *obj = NULL;
602 dns_acl_t *acl = NULL;
603 isc_result_t result = ISC_R_SUCCESS, tresult;
604 dns_v4_aaaa_t filter;
605 const char *forview = " for view ";
607 if (voptions != NULL)
608 cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
609 if (obj == NULL && config != NULL) {
611 cfg_map_get(config, "options", &options);
613 cfg_map_get(options, "filter-aaaa-on-v4", &obj);
617 filter = dns_v4_aaaa_ok; /* default */
618 else if (cfg_obj_isboolean(obj))
619 filter = cfg_obj_asboolean(obj) ? dns_v4_aaaa_filter :
622 filter = dns_v4_aaaa_break_dnssec; /* break-dnssec */
624 if (viewname == NULL) {
629 aclobj = options = NULL;
632 if (voptions != NULL)
633 cfg_map_get(voptions, "filter-aaaa", &aclobj);
634 if (config != NULL && aclobj == NULL) {
636 cfg_map_get(config, "options", &options);
638 cfg_map_get(options, "filter-aaaa", &aclobj);
643 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
644 actx, mctx, 0, &acl);
646 if (tresult != ISC_R_SUCCESS) {
648 } else if (filter != dns_v4_aaaa_ok && dns_acl_isnone(acl)) {
649 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
650 "both \"filter-aaaa-on-v4 %s;\" and "
651 "\"filter-aaaa\" is 'none;'%s%s",
652 filter == dns_v4_aaaa_break_dnssec ?
653 "break-dnssec" : "yes", forview, viewname);
654 result = ISC_R_FAILURE;
655 } else if (filter == dns_v4_aaaa_ok && !dns_acl_isnone(acl)) {
656 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
657 "both \"filter-aaaa-on-v4 no;\" and "
658 "\"filter-aaaa\" is set%s%s", forview, viewname);
659 result = ISC_R_FAILURE;
663 dns_acl_detach(&acl);
675 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
676 isc_result_t result = ISC_R_SUCCESS;
677 isc_result_t tresult;
679 const cfg_obj_t *obj = NULL;
680 const cfg_obj_t *resignobj = NULL;
681 const cfg_listelt_t *element;
682 isc_symtab_t *symtab = NULL;
683 dns_fixedname_t fixed;
688 static intervaltable intervals[] = {
689 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
690 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
691 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
692 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
693 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
694 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
695 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
696 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
699 static const char *server_contact[] = {
700 "empty-server", "empty-contact",
701 "dns64-server", "dns64-contact",
706 * Check that fields specified in units of time other than seconds
707 * have reasonable values.
709 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
712 (void)cfg_map_get(options, intervals[i].name, &obj);
715 val = cfg_obj_asuint32(obj);
716 if (val > intervals[i].max) {
717 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
718 "%s '%u' is out of range (0..%u)",
719 intervals[i].name, val,
721 result = ISC_R_RANGE;
722 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
723 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
724 "%s '%d' is out of range",
725 intervals[i].name, val);
726 result = ISC_R_RANGE;
731 cfg_map_get(options, "sig-validity-interval", &obj);
733 isc_uint32_t validity, resign = 0;
735 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
736 resignobj = cfg_tuple_get(obj, "re-sign");
737 if (!cfg_obj_isvoid(resignobj))
738 resign = cfg_obj_asuint32(resignobj);
740 if (validity > 3660 || validity == 0) { /* 10 years */
741 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
742 "%s '%u' is out of range (1..3660)",
743 "sig-validity-interval", validity);
744 result = ISC_R_RANGE;
747 if (!cfg_obj_isvoid(resignobj)) {
748 if (resign > 3660 || resign == 0) { /* 10 years */
749 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
750 "%s '%u' is out of range (1..3660)",
751 "sig-validity-interval (re-sign)",
753 result = ISC_R_RANGE;
754 } else if ((validity > 7 && validity < resign) ||
755 (validity <= 7 && validity * 24 < resign)) {
756 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
757 "validity interval (%u days) "
758 "less than re-signing interval "
759 "(%u %s)", validity, resign,
760 (validity > 7) ? "days" : "hours");
761 result = ISC_R_RANGE;
767 (void)cfg_map_get(options, "preferred-glue", &obj);
770 str = cfg_obj_asstring(obj);
771 if (strcasecmp(str, "a") != 0 &&
772 strcasecmp(str, "aaaa") != 0 &&
773 strcasecmp(str, "none") != 0)
774 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
775 "preferred-glue unexpected value '%s'",
780 (void)cfg_map_get(options, "root-delegation-only", &obj);
782 if (!cfg_obj_isvoid(obj)) {
783 const cfg_listelt_t *element;
784 const cfg_obj_t *exclude;
786 dns_fixedname_t fixed;
790 dns_fixedname_init(&fixed);
791 name = dns_fixedname_name(&fixed);
792 for (element = cfg_list_first(obj);
794 element = cfg_list_next(element)) {
795 exclude = cfg_listelt_value(element);
796 str = cfg_obj_asstring(exclude);
797 isc_buffer_init(&b, str, strlen(str));
798 isc_buffer_add(&b, strlen(str));
799 tresult = dns_name_fromtext(name, &b,
802 if (tresult != ISC_R_SUCCESS) {
803 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
804 "bad domain name '%s'",
813 * Set supported DNSSEC algorithms.
816 (void)cfg_map_get(options, "disable-algorithms", &obj);
818 for (element = cfg_list_first(obj);
820 element = cfg_list_next(element))
822 obj = cfg_listelt_value(element);
823 tresult = disabled_algorithms(obj, logctx);
824 if (tresult != ISC_R_SUCCESS)
829 dns_fixedname_init(&fixed);
830 name = dns_fixedname_name(&fixed);
833 * Check the DLV zone name.
836 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
838 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
840 if (tresult != ISC_R_SUCCESS)
842 for (element = cfg_list_first(obj);
844 element = cfg_list_next(element))
847 const cfg_obj_t *anchor;
849 obj = cfg_listelt_value(element);
851 dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
852 anchor = cfg_tuple_get(obj, "trust-anchor");
855 * If domain is "auto" and trust anchor is missing,
856 * skip remaining tests
858 if (!strcmp(dlv, "auto") && cfg_obj_isvoid(anchor))
861 isc_buffer_init(&b, dlv, strlen(dlv));
862 isc_buffer_add(&b, strlen(dlv));
863 tresult = dns_name_fromtext(name, &b, dns_rootname,
865 if (tresult != ISC_R_SUCCESS) {
866 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
867 "bad domain name '%s'", dlv);
871 if (symtab != NULL) {
872 tresult = nameexist(obj, dlv, 1, symtab,
873 "dnssec-lookaside '%s': "
874 "already exists previous "
877 if (tresult != ISC_R_SUCCESS &&
878 result == ISC_R_SUCCESS)
882 * XXXMPA to be removed when multiple lookaside
883 * namespaces are supported.
885 if (!dns_name_equal(dns_rootname, name)) {
886 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
887 "dnssec-lookaside '%s': "
888 "non-root not yet supported", dlv);
889 if (result == ISC_R_SUCCESS)
890 result = ISC_R_FAILURE;
893 if (!cfg_obj_isvoid(anchor)) {
894 dlv = cfg_obj_asstring(anchor);
895 isc_buffer_init(&b, dlv, strlen(dlv));
896 isc_buffer_add(&b, strlen(dlv));
897 tresult = dns_name_fromtext(name, &b,
901 if (tresult != ISC_R_SUCCESS) {
902 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
903 "bad domain name '%s'",
905 if (result == ISC_R_SUCCESS)
909 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
910 "dnssec-lookaside requires "
911 "either 'auto' or a domain and "
913 if (result == ISC_R_SUCCESS)
914 result = ISC_R_FAILURE;
919 isc_symtab_destroy(&symtab);
923 * Check dnssec-must-be-secure.
926 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
928 isc_symtab_t *symtab = NULL;
929 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
931 if (tresult != ISC_R_SUCCESS)
933 for (element = cfg_list_first(obj);
935 element = cfg_list_next(element))
937 obj = cfg_listelt_value(element);
938 tresult = mustbesecure(obj, symtab, logctx, mctx);
939 if (tresult != ISC_R_SUCCESS)
943 isc_symtab_destroy(&symtab);
947 * Check server/contacts for syntactic validity.
949 for (i= 0; server_contact[i] != NULL; i++) {
951 (void)cfg_map_get(options, server_contact[i], &obj);
953 str = cfg_obj_asstring(obj);
954 isc_buffer_init(&b, str, strlen(str));
955 isc_buffer_add(&b, strlen(str));
956 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
957 &b, dns_rootname, 0, NULL);
958 if (tresult != ISC_R_SUCCESS) {
959 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
960 "%s: invalid name '%s'",
961 server_contact[i], str);
962 result = ISC_R_FAILURE;
968 * Check empty zone configuration.
971 (void)cfg_map_get(options, "disable-empty-zone", &obj);
972 for (element = cfg_list_first(obj);
974 element = cfg_list_next(element))
976 obj = cfg_listelt_value(element);
977 str = cfg_obj_asstring(obj);
978 isc_buffer_init(&b, str, strlen(str));
979 isc_buffer_add(&b, strlen(str));
980 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
981 dns_rootname, 0, NULL);
982 if (tresult != ISC_R_SUCCESS) {
983 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
984 "disable-empty-zone: invalid name '%s'",
986 result = ISC_R_FAILURE;
991 * Check that server-id is not too long.
992 * 1024 bytes should be big enough.
995 (void)cfg_map_get(options, "server-id", &obj);
996 if (obj != NULL && cfg_obj_isstring(obj) &&
997 strlen(cfg_obj_asstring(obj)) > 1024U) {
998 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
999 "'server-id' too big (>1024 bytes)");
1000 result = ISC_R_FAILURE;
1007 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
1008 isc_result_t result;
1009 const cfg_obj_t *masters = NULL;
1010 const cfg_listelt_t *elt;
1012 result = cfg_map_get(cctx, "masters", &masters);
1013 if (result != ISC_R_SUCCESS)
1015 for (elt = cfg_list_first(masters);
1017 elt = cfg_list_next(elt)) {
1018 const cfg_obj_t *list;
1019 const char *listname;
1021 list = cfg_listelt_value(elt);
1022 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
1024 if (strcasecmp(listname, name) == 0) {
1026 return (ISC_R_SUCCESS);
1029 return (ISC_R_NOTFOUND);
1033 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
1034 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
1036 isc_result_t result = ISC_R_SUCCESS;
1037 isc_result_t tresult;
1038 isc_uint32_t count = 0;
1039 isc_symtab_t *symtab = NULL;
1040 isc_symvalue_t symvalue;
1041 const cfg_listelt_t *element;
1042 const cfg_listelt_t **stack = NULL;
1043 isc_uint32_t stackcount = 0, pushed = 0;
1044 const cfg_obj_t *list;
1046 REQUIRE(countp != NULL);
1047 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1048 if (result != ISC_R_SUCCESS) {
1054 list = cfg_tuple_get(obj, "addresses");
1055 element = cfg_list_first(list);
1059 element = cfg_list_next(element))
1061 const char *listname;
1062 const cfg_obj_t *addr;
1063 const cfg_obj_t *key;
1065 addr = cfg_tuple_get(cfg_listelt_value(element),
1067 key = cfg_tuple_get(cfg_listelt_value(element), "key");
1069 if (cfg_obj_issockaddr(addr)) {
1073 if (!cfg_obj_isvoid(key)) {
1074 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1075 "unexpected token '%s'",
1076 cfg_obj_asstring(key));
1077 if (result == ISC_R_SUCCESS)
1078 result = ISC_R_FAILURE;
1080 listname = cfg_obj_asstring(addr);
1081 symvalue.as_cpointer = addr;
1082 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
1083 isc_symexists_reject);
1084 if (tresult == ISC_R_EXISTS)
1086 tresult = get_masters_def(config, listname, &obj);
1087 if (tresult != ISC_R_SUCCESS) {
1088 if (result == ISC_R_SUCCESS)
1090 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
1091 "unable to find masters list '%s'",
1096 if (stackcount == pushed) {
1098 isc_uint32_t newlen = stackcount + 16;
1099 size_t newsize, oldsize;
1101 newsize = newlen * sizeof(*stack);
1102 oldsize = stackcount * sizeof(*stack);
1103 new = isc_mem_get(mctx, newsize);
1106 if (stackcount != 0) {
1109 DE_CONST(stack, ptr);
1110 memcpy(new, stack, oldsize);
1111 isc_mem_put(mctx, ptr, oldsize);
1114 stackcount = newlen;
1116 stack[pushed++] = cfg_list_next(element);
1120 element = stack[--pushed];
1124 if (stack != NULL) {
1127 DE_CONST(stack, ptr);
1128 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1130 isc_symtab_destroy(&symtab);
1136 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1137 isc_result_t result = ISC_R_SUCCESS;
1138 isc_result_t tresult;
1139 const cfg_listelt_t *element;
1140 const cfg_listelt_t *element2;
1141 dns_fixedname_t fixed;
1145 /* Check for "update-policy local;" */
1146 if (cfg_obj_isstring(policy) &&
1147 strcmp("local", cfg_obj_asstring(policy)) == 0)
1148 return (ISC_R_SUCCESS);
1150 /* Now check the grant policy */
1151 for (element = cfg_list_first(policy);
1153 element = cfg_list_next(element))
1155 const cfg_obj_t *stmt = cfg_listelt_value(element);
1156 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1157 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1158 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1159 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1161 dns_fixedname_init(&fixed);
1162 str = cfg_obj_asstring(identity);
1163 isc_buffer_init(&b, str, strlen(str));
1164 isc_buffer_add(&b, strlen(str));
1165 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1166 dns_rootname, 0, NULL);
1167 if (tresult != ISC_R_SUCCESS) {
1168 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1169 "'%s' is not a valid name", str);
1173 if (tresult == ISC_R_SUCCESS &&
1174 strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
1175 dns_fixedname_init(&fixed);
1176 str = cfg_obj_asstring(dname);
1177 isc_buffer_init(&b, str, strlen(str));
1178 isc_buffer_add(&b, strlen(str));
1179 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
1180 &b, dns_rootname, 0, NULL);
1181 if (tresult != ISC_R_SUCCESS) {
1182 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1183 "'%s' is not a valid name", str);
1188 if (tresult == ISC_R_SUCCESS &&
1189 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
1190 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
1191 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1192 "'%s' is not a wildcard", str);
1193 result = ISC_R_FAILURE;
1196 for (element2 = cfg_list_first(typelist);
1198 element2 = cfg_list_next(element2))
1200 const cfg_obj_t *typeobj;
1202 dns_rdatatype_t type;
1204 typeobj = cfg_listelt_value(element2);
1205 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1206 r.length = strlen(r.base);
1208 tresult = dns_rdatatype_fromtext(&type, &r);
1209 if (tresult != ISC_R_SUCCESS) {
1210 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1211 "'%s' is not a valid type", r.base);
1219 #define MASTERZONE 1
1223 #define FORWARDZONE 16
1224 #define DELEGATIONZONE 32
1225 #define STATICSTUBZONE 64
1226 #define CHECKACL 128
1234 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1235 const cfg_obj_t *config, isc_symtab_t *symtab,
1236 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
1237 isc_log_t *logctx, isc_mem_t *mctx)
1239 const char *znamestr;
1240 const char *typestr;
1242 const cfg_obj_t *zoptions;
1243 const cfg_obj_t *obj = NULL;
1244 isc_result_t result = ISC_R_SUCCESS;
1245 isc_result_t tresult;
1247 dns_rdataclass_t zclass;
1248 dns_fixedname_t fixedname;
1249 dns_name_t *zname = NULL;
1251 isc_boolean_t root = ISC_FALSE;
1252 const cfg_listelt_t *element;
1254 static optionstable options[] = {
1255 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL |
1257 { "allow-notify", SLAVEZONE | CHECKACL },
1258 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1259 { "notify", MASTERZONE | SLAVEZONE },
1260 { "also-notify", MASTERZONE | SLAVEZONE },
1261 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
1262 { "delegation-only", HINTZONE | STUBZONE | DELEGATIONZONE },
1263 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1264 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1265 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
1266 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
1267 { "notify-source", MASTERZONE | SLAVEZONE },
1268 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1269 { "transfer-source", SLAVEZONE | STUBZONE },
1270 { "transfer-source-v6", SLAVEZONE | STUBZONE },
1271 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
1272 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1273 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
1274 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1275 { "max-retry-time", SLAVEZONE | STUBZONE },
1276 { "min-retry-time", SLAVEZONE | STUBZONE },
1277 { "max-refresh-time", SLAVEZONE | STUBZONE },
1278 { "min-refresh-time", SLAVEZONE | STUBZONE },
1279 { "dnssec-secure-to-insecure", MASTERZONE },
1280 { "sig-validity-interval", MASTERZONE },
1281 { "sig-re-signing-interval", MASTERZONE },
1282 { "sig-signing-nodes", MASTERZONE },
1283 { "sig-signing-type", MASTERZONE },
1284 { "sig-signing-signatures", MASTERZONE },
1285 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
1287 { "allow-update", MASTERZONE | CHECKACL },
1288 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1289 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1290 { "journal", MASTERZONE | SLAVEZONE },
1291 { "ixfr-base", MASTERZONE | SLAVEZONE },
1292 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1293 { "masters", SLAVEZONE | STUBZONE },
1294 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1295 { "update-policy", MASTERZONE },
1296 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
1297 { "key-directory", MASTERZONE },
1298 { "check-wildcard", MASTERZONE },
1299 { "check-mx", MASTERZONE },
1300 { "check-dup-records", MASTERZONE },
1301 { "integrity-check", MASTERZONE },
1302 { "check-mx-cname", MASTERZONE },
1303 { "check-srv-cname", MASTERZONE },
1304 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1305 { "update-check-ksk", MASTERZONE },
1306 { "dnssec-dnskey-kskonly", MASTERZONE },
1307 { "auto-dnssec", MASTERZONE },
1308 { "try-tcp-refresh", SLAVEZONE },
1309 { "server-addresses", STATICSTUBZONE },
1310 { "server-names", STATICSTUBZONE },
1313 static optionstable dialups[] = {
1314 { "notify", MASTERZONE | SLAVEZONE },
1315 { "notify-passive", SLAVEZONE },
1316 { "refresh", SLAVEZONE | STUBZONE },
1317 { "passive", SLAVEZONE | STUBZONE },
1320 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1322 zoptions = cfg_tuple_get(zconfig, "options");
1325 (void)cfg_map_get(zoptions, "type", &obj);
1327 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1328 "zone '%s': type not present", znamestr);
1329 return (ISC_R_FAILURE);
1332 typestr = cfg_obj_asstring(obj);
1333 if (strcasecmp(typestr, "master") == 0)
1335 else if (strcasecmp(typestr, "slave") == 0)
1337 else if (strcasecmp(typestr, "stub") == 0)
1339 else if (strcasecmp(typestr, "static-stub") == 0)
1340 ztype = STATICSTUBZONE;
1341 else if (strcasecmp(typestr, "forward") == 0)
1342 ztype = FORWARDZONE;
1343 else if (strcasecmp(typestr, "hint") == 0)
1345 else if (strcasecmp(typestr, "delegation-only") == 0)
1346 ztype = DELEGATIONZONE;
1348 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1349 "zone '%s': invalid type %s",
1351 return (ISC_R_FAILURE);
1354 obj = cfg_tuple_get(zconfig, "class");
1355 if (cfg_obj_isstring(obj)) {
1358 DE_CONST(cfg_obj_asstring(obj), r.base);
1359 r.length = strlen(r.base);
1360 result = dns_rdataclass_fromtext(&zclass, &r);
1361 if (result != ISC_R_SUCCESS) {
1362 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1363 "zone '%s': invalid class %s",
1365 return (ISC_R_FAILURE);
1367 if (zclass != defclass) {
1368 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1369 "zone '%s': class '%s' does not "
1370 "match view/default class",
1372 return (ISC_R_FAILURE);
1377 * Look for an already existing zone.
1378 * We need to make this canonical as isc_symtab_define()
1379 * deals with strings.
1381 dns_fixedname_init(&fixedname);
1382 isc_buffer_init(&b, znamestr, strlen(znamestr));
1383 isc_buffer_add(&b, strlen(znamestr));
1384 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1385 dns_rootname, DNS_NAME_DOWNCASE, NULL);
1386 if (tresult != ISC_R_SUCCESS) {
1387 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1388 "zone '%s': is not a valid name", znamestr);
1389 result = ISC_R_FAILURE;
1391 char namebuf[DNS_NAME_FORMATSIZE];
1393 zname = dns_fixedname_name(&fixedname);
1394 dns_name_format(zname, namebuf, sizeof(namebuf));
1395 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1396 symtab, "zone '%s': already exists "
1397 "previous definition: %s:%u", logctx, mctx);
1398 if (tresult != ISC_R_SUCCESS)
1400 if (dns_name_equal(zname, dns_rootname))
1405 * Look for inappropriate options for the given zone type.
1406 * Check that ACLs expand correctly.
1408 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1410 if ((options[i].allowed & ztype) == 0 &&
1411 cfg_map_get(zoptions, options[i].name, &obj) ==
1414 if (strcmp(options[i].name, "allow-update") != 0 ||
1415 ztype != SLAVEZONE) {
1416 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1417 "option '%s' is not allowed "
1418 "in '%s' zone '%s'",
1419 options[i].name, typestr,
1421 result = ISC_R_FAILURE;
1423 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1424 "option '%s' is not allowed "
1425 "in '%s' zone '%s'",
1426 options[i].name, typestr,
1430 if ((options[i].allowed & ztype) != 0 &&
1431 (options[i].allowed & CHECKACL) != 0) {
1433 tresult = checkacl(options[i].name, actx, zconfig,
1434 voptions, config, logctx, mctx);
1435 if (tresult != ISC_R_SUCCESS)
1442 * Slave & stub zones must have a "masters" field.
1444 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1446 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1447 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1448 "zone '%s': missing 'masters' entry",
1450 result = ISC_R_FAILURE;
1453 tresult = validate_masters(obj, config, &count,
1455 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1457 if (tresult == ISC_R_SUCCESS && count == 0) {
1458 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1459 "zone '%s': empty 'masters' entry",
1461 result = ISC_R_FAILURE;
1467 * Master zones can't have both "allow-update" and "update-policy".
1469 if (ztype == MASTERZONE) {
1470 isc_result_t res1, res2, res3;
1475 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1477 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1478 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1479 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1480 "zone '%s': 'allow-update' is ignored "
1481 "when 'update-policy' is present",
1483 result = ISC_R_FAILURE;
1484 } else if (res2 == ISC_R_SUCCESS &&
1485 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1486 result = ISC_R_FAILURE;
1487 ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS);
1491 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
1492 if (res3 == ISC_R_SUCCESS)
1493 arg = cfg_obj_asstring(obj);
1494 if (strcasecmp(arg, "off") != 0 && !ddns) {
1495 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1496 "'auto-dnssec %s;' requires "
1497 "dynamic DNS to be configured in the zone",
1499 result = ISC_R_FAILURE;
1501 if (strcasecmp(arg, "create") == 0) {
1502 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1503 "'auto-dnssec create;' is not "
1505 result = ISC_R_FAILURE;
1509 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1510 if (res1 == ISC_R_SUCCESS) {
1511 isc_uint32_t type = cfg_obj_asuint32(obj);
1512 if (type < 0xff00U || type > 0xffffU)
1513 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1514 "sig-signing-type: %u out of "
1515 "range [%u..%u]", type,
1517 result = ISC_R_FAILURE;
1522 * Check the excessively complicated "dialup" option.
1524 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1525 const cfg_obj_t *dialup = NULL;
1526 (void)cfg_map_get(zoptions, "dialup", &dialup);
1527 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1528 const char *str = cfg_obj_asstring(dialup);
1530 i < sizeof(dialups) / sizeof(dialups[0]);
1533 if (strcasecmp(dialups[i].name, str) != 0)
1535 if ((dialups[i].allowed & ztype) == 0) {
1536 cfg_obj_log(obj, logctx,
1538 "dialup type '%s' is not "
1541 str, typestr, znamestr);
1542 result = ISC_R_FAILURE;
1546 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1547 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1548 "invalid dialup type '%s' in zone "
1549 "'%s'", str, znamestr);
1550 result = ISC_R_FAILURE;
1556 * Check that forwarding is reasonable.
1560 if (voptions != NULL)
1561 (void)cfg_map_get(voptions, "forwarders", &obj);
1563 const cfg_obj_t *options = NULL;
1564 (void)cfg_map_get(config, "options", &options);
1565 if (options != NULL)
1566 (void)cfg_map_get(options, "forwarders", &obj);
1569 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1570 result = ISC_R_FAILURE;
1573 * Check validity of static stub server addresses.
1576 (void)cfg_map_get(zoptions, "server-addresses", &obj);
1577 if (ztype == STATICSTUBZONE && obj != NULL) {
1578 for (element = cfg_list_first(obj);
1580 element = cfg_list_next(element))
1584 obj = cfg_listelt_value(element);
1585 sa = *cfg_obj_assockaddr(obj);
1587 if (isc_sockaddr_getport(&sa) != 0) {
1588 result = ISC_R_FAILURE;
1589 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1590 "port is not configurable for "
1591 "static stub server-addresses");
1594 isc_netaddr_fromsockaddr(&na, &sa);
1595 if (isc_netaddr_getzone(&na) != 0) {
1596 result = ISC_R_FAILURE;
1597 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1598 "scoped address is not allowed "
1600 "server-addresses");
1606 * Check validity of static stub server names.
1609 (void)cfg_map_get(zoptions, "server-names", &obj);
1610 if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
1611 for (element = cfg_list_first(obj);
1613 element = cfg_list_next(element))
1615 const char *snamestr;
1616 dns_fixedname_t fixed_sname;
1620 obj = cfg_listelt_value(element);
1621 snamestr = cfg_obj_asstring(obj);
1623 dns_fixedname_init(&fixed_sname);
1624 isc_buffer_init(&b2, snamestr, strlen(snamestr));
1625 isc_buffer_add(&b2, strlen(snamestr));
1626 sname = dns_fixedname_name(&fixed_sname);
1627 tresult = dns_name_fromtext(sname, &b2, dns_rootname,
1629 if (tresult != ISC_R_SUCCESS) {
1630 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1631 "server-name '%s' is not a valid "
1633 result = ISC_R_FAILURE;
1634 } else if (dns_name_issubdomain(sname, zname)) {
1635 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1636 "server-name '%s' must not be a "
1637 "subdomain of zone name '%s'",
1638 snamestr, znamestr);
1639 result = ISC_R_FAILURE;
1645 * Check various options.
1647 tresult = check_options(zoptions, logctx, mctx);
1648 if (tresult != ISC_R_SUCCESS)
1652 * If the zone type is rbt/rbt64 then master/hint zones
1653 * require file clauses.
1656 tresult = cfg_map_get(zoptions, "database", &obj);
1657 if (tresult == ISC_R_NOTFOUND ||
1658 (tresult == ISC_R_SUCCESS &&
1659 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1660 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1662 tresult = cfg_map_get(zoptions, "file", &obj);
1663 if (tresult != ISC_R_SUCCESS &&
1664 (ztype == MASTERZONE || ztype == HINTZONE)) {
1665 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1666 "zone '%s': missing 'file' entry",
1676 typedef struct keyalgorithms {
1682 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1683 const cfg_obj_t *algobj = NULL;
1684 const cfg_obj_t *secretobj = NULL;
1685 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1686 const char *algorithm;
1689 isc_result_t result;
1691 unsigned char secretbuf[1024];
1692 static const algorithmtable algorithms[] = {
1693 { "hmac-md5", 128 },
1694 { "hmac-md5.sig-alg.reg.int", 0 },
1695 { "hmac-md5.sig-alg.reg.int.", 0 },
1696 { "hmac-sha1", 160 },
1697 { "hmac-sha224", 224 },
1698 { "hmac-sha256", 256 },
1699 { "hmac-sha384", 384 },
1700 { "hmac-sha512", 512 },
1704 (void)cfg_map_get(key, "algorithm", &algobj);
1705 (void)cfg_map_get(key, "secret", &secretobj);
1706 if (secretobj == NULL || algobj == NULL) {
1707 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1708 "key '%s' must have both 'secret' and "
1709 "'algorithm' defined",
1711 return (ISC_R_FAILURE);
1714 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
1715 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
1716 if (result != ISC_R_SUCCESS) {
1717 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
1718 "bad secret '%s'", isc_result_totext(result));
1722 algorithm = cfg_obj_asstring(algobj);
1723 for (i = 0; algorithms[i].name != NULL; i++) {
1724 len = strlen(algorithms[i].name);
1725 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1726 (algorithm[len] == '\0' ||
1727 (algorithms[i].size != 0 && algorithm[len] == '-')))
1730 if (algorithms[i].name == NULL) {
1731 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1732 "unknown algorithm '%s'", algorithm);
1733 return (ISC_R_NOTFOUND);
1735 if (algorithm[len] == '-') {
1736 isc_uint16_t digestbits;
1737 isc_result_t result;
1738 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1739 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1740 if (result == ISC_R_RANGE ||
1741 digestbits > algorithms[i].size) {
1742 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1743 "key '%s' digest-bits too large "
1744 "[%u..%u]", keyname,
1745 algorithms[i].size / 2,
1746 algorithms[i].size);
1747 return (ISC_R_RANGE);
1749 if ((digestbits % 8) != 0) {
1750 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1751 "key '%s' digest-bits not multiple"
1753 return (ISC_R_RANGE);
1756 * Recommended minima for hmac algorithms.
1758 if ((digestbits < (algorithms[i].size / 2U) ||
1759 (digestbits < 80U)))
1760 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1761 "key '%s' digest-bits too small "
1763 algorithms[i].size/2);
1765 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1766 "key '%s': unable to parse digest-bits",
1771 return (ISC_R_SUCCESS);
1775 * Check key list for duplicates key names and that the key names
1776 * are valid domain names as these keys are used for TSIG.
1778 * Check the key contents for validity.
1781 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
1782 isc_mem_t *mctx, isc_log_t *logctx)
1784 char namebuf[DNS_NAME_FORMATSIZE];
1785 dns_fixedname_t fname;
1787 isc_result_t result = ISC_R_SUCCESS;
1788 isc_result_t tresult;
1789 const cfg_listelt_t *element;
1791 dns_fixedname_init(&fname);
1792 name = dns_fixedname_name(&fname);
1793 for (element = cfg_list_first(keys);
1795 element = cfg_list_next(element))
1797 const cfg_obj_t *key = cfg_listelt_value(element);
1798 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
1799 isc_symvalue_t symvalue;
1803 isc_buffer_init(&b, keyid, strlen(keyid));
1804 isc_buffer_add(&b, strlen(keyid));
1805 tresult = dns_name_fromtext(name, &b, dns_rootname,
1807 if (tresult != ISC_R_SUCCESS) {
1808 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1809 "key '%s': bad key name", keyid);
1813 tresult = bind9_check_key(key, logctx);
1814 if (tresult != ISC_R_SUCCESS)
1817 dns_name_format(name, namebuf, sizeof(namebuf));
1818 keyname = isc_mem_strdup(mctx, namebuf);
1819 if (keyname == NULL)
1820 return (ISC_R_NOMEMORY);
1821 symvalue.as_cpointer = key;
1822 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
1823 isc_symexists_reject);
1824 if (tresult == ISC_R_EXISTS) {
1828 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1829 1, &symvalue) == ISC_R_SUCCESS);
1830 file = cfg_obj_file(symvalue.as_cpointer);
1831 line = cfg_obj_line(symvalue.as_cpointer);
1834 file = "<unknown file>";
1835 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1836 "key '%s': already exists "
1837 "previous definition: %s:%u",
1839 isc_mem_free(mctx, keyname);
1841 } else if (tresult != ISC_R_SUCCESS) {
1842 isc_mem_free(mctx, keyname);
1853 { "transfer-source", "transfer-source-v6" },
1854 { "notify-source", "notify-source-v6" },
1855 { "query-source", "query-source-v6" },
1860 * RNDC keys are not normalised unlike TSIG keys.
1862 * "foo." is different to "foo".
1864 static isc_boolean_t
1865 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
1866 const cfg_listelt_t *element;
1867 const cfg_obj_t *obj;
1870 if (keylist == NULL)
1873 for (element = cfg_list_first(keylist);
1875 element = cfg_list_next(element))
1877 obj = cfg_listelt_value(element);
1878 str = cfg_obj_asstring(cfg_map_getname(obj));
1879 if (!strcasecmp(str, keyname))
1886 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
1887 isc_symtab_t *symtab, isc_log_t *logctx)
1889 dns_fixedname_t fname;
1890 isc_result_t result = ISC_R_SUCCESS;
1891 isc_result_t tresult;
1892 const cfg_listelt_t *e1, *e2;
1893 const cfg_obj_t *v1, *v2, *keys;
1894 const cfg_obj_t *servers;
1895 isc_netaddr_t n1, n2;
1896 unsigned int p1, p2;
1897 const cfg_obj_t *obj;
1898 char buf[ISC_NETADDR_FORMATSIZE];
1899 char namebuf[DNS_NAME_FORMATSIZE];
1904 dns_name_t *keyname;
1907 if (voptions != NULL)
1908 (void)cfg_map_get(voptions, "server", &servers);
1909 if (servers == NULL)
1910 (void)cfg_map_get(config, "server", &servers);
1911 if (servers == NULL)
1912 return (ISC_R_SUCCESS);
1914 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1915 v1 = cfg_listelt_value(e1);
1916 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1918 * Check that unused bits are zero.
1920 tresult = isc_netaddr_prefixok(&n1, p1);
1921 if (tresult != ISC_R_SUCCESS) {
1922 INSIST(tresult == ISC_R_FAILURE);
1923 isc_netaddr_format(&n1, buf, sizeof(buf));
1924 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1925 "server '%s/%u': invalid prefix "
1926 "(extra bits specified)", buf, p1);
1932 if (n1.family == AF_INET)
1933 xfr = sources[source].v6;
1935 xfr = sources[source].v4;
1936 (void)cfg_map_get(v1, xfr, &obj);
1938 isc_netaddr_format(&n1, buf, sizeof(buf));
1939 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1940 "server '%s/%u': %s not legal",
1942 result = ISC_R_FAILURE;
1944 } while (sources[++source].v4 != NULL);
1946 while ((e2 = cfg_list_next(e2)) != NULL) {
1947 v2 = cfg_listelt_value(e2);
1948 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
1949 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
1950 const char *file = cfg_obj_file(v1);
1951 unsigned int line = cfg_obj_line(v1);
1954 file = "<unknown file>";
1956 isc_netaddr_format(&n2, buf, sizeof(buf));
1957 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1958 "server '%s/%u': already exists "
1959 "previous definition: %s:%u",
1960 buf, p2, file, line);
1961 result = ISC_R_FAILURE;
1965 cfg_map_get(v1, "keys", &keys);
1968 * Normalize key name.
1970 keyval = cfg_obj_asstring(keys);
1971 dns_fixedname_init(&fname);
1972 isc_buffer_init(&b, keyval, strlen(keyval));
1973 isc_buffer_add(&b, strlen(keyval));
1974 keyname = dns_fixedname_name(&fname);
1975 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
1977 if (tresult != ISC_R_SUCCESS) {
1978 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
1979 "bad key name '%s'", keyval);
1980 result = ISC_R_FAILURE;
1983 dns_name_format(keyname, namebuf, sizeof(namebuf));
1984 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
1985 if (tresult != ISC_R_SUCCESS) {
1986 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
1987 "unknown key '%s'", keyval);
1988 result = ISC_R_FAILURE;
1996 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
1999 const char *keystr, *keynamestr;
2000 dns_fixedname_t fkeyname;
2001 dns_name_t *keyname;
2004 isc_result_t result = ISC_R_SUCCESS;
2005 isc_result_t tresult;
2006 isc_uint32_t flags, proto, alg;
2007 unsigned char keydata[4096];
2009 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
2010 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
2011 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
2013 dns_fixedname_init(&fkeyname);
2014 keyname = dns_fixedname_name(&fkeyname);
2015 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
2017 isc_buffer_init(&b, keynamestr, strlen(keynamestr));
2018 isc_buffer_add(&b, strlen(keynamestr));
2019 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
2020 if (result != ISC_R_SUCCESS) {
2021 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
2022 isc_result_totext(result));
2023 result = ISC_R_FAILURE;
2026 if (flags > 0xffff) {
2027 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2028 "flags too big: %u\n", flags);
2029 result = ISC_R_FAILURE;
2032 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2033 "protocol too big: %u\n", proto);
2034 result = ISC_R_FAILURE;
2037 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2038 "algorithm too big: %u\n", alg);
2039 result = ISC_R_FAILURE;
2043 const char *initmethod;
2044 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
2046 if (strcasecmp(initmethod, "initial-key") != 0) {
2047 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2048 "managed key '%s': "
2049 "invalid initialization method '%s'",
2050 keynamestr, initmethod);
2051 result = ISC_R_FAILURE;
2055 isc_buffer_init(&b, keydata, sizeof(keydata));
2057 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
2058 tresult = isc_base64_decodestring(keystr, &b);
2060 if (tresult != ISC_R_SUCCESS) {
2061 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2062 "%s", isc_result_totext(tresult));
2063 result = ISC_R_FAILURE;
2065 isc_buffer_usedregion(&b, &r);
2067 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
2068 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
2069 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2070 "%s key '%s' has a weak exponent",
2071 managed ? "managed" : "trusted",
2079 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
2080 const char *viewname, dns_rdataclass_t vclass,
2081 isc_log_t *logctx, isc_mem_t *mctx)
2083 const cfg_obj_t *zones = NULL;
2084 const cfg_obj_t *keys = NULL;
2085 const cfg_listelt_t *element, *element2;
2086 isc_symtab_t *symtab = NULL;
2087 isc_result_t result = ISC_R_SUCCESS;
2088 isc_result_t tresult = ISC_R_SUCCESS;
2089 cfg_aclconfctx_t *actx = NULL;
2090 const cfg_obj_t *obj;
2091 const cfg_obj_t *options = NULL;
2092 isc_boolean_t enablednssec, enablevalidation;
2093 const char *valstr = "no";
2096 * Get global options block
2098 (void)cfg_map_get(config, "options", &options);
2101 * Check that all zone statements are syntactically correct and
2102 * there are no duplicate zones.
2104 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
2105 ISC_FALSE, &symtab);
2106 if (tresult != ISC_R_SUCCESS)
2107 return (ISC_R_NOMEMORY);
2109 cfg_aclconfctx_create(mctx, &actx);
2111 if (voptions != NULL)
2112 (void)cfg_map_get(voptions, "zone", &zones);
2114 (void)cfg_map_get(config, "zone", &zones);
2116 for (element = cfg_list_first(zones);
2118 element = cfg_list_next(element))
2120 isc_result_t tresult;
2121 const cfg_obj_t *zone = cfg_listelt_value(element);
2123 tresult = check_zoneconf(zone, voptions, config, symtab,
2124 vclass, actx, logctx, mctx);
2125 if (tresult != ISC_R_SUCCESS)
2126 result = ISC_R_FAILURE;
2129 isc_symtab_destroy(&symtab);
2132 * Check that forwarding is reasonable.
2134 if (voptions == NULL) {
2135 if (options != NULL)
2136 if (check_forward(options, NULL,
2137 logctx) != ISC_R_SUCCESS)
2138 result = ISC_R_FAILURE;
2140 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
2141 result = ISC_R_FAILURE;
2145 * Check that dual-stack-servers is reasonable.
2147 if (voptions == NULL) {
2148 if (options != NULL)
2149 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2150 result = ISC_R_FAILURE;
2152 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
2153 result = ISC_R_FAILURE;
2157 * Check that rrset-order is reasonable.
2159 if (voptions != NULL) {
2160 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
2161 result = ISC_R_FAILURE;
2165 * Check that all key statements are syntactically correct and
2166 * there are no duplicate keys.
2168 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
2169 ISC_FALSE, &symtab);
2170 if (tresult != ISC_R_SUCCESS)
2171 return (ISC_R_NOMEMORY);
2173 (void)cfg_map_get(config, "key", &keys);
2174 tresult = check_keylist(keys, symtab, mctx, logctx);
2175 if (tresult == ISC_R_EXISTS)
2176 result = ISC_R_FAILURE;
2177 else if (tresult != ISC_R_SUCCESS) {
2178 isc_symtab_destroy(&symtab);
2182 if (voptions != NULL) {
2184 (void)cfg_map_get(voptions, "key", &keys);
2185 tresult = check_keylist(keys, symtab, mctx, logctx);
2186 if (tresult == ISC_R_EXISTS)
2187 result = ISC_R_FAILURE;
2188 else if (tresult != ISC_R_SUCCESS) {
2189 isc_symtab_destroy(&symtab);
2195 * Global servers can refer to keys in views.
2197 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
2198 result = ISC_R_FAILURE;
2200 isc_symtab_destroy(&symtab);
2203 * Check that dnssec-enable/dnssec-validation are sensible.
2206 if (voptions != NULL)
2207 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
2208 if (obj == NULL && options != NULL)
2209 (void)cfg_map_get(options, "dnssec-enable", &obj);
2211 enablednssec = ISC_TRUE;
2213 enablednssec = cfg_obj_asboolean(obj);
2216 if (voptions != NULL)
2217 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
2218 if (obj == NULL && options != NULL)
2219 (void)cfg_map_get(options, "dnssec-validation", &obj);
2221 enablevalidation = enablednssec;
2223 } else if (cfg_obj_isboolean(obj)) {
2224 enablevalidation = cfg_obj_asboolean(obj);
2225 valstr = enablevalidation ? "yes" : "no";
2227 enablevalidation = ISC_TRUE;
2231 if (enablevalidation && !enablednssec)
2232 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2233 "'dnssec-validation %s;' and 'dnssec-enable no;'",
2237 * Check trusted-keys and managed-keys.
2240 if (voptions != NULL)
2241 (void)cfg_map_get(voptions, "trusted-keys", &keys);
2243 (void)cfg_map_get(config, "trusted-keys", &keys);
2245 for (element = cfg_list_first(keys);
2247 element = cfg_list_next(element))
2249 const cfg_obj_t *keylist = cfg_listelt_value(element);
2250 for (element2 = cfg_list_first(keylist);
2252 element2 = cfg_list_next(element2)) {
2253 obj = cfg_listelt_value(element2);
2254 tresult = check_trusted_key(obj, ISC_FALSE, logctx);
2255 if (tresult != ISC_R_SUCCESS)
2261 if (voptions != NULL)
2262 (void)cfg_map_get(voptions, "managed-keys", &keys);
2264 (void)cfg_map_get(config, "managed-keys", &keys);
2266 for (element = cfg_list_first(keys);
2268 element = cfg_list_next(element))
2270 const cfg_obj_t *keylist = cfg_listelt_value(element);
2271 for (element2 = cfg_list_first(keylist);
2273 element2 = cfg_list_next(element2)) {
2274 obj = cfg_listelt_value(element2);
2275 tresult = check_trusted_key(obj, ISC_TRUE, logctx);
2276 if (tresult != ISC_R_SUCCESS)
2283 if (voptions != NULL)
2284 tresult = check_options(voptions, logctx, mctx);
2286 tresult = check_options(config, logctx, mctx);
2287 if (tresult != ISC_R_SUCCESS)
2290 tresult = check_viewacls(actx, voptions, config, logctx, mctx);
2291 if (tresult != ISC_R_SUCCESS)
2294 tresult = check_recursionacls(actx, voptions, viewname,
2295 config, logctx, mctx);
2296 if (tresult != ISC_R_SUCCESS)
2299 tresult = check_filteraaaa(actx, voptions, viewname, config,
2301 if (tresult != ISC_R_SUCCESS)
2304 tresult = check_dns64(actx, voptions, config, logctx, mctx);
2305 if (tresult != ISC_R_SUCCESS)
2308 cfg_aclconfctx_detach(&actx);
2314 default_channels[] = {
2323 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
2326 const cfg_obj_t *categories = NULL;
2327 const cfg_obj_t *category;
2328 const cfg_obj_t *channels = NULL;
2329 const cfg_obj_t *channel;
2330 const cfg_listelt_t *element;
2331 const cfg_listelt_t *delement;
2332 const char *channelname;
2333 const char *catname;
2334 const cfg_obj_t *fileobj = NULL;
2335 const cfg_obj_t *syslogobj = NULL;
2336 const cfg_obj_t *nullobj = NULL;
2337 const cfg_obj_t *stderrobj = NULL;
2338 const cfg_obj_t *logobj = NULL;
2339 isc_result_t result = ISC_R_SUCCESS;
2340 isc_result_t tresult;
2341 isc_symtab_t *symtab = NULL;
2342 isc_symvalue_t symvalue;
2345 (void)cfg_map_get(config, "logging", &logobj);
2347 return (ISC_R_SUCCESS);
2349 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
2350 if (result != ISC_R_SUCCESS)
2353 symvalue.as_cpointer = NULL;
2354 for (i = 0; default_channels[i] != NULL; i++) {
2355 tresult = isc_symtab_define(symtab, default_channels[i], 1,
2356 symvalue, isc_symexists_replace);
2357 if (tresult != ISC_R_SUCCESS)
2361 cfg_map_get(logobj, "channel", &channels);
2363 for (element = cfg_list_first(channels);
2365 element = cfg_list_next(element))
2367 channel = cfg_listelt_value(element);
2368 channelname = cfg_obj_asstring(cfg_map_getname(channel));
2369 fileobj = syslogobj = nullobj = stderrobj = NULL;
2370 (void)cfg_map_get(channel, "file", &fileobj);
2371 (void)cfg_map_get(channel, "syslog", &syslogobj);
2372 (void)cfg_map_get(channel, "null", &nullobj);
2373 (void)cfg_map_get(channel, "stderr", &stderrobj);
2375 if (fileobj != NULL)
2377 if (syslogobj != NULL)
2379 if (nullobj != NULL)
2381 if (stderrobj != NULL)
2384 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2385 "channel '%s': exactly one of file, syslog, "
2386 "null, and stderr must be present",
2388 result = ISC_R_FAILURE;
2390 tresult = isc_symtab_define(symtab, channelname, 1,
2391 symvalue, isc_symexists_replace);
2392 if (tresult != ISC_R_SUCCESS)
2396 cfg_map_get(logobj, "category", &categories);
2398 for (element = cfg_list_first(categories);
2400 element = cfg_list_next(element))
2402 category = cfg_listelt_value(element);
2403 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
2404 if (isc_log_categorybyname(logctx, catname) == NULL) {
2405 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
2406 "undefined category: '%s'", catname);
2407 result = ISC_R_FAILURE;
2409 channels = cfg_tuple_get(category, "destinations");
2410 for (delement = cfg_list_first(channels);
2412 delement = cfg_list_next(delement))
2414 channel = cfg_listelt_value(delement);
2415 channelname = cfg_obj_asstring(channel);
2416 tresult = isc_symtab_lookup(symtab, channelname, 1,
2418 if (tresult != ISC_R_SUCCESS) {
2419 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2420 "undefined channel: '%s'",
2426 isc_symtab_destroy(&symtab);
2431 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
2434 isc_result_t result = ISC_R_SUCCESS;
2435 const cfg_obj_t *control_keylist;
2436 const cfg_listelt_t *element;
2437 const cfg_obj_t *key;
2440 control_keylist = cfg_tuple_get(control, "keys");
2441 if (cfg_obj_isvoid(control_keylist))
2442 return (ISC_R_SUCCESS);
2444 for (element = cfg_list_first(control_keylist);
2446 element = cfg_list_next(element))
2448 key = cfg_listelt_value(element);
2449 keyval = cfg_obj_asstring(key);
2451 if (!rndckey_exists(keylist, keyval)) {
2452 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2453 "unknown key '%s'", keyval);
2454 result = ISC_R_NOTFOUND;
2461 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
2464 isc_result_t result = ISC_R_SUCCESS, tresult;
2465 cfg_aclconfctx_t *actx = NULL;
2466 const cfg_listelt_t *element, *element2;
2467 const cfg_obj_t *allow;
2468 const cfg_obj_t *control;
2469 const cfg_obj_t *controls;
2470 const cfg_obj_t *controlslist = NULL;
2471 const cfg_obj_t *inetcontrols;
2472 const cfg_obj_t *unixcontrols;
2473 const cfg_obj_t *keylist = NULL;
2475 isc_uint32_t perm, mask;
2476 dns_acl_t *acl = NULL;
2477 isc_sockaddr_t addr;
2480 (void)cfg_map_get(config, "controls", &controlslist);
2481 if (controlslist == NULL)
2482 return (ISC_R_SUCCESS);
2484 (void)cfg_map_get(config, "key", &keylist);
2486 cfg_aclconfctx_create(mctx, &actx);
2489 * INET: Check allow clause.
2490 * UNIX: Check "perm" for sanity, check path length.
2492 for (element = cfg_list_first(controlslist);
2494 element = cfg_list_next(element)) {
2495 controls = cfg_listelt_value(element);
2496 unixcontrols = NULL;
2497 inetcontrols = NULL;
2498 (void)cfg_map_get(controls, "unix", &unixcontrols);
2499 (void)cfg_map_get(controls, "inet", &inetcontrols);
2500 for (element2 = cfg_list_first(inetcontrols);
2502 element2 = cfg_list_next(element2)) {
2503 control = cfg_listelt_value(element2);
2504 allow = cfg_tuple_get(control, "allow");
2505 tresult = cfg_acl_fromconfig(allow, config, logctx,
2506 actx, mctx, 0, &acl);
2508 dns_acl_detach(&acl);
2509 if (tresult != ISC_R_SUCCESS)
2511 tresult = bind9_check_controlskeys(control, keylist,
2513 if (tresult != ISC_R_SUCCESS)
2516 for (element2 = cfg_list_first(unixcontrols);
2518 element2 = cfg_list_next(element2)) {
2519 control = cfg_listelt_value(element2);
2520 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
2521 tresult = isc_sockaddr_frompath(&addr, path);
2522 if (tresult == ISC_R_NOSPACE) {
2523 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
2524 "unix control '%s': path too long",
2526 result = ISC_R_NOSPACE;
2528 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
2529 for (i = 0; i < 3; i++) {
2530 #ifdef NEED_SECURE_DIRECTORY
2531 mask = (0x1 << (i*3)); /* SEARCH */
2533 mask = (0x6 << (i*3)); /* READ + WRITE */
2535 if ((perm & mask) == mask)
2539 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2540 "unix control '%s' allows access "
2541 "to everyone", path);
2542 } else if (i == 3) {
2543 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2544 "unix control '%s' allows access "
2547 tresult = bind9_check_controlskeys(control, keylist,
2549 if (tresult != ISC_R_SUCCESS)
2553 cfg_aclconfctx_detach(&actx);
2558 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
2561 const cfg_obj_t *options = NULL;
2562 const cfg_obj_t *views = NULL;
2563 const cfg_obj_t *acls = NULL;
2564 const cfg_obj_t *kals = NULL;
2565 const cfg_obj_t *obj;
2566 const cfg_listelt_t *velement;
2567 isc_result_t result = ISC_R_SUCCESS;
2568 isc_result_t tresult;
2569 isc_symtab_t *symtab = NULL;
2571 static const char *builtin[] = { "localhost", "localnets",
2574 (void)cfg_map_get(config, "options", &options);
2576 if (options != NULL &&
2577 check_options(options, logctx, mctx) != ISC_R_SUCCESS)
2578 result = ISC_R_FAILURE;
2580 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
2581 result = ISC_R_FAILURE;
2583 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
2584 result = ISC_R_FAILURE;
2586 if (options != NULL &&
2587 check_order(options, logctx) != ISC_R_SUCCESS)
2588 result = ISC_R_FAILURE;
2590 (void)cfg_map_get(config, "view", &views);
2592 if (views != NULL && options != NULL)
2593 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2594 result = ISC_R_FAILURE;
2596 if (views == NULL) {
2597 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
2598 logctx, mctx) != ISC_R_SUCCESS)
2599 result = ISC_R_FAILURE;
2601 const cfg_obj_t *zones = NULL;
2603 (void)cfg_map_get(config, "zone", &zones);
2604 if (zones != NULL) {
2605 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
2606 "when using 'view' statements, "
2607 "all zones must be in views");
2608 result = ISC_R_FAILURE;
2612 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
2613 if (tresult != ISC_R_SUCCESS)
2615 for (velement = cfg_list_first(views);
2617 velement = cfg_list_next(velement))
2619 const cfg_obj_t *view = cfg_listelt_value(velement);
2620 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
2621 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
2622 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
2623 dns_rdataclass_t vclass = dns_rdataclass_in;
2624 isc_result_t tresult = ISC_R_SUCCESS;
2625 const char *key = cfg_obj_asstring(vname);
2626 isc_symvalue_t symvalue;
2628 if (cfg_obj_isstring(vclassobj)) {
2631 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
2632 r.length = strlen(r.base);
2633 tresult = dns_rdataclass_fromtext(&vclass, &r);
2634 if (tresult != ISC_R_SUCCESS)
2635 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
2636 "view '%s': invalid class %s",
2637 cfg_obj_asstring(vname), r.base);
2639 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
2640 symvalue.as_cpointer = view;
2641 tresult = isc_symtab_define(symtab, key, vclass,
2643 isc_symexists_reject);
2644 if (tresult == ISC_R_EXISTS) {
2647 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
2648 vclass, &symvalue) == ISC_R_SUCCESS);
2649 file = cfg_obj_file(symvalue.as_cpointer);
2650 line = cfg_obj_line(symvalue.as_cpointer);
2651 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2652 "view '%s': already exists "
2653 "previous definition: %s:%u",
2656 } else if (tresult != ISC_R_SUCCESS) {
2658 } else if ((strcasecmp(key, "_bind") == 0 &&
2659 vclass == dns_rdataclass_ch) ||
2660 (strcasecmp(key, "_default") == 0 &&
2661 vclass == dns_rdataclass_in)) {
2662 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2663 "attempt to redefine builtin view "
2665 result = ISC_R_EXISTS;
2668 if (tresult == ISC_R_SUCCESS)
2669 tresult = check_viewconf(config, voptions, key,
2670 vclass, logctx, mctx);
2671 if (tresult != ISC_R_SUCCESS)
2672 result = ISC_R_FAILURE;
2675 isc_symtab_destroy(&symtab);
2677 if (views != NULL && options != NULL) {
2679 tresult = cfg_map_get(options, "cache-file", &obj);
2680 if (tresult == ISC_R_SUCCESS) {
2681 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2682 "'cache-file' cannot be a global "
2683 "option if views are present");
2684 result = ISC_R_FAILURE;
2688 cfg_map_get(config, "acl", &acls);
2691 const cfg_listelt_t *elt;
2692 const cfg_listelt_t *elt2;
2693 const char *aclname;
2695 for (elt = cfg_list_first(acls);
2697 elt = cfg_list_next(elt)) {
2698 const cfg_obj_t *acl = cfg_listelt_value(elt);
2699 unsigned int line = cfg_obj_line(acl);
2702 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2704 i < sizeof(builtin) / sizeof(builtin[0]);
2706 if (strcasecmp(aclname, builtin[i]) == 0) {
2707 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
2708 "attempt to redefine "
2711 result = ISC_R_FAILURE;
2715 for (elt2 = cfg_list_next(elt);
2717 elt2 = cfg_list_next(elt2)) {
2718 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2720 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2722 if (strcasecmp(aclname, name) == 0) {
2723 const char *file = cfg_obj_file(acl);
2726 file = "<unknown file>";
2728 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2729 "attempt to redefine "
2730 "acl '%s' previous "
2731 "definition: %s:%u",
2733 result = ISC_R_FAILURE;
2739 tresult = cfg_map_get(config, "kal", &kals);
2740 if (tresult == ISC_R_SUCCESS) {
2741 const cfg_listelt_t *elt;
2742 const cfg_listelt_t *elt2;
2743 const char *aclname;
2745 for (elt = cfg_list_first(kals);
2747 elt = cfg_list_next(elt)) {
2748 const cfg_obj_t *acl = cfg_listelt_value(elt);
2750 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2752 for (elt2 = cfg_list_next(elt);
2754 elt2 = cfg_list_next(elt2)) {
2755 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2757 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2759 if (strcasecmp(aclname, name) == 0) {
2760 const char *file = cfg_obj_file(acl);
2761 unsigned int line = cfg_obj_line(acl);
2764 file = "<unknown file>";
2766 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2767 "attempt to redefine "
2768 "kal '%s' previous "
2769 "definition: %s:%u",
2771 result = ISC_R_FAILURE;