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) {
290 cfg_obj_log(cfg_listelt_value(element), logctx,
291 ISC_LOG_ERROR, "invalid algorithm '%s'",
300 nameexist(const cfg_obj_t *obj, const char *name, int value,
301 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
308 isc_symvalue_t symvalue;
310 key = isc_mem_strdup(mctx, name);
312 return (ISC_R_NOMEMORY);
313 symvalue.as_cpointer = obj;
314 result = isc_symtab_define(symtab, key, value, symvalue,
315 isc_symexists_reject);
316 if (result == ISC_R_EXISTS) {
317 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
318 &symvalue) == ISC_R_SUCCESS);
319 file = cfg_obj_file(symvalue.as_cpointer);
320 line = cfg_obj_line(symvalue.as_cpointer);
323 file = "<unknown file>";
324 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
325 isc_mem_free(mctx, key);
326 result = ISC_R_EXISTS;
327 } else if (result != ISC_R_SUCCESS) {
328 isc_mem_free(mctx, key);
334 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
337 const cfg_obj_t *obj;
338 char namebuf[DNS_NAME_FORMATSIZE];
340 dns_fixedname_t fixed;
343 isc_result_t result = ISC_R_SUCCESS;
345 dns_fixedname_init(&fixed);
346 name = dns_fixedname_name(&fixed);
347 obj = cfg_tuple_get(secure, "name");
348 str = cfg_obj_asstring(obj);
349 isc_buffer_init(&b, str, strlen(str));
350 isc_buffer_add(&b, strlen(str));
351 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
352 if (result != ISC_R_SUCCESS) {
353 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
354 "bad domain name '%s'", str);
356 dns_name_format(name, namebuf, sizeof(namebuf));
357 result = nameexist(secure, namebuf, 1, symtab,
358 "dnssec-must-be-secure '%s': already "
359 "exists previous definition: %s:%u",
366 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
367 const cfg_obj_t *voptions, const cfg_obj_t *config,
368 isc_log_t *logctx, isc_mem_t *mctx)
371 const cfg_obj_t *aclobj = NULL;
372 const cfg_obj_t *options;
373 dns_acl_t *acl = NULL;
375 if (zconfig != NULL) {
376 options = cfg_tuple_get(zconfig, "options");
377 cfg_map_get(options, aclname, &aclobj);
379 if (voptions != NULL && aclobj == NULL)
380 cfg_map_get(voptions, aclname, &aclobj);
381 if (config != NULL && aclobj == NULL) {
383 cfg_map_get(config, "options", &options);
385 cfg_map_get(options, aclname, &aclobj);
388 return (ISC_R_SUCCESS);
389 result = cfg_acl_fromconfig(aclobj, config, logctx,
390 actx, mctx, 0, &acl);
392 dns_acl_detach(&acl);
397 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
398 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
400 isc_result_t result = ISC_R_SUCCESS, tresult;
403 static const char *acls[] = { "allow-query", "allow-query-on",
404 "allow-query-cache", "allow-query-cache-on",
405 "blackhole", "match-clients", "match-destinations",
406 "sortlist", "filter-aaaa", NULL };
408 while (acls[i] != NULL) {
409 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
411 if (tresult != ISC_R_SUCCESS)
417 static const unsigned char zeros[16];
420 check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
421 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
423 isc_result_t result = ISC_R_SUCCESS;
424 const cfg_obj_t *dns64 = NULL;
425 const cfg_obj_t *options;
426 const cfg_listelt_t *element;
427 const cfg_obj_t *map, *obj;
428 isc_netaddr_t na, sa;
429 unsigned int prefixlen;
433 static const char *acls[] = { "clients", "exclude", "mapped", NULL};
435 if (voptions != NULL)
436 cfg_map_get(voptions, "dns64", &dns64);
437 if (config != NULL && dns64 == NULL) {
439 cfg_map_get(config, "options", &options);
441 cfg_map_get(options, "dns64", &dns64);
444 return (ISC_R_SUCCESS);
446 for (element = cfg_list_first(dns64);
448 element = cfg_list_next(element))
450 map = cfg_listelt_value(element);
451 obj = cfg_map_getname(map);
453 cfg_obj_asnetprefix(obj, &na, &prefixlen);
454 if (na.family != AF_INET6) {
455 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
456 "dns64 requires a IPv6 prefix");
457 result = ISC_R_FAILURE;
461 if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
462 prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
463 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
464 "bad prefix length %u [32/40/48/56/64/96]",
466 result = ISC_R_FAILURE;
470 for (i = 0; acls[i] != NULL; i++) {
472 (void)cfg_map_get(map, acls[i], &obj);
474 dns_acl_t *acl = NULL;
475 isc_result_t tresult;
477 tresult = cfg_acl_fromconfig(obj, config,
481 dns_acl_detach(&acl);
482 if (tresult != ISC_R_SUCCESS)
488 (void)cfg_map_get(map, "suffix", &obj);
490 isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
491 if (sa.family != AF_INET6) {
492 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
493 "dns64 requires a IPv6 suffix");
494 result = ISC_R_FAILURE;
497 nbytes = prefixlen / 8 + 4;
498 if (prefixlen >= 32 && prefixlen <= 64)
500 if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
501 char netaddrbuf[ISC_NETADDR_FORMATSIZE];
502 isc_netaddr_format(&sa, netaddrbuf,
504 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
505 "bad suffix '%s' leading "
506 "%u octets not zeros",
508 result = ISC_R_FAILURE;
518 * Check allow-recursion and allow-recursion-on acls, and also log a
519 * warning if they're inconsistent with the "recursion" option.
522 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
523 const char *viewname, const cfg_obj_t *config,
524 isc_log_t *logctx, isc_mem_t *mctx)
526 const cfg_obj_t *options, *aclobj, *obj = NULL;
527 dns_acl_t *acl = NULL;
528 isc_result_t result = ISC_R_SUCCESS, tresult;
529 isc_boolean_t recursion;
530 const char *forview = " for view ";
533 static const char *acls[] = { "allow-recursion", "allow-recursion-on",
536 if (voptions != NULL)
537 cfg_map_get(voptions, "recursion", &obj);
538 if (obj == NULL && config != NULL) {
540 cfg_map_get(config, "options", &options);
542 cfg_map_get(options, "recursion", &obj);
545 recursion = ISC_TRUE;
547 recursion = cfg_obj_asboolean(obj);
549 if (viewname == NULL) {
554 for (i = 0; acls[i] != NULL; i++) {
555 aclobj = options = NULL;
558 if (voptions != NULL)
559 cfg_map_get(voptions, acls[i], &aclobj);
560 if (config != NULL && aclobj == NULL) {
562 cfg_map_get(config, "options", &options);
564 cfg_map_get(options, acls[i], &aclobj);
569 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
570 actx, mctx, 0, &acl);
572 if (tresult != ISC_R_SUCCESS)
578 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
579 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
580 "both \"recursion no;\" and "
582 acls[i], forview, viewname);
586 dns_acl_detach(&acl);
593 check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
594 const char *viewname, const cfg_obj_t *config,
595 isc_log_t *logctx, isc_mem_t *mctx)
597 const cfg_obj_t *options, *aclobj, *obj = NULL;
598 dns_acl_t *acl = NULL;
599 isc_result_t result = ISC_R_SUCCESS, tresult;
600 dns_v4_aaaa_t filter;
601 const char *forview = " for view ";
603 if (voptions != NULL)
604 cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
605 if (obj == NULL && config != NULL) {
607 cfg_map_get(config, "options", &options);
609 cfg_map_get(options, "filter-aaaa-on-v4", &obj);
613 filter = dns_v4_aaaa_ok; /* default */
614 else if (cfg_obj_isboolean(obj))
615 filter = cfg_obj_asboolean(obj) ? dns_v4_aaaa_filter :
618 filter = dns_v4_aaaa_break_dnssec; /* break-dnssec */
620 if (viewname == NULL) {
625 aclobj = options = NULL;
628 if (voptions != NULL)
629 cfg_map_get(voptions, "filter-aaaa", &aclobj);
630 if (config != NULL && aclobj == NULL) {
632 cfg_map_get(config, "options", &options);
634 cfg_map_get(options, "filter-aaaa", &aclobj);
639 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
640 actx, mctx, 0, &acl);
642 if (tresult != ISC_R_SUCCESS) {
644 } else if (filter != dns_v4_aaaa_ok && dns_acl_isnone(acl)) {
645 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
646 "both \"filter-aaaa-on-v4 %s;\" and "
647 "\"filter-aaaa\" is 'none;'%s%s",
648 filter == dns_v4_aaaa_break_dnssec ?
649 "break-dnssec" : "yes", forview, viewname);
650 result = ISC_R_FAILURE;
651 } else if (filter == dns_v4_aaaa_ok && !dns_acl_isnone(acl)) {
652 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
653 "both \"filter-aaaa-on-v4 no;\" and "
654 "\"filter-aaaa\" is set%s%s", forview, viewname);
655 result = ISC_R_FAILURE;
659 dns_acl_detach(&acl);
678 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
681 isc_result_t result = ISC_R_SUCCESS;
682 isc_result_t tresult;
684 const cfg_obj_t *obj = NULL;
685 const cfg_obj_t *resignobj = NULL;
686 const cfg_listelt_t *element;
687 isc_symtab_t *symtab = NULL;
688 dns_fixedname_t fixed;
693 static intervaltable intervals[] = {
694 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
695 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
696 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
697 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
698 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
699 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
700 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
701 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
704 static const char *server_contact[] = {
705 "empty-server", "empty-contact",
706 "dns64-server", "dns64-contact",
711 * Check that fields specified in units of time other than seconds
712 * have reasonable values.
714 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
717 (void)cfg_map_get(options, intervals[i].name, &obj);
720 val = cfg_obj_asuint32(obj);
721 if (val > intervals[i].max) {
722 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
723 "%s '%u' is out of range (0..%u)",
724 intervals[i].name, val,
726 result = ISC_R_RANGE;
727 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
728 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
729 "%s '%d' is out of range",
730 intervals[i].name, val);
731 result = ISC_R_RANGE;
736 cfg_map_get(options, "sig-validity-interval", &obj);
738 isc_uint32_t validity, resign = 0;
740 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
741 resignobj = cfg_tuple_get(obj, "re-sign");
742 if (!cfg_obj_isvoid(resignobj))
743 resign = cfg_obj_asuint32(resignobj);
745 if (validity > 3660 || validity == 0) { /* 10 years */
746 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
747 "%s '%u' is out of range (1..3660)",
748 "sig-validity-interval", validity);
749 result = ISC_R_RANGE;
752 if (!cfg_obj_isvoid(resignobj)) {
753 if (resign > 3660 || resign == 0) { /* 10 years */
754 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
755 "%s '%u' is out of range (1..3660)",
756 "sig-validity-interval (re-sign)",
758 result = ISC_R_RANGE;
759 } else if ((validity > 7 && validity < resign) ||
760 (validity <= 7 && validity * 24 < resign)) {
761 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
762 "validity interval (%u days) "
763 "less than re-signing interval "
764 "(%u %s)", validity, resign,
765 (validity > 7) ? "days" : "hours");
766 result = ISC_R_RANGE;
772 (void)cfg_map_get(options, "preferred-glue", &obj);
775 str = cfg_obj_asstring(obj);
776 if (strcasecmp(str, "a") != 0 &&
777 strcasecmp(str, "aaaa") != 0 &&
778 strcasecmp(str, "none") != 0)
779 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
780 "preferred-glue unexpected value '%s'",
785 (void)cfg_map_get(options, "root-delegation-only", &obj);
787 if (!cfg_obj_isvoid(obj)) {
788 const cfg_listelt_t *element;
789 const cfg_obj_t *exclude;
791 dns_fixedname_t fixed;
795 dns_fixedname_init(&fixed);
796 name = dns_fixedname_name(&fixed);
797 for (element = cfg_list_first(obj);
799 element = cfg_list_next(element)) {
800 exclude = cfg_listelt_value(element);
801 str = cfg_obj_asstring(exclude);
802 isc_buffer_init(&b, str, strlen(str));
803 isc_buffer_add(&b, strlen(str));
804 tresult = dns_name_fromtext(name, &b,
807 if (tresult != ISC_R_SUCCESS) {
808 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
809 "bad domain name '%s'",
818 * Set supported DNSSEC algorithms.
821 (void)cfg_map_get(options, "disable-algorithms", &obj);
823 for (element = cfg_list_first(obj);
825 element = cfg_list_next(element))
827 obj = cfg_listelt_value(element);
828 tresult = disabled_algorithms(obj, logctx);
829 if (tresult != ISC_R_SUCCESS)
834 dns_fixedname_init(&fixed);
835 name = dns_fixedname_name(&fixed);
838 * Check the DLV zone name.
841 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
843 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
845 if (tresult != ISC_R_SUCCESS)
847 for (element = cfg_list_first(obj);
849 element = cfg_list_next(element))
852 const cfg_obj_t *dlvobj, *anchor;
854 obj = cfg_listelt_value(element);
856 anchor = cfg_tuple_get(obj, "trust-anchor");
857 dlvobj = cfg_tuple_get(obj, "domain");
858 dlv = cfg_obj_asstring(dlvobj);
861 * If domain is "auto" or "no" and trust anchor
862 * is missing, skip remaining tests
864 if (cfg_obj_isvoid(anchor)) {
865 if (!strcasecmp(dlv, "no") ||
866 !strcasecmp(dlv, "auto"))
870 isc_buffer_init(&b, dlv, strlen(dlv));
871 isc_buffer_add(&b, strlen(dlv));
872 tresult = dns_name_fromtext(name, &b, dns_rootname,
874 if (tresult != ISC_R_SUCCESS) {
875 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
876 "bad domain name '%s'", dlv);
880 if (symtab != NULL) {
881 tresult = nameexist(obj, dlv, 1, symtab,
882 "dnssec-lookaside '%s': "
883 "already exists previous "
886 if (tresult != ISC_R_SUCCESS &&
887 result == ISC_R_SUCCESS)
891 * XXXMPA to be removed when multiple lookaside
892 * namespaces are supported.
894 if (!dns_name_equal(dns_rootname, name)) {
895 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
896 "dnssec-lookaside '%s': "
897 "non-root not yet supported", dlv);
898 if (result == ISC_R_SUCCESS)
899 result = ISC_R_FAILURE;
902 if (!cfg_obj_isvoid(anchor)) {
903 dlv = cfg_obj_asstring(anchor);
904 isc_buffer_init(&b, dlv, strlen(dlv));
905 isc_buffer_add(&b, strlen(dlv));
906 tresult = dns_name_fromtext(name, &b,
910 if (tresult != ISC_R_SUCCESS) {
911 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
912 "bad domain name '%s'",
914 if (result == ISC_R_SUCCESS)
918 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
919 "dnssec-lookaside requires "
920 "either 'auto' or 'no', or a "
921 "domain and trust anchor");
922 if (result == ISC_R_SUCCESS)
923 result = ISC_R_FAILURE;
928 isc_symtab_destroy(&symtab);
932 * Check auto-dnssec at the view/options level
935 (void)cfg_map_get(options, "auto-dnssec", &obj);
937 const char *arg = cfg_obj_asstring(obj);
938 if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
939 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
940 "auto-dnssec may only be activated at the "
942 result = ISC_R_FAILURE;
947 * Check dnssec-must-be-secure.
950 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
952 isc_symtab_t *symtab = NULL;
953 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
955 if (tresult != ISC_R_SUCCESS)
957 for (element = cfg_list_first(obj);
959 element = cfg_list_next(element))
961 obj = cfg_listelt_value(element);
962 tresult = mustbesecure(obj, symtab, logctx, mctx);
963 if (tresult != ISC_R_SUCCESS)
967 isc_symtab_destroy(&symtab);
971 * Check server/contacts for syntactic validity.
973 for (i= 0; server_contact[i] != NULL; i++) {
975 (void)cfg_map_get(options, server_contact[i], &obj);
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),
981 &b, dns_rootname, 0, NULL);
982 if (tresult != ISC_R_SUCCESS) {
983 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
984 "%s: invalid name '%s'",
985 server_contact[i], str);
986 result = ISC_R_FAILURE;
992 * Check empty zone configuration.
995 (void)cfg_map_get(options, "disable-empty-zone", &obj);
996 for (element = cfg_list_first(obj);
998 element = cfg_list_next(element))
1000 obj = cfg_listelt_value(element);
1001 str = cfg_obj_asstring(obj);
1002 isc_buffer_init(&b, str, strlen(str));
1003 isc_buffer_add(&b, strlen(str));
1004 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1005 dns_rootname, 0, NULL);
1006 if (tresult != ISC_R_SUCCESS) {
1007 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1008 "disable-empty-zone: invalid name '%s'",
1010 result = ISC_R_FAILURE;
1015 * Check that server-id is not too long.
1016 * 1024 bytes should be big enough.
1019 (void)cfg_map_get(options, "server-id", &obj);
1020 if (obj != NULL && cfg_obj_isstring(obj) &&
1021 strlen(cfg_obj_asstring(obj)) > 1024U) {
1022 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1023 "'server-id' too big (>1024 bytes)");
1024 result = ISC_R_FAILURE;
1031 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
1032 isc_result_t result;
1033 const cfg_obj_t *masters = NULL;
1034 const cfg_listelt_t *elt;
1036 result = cfg_map_get(cctx, "masters", &masters);
1037 if (result != ISC_R_SUCCESS)
1039 for (elt = cfg_list_first(masters);
1041 elt = cfg_list_next(elt)) {
1042 const cfg_obj_t *list;
1043 const char *listname;
1045 list = cfg_listelt_value(elt);
1046 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
1048 if (strcasecmp(listname, name) == 0) {
1050 return (ISC_R_SUCCESS);
1053 return (ISC_R_NOTFOUND);
1057 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
1058 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
1060 isc_result_t result = ISC_R_SUCCESS;
1061 isc_result_t tresult;
1062 isc_uint32_t count = 0;
1063 isc_symtab_t *symtab = NULL;
1064 isc_symvalue_t symvalue;
1065 const cfg_listelt_t *element;
1066 const cfg_listelt_t **stack = NULL;
1067 isc_uint32_t stackcount = 0, pushed = 0;
1068 const cfg_obj_t *list;
1070 REQUIRE(countp != NULL);
1071 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1072 if (result != ISC_R_SUCCESS) {
1078 list = cfg_tuple_get(obj, "addresses");
1079 element = cfg_list_first(list);
1083 element = cfg_list_next(element))
1085 const char *listname;
1086 const cfg_obj_t *addr;
1087 const cfg_obj_t *key;
1089 addr = cfg_tuple_get(cfg_listelt_value(element),
1091 key = cfg_tuple_get(cfg_listelt_value(element), "key");
1093 if (cfg_obj_issockaddr(addr)) {
1097 if (!cfg_obj_isvoid(key)) {
1098 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1099 "unexpected token '%s'",
1100 cfg_obj_asstring(key));
1101 if (result == ISC_R_SUCCESS)
1102 result = ISC_R_FAILURE;
1104 listname = cfg_obj_asstring(addr);
1105 symvalue.as_cpointer = addr;
1106 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
1107 isc_symexists_reject);
1108 if (tresult == ISC_R_EXISTS)
1110 tresult = get_masters_def(config, listname, &obj);
1111 if (tresult != ISC_R_SUCCESS) {
1112 if (result == ISC_R_SUCCESS)
1114 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
1115 "unable to find masters list '%s'",
1120 if (stackcount == pushed) {
1122 isc_uint32_t newlen = stackcount + 16;
1123 size_t newsize, oldsize;
1125 newsize = newlen * sizeof(*stack);
1126 oldsize = stackcount * sizeof(*stack);
1127 new = isc_mem_get(mctx, newsize);
1130 if (stackcount != 0) {
1133 DE_CONST(stack, ptr);
1134 memcpy(new, stack, oldsize);
1135 isc_mem_put(mctx, ptr, oldsize);
1138 stackcount = newlen;
1140 stack[pushed++] = cfg_list_next(element);
1144 element = stack[--pushed];
1148 if (stack != NULL) {
1151 DE_CONST(stack, ptr);
1152 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1154 isc_symtab_destroy(&symtab);
1160 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1161 isc_result_t result = ISC_R_SUCCESS;
1162 isc_result_t tresult;
1163 const cfg_listelt_t *element;
1164 const cfg_listelt_t *element2;
1165 dns_fixedname_t fixed;
1169 /* Check for "update-policy local;" */
1170 if (cfg_obj_isstring(policy) &&
1171 strcmp("local", cfg_obj_asstring(policy)) == 0)
1172 return (ISC_R_SUCCESS);
1174 /* Now check the grant policy */
1175 for (element = cfg_list_first(policy);
1177 element = cfg_list_next(element))
1179 const cfg_obj_t *stmt = cfg_listelt_value(element);
1180 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1181 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1182 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1183 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1185 dns_fixedname_init(&fixed);
1186 str = cfg_obj_asstring(identity);
1187 isc_buffer_init(&b, str, strlen(str));
1188 isc_buffer_add(&b, strlen(str));
1189 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1190 dns_rootname, 0, NULL);
1191 if (tresult != ISC_R_SUCCESS) {
1192 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1193 "'%s' is not a valid name", str);
1197 if (tresult == ISC_R_SUCCESS &&
1198 strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
1199 dns_fixedname_init(&fixed);
1200 str = cfg_obj_asstring(dname);
1201 isc_buffer_init(&b, str, strlen(str));
1202 isc_buffer_add(&b, strlen(str));
1203 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
1204 &b, dns_rootname, 0, NULL);
1205 if (tresult != ISC_R_SUCCESS) {
1206 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1207 "'%s' is not a valid name", str);
1212 if (tresult == ISC_R_SUCCESS &&
1213 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
1214 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
1215 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1216 "'%s' is not a wildcard", str);
1217 result = ISC_R_FAILURE;
1220 for (element2 = cfg_list_first(typelist);
1222 element2 = cfg_list_next(element2))
1224 const cfg_obj_t *typeobj;
1226 dns_rdatatype_t type;
1228 typeobj = cfg_listelt_value(element2);
1229 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1230 r.length = strlen(r.base);
1232 tresult = dns_rdatatype_fromtext(&type, &r);
1233 if (tresult != ISC_R_SUCCESS) {
1234 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1235 "'%s' is not a valid type", r.base);
1243 #define MASTERZONE 1
1247 #define FORWARDZONE 16
1248 #define DELEGATIONZONE 32
1249 #define STATICSTUBZONE 64
1250 #define CHECKACL 128
1258 check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) {
1259 isc_result_t result = ISC_R_SUCCESS;
1260 const cfg_obj_t *obj = NULL;
1263 static const char *nonzero[] = { "max-retry-time", "min-retry-time",
1264 "max-refresh-time", "min-refresh-time" };
1266 * Check if value is zero.
1268 for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) {
1270 if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS &&
1271 cfg_obj_asuint32(obj) == 0) {
1272 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1273 "'%s' must not be zero", nonzero[i]);
1274 result = ISC_R_FAILURE;
1281 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1282 const cfg_obj_t *config, isc_symtab_t *symtab,
1283 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
1284 isc_log_t *logctx, isc_mem_t *mctx)
1286 const char *znamestr;
1287 const char *typestr;
1289 const cfg_obj_t *zoptions, *goptions = NULL;
1290 const cfg_obj_t *obj = NULL;
1291 isc_result_t result = ISC_R_SUCCESS;
1292 isc_result_t tresult;
1294 dns_rdataclass_t zclass;
1295 dns_fixedname_t fixedname;
1296 dns_name_t *zname = NULL;
1298 isc_boolean_t root = ISC_FALSE;
1299 const cfg_listelt_t *element;
1301 static optionstable options[] = {
1302 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL |
1304 { "allow-notify", SLAVEZONE | CHECKACL },
1305 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1306 { "notify", MASTERZONE | SLAVEZONE },
1307 { "also-notify", MASTERZONE | SLAVEZONE },
1308 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
1309 { "delegation-only", HINTZONE | STUBZONE | DELEGATIONZONE },
1310 { "forward", MASTERZONE | SLAVEZONE | STUBZONE |
1311 STATICSTUBZONE | FORWARDZONE },
1312 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE |
1313 STATICSTUBZONE | FORWARDZONE },
1314 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
1315 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
1316 { "notify-source", MASTERZONE | SLAVEZONE },
1317 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1318 { "transfer-source", SLAVEZONE | STUBZONE },
1319 { "transfer-source-v6", SLAVEZONE | STUBZONE },
1320 { "max-transfer-time-in", SLAVEZONE | STUBZONE },
1321 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1322 { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
1323 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1324 { "max-retry-time", SLAVEZONE | STUBZONE },
1325 { "min-retry-time", SLAVEZONE | STUBZONE },
1326 { "max-refresh-time", SLAVEZONE | STUBZONE },
1327 { "min-refresh-time", SLAVEZONE | STUBZONE },
1328 { "dnssec-secure-to-insecure", MASTERZONE },
1329 { "sig-validity-interval", MASTERZONE },
1330 { "sig-re-signing-interval", MASTERZONE },
1331 { "sig-signing-nodes", MASTERZONE },
1332 { "sig-signing-type", MASTERZONE },
1333 { "sig-signing-signatures", MASTERZONE },
1334 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
1336 { "allow-update", MASTERZONE | CHECKACL },
1337 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1338 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1339 { "journal", MASTERZONE | SLAVEZONE },
1340 { "ixfr-base", MASTERZONE | SLAVEZONE },
1341 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1342 { "masters", SLAVEZONE | STUBZONE },
1343 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1344 { "update-policy", MASTERZONE },
1345 { "database", MASTERZONE | SLAVEZONE | STUBZONE },
1346 { "key-directory", MASTERZONE },
1347 { "check-wildcard", MASTERZONE },
1348 { "check-mx", MASTERZONE },
1349 { "check-dup-records", MASTERZONE },
1350 { "integrity-check", MASTERZONE },
1351 { "check-mx-cname", MASTERZONE },
1352 { "check-srv-cname", MASTERZONE },
1353 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
1354 { "update-check-ksk", MASTERZONE },
1355 { "dnssec-dnskey-kskonly", MASTERZONE },
1356 { "auto-dnssec", MASTERZONE },
1357 { "try-tcp-refresh", SLAVEZONE },
1358 { "server-addresses", STATICSTUBZONE },
1359 { "server-names", STATICSTUBZONE },
1362 static optionstable dialups[] = {
1363 { "notify", MASTERZONE | SLAVEZONE },
1364 { "notify-passive", SLAVEZONE },
1365 { "refresh", SLAVEZONE | STUBZONE },
1366 { "passive", SLAVEZONE | STUBZONE },
1370 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1372 zoptions = cfg_tuple_get(zconfig, "options");
1375 cfg_map_get(config, "options", &goptions);
1378 (void)cfg_map_get(zoptions, "type", &obj);
1380 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1381 "zone '%s': type not present", znamestr);
1382 return (ISC_R_FAILURE);
1385 typestr = cfg_obj_asstring(obj);
1386 if (strcasecmp(typestr, "master") == 0)
1388 else if (strcasecmp(typestr, "slave") == 0)
1390 else if (strcasecmp(typestr, "stub") == 0)
1392 else if (strcasecmp(typestr, "static-stub") == 0)
1393 ztype = STATICSTUBZONE;
1394 else if (strcasecmp(typestr, "forward") == 0)
1395 ztype = FORWARDZONE;
1396 else if (strcasecmp(typestr, "hint") == 0)
1398 else if (strcasecmp(typestr, "delegation-only") == 0)
1399 ztype = DELEGATIONZONE;
1401 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1402 "zone '%s': invalid type %s",
1404 return (ISC_R_FAILURE);
1407 obj = cfg_tuple_get(zconfig, "class");
1408 if (cfg_obj_isstring(obj)) {
1411 DE_CONST(cfg_obj_asstring(obj), r.base);
1412 r.length = strlen(r.base);
1413 result = dns_rdataclass_fromtext(&zclass, &r);
1414 if (result != ISC_R_SUCCESS) {
1415 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1416 "zone '%s': invalid class %s",
1418 return (ISC_R_FAILURE);
1420 if (zclass != defclass) {
1421 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1422 "zone '%s': class '%s' does not "
1423 "match view/default class",
1425 return (ISC_R_FAILURE);
1430 * Look for an already existing zone.
1431 * We need to make this canonical as isc_symtab_define()
1432 * deals with strings.
1434 dns_fixedname_init(&fixedname);
1435 isc_buffer_init(&b, znamestr, strlen(znamestr));
1436 isc_buffer_add(&b, strlen(znamestr));
1437 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1438 dns_rootname, DNS_NAME_DOWNCASE, NULL);
1439 if (tresult != ISC_R_SUCCESS) {
1440 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1441 "zone '%s': is not a valid name", znamestr);
1442 result = ISC_R_FAILURE;
1444 char namebuf[DNS_NAME_FORMATSIZE];
1446 zname = dns_fixedname_name(&fixedname);
1447 dns_name_format(zname, namebuf, sizeof(namebuf));
1448 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1449 symtab, "zone '%s': already exists "
1450 "previous definition: %s:%u", logctx, mctx);
1451 if (tresult != ISC_R_SUCCESS)
1453 if (dns_name_equal(zname, dns_rootname))
1458 * Check if value is zero.
1460 if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
1461 result = ISC_R_FAILURE;
1464 * Look for inappropriate options for the given zone type.
1465 * Check that ACLs expand correctly.
1467 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1469 if ((options[i].allowed & ztype) == 0 &&
1470 cfg_map_get(zoptions, options[i].name, &obj) ==
1473 if (strcmp(options[i].name, "allow-update") != 0 ||
1474 ztype != SLAVEZONE) {
1475 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1476 "option '%s' is not allowed "
1477 "in '%s' zone '%s'",
1478 options[i].name, typestr,
1480 result = ISC_R_FAILURE;
1482 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1483 "option '%s' is not allowed "
1484 "in '%s' zone '%s'",
1485 options[i].name, typestr,
1489 if ((options[i].allowed & ztype) != 0 &&
1490 (options[i].allowed & CHECKACL) != 0) {
1492 tresult = checkacl(options[i].name, actx, zconfig,
1493 voptions, config, logctx, mctx);
1494 if (tresult != ISC_R_SUCCESS)
1501 * Slave & stub zones must have a "masters" field.
1503 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1505 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1506 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1507 "zone '%s': missing 'masters' entry",
1509 result = ISC_R_FAILURE;
1512 tresult = validate_masters(obj, config, &count,
1514 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1516 if (tresult == ISC_R_SUCCESS && count == 0) {
1517 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1518 "zone '%s': empty 'masters' entry",
1520 result = ISC_R_FAILURE;
1526 * Master zones can't have both "allow-update" and "update-policy".
1528 if (ztype == MASTERZONE) {
1529 isc_result_t res1, res2, res3;
1534 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1536 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1537 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1538 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1539 "zone '%s': 'allow-update' is ignored "
1540 "when 'update-policy' is present",
1542 result = ISC_R_FAILURE;
1543 } else if (res2 == ISC_R_SUCCESS &&
1544 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1545 result = ISC_R_FAILURE;
1546 ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS);
1550 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
1551 if (res3 == ISC_R_SUCCESS)
1552 arg = cfg_obj_asstring(obj);
1553 if (strcasecmp(arg, "off") != 0 && !ddns) {
1554 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1555 "'auto-dnssec %s;' requires "
1556 "dynamic DNS to be configured in the zone",
1558 result = ISC_R_FAILURE;
1560 if (strcasecmp(arg, "create") == 0) {
1561 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1562 "'auto-dnssec create;' is not "
1564 result = ISC_R_FAILURE;
1568 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1569 if (res1 == ISC_R_SUCCESS) {
1570 isc_uint32_t type = cfg_obj_asuint32(obj);
1571 if (type < 0xff00U || type > 0xffffU)
1572 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1573 "sig-signing-type: %u out of "
1574 "range [%u..%u]", type,
1576 result = ISC_R_FAILURE;
1581 * Check the excessively complicated "dialup" option.
1583 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1584 const cfg_obj_t *dialup = NULL;
1585 (void)cfg_map_get(zoptions, "dialup", &dialup);
1586 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1587 const char *str = cfg_obj_asstring(dialup);
1589 i < sizeof(dialups) / sizeof(dialups[0]);
1592 if (strcasecmp(dialups[i].name, str) != 0)
1594 if ((dialups[i].allowed & ztype) == 0) {
1595 cfg_obj_log(obj, logctx,
1597 "dialup type '%s' is not "
1600 str, typestr, znamestr);
1601 result = ISC_R_FAILURE;
1605 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1606 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1607 "invalid dialup type '%s' in zone "
1608 "'%s'", str, znamestr);
1609 result = ISC_R_FAILURE;
1615 * Check that forwarding is reasonable.
1619 if (voptions != NULL)
1620 (void)cfg_map_get(voptions, "forwarders", &obj);
1622 const cfg_obj_t *options = NULL;
1623 (void)cfg_map_get(config, "options", &options);
1624 if (options != NULL)
1625 (void)cfg_map_get(options, "forwarders", &obj);
1628 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1629 result = ISC_R_FAILURE;
1632 * Check validity of static stub server addresses.
1635 (void)cfg_map_get(zoptions, "server-addresses", &obj);
1636 if (ztype == STATICSTUBZONE && obj != NULL) {
1637 for (element = cfg_list_first(obj);
1639 element = cfg_list_next(element))
1643 obj = cfg_listelt_value(element);
1644 sa = *cfg_obj_assockaddr(obj);
1646 if (isc_sockaddr_getport(&sa) != 0) {
1647 result = ISC_R_FAILURE;
1648 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1649 "port is not configurable for "
1650 "static stub server-addresses");
1653 isc_netaddr_fromsockaddr(&na, &sa);
1654 if (isc_netaddr_getzone(&na) != 0) {
1655 result = ISC_R_FAILURE;
1656 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1657 "scoped address is not allowed "
1659 "server-addresses");
1665 * Check validity of static stub server names.
1668 (void)cfg_map_get(zoptions, "server-names", &obj);
1669 if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
1670 for (element = cfg_list_first(obj);
1672 element = cfg_list_next(element))
1674 const char *snamestr;
1675 dns_fixedname_t fixed_sname;
1679 obj = cfg_listelt_value(element);
1680 snamestr = cfg_obj_asstring(obj);
1682 dns_fixedname_init(&fixed_sname);
1683 isc_buffer_init(&b2, snamestr, strlen(snamestr));
1684 isc_buffer_add(&b2, strlen(snamestr));
1685 sname = dns_fixedname_name(&fixed_sname);
1686 tresult = dns_name_fromtext(sname, &b2, dns_rootname,
1688 if (tresult != ISC_R_SUCCESS) {
1689 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1690 "server-name '%s' is not a valid "
1692 result = ISC_R_FAILURE;
1693 } else if (dns_name_issubdomain(sname, zname)) {
1694 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1695 "server-name '%s' must not be a "
1696 "subdomain of zone name '%s'",
1697 snamestr, znamestr);
1698 result = ISC_R_FAILURE;
1704 * Check various options.
1706 tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
1707 if (tresult != ISC_R_SUCCESS)
1711 * If the zone type is rbt/rbt64 then master/hint zones
1712 * require file clauses.
1715 tresult = cfg_map_get(zoptions, "database", &obj);
1716 if (tresult == ISC_R_NOTFOUND ||
1717 (tresult == ISC_R_SUCCESS &&
1718 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1719 strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1721 tresult = cfg_map_get(zoptions, "file", &obj);
1722 if (tresult != ISC_R_SUCCESS &&
1723 (ztype == MASTERZONE || ztype == HINTZONE)) {
1724 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1725 "zone '%s': missing 'file' entry",
1735 typedef struct keyalgorithms {
1741 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1742 const cfg_obj_t *algobj = NULL;
1743 const cfg_obj_t *secretobj = NULL;
1744 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1745 const char *algorithm;
1748 isc_result_t result;
1750 unsigned char secretbuf[1024];
1751 static const algorithmtable algorithms[] = {
1752 { "hmac-md5", 128 },
1753 { "hmac-md5.sig-alg.reg.int", 0 },
1754 { "hmac-md5.sig-alg.reg.int.", 0 },
1755 { "hmac-sha1", 160 },
1756 { "hmac-sha224", 224 },
1757 { "hmac-sha256", 256 },
1758 { "hmac-sha384", 384 },
1759 { "hmac-sha512", 512 },
1763 (void)cfg_map_get(key, "algorithm", &algobj);
1764 (void)cfg_map_get(key, "secret", &secretobj);
1765 if (secretobj == NULL || algobj == NULL) {
1766 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1767 "key '%s' must have both 'secret' and "
1768 "'algorithm' defined",
1770 return (ISC_R_FAILURE);
1773 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
1774 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
1775 if (result != ISC_R_SUCCESS) {
1776 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
1777 "bad secret '%s'", isc_result_totext(result));
1781 algorithm = cfg_obj_asstring(algobj);
1782 for (i = 0; algorithms[i].name != NULL; i++) {
1783 len = strlen(algorithms[i].name);
1784 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1785 (algorithm[len] == '\0' ||
1786 (algorithms[i].size != 0 && algorithm[len] == '-')))
1789 if (algorithms[i].name == NULL) {
1790 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1791 "unknown algorithm '%s'", algorithm);
1792 return (ISC_R_NOTFOUND);
1794 if (algorithm[len] == '-') {
1795 isc_uint16_t digestbits;
1796 isc_result_t result;
1797 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1798 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1799 if (result == ISC_R_RANGE ||
1800 digestbits > algorithms[i].size) {
1801 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1802 "key '%s' digest-bits too large "
1803 "[%u..%u]", keyname,
1804 algorithms[i].size / 2,
1805 algorithms[i].size);
1806 return (ISC_R_RANGE);
1808 if ((digestbits % 8) != 0) {
1809 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1810 "key '%s' digest-bits not multiple"
1812 return (ISC_R_RANGE);
1815 * Recommended minima for hmac algorithms.
1817 if ((digestbits < (algorithms[i].size / 2U) ||
1818 (digestbits < 80U)))
1819 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1820 "key '%s' digest-bits too small "
1822 algorithms[i].size/2);
1824 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1825 "key '%s': unable to parse digest-bits",
1830 return (ISC_R_SUCCESS);
1834 * Check key list for duplicates key names and that the key names
1835 * are valid domain names as these keys are used for TSIG.
1837 * Check the key contents for validity.
1840 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
1841 isc_mem_t *mctx, isc_log_t *logctx)
1843 char namebuf[DNS_NAME_FORMATSIZE];
1844 dns_fixedname_t fname;
1846 isc_result_t result = ISC_R_SUCCESS;
1847 isc_result_t tresult;
1848 const cfg_listelt_t *element;
1850 dns_fixedname_init(&fname);
1851 name = dns_fixedname_name(&fname);
1852 for (element = cfg_list_first(keys);
1854 element = cfg_list_next(element))
1856 const cfg_obj_t *key = cfg_listelt_value(element);
1857 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
1858 isc_symvalue_t symvalue;
1862 isc_buffer_init(&b, keyid, strlen(keyid));
1863 isc_buffer_add(&b, strlen(keyid));
1864 tresult = dns_name_fromtext(name, &b, dns_rootname,
1866 if (tresult != ISC_R_SUCCESS) {
1867 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1868 "key '%s': bad key name", keyid);
1872 tresult = bind9_check_key(key, logctx);
1873 if (tresult != ISC_R_SUCCESS)
1876 dns_name_format(name, namebuf, sizeof(namebuf));
1877 keyname = isc_mem_strdup(mctx, namebuf);
1878 if (keyname == NULL)
1879 return (ISC_R_NOMEMORY);
1880 symvalue.as_cpointer = key;
1881 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
1882 isc_symexists_reject);
1883 if (tresult == ISC_R_EXISTS) {
1887 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1888 1, &symvalue) == ISC_R_SUCCESS);
1889 file = cfg_obj_file(symvalue.as_cpointer);
1890 line = cfg_obj_line(symvalue.as_cpointer);
1893 file = "<unknown file>";
1894 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1895 "key '%s': already exists "
1896 "previous definition: %s:%u",
1898 isc_mem_free(mctx, keyname);
1900 } else if (tresult != ISC_R_SUCCESS) {
1901 isc_mem_free(mctx, keyname);
1912 { "transfer-source", "transfer-source-v6" },
1913 { "notify-source", "notify-source-v6" },
1914 { "query-source", "query-source-v6" },
1919 * RNDC keys are not normalised unlike TSIG keys.
1921 * "foo." is different to "foo".
1923 static isc_boolean_t
1924 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
1925 const cfg_listelt_t *element;
1926 const cfg_obj_t *obj;
1929 if (keylist == NULL)
1932 for (element = cfg_list_first(keylist);
1934 element = cfg_list_next(element))
1936 obj = cfg_listelt_value(element);
1937 str = cfg_obj_asstring(cfg_map_getname(obj));
1938 if (!strcasecmp(str, keyname))
1945 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
1946 isc_symtab_t *symtab, isc_log_t *logctx)
1948 dns_fixedname_t fname;
1949 isc_result_t result = ISC_R_SUCCESS;
1950 isc_result_t tresult;
1951 const cfg_listelt_t *e1, *e2;
1952 const cfg_obj_t *v1, *v2, *keys;
1953 const cfg_obj_t *servers;
1954 isc_netaddr_t n1, n2;
1955 unsigned int p1, p2;
1956 const cfg_obj_t *obj;
1957 char buf[ISC_NETADDR_FORMATSIZE];
1958 char namebuf[DNS_NAME_FORMATSIZE];
1963 dns_name_t *keyname;
1966 if (voptions != NULL)
1967 (void)cfg_map_get(voptions, "server", &servers);
1968 if (servers == NULL)
1969 (void)cfg_map_get(config, "server", &servers);
1970 if (servers == NULL)
1971 return (ISC_R_SUCCESS);
1973 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1974 v1 = cfg_listelt_value(e1);
1975 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1977 * Check that unused bits are zero.
1979 tresult = isc_netaddr_prefixok(&n1, p1);
1980 if (tresult != ISC_R_SUCCESS) {
1981 INSIST(tresult == ISC_R_FAILURE);
1982 isc_netaddr_format(&n1, buf, sizeof(buf));
1983 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1984 "server '%s/%u': invalid prefix "
1985 "(extra bits specified)", buf, p1);
1991 if (n1.family == AF_INET)
1992 xfr = sources[source].v6;
1994 xfr = sources[source].v4;
1995 (void)cfg_map_get(v1, xfr, &obj);
1997 isc_netaddr_format(&n1, buf, sizeof(buf));
1998 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1999 "server '%s/%u': %s not legal",
2001 result = ISC_R_FAILURE;
2003 } while (sources[++source].v4 != NULL);
2005 while ((e2 = cfg_list_next(e2)) != NULL) {
2006 v2 = cfg_listelt_value(e2);
2007 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
2008 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
2009 const char *file = cfg_obj_file(v1);
2010 unsigned int line = cfg_obj_line(v1);
2013 file = "<unknown file>";
2015 isc_netaddr_format(&n2, buf, sizeof(buf));
2016 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
2017 "server '%s/%u': already exists "
2018 "previous definition: %s:%u",
2019 buf, p2, file, line);
2020 result = ISC_R_FAILURE;
2024 cfg_map_get(v1, "keys", &keys);
2027 * Normalize key name.
2029 keyval = cfg_obj_asstring(keys);
2030 dns_fixedname_init(&fname);
2031 isc_buffer_init(&b, keyval, strlen(keyval));
2032 isc_buffer_add(&b, strlen(keyval));
2033 keyname = dns_fixedname_name(&fname);
2034 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
2036 if (tresult != ISC_R_SUCCESS) {
2037 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2038 "bad key name '%s'", keyval);
2039 result = ISC_R_FAILURE;
2042 dns_name_format(keyname, namebuf, sizeof(namebuf));
2043 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
2044 if (tresult != ISC_R_SUCCESS) {
2045 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2046 "unknown key '%s'", keyval);
2047 result = ISC_R_FAILURE;
2055 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
2058 const char *keystr, *keynamestr;
2059 dns_fixedname_t fkeyname;
2060 dns_name_t *keyname;
2063 isc_result_t result = ISC_R_SUCCESS;
2064 isc_result_t tresult;
2065 isc_uint32_t flags, proto, alg;
2066 unsigned char keydata[4096];
2068 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
2069 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
2070 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
2072 dns_fixedname_init(&fkeyname);
2073 keyname = dns_fixedname_name(&fkeyname);
2074 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
2076 isc_buffer_init(&b, keynamestr, strlen(keynamestr));
2077 isc_buffer_add(&b, strlen(keynamestr));
2078 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
2079 if (result != ISC_R_SUCCESS) {
2080 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
2081 isc_result_totext(result));
2082 result = ISC_R_FAILURE;
2085 if (flags > 0xffff) {
2086 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2087 "flags too big: %u\n", flags);
2088 result = ISC_R_FAILURE;
2091 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2092 "protocol too big: %u\n", proto);
2093 result = ISC_R_FAILURE;
2096 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2097 "algorithm too big: %u\n", alg);
2098 result = ISC_R_FAILURE;
2102 const char *initmethod;
2103 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
2105 if (strcasecmp(initmethod, "initial-key") != 0) {
2106 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2107 "managed key '%s': "
2108 "invalid initialization method '%s'",
2109 keynamestr, initmethod);
2110 result = ISC_R_FAILURE;
2114 isc_buffer_init(&b, keydata, sizeof(keydata));
2116 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
2117 tresult = isc_base64_decodestring(keystr, &b);
2119 if (tresult != ISC_R_SUCCESS) {
2120 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2121 "%s", isc_result_totext(tresult));
2122 result = ISC_R_FAILURE;
2124 isc_buffer_usedregion(&b, &r);
2126 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
2127 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
2128 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2129 "%s key '%s' has a weak exponent",
2130 managed ? "managed" : "trusted",
2138 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
2139 const char *viewname, dns_rdataclass_t vclass,
2140 isc_log_t *logctx, isc_mem_t *mctx)
2142 const cfg_obj_t *zones = NULL;
2143 const cfg_obj_t *keys = NULL;
2144 const cfg_listelt_t *element, *element2;
2145 isc_symtab_t *symtab = NULL;
2146 isc_result_t result = ISC_R_SUCCESS;
2147 isc_result_t tresult = ISC_R_SUCCESS;
2148 cfg_aclconfctx_t *actx = NULL;
2149 const cfg_obj_t *obj;
2150 const cfg_obj_t *options = NULL;
2151 isc_boolean_t enablednssec, enablevalidation;
2152 const char *valstr = "no";
2155 * Get global options block
2157 (void)cfg_map_get(config, "options", &options);
2160 * Check that all zone statements are syntactically correct and
2161 * there are no duplicate zones.
2163 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2164 ISC_FALSE, &symtab);
2165 if (tresult != ISC_R_SUCCESS)
2166 return (ISC_R_NOMEMORY);
2168 cfg_aclconfctx_create(mctx, &actx);
2170 if (voptions != NULL)
2171 (void)cfg_map_get(voptions, "zone", &zones);
2173 (void)cfg_map_get(config, "zone", &zones);
2175 for (element = cfg_list_first(zones);
2177 element = cfg_list_next(element))
2179 isc_result_t tresult;
2180 const cfg_obj_t *zone = cfg_listelt_value(element);
2182 tresult = check_zoneconf(zone, voptions, config, symtab,
2183 vclass, actx, logctx, mctx);
2184 if (tresult != ISC_R_SUCCESS)
2185 result = ISC_R_FAILURE;
2188 isc_symtab_destroy(&symtab);
2191 * Check that forwarding is reasonable.
2193 if (voptions == NULL) {
2194 if (options != NULL)
2195 if (check_forward(options, NULL,
2196 logctx) != ISC_R_SUCCESS)
2197 result = ISC_R_FAILURE;
2199 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
2200 result = ISC_R_FAILURE;
2204 * Check non-zero options at the global and view levels.
2206 if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS)
2207 result = ISC_R_FAILURE;
2208 if (voptions != NULL &&check_nonzero(voptions, logctx) != ISC_R_SUCCESS)
2209 result = ISC_R_FAILURE;
2212 * Check that dual-stack-servers is reasonable.
2214 if (voptions == NULL) {
2215 if (options != NULL)
2216 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2217 result = ISC_R_FAILURE;
2219 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
2220 result = ISC_R_FAILURE;
2224 * Check that rrset-order is reasonable.
2226 if (voptions != NULL) {
2227 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
2228 result = ISC_R_FAILURE;
2232 * Check that all key statements are syntactically correct and
2233 * there are no duplicate keys.
2235 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2236 ISC_FALSE, &symtab);
2237 if (tresult != ISC_R_SUCCESS)
2240 (void)cfg_map_get(config, "key", &keys);
2241 tresult = check_keylist(keys, symtab, mctx, logctx);
2242 if (tresult == ISC_R_EXISTS)
2243 result = ISC_R_FAILURE;
2244 else if (tresult != ISC_R_SUCCESS) {
2249 if (voptions != NULL) {
2251 (void)cfg_map_get(voptions, "key", &keys);
2252 tresult = check_keylist(keys, symtab, mctx, logctx);
2253 if (tresult == ISC_R_EXISTS)
2254 result = ISC_R_FAILURE;
2255 else if (tresult != ISC_R_SUCCESS) {
2262 * Global servers can refer to keys in views.
2264 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
2265 result = ISC_R_FAILURE;
2267 isc_symtab_destroy(&symtab);
2270 * Check that dnssec-enable/dnssec-validation are sensible.
2273 if (voptions != NULL)
2274 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
2275 if (obj == NULL && options != NULL)
2276 (void)cfg_map_get(options, "dnssec-enable", &obj);
2278 enablednssec = ISC_TRUE;
2280 enablednssec = cfg_obj_asboolean(obj);
2283 if (voptions != NULL)
2284 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
2285 if (obj == NULL && options != NULL)
2286 (void)cfg_map_get(options, "dnssec-validation", &obj);
2288 enablevalidation = enablednssec;
2290 } else if (cfg_obj_isboolean(obj)) {
2291 enablevalidation = cfg_obj_asboolean(obj);
2292 valstr = enablevalidation ? "yes" : "no";
2294 enablevalidation = ISC_TRUE;
2298 if (enablevalidation && !enablednssec)
2299 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2300 "'dnssec-validation %s;' and 'dnssec-enable no;'",
2304 * Check trusted-keys and managed-keys.
2307 if (voptions != NULL)
2308 (void)cfg_map_get(voptions, "trusted-keys", &keys);
2310 (void)cfg_map_get(config, "trusted-keys", &keys);
2312 for (element = cfg_list_first(keys);
2314 element = cfg_list_next(element))
2316 const cfg_obj_t *keylist = cfg_listelt_value(element);
2317 for (element2 = cfg_list_first(keylist);
2319 element2 = cfg_list_next(element2)) {
2320 obj = cfg_listelt_value(element2);
2321 tresult = check_trusted_key(obj, ISC_FALSE, logctx);
2322 if (tresult != ISC_R_SUCCESS)
2328 if (voptions != NULL)
2329 (void)cfg_map_get(voptions, "managed-keys", &keys);
2331 (void)cfg_map_get(config, "managed-keys", &keys);
2333 for (element = cfg_list_first(keys);
2335 element = cfg_list_next(element))
2337 const cfg_obj_t *keylist = cfg_listelt_value(element);
2338 for (element2 = cfg_list_first(keylist);
2340 element2 = cfg_list_next(element2)) {
2341 obj = cfg_listelt_value(element2);
2342 tresult = check_trusted_key(obj, ISC_TRUE, logctx);
2343 if (tresult != ISC_R_SUCCESS)
2351 if (voptions != NULL)
2352 tresult = check_options(voptions, logctx, mctx,
2355 tresult = check_options(config, logctx, mctx,
2357 if (tresult != ISC_R_SUCCESS)
2360 tresult = check_viewacls(actx, voptions, config, logctx, mctx);
2361 if (tresult != ISC_R_SUCCESS)
2364 tresult = check_recursionacls(actx, voptions, viewname,
2365 config, logctx, mctx);
2366 if (tresult != ISC_R_SUCCESS)
2369 tresult = check_filteraaaa(actx, voptions, viewname, config,
2371 if (tresult != ISC_R_SUCCESS)
2374 tresult = check_dns64(actx, voptions, config, logctx, mctx);
2375 if (tresult != ISC_R_SUCCESS)
2380 isc_symtab_destroy(&symtab);
2382 cfg_aclconfctx_detach(&actx);
2388 default_channels[] = {
2397 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
2400 const cfg_obj_t *categories = NULL;
2401 const cfg_obj_t *category;
2402 const cfg_obj_t *channels = NULL;
2403 const cfg_obj_t *channel;
2404 const cfg_listelt_t *element;
2405 const cfg_listelt_t *delement;
2406 const char *channelname;
2407 const char *catname;
2408 const cfg_obj_t *fileobj = NULL;
2409 const cfg_obj_t *syslogobj = NULL;
2410 const cfg_obj_t *nullobj = NULL;
2411 const cfg_obj_t *stderrobj = NULL;
2412 const cfg_obj_t *logobj = NULL;
2413 isc_result_t result = ISC_R_SUCCESS;
2414 isc_result_t tresult;
2415 isc_symtab_t *symtab = NULL;
2416 isc_symvalue_t symvalue;
2419 (void)cfg_map_get(config, "logging", &logobj);
2421 return (ISC_R_SUCCESS);
2423 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
2424 if (result != ISC_R_SUCCESS)
2427 symvalue.as_cpointer = NULL;
2428 for (i = 0; default_channels[i] != NULL; i++) {
2429 tresult = isc_symtab_define(symtab, default_channels[i], 1,
2430 symvalue, isc_symexists_replace);
2431 if (tresult != ISC_R_SUCCESS)
2435 cfg_map_get(logobj, "channel", &channels);
2437 for (element = cfg_list_first(channels);
2439 element = cfg_list_next(element))
2441 channel = cfg_listelt_value(element);
2442 channelname = cfg_obj_asstring(cfg_map_getname(channel));
2443 fileobj = syslogobj = nullobj = stderrobj = NULL;
2444 (void)cfg_map_get(channel, "file", &fileobj);
2445 (void)cfg_map_get(channel, "syslog", &syslogobj);
2446 (void)cfg_map_get(channel, "null", &nullobj);
2447 (void)cfg_map_get(channel, "stderr", &stderrobj);
2449 if (fileobj != NULL)
2451 if (syslogobj != NULL)
2453 if (nullobj != NULL)
2455 if (stderrobj != NULL)
2458 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2459 "channel '%s': exactly one of file, syslog, "
2460 "null, and stderr must be present",
2462 result = ISC_R_FAILURE;
2464 tresult = isc_symtab_define(symtab, channelname, 1,
2465 symvalue, isc_symexists_replace);
2466 if (tresult != ISC_R_SUCCESS)
2470 cfg_map_get(logobj, "category", &categories);
2472 for (element = cfg_list_first(categories);
2474 element = cfg_list_next(element))
2476 category = cfg_listelt_value(element);
2477 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
2478 if (isc_log_categorybyname(logctx, catname) == NULL) {
2479 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
2480 "undefined category: '%s'", catname);
2481 result = ISC_R_FAILURE;
2483 channels = cfg_tuple_get(category, "destinations");
2484 for (delement = cfg_list_first(channels);
2486 delement = cfg_list_next(delement))
2488 channel = cfg_listelt_value(delement);
2489 channelname = cfg_obj_asstring(channel);
2490 tresult = isc_symtab_lookup(symtab, channelname, 1,
2492 if (tresult != ISC_R_SUCCESS) {
2493 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2494 "undefined channel: '%s'",
2500 isc_symtab_destroy(&symtab);
2505 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
2508 isc_result_t result = ISC_R_SUCCESS;
2509 const cfg_obj_t *control_keylist;
2510 const cfg_listelt_t *element;
2511 const cfg_obj_t *key;
2514 control_keylist = cfg_tuple_get(control, "keys");
2515 if (cfg_obj_isvoid(control_keylist))
2516 return (ISC_R_SUCCESS);
2518 for (element = cfg_list_first(control_keylist);
2520 element = cfg_list_next(element))
2522 key = cfg_listelt_value(element);
2523 keyval = cfg_obj_asstring(key);
2525 if (!rndckey_exists(keylist, keyval)) {
2526 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2527 "unknown key '%s'", keyval);
2528 result = ISC_R_NOTFOUND;
2535 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
2538 isc_result_t result = ISC_R_SUCCESS, tresult;
2539 cfg_aclconfctx_t *actx = NULL;
2540 const cfg_listelt_t *element, *element2;
2541 const cfg_obj_t *allow;
2542 const cfg_obj_t *control;
2543 const cfg_obj_t *controls;
2544 const cfg_obj_t *controlslist = NULL;
2545 const cfg_obj_t *inetcontrols;
2546 const cfg_obj_t *unixcontrols;
2547 const cfg_obj_t *keylist = NULL;
2549 isc_uint32_t perm, mask;
2550 dns_acl_t *acl = NULL;
2551 isc_sockaddr_t addr;
2554 (void)cfg_map_get(config, "controls", &controlslist);
2555 if (controlslist == NULL)
2556 return (ISC_R_SUCCESS);
2558 (void)cfg_map_get(config, "key", &keylist);
2560 cfg_aclconfctx_create(mctx, &actx);
2563 * INET: Check allow clause.
2564 * UNIX: Check "perm" for sanity, check path length.
2566 for (element = cfg_list_first(controlslist);
2568 element = cfg_list_next(element)) {
2569 controls = cfg_listelt_value(element);
2570 unixcontrols = NULL;
2571 inetcontrols = NULL;
2572 (void)cfg_map_get(controls, "unix", &unixcontrols);
2573 (void)cfg_map_get(controls, "inet", &inetcontrols);
2574 for (element2 = cfg_list_first(inetcontrols);
2576 element2 = cfg_list_next(element2)) {
2577 control = cfg_listelt_value(element2);
2578 allow = cfg_tuple_get(control, "allow");
2579 tresult = cfg_acl_fromconfig(allow, config, logctx,
2580 actx, mctx, 0, &acl);
2582 dns_acl_detach(&acl);
2583 if (tresult != ISC_R_SUCCESS)
2585 tresult = bind9_check_controlskeys(control, keylist,
2587 if (tresult != ISC_R_SUCCESS)
2590 for (element2 = cfg_list_first(unixcontrols);
2592 element2 = cfg_list_next(element2)) {
2593 control = cfg_listelt_value(element2);
2594 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
2595 tresult = isc_sockaddr_frompath(&addr, path);
2596 if (tresult == ISC_R_NOSPACE) {
2597 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
2598 "unix control '%s': path too long",
2600 result = ISC_R_NOSPACE;
2602 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
2603 for (i = 0; i < 3; i++) {
2604 #ifdef NEED_SECURE_DIRECTORY
2605 mask = (0x1 << (i*3)); /* SEARCH */
2607 mask = (0x6 << (i*3)); /* READ + WRITE */
2609 if ((perm & mask) == mask)
2613 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2614 "unix control '%s' allows access "
2615 "to everyone", path);
2616 } else if (i == 3) {
2617 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2618 "unix control '%s' allows access "
2621 tresult = bind9_check_controlskeys(control, keylist,
2623 if (tresult != ISC_R_SUCCESS)
2627 cfg_aclconfctx_detach(&actx);
2632 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
2635 const cfg_obj_t *options = NULL;
2636 const cfg_obj_t *views = NULL;
2637 const cfg_obj_t *acls = NULL;
2638 const cfg_obj_t *kals = NULL;
2639 const cfg_obj_t *obj;
2640 const cfg_listelt_t *velement;
2641 isc_result_t result = ISC_R_SUCCESS;
2642 isc_result_t tresult;
2643 isc_symtab_t *symtab = NULL;
2645 static const char *builtin[] = { "localhost", "localnets",
2648 (void)cfg_map_get(config, "options", &options);
2650 if (options != NULL &&
2651 check_options(options, logctx, mctx,
2652 optlevel_options) != ISC_R_SUCCESS)
2653 result = ISC_R_FAILURE;
2655 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
2656 result = ISC_R_FAILURE;
2658 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
2659 result = ISC_R_FAILURE;
2661 if (options != NULL &&
2662 check_order(options, logctx) != ISC_R_SUCCESS)
2663 result = ISC_R_FAILURE;
2665 (void)cfg_map_get(config, "view", &views);
2667 if (views != NULL && options != NULL)
2668 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2669 result = ISC_R_FAILURE;
2671 if (views == NULL) {
2672 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
2673 logctx, mctx) != ISC_R_SUCCESS)
2674 result = ISC_R_FAILURE;
2676 const cfg_obj_t *zones = NULL;
2678 (void)cfg_map_get(config, "zone", &zones);
2679 if (zones != NULL) {
2680 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
2681 "when using 'view' statements, "
2682 "all zones must be in views");
2683 result = ISC_R_FAILURE;
2687 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
2688 if (tresult != ISC_R_SUCCESS)
2690 for (velement = cfg_list_first(views);
2692 velement = cfg_list_next(velement))
2694 const cfg_obj_t *view = cfg_listelt_value(velement);
2695 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
2696 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
2697 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
2698 dns_rdataclass_t vclass = dns_rdataclass_in;
2699 isc_result_t tresult = ISC_R_SUCCESS;
2700 const char *key = cfg_obj_asstring(vname);
2701 isc_symvalue_t symvalue;
2703 if (cfg_obj_isstring(vclassobj)) {
2706 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
2707 r.length = strlen(r.base);
2708 tresult = dns_rdataclass_fromtext(&vclass, &r);
2709 if (tresult != ISC_R_SUCCESS)
2710 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
2711 "view '%s': invalid class %s",
2712 cfg_obj_asstring(vname), r.base);
2714 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
2715 symvalue.as_cpointer = view;
2716 tresult = isc_symtab_define(symtab, key, vclass,
2718 isc_symexists_reject);
2719 if (tresult == ISC_R_EXISTS) {
2722 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
2723 vclass, &symvalue) == ISC_R_SUCCESS);
2724 file = cfg_obj_file(symvalue.as_cpointer);
2725 line = cfg_obj_line(symvalue.as_cpointer);
2726 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2727 "view '%s': already exists "
2728 "previous definition: %s:%u",
2731 } else if (tresult != ISC_R_SUCCESS) {
2733 } else if ((strcasecmp(key, "_bind") == 0 &&
2734 vclass == dns_rdataclass_ch) ||
2735 (strcasecmp(key, "_default") == 0 &&
2736 vclass == dns_rdataclass_in)) {
2737 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2738 "attempt to redefine builtin view "
2740 result = ISC_R_EXISTS;
2743 if (tresult == ISC_R_SUCCESS)
2744 tresult = check_viewconf(config, voptions, key,
2745 vclass, logctx, mctx);
2746 if (tresult != ISC_R_SUCCESS)
2747 result = ISC_R_FAILURE;
2750 isc_symtab_destroy(&symtab);
2752 if (views != NULL && options != NULL) {
2754 tresult = cfg_map_get(options, "cache-file", &obj);
2755 if (tresult == ISC_R_SUCCESS) {
2756 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2757 "'cache-file' cannot be a global "
2758 "option if views are present");
2759 result = ISC_R_FAILURE;
2763 cfg_map_get(config, "acl", &acls);
2766 const cfg_listelt_t *elt;
2767 const cfg_listelt_t *elt2;
2768 const char *aclname;
2770 for (elt = cfg_list_first(acls);
2772 elt = cfg_list_next(elt)) {
2773 const cfg_obj_t *acl = cfg_listelt_value(elt);
2774 unsigned int line = cfg_obj_line(acl);
2777 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2779 i < sizeof(builtin) / sizeof(builtin[0]);
2781 if (strcasecmp(aclname, builtin[i]) == 0) {
2782 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
2783 "attempt to redefine "
2786 result = ISC_R_FAILURE;
2790 for (elt2 = cfg_list_next(elt);
2792 elt2 = cfg_list_next(elt2)) {
2793 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2795 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2797 if (strcasecmp(aclname, name) == 0) {
2798 const char *file = cfg_obj_file(acl);
2801 file = "<unknown file>";
2803 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2804 "attempt to redefine "
2805 "acl '%s' previous "
2806 "definition: %s:%u",
2808 result = ISC_R_FAILURE;
2814 tresult = cfg_map_get(config, "kal", &kals);
2815 if (tresult == ISC_R_SUCCESS) {
2816 const cfg_listelt_t *elt;
2817 const cfg_listelt_t *elt2;
2818 const char *aclname;
2820 for (elt = cfg_list_first(kals);
2822 elt = cfg_list_next(elt)) {
2823 const cfg_obj_t *acl = cfg_listelt_value(elt);
2825 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2827 for (elt2 = cfg_list_next(elt);
2829 elt2 = cfg_list_next(elt2)) {
2830 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2832 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2834 if (strcasecmp(aclname, name) == 0) {
2835 const char *file = cfg_obj_file(acl);
2836 unsigned int line = cfg_obj_line(acl);
2839 file = "<unknown file>";
2841 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2842 "attempt to redefine "
2843 "kal '%s' previous "
2844 "definition: %s:%u",
2846 result = ISC_R_FAILURE;