2 * Copyright (C) 2004-2016 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.
24 #include <isc/base64.h>
25 #include <isc/buffer.h>
29 #include <isc/netaddr.h>
30 #include <isc/parseint.h>
31 #include <isc/region.h>
32 #include <isc/result.h>
33 #include <isc/sockaddr.h>
34 #include <isc/string.h>
35 #include <isc/symtab.h>
39 #include <dns/fixedname.h>
40 #include <dns/rdataclass.h>
41 #include <dns/rdatatype.h>
42 #include <dns/secalg.h>
46 #include <isccfg/aclconf.h>
47 #include <isccfg/cfg.h>
49 #include <bind9/check.h>
52 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
53 isc_log_t *logctxlogc);
56 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
59 isc_mem_free(userarg, key);
63 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
64 isc_result_t result = ISC_R_SUCCESS;
67 dns_fixedname_t fixed;
69 dns_rdataclass_t rdclass;
70 dns_rdatatype_t rdtype;
74 dns_fixedname_init(&fixed);
75 obj = cfg_tuple_get(ent, "class");
76 if (cfg_obj_isstring(obj)) {
78 DE_CONST(cfg_obj_asstring(obj), r.base);
79 r.length = strlen(r.base);
80 tresult = dns_rdataclass_fromtext(&rdclass, &r);
81 if (tresult != ISC_R_SUCCESS) {
82 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
83 "rrset-order: invalid class '%s'",
85 result = ISC_R_FAILURE;
89 obj = cfg_tuple_get(ent, "type");
90 if (cfg_obj_isstring(obj)) {
91 DE_CONST(cfg_obj_asstring(obj), r.base);
92 r.length = strlen(r.base);
93 tresult = dns_rdatatype_fromtext(&rdtype, &r);
94 if (tresult != ISC_R_SUCCESS) {
95 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
96 "rrset-order: invalid type '%s'",
98 result = ISC_R_FAILURE;
102 obj = cfg_tuple_get(ent, "name");
103 if (cfg_obj_isstring(obj)) {
104 str = cfg_obj_asstring(obj);
105 isc_buffer_constinit(&b, str, strlen(str));
106 isc_buffer_add(&b, strlen(str));
107 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
108 dns_rootname, 0, NULL);
109 if (tresult != ISC_R_SUCCESS) {
110 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
111 "rrset-order: invalid name '%s'", str);
112 result = ISC_R_FAILURE;
116 obj = cfg_tuple_get(ent, "order");
117 if (!cfg_obj_isstring(obj) ||
118 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
119 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
120 "rrset-order: keyword 'order' missing");
121 result = ISC_R_FAILURE;
124 obj = cfg_tuple_get(ent, "ordering");
125 if (!cfg_obj_isstring(obj)) {
126 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
127 "rrset-order: missing ordering");
128 result = ISC_R_FAILURE;
129 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
130 #if !DNS_RDATASET_FIXED
131 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
132 "rrset-order: order 'fixed' was disabled at "
135 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
136 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
137 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
138 "rrset-order: invalid order '%s'",
139 cfg_obj_asstring(obj));
140 result = ISC_R_FAILURE;
146 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
147 isc_result_t result = ISC_R_SUCCESS;
148 isc_result_t tresult;
149 const cfg_listelt_t *element;
150 const cfg_obj_t *obj = NULL;
152 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
155 for (element = cfg_list_first(obj);
157 element = cfg_list_next(element))
159 tresult = check_orderent(cfg_listelt_value(element), logctx);
160 if (tresult != ISC_R_SUCCESS)
167 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
168 const cfg_listelt_t *element;
169 const cfg_obj_t *alternates = NULL;
170 const cfg_obj_t *value;
171 const cfg_obj_t *obj;
173 dns_fixedname_t fixed;
176 isc_result_t result = ISC_R_SUCCESS;
177 isc_result_t tresult;
179 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
181 if (alternates == NULL)
182 return (ISC_R_SUCCESS);
184 obj = cfg_tuple_get(alternates, "port");
185 if (cfg_obj_isuint32(obj)) {
186 isc_uint32_t val = cfg_obj_asuint32(obj);
187 if (val > ISC_UINT16_MAX) {
188 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
189 "port '%u' out of range", val);
190 result = ISC_R_FAILURE;
193 obj = cfg_tuple_get(alternates, "addresses");
194 for (element = cfg_list_first(obj);
196 element = cfg_list_next(element)) {
197 value = cfg_listelt_value(element);
198 if (cfg_obj_issockaddr(value))
200 obj = cfg_tuple_get(value, "name");
201 str = cfg_obj_asstring(obj);
202 isc_buffer_constinit(&buffer, str, strlen(str));
203 isc_buffer_add(&buffer, strlen(str));
204 dns_fixedname_init(&fixed);
205 name = dns_fixedname_name(&fixed);
206 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
208 if (tresult != ISC_R_SUCCESS) {
209 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
210 "bad name '%s'", str);
211 result = ISC_R_FAILURE;
213 obj = cfg_tuple_get(value, "port");
214 if (cfg_obj_isuint32(obj)) {
215 isc_uint32_t val = cfg_obj_asuint32(obj);
216 if (val > ISC_UINT16_MAX) {
217 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
218 "port '%u' out of range", val);
219 result = ISC_R_FAILURE;
227 check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
230 const cfg_obj_t *forward = NULL;
231 const cfg_obj_t *forwarders = NULL;
233 (void)cfg_map_get(options, "forward", &forward);
234 (void)cfg_map_get(options, "forwarders", &forwarders);
236 if (forwarders != NULL && global != NULL) {
237 const char *file = cfg_obj_file(global);
238 unsigned int line = cfg_obj_line(global);
239 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
240 "forwarders declared in root zone and "
241 "in general configuration: %s:%u",
243 return (ISC_R_FAILURE);
245 if (forward != NULL && forwarders == NULL) {
246 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
247 "no matching 'forwarders' statement");
248 return (ISC_R_FAILURE);
250 return (ISC_R_SUCCESS);
254 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
255 isc_result_t result = ISC_R_SUCCESS;
256 isc_result_t tresult;
257 const cfg_listelt_t *element;
260 dns_fixedname_t fixed;
262 const cfg_obj_t *obj;
264 dns_fixedname_init(&fixed);
265 name = dns_fixedname_name(&fixed);
266 obj = cfg_tuple_get(disabled, "name");
267 str = cfg_obj_asstring(obj);
268 isc_buffer_constinit(&b, str, strlen(str));
269 isc_buffer_add(&b, strlen(str));
270 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
271 if (tresult != ISC_R_SUCCESS) {
272 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
273 "bad domain name '%s'", str);
277 obj = cfg_tuple_get(disabled, "algorithms");
279 for (element = cfg_list_first(obj);
281 element = cfg_list_next(element))
286 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
287 r.length = strlen(r.base);
289 tresult = dns_secalg_fromtext(&alg, &r);
290 if (tresult != ISC_R_SUCCESS) {
291 cfg_obj_log(cfg_listelt_value(element), logctx,
292 ISC_LOG_ERROR, "invalid algorithm '%s'",
301 nameexist(const cfg_obj_t *obj, const char *name, int value,
302 isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
309 isc_symvalue_t symvalue;
311 key = isc_mem_strdup(mctx, name);
313 return (ISC_R_NOMEMORY);
314 symvalue.as_cpointer = obj;
315 result = isc_symtab_define(symtab, key, value, symvalue,
316 isc_symexists_reject);
317 if (result == ISC_R_EXISTS) {
318 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
319 &symvalue) == ISC_R_SUCCESS);
320 file = cfg_obj_file(symvalue.as_cpointer);
321 line = cfg_obj_line(symvalue.as_cpointer);
324 file = "<unknown file>";
325 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
326 isc_mem_free(mctx, key);
327 result = ISC_R_EXISTS;
328 } else if (result != ISC_R_SUCCESS) {
329 isc_mem_free(mctx, key);
335 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
338 const cfg_obj_t *obj;
339 char namebuf[DNS_NAME_FORMATSIZE];
341 dns_fixedname_t fixed;
344 isc_result_t result = ISC_R_SUCCESS;
346 dns_fixedname_init(&fixed);
347 name = dns_fixedname_name(&fixed);
348 obj = cfg_tuple_get(secure, "name");
349 str = cfg_obj_asstring(obj);
350 isc_buffer_constinit(&b, str, strlen(str));
351 isc_buffer_add(&b, strlen(str));
352 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
353 if (result != ISC_R_SUCCESS) {
354 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
355 "bad domain name '%s'", str);
357 dns_name_format(name, namebuf, sizeof(namebuf));
358 result = nameexist(secure, namebuf, 1, symtab,
359 "dnssec-must-be-secure '%s': already "
360 "exists previous definition: %s:%u",
367 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
368 const cfg_obj_t *voptions, const cfg_obj_t *config,
369 isc_log_t *logctx, isc_mem_t *mctx)
372 const cfg_obj_t *aclobj = NULL;
373 const cfg_obj_t *options;
374 dns_acl_t *acl = NULL;
376 if (zconfig != NULL) {
377 options = cfg_tuple_get(zconfig, "options");
378 cfg_map_get(options, aclname, &aclobj);
380 if (voptions != NULL && aclobj == NULL)
381 cfg_map_get(voptions, aclname, &aclobj);
382 if (config != NULL && aclobj == NULL) {
384 cfg_map_get(config, "options", &options);
386 cfg_map_get(options, aclname, &aclobj);
389 return (ISC_R_SUCCESS);
390 result = cfg_acl_fromconfig(aclobj, config, logctx,
391 actx, mctx, 0, &acl);
393 dns_acl_detach(&acl);
398 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
399 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
401 isc_result_t result = ISC_R_SUCCESS, tresult;
404 static const char *acls[] = { "allow-query", "allow-query-on",
405 "allow-query-cache", "allow-query-cache-on",
406 "blackhole", "match-clients", "match-destinations",
407 "sortlist", "filter-aaaa", NULL };
409 while (acls[i] != NULL) {
410 tresult = checkacl(acls[i++], actx, NULL, voptions, config,
412 if (tresult != ISC_R_SUCCESS)
418 static const unsigned char zeros[16];
421 check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
422 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
424 isc_result_t result = ISC_R_SUCCESS;
425 const cfg_obj_t *dns64 = NULL;
426 const cfg_obj_t *options;
427 const cfg_listelt_t *element;
428 const cfg_obj_t *map, *obj;
429 isc_netaddr_t na, sa;
430 unsigned int prefixlen;
434 static const char *acls[] = { "clients", "exclude", "mapped", NULL};
436 if (voptions != NULL)
437 cfg_map_get(voptions, "dns64", &dns64);
438 if (config != NULL && dns64 == NULL) {
440 cfg_map_get(config, "options", &options);
442 cfg_map_get(options, "dns64", &dns64);
445 return (ISC_R_SUCCESS);
447 for (element = cfg_list_first(dns64);
449 element = cfg_list_next(element))
451 map = cfg_listelt_value(element);
452 obj = cfg_map_getname(map);
454 cfg_obj_asnetprefix(obj, &na, &prefixlen);
455 if (na.family != AF_INET6) {
456 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
457 "dns64 requires a IPv6 prefix");
458 result = ISC_R_FAILURE;
462 if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
463 prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
464 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
465 "bad prefix length %u [32/40/48/56/64/96]",
467 result = ISC_R_FAILURE;
471 for (i = 0; acls[i] != NULL; i++) {
473 (void)cfg_map_get(map, acls[i], &obj);
475 dns_acl_t *acl = NULL;
476 isc_result_t tresult;
478 tresult = cfg_acl_fromconfig(obj, config,
482 dns_acl_detach(&acl);
483 if (tresult != ISC_R_SUCCESS)
489 (void)cfg_map_get(map, "suffix", &obj);
491 isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
492 if (sa.family != AF_INET6) {
493 cfg_obj_log(map, logctx, ISC_LOG_ERROR,
494 "dns64 requires a IPv6 suffix");
495 result = ISC_R_FAILURE;
498 nbytes = prefixlen / 8 + 4;
499 if (prefixlen >= 32 && prefixlen <= 64)
501 if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
502 char netaddrbuf[ISC_NETADDR_FORMATSIZE];
503 isc_netaddr_format(&sa, netaddrbuf,
505 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
506 "bad suffix '%s' leading "
507 "%u octets not zeros",
509 result = ISC_R_FAILURE;
519 * Check allow-recursion and allow-recursion-on acls, and also log a
520 * warning if they're inconsistent with the "recursion" option.
523 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
524 const char *viewname, const cfg_obj_t *config,
525 isc_log_t *logctx, isc_mem_t *mctx)
527 const cfg_obj_t *options, *aclobj, *obj = NULL;
528 dns_acl_t *acl = NULL;
529 isc_result_t result = ISC_R_SUCCESS, tresult;
530 isc_boolean_t recursion;
531 const char *forview = " for view ";
534 static const char *acls[] = { "allow-recursion", "allow-recursion-on",
537 if (voptions != NULL)
538 cfg_map_get(voptions, "recursion", &obj);
539 if (obj == NULL && config != NULL) {
541 cfg_map_get(config, "options", &options);
543 cfg_map_get(options, "recursion", &obj);
546 recursion = ISC_TRUE;
548 recursion = cfg_obj_asboolean(obj);
550 if (viewname == NULL) {
555 for (i = 0; acls[i] != NULL; i++) {
556 aclobj = options = NULL;
559 if (voptions != NULL)
560 cfg_map_get(voptions, acls[i], &aclobj);
561 if (config != NULL && aclobj == NULL) {
563 cfg_map_get(config, "options", &options);
565 cfg_map_get(options, acls[i], &aclobj);
570 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
571 actx, mctx, 0, &acl);
573 if (tresult != ISC_R_SUCCESS)
579 if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
580 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
581 "both \"recursion no;\" and "
583 acls[i], forview, viewname);
587 dns_acl_detach(&acl);
594 check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
595 const char *viewname, const cfg_obj_t *config,
596 isc_log_t *logctx, isc_mem_t *mctx)
598 const cfg_obj_t *options, *aclobj, *obj = NULL;
599 dns_acl_t *acl = NULL;
600 isc_result_t result = ISC_R_SUCCESS, tresult;
601 dns_v4_aaaa_t filter;
602 const char *forview = " for view ";
604 if (voptions != NULL)
605 cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
606 if (obj == NULL && config != NULL) {
608 cfg_map_get(config, "options", &options);
610 cfg_map_get(options, "filter-aaaa-on-v4", &obj);
614 filter = dns_v4_aaaa_ok; /* default */
615 else if (cfg_obj_isboolean(obj))
616 filter = cfg_obj_asboolean(obj) ? dns_v4_aaaa_filter :
619 filter = dns_v4_aaaa_break_dnssec; /* break-dnssec */
621 if (viewname == NULL) {
626 aclobj = options = NULL;
629 if (voptions != NULL)
630 cfg_map_get(voptions, "filter-aaaa", &aclobj);
631 if (config != NULL && aclobj == NULL) {
633 cfg_map_get(config, "options", &options);
635 cfg_map_get(options, "filter-aaaa", &aclobj);
640 tresult = cfg_acl_fromconfig(aclobj, config, logctx,
641 actx, mctx, 0, &acl);
643 if (tresult != ISC_R_SUCCESS) {
645 } else if (filter != dns_v4_aaaa_ok && dns_acl_isnone(acl)) {
646 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
647 "both \"filter-aaaa-on-v4 %s;\" and "
648 "\"filter-aaaa\" is 'none;'%s%s",
649 filter == dns_v4_aaaa_break_dnssec ?
650 "break-dnssec" : "yes", forview, viewname);
651 result = ISC_R_FAILURE;
652 } else if (filter == dns_v4_aaaa_ok && !dns_acl_isnone(acl)) {
653 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
654 "both \"filter-aaaa-on-v4 no;\" and "
655 "\"filter-aaaa\" is set%s%s", forview, viewname);
656 result = ISC_R_FAILURE;
660 dns_acl_detach(&acl);
679 check_name(const char *str) {
680 dns_fixedname_t fixed;
682 dns_fixedname_init(&fixed);
683 return (dns_name_fromstring(dns_fixedname_name(&fixed), str, 0, NULL));
687 check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
690 isc_result_t result = ISC_R_SUCCESS;
691 isc_result_t tresult;
693 const cfg_obj_t *obj = NULL;
694 const cfg_obj_t *resignobj = NULL;
695 const cfg_listelt_t *element;
696 isc_symtab_t *symtab = NULL;
697 dns_fixedname_t fixed;
701 static intervaltable intervals[] = {
702 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
703 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
704 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
705 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
706 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
707 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
708 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
709 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
712 static const char *server_contact[] = {
713 "empty-server", "empty-contact",
714 "dns64-server", "dns64-contact",
719 * Check that fields specified in units of time other than seconds
720 * have reasonable values.
722 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
725 (void)cfg_map_get(options, intervals[i].name, &obj);
728 val = cfg_obj_asuint32(obj);
729 if (val > intervals[i].max) {
730 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
731 "%s '%u' is out of range (0..%u)",
732 intervals[i].name, val,
734 result = ISC_R_RANGE;
735 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
736 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
737 "%s '%d' is out of range",
738 intervals[i].name, val);
739 result = ISC_R_RANGE;
744 cfg_map_get(options, "max-rsa-exponent-size", &obj);
748 val = cfg_obj_asuint32(obj);
749 if (val != 0 && (val < 35 || val > 4096)) {
750 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
751 "max-rsa-exponent-size '%u' is out of "
752 "range (35..4096)", val);
753 result = ISC_R_RANGE;
758 cfg_map_get(options, "sig-validity-interval", &obj);
760 isc_uint32_t validity, resign = 0;
762 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
763 resignobj = cfg_tuple_get(obj, "re-sign");
764 if (!cfg_obj_isvoid(resignobj))
765 resign = cfg_obj_asuint32(resignobj);
767 if (validity > 3660 || validity == 0) { /* 10 years */
768 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
769 "%s '%u' is out of range (1..3660)",
770 "sig-validity-interval", validity);
771 result = ISC_R_RANGE;
774 if (!cfg_obj_isvoid(resignobj)) {
775 if (resign > 3660 || resign == 0) { /* 10 years */
776 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
777 "%s '%u' is out of range (1..3660)",
778 "sig-validity-interval (re-sign)",
780 result = ISC_R_RANGE;
781 } else if ((validity > 7 && validity < resign) ||
782 (validity <= 7 && validity * 24 < resign)) {
783 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
784 "validity interval (%u days) "
785 "less than re-signing interval "
786 "(%u %s)", validity, resign,
787 (validity > 7) ? "days" : "hours");
788 result = ISC_R_RANGE;
794 (void)cfg_map_get(options, "preferred-glue", &obj);
796 str = cfg_obj_asstring(obj);
797 if (strcasecmp(str, "a") != 0 &&
798 strcasecmp(str, "aaaa") != 0 &&
799 strcasecmp(str, "none") != 0)
800 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
801 "preferred-glue unexpected value '%s'",
806 (void)cfg_map_get(options, "root-delegation-only", &obj);
808 if (!cfg_obj_isvoid(obj)) {
809 for (element = cfg_list_first(obj);
811 element = cfg_list_next(element)) {
812 const cfg_obj_t *exclude;
814 exclude = cfg_listelt_value(element);
815 str = cfg_obj_asstring(exclude);
816 tresult = check_name(str);
817 if (tresult != ISC_R_SUCCESS) {
818 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
819 "bad domain name '%s'",
828 * Set supported DNSSEC algorithms.
831 (void)cfg_map_get(options, "disable-algorithms", &obj);
833 for (element = cfg_list_first(obj);
835 element = cfg_list_next(element))
837 obj = cfg_listelt_value(element);
838 tresult = disabled_algorithms(obj, logctx);
839 if (tresult != ISC_R_SUCCESS)
844 dns_fixedname_init(&fixed);
845 name = dns_fixedname_name(&fixed);
848 * Check the DLV zone name.
851 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
853 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
855 if (tresult != ISC_R_SUCCESS)
857 for (element = cfg_list_first(obj);
859 element = cfg_list_next(element))
862 const cfg_obj_t *dlvobj, *anchor;
864 obj = cfg_listelt_value(element);
866 anchor = cfg_tuple_get(obj, "trust-anchor");
867 dlvobj = cfg_tuple_get(obj, "domain");
868 dlv = cfg_obj_asstring(dlvobj);
871 * If domain is "auto" or "no" and trust anchor
872 * is missing, skip remaining tests
874 if (cfg_obj_isvoid(anchor)) {
875 if (!strcasecmp(dlv, "no") ||
876 !strcasecmp(dlv, "auto"))
880 tresult = dns_name_fromstring(name, dlv, 0, NULL);
881 if (tresult != ISC_R_SUCCESS) {
882 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
883 "bad domain name '%s'", dlv);
887 if (symtab != NULL) {
888 tresult = nameexist(obj, dlv, 1, symtab,
889 "dnssec-lookaside '%s': "
890 "already exists previous "
893 if (tresult != ISC_R_SUCCESS &&
894 result == ISC_R_SUCCESS)
899 * XXXMPA to be removed when multiple lookaside
900 * namespaces are supported.
902 if (!dns_name_equal(dns_rootname, name)) {
903 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
904 "dnssec-lookaside '%s': "
905 "non-root not yet supported", dlv);
906 if (result == ISC_R_SUCCESS)
907 result = ISC_R_FAILURE;
910 if (!cfg_obj_isvoid(anchor)) {
911 dlv = cfg_obj_asstring(anchor);
912 tresult = check_name(dlv);
913 if (tresult != ISC_R_SUCCESS) {
914 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
915 "bad domain name '%s'",
917 if (result == ISC_R_SUCCESS)
921 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
922 "dnssec-lookaside requires "
923 "either 'auto' or 'no', or a "
924 "domain and trust anchor");
925 if (result == ISC_R_SUCCESS)
926 result = ISC_R_FAILURE;
931 isc_symtab_destroy(&symtab);
935 * Check auto-dnssec at the view/options level
938 (void)cfg_map_get(options, "auto-dnssec", &obj);
940 const char *arg = cfg_obj_asstring(obj);
941 if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
942 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
943 "auto-dnssec may only be activated at the "
945 result = ISC_R_FAILURE;
950 * Check dnssec-must-be-secure.
953 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
955 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
957 if (tresult != ISC_R_SUCCESS)
959 for (element = cfg_list_first(obj);
961 element = cfg_list_next(element))
963 obj = cfg_listelt_value(element);
964 tresult = mustbesecure(obj, symtab, logctx, mctx);
965 if (tresult != ISC_R_SUCCESS)
969 isc_symtab_destroy(&symtab);
973 * Check server/contacts for syntactic validity.
975 for (i= 0; server_contact[i] != NULL; i++) {
977 (void)cfg_map_get(options, server_contact[i], &obj);
979 str = cfg_obj_asstring(obj);
980 if (check_name(str) != ISC_R_SUCCESS) {
981 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
982 "%s: invalid name '%s'",
983 server_contact[i], str);
984 result = ISC_R_FAILURE;
990 * Check empty zone configuration.
993 (void)cfg_map_get(options, "disable-empty-zone", &obj);
994 for (element = cfg_list_first(obj);
996 element = cfg_list_next(element))
998 obj = cfg_listelt_value(element);
999 str = cfg_obj_asstring(obj);
1000 if (check_name(str) != ISC_R_SUCCESS) {
1001 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1002 "disable-empty-zone: invalid name '%s'",
1004 result = ISC_R_FAILURE;
1009 * Check that server-id is not too long.
1010 * 1024 bytes should be big enough.
1013 (void)cfg_map_get(options, "server-id", &obj);
1014 if (obj != NULL && cfg_obj_isstring(obj) &&
1015 strlen(cfg_obj_asstring(obj)) > 1024U) {
1016 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1017 "'server-id' too big (>1024 bytes)");
1018 result = ISC_R_FAILURE;
1025 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
1026 isc_result_t result;
1027 const cfg_obj_t *masters = NULL;
1028 const cfg_listelt_t *elt;
1030 result = cfg_map_get(cctx, "masters", &masters);
1031 if (result != ISC_R_SUCCESS)
1033 for (elt = cfg_list_first(masters);
1035 elt = cfg_list_next(elt)) {
1036 const cfg_obj_t *list;
1037 const char *listname;
1039 list = cfg_listelt_value(elt);
1040 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
1042 if (strcasecmp(listname, name) == 0) {
1044 return (ISC_R_SUCCESS);
1047 return (ISC_R_NOTFOUND);
1051 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
1052 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
1054 isc_result_t result = ISC_R_SUCCESS;
1055 isc_result_t tresult;
1056 isc_uint32_t count = 0;
1057 isc_symtab_t *symtab = NULL;
1058 isc_symvalue_t symvalue;
1059 const cfg_listelt_t *element;
1060 const cfg_listelt_t **stack = NULL;
1061 isc_uint32_t stackcount = 0, pushed = 0;
1062 const cfg_obj_t *list;
1064 REQUIRE(countp != NULL);
1065 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1066 if (result != ISC_R_SUCCESS) {
1072 list = cfg_tuple_get(obj, "addresses");
1073 element = cfg_list_first(list);
1077 element = cfg_list_next(element))
1079 const char *listname;
1080 const cfg_obj_t *addr;
1081 const cfg_obj_t *key;
1083 addr = cfg_tuple_get(cfg_listelt_value(element),
1085 key = cfg_tuple_get(cfg_listelt_value(element), "key");
1087 if (cfg_obj_issockaddr(addr)) {
1091 if (!cfg_obj_isvoid(key)) {
1092 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1093 "unexpected token '%s'",
1094 cfg_obj_asstring(key));
1095 if (result == ISC_R_SUCCESS)
1096 result = ISC_R_FAILURE;
1098 listname = cfg_obj_asstring(addr);
1099 symvalue.as_cpointer = addr;
1100 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
1101 isc_symexists_reject);
1102 if (tresult == ISC_R_EXISTS)
1104 tresult = get_masters_def(config, listname, &obj);
1105 if (tresult != ISC_R_SUCCESS) {
1106 if (result == ISC_R_SUCCESS)
1108 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
1109 "unable to find masters list '%s'",
1114 if (stackcount == pushed) {
1116 isc_uint32_t newlen = stackcount + 16;
1117 size_t newsize, oldsize;
1119 newsize = newlen * sizeof(*stack);
1120 oldsize = stackcount * sizeof(*stack);
1121 new = isc_mem_get(mctx, newsize);
1124 if (stackcount != 0) {
1127 DE_CONST(stack, ptr);
1128 memmove(new, stack, oldsize);
1129 isc_mem_put(mctx, ptr, oldsize);
1132 stackcount = newlen;
1134 stack[pushed++] = cfg_list_next(element);
1138 element = stack[--pushed];
1142 if (stack != NULL) {
1145 DE_CONST(stack, ptr);
1146 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1148 isc_symtab_destroy(&symtab);
1154 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1155 isc_result_t result = ISC_R_SUCCESS;
1156 isc_result_t tresult;
1157 const cfg_listelt_t *element;
1158 const cfg_listelt_t *element2;
1159 dns_fixedname_t fixed;
1163 /* Check for "update-policy local;" */
1164 if (cfg_obj_isstring(policy) &&
1165 strcmp("local", cfg_obj_asstring(policy)) == 0)
1166 return (ISC_R_SUCCESS);
1168 /* Now check the grant policy */
1169 for (element = cfg_list_first(policy);
1171 element = cfg_list_next(element))
1173 const cfg_obj_t *stmt = cfg_listelt_value(element);
1174 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1175 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1176 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1177 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1179 dns_fixedname_init(&fixed);
1180 str = cfg_obj_asstring(identity);
1181 isc_buffer_constinit(&b, str, strlen(str));
1182 isc_buffer_add(&b, strlen(str));
1183 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1184 dns_rootname, 0, NULL);
1185 if (tresult != ISC_R_SUCCESS) {
1186 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1187 "'%s' is not a valid name", str);
1191 if (tresult == ISC_R_SUCCESS &&
1192 strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
1193 dns_fixedname_init(&fixed);
1194 str = cfg_obj_asstring(dname);
1195 isc_buffer_constinit(&b, str, strlen(str));
1196 isc_buffer_add(&b, strlen(str));
1197 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
1198 &b, dns_rootname, 0, NULL);
1199 if (tresult != ISC_R_SUCCESS) {
1200 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1201 "'%s' is not a valid name", str);
1206 if (tresult == ISC_R_SUCCESS &&
1207 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
1208 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
1209 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1210 "'%s' is not a wildcard", str);
1211 result = ISC_R_FAILURE;
1214 for (element2 = cfg_list_first(typelist);
1216 element2 = cfg_list_next(element2))
1218 const cfg_obj_t *typeobj;
1220 dns_rdatatype_t type;
1222 typeobj = cfg_listelt_value(element2);
1223 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1224 r.length = strlen(r.base);
1226 tresult = dns_rdatatype_fromtext(&type, &r);
1227 if (tresult != ISC_R_SUCCESS) {
1228 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1229 "'%s' is not a valid type", r.base);
1237 #define MASTERZONE 1
1241 #define FORWARDZONE 16
1242 #define DELEGATIONZONE 32
1243 #define STATICSTUBZONE 64
1244 #define REDIRECTZONE 128
1245 #define STREDIRECTZONE 0 /* Set to REDIRECTZONE to allow xfr-in. */
1246 #define CHECKACL 512
1254 check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) {
1255 isc_result_t result = ISC_R_SUCCESS;
1256 const cfg_obj_t *obj = NULL;
1259 static const char *nonzero[] = { "max-retry-time", "min-retry-time",
1260 "max-refresh-time", "min-refresh-time" };
1262 * Check if value is zero.
1264 for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) {
1266 if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS &&
1267 cfg_obj_asuint32(obj) == 0) {
1268 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1269 "'%s' must not be zero", nonzero[i]);
1270 result = ISC_R_FAILURE;
1277 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1278 const cfg_obj_t *config, isc_symtab_t *symtab,
1279 isc_symtab_t *files, dns_rdataclass_t defclass,
1280 cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx)
1282 const char *znamestr;
1283 const char *typestr;
1285 const cfg_obj_t *zoptions, *goptions = NULL;
1286 const cfg_obj_t *obj = NULL;
1287 isc_result_t result = ISC_R_SUCCESS;
1288 isc_result_t tresult;
1290 dns_rdataclass_t zclass;
1291 dns_fixedname_t fixedname;
1292 dns_name_t *zname = NULL;
1294 isc_boolean_t root = ISC_FALSE;
1295 isc_boolean_t rfc1918 = ISC_FALSE;
1296 isc_boolean_t ula = ISC_FALSE;
1297 const cfg_listelt_t *element;
1298 isc_boolean_t ddns = ISC_FALSE;
1300 static optionstable options[] = {
1301 { "allow-notify", SLAVEZONE | CHECKACL },
1302 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE |
1303 CHECKACL | STATICSTUBZONE },
1304 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1305 { "allow-update", MASTERZONE | CHECKACL },
1306 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1307 { "also-notify", MASTERZONE | SLAVEZONE },
1308 { "auto-dnssec", MASTERZONE | SLAVEZONE },
1309 { "check-dup-records", MASTERZONE },
1310 { "check-mx", MASTERZONE },
1311 { "check-mx-cname", MASTERZONE },
1312 { "check-srv-cname", MASTERZONE },
1313 { "check-wildcard", MASTERZONE },
1314 { "database", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE },
1315 { "delegation-only", HINTZONE | STUBZONE | FORWARDZONE |
1317 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE | STREDIRECTZONE },
1318 { "dnssec-dnskey-kskonly", MASTERZONE | SLAVEZONE },
1319 { "dnssec-loadkeys-interval", MASTERZONE | SLAVEZONE },
1320 { "dnssec-secure-to-insecure", MASTERZONE },
1321 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE | REDIRECTZONE },
1322 { "forward", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
1324 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | STATICSTUBZONE |
1326 { "integrity-check", MASTERZONE },
1327 { "ixfr-base", MASTERZONE | SLAVEZONE },
1328 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1329 { "journal", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1330 { "key-directory", MASTERZONE | SLAVEZONE },
1331 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1332 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE |
1334 { "masters", SLAVEZONE | STUBZONE | REDIRECTZONE },
1335 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1336 { "max-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1337 { "max-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1338 { "max-transfer-idle-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1339 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1340 { "max-transfer-time-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1341 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1342 { "min-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1343 { "min-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1344 { "notify", MASTERZONE | SLAVEZONE },
1345 { "notify-source", MASTERZONE | SLAVEZONE },
1346 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1347 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1348 { "request-ixfr", SLAVEZONE | REDIRECTZONE },
1349 { "server-addresses", STATICSTUBZONE },
1350 { "server-names", STATICSTUBZONE },
1351 { "sig-re-signing-interval", MASTERZONE | SLAVEZONE },
1352 { "sig-signing-nodes", MASTERZONE | SLAVEZONE },
1353 { "sig-signing-signatures", MASTERZONE | SLAVEZONE },
1354 { "sig-signing-type", MASTERZONE | SLAVEZONE },
1355 { "sig-validity-interval", MASTERZONE | SLAVEZONE },
1356 { "signing", MASTERZONE | SLAVEZONE },
1357 { "transfer-source", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1358 { "transfer-source-v6", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1359 { "try-tcp-refresh", SLAVEZONE | STREDIRECTZONE },
1360 { "update-check-ksk", MASTERZONE | SLAVEZONE },
1361 { "update-policy", MASTERZONE },
1362 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
1363 STATICSTUBZONE | REDIRECTZONE },
1366 static optionstable dialups[] = {
1367 { "notify", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1368 { "notify-passive", SLAVEZONE | STREDIRECTZONE },
1369 { "refresh", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1370 { "passive", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1373 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1375 zoptions = cfg_tuple_get(zconfig, "options");
1378 cfg_map_get(config, "options", &goptions);
1381 (void)cfg_map_get(zoptions, "type", &obj);
1383 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1384 "zone '%s': type not present", znamestr);
1385 return (ISC_R_FAILURE);
1388 typestr = cfg_obj_asstring(obj);
1389 if (strcasecmp(typestr, "master") == 0)
1391 else if (strcasecmp(typestr, "slave") == 0)
1393 else if (strcasecmp(typestr, "stub") == 0)
1395 else if (strcasecmp(typestr, "static-stub") == 0)
1396 ztype = STATICSTUBZONE;
1397 else if (strcasecmp(typestr, "forward") == 0)
1398 ztype = FORWARDZONE;
1399 else if (strcasecmp(typestr, "hint") == 0)
1401 else if (strcasecmp(typestr, "delegation-only") == 0)
1402 ztype = DELEGATIONZONE;
1403 else if (strcasecmp(typestr, "redirect") == 0)
1404 ztype = REDIRECTZONE;
1406 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1407 "zone '%s': invalid type %s",
1409 return (ISC_R_FAILURE);
1412 if (ztype == REDIRECTZONE && strcmp(znamestr, ".") != 0) {
1413 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1414 "redirect zones must be called \".\"");
1415 return (ISC_R_FAILURE);
1417 obj = cfg_tuple_get(zconfig, "class");
1418 if (cfg_obj_isstring(obj)) {
1421 DE_CONST(cfg_obj_asstring(obj), r.base);
1422 r.length = strlen(r.base);
1423 result = dns_rdataclass_fromtext(&zclass, &r);
1424 if (result != ISC_R_SUCCESS) {
1425 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1426 "zone '%s': invalid class %s",
1428 return (ISC_R_FAILURE);
1430 if (zclass != defclass) {
1431 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1432 "zone '%s': class '%s' does not "
1433 "match view/default class",
1435 return (ISC_R_FAILURE);
1440 * Look for an already existing zone.
1441 * We need to make this canonical as isc_symtab_define()
1442 * deals with strings.
1444 dns_fixedname_init(&fixedname);
1445 isc_buffer_constinit(&b, znamestr, strlen(znamestr));
1446 isc_buffer_add(&b, strlen(znamestr));
1447 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1448 dns_rootname, DNS_NAME_DOWNCASE, NULL);
1449 if (tresult != ISC_R_SUCCESS) {
1450 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1451 "zone '%s': is not a valid name", znamestr);
1452 result = ISC_R_FAILURE;
1454 char namebuf[DNS_NAME_FORMATSIZE];
1456 zname = dns_fixedname_name(&fixedname);
1457 dns_name_format(zname, namebuf, sizeof(namebuf));
1458 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 :
1459 ztype == REDIRECTZONE ? 2 : 3,
1460 symtab, "zone '%s': already exists "
1461 "previous definition: %s:%u", logctx, mctx);
1462 if (tresult != ISC_R_SUCCESS)
1464 if (dns_name_equal(zname, dns_rootname))
1466 else if (dns_name_isrfc1918(zname))
1468 else if (dns_name_isula(zname))
1473 * Check if value is zero.
1475 if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
1476 result = ISC_R_FAILURE;
1479 * Look for inappropriate options for the given zone type.
1480 * Check that ACLs expand correctly.
1482 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1484 if ((options[i].allowed & ztype) == 0 &&
1485 cfg_map_get(zoptions, options[i].name, &obj) ==
1488 if (strcmp(options[i].name, "allow-update") != 0 ||
1489 ztype != SLAVEZONE) {
1490 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1491 "option '%s' is not allowed "
1492 "in '%s' zone '%s'",
1493 options[i].name, typestr,
1495 result = ISC_R_FAILURE;
1497 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1498 "option '%s' is not allowed "
1499 "in '%s' zone '%s'",
1500 options[i].name, typestr,
1504 if ((options[i].allowed & ztype) != 0 &&
1505 (options[i].allowed & CHECKACL) != 0) {
1507 tresult = checkacl(options[i].name, actx, zconfig,
1508 voptions, config, logctx, mctx);
1509 if (tresult != ISC_R_SUCCESS)
1516 * Master & slave zones may have an "also-notify" field, but
1517 * shouldn't if notify is disabled.
1519 if (ztype == MASTERZONE || ztype == SLAVEZONE ) {
1520 isc_boolean_t donotify = ISC_TRUE;
1523 tresult = cfg_map_get(zoptions, "notify", &obj);
1524 if (tresult != ISC_R_SUCCESS && voptions != NULL)
1525 tresult = cfg_map_get(voptions, "notify", &obj);
1526 if (tresult != ISC_R_SUCCESS && goptions != NULL)
1527 tresult = cfg_map_get(goptions, "notify", &obj);
1528 if (tresult == ISC_R_SUCCESS) {
1529 if (cfg_obj_isboolean(obj))
1530 donotify = cfg_obj_asboolean(obj);
1532 const char *notifystr = cfg_obj_asstring(obj);
1533 if (ztype != MASTERZONE &&
1534 strcasecmp(notifystr, "master-only") == 0)
1535 donotify = ISC_FALSE;
1540 tresult = cfg_map_get(zoptions, "also-notify", &obj);
1541 if (tresult == ISC_R_SUCCESS && !donotify) {
1542 cfg_obj_log(zoptions, logctx, ISC_LOG_WARNING,
1543 "zone '%s': 'also-notify' set but "
1544 "'notify' is disabled", znamestr);
1545 } else if (tresult == ISC_R_SUCCESS) {
1547 tresult = validate_masters(obj, config, &count,
1549 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1555 * Slave & stub zones must have a "masters" field.
1557 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1559 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1560 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1561 "zone '%s': missing 'masters' entry",
1563 result = ISC_R_FAILURE;
1566 tresult = validate_masters(obj, config, &count,
1568 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1570 if (tresult == ISC_R_SUCCESS && count == 0) {
1571 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1572 "zone '%s': empty 'masters' entry",
1574 result = ISC_R_FAILURE;
1580 * Master zones can't have both "allow-update" and "update-policy".
1582 if (ztype == MASTERZONE || ztype == SLAVEZONE) {
1583 isc_boolean_t signing = ISC_FALSE;
1584 isc_result_t res1, res2, res3;
1585 const cfg_obj_t *au = NULL;
1589 res1 = cfg_map_get(zoptions, "allow-update", &au);
1591 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1592 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1593 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1594 "zone '%s': 'allow-update' is ignored "
1595 "when 'update-policy' is present",
1597 result = ISC_R_FAILURE;
1598 } else if (res2 == ISC_R_SUCCESS) {
1599 res3 = check_update_policy(obj, logctx);
1600 if (res3 != ISC_R_SUCCESS)
1601 result = ISC_R_FAILURE;
1605 * To determine whether auto-dnssec is allowed,
1606 * we should also check for allow-update at the
1607 * view and options levels.
1609 if (res1 != ISC_R_SUCCESS && voptions != NULL)
1610 res1 = cfg_map_get(voptions, "allow-update", &au);
1611 if (res1 != ISC_R_SUCCESS && goptions != NULL)
1612 res1 = cfg_map_get(goptions, "allow-update", &au);
1614 if (res2 == ISC_R_SUCCESS)
1616 else if (res1 == ISC_R_SUCCESS) {
1617 dns_acl_t *acl = NULL;
1618 res1 = cfg_acl_fromconfig(au, config, logctx,
1619 actx, mctx, 0, &acl);
1620 if (res1 != ISC_R_SUCCESS) {
1621 cfg_obj_log(au, logctx, ISC_LOG_ERROR,
1622 "acl expansion failed: %s",
1623 isc_result_totext(result));
1624 result = ISC_R_FAILURE;
1625 } else if (acl != NULL) {
1626 if (!dns_acl_isnone(acl))
1628 dns_acl_detach(&acl);
1633 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
1634 if (res1 == ISC_R_SUCCESS)
1635 signing = cfg_obj_asboolean(obj);
1639 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
1640 if (res3 == ISC_R_SUCCESS)
1641 arg = cfg_obj_asstring(obj);
1642 if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
1643 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1644 "'auto-dnssec %s;' requires%s "
1645 "inline-signing to be configured for "
1647 (ztype == MASTERZONE) ?
1648 " dynamic DNS or" : "");
1649 result = ISC_R_FAILURE;
1653 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1654 if (res1 == ISC_R_SUCCESS) {
1655 isc_uint32_t type = cfg_obj_asuint32(obj);
1656 if (type < 0xff00U || type > 0xffffU)
1657 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1658 "sig-signing-type: %u out of "
1659 "range [%u..%u]", type,
1661 result = ISC_R_FAILURE;
1665 res1 = cfg_map_get(zoptions, "dnssec-dnskey-kskonly", &obj);
1666 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1667 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1668 "dnssec-dnskey-kskonly: requires "
1669 "inline-signing when used in slave zone");
1670 result = ISC_R_FAILURE;
1674 res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
1675 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1676 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1677 "dnssec-loadkeys-interval: requires "
1678 "inline-signing when used in slave zone");
1679 result = ISC_R_FAILURE;
1683 res1 = cfg_map_get(zoptions, "update-check-ksk", &obj);
1684 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1685 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1686 "update-check-ksk: requires "
1687 "inline-signing when used in slave zone");
1688 result = ISC_R_FAILURE;
1693 * Check the excessively complicated "dialup" option.
1695 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1696 const cfg_obj_t *dialup = NULL;
1697 (void)cfg_map_get(zoptions, "dialup", &dialup);
1698 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1699 const char *str = cfg_obj_asstring(dialup);
1701 i < sizeof(dialups) / sizeof(dialups[0]);
1704 if (strcasecmp(dialups[i].name, str) != 0)
1706 if ((dialups[i].allowed & ztype) == 0) {
1707 cfg_obj_log(obj, logctx,
1709 "dialup type '%s' is not "
1712 str, typestr, znamestr);
1713 result = ISC_R_FAILURE;
1717 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1718 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1719 "invalid dialup type '%s' in zone "
1720 "'%s'", str, znamestr);
1721 result = ISC_R_FAILURE;
1727 * Check that forwarding is reasonable.
1731 if (voptions != NULL)
1732 (void)cfg_map_get(voptions, "forwarders", &obj);
1733 if (obj == NULL && goptions != NULL)
1734 (void)cfg_map_get(goptions, "forwarders", &obj);
1736 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1737 result = ISC_R_FAILURE;
1740 * Check that a RFC 1918 / ULA reverse zone is not forward first
1741 * unless explictly configured to be so.
1743 if (ztype == FORWARDZONE && (rfc1918 || ula)) {
1745 (void)cfg_map_get(zoptions, "forward", &obj);
1748 * Forward mode not explicity configured.
1750 if (voptions != NULL)
1751 cfg_map_get(voptions, "forward", &obj);
1752 if (obj == NULL && goptions != NULL)
1753 cfg_map_get(goptions, "forward", &obj);
1755 strcasecmp(cfg_obj_asstring(obj), "first") == 0)
1756 cfg_obj_log(zconfig, logctx, ISC_LOG_WARNING,
1757 "inherited 'forward first;' for "
1758 "%s zone '%s' - did you want "
1760 rfc1918 ? "rfc1918" : "ula",
1766 * Check validity of static stub server addresses.
1769 (void)cfg_map_get(zoptions, "server-addresses", &obj);
1770 if (ztype == STATICSTUBZONE && obj != NULL) {
1771 for (element = cfg_list_first(obj);
1773 element = cfg_list_next(element))
1777 obj = cfg_listelt_value(element);
1778 sa = *cfg_obj_assockaddr(obj);
1780 if (isc_sockaddr_getport(&sa) != 0) {
1781 result = ISC_R_FAILURE;
1782 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1783 "port is not configurable for "
1784 "static stub server-addresses");
1787 isc_netaddr_fromsockaddr(&na, &sa);
1788 if (isc_netaddr_getzone(&na) != 0) {
1789 result = ISC_R_FAILURE;
1790 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1791 "scoped address is not allowed "
1793 "server-addresses");
1799 * Check validity of static stub server names.
1802 (void)cfg_map_get(zoptions, "server-names", &obj);
1803 if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
1804 for (element = cfg_list_first(obj);
1806 element = cfg_list_next(element))
1808 const char *snamestr;
1809 dns_fixedname_t fixed_sname;
1813 obj = cfg_listelt_value(element);
1814 snamestr = cfg_obj_asstring(obj);
1816 dns_fixedname_init(&fixed_sname);
1817 isc_buffer_constinit(&b2, snamestr, strlen(snamestr));
1818 isc_buffer_add(&b2, strlen(snamestr));
1819 sname = dns_fixedname_name(&fixed_sname);
1820 tresult = dns_name_fromtext(sname, &b2, dns_rootname,
1822 if (tresult != ISC_R_SUCCESS) {
1823 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1824 "server-name '%s' is not a valid "
1826 result = ISC_R_FAILURE;
1827 } else if (dns_name_issubdomain(sname, zname)) {
1828 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1829 "server-name '%s' must not be a "
1830 "subdomain of zone name '%s'",
1831 snamestr, znamestr);
1832 result = ISC_R_FAILURE;
1838 * Warn if key-directory doesn't exist
1841 tresult = cfg_map_get(zoptions, "key-directory", &obj);
1842 if (tresult == ISC_R_SUCCESS) {
1843 const char *dir = cfg_obj_asstring(obj);
1844 tresult = isc_file_isdirectory(dir);
1848 case ISC_R_FILENOTFOUND:
1849 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1850 "key-directory: '%s' does not exist",
1853 case ISC_R_INVALIDFILE:
1854 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1855 "key-directory: '%s' is not a directory",
1859 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1860 "key-directory: '%s' %s",
1861 dir, isc_result_totext(tresult));
1867 * Check various options.
1869 tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
1870 if (tresult != ISC_R_SUCCESS)
1874 * If the zone type is rbt/rbt64 then master/hint zones
1875 * require file clauses.
1876 * If inline signing is used, then slave zones require a
1877 * file clause as well
1880 tresult = cfg_map_get(zoptions, "database", &obj);
1881 if (tresult == ISC_R_NOTFOUND ||
1882 (tresult == ISC_R_SUCCESS &&
1883 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1884 strcmp("rbt64", cfg_obj_asstring(obj)) == 0)))
1887 const cfg_obj_t *fileobj = NULL;
1888 tresult = cfg_map_get(zoptions, "file", &fileobj);
1890 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
1891 if ((tresult != ISC_R_SUCCESS &&
1892 (ztype == MASTERZONE || ztype == HINTZONE ||
1893 (ztype == SLAVEZONE && res1 == ISC_R_SUCCESS &&
1894 cfg_obj_asboolean(obj))))) {
1895 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1896 "zone '%s': missing 'file' entry",
1899 } else if (tresult == ISC_R_SUCCESS &&
1900 (ztype == SLAVEZONE || ddns)) {
1901 tresult = fileexist(fileobj, files, ISC_TRUE, logctx);
1902 if (tresult != ISC_R_SUCCESS)
1904 } else if (tresult == ISC_R_SUCCESS &&
1905 (ztype == MASTERZONE || ztype == HINTZONE)) {
1906 tresult = fileexist(fileobj, files, ISC_FALSE, logctx);
1907 if (tresult != ISC_R_SUCCESS)
1916 typedef struct keyalgorithms {
1922 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1923 const cfg_obj_t *algobj = NULL;
1924 const cfg_obj_t *secretobj = NULL;
1925 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1926 const char *algorithm;
1929 isc_result_t result;
1931 unsigned char secretbuf[1024];
1932 static const algorithmtable algorithms[] = {
1933 { "hmac-md5", 128 },
1934 { "hmac-md5.sig-alg.reg.int", 0 },
1935 { "hmac-md5.sig-alg.reg.int.", 0 },
1936 { "hmac-sha1", 160 },
1937 { "hmac-sha224", 224 },
1938 { "hmac-sha256", 256 },
1939 { "hmac-sha384", 384 },
1940 { "hmac-sha512", 512 },
1944 (void)cfg_map_get(key, "algorithm", &algobj);
1945 (void)cfg_map_get(key, "secret", &secretobj);
1946 if (secretobj == NULL || algobj == NULL) {
1947 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1948 "key '%s' must have both 'secret' and "
1949 "'algorithm' defined",
1951 return (ISC_R_FAILURE);
1954 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
1955 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
1956 if (result != ISC_R_SUCCESS) {
1957 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
1958 "bad secret '%s'", isc_result_totext(result));
1962 algorithm = cfg_obj_asstring(algobj);
1963 for (i = 0; algorithms[i].name != NULL; i++) {
1964 len = strlen(algorithms[i].name);
1965 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1966 (algorithm[len] == '\0' ||
1967 (algorithms[i].size != 0 && algorithm[len] == '-')))
1970 if (algorithms[i].name == NULL) {
1971 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1972 "unknown algorithm '%s'", algorithm);
1973 return (ISC_R_NOTFOUND);
1975 if (algorithm[len] == '-') {
1976 isc_uint16_t digestbits;
1977 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1978 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1979 if (result == ISC_R_RANGE ||
1980 digestbits > algorithms[i].size) {
1981 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1982 "key '%s' digest-bits too large "
1983 "[%u..%u]", keyname,
1984 algorithms[i].size / 2,
1985 algorithms[i].size);
1986 return (ISC_R_RANGE);
1988 if ((digestbits % 8) != 0) {
1989 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1990 "key '%s' digest-bits not multiple"
1992 return (ISC_R_RANGE);
1995 * Recommended minima for hmac algorithms.
1997 if ((digestbits < (algorithms[i].size / 2U) ||
1998 (digestbits < 80U)))
1999 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
2000 "key '%s' digest-bits too small "
2002 algorithms[i].size/2);
2004 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2005 "key '%s': unable to parse digest-bits",
2010 return (ISC_R_SUCCESS);
2014 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, isc_boolean_t writeable,
2017 isc_result_t result;
2018 isc_symvalue_t symvalue;
2022 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 0, &symvalue);
2023 if (result == ISC_R_SUCCESS) {
2025 file = cfg_obj_file(symvalue.as_cpointer);
2026 line = cfg_obj_line(symvalue.as_cpointer);
2027 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2028 "writeable file '%s': already in use: "
2029 "%s:%u", cfg_obj_asstring(obj),
2031 return (ISC_R_EXISTS);
2033 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 2,
2035 if (result == ISC_R_SUCCESS) {
2036 file = cfg_obj_file(symvalue.as_cpointer);
2037 line = cfg_obj_line(symvalue.as_cpointer);
2038 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2039 "writeable file '%s': already in use: "
2040 "%s:%u", cfg_obj_asstring(obj),
2042 return (ISC_R_EXISTS);
2044 return (ISC_R_SUCCESS);
2047 symvalue.as_cpointer = obj;
2048 result = isc_symtab_define(symtab, cfg_obj_asstring(obj),
2049 writeable ? 2 : 1, symvalue,
2050 isc_symexists_reject);
2055 * Check key list for duplicates key names and that the key names
2056 * are valid domain names as these keys are used for TSIG.
2058 * Check the key contents for validity.
2061 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
2062 isc_mem_t *mctx, isc_log_t *logctx)
2064 char namebuf[DNS_NAME_FORMATSIZE];
2065 dns_fixedname_t fname;
2067 isc_result_t result = ISC_R_SUCCESS;
2068 isc_result_t tresult;
2069 const cfg_listelt_t *element;
2071 dns_fixedname_init(&fname);
2072 name = dns_fixedname_name(&fname);
2073 for (element = cfg_list_first(keys);
2075 element = cfg_list_next(element))
2077 const cfg_obj_t *key = cfg_listelt_value(element);
2078 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
2079 isc_symvalue_t symvalue;
2083 isc_buffer_constinit(&b, keyid, strlen(keyid));
2084 isc_buffer_add(&b, strlen(keyid));
2085 tresult = dns_name_fromtext(name, &b, dns_rootname,
2087 if (tresult != ISC_R_SUCCESS) {
2088 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2089 "key '%s': bad key name", keyid);
2093 tresult = bind9_check_key(key, logctx);
2094 if (tresult != ISC_R_SUCCESS)
2097 dns_name_format(name, namebuf, sizeof(namebuf));
2098 keyname = isc_mem_strdup(mctx, namebuf);
2099 if (keyname == NULL)
2100 return (ISC_R_NOMEMORY);
2101 symvalue.as_cpointer = key;
2102 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
2103 isc_symexists_reject);
2104 if (tresult == ISC_R_EXISTS) {
2108 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
2109 1, &symvalue) == ISC_R_SUCCESS);
2110 file = cfg_obj_file(symvalue.as_cpointer);
2111 line = cfg_obj_line(symvalue.as_cpointer);
2114 file = "<unknown file>";
2115 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2116 "key '%s': already exists "
2117 "previous definition: %s:%u",
2119 isc_mem_free(mctx, keyname);
2121 } else if (tresult != ISC_R_SUCCESS) {
2122 isc_mem_free(mctx, keyname);
2133 { "transfer-source", "transfer-source-v6" },
2134 { "notify-source", "notify-source-v6" },
2135 { "query-source", "query-source-v6" },
2140 * RNDC keys are not normalised unlike TSIG keys.
2142 * "foo." is different to "foo".
2144 static isc_boolean_t
2145 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
2146 const cfg_listelt_t *element;
2147 const cfg_obj_t *obj;
2150 if (keylist == NULL)
2153 for (element = cfg_list_first(keylist);
2155 element = cfg_list_next(element))
2157 obj = cfg_listelt_value(element);
2158 str = cfg_obj_asstring(cfg_map_getname(obj));
2159 if (!strcasecmp(str, keyname))
2166 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
2167 isc_symtab_t *symtab, isc_log_t *logctx)
2169 dns_fixedname_t fname;
2170 isc_result_t result = ISC_R_SUCCESS;
2171 isc_result_t tresult;
2172 const cfg_listelt_t *e1, *e2;
2173 const cfg_obj_t *v1, *v2, *keys;
2174 const cfg_obj_t *servers;
2175 isc_netaddr_t n1, n2;
2176 unsigned int p1, p2;
2177 const cfg_obj_t *obj;
2178 char buf[ISC_NETADDR_FORMATSIZE];
2179 char namebuf[DNS_NAME_FORMATSIZE];
2184 dns_name_t *keyname;
2187 if (voptions != NULL)
2188 (void)cfg_map_get(voptions, "server", &servers);
2189 if (servers == NULL)
2190 (void)cfg_map_get(config, "server", &servers);
2191 if (servers == NULL)
2192 return (ISC_R_SUCCESS);
2194 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
2195 v1 = cfg_listelt_value(e1);
2196 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
2198 * Check that unused bits are zero.
2200 tresult = isc_netaddr_prefixok(&n1, p1);
2201 if (tresult != ISC_R_SUCCESS) {
2202 INSIST(tresult == ISC_R_FAILURE);
2203 isc_netaddr_format(&n1, buf, sizeof(buf));
2204 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
2205 "server '%s/%u': invalid prefix "
2206 "(extra bits specified)", buf, p1);
2212 if (n1.family == AF_INET)
2213 xfr = sources[source].v6;
2215 xfr = sources[source].v4;
2216 (void)cfg_map_get(v1, xfr, &obj);
2218 isc_netaddr_format(&n1, buf, sizeof(buf));
2219 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
2220 "server '%s/%u': %s not legal",
2222 result = ISC_R_FAILURE;
2224 } while (sources[++source].v4 != NULL);
2226 while ((e2 = cfg_list_next(e2)) != NULL) {
2227 v2 = cfg_listelt_value(e2);
2228 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
2229 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
2230 const char *file = cfg_obj_file(v1);
2231 unsigned int line = cfg_obj_line(v1);
2234 file = "<unknown file>";
2236 isc_netaddr_format(&n2, buf, sizeof(buf));
2237 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
2238 "server '%s/%u': already exists "
2239 "previous definition: %s:%u",
2240 buf, p2, file, line);
2241 result = ISC_R_FAILURE;
2245 cfg_map_get(v1, "keys", &keys);
2248 * Normalize key name.
2250 keyval = cfg_obj_asstring(keys);
2251 dns_fixedname_init(&fname);
2252 isc_buffer_constinit(&b, keyval, strlen(keyval));
2253 isc_buffer_add(&b, strlen(keyval));
2254 keyname = dns_fixedname_name(&fname);
2255 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
2257 if (tresult != ISC_R_SUCCESS) {
2258 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2259 "bad key name '%s'", keyval);
2260 result = ISC_R_FAILURE;
2263 dns_name_format(keyname, namebuf, sizeof(namebuf));
2264 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
2265 if (tresult != ISC_R_SUCCESS) {
2266 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2267 "unknown key '%s'", keyval);
2268 result = ISC_R_FAILURE;
2276 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
2279 const char *keystr, *keynamestr;
2280 dns_fixedname_t fkeyname;
2281 dns_name_t *keyname;
2284 isc_result_t result = ISC_R_SUCCESS;
2285 isc_result_t tresult;
2286 isc_uint32_t flags, proto, alg;
2287 unsigned char keydata[4096];
2289 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
2290 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
2291 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
2293 dns_fixedname_init(&fkeyname);
2294 keyname = dns_fixedname_name(&fkeyname);
2295 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
2297 isc_buffer_constinit(&b, keynamestr, strlen(keynamestr));
2298 isc_buffer_add(&b, strlen(keynamestr));
2299 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
2300 if (result != ISC_R_SUCCESS) {
2301 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
2302 isc_result_totext(result));
2303 result = ISC_R_FAILURE;
2306 if (flags > 0xffff) {
2307 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2308 "flags too big: %u\n", flags);
2309 result = ISC_R_FAILURE;
2312 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2313 "protocol too big: %u\n", proto);
2314 result = ISC_R_FAILURE;
2317 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2318 "algorithm too big: %u\n", alg);
2319 result = ISC_R_FAILURE;
2323 const char *initmethod;
2324 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
2326 if (strcasecmp(initmethod, "initial-key") != 0) {
2327 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2328 "managed key '%s': "
2329 "invalid initialization method '%s'",
2330 keynamestr, initmethod);
2331 result = ISC_R_FAILURE;
2335 isc_buffer_init(&b, keydata, sizeof(keydata));
2337 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
2338 tresult = isc_base64_decodestring(keystr, &b);
2340 if (tresult != ISC_R_SUCCESS) {
2341 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2342 "%s", isc_result_totext(tresult));
2343 result = ISC_R_FAILURE;
2345 isc_buffer_usedregion(&b, &r);
2347 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
2348 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
2349 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2350 "%s key '%s' has a weak exponent",
2351 managed ? "managed" : "trusted",
2359 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
2360 const char *viewname, dns_rdataclass_t vclass,
2361 isc_symtab_t *files, isc_log_t *logctx, isc_mem_t *mctx)
2363 const cfg_obj_t *zones = NULL;
2364 const cfg_obj_t *keys = NULL;
2365 const cfg_listelt_t *element, *element2;
2366 isc_symtab_t *symtab = NULL;
2367 isc_result_t result = ISC_R_SUCCESS;
2368 isc_result_t tresult = ISC_R_SUCCESS;
2369 cfg_aclconfctx_t *actx = NULL;
2370 const cfg_obj_t *obj;
2371 const cfg_obj_t *options = NULL;
2372 isc_boolean_t enablednssec, enablevalidation;
2373 const char *valstr = "no";
2376 * Get global options block
2378 (void)cfg_map_get(config, "options", &options);
2381 * Check that all zone statements are syntactically correct and
2382 * there are no duplicate zones.
2384 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2385 ISC_FALSE, &symtab);
2386 if (tresult != ISC_R_SUCCESS)
2387 return (ISC_R_NOMEMORY);
2389 cfg_aclconfctx_create(mctx, &actx);
2391 if (voptions != NULL)
2392 (void)cfg_map_get(voptions, "zone", &zones);
2394 (void)cfg_map_get(config, "zone", &zones);
2396 for (element = cfg_list_first(zones);
2398 element = cfg_list_next(element))
2400 const cfg_obj_t *zone = cfg_listelt_value(element);
2402 tresult = check_zoneconf(zone, voptions, config, symtab,
2403 files, vclass, actx, logctx,
2405 if (tresult != ISC_R_SUCCESS)
2406 result = ISC_R_FAILURE;
2409 isc_symtab_destroy(&symtab);
2412 * Check that forwarding is reasonable.
2414 if (voptions == NULL) {
2415 if (options != NULL)
2416 if (check_forward(options, NULL,
2417 logctx) != ISC_R_SUCCESS)
2418 result = ISC_R_FAILURE;
2420 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
2421 result = ISC_R_FAILURE;
2425 * Check non-zero options at the global and view levels.
2427 if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS)
2428 result = ISC_R_FAILURE;
2429 if (voptions != NULL &&check_nonzero(voptions, logctx) != ISC_R_SUCCESS)
2430 result = ISC_R_FAILURE;
2433 * Check that dual-stack-servers is reasonable.
2435 if (voptions == NULL) {
2436 if (options != NULL)
2437 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2438 result = ISC_R_FAILURE;
2440 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
2441 result = ISC_R_FAILURE;
2445 * Check that rrset-order is reasonable.
2447 if (voptions != NULL) {
2448 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
2449 result = ISC_R_FAILURE;
2453 * Check that all key statements are syntactically correct and
2454 * there are no duplicate keys.
2456 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2457 ISC_FALSE, &symtab);
2458 if (tresult != ISC_R_SUCCESS)
2461 (void)cfg_map_get(config, "key", &keys);
2462 tresult = check_keylist(keys, symtab, mctx, logctx);
2463 if (tresult == ISC_R_EXISTS)
2464 result = ISC_R_FAILURE;
2465 else if (tresult != ISC_R_SUCCESS) {
2470 if (voptions != NULL) {
2472 (void)cfg_map_get(voptions, "key", &keys);
2473 tresult = check_keylist(keys, symtab, mctx, logctx);
2474 if (tresult == ISC_R_EXISTS)
2475 result = ISC_R_FAILURE;
2476 else if (tresult != ISC_R_SUCCESS) {
2483 * Global servers can refer to keys in views.
2485 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
2486 result = ISC_R_FAILURE;
2488 isc_symtab_destroy(&symtab);
2491 * Check that dnssec-enable/dnssec-validation are sensible.
2494 if (voptions != NULL)
2495 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
2496 if (obj == NULL && options != NULL)
2497 (void)cfg_map_get(options, "dnssec-enable", &obj);
2499 enablednssec = ISC_TRUE;
2501 enablednssec = cfg_obj_asboolean(obj);
2504 if (voptions != NULL)
2505 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
2506 if (obj == NULL && options != NULL)
2507 (void)cfg_map_get(options, "dnssec-validation", &obj);
2509 enablevalidation = enablednssec;
2511 } else if (cfg_obj_isboolean(obj)) {
2512 enablevalidation = cfg_obj_asboolean(obj);
2513 valstr = enablevalidation ? "yes" : "no";
2515 enablevalidation = ISC_TRUE;
2519 if (enablevalidation && !enablednssec)
2520 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2521 "'dnssec-validation %s;' and 'dnssec-enable no;'",
2525 * Check trusted-keys and managed-keys.
2528 if (voptions != NULL)
2529 (void)cfg_map_get(voptions, "trusted-keys", &keys);
2531 (void)cfg_map_get(config, "trusted-keys", &keys);
2533 for (element = cfg_list_first(keys);
2535 element = cfg_list_next(element))
2537 const cfg_obj_t *keylist = cfg_listelt_value(element);
2538 for (element2 = cfg_list_first(keylist);
2540 element2 = cfg_list_next(element2)) {
2541 obj = cfg_listelt_value(element2);
2542 tresult = check_trusted_key(obj, ISC_FALSE, logctx);
2543 if (tresult != ISC_R_SUCCESS)
2549 if (voptions != NULL)
2550 (void)cfg_map_get(voptions, "managed-keys", &keys);
2552 (void)cfg_map_get(config, "managed-keys", &keys);
2554 for (element = cfg_list_first(keys);
2556 element = cfg_list_next(element))
2558 const cfg_obj_t *keylist = cfg_listelt_value(element);
2559 for (element2 = cfg_list_first(keylist);
2561 element2 = cfg_list_next(element2)) {
2562 obj = cfg_listelt_value(element2);
2563 tresult = check_trusted_key(obj, ISC_TRUE, logctx);
2564 if (tresult != ISC_R_SUCCESS)
2572 if (voptions != NULL)
2573 tresult = check_options(voptions, logctx, mctx,
2576 tresult = check_options(config, logctx, mctx,
2578 if (tresult != ISC_R_SUCCESS)
2581 tresult = check_viewacls(actx, voptions, config, logctx, mctx);
2582 if (tresult != ISC_R_SUCCESS)
2585 tresult = check_recursionacls(actx, voptions, viewname,
2586 config, logctx, mctx);
2587 if (tresult != ISC_R_SUCCESS)
2590 tresult = check_filteraaaa(actx, voptions, viewname, config,
2592 if (tresult != ISC_R_SUCCESS)
2595 tresult = check_dns64(actx, voptions, config, logctx, mctx);
2596 if (tresult != ISC_R_SUCCESS)
2601 isc_symtab_destroy(&symtab);
2603 cfg_aclconfctx_detach(&actx);
2609 default_channels[] = {
2618 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
2621 const cfg_obj_t *categories = NULL;
2622 const cfg_obj_t *category;
2623 const cfg_obj_t *channels = NULL;
2624 const cfg_obj_t *channel;
2625 const cfg_listelt_t *element;
2626 const cfg_listelt_t *delement;
2627 const char *channelname;
2628 const char *catname;
2629 const cfg_obj_t *fileobj = NULL;
2630 const cfg_obj_t *syslogobj = NULL;
2631 const cfg_obj_t *nullobj = NULL;
2632 const cfg_obj_t *stderrobj = NULL;
2633 const cfg_obj_t *logobj = NULL;
2634 isc_result_t result = ISC_R_SUCCESS;
2635 isc_result_t tresult;
2636 isc_symtab_t *symtab = NULL;
2637 isc_symvalue_t symvalue;
2640 (void)cfg_map_get(config, "logging", &logobj);
2642 return (ISC_R_SUCCESS);
2644 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
2645 if (result != ISC_R_SUCCESS)
2648 symvalue.as_cpointer = NULL;
2649 for (i = 0; default_channels[i] != NULL; i++) {
2650 tresult = isc_symtab_define(symtab, default_channels[i], 1,
2651 symvalue, isc_symexists_replace);
2652 if (tresult != ISC_R_SUCCESS)
2656 cfg_map_get(logobj, "channel", &channels);
2658 for (element = cfg_list_first(channels);
2660 element = cfg_list_next(element))
2662 channel = cfg_listelt_value(element);
2663 channelname = cfg_obj_asstring(cfg_map_getname(channel));
2664 fileobj = syslogobj = nullobj = stderrobj = NULL;
2665 (void)cfg_map_get(channel, "file", &fileobj);
2666 (void)cfg_map_get(channel, "syslog", &syslogobj);
2667 (void)cfg_map_get(channel, "null", &nullobj);
2668 (void)cfg_map_get(channel, "stderr", &stderrobj);
2670 if (fileobj != NULL)
2672 if (syslogobj != NULL)
2674 if (nullobj != NULL)
2676 if (stderrobj != NULL)
2679 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2680 "channel '%s': exactly one of file, syslog, "
2681 "null, and stderr must be present",
2683 result = ISC_R_FAILURE;
2685 tresult = isc_symtab_define(symtab, channelname, 1,
2686 symvalue, isc_symexists_replace);
2687 if (tresult != ISC_R_SUCCESS)
2691 cfg_map_get(logobj, "category", &categories);
2693 for (element = cfg_list_first(categories);
2695 element = cfg_list_next(element))
2697 category = cfg_listelt_value(element);
2698 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
2699 if (isc_log_categorybyname(logctx, catname) == NULL) {
2700 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
2701 "undefined category: '%s'", catname);
2702 result = ISC_R_FAILURE;
2704 channels = cfg_tuple_get(category, "destinations");
2705 for (delement = cfg_list_first(channels);
2707 delement = cfg_list_next(delement))
2709 channel = cfg_listelt_value(delement);
2710 channelname = cfg_obj_asstring(channel);
2711 tresult = isc_symtab_lookup(symtab, channelname, 1,
2713 if (tresult != ISC_R_SUCCESS) {
2714 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2715 "undefined channel: '%s'",
2721 isc_symtab_destroy(&symtab);
2726 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
2729 isc_result_t result = ISC_R_SUCCESS;
2730 const cfg_obj_t *control_keylist;
2731 const cfg_listelt_t *element;
2732 const cfg_obj_t *key;
2735 control_keylist = cfg_tuple_get(control, "keys");
2736 if (cfg_obj_isvoid(control_keylist))
2737 return (ISC_R_SUCCESS);
2739 for (element = cfg_list_first(control_keylist);
2741 element = cfg_list_next(element))
2743 key = cfg_listelt_value(element);
2744 keyval = cfg_obj_asstring(key);
2746 if (!rndckey_exists(keylist, keyval)) {
2747 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2748 "unknown key '%s'", keyval);
2749 result = ISC_R_NOTFOUND;
2756 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
2759 isc_result_t result = ISC_R_SUCCESS, tresult;
2760 cfg_aclconfctx_t *actx = NULL;
2761 const cfg_listelt_t *element, *element2;
2762 const cfg_obj_t *allow;
2763 const cfg_obj_t *control;
2764 const cfg_obj_t *controls;
2765 const cfg_obj_t *controlslist = NULL;
2766 const cfg_obj_t *inetcontrols;
2767 const cfg_obj_t *unixcontrols;
2768 const cfg_obj_t *keylist = NULL;
2770 isc_uint32_t perm, mask;
2771 dns_acl_t *acl = NULL;
2772 isc_sockaddr_t addr;
2775 (void)cfg_map_get(config, "controls", &controlslist);
2776 if (controlslist == NULL)
2777 return (ISC_R_SUCCESS);
2779 (void)cfg_map_get(config, "key", &keylist);
2781 cfg_aclconfctx_create(mctx, &actx);
2784 * INET: Check allow clause.
2785 * UNIX: Check "perm" for sanity, check path length.
2787 for (element = cfg_list_first(controlslist);
2789 element = cfg_list_next(element)) {
2790 controls = cfg_listelt_value(element);
2791 unixcontrols = NULL;
2792 inetcontrols = NULL;
2793 (void)cfg_map_get(controls, "unix", &unixcontrols);
2794 (void)cfg_map_get(controls, "inet", &inetcontrols);
2795 for (element2 = cfg_list_first(inetcontrols);
2797 element2 = cfg_list_next(element2)) {
2798 control = cfg_listelt_value(element2);
2799 allow = cfg_tuple_get(control, "allow");
2800 tresult = cfg_acl_fromconfig(allow, config, logctx,
2801 actx, mctx, 0, &acl);
2803 dns_acl_detach(&acl);
2804 if (tresult != ISC_R_SUCCESS)
2806 tresult = bind9_check_controlskeys(control, keylist,
2808 if (tresult != ISC_R_SUCCESS)
2811 for (element2 = cfg_list_first(unixcontrols);
2813 element2 = cfg_list_next(element2)) {
2814 control = cfg_listelt_value(element2);
2815 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
2816 tresult = isc_sockaddr_frompath(&addr, path);
2817 if (tresult == ISC_R_NOSPACE) {
2818 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
2819 "unix control '%s': path too long",
2821 result = ISC_R_NOSPACE;
2823 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
2824 for (i = 0; i < 3; i++) {
2825 #ifdef NEED_SECURE_DIRECTORY
2826 mask = (0x1 << (i*3)); /* SEARCH */
2828 mask = (0x6 << (i*3)); /* READ + WRITE */
2830 if ((perm & mask) == mask)
2834 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2835 "unix control '%s' allows access "
2836 "to everyone", path);
2837 } else if (i == 3) {
2838 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2839 "unix control '%s' allows access "
2842 tresult = bind9_check_controlskeys(control, keylist,
2844 if (tresult != ISC_R_SUCCESS)
2848 cfg_aclconfctx_detach(&actx);
2853 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
2856 const cfg_obj_t *options = NULL;
2857 const cfg_obj_t *views = NULL;
2858 const cfg_obj_t *acls = NULL;
2859 const cfg_obj_t *kals = NULL;
2860 const cfg_obj_t *obj;
2861 const cfg_listelt_t *velement;
2862 isc_result_t result = ISC_R_SUCCESS;
2863 isc_result_t tresult;
2864 isc_symtab_t *symtab = NULL;
2865 isc_symtab_t *files = NULL;
2867 static const char *builtin[] = { "localhost", "localnets",
2870 (void)cfg_map_get(config, "options", &options);
2872 if (options != NULL &&
2873 check_options(options, logctx, mctx,
2874 optlevel_options) != ISC_R_SUCCESS)
2875 result = ISC_R_FAILURE;
2877 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
2878 result = ISC_R_FAILURE;
2880 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
2881 result = ISC_R_FAILURE;
2883 if (options != NULL &&
2884 check_order(options, logctx) != ISC_R_SUCCESS)
2885 result = ISC_R_FAILURE;
2887 (void)cfg_map_get(config, "view", &views);
2889 if (views != NULL && options != NULL)
2890 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2891 result = ISC_R_FAILURE;
2894 * Use case insensitve comparision as not all file systems are
2895 * case sensitive. This will prevent people using FOO.DB and foo.db
2896 * on case sensitive file systems but that shouldn't be a major issue.
2898 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE,
2900 if (tresult != ISC_R_SUCCESS)
2903 if (views == NULL) {
2904 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
2905 files, logctx, mctx) != ISC_R_SUCCESS)
2906 result = ISC_R_FAILURE;
2908 const cfg_obj_t *zones = NULL;
2910 (void)cfg_map_get(config, "zone", &zones);
2911 if (zones != NULL) {
2912 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
2913 "when using 'view' statements, "
2914 "all zones must be in views");
2915 result = ISC_R_FAILURE;
2919 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
2920 if (tresult != ISC_R_SUCCESS)
2922 for (velement = cfg_list_first(views);
2924 velement = cfg_list_next(velement))
2926 const cfg_obj_t *view = cfg_listelt_value(velement);
2927 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
2928 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
2929 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
2930 dns_rdataclass_t vclass = dns_rdataclass_in;
2931 const char *key = cfg_obj_asstring(vname);
2932 isc_symvalue_t symvalue;
2933 unsigned int symtype;
2935 tresult = ISC_R_SUCCESS;
2936 if (cfg_obj_isstring(vclassobj)) {
2939 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
2940 r.length = strlen(r.base);
2941 tresult = dns_rdataclass_fromtext(&vclass, &r);
2942 if (tresult != ISC_R_SUCCESS)
2943 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
2944 "view '%s': invalid class %s",
2945 cfg_obj_asstring(vname), r.base);
2947 symtype = vclass + 1;
2948 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
2949 symvalue.as_cpointer = view;
2950 tresult = isc_symtab_define(symtab, key, symtype,
2952 isc_symexists_reject);
2953 if (tresult == ISC_R_EXISTS) {
2956 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
2957 symtype, &symvalue) == ISC_R_SUCCESS);
2958 file = cfg_obj_file(symvalue.as_cpointer);
2959 line = cfg_obj_line(symvalue.as_cpointer);
2960 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2961 "view '%s': already exists "
2962 "previous definition: %s:%u",
2965 } else if (tresult != ISC_R_SUCCESS) {
2967 } else if ((strcasecmp(key, "_bind") == 0 &&
2968 vclass == dns_rdataclass_ch) ||
2969 (strcasecmp(key, "_default") == 0 &&
2970 vclass == dns_rdataclass_in)) {
2971 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2972 "attempt to redefine builtin view "
2974 result = ISC_R_EXISTS;
2977 if (tresult == ISC_R_SUCCESS)
2978 tresult = check_viewconf(config, voptions, key, vclass,
2979 files, logctx, mctx);
2980 if (tresult != ISC_R_SUCCESS)
2981 result = ISC_R_FAILURE;
2984 isc_symtab_destroy(&symtab);
2986 isc_symtab_destroy(&files);
2988 if (views != NULL && options != NULL) {
2990 tresult = cfg_map_get(options, "cache-file", &obj);
2991 if (tresult == ISC_R_SUCCESS) {
2992 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2993 "'cache-file' cannot be a global "
2994 "option if views are present");
2995 result = ISC_R_FAILURE;
2999 cfg_map_get(config, "acl", &acls);
3002 const cfg_listelt_t *elt;
3003 const cfg_listelt_t *elt2;
3004 const char *aclname;
3006 for (elt = cfg_list_first(acls);
3008 elt = cfg_list_next(elt)) {
3009 const cfg_obj_t *acl = cfg_listelt_value(elt);
3010 unsigned int line = cfg_obj_line(acl);
3013 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
3015 i < sizeof(builtin) / sizeof(builtin[0]);
3017 if (strcasecmp(aclname, builtin[i]) == 0) {
3018 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
3019 "attempt to redefine "
3022 result = ISC_R_FAILURE;
3026 for (elt2 = cfg_list_next(elt);
3028 elt2 = cfg_list_next(elt2)) {
3029 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
3031 name = cfg_obj_asstring(cfg_tuple_get(acl2,
3033 if (strcasecmp(aclname, name) == 0) {
3034 const char *file = cfg_obj_file(acl);
3037 file = "<unknown file>";
3039 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
3040 "attempt to redefine "
3041 "acl '%s' previous "
3042 "definition: %s:%u",
3044 result = ISC_R_FAILURE;
3050 tresult = cfg_map_get(config, "kal", &kals);
3051 if (tresult == ISC_R_SUCCESS) {
3052 const cfg_listelt_t *elt;
3053 const cfg_listelt_t *elt2;
3054 const char *aclname;
3056 for (elt = cfg_list_first(kals);
3058 elt = cfg_list_next(elt)) {
3059 const cfg_obj_t *acl = cfg_listelt_value(elt);
3061 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
3063 for (elt2 = cfg_list_next(elt);
3065 elt2 = cfg_list_next(elt2)) {
3066 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
3068 name = cfg_obj_asstring(cfg_tuple_get(acl2,
3070 if (strcasecmp(aclname, name) == 0) {
3071 const char *file = cfg_obj_file(acl);
3072 unsigned int line = cfg_obj_line(acl);
3075 file = "<unknown file>";
3077 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
3078 "attempt to redefine "
3079 "kal '%s' previous "
3080 "definition: %s:%u",
3082 result = ISC_R_FAILURE;