2 * Copyright (C) 2004-2012 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.
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);
682 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
685 isc_result_t result = ISC_R_SUCCESS;
686 isc_result_t tresult;
688 const cfg_obj_t *obj = NULL;
689 const cfg_obj_t *resignobj = NULL;
690 const cfg_listelt_t *element;
691 isc_symtab_t *symtab = NULL;
692 dns_fixedname_t fixed;
697 static intervaltable intervals[] = {
698 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
699 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
700 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
701 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
702 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
703 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
704 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
705 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
708 static const char *server_contact[] = {
709 "empty-server", "empty-contact",
710 "dns64-server", "dns64-contact",
715 * Check that fields specified in units of time other than seconds
716 * have reasonable values.
718 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
721 (void)cfg_map_get(options, intervals[i].name, &obj);
724 val = cfg_obj_asuint32(obj);
725 if (val > intervals[i].max) {
726 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
727 "%s '%u' is out of range (0..%u)",
728 intervals[i].name, val,
730 result = ISC_R_RANGE;
731 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
732 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
733 "%s '%d' is out of range",
734 intervals[i].name, val);
735 result = ISC_R_RANGE;
740 cfg_map_get(options, "sig-validity-interval", &obj);
742 isc_uint32_t validity, resign = 0;
744 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
745 resignobj = cfg_tuple_get(obj, "re-sign");
746 if (!cfg_obj_isvoid(resignobj))
747 resign = cfg_obj_asuint32(resignobj);
749 if (validity > 3660 || validity == 0) { /* 10 years */
750 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
751 "%s '%u' is out of range (1..3660)",
752 "sig-validity-interval", validity);
753 result = ISC_R_RANGE;
756 if (!cfg_obj_isvoid(resignobj)) {
757 if (resign > 3660 || resign == 0) { /* 10 years */
758 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
759 "%s '%u' is out of range (1..3660)",
760 "sig-validity-interval (re-sign)",
762 result = ISC_R_RANGE;
763 } else if ((validity > 7 && validity < resign) ||
764 (validity <= 7 && validity * 24 < resign)) {
765 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
766 "validity interval (%u days) "
767 "less than re-signing interval "
768 "(%u %s)", validity, resign,
769 (validity > 7) ? "days" : "hours");
770 result = ISC_R_RANGE;
776 (void)cfg_map_get(options, "preferred-glue", &obj);
779 str = cfg_obj_asstring(obj);
780 if (strcasecmp(str, "a") != 0 &&
781 strcasecmp(str, "aaaa") != 0 &&
782 strcasecmp(str, "none") != 0)
783 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
784 "preferred-glue unexpected value '%s'",
789 (void)cfg_map_get(options, "root-delegation-only", &obj);
791 if (!cfg_obj_isvoid(obj)) {
792 const cfg_listelt_t *element;
793 const cfg_obj_t *exclude;
795 dns_fixedname_t fixed;
799 dns_fixedname_init(&fixed);
800 name = dns_fixedname_name(&fixed);
801 for (element = cfg_list_first(obj);
803 element = cfg_list_next(element)) {
804 exclude = cfg_listelt_value(element);
805 str = cfg_obj_asstring(exclude);
806 isc_buffer_init(&b, str, strlen(str));
807 isc_buffer_add(&b, strlen(str));
808 tresult = dns_name_fromtext(name, &b,
811 if (tresult != ISC_R_SUCCESS) {
812 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
813 "bad domain name '%s'",
822 * Set supported DNSSEC algorithms.
825 (void)cfg_map_get(options, "disable-algorithms", &obj);
827 for (element = cfg_list_first(obj);
829 element = cfg_list_next(element))
831 obj = cfg_listelt_value(element);
832 tresult = disabled_algorithms(obj, logctx);
833 if (tresult != ISC_R_SUCCESS)
838 dns_fixedname_init(&fixed);
839 name = dns_fixedname_name(&fixed);
842 * Check the DLV zone name.
845 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
847 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
849 if (tresult != ISC_R_SUCCESS)
851 for (element = cfg_list_first(obj);
853 element = cfg_list_next(element))
856 const cfg_obj_t *dlvobj, *anchor;
858 obj = cfg_listelt_value(element);
860 anchor = cfg_tuple_get(obj, "trust-anchor");
861 dlvobj = cfg_tuple_get(obj, "domain");
862 dlv = cfg_obj_asstring(dlvobj);
865 * If domain is "auto" or "no" and trust anchor
866 * is missing, skip remaining tests
868 if (cfg_obj_isvoid(anchor)) {
869 if (!strcasecmp(dlv, "no") ||
870 !strcasecmp(dlv, "auto"))
874 isc_buffer_init(&b, dlv, strlen(dlv));
875 isc_buffer_add(&b, strlen(dlv));
876 tresult = dns_name_fromtext(name, &b, dns_rootname,
878 if (tresult != ISC_R_SUCCESS) {
879 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
880 "bad domain name '%s'", dlv);
884 if (symtab != NULL) {
885 tresult = nameexist(obj, dlv, 1, symtab,
886 "dnssec-lookaside '%s': "
887 "already exists previous "
890 if (tresult != ISC_R_SUCCESS &&
891 result == ISC_R_SUCCESS)
895 * XXXMPA to be removed when multiple lookaside
896 * namespaces are supported.
898 if (!dns_name_equal(dns_rootname, name)) {
899 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
900 "dnssec-lookaside '%s': "
901 "non-root not yet supported", dlv);
902 if (result == ISC_R_SUCCESS)
903 result = ISC_R_FAILURE;
906 if (!cfg_obj_isvoid(anchor)) {
907 dlv = cfg_obj_asstring(anchor);
908 isc_buffer_init(&b, dlv, strlen(dlv));
909 isc_buffer_add(&b, strlen(dlv));
910 tresult = dns_name_fromtext(name, &b,
914 if (tresult != ISC_R_SUCCESS) {
915 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
916 "bad domain name '%s'",
918 if (result == ISC_R_SUCCESS)
922 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
923 "dnssec-lookaside requires "
924 "either 'auto' or 'no', or a "
925 "domain and trust anchor");
926 if (result == ISC_R_SUCCESS)
927 result = ISC_R_FAILURE;
932 isc_symtab_destroy(&symtab);
936 * Check auto-dnssec at the view/options level
939 (void)cfg_map_get(options, "auto-dnssec", &obj);
941 const char *arg = cfg_obj_asstring(obj);
942 if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
943 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
944 "auto-dnssec may only be activated at the "
946 result = ISC_R_FAILURE;
951 * Check dnssec-must-be-secure.
954 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
956 isc_symtab_t *symtab = NULL;
957 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
959 if (tresult != ISC_R_SUCCESS)
961 for (element = cfg_list_first(obj);
963 element = cfg_list_next(element))
965 obj = cfg_listelt_value(element);
966 tresult = mustbesecure(obj, symtab, logctx, mctx);
967 if (tresult != ISC_R_SUCCESS)
971 isc_symtab_destroy(&symtab);
975 * Check server/contacts for syntactic validity.
977 for (i= 0; server_contact[i] != NULL; i++) {
979 (void)cfg_map_get(options, server_contact[i], &obj);
981 str = cfg_obj_asstring(obj);
982 isc_buffer_init(&b, str, strlen(str));
983 isc_buffer_add(&b, strlen(str));
984 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
985 &b, dns_rootname, 0, NULL);
986 if (tresult != ISC_R_SUCCESS) {
987 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
988 "%s: invalid name '%s'",
989 server_contact[i], str);
990 result = ISC_R_FAILURE;
996 * Check empty zone configuration.
999 (void)cfg_map_get(options, "disable-empty-zone", &obj);
1000 for (element = cfg_list_first(obj);
1002 element = cfg_list_next(element))
1004 obj = cfg_listelt_value(element);
1005 str = cfg_obj_asstring(obj);
1006 isc_buffer_init(&b, str, strlen(str));
1007 isc_buffer_add(&b, strlen(str));
1008 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1009 dns_rootname, 0, NULL);
1010 if (tresult != ISC_R_SUCCESS) {
1011 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1012 "disable-empty-zone: invalid name '%s'",
1014 result = ISC_R_FAILURE;
1019 * Check that server-id is not too long.
1020 * 1024 bytes should be big enough.
1023 (void)cfg_map_get(options, "server-id", &obj);
1024 if (obj != NULL && cfg_obj_isstring(obj) &&
1025 strlen(cfg_obj_asstring(obj)) > 1024U) {
1026 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1027 "'server-id' too big (>1024 bytes)");
1028 result = ISC_R_FAILURE;
1035 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
1036 isc_result_t result;
1037 const cfg_obj_t *masters = NULL;
1038 const cfg_listelt_t *elt;
1040 result = cfg_map_get(cctx, "masters", &masters);
1041 if (result != ISC_R_SUCCESS)
1043 for (elt = cfg_list_first(masters);
1045 elt = cfg_list_next(elt)) {
1046 const cfg_obj_t *list;
1047 const char *listname;
1049 list = cfg_listelt_value(elt);
1050 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
1052 if (strcasecmp(listname, name) == 0) {
1054 return (ISC_R_SUCCESS);
1057 return (ISC_R_NOTFOUND);
1061 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
1062 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
1064 isc_result_t result = ISC_R_SUCCESS;
1065 isc_result_t tresult;
1066 isc_uint32_t count = 0;
1067 isc_symtab_t *symtab = NULL;
1068 isc_symvalue_t symvalue;
1069 const cfg_listelt_t *element;
1070 const cfg_listelt_t **stack = NULL;
1071 isc_uint32_t stackcount = 0, pushed = 0;
1072 const cfg_obj_t *list;
1074 REQUIRE(countp != NULL);
1075 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1076 if (result != ISC_R_SUCCESS) {
1082 list = cfg_tuple_get(obj, "addresses");
1083 element = cfg_list_first(list);
1087 element = cfg_list_next(element))
1089 const char *listname;
1090 const cfg_obj_t *addr;
1091 const cfg_obj_t *key;
1093 addr = cfg_tuple_get(cfg_listelt_value(element),
1095 key = cfg_tuple_get(cfg_listelt_value(element), "key");
1097 if (cfg_obj_issockaddr(addr)) {
1101 if (!cfg_obj_isvoid(key)) {
1102 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1103 "unexpected token '%s'",
1104 cfg_obj_asstring(key));
1105 if (result == ISC_R_SUCCESS)
1106 result = ISC_R_FAILURE;
1108 listname = cfg_obj_asstring(addr);
1109 symvalue.as_cpointer = addr;
1110 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
1111 isc_symexists_reject);
1112 if (tresult == ISC_R_EXISTS)
1114 tresult = get_masters_def(config, listname, &obj);
1115 if (tresult != ISC_R_SUCCESS) {
1116 if (result == ISC_R_SUCCESS)
1118 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
1119 "unable to find masters list '%s'",
1124 if (stackcount == pushed) {
1126 isc_uint32_t newlen = stackcount + 16;
1127 size_t newsize, oldsize;
1129 newsize = newlen * sizeof(*stack);
1130 oldsize = stackcount * sizeof(*stack);
1131 new = isc_mem_get(mctx, newsize);
1134 if (stackcount != 0) {
1137 DE_CONST(stack, ptr);
1138 memcpy(new, stack, oldsize);
1139 isc_mem_put(mctx, ptr, oldsize);
1142 stackcount = newlen;
1144 stack[pushed++] = cfg_list_next(element);
1148 element = stack[--pushed];
1152 if (stack != NULL) {
1155 DE_CONST(stack, ptr);
1156 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1158 isc_symtab_destroy(&symtab);
1164 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1165 isc_result_t result = ISC_R_SUCCESS;
1166 isc_result_t tresult;
1167 const cfg_listelt_t *element;
1168 const cfg_listelt_t *element2;
1169 dns_fixedname_t fixed;
1173 /* Check for "update-policy local;" */
1174 if (cfg_obj_isstring(policy) &&
1175 strcmp("local", cfg_obj_asstring(policy)) == 0)
1176 return (ISC_R_SUCCESS);
1178 /* Now check the grant policy */
1179 for (element = cfg_list_first(policy);
1181 element = cfg_list_next(element))
1183 const cfg_obj_t *stmt = cfg_listelt_value(element);
1184 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1185 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1186 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1187 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1189 dns_fixedname_init(&fixed);
1190 str = cfg_obj_asstring(identity);
1191 isc_buffer_init(&b, str, strlen(str));
1192 isc_buffer_add(&b, strlen(str));
1193 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1194 dns_rootname, 0, NULL);
1195 if (tresult != ISC_R_SUCCESS) {
1196 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1197 "'%s' is not a valid name", str);
1201 if (tresult == ISC_R_SUCCESS &&
1202 strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
1203 dns_fixedname_init(&fixed);
1204 str = cfg_obj_asstring(dname);
1205 isc_buffer_init(&b, str, strlen(str));
1206 isc_buffer_add(&b, strlen(str));
1207 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
1208 &b, dns_rootname, 0, NULL);
1209 if (tresult != ISC_R_SUCCESS) {
1210 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1211 "'%s' is not a valid name", str);
1216 if (tresult == ISC_R_SUCCESS &&
1217 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
1218 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
1219 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1220 "'%s' is not a wildcard", str);
1221 result = ISC_R_FAILURE;
1224 for (element2 = cfg_list_first(typelist);
1226 element2 = cfg_list_next(element2))
1228 const cfg_obj_t *typeobj;
1230 dns_rdatatype_t type;
1232 typeobj = cfg_listelt_value(element2);
1233 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1234 r.length = strlen(r.base);
1236 tresult = dns_rdatatype_fromtext(&type, &r);
1237 if (tresult != ISC_R_SUCCESS) {
1238 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1239 "'%s' is not a valid type", r.base);
1247 #define MASTERZONE 1
1251 #define FORWARDZONE 16
1252 #define DELEGATIONZONE 32
1253 #define STATICSTUBZONE 64
1254 #define CHECKACL 128
1262 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1263 const cfg_obj_t *config, isc_symtab_t *symtab,
1264 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
1265 isc_log_t *logctx, isc_mem_t *mctx)
1267 const char *znamestr;
1268 const char *typestr;
1270 const cfg_obj_t *zoptions;
1271 const cfg_obj_t *obj = NULL;
1272 isc_result_t result = ISC_R_SUCCESS;
1273 isc_result_t tresult;
1275 dns_rdataclass_t zclass;
1276 dns_fixedname_t fixedname;
1277 dns_name_t *zname = NULL;
1279 isc_boolean_t root = ISC_FALSE;
1280 const cfg_listelt_t *element;
1282 static optionstable options[] = {
1283 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL |
1285 { "allow-notify", SLAVEZONE | CHECKACL },
1286 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1287 { "notify", MASTERZONE | SLAVEZONE },
1288 { "also-notify", MASTERZONE | SLAVEZONE },
1289 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
1290 { "delegation-only", HINTZONE | STUBZONE | DELEGATIONZONE },
1291 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1292 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
1293 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
1294 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
1295 { "notify-source", MASTERZONE | SLAVEZONE },
1296 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1297 { "transfer-source", SLAVEZONE | STUBZONE },
1298 { "transfer-source-v6", SLAVEZONE | STUBZONE },
1299 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
1300 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1301 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
1302 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1303 { "max-retry-time", SLAVEZONE | STUBZONE },
1304 { "min-retry-time", SLAVEZONE | STUBZONE },
1305 { "max-refresh-time", SLAVEZONE | STUBZONE },
1306 { "min-refresh-time", SLAVEZONE | STUBZONE },
1307 { "dnssec-secure-to-insecure", MASTERZONE },
1308 { "sig-validity-interval", MASTERZONE },
1309 { "sig-re-signing-interval", MASTERZONE },
1310 { "sig-signing-nodes", MASTERZONE },
1311 { "sig-signing-type", MASTERZONE },
1312 { "sig-signing-signatures", MASTERZONE },
1313 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
1315 { "allow-update", MASTERZONE | CHECKACL },
1316 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1317 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1318 { "journal", MASTERZONE | SLAVEZONE },
1319 { "ixfr-base", MASTERZONE | SLAVEZONE },
1320 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1321 { "masters", SLAVEZONE | STUBZONE },
1322 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1323 { "update-policy", MASTERZONE },
1324 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
1325 { "key-directory", MASTERZONE },
1326 { "check-wildcard", MASTERZONE },
1327 { "check-mx", MASTERZONE },
1328 { "check-dup-records", MASTERZONE },
1329 { "integrity-check", MASTERZONE },
1330 { "check-mx-cname", MASTERZONE },
1331 { "check-srv-cname", MASTERZONE },
1332 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1333 { "update-check-ksk", MASTERZONE },
1334 { "dnssec-dnskey-kskonly", MASTERZONE },
1335 { "auto-dnssec", MASTERZONE },
1336 { "try-tcp-refresh", SLAVEZONE },
1337 { "server-addresses", STATICSTUBZONE },
1338 { "server-names", STATICSTUBZONE },
1341 static optionstable dialups[] = {
1342 { "notify", MASTERZONE | SLAVEZONE },
1343 { "notify-passive", SLAVEZONE },
1344 { "refresh", SLAVEZONE | STUBZONE },
1345 { "passive", SLAVEZONE | STUBZONE },
1348 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1350 zoptions = cfg_tuple_get(zconfig, "options");
1353 (void)cfg_map_get(zoptions, "type", &obj);
1355 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1356 "zone '%s': type not present", znamestr);
1357 return (ISC_R_FAILURE);
1360 typestr = cfg_obj_asstring(obj);
1361 if (strcasecmp(typestr, "master") == 0)
1363 else if (strcasecmp(typestr, "slave") == 0)
1365 else if (strcasecmp(typestr, "stub") == 0)
1367 else if (strcasecmp(typestr, "static-stub") == 0)
1368 ztype = STATICSTUBZONE;
1369 else if (strcasecmp(typestr, "forward") == 0)
1370 ztype = FORWARDZONE;
1371 else if (strcasecmp(typestr, "hint") == 0)
1373 else if (strcasecmp(typestr, "delegation-only") == 0)
1374 ztype = DELEGATIONZONE;
1376 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1377 "zone '%s': invalid type %s",
1379 return (ISC_R_FAILURE);
1382 obj = cfg_tuple_get(zconfig, "class");
1383 if (cfg_obj_isstring(obj)) {
1386 DE_CONST(cfg_obj_asstring(obj), r.base);
1387 r.length = strlen(r.base);
1388 result = dns_rdataclass_fromtext(&zclass, &r);
1389 if (result != ISC_R_SUCCESS) {
1390 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1391 "zone '%s': invalid class %s",
1393 return (ISC_R_FAILURE);
1395 if (zclass != defclass) {
1396 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1397 "zone '%s': class '%s' does not "
1398 "match view/default class",
1400 return (ISC_R_FAILURE);
1405 * Look for an already existing zone.
1406 * We need to make this canonical as isc_symtab_define()
1407 * deals with strings.
1409 dns_fixedname_init(&fixedname);
1410 isc_buffer_init(&b, znamestr, strlen(znamestr));
1411 isc_buffer_add(&b, strlen(znamestr));
1412 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1413 dns_rootname, DNS_NAME_DOWNCASE, NULL);
1414 if (tresult != ISC_R_SUCCESS) {
1415 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1416 "zone '%s': is not a valid name", znamestr);
1417 result = ISC_R_FAILURE;
1419 char namebuf[DNS_NAME_FORMATSIZE];
1421 zname = dns_fixedname_name(&fixedname);
1422 dns_name_format(zname, namebuf, sizeof(namebuf));
1423 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1424 symtab, "zone '%s': already exists "
1425 "previous definition: %s:%u", logctx, mctx);
1426 if (tresult != ISC_R_SUCCESS)
1428 if (dns_name_equal(zname, dns_rootname))
1433 * Look for inappropriate options for the given zone type.
1434 * Check that ACLs expand correctly.
1436 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1438 if ((options[i].allowed & ztype) == 0 &&
1439 cfg_map_get(zoptions, options[i].name, &obj) ==
1442 if (strcmp(options[i].name, "allow-update") != 0 ||
1443 ztype != SLAVEZONE) {
1444 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1445 "option '%s' is not allowed "
1446 "in '%s' zone '%s'",
1447 options[i].name, typestr,
1449 result = ISC_R_FAILURE;
1451 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1452 "option '%s' is not allowed "
1453 "in '%s' zone '%s'",
1454 options[i].name, typestr,
1458 if ((options[i].allowed & ztype) != 0 &&
1459 (options[i].allowed & CHECKACL) != 0) {
1461 tresult = checkacl(options[i].name, actx, zconfig,
1462 voptions, config, logctx, mctx);
1463 if (tresult != ISC_R_SUCCESS)
1470 * Slave & stub zones must have a "masters" field.
1472 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1474 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1475 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1476 "zone '%s': missing 'masters' entry",
1478 result = ISC_R_FAILURE;
1481 tresult = validate_masters(obj, config, &count,
1483 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1485 if (tresult == ISC_R_SUCCESS && count == 0) {
1486 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1487 "zone '%s': empty 'masters' entry",
1489 result = ISC_R_FAILURE;
1495 * Master zones can't have both "allow-update" and "update-policy".
1497 if (ztype == MASTERZONE) {
1498 isc_result_t res1, res2, res3;
1503 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1505 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1506 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1507 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1508 "zone '%s': 'allow-update' is ignored "
1509 "when 'update-policy' is present",
1511 result = ISC_R_FAILURE;
1512 } else if (res2 == ISC_R_SUCCESS &&
1513 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1514 result = ISC_R_FAILURE;
1515 ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS);
1519 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
1520 if (res3 == ISC_R_SUCCESS)
1521 arg = cfg_obj_asstring(obj);
1522 if (strcasecmp(arg, "off") != 0 && !ddns) {
1523 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1524 "'auto-dnssec %s;' requires "
1525 "dynamic DNS to be configured in the zone",
1527 result = ISC_R_FAILURE;
1529 if (strcasecmp(arg, "create") == 0) {
1530 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1531 "'auto-dnssec create;' is not "
1533 result = ISC_R_FAILURE;
1537 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1538 if (res1 == ISC_R_SUCCESS) {
1539 isc_uint32_t type = cfg_obj_asuint32(obj);
1540 if (type < 0xff00U || type > 0xffffU)
1541 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1542 "sig-signing-type: %u out of "
1543 "range [%u..%u]", type,
1545 result = ISC_R_FAILURE;
1550 * Check the excessively complicated "dialup" option.
1552 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1553 const cfg_obj_t *dialup = NULL;
1554 (void)cfg_map_get(zoptions, "dialup", &dialup);
1555 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1556 const char *str = cfg_obj_asstring(dialup);
1558 i < sizeof(dialups) / sizeof(dialups[0]);
1561 if (strcasecmp(dialups[i].name, str) != 0)
1563 if ((dialups[i].allowed & ztype) == 0) {
1564 cfg_obj_log(obj, logctx,
1566 "dialup type '%s' is not "
1569 str, typestr, znamestr);
1570 result = ISC_R_FAILURE;
1574 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1575 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1576 "invalid dialup type '%s' in zone "
1577 "'%s'", str, znamestr);
1578 result = ISC_R_FAILURE;
1584 * Check that forwarding is reasonable.
1588 if (voptions != NULL)
1589 (void)cfg_map_get(voptions, "forwarders", &obj);
1591 const cfg_obj_t *options = NULL;
1592 (void)cfg_map_get(config, "options", &options);
1593 if (options != NULL)
1594 (void)cfg_map_get(options, "forwarders", &obj);
1597 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1598 result = ISC_R_FAILURE;
1601 * Check validity of static stub server addresses.
1604 (void)cfg_map_get(zoptions, "server-addresses", &obj);
1605 if (ztype == STATICSTUBZONE && obj != NULL) {
1606 for (element = cfg_list_first(obj);
1608 element = cfg_list_next(element))
1612 obj = cfg_listelt_value(element);
1613 sa = *cfg_obj_assockaddr(obj);
1615 if (isc_sockaddr_getport(&sa) != 0) {
1616 result = ISC_R_FAILURE;
1617 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1618 "port is not configurable for "
1619 "static stub server-addresses");
1622 isc_netaddr_fromsockaddr(&na, &sa);
1623 if (isc_netaddr_getzone(&na) != 0) {
1624 result = ISC_R_FAILURE;
1625 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1626 "scoped address is not allowed "
1628 "server-addresses");
1634 * Check validity of static stub server names.
1637 (void)cfg_map_get(zoptions, "server-names", &obj);
1638 if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
1639 for (element = cfg_list_first(obj);
1641 element = cfg_list_next(element))
1643 const char *snamestr;
1644 dns_fixedname_t fixed_sname;
1648 obj = cfg_listelt_value(element);
1649 snamestr = cfg_obj_asstring(obj);
1651 dns_fixedname_init(&fixed_sname);
1652 isc_buffer_init(&b2, snamestr, strlen(snamestr));
1653 isc_buffer_add(&b2, strlen(snamestr));
1654 sname = dns_fixedname_name(&fixed_sname);
1655 tresult = dns_name_fromtext(sname, &b2, dns_rootname,
1657 if (tresult != ISC_R_SUCCESS) {
1658 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1659 "server-name '%s' is not a valid "
1661 result = ISC_R_FAILURE;
1662 } else if (dns_name_issubdomain(sname, zname)) {
1663 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1664 "server-name '%s' must not be a "
1665 "subdomain of zone name '%s'",
1666 snamestr, znamestr);
1667 result = ISC_R_FAILURE;
1673 * Check various options.
1675 tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
1676 if (tresult != ISC_R_SUCCESS)
1680 * If the zone type is rbt/rbt64 then master/hint zones
1681 * require file clauses.
1684 tresult = cfg_map_get(zoptions, "database", &obj);
1685 if (tresult == ISC_R_NOTFOUND ||
1686 (tresult == ISC_R_SUCCESS &&
1687 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1688 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1690 tresult = cfg_map_get(zoptions, "file", &obj);
1691 if (tresult != ISC_R_SUCCESS &&
1692 (ztype == MASTERZONE || ztype == HINTZONE)) {
1693 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1694 "zone '%s': missing 'file' entry",
1704 typedef struct keyalgorithms {
1710 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1711 const cfg_obj_t *algobj = NULL;
1712 const cfg_obj_t *secretobj = NULL;
1713 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1714 const char *algorithm;
1717 isc_result_t result;
1719 unsigned char secretbuf[1024];
1720 static const algorithmtable algorithms[] = {
1721 { "hmac-md5", 128 },
1722 { "hmac-md5.sig-alg.reg.int", 0 },
1723 { "hmac-md5.sig-alg.reg.int.", 0 },
1724 { "hmac-sha1", 160 },
1725 { "hmac-sha224", 224 },
1726 { "hmac-sha256", 256 },
1727 { "hmac-sha384", 384 },
1728 { "hmac-sha512", 512 },
1732 (void)cfg_map_get(key, "algorithm", &algobj);
1733 (void)cfg_map_get(key, "secret", &secretobj);
1734 if (secretobj == NULL || algobj == NULL) {
1735 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1736 "key '%s' must have both 'secret' and "
1737 "'algorithm' defined",
1739 return (ISC_R_FAILURE);
1742 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
1743 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
1744 if (result != ISC_R_SUCCESS) {
1745 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
1746 "bad secret '%s'", isc_result_totext(result));
1750 algorithm = cfg_obj_asstring(algobj);
1751 for (i = 0; algorithms[i].name != NULL; i++) {
1752 len = strlen(algorithms[i].name);
1753 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1754 (algorithm[len] == '\0' ||
1755 (algorithms[i].size != 0 && algorithm[len] == '-')))
1758 if (algorithms[i].name == NULL) {
1759 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1760 "unknown algorithm '%s'", algorithm);
1761 return (ISC_R_NOTFOUND);
1763 if (algorithm[len] == '-') {
1764 isc_uint16_t digestbits;
1765 isc_result_t result;
1766 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1767 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1768 if (result == ISC_R_RANGE ||
1769 digestbits > algorithms[i].size) {
1770 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1771 "key '%s' digest-bits too large "
1772 "[%u..%u]", keyname,
1773 algorithms[i].size / 2,
1774 algorithms[i].size);
1775 return (ISC_R_RANGE);
1777 if ((digestbits % 8) != 0) {
1778 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1779 "key '%s' digest-bits not multiple"
1781 return (ISC_R_RANGE);
1784 * Recommended minima for hmac algorithms.
1786 if ((digestbits < (algorithms[i].size / 2U) ||
1787 (digestbits < 80U)))
1788 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1789 "key '%s' digest-bits too small "
1791 algorithms[i].size/2);
1793 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1794 "key '%s': unable to parse digest-bits",
1799 return (ISC_R_SUCCESS);
1803 * Check key list for duplicates key names and that the key names
1804 * are valid domain names as these keys are used for TSIG.
1806 * Check the key contents for validity.
1809 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
1810 isc_mem_t *mctx, isc_log_t *logctx)
1812 char namebuf[DNS_NAME_FORMATSIZE];
1813 dns_fixedname_t fname;
1815 isc_result_t result = ISC_R_SUCCESS;
1816 isc_result_t tresult;
1817 const cfg_listelt_t *element;
1819 dns_fixedname_init(&fname);
1820 name = dns_fixedname_name(&fname);
1821 for (element = cfg_list_first(keys);
1823 element = cfg_list_next(element))
1825 const cfg_obj_t *key = cfg_listelt_value(element);
1826 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
1827 isc_symvalue_t symvalue;
1831 isc_buffer_init(&b, keyid, strlen(keyid));
1832 isc_buffer_add(&b, strlen(keyid));
1833 tresult = dns_name_fromtext(name, &b, dns_rootname,
1835 if (tresult != ISC_R_SUCCESS) {
1836 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1837 "key '%s': bad key name", keyid);
1841 tresult = bind9_check_key(key, logctx);
1842 if (tresult != ISC_R_SUCCESS)
1845 dns_name_format(name, namebuf, sizeof(namebuf));
1846 keyname = isc_mem_strdup(mctx, namebuf);
1847 if (keyname == NULL)
1848 return (ISC_R_NOMEMORY);
1849 symvalue.as_cpointer = key;
1850 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
1851 isc_symexists_reject);
1852 if (tresult == ISC_R_EXISTS) {
1856 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1857 1, &symvalue) == ISC_R_SUCCESS);
1858 file = cfg_obj_file(symvalue.as_cpointer);
1859 line = cfg_obj_line(symvalue.as_cpointer);
1862 file = "<unknown file>";
1863 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1864 "key '%s': already exists "
1865 "previous definition: %s:%u",
1867 isc_mem_free(mctx, keyname);
1869 } else if (tresult != ISC_R_SUCCESS) {
1870 isc_mem_free(mctx, keyname);
1881 { "transfer-source", "transfer-source-v6" },
1882 { "notify-source", "notify-source-v6" },
1883 { "query-source", "query-source-v6" },
1888 * RNDC keys are not normalised unlike TSIG keys.
1890 * "foo." is different to "foo".
1892 static isc_boolean_t
1893 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
1894 const cfg_listelt_t *element;
1895 const cfg_obj_t *obj;
1898 if (keylist == NULL)
1901 for (element = cfg_list_first(keylist);
1903 element = cfg_list_next(element))
1905 obj = cfg_listelt_value(element);
1906 str = cfg_obj_asstring(cfg_map_getname(obj));
1907 if (!strcasecmp(str, keyname))
1914 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
1915 isc_symtab_t *symtab, isc_log_t *logctx)
1917 dns_fixedname_t fname;
1918 isc_result_t result = ISC_R_SUCCESS;
1919 isc_result_t tresult;
1920 const cfg_listelt_t *e1, *e2;
1921 const cfg_obj_t *v1, *v2, *keys;
1922 const cfg_obj_t *servers;
1923 isc_netaddr_t n1, n2;
1924 unsigned int p1, p2;
1925 const cfg_obj_t *obj;
1926 char buf[ISC_NETADDR_FORMATSIZE];
1927 char namebuf[DNS_NAME_FORMATSIZE];
1932 dns_name_t *keyname;
1935 if (voptions != NULL)
1936 (void)cfg_map_get(voptions, "server", &servers);
1937 if (servers == NULL)
1938 (void)cfg_map_get(config, "server", &servers);
1939 if (servers == NULL)
1940 return (ISC_R_SUCCESS);
1942 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1943 v1 = cfg_listelt_value(e1);
1944 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1946 * Check that unused bits are zero.
1948 tresult = isc_netaddr_prefixok(&n1, p1);
1949 if (tresult != ISC_R_SUCCESS) {
1950 INSIST(tresult == ISC_R_FAILURE);
1951 isc_netaddr_format(&n1, buf, sizeof(buf));
1952 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1953 "server '%s/%u': invalid prefix "
1954 "(extra bits specified)", buf, p1);
1960 if (n1.family == AF_INET)
1961 xfr = sources[source].v6;
1963 xfr = sources[source].v4;
1964 (void)cfg_map_get(v1, xfr, &obj);
1966 isc_netaddr_format(&n1, buf, sizeof(buf));
1967 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1968 "server '%s/%u': %s not legal",
1970 result = ISC_R_FAILURE;
1972 } while (sources[++source].v4 != NULL);
1974 while ((e2 = cfg_list_next(e2)) != NULL) {
1975 v2 = cfg_listelt_value(e2);
1976 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
1977 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
1978 const char *file = cfg_obj_file(v1);
1979 unsigned int line = cfg_obj_line(v1);
1982 file = "<unknown file>";
1984 isc_netaddr_format(&n2, buf, sizeof(buf));
1985 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1986 "server '%s/%u': already exists "
1987 "previous definition: %s:%u",
1988 buf, p2, file, line);
1989 result = ISC_R_FAILURE;
1993 cfg_map_get(v1, "keys", &keys);
1996 * Normalize key name.
1998 keyval = cfg_obj_asstring(keys);
1999 dns_fixedname_init(&fname);
2000 isc_buffer_init(&b, keyval, strlen(keyval));
2001 isc_buffer_add(&b, strlen(keyval));
2002 keyname = dns_fixedname_name(&fname);
2003 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
2005 if (tresult != ISC_R_SUCCESS) {
2006 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2007 "bad key name '%s'", keyval);
2008 result = ISC_R_FAILURE;
2011 dns_name_format(keyname, namebuf, sizeof(namebuf));
2012 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
2013 if (tresult != ISC_R_SUCCESS) {
2014 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2015 "unknown key '%s'", keyval);
2016 result = ISC_R_FAILURE;
2024 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
2027 const char *keystr, *keynamestr;
2028 dns_fixedname_t fkeyname;
2029 dns_name_t *keyname;
2032 isc_result_t result = ISC_R_SUCCESS;
2033 isc_result_t tresult;
2034 isc_uint32_t flags, proto, alg;
2035 unsigned char keydata[4096];
2037 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
2038 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
2039 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
2041 dns_fixedname_init(&fkeyname);
2042 keyname = dns_fixedname_name(&fkeyname);
2043 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
2045 isc_buffer_init(&b, keynamestr, strlen(keynamestr));
2046 isc_buffer_add(&b, strlen(keynamestr));
2047 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
2048 if (result != ISC_R_SUCCESS) {
2049 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
2050 isc_result_totext(result));
2051 result = ISC_R_FAILURE;
2054 if (flags > 0xffff) {
2055 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2056 "flags too big: %u\n", flags);
2057 result = ISC_R_FAILURE;
2060 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2061 "protocol too big: %u\n", proto);
2062 result = ISC_R_FAILURE;
2065 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2066 "algorithm too big: %u\n", alg);
2067 result = ISC_R_FAILURE;
2071 const char *initmethod;
2072 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
2074 if (strcasecmp(initmethod, "initial-key") != 0) {
2075 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2076 "managed key '%s': "
2077 "invalid initialization method '%s'",
2078 keynamestr, initmethod);
2079 result = ISC_R_FAILURE;
2083 isc_buffer_init(&b, keydata, sizeof(keydata));
2085 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
2086 tresult = isc_base64_decodestring(keystr, &b);
2088 if (tresult != ISC_R_SUCCESS) {
2089 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2090 "%s", isc_result_totext(tresult));
2091 result = ISC_R_FAILURE;
2093 isc_buffer_usedregion(&b, &r);
2095 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
2096 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
2097 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2098 "%s key '%s' has a weak exponent",
2099 managed ? "managed" : "trusted",
2107 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
2108 const char *viewname, dns_rdataclass_t vclass,
2109 isc_log_t *logctx, isc_mem_t *mctx)
2111 const cfg_obj_t *zones = NULL;
2112 const cfg_obj_t *keys = NULL;
2113 const cfg_listelt_t *element, *element2;
2114 isc_symtab_t *symtab = NULL;
2115 isc_result_t result = ISC_R_SUCCESS;
2116 isc_result_t tresult = ISC_R_SUCCESS;
2117 cfg_aclconfctx_t *actx = NULL;
2118 const cfg_obj_t *obj;
2119 const cfg_obj_t *options = NULL;
2120 isc_boolean_t enablednssec, enablevalidation;
2121 const char *valstr = "no";
2124 * Get global options block
2126 (void)cfg_map_get(config, "options", &options);
2129 * Check that all zone statements are syntactically correct and
2130 * there are no duplicate zones.
2132 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2133 ISC_FALSE, &symtab);
2134 if (tresult != ISC_R_SUCCESS)
2135 return (ISC_R_NOMEMORY);
2137 cfg_aclconfctx_create(mctx, &actx);
2139 if (voptions != NULL)
2140 (void)cfg_map_get(voptions, "zone", &zones);
2142 (void)cfg_map_get(config, "zone", &zones);
2144 for (element = cfg_list_first(zones);
2146 element = cfg_list_next(element))
2148 isc_result_t tresult;
2149 const cfg_obj_t *zone = cfg_listelt_value(element);
2151 tresult = check_zoneconf(zone, voptions, config, symtab,
2152 vclass, actx, logctx, mctx);
2153 if (tresult != ISC_R_SUCCESS)
2154 result = ISC_R_FAILURE;
2157 isc_symtab_destroy(&symtab);
2160 * Check that forwarding is reasonable.
2162 if (voptions == NULL) {
2163 if (options != NULL)
2164 if (check_forward(options, NULL,
2165 logctx) != ISC_R_SUCCESS)
2166 result = ISC_R_FAILURE;
2168 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
2169 result = ISC_R_FAILURE;
2173 * Check that dual-stack-servers is reasonable.
2175 if (voptions == NULL) {
2176 if (options != NULL)
2177 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2178 result = ISC_R_FAILURE;
2180 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
2181 result = ISC_R_FAILURE;
2185 * Check that rrset-order is reasonable.
2187 if (voptions != NULL) {
2188 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
2189 result = ISC_R_FAILURE;
2193 * Check that all key statements are syntactically correct and
2194 * there are no duplicate keys.
2196 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2197 ISC_FALSE, &symtab);
2198 if (tresult != ISC_R_SUCCESS)
2199 return (ISC_R_NOMEMORY);
2201 (void)cfg_map_get(config, "key", &keys);
2202 tresult = check_keylist(keys, symtab, mctx, logctx);
2203 if (tresult == ISC_R_EXISTS)
2204 result = ISC_R_FAILURE;
2205 else if (tresult != ISC_R_SUCCESS) {
2206 isc_symtab_destroy(&symtab);
2210 if (voptions != NULL) {
2212 (void)cfg_map_get(voptions, "key", &keys);
2213 tresult = check_keylist(keys, symtab, mctx, logctx);
2214 if (tresult == ISC_R_EXISTS)
2215 result = ISC_R_FAILURE;
2216 else if (tresult != ISC_R_SUCCESS) {
2217 isc_symtab_destroy(&symtab);
2223 * Global servers can refer to keys in views.
2225 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
2226 result = ISC_R_FAILURE;
2228 isc_symtab_destroy(&symtab);
2231 * Check that dnssec-enable/dnssec-validation are sensible.
2234 if (voptions != NULL)
2235 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
2236 if (obj == NULL && options != NULL)
2237 (void)cfg_map_get(options, "dnssec-enable", &obj);
2239 enablednssec = ISC_TRUE;
2241 enablednssec = cfg_obj_asboolean(obj);
2244 if (voptions != NULL)
2245 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
2246 if (obj == NULL && options != NULL)
2247 (void)cfg_map_get(options, "dnssec-validation", &obj);
2249 enablevalidation = enablednssec;
2251 } else if (cfg_obj_isboolean(obj)) {
2252 enablevalidation = cfg_obj_asboolean(obj);
2253 valstr = enablevalidation ? "yes" : "no";
2255 enablevalidation = ISC_TRUE;
2259 if (enablevalidation && !enablednssec)
2260 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2261 "'dnssec-validation %s;' and 'dnssec-enable no;'",
2265 * Check trusted-keys and managed-keys.
2268 if (voptions != NULL)
2269 (void)cfg_map_get(voptions, "trusted-keys", &keys);
2271 (void)cfg_map_get(config, "trusted-keys", &keys);
2273 for (element = cfg_list_first(keys);
2275 element = cfg_list_next(element))
2277 const cfg_obj_t *keylist = cfg_listelt_value(element);
2278 for (element2 = cfg_list_first(keylist);
2280 element2 = cfg_list_next(element2)) {
2281 obj = cfg_listelt_value(element2);
2282 tresult = check_trusted_key(obj, ISC_FALSE, logctx);
2283 if (tresult != ISC_R_SUCCESS)
2289 if (voptions != NULL)
2290 (void)cfg_map_get(voptions, "managed-keys", &keys);
2292 (void)cfg_map_get(config, "managed-keys", &keys);
2294 for (element = cfg_list_first(keys);
2296 element = cfg_list_next(element))
2298 const cfg_obj_t *keylist = cfg_listelt_value(element);
2299 for (element2 = cfg_list_first(keylist);
2301 element2 = cfg_list_next(element2)) {
2302 obj = cfg_listelt_value(element2);
2303 tresult = check_trusted_key(obj, ISC_TRUE, logctx);
2304 if (tresult != ISC_R_SUCCESS)
2312 if (voptions != NULL)
2313 tresult = check_options(voptions, logctx, mctx,
2316 tresult = check_options(config, logctx, mctx,
2318 if (tresult != ISC_R_SUCCESS)
2321 tresult = check_viewacls(actx, voptions, config, logctx, mctx);
2322 if (tresult != ISC_R_SUCCESS)
2325 tresult = check_recursionacls(actx, voptions, viewname,
2326 config, logctx, mctx);
2327 if (tresult != ISC_R_SUCCESS)
2330 tresult = check_filteraaaa(actx, voptions, viewname, config,
2332 if (tresult != ISC_R_SUCCESS)
2335 tresult = check_dns64(actx, voptions, config, logctx, mctx);
2336 if (tresult != ISC_R_SUCCESS)
2339 cfg_aclconfctx_detach(&actx);
2345 default_channels[] = {
2354 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
2357 const cfg_obj_t *categories = NULL;
2358 const cfg_obj_t *category;
2359 const cfg_obj_t *channels = NULL;
2360 const cfg_obj_t *channel;
2361 const cfg_listelt_t *element;
2362 const cfg_listelt_t *delement;
2363 const char *channelname;
2364 const char *catname;
2365 const cfg_obj_t *fileobj = NULL;
2366 const cfg_obj_t *syslogobj = NULL;
2367 const cfg_obj_t *nullobj = NULL;
2368 const cfg_obj_t *stderrobj = NULL;
2369 const cfg_obj_t *logobj = NULL;
2370 isc_result_t result = ISC_R_SUCCESS;
2371 isc_result_t tresult;
2372 isc_symtab_t *symtab = NULL;
2373 isc_symvalue_t symvalue;
2376 (void)cfg_map_get(config, "logging", &logobj);
2378 return (ISC_R_SUCCESS);
2380 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
2381 if (result != ISC_R_SUCCESS)
2384 symvalue.as_cpointer = NULL;
2385 for (i = 0; default_channels[i] != NULL; i++) {
2386 tresult = isc_symtab_define(symtab, default_channels[i], 1,
2387 symvalue, isc_symexists_replace);
2388 if (tresult != ISC_R_SUCCESS)
2392 cfg_map_get(logobj, "channel", &channels);
2394 for (element = cfg_list_first(channels);
2396 element = cfg_list_next(element))
2398 channel = cfg_listelt_value(element);
2399 channelname = cfg_obj_asstring(cfg_map_getname(channel));
2400 fileobj = syslogobj = nullobj = stderrobj = NULL;
2401 (void)cfg_map_get(channel, "file", &fileobj);
2402 (void)cfg_map_get(channel, "syslog", &syslogobj);
2403 (void)cfg_map_get(channel, "null", &nullobj);
2404 (void)cfg_map_get(channel, "stderr", &stderrobj);
2406 if (fileobj != NULL)
2408 if (syslogobj != NULL)
2410 if (nullobj != NULL)
2412 if (stderrobj != NULL)
2415 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2416 "channel '%s': exactly one of file, syslog, "
2417 "null, and stderr must be present",
2419 result = ISC_R_FAILURE;
2421 tresult = isc_symtab_define(symtab, channelname, 1,
2422 symvalue, isc_symexists_replace);
2423 if (tresult != ISC_R_SUCCESS)
2427 cfg_map_get(logobj, "category", &categories);
2429 for (element = cfg_list_first(categories);
2431 element = cfg_list_next(element))
2433 category = cfg_listelt_value(element);
2434 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
2435 if (isc_log_categorybyname(logctx, catname) == NULL) {
2436 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
2437 "undefined category: '%s'", catname);
2438 result = ISC_R_FAILURE;
2440 channels = cfg_tuple_get(category, "destinations");
2441 for (delement = cfg_list_first(channels);
2443 delement = cfg_list_next(delement))
2445 channel = cfg_listelt_value(delement);
2446 channelname = cfg_obj_asstring(channel);
2447 tresult = isc_symtab_lookup(symtab, channelname, 1,
2449 if (tresult != ISC_R_SUCCESS) {
2450 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2451 "undefined channel: '%s'",
2457 isc_symtab_destroy(&symtab);
2462 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
2465 isc_result_t result = ISC_R_SUCCESS;
2466 const cfg_obj_t *control_keylist;
2467 const cfg_listelt_t *element;
2468 const cfg_obj_t *key;
2471 control_keylist = cfg_tuple_get(control, "keys");
2472 if (cfg_obj_isvoid(control_keylist))
2473 return (ISC_R_SUCCESS);
2475 for (element = cfg_list_first(control_keylist);
2477 element = cfg_list_next(element))
2479 key = cfg_listelt_value(element);
2480 keyval = cfg_obj_asstring(key);
2482 if (!rndckey_exists(keylist, keyval)) {
2483 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2484 "unknown key '%s'", keyval);
2485 result = ISC_R_NOTFOUND;
2492 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
2495 isc_result_t result = ISC_R_SUCCESS, tresult;
2496 cfg_aclconfctx_t *actx = NULL;
2497 const cfg_listelt_t *element, *element2;
2498 const cfg_obj_t *allow;
2499 const cfg_obj_t *control;
2500 const cfg_obj_t *controls;
2501 const cfg_obj_t *controlslist = NULL;
2502 const cfg_obj_t *inetcontrols;
2503 const cfg_obj_t *unixcontrols;
2504 const cfg_obj_t *keylist = NULL;
2506 isc_uint32_t perm, mask;
2507 dns_acl_t *acl = NULL;
2508 isc_sockaddr_t addr;
2511 (void)cfg_map_get(config, "controls", &controlslist);
2512 if (controlslist == NULL)
2513 return (ISC_R_SUCCESS);
2515 (void)cfg_map_get(config, "key", &keylist);
2517 cfg_aclconfctx_create(mctx, &actx);
2520 * INET: Check allow clause.
2521 * UNIX: Check "perm" for sanity, check path length.
2523 for (element = cfg_list_first(controlslist);
2525 element = cfg_list_next(element)) {
2526 controls = cfg_listelt_value(element);
2527 unixcontrols = NULL;
2528 inetcontrols = NULL;
2529 (void)cfg_map_get(controls, "unix", &unixcontrols);
2530 (void)cfg_map_get(controls, "inet", &inetcontrols);
2531 for (element2 = cfg_list_first(inetcontrols);
2533 element2 = cfg_list_next(element2)) {
2534 control = cfg_listelt_value(element2);
2535 allow = cfg_tuple_get(control, "allow");
2536 tresult = cfg_acl_fromconfig(allow, config, logctx,
2537 actx, mctx, 0, &acl);
2539 dns_acl_detach(&acl);
2540 if (tresult != ISC_R_SUCCESS)
2542 tresult = bind9_check_controlskeys(control, keylist,
2544 if (tresult != ISC_R_SUCCESS)
2547 for (element2 = cfg_list_first(unixcontrols);
2549 element2 = cfg_list_next(element2)) {
2550 control = cfg_listelt_value(element2);
2551 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
2552 tresult = isc_sockaddr_frompath(&addr, path);
2553 if (tresult == ISC_R_NOSPACE) {
2554 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
2555 "unix control '%s': path too long",
2557 result = ISC_R_NOSPACE;
2559 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
2560 for (i = 0; i < 3; i++) {
2561 #ifdef NEED_SECURE_DIRECTORY
2562 mask = (0x1 << (i*3)); /* SEARCH */
2564 mask = (0x6 << (i*3)); /* READ + WRITE */
2566 if ((perm & mask) == mask)
2570 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2571 "unix control '%s' allows access "
2572 "to everyone", path);
2573 } else if (i == 3) {
2574 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2575 "unix control '%s' allows access "
2578 tresult = bind9_check_controlskeys(control, keylist,
2580 if (tresult != ISC_R_SUCCESS)
2584 cfg_aclconfctx_detach(&actx);
2589 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
2592 const cfg_obj_t *options = NULL;
2593 const cfg_obj_t *views = NULL;
2594 const cfg_obj_t *acls = NULL;
2595 const cfg_obj_t *kals = NULL;
2596 const cfg_obj_t *obj;
2597 const cfg_listelt_t *velement;
2598 isc_result_t result = ISC_R_SUCCESS;
2599 isc_result_t tresult;
2600 isc_symtab_t *symtab = NULL;
2602 static const char *builtin[] = { "localhost", "localnets",
2605 (void)cfg_map_get(config, "options", &options);
2607 if (options != NULL &&
2608 check_options(options, logctx, mctx,
2609 optlevel_options) != ISC_R_SUCCESS)
2610 result = ISC_R_FAILURE;
2612 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
2613 result = ISC_R_FAILURE;
2615 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
2616 result = ISC_R_FAILURE;
2618 if (options != NULL &&
2619 check_order(options, logctx) != ISC_R_SUCCESS)
2620 result = ISC_R_FAILURE;
2622 (void)cfg_map_get(config, "view", &views);
2624 if (views != NULL && options != NULL)
2625 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2626 result = ISC_R_FAILURE;
2628 if (views == NULL) {
2629 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
2630 logctx, mctx) != ISC_R_SUCCESS)
2631 result = ISC_R_FAILURE;
2633 const cfg_obj_t *zones = NULL;
2635 (void)cfg_map_get(config, "zone", &zones);
2636 if (zones != NULL) {
2637 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
2638 "when using 'view' statements, "
2639 "all zones must be in views");
2640 result = ISC_R_FAILURE;
2644 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
2645 if (tresult != ISC_R_SUCCESS)
2647 for (velement = cfg_list_first(views);
2649 velement = cfg_list_next(velement))
2651 const cfg_obj_t *view = cfg_listelt_value(velement);
2652 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
2653 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
2654 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
2655 dns_rdataclass_t vclass = dns_rdataclass_in;
2656 isc_result_t tresult = ISC_R_SUCCESS;
2657 const char *key = cfg_obj_asstring(vname);
2658 isc_symvalue_t symvalue;
2660 if (cfg_obj_isstring(vclassobj)) {
2663 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
2664 r.length = strlen(r.base);
2665 tresult = dns_rdataclass_fromtext(&vclass, &r);
2666 if (tresult != ISC_R_SUCCESS)
2667 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
2668 "view '%s': invalid class %s",
2669 cfg_obj_asstring(vname), r.base);
2671 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
2672 symvalue.as_cpointer = view;
2673 tresult = isc_symtab_define(symtab, key, vclass,
2675 isc_symexists_reject);
2676 if (tresult == ISC_R_EXISTS) {
2679 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
2680 vclass, &symvalue) == ISC_R_SUCCESS);
2681 file = cfg_obj_file(symvalue.as_cpointer);
2682 line = cfg_obj_line(symvalue.as_cpointer);
2683 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2684 "view '%s': already exists "
2685 "previous definition: %s:%u",
2688 } else if (tresult != ISC_R_SUCCESS) {
2690 } else if ((strcasecmp(key, "_bind") == 0 &&
2691 vclass == dns_rdataclass_ch) ||
2692 (strcasecmp(key, "_default") == 0 &&
2693 vclass == dns_rdataclass_in)) {
2694 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2695 "attempt to redefine builtin view "
2697 result = ISC_R_EXISTS;
2700 if (tresult == ISC_R_SUCCESS)
2701 tresult = check_viewconf(config, voptions, key,
2702 vclass, logctx, mctx);
2703 if (tresult != ISC_R_SUCCESS)
2704 result = ISC_R_FAILURE;
2707 isc_symtab_destroy(&symtab);
2709 if (views != NULL && options != NULL) {
2711 tresult = cfg_map_get(options, "cache-file", &obj);
2712 if (tresult == ISC_R_SUCCESS) {
2713 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2714 "'cache-file' cannot be a global "
2715 "option if views are present");
2716 result = ISC_R_FAILURE;
2720 cfg_map_get(config, "acl", &acls);
2723 const cfg_listelt_t *elt;
2724 const cfg_listelt_t *elt2;
2725 const char *aclname;
2727 for (elt = cfg_list_first(acls);
2729 elt = cfg_list_next(elt)) {
2730 const cfg_obj_t *acl = cfg_listelt_value(elt);
2731 unsigned int line = cfg_obj_line(acl);
2734 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2736 i < sizeof(builtin) / sizeof(builtin[0]);
2738 if (strcasecmp(aclname, builtin[i]) == 0) {
2739 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
2740 "attempt to redefine "
2743 result = ISC_R_FAILURE;
2747 for (elt2 = cfg_list_next(elt);
2749 elt2 = cfg_list_next(elt2)) {
2750 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2752 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2754 if (strcasecmp(aclname, name) == 0) {
2755 const char *file = cfg_obj_file(acl);
2758 file = "<unknown file>";
2760 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2761 "attempt to redefine "
2762 "acl '%s' previous "
2763 "definition: %s:%u",
2765 result = ISC_R_FAILURE;
2771 tresult = cfg_map_get(config, "kal", &kals);
2772 if (tresult == ISC_R_SUCCESS) {
2773 const cfg_listelt_t *elt;
2774 const cfg_listelt_t *elt2;
2775 const char *aclname;
2777 for (elt = cfg_list_first(kals);
2779 elt = cfg_list_next(elt)) {
2780 const cfg_obj_t *acl = cfg_listelt_value(elt);
2782 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2784 for (elt2 = cfg_list_next(elt);
2786 elt2 = cfg_list_next(elt2)) {
2787 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2789 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2791 if (strcasecmp(aclname, name) == 0) {
2792 const char *file = cfg_obj_file(acl);
2793 unsigned int line = cfg_obj_line(acl);
2796 file = "<unknown file>";
2798 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2799 "attempt to redefine "
2800 "kal '%s' previous "
2801 "definition: %s:%u",
2803 result = ISC_R_FAILURE;