2 * Copyright (C) 2004-2014 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>
31 #include <isc/netaddr.h>
32 #include <isc/parseint.h>
33 #include <isc/region.h>
34 #include <isc/result.h>
35 #include <isc/sockaddr.h>
36 #include <isc/string.h>
37 #include <isc/symtab.h>
41 #include <dns/fixedname.h>
42 #include <dns/rdataclass.h>
43 #include <dns/rdatatype.h>
44 #include <dns/secalg.h>
48 #include <isccfg/aclconf.h>
49 #include <isccfg/cfg.h>
51 #include <bind9/check.h>
54 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
57 isc_mem_free(userarg, key);
61 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
62 isc_result_t result = ISC_R_SUCCESS;
65 dns_fixedname_t fixed;
67 dns_rdataclass_t rdclass;
68 dns_rdatatype_t rdtype;
72 dns_fixedname_init(&fixed);
73 obj = cfg_tuple_get(ent, "class");
74 if (cfg_obj_isstring(obj)) {
76 DE_CONST(cfg_obj_asstring(obj), r.base);
77 r.length = strlen(r.base);
78 tresult = dns_rdataclass_fromtext(&rdclass, &r);
79 if (tresult != ISC_R_SUCCESS) {
80 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
81 "rrset-order: invalid class '%s'",
83 result = ISC_R_FAILURE;
87 obj = cfg_tuple_get(ent, "type");
88 if (cfg_obj_isstring(obj)) {
90 DE_CONST(cfg_obj_asstring(obj), r.base);
91 r.length = strlen(r.base);
92 tresult = dns_rdatatype_fromtext(&rdtype, &r);
93 if (tresult != ISC_R_SUCCESS) {
94 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
95 "rrset-order: invalid type '%s'",
97 result = ISC_R_FAILURE;
101 obj = cfg_tuple_get(ent, "name");
102 if (cfg_obj_isstring(obj)) {
103 str = cfg_obj_asstring(obj);
104 isc_buffer_constinit(&b, str, strlen(str));
105 isc_buffer_add(&b, strlen(str));
106 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
107 dns_rootname, 0, NULL);
108 if (tresult != ISC_R_SUCCESS) {
109 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
110 "rrset-order: invalid name '%s'", str);
111 result = ISC_R_FAILURE;
115 obj = cfg_tuple_get(ent, "order");
116 if (!cfg_obj_isstring(obj) ||
117 strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
118 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
119 "rrset-order: keyword 'order' missing");
120 result = ISC_R_FAILURE;
123 obj = cfg_tuple_get(ent, "ordering");
124 if (!cfg_obj_isstring(obj)) {
125 cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
126 "rrset-order: missing ordering");
127 result = ISC_R_FAILURE;
128 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
129 #if !DNS_RDATASET_FIXED
130 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
131 "rrset-order: order 'fixed' was disabled at "
134 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
135 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
136 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
137 "rrset-order: invalid order '%s'",
138 cfg_obj_asstring(obj));
139 result = ISC_R_FAILURE;
145 check_order(const cfg_obj_t *options, isc_log_t *logctx) {
146 isc_result_t result = ISC_R_SUCCESS;
147 isc_result_t tresult;
148 const cfg_listelt_t *element;
149 const cfg_obj_t *obj = NULL;
151 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
154 for (element = cfg_list_first(obj);
156 element = cfg_list_next(element))
158 tresult = check_orderent(cfg_listelt_value(element), logctx);
159 if (tresult != ISC_R_SUCCESS)
166 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
167 const cfg_listelt_t *element;
168 const cfg_obj_t *alternates = NULL;
169 const cfg_obj_t *value;
170 const cfg_obj_t *obj;
172 dns_fixedname_t fixed;
175 isc_result_t result = ISC_R_SUCCESS;
176 isc_result_t tresult;
178 (void)cfg_map_get(options, "dual-stack-servers", &alternates);
180 if (alternates == NULL)
181 return (ISC_R_SUCCESS);
183 obj = cfg_tuple_get(alternates, "port");
184 if (cfg_obj_isuint32(obj)) {
185 isc_uint32_t val = cfg_obj_asuint32(obj);
186 if (val > ISC_UINT16_MAX) {
187 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
188 "port '%u' out of range", val);
189 result = ISC_R_FAILURE;
192 obj = cfg_tuple_get(alternates, "addresses");
193 for (element = cfg_list_first(obj);
195 element = cfg_list_next(element)) {
196 value = cfg_listelt_value(element);
197 if (cfg_obj_issockaddr(value))
199 obj = cfg_tuple_get(value, "name");
200 str = cfg_obj_asstring(obj);
201 isc_buffer_constinit(&buffer, str, strlen(str));
202 isc_buffer_add(&buffer, strlen(str));
203 dns_fixedname_init(&fixed);
204 name = dns_fixedname_name(&fixed);
205 tresult = dns_name_fromtext(name, &buffer, dns_rootname,
207 if (tresult != ISC_R_SUCCESS) {
208 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
209 "bad name '%s'", str);
210 result = ISC_R_FAILURE;
212 obj = cfg_tuple_get(value, "port");
213 if (cfg_obj_isuint32(obj)) {
214 isc_uint32_t val = cfg_obj_asuint32(obj);
215 if (val > ISC_UINT16_MAX) {
216 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
217 "port '%u' out of range", val);
218 result = ISC_R_FAILURE;
226 check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
229 const cfg_obj_t *forward = NULL;
230 const cfg_obj_t *forwarders = NULL;
232 (void)cfg_map_get(options, "forward", &forward);
233 (void)cfg_map_get(options, "forwarders", &forwarders);
235 if (forwarders != NULL && global != NULL) {
236 const char *file = cfg_obj_file(global);
237 unsigned int line = cfg_obj_line(global);
238 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
239 "forwarders declared in root zone and "
240 "in general configuration: %s:%u",
242 return (ISC_R_FAILURE);
244 if (forward != NULL && forwarders == NULL) {
245 cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
246 "no matching 'forwarders' statement");
247 return (ISC_R_FAILURE);
249 return (ISC_R_SUCCESS);
253 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
254 isc_result_t result = ISC_R_SUCCESS;
255 isc_result_t tresult;
256 const cfg_listelt_t *element;
259 dns_fixedname_t fixed;
261 const cfg_obj_t *obj;
263 dns_fixedname_init(&fixed);
264 name = dns_fixedname_name(&fixed);
265 obj = cfg_tuple_get(disabled, "name");
266 str = cfg_obj_asstring(obj);
267 isc_buffer_constinit(&b, str, strlen(str));
268 isc_buffer_add(&b, strlen(str));
269 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
270 if (tresult != ISC_R_SUCCESS) {
271 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
272 "bad domain name '%s'", str);
276 obj = cfg_tuple_get(disabled, "algorithms");
278 for (element = cfg_list_first(obj);
280 element = cfg_list_next(element))
284 isc_result_t tresult;
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_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
682 isc_result_t result = ISC_R_SUCCESS;
683 isc_result_t tresult;
685 const cfg_obj_t *obj = NULL;
686 const cfg_obj_t *resignobj = NULL;
687 const cfg_listelt_t *element;
688 isc_symtab_t *symtab = NULL;
689 dns_fixedname_t fixed;
694 static intervaltable intervals[] = {
695 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
696 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
697 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
698 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
699 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
700 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
701 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
702 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
705 static const char *server_contact[] = {
706 "empty-server", "empty-contact",
707 "dns64-server", "dns64-contact",
712 * Check that fields specified in units of time other than seconds
713 * have reasonable values.
715 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
718 (void)cfg_map_get(options, intervals[i].name, &obj);
721 val = cfg_obj_asuint32(obj);
722 if (val > intervals[i].max) {
723 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
724 "%s '%u' is out of range (0..%u)",
725 intervals[i].name, val,
727 result = ISC_R_RANGE;
728 } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
729 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
730 "%s '%d' is out of range",
731 intervals[i].name, val);
732 result = ISC_R_RANGE;
737 cfg_map_get(options, "max-rsa-exponent-size", &obj);
741 val = cfg_obj_asuint32(obj);
742 if (val != 0 && (val < 35 || val > 4096)) {
743 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
744 "max-rsa-exponent-size '%u' is out of "
745 "range (35..4096)", val);
746 result = ISC_R_RANGE;
751 cfg_map_get(options, "sig-validity-interval", &obj);
753 isc_uint32_t validity, resign = 0;
755 validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
756 resignobj = cfg_tuple_get(obj, "re-sign");
757 if (!cfg_obj_isvoid(resignobj))
758 resign = cfg_obj_asuint32(resignobj);
760 if (validity > 3660 || validity == 0) { /* 10 years */
761 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
762 "%s '%u' is out of range (1..3660)",
763 "sig-validity-interval", validity);
764 result = ISC_R_RANGE;
767 if (!cfg_obj_isvoid(resignobj)) {
768 if (resign > 3660 || resign == 0) { /* 10 years */
769 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
770 "%s '%u' is out of range (1..3660)",
771 "sig-validity-interval (re-sign)",
773 result = ISC_R_RANGE;
774 } else if ((validity > 7 && validity < resign) ||
775 (validity <= 7 && validity * 24 < resign)) {
776 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
777 "validity interval (%u days) "
778 "less than re-signing interval "
779 "(%u %s)", validity, resign,
780 (validity > 7) ? "days" : "hours");
781 result = ISC_R_RANGE;
787 (void)cfg_map_get(options, "preferred-glue", &obj);
790 str = cfg_obj_asstring(obj);
791 if (strcasecmp(str, "a") != 0 &&
792 strcasecmp(str, "aaaa") != 0 &&
793 strcasecmp(str, "none") != 0)
794 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
795 "preferred-glue unexpected value '%s'",
800 (void)cfg_map_get(options, "root-delegation-only", &obj);
802 if (!cfg_obj_isvoid(obj)) {
803 const cfg_listelt_t *element;
804 const cfg_obj_t *exclude;
806 dns_fixedname_t fixed;
810 dns_fixedname_init(&fixed);
811 name = dns_fixedname_name(&fixed);
812 for (element = cfg_list_first(obj);
814 element = cfg_list_next(element)) {
815 exclude = cfg_listelt_value(element);
816 str = cfg_obj_asstring(exclude);
817 isc_buffer_constinit(&b, str, strlen(str));
818 isc_buffer_add(&b, strlen(str));
819 tresult = dns_name_fromtext(name, &b,
822 if (tresult != ISC_R_SUCCESS) {
823 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
824 "bad domain name '%s'",
833 * Set supported DNSSEC algorithms.
836 (void)cfg_map_get(options, "disable-algorithms", &obj);
838 for (element = cfg_list_first(obj);
840 element = cfg_list_next(element))
842 obj = cfg_listelt_value(element);
843 tresult = disabled_algorithms(obj, logctx);
844 if (tresult != ISC_R_SUCCESS)
849 dns_fixedname_init(&fixed);
850 name = dns_fixedname_name(&fixed);
853 * Check the DLV zone name.
856 (void)cfg_map_get(options, "dnssec-lookaside", &obj);
858 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
860 if (tresult != ISC_R_SUCCESS)
862 for (element = cfg_list_first(obj);
864 element = cfg_list_next(element))
867 const cfg_obj_t *dlvobj, *anchor;
869 obj = cfg_listelt_value(element);
871 anchor = cfg_tuple_get(obj, "trust-anchor");
872 dlvobj = cfg_tuple_get(obj, "domain");
873 dlv = cfg_obj_asstring(dlvobj);
876 * If domain is "auto" or "no" and trust anchor
877 * is missing, skip remaining tests
879 if (cfg_obj_isvoid(anchor)) {
880 if (!strcasecmp(dlv, "no") ||
881 !strcasecmp(dlv, "auto"))
885 isc_buffer_constinit(&b, dlv, strlen(dlv));
886 isc_buffer_add(&b, strlen(dlv));
887 tresult = dns_name_fromtext(name, &b, dns_rootname,
889 if (tresult != ISC_R_SUCCESS) {
890 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
891 "bad domain name '%s'", dlv);
895 if (symtab != NULL) {
896 tresult = nameexist(obj, dlv, 1, symtab,
897 "dnssec-lookaside '%s': "
898 "already exists previous "
901 if (tresult != ISC_R_SUCCESS &&
902 result == ISC_R_SUCCESS)
906 * XXXMPA to be removed when multiple lookaside
907 * namespaces are supported.
909 if (!dns_name_equal(dns_rootname, name)) {
910 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
911 "dnssec-lookaside '%s': "
912 "non-root not yet supported", dlv);
913 if (result == ISC_R_SUCCESS)
914 result = ISC_R_FAILURE;
917 if (!cfg_obj_isvoid(anchor)) {
918 dlv = cfg_obj_asstring(anchor);
919 isc_buffer_constinit(&b, dlv, strlen(dlv));
920 isc_buffer_add(&b, strlen(dlv));
921 tresult = dns_name_fromtext(name, &b,
925 if (tresult != ISC_R_SUCCESS) {
926 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
927 "bad domain name '%s'",
929 if (result == ISC_R_SUCCESS)
933 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
934 "dnssec-lookaside requires "
935 "either 'auto' or 'no', or a "
936 "domain and trust anchor");
937 if (result == ISC_R_SUCCESS)
938 result = ISC_R_FAILURE;
943 isc_symtab_destroy(&symtab);
947 * Check auto-dnssec at the view/options level
950 (void)cfg_map_get(options, "auto-dnssec", &obj);
952 const char *arg = cfg_obj_asstring(obj);
953 if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
954 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
955 "auto-dnssec may only be activated at the "
957 result = ISC_R_FAILURE;
962 * Check dnssec-must-be-secure.
965 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
967 isc_symtab_t *symtab = NULL;
968 tresult = isc_symtab_create(mctx, 100, freekey, mctx,
970 if (tresult != ISC_R_SUCCESS)
972 for (element = cfg_list_first(obj);
974 element = cfg_list_next(element))
976 obj = cfg_listelt_value(element);
977 tresult = mustbesecure(obj, symtab, logctx, mctx);
978 if (tresult != ISC_R_SUCCESS)
982 isc_symtab_destroy(&symtab);
986 * Check server/contacts for syntactic validity.
988 for (i= 0; server_contact[i] != NULL; i++) {
990 (void)cfg_map_get(options, server_contact[i], &obj);
992 str = cfg_obj_asstring(obj);
993 isc_buffer_constinit(&b, str, strlen(str));
994 isc_buffer_add(&b, strlen(str));
995 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
996 &b, dns_rootname, 0, NULL);
997 if (tresult != ISC_R_SUCCESS) {
998 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
999 "%s: invalid name '%s'",
1000 server_contact[i], str);
1001 result = ISC_R_FAILURE;
1007 * Check empty zone configuration.
1010 (void)cfg_map_get(options, "disable-empty-zone", &obj);
1011 for (element = cfg_list_first(obj);
1013 element = cfg_list_next(element))
1015 obj = cfg_listelt_value(element);
1016 str = cfg_obj_asstring(obj);
1017 isc_buffer_constinit(&b, str, strlen(str));
1018 isc_buffer_add(&b, strlen(str));
1019 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1020 dns_rootname, 0, NULL);
1021 if (tresult != ISC_R_SUCCESS) {
1022 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1023 "disable-empty-zone: invalid name '%s'",
1025 result = ISC_R_FAILURE;
1030 * Check that server-id is not too long.
1031 * 1024 bytes should be big enough.
1034 (void)cfg_map_get(options, "server-id", &obj);
1035 if (obj != NULL && cfg_obj_isstring(obj) &&
1036 strlen(cfg_obj_asstring(obj)) > 1024U) {
1037 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1038 "'server-id' too big (>1024 bytes)");
1039 result = ISC_R_FAILURE;
1046 get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
1047 isc_result_t result;
1048 const cfg_obj_t *masters = NULL;
1049 const cfg_listelt_t *elt;
1051 result = cfg_map_get(cctx, "masters", &masters);
1052 if (result != ISC_R_SUCCESS)
1054 for (elt = cfg_list_first(masters);
1056 elt = cfg_list_next(elt)) {
1057 const cfg_obj_t *list;
1058 const char *listname;
1060 list = cfg_listelt_value(elt);
1061 listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
1063 if (strcasecmp(listname, name) == 0) {
1065 return (ISC_R_SUCCESS);
1068 return (ISC_R_NOTFOUND);
1072 validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
1073 isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
1075 isc_result_t result = ISC_R_SUCCESS;
1076 isc_result_t tresult;
1077 isc_uint32_t count = 0;
1078 isc_symtab_t *symtab = NULL;
1079 isc_symvalue_t symvalue;
1080 const cfg_listelt_t *element;
1081 const cfg_listelt_t **stack = NULL;
1082 isc_uint32_t stackcount = 0, pushed = 0;
1083 const cfg_obj_t *list;
1085 REQUIRE(countp != NULL);
1086 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1087 if (result != ISC_R_SUCCESS) {
1093 list = cfg_tuple_get(obj, "addresses");
1094 element = cfg_list_first(list);
1098 element = cfg_list_next(element))
1100 const char *listname;
1101 const cfg_obj_t *addr;
1102 const cfg_obj_t *key;
1104 addr = cfg_tuple_get(cfg_listelt_value(element),
1106 key = cfg_tuple_get(cfg_listelt_value(element), "key");
1108 if (cfg_obj_issockaddr(addr)) {
1112 if (!cfg_obj_isvoid(key)) {
1113 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1114 "unexpected token '%s'",
1115 cfg_obj_asstring(key));
1116 if (result == ISC_R_SUCCESS)
1117 result = ISC_R_FAILURE;
1119 listname = cfg_obj_asstring(addr);
1120 symvalue.as_cpointer = addr;
1121 tresult = isc_symtab_define(symtab, listname, 1, symvalue,
1122 isc_symexists_reject);
1123 if (tresult == ISC_R_EXISTS)
1125 tresult = get_masters_def(config, listname, &obj);
1126 if (tresult != ISC_R_SUCCESS) {
1127 if (result == ISC_R_SUCCESS)
1129 cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
1130 "unable to find masters list '%s'",
1135 if (stackcount == pushed) {
1137 isc_uint32_t newlen = stackcount + 16;
1138 size_t newsize, oldsize;
1140 newsize = newlen * sizeof(*stack);
1141 oldsize = stackcount * sizeof(*stack);
1142 new = isc_mem_get(mctx, newsize);
1145 if (stackcount != 0) {
1148 DE_CONST(stack, ptr);
1149 memmove(new, stack, oldsize);
1150 isc_mem_put(mctx, ptr, oldsize);
1153 stackcount = newlen;
1155 stack[pushed++] = cfg_list_next(element);
1159 element = stack[--pushed];
1163 if (stack != NULL) {
1166 DE_CONST(stack, ptr);
1167 isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1169 isc_symtab_destroy(&symtab);
1175 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1176 isc_result_t result = ISC_R_SUCCESS;
1177 isc_result_t tresult;
1178 const cfg_listelt_t *element;
1179 const cfg_listelt_t *element2;
1180 dns_fixedname_t fixed;
1184 /* Check for "update-policy local;" */
1185 if (cfg_obj_isstring(policy) &&
1186 strcmp("local", cfg_obj_asstring(policy)) == 0)
1187 return (ISC_R_SUCCESS);
1189 /* Now check the grant policy */
1190 for (element = cfg_list_first(policy);
1192 element = cfg_list_next(element))
1194 const cfg_obj_t *stmt = cfg_listelt_value(element);
1195 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1196 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1197 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1198 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1200 dns_fixedname_init(&fixed);
1201 str = cfg_obj_asstring(identity);
1202 isc_buffer_constinit(&b, str, strlen(str));
1203 isc_buffer_add(&b, strlen(str));
1204 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1205 dns_rootname, 0, NULL);
1206 if (tresult != ISC_R_SUCCESS) {
1207 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1208 "'%s' is not a valid name", str);
1212 if (tresult == ISC_R_SUCCESS &&
1213 strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
1214 dns_fixedname_init(&fixed);
1215 str = cfg_obj_asstring(dname);
1216 isc_buffer_constinit(&b, str, strlen(str));
1217 isc_buffer_add(&b, strlen(str));
1218 tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
1219 &b, dns_rootname, 0, NULL);
1220 if (tresult != ISC_R_SUCCESS) {
1221 cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1222 "'%s' is not a valid name", str);
1227 if (tresult == ISC_R_SUCCESS &&
1228 strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
1229 !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
1230 cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1231 "'%s' is not a wildcard", str);
1232 result = ISC_R_FAILURE;
1235 for (element2 = cfg_list_first(typelist);
1237 element2 = cfg_list_next(element2))
1239 const cfg_obj_t *typeobj;
1241 dns_rdatatype_t type;
1243 typeobj = cfg_listelt_value(element2);
1244 DE_CONST(cfg_obj_asstring(typeobj), r.base);
1245 r.length = strlen(r.base);
1247 tresult = dns_rdatatype_fromtext(&type, &r);
1248 if (tresult != ISC_R_SUCCESS) {
1249 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1250 "'%s' is not a valid type", r.base);
1258 #define MASTERZONE 1
1262 #define FORWARDZONE 16
1263 #define DELEGATIONZONE 32
1264 #define STATICSTUBZONE 64
1265 #define REDIRECTZONE 128
1266 #define STREDIRECTZONE 0 /* Set to REDIRECTZONE to allow xfr-in. */
1267 #define CHECKACL 512
1275 check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) {
1276 isc_result_t result = ISC_R_SUCCESS;
1277 const cfg_obj_t *obj = NULL;
1280 static const char *nonzero[] = { "max-retry-time", "min-retry-time",
1281 "max-refresh-time", "min-refresh-time" };
1283 * Check if value is zero.
1285 for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) {
1287 if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS &&
1288 cfg_obj_asuint32(obj) == 0) {
1289 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1290 "'%s' must not be zero", nonzero[i]);
1291 result = ISC_R_FAILURE;
1298 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1299 const cfg_obj_t *config, isc_symtab_t *symtab,
1300 dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
1301 isc_log_t *logctx, isc_mem_t *mctx)
1303 const char *znamestr;
1304 const char *typestr;
1306 const cfg_obj_t *zoptions, *goptions = NULL;
1307 const cfg_obj_t *obj = NULL;
1308 isc_result_t result = ISC_R_SUCCESS;
1309 isc_result_t tresult;
1311 dns_rdataclass_t zclass;
1312 dns_fixedname_t fixedname;
1313 dns_name_t *zname = NULL;
1315 isc_boolean_t root = ISC_FALSE;
1316 const cfg_listelt_t *element;
1318 static optionstable options[] = {
1319 { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE |
1320 CHECKACL | STATICSTUBZONE },
1321 { "allow-notify", SLAVEZONE | CHECKACL },
1322 { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
1323 { "notify", MASTERZONE | SLAVEZONE },
1324 { "also-notify", MASTERZONE | SLAVEZONE },
1325 { "dialup", MASTERZONE | SLAVEZONE | STUBZONE | STREDIRECTZONE },
1326 { "delegation-only", HINTZONE | STUBZONE | DELEGATIONZONE },
1327 { "forward", MASTERZONE | SLAVEZONE | STUBZONE |
1328 STATICSTUBZONE | FORWARDZONE },
1329 { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE |
1330 STATICSTUBZONE | FORWARDZONE },
1331 { "maintain-ixfr-base", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1332 { "max-ixfr-log-size", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1333 { "notify-source", MASTERZONE | SLAVEZONE },
1334 { "notify-source-v6", MASTERZONE | SLAVEZONE },
1335 { "transfer-source", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1336 { "transfer-source-v6", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1337 { "max-transfer-time-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1338 { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
1339 { "max-transfer-idle-in", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1340 { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
1341 { "max-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1342 { "min-retry-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1343 { "max-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1344 { "min-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1345 { "dnssec-secure-to-insecure", MASTERZONE },
1346 { "sig-re-signing-interval", MASTERZONE | SLAVEZONE },
1347 { "sig-signing-nodes", MASTERZONE | SLAVEZONE },
1348 { "sig-signing-signatures", MASTERZONE | SLAVEZONE },
1349 { "sig-signing-type", MASTERZONE | SLAVEZONE },
1350 { "sig-validity-interval", MASTERZONE | SLAVEZONE },
1351 { "signing", MASTERZONE | SLAVEZONE },
1352 { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
1353 STATICSTUBZONE | REDIRECTZONE },
1354 { "allow-update", MASTERZONE | CHECKACL },
1355 { "allow-update-forwarding", SLAVEZONE | CHECKACL },
1356 { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE | REDIRECTZONE },
1357 { "journal", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1358 { "ixfr-base", MASTERZONE | SLAVEZONE },
1359 { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
1360 { "masters", SLAVEZONE | STUBZONE | REDIRECTZONE },
1361 { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
1362 { "update-policy", MASTERZONE },
1363 { "database", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE },
1364 { "key-directory", MASTERZONE | SLAVEZONE },
1365 { "check-wildcard", MASTERZONE },
1366 { "check-mx", MASTERZONE },
1367 { "check-dup-records", MASTERZONE },
1368 { "integrity-check", MASTERZONE },
1369 { "check-mx-cname", MASTERZONE },
1370 { "check-srv-cname", MASTERZONE },
1371 { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE |
1373 { "update-check-ksk", MASTERZONE | SLAVEZONE },
1374 { "dnssec-dnskey-kskonly", MASTERZONE | SLAVEZONE },
1375 { "dnssec-loadkeys-interval", MASTERZONE | SLAVEZONE },
1376 { "auto-dnssec", MASTERZONE | SLAVEZONE },
1377 { "try-tcp-refresh", SLAVEZONE | STREDIRECTZONE },
1378 { "server-addresses", STATICSTUBZONE },
1379 { "server-names", STATICSTUBZONE },
1382 static optionstable dialups[] = {
1383 { "notify", MASTERZONE | SLAVEZONE | STREDIRECTZONE },
1384 { "notify-passive", SLAVEZONE | STREDIRECTZONE },
1385 { "refresh", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1386 { "passive", SLAVEZONE | STUBZONE | STREDIRECTZONE },
1389 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
1391 zoptions = cfg_tuple_get(zconfig, "options");
1394 cfg_map_get(config, "options", &goptions);
1397 (void)cfg_map_get(zoptions, "type", &obj);
1399 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1400 "zone '%s': type not present", znamestr);
1401 return (ISC_R_FAILURE);
1404 typestr = cfg_obj_asstring(obj);
1405 if (strcasecmp(typestr, "master") == 0)
1407 else if (strcasecmp(typestr, "slave") == 0)
1409 else if (strcasecmp(typestr, "stub") == 0)
1411 else if (strcasecmp(typestr, "static-stub") == 0)
1412 ztype = STATICSTUBZONE;
1413 else if (strcasecmp(typestr, "forward") == 0)
1414 ztype = FORWARDZONE;
1415 else if (strcasecmp(typestr, "hint") == 0)
1417 else if (strcasecmp(typestr, "delegation-only") == 0)
1418 ztype = DELEGATIONZONE;
1419 else if (strcasecmp(typestr, "redirect") == 0)
1420 ztype = REDIRECTZONE;
1422 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1423 "zone '%s': invalid type %s",
1425 return (ISC_R_FAILURE);
1428 if (ztype == REDIRECTZONE && strcmp(znamestr, ".") != 0) {
1429 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1430 "redirect zones must be called \".\"");
1431 return (ISC_R_FAILURE);
1433 obj = cfg_tuple_get(zconfig, "class");
1434 if (cfg_obj_isstring(obj)) {
1437 DE_CONST(cfg_obj_asstring(obj), r.base);
1438 r.length = strlen(r.base);
1439 result = dns_rdataclass_fromtext(&zclass, &r);
1440 if (result != ISC_R_SUCCESS) {
1441 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1442 "zone '%s': invalid class %s",
1444 return (ISC_R_FAILURE);
1446 if (zclass != defclass) {
1447 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1448 "zone '%s': class '%s' does not "
1449 "match view/default class",
1451 return (ISC_R_FAILURE);
1456 * Look for an already existing zone.
1457 * We need to make this canonical as isc_symtab_define()
1458 * deals with strings.
1460 dns_fixedname_init(&fixedname);
1461 isc_buffer_constinit(&b, znamestr, strlen(znamestr));
1462 isc_buffer_add(&b, strlen(znamestr));
1463 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1464 dns_rootname, DNS_NAME_DOWNCASE, NULL);
1465 if (tresult != ISC_R_SUCCESS) {
1466 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1467 "zone '%s': is not a valid name", znamestr);
1468 result = ISC_R_FAILURE;
1470 char namebuf[DNS_NAME_FORMATSIZE];
1472 zname = dns_fixedname_name(&fixedname);
1473 dns_name_format(zname, namebuf, sizeof(namebuf));
1474 tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 :
1475 ztype == REDIRECTZONE ? 2 : 3,
1476 symtab, "zone '%s': already exists "
1477 "previous definition: %s:%u", logctx, mctx);
1478 if (tresult != ISC_R_SUCCESS)
1480 if (dns_name_equal(zname, dns_rootname))
1485 * Check if value is zero.
1487 if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
1488 result = ISC_R_FAILURE;
1491 * Look for inappropriate options for the given zone type.
1492 * Check that ACLs expand correctly.
1494 for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1496 if ((options[i].allowed & ztype) == 0 &&
1497 cfg_map_get(zoptions, options[i].name, &obj) ==
1500 if (strcmp(options[i].name, "allow-update") != 0 ||
1501 ztype != SLAVEZONE) {
1502 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1503 "option '%s' is not allowed "
1504 "in '%s' zone '%s'",
1505 options[i].name, typestr,
1507 result = ISC_R_FAILURE;
1509 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1510 "option '%s' is not allowed "
1511 "in '%s' zone '%s'",
1512 options[i].name, typestr,
1516 if ((options[i].allowed & ztype) != 0 &&
1517 (options[i].allowed & CHECKACL) != 0) {
1519 tresult = checkacl(options[i].name, actx, zconfig,
1520 voptions, config, logctx, mctx);
1521 if (tresult != ISC_R_SUCCESS)
1528 * Master & slave zones must have a "also-notify" field.
1530 if (ztype == MASTERZONE || ztype == SLAVEZONE ) {
1532 tresult = cfg_map_get(zoptions, "also-notify", &obj);
1533 if (tresult == ISC_R_SUCCESS) {
1535 tresult = validate_masters(obj, config, &count,
1537 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1543 * Slave & stub zones must have a "masters" field.
1545 if (ztype == SLAVEZONE || ztype == STUBZONE) {
1547 if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1548 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1549 "zone '%s': missing 'masters' entry",
1551 result = ISC_R_FAILURE;
1554 tresult = validate_masters(obj, config, &count,
1556 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1558 if (tresult == ISC_R_SUCCESS && count == 0) {
1559 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1560 "zone '%s': empty 'masters' entry",
1562 result = ISC_R_FAILURE;
1568 * Master zones can't have both "allow-update" and "update-policy".
1570 if (ztype == MASTERZONE || ztype == SLAVEZONE) {
1571 isc_result_t res1, res2, res3;
1573 isc_boolean_t ddns = ISC_FALSE, signing = ISC_FALSE;
1576 res1 = cfg_map_get(zoptions, "allow-update", &obj);
1578 res2 = cfg_map_get(zoptions, "update-policy", &obj);
1579 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1580 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1581 "zone '%s': 'allow-update' is ignored "
1582 "when 'update-policy' is present",
1584 result = ISC_R_FAILURE;
1585 } else if (res2 == ISC_R_SUCCESS &&
1586 check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1587 result = ISC_R_FAILURE;
1588 ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS);
1591 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
1592 if (res1 == ISC_R_SUCCESS)
1593 signing = cfg_obj_asboolean(obj);
1597 res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
1598 if (res3 == ISC_R_SUCCESS)
1599 arg = cfg_obj_asstring(obj);
1600 if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
1601 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1602 "'auto-dnssec %s;' requires%s "
1603 "inline-signing to be configured for "
1605 (ztype == MASTERZONE) ?
1606 " dynamic DNS or" : "");
1607 result = ISC_R_FAILURE;
1609 if (strcasecmp(arg, "create") == 0) {
1610 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1611 "'auto-dnssec create;' is not "
1613 result = ISC_R_FAILURE;
1617 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
1618 if (res1 == ISC_R_SUCCESS) {
1619 isc_uint32_t type = cfg_obj_asuint32(obj);
1620 if (type < 0xff00U || type > 0xffffU)
1621 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1622 "sig-signing-type: %u out of "
1623 "range [%u..%u]", type,
1625 result = ISC_R_FAILURE;
1629 res1 = cfg_map_get(zoptions, "dnssec-dnskey-kskonly", &obj);
1630 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1631 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1632 "dnssec-dnskey-kskonly: requires "
1633 "inline-signing when used in slave zone");
1634 result = ISC_R_FAILURE;
1638 res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
1639 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1640 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1641 "dnssec-loadkeys-interval: requires "
1642 "inline-signing when used in slave zone");
1643 result = ISC_R_FAILURE;
1647 res1 = cfg_map_get(zoptions, "update-check-ksk", &obj);
1648 if (res1 == ISC_R_SUCCESS && ztype == SLAVEZONE && !signing) {
1649 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1650 "update-check-ksk: requires "
1651 "inline-signing when used in slave zone");
1652 result = ISC_R_FAILURE;
1657 * Check the excessively complicated "dialup" option.
1659 if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1660 const cfg_obj_t *dialup = NULL;
1661 (void)cfg_map_get(zoptions, "dialup", &dialup);
1662 if (dialup != NULL && cfg_obj_isstring(dialup)) {
1663 const char *str = cfg_obj_asstring(dialup);
1665 i < sizeof(dialups) / sizeof(dialups[0]);
1668 if (strcasecmp(dialups[i].name, str) != 0)
1670 if ((dialups[i].allowed & ztype) == 0) {
1671 cfg_obj_log(obj, logctx,
1673 "dialup type '%s' is not "
1676 str, typestr, znamestr);
1677 result = ISC_R_FAILURE;
1681 if (i == sizeof(dialups) / sizeof(dialups[0])) {
1682 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1683 "invalid dialup type '%s' in zone "
1684 "'%s'", str, znamestr);
1685 result = ISC_R_FAILURE;
1691 * Check that forwarding is reasonable.
1695 if (voptions != NULL)
1696 (void)cfg_map_get(voptions, "forwarders", &obj);
1698 const cfg_obj_t *options = NULL;
1699 (void)cfg_map_get(config, "options", &options);
1700 if (options != NULL)
1701 (void)cfg_map_get(options, "forwarders", &obj);
1704 if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
1705 result = ISC_R_FAILURE;
1708 * Check validity of static stub server addresses.
1711 (void)cfg_map_get(zoptions, "server-addresses", &obj);
1712 if (ztype == STATICSTUBZONE && obj != NULL) {
1713 for (element = cfg_list_first(obj);
1715 element = cfg_list_next(element))
1719 obj = cfg_listelt_value(element);
1720 sa = *cfg_obj_assockaddr(obj);
1722 if (isc_sockaddr_getport(&sa) != 0) {
1723 result = ISC_R_FAILURE;
1724 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1725 "port is not configurable for "
1726 "static stub server-addresses");
1729 isc_netaddr_fromsockaddr(&na, &sa);
1730 if (isc_netaddr_getzone(&na) != 0) {
1731 result = ISC_R_FAILURE;
1732 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1733 "scoped address is not allowed "
1735 "server-addresses");
1741 * Check validity of static stub server names.
1744 (void)cfg_map_get(zoptions, "server-names", &obj);
1745 if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
1746 for (element = cfg_list_first(obj);
1748 element = cfg_list_next(element))
1750 const char *snamestr;
1751 dns_fixedname_t fixed_sname;
1755 obj = cfg_listelt_value(element);
1756 snamestr = cfg_obj_asstring(obj);
1758 dns_fixedname_init(&fixed_sname);
1759 isc_buffer_constinit(&b2, snamestr, strlen(snamestr));
1760 isc_buffer_add(&b2, strlen(snamestr));
1761 sname = dns_fixedname_name(&fixed_sname);
1762 tresult = dns_name_fromtext(sname, &b2, dns_rootname,
1764 if (tresult != ISC_R_SUCCESS) {
1765 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1766 "server-name '%s' is not a valid "
1768 result = ISC_R_FAILURE;
1769 } else if (dns_name_issubdomain(sname, zname)) {
1770 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1771 "server-name '%s' must not be a "
1772 "subdomain of zone name '%s'",
1773 snamestr, znamestr);
1774 result = ISC_R_FAILURE;
1780 * Warn if key-directory doesn't exist
1783 tresult = cfg_map_get(zoptions, "key-directory", &obj);
1784 if (tresult == ISC_R_SUCCESS) {
1785 const char *dir = cfg_obj_asstring(obj);
1786 tresult = isc_file_isdirectory(dir);
1790 case ISC_R_FILENOTFOUND:
1791 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1792 "key-directory: '%s' does not exist",
1795 case ISC_R_INVALIDFILE:
1796 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1797 "key-directory: '%s' is not a directory",
1801 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1802 "key-directory: '%s' %s",
1803 dir, isc_result_totext(tresult));
1809 * Check various options.
1811 tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
1812 if (tresult != ISC_R_SUCCESS)
1816 * If the zone type is rbt/rbt64 then master/hint zones
1817 * require file clauses.
1818 * If inline signing is used, then slave zones require a
1819 * file clause as well
1822 tresult = cfg_map_get(zoptions, "database", &obj);
1823 if (tresult == ISC_R_NOTFOUND ||
1824 (tresult == ISC_R_SUCCESS &&
1825 (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1826 strcmp("rbt64", cfg_obj_asstring(obj)) == 0)))
1830 tresult = cfg_map_get(zoptions, "file", &obj);
1832 res1 = cfg_map_get(zoptions, "inline-signing", &obj);
1833 if ((tresult != ISC_R_SUCCESS &&
1834 (ztype == MASTERZONE || ztype == HINTZONE ||
1835 (ztype == SLAVEZONE && res1 == ISC_R_SUCCESS &&
1836 cfg_obj_asboolean(obj))))) {
1837 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1838 "zone '%s': missing 'file' entry",
1848 typedef struct keyalgorithms {
1854 bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1855 const cfg_obj_t *algobj = NULL;
1856 const cfg_obj_t *secretobj = NULL;
1857 const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1858 const char *algorithm;
1861 isc_result_t result;
1863 unsigned char secretbuf[1024];
1864 static const algorithmtable algorithms[] = {
1865 { "hmac-md5", 128 },
1866 { "hmac-md5.sig-alg.reg.int", 0 },
1867 { "hmac-md5.sig-alg.reg.int.", 0 },
1868 { "hmac-sha1", 160 },
1869 { "hmac-sha224", 224 },
1870 { "hmac-sha256", 256 },
1871 { "hmac-sha384", 384 },
1872 { "hmac-sha512", 512 },
1876 (void)cfg_map_get(key, "algorithm", &algobj);
1877 (void)cfg_map_get(key, "secret", &secretobj);
1878 if (secretobj == NULL || algobj == NULL) {
1879 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1880 "key '%s' must have both 'secret' and "
1881 "'algorithm' defined",
1883 return (ISC_R_FAILURE);
1886 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
1887 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
1888 if (result != ISC_R_SUCCESS) {
1889 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
1890 "bad secret '%s'", isc_result_totext(result));
1894 algorithm = cfg_obj_asstring(algobj);
1895 for (i = 0; algorithms[i].name != NULL; i++) {
1896 len = strlen(algorithms[i].name);
1897 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1898 (algorithm[len] == '\0' ||
1899 (algorithms[i].size != 0 && algorithm[len] == '-')))
1902 if (algorithms[i].name == NULL) {
1903 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1904 "unknown algorithm '%s'", algorithm);
1905 return (ISC_R_NOTFOUND);
1907 if (algorithm[len] == '-') {
1908 isc_uint16_t digestbits;
1909 isc_result_t result;
1910 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1911 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1912 if (result == ISC_R_RANGE ||
1913 digestbits > algorithms[i].size) {
1914 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1915 "key '%s' digest-bits too large "
1916 "[%u..%u]", keyname,
1917 algorithms[i].size / 2,
1918 algorithms[i].size);
1919 return (ISC_R_RANGE);
1921 if ((digestbits % 8) != 0) {
1922 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1923 "key '%s' digest-bits not multiple"
1925 return (ISC_R_RANGE);
1928 * Recommended minima for hmac algorithms.
1930 if ((digestbits < (algorithms[i].size / 2U) ||
1931 (digestbits < 80U)))
1932 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1933 "key '%s' digest-bits too small "
1935 algorithms[i].size/2);
1937 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1938 "key '%s': unable to parse digest-bits",
1943 return (ISC_R_SUCCESS);
1947 * Check key list for duplicates key names and that the key names
1948 * are valid domain names as these keys are used for TSIG.
1950 * Check the key contents for validity.
1953 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
1954 isc_mem_t *mctx, isc_log_t *logctx)
1956 char namebuf[DNS_NAME_FORMATSIZE];
1957 dns_fixedname_t fname;
1959 isc_result_t result = ISC_R_SUCCESS;
1960 isc_result_t tresult;
1961 const cfg_listelt_t *element;
1963 dns_fixedname_init(&fname);
1964 name = dns_fixedname_name(&fname);
1965 for (element = cfg_list_first(keys);
1967 element = cfg_list_next(element))
1969 const cfg_obj_t *key = cfg_listelt_value(element);
1970 const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
1971 isc_symvalue_t symvalue;
1975 isc_buffer_constinit(&b, keyid, strlen(keyid));
1976 isc_buffer_add(&b, strlen(keyid));
1977 tresult = dns_name_fromtext(name, &b, dns_rootname,
1979 if (tresult != ISC_R_SUCCESS) {
1980 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1981 "key '%s': bad key name", keyid);
1985 tresult = bind9_check_key(key, logctx);
1986 if (tresult != ISC_R_SUCCESS)
1989 dns_name_format(name, namebuf, sizeof(namebuf));
1990 keyname = isc_mem_strdup(mctx, namebuf);
1991 if (keyname == NULL)
1992 return (ISC_R_NOMEMORY);
1993 symvalue.as_cpointer = key;
1994 tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
1995 isc_symexists_reject);
1996 if (tresult == ISC_R_EXISTS) {
2000 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
2001 1, &symvalue) == ISC_R_SUCCESS);
2002 file = cfg_obj_file(symvalue.as_cpointer);
2003 line = cfg_obj_line(symvalue.as_cpointer);
2006 file = "<unknown file>";
2007 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2008 "key '%s': already exists "
2009 "previous definition: %s:%u",
2011 isc_mem_free(mctx, keyname);
2013 } else if (tresult != ISC_R_SUCCESS) {
2014 isc_mem_free(mctx, keyname);
2025 { "transfer-source", "transfer-source-v6" },
2026 { "notify-source", "notify-source-v6" },
2027 { "query-source", "query-source-v6" },
2032 * RNDC keys are not normalised unlike TSIG keys.
2034 * "foo." is different to "foo".
2036 static isc_boolean_t
2037 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
2038 const cfg_listelt_t *element;
2039 const cfg_obj_t *obj;
2042 if (keylist == NULL)
2045 for (element = cfg_list_first(keylist);
2047 element = cfg_list_next(element))
2049 obj = cfg_listelt_value(element);
2050 str = cfg_obj_asstring(cfg_map_getname(obj));
2051 if (!strcasecmp(str, keyname))
2058 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
2059 isc_symtab_t *symtab, isc_log_t *logctx)
2061 dns_fixedname_t fname;
2062 isc_result_t result = ISC_R_SUCCESS;
2063 isc_result_t tresult;
2064 const cfg_listelt_t *e1, *e2;
2065 const cfg_obj_t *v1, *v2, *keys;
2066 const cfg_obj_t *servers;
2067 isc_netaddr_t n1, n2;
2068 unsigned int p1, p2;
2069 const cfg_obj_t *obj;
2070 char buf[ISC_NETADDR_FORMATSIZE];
2071 char namebuf[DNS_NAME_FORMATSIZE];
2076 dns_name_t *keyname;
2079 if (voptions != NULL)
2080 (void)cfg_map_get(voptions, "server", &servers);
2081 if (servers == NULL)
2082 (void)cfg_map_get(config, "server", &servers);
2083 if (servers == NULL)
2084 return (ISC_R_SUCCESS);
2086 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
2087 v1 = cfg_listelt_value(e1);
2088 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
2090 * Check that unused bits are zero.
2092 tresult = isc_netaddr_prefixok(&n1, p1);
2093 if (tresult != ISC_R_SUCCESS) {
2094 INSIST(tresult == ISC_R_FAILURE);
2095 isc_netaddr_format(&n1, buf, sizeof(buf));
2096 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
2097 "server '%s/%u': invalid prefix "
2098 "(extra bits specified)", buf, p1);
2104 if (n1.family == AF_INET)
2105 xfr = sources[source].v6;
2107 xfr = sources[source].v4;
2108 (void)cfg_map_get(v1, xfr, &obj);
2110 isc_netaddr_format(&n1, buf, sizeof(buf));
2111 cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
2112 "server '%s/%u': %s not legal",
2114 result = ISC_R_FAILURE;
2116 } while (sources[++source].v4 != NULL);
2118 while ((e2 = cfg_list_next(e2)) != NULL) {
2119 v2 = cfg_listelt_value(e2);
2120 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
2121 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
2122 const char *file = cfg_obj_file(v1);
2123 unsigned int line = cfg_obj_line(v1);
2126 file = "<unknown file>";
2128 isc_netaddr_format(&n2, buf, sizeof(buf));
2129 cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
2130 "server '%s/%u': already exists "
2131 "previous definition: %s:%u",
2132 buf, p2, file, line);
2133 result = ISC_R_FAILURE;
2137 cfg_map_get(v1, "keys", &keys);
2140 * Normalize key name.
2142 keyval = cfg_obj_asstring(keys);
2143 dns_fixedname_init(&fname);
2144 isc_buffer_constinit(&b, keyval, strlen(keyval));
2145 isc_buffer_add(&b, strlen(keyval));
2146 keyname = dns_fixedname_name(&fname);
2147 tresult = dns_name_fromtext(keyname, &b, dns_rootname,
2149 if (tresult != ISC_R_SUCCESS) {
2150 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2151 "bad key name '%s'", keyval);
2152 result = ISC_R_FAILURE;
2155 dns_name_format(keyname, namebuf, sizeof(namebuf));
2156 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
2157 if (tresult != ISC_R_SUCCESS) {
2158 cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
2159 "unknown key '%s'", keyval);
2160 result = ISC_R_FAILURE;
2168 check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
2171 const char *keystr, *keynamestr;
2172 dns_fixedname_t fkeyname;
2173 dns_name_t *keyname;
2176 isc_result_t result = ISC_R_SUCCESS;
2177 isc_result_t tresult;
2178 isc_uint32_t flags, proto, alg;
2179 unsigned char keydata[4096];
2181 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
2182 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
2183 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
2185 dns_fixedname_init(&fkeyname);
2186 keyname = dns_fixedname_name(&fkeyname);
2187 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
2189 isc_buffer_constinit(&b, keynamestr, strlen(keynamestr));
2190 isc_buffer_add(&b, strlen(keynamestr));
2191 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
2192 if (result != ISC_R_SUCCESS) {
2193 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
2194 isc_result_totext(result));
2195 result = ISC_R_FAILURE;
2198 if (flags > 0xffff) {
2199 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2200 "flags too big: %u\n", flags);
2201 result = ISC_R_FAILURE;
2204 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2205 "protocol too big: %u\n", proto);
2206 result = ISC_R_FAILURE;
2209 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2210 "algorithm too big: %u\n", alg);
2211 result = ISC_R_FAILURE;
2215 const char *initmethod;
2216 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
2218 if (strcasecmp(initmethod, "initial-key") != 0) {
2219 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2220 "managed key '%s': "
2221 "invalid initialization method '%s'",
2222 keynamestr, initmethod);
2223 result = ISC_R_FAILURE;
2227 isc_buffer_init(&b, keydata, sizeof(keydata));
2229 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
2230 tresult = isc_base64_decodestring(keystr, &b);
2232 if (tresult != ISC_R_SUCCESS) {
2233 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2234 "%s", isc_result_totext(tresult));
2235 result = ISC_R_FAILURE;
2237 isc_buffer_usedregion(&b, &r);
2239 if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
2240 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
2241 cfg_obj_log(key, logctx, ISC_LOG_WARNING,
2242 "%s key '%s' has a weak exponent",
2243 managed ? "managed" : "trusted",
2251 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
2252 const char *viewname, dns_rdataclass_t vclass,
2253 isc_log_t *logctx, isc_mem_t *mctx)
2255 const cfg_obj_t *zones = NULL;
2256 const cfg_obj_t *keys = NULL;
2257 const cfg_listelt_t *element, *element2;
2258 isc_symtab_t *symtab = NULL;
2259 isc_result_t result = ISC_R_SUCCESS;
2260 isc_result_t tresult = ISC_R_SUCCESS;
2261 cfg_aclconfctx_t *actx = NULL;
2262 const cfg_obj_t *obj;
2263 const cfg_obj_t *options = NULL;
2264 isc_boolean_t enablednssec, enablevalidation;
2265 const char *valstr = "no";
2268 * Get global options block
2270 (void)cfg_map_get(config, "options", &options);
2273 * Check that all zone statements are syntactically correct and
2274 * there are no duplicate zones.
2276 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2277 ISC_FALSE, &symtab);
2278 if (tresult != ISC_R_SUCCESS)
2279 return (ISC_R_NOMEMORY);
2281 cfg_aclconfctx_create(mctx, &actx);
2283 if (voptions != NULL)
2284 (void)cfg_map_get(voptions, "zone", &zones);
2286 (void)cfg_map_get(config, "zone", &zones);
2288 for (element = cfg_list_first(zones);
2290 element = cfg_list_next(element))
2292 isc_result_t tresult;
2293 const cfg_obj_t *zone = cfg_listelt_value(element);
2295 tresult = check_zoneconf(zone, voptions, config, symtab,
2296 vclass, actx, logctx, mctx);
2297 if (tresult != ISC_R_SUCCESS)
2298 result = ISC_R_FAILURE;
2301 isc_symtab_destroy(&symtab);
2304 * Check that forwarding is reasonable.
2306 if (voptions == NULL) {
2307 if (options != NULL)
2308 if (check_forward(options, NULL,
2309 logctx) != ISC_R_SUCCESS)
2310 result = ISC_R_FAILURE;
2312 if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
2313 result = ISC_R_FAILURE;
2317 * Check non-zero options at the global and view levels.
2319 if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS)
2320 result = ISC_R_FAILURE;
2321 if (voptions != NULL &&check_nonzero(voptions, logctx) != ISC_R_SUCCESS)
2322 result = ISC_R_FAILURE;
2325 * Check that dual-stack-servers is reasonable.
2327 if (voptions == NULL) {
2328 if (options != NULL)
2329 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2330 result = ISC_R_FAILURE;
2332 if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
2333 result = ISC_R_FAILURE;
2337 * Check that rrset-order is reasonable.
2339 if (voptions != NULL) {
2340 if (check_order(voptions, logctx) != ISC_R_SUCCESS)
2341 result = ISC_R_FAILURE;
2345 * Check that all key statements are syntactically correct and
2346 * there are no duplicate keys.
2348 tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
2349 ISC_FALSE, &symtab);
2350 if (tresult != ISC_R_SUCCESS)
2353 (void)cfg_map_get(config, "key", &keys);
2354 tresult = check_keylist(keys, symtab, mctx, logctx);
2355 if (tresult == ISC_R_EXISTS)
2356 result = ISC_R_FAILURE;
2357 else if (tresult != ISC_R_SUCCESS) {
2362 if (voptions != NULL) {
2364 (void)cfg_map_get(voptions, "key", &keys);
2365 tresult = check_keylist(keys, symtab, mctx, logctx);
2366 if (tresult == ISC_R_EXISTS)
2367 result = ISC_R_FAILURE;
2368 else if (tresult != ISC_R_SUCCESS) {
2375 * Global servers can refer to keys in views.
2377 if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
2378 result = ISC_R_FAILURE;
2380 isc_symtab_destroy(&symtab);
2383 * Check that dnssec-enable/dnssec-validation are sensible.
2386 if (voptions != NULL)
2387 (void)cfg_map_get(voptions, "dnssec-enable", &obj);
2388 if (obj == NULL && options != NULL)
2389 (void)cfg_map_get(options, "dnssec-enable", &obj);
2391 enablednssec = ISC_TRUE;
2393 enablednssec = cfg_obj_asboolean(obj);
2396 if (voptions != NULL)
2397 (void)cfg_map_get(voptions, "dnssec-validation", &obj);
2398 if (obj == NULL && options != NULL)
2399 (void)cfg_map_get(options, "dnssec-validation", &obj);
2401 enablevalidation = enablednssec;
2403 } else if (cfg_obj_isboolean(obj)) {
2404 enablevalidation = cfg_obj_asboolean(obj);
2405 valstr = enablevalidation ? "yes" : "no";
2407 enablevalidation = ISC_TRUE;
2411 if (enablevalidation && !enablednssec)
2412 cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2413 "'dnssec-validation %s;' and 'dnssec-enable no;'",
2417 * Check trusted-keys and managed-keys.
2420 if (voptions != NULL)
2421 (void)cfg_map_get(voptions, "trusted-keys", &keys);
2423 (void)cfg_map_get(config, "trusted-keys", &keys);
2425 for (element = cfg_list_first(keys);
2427 element = cfg_list_next(element))
2429 const cfg_obj_t *keylist = cfg_listelt_value(element);
2430 for (element2 = cfg_list_first(keylist);
2432 element2 = cfg_list_next(element2)) {
2433 obj = cfg_listelt_value(element2);
2434 tresult = check_trusted_key(obj, ISC_FALSE, logctx);
2435 if (tresult != ISC_R_SUCCESS)
2441 if (voptions != NULL)
2442 (void)cfg_map_get(voptions, "managed-keys", &keys);
2444 (void)cfg_map_get(config, "managed-keys", &keys);
2446 for (element = cfg_list_first(keys);
2448 element = cfg_list_next(element))
2450 const cfg_obj_t *keylist = cfg_listelt_value(element);
2451 for (element2 = cfg_list_first(keylist);
2453 element2 = cfg_list_next(element2)) {
2454 obj = cfg_listelt_value(element2);
2455 tresult = check_trusted_key(obj, ISC_TRUE, logctx);
2456 if (tresult != ISC_R_SUCCESS)
2464 if (voptions != NULL)
2465 tresult = check_options(voptions, logctx, mctx,
2468 tresult = check_options(config, logctx, mctx,
2470 if (tresult != ISC_R_SUCCESS)
2473 tresult = check_viewacls(actx, voptions, config, logctx, mctx);
2474 if (tresult != ISC_R_SUCCESS)
2477 tresult = check_recursionacls(actx, voptions, viewname,
2478 config, logctx, mctx);
2479 if (tresult != ISC_R_SUCCESS)
2482 tresult = check_filteraaaa(actx, voptions, viewname, config,
2484 if (tresult != ISC_R_SUCCESS)
2487 tresult = check_dns64(actx, voptions, config, logctx, mctx);
2488 if (tresult != ISC_R_SUCCESS)
2493 isc_symtab_destroy(&symtab);
2495 cfg_aclconfctx_detach(&actx);
2501 default_channels[] = {
2510 bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
2513 const cfg_obj_t *categories = NULL;
2514 const cfg_obj_t *category;
2515 const cfg_obj_t *channels = NULL;
2516 const cfg_obj_t *channel;
2517 const cfg_listelt_t *element;
2518 const cfg_listelt_t *delement;
2519 const char *channelname;
2520 const char *catname;
2521 const cfg_obj_t *fileobj = NULL;
2522 const cfg_obj_t *syslogobj = NULL;
2523 const cfg_obj_t *nullobj = NULL;
2524 const cfg_obj_t *stderrobj = NULL;
2525 const cfg_obj_t *logobj = NULL;
2526 isc_result_t result = ISC_R_SUCCESS;
2527 isc_result_t tresult;
2528 isc_symtab_t *symtab = NULL;
2529 isc_symvalue_t symvalue;
2532 (void)cfg_map_get(config, "logging", &logobj);
2534 return (ISC_R_SUCCESS);
2536 result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
2537 if (result != ISC_R_SUCCESS)
2540 symvalue.as_cpointer = NULL;
2541 for (i = 0; default_channels[i] != NULL; i++) {
2542 tresult = isc_symtab_define(symtab, default_channels[i], 1,
2543 symvalue, isc_symexists_replace);
2544 if (tresult != ISC_R_SUCCESS)
2548 cfg_map_get(logobj, "channel", &channels);
2550 for (element = cfg_list_first(channels);
2552 element = cfg_list_next(element))
2554 channel = cfg_listelt_value(element);
2555 channelname = cfg_obj_asstring(cfg_map_getname(channel));
2556 fileobj = syslogobj = nullobj = stderrobj = NULL;
2557 (void)cfg_map_get(channel, "file", &fileobj);
2558 (void)cfg_map_get(channel, "syslog", &syslogobj);
2559 (void)cfg_map_get(channel, "null", &nullobj);
2560 (void)cfg_map_get(channel, "stderr", &stderrobj);
2562 if (fileobj != NULL)
2564 if (syslogobj != NULL)
2566 if (nullobj != NULL)
2568 if (stderrobj != NULL)
2571 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2572 "channel '%s': exactly one of file, syslog, "
2573 "null, and stderr must be present",
2575 result = ISC_R_FAILURE;
2577 tresult = isc_symtab_define(symtab, channelname, 1,
2578 symvalue, isc_symexists_replace);
2579 if (tresult != ISC_R_SUCCESS)
2583 cfg_map_get(logobj, "category", &categories);
2585 for (element = cfg_list_first(categories);
2587 element = cfg_list_next(element))
2589 category = cfg_listelt_value(element);
2590 catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
2591 if (isc_log_categorybyname(logctx, catname) == NULL) {
2592 cfg_obj_log(category, logctx, ISC_LOG_ERROR,
2593 "undefined category: '%s'", catname);
2594 result = ISC_R_FAILURE;
2596 channels = cfg_tuple_get(category, "destinations");
2597 for (delement = cfg_list_first(channels);
2599 delement = cfg_list_next(delement))
2601 channel = cfg_listelt_value(delement);
2602 channelname = cfg_obj_asstring(channel);
2603 tresult = isc_symtab_lookup(symtab, channelname, 1,
2605 if (tresult != ISC_R_SUCCESS) {
2606 cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
2607 "undefined channel: '%s'",
2613 isc_symtab_destroy(&symtab);
2618 bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
2621 isc_result_t result = ISC_R_SUCCESS;
2622 const cfg_obj_t *control_keylist;
2623 const cfg_listelt_t *element;
2624 const cfg_obj_t *key;
2627 control_keylist = cfg_tuple_get(control, "keys");
2628 if (cfg_obj_isvoid(control_keylist))
2629 return (ISC_R_SUCCESS);
2631 for (element = cfg_list_first(control_keylist);
2633 element = cfg_list_next(element))
2635 key = cfg_listelt_value(element);
2636 keyval = cfg_obj_asstring(key);
2638 if (!rndckey_exists(keylist, keyval)) {
2639 cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2640 "unknown key '%s'", keyval);
2641 result = ISC_R_NOTFOUND;
2648 bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
2651 isc_result_t result = ISC_R_SUCCESS, tresult;
2652 cfg_aclconfctx_t *actx = NULL;
2653 const cfg_listelt_t *element, *element2;
2654 const cfg_obj_t *allow;
2655 const cfg_obj_t *control;
2656 const cfg_obj_t *controls;
2657 const cfg_obj_t *controlslist = NULL;
2658 const cfg_obj_t *inetcontrols;
2659 const cfg_obj_t *unixcontrols;
2660 const cfg_obj_t *keylist = NULL;
2662 isc_uint32_t perm, mask;
2663 dns_acl_t *acl = NULL;
2664 isc_sockaddr_t addr;
2667 (void)cfg_map_get(config, "controls", &controlslist);
2668 if (controlslist == NULL)
2669 return (ISC_R_SUCCESS);
2671 (void)cfg_map_get(config, "key", &keylist);
2673 cfg_aclconfctx_create(mctx, &actx);
2676 * INET: Check allow clause.
2677 * UNIX: Check "perm" for sanity, check path length.
2679 for (element = cfg_list_first(controlslist);
2681 element = cfg_list_next(element)) {
2682 controls = cfg_listelt_value(element);
2683 unixcontrols = NULL;
2684 inetcontrols = NULL;
2685 (void)cfg_map_get(controls, "unix", &unixcontrols);
2686 (void)cfg_map_get(controls, "inet", &inetcontrols);
2687 for (element2 = cfg_list_first(inetcontrols);
2689 element2 = cfg_list_next(element2)) {
2690 control = cfg_listelt_value(element2);
2691 allow = cfg_tuple_get(control, "allow");
2692 tresult = cfg_acl_fromconfig(allow, config, logctx,
2693 actx, mctx, 0, &acl);
2695 dns_acl_detach(&acl);
2696 if (tresult != ISC_R_SUCCESS)
2698 tresult = bind9_check_controlskeys(control, keylist,
2700 if (tresult != ISC_R_SUCCESS)
2703 for (element2 = cfg_list_first(unixcontrols);
2705 element2 = cfg_list_next(element2)) {
2706 control = cfg_listelt_value(element2);
2707 path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
2708 tresult = isc_sockaddr_frompath(&addr, path);
2709 if (tresult == ISC_R_NOSPACE) {
2710 cfg_obj_log(control, logctx, ISC_LOG_ERROR,
2711 "unix control '%s': path too long",
2713 result = ISC_R_NOSPACE;
2715 perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
2716 for (i = 0; i < 3; i++) {
2717 #ifdef NEED_SECURE_DIRECTORY
2718 mask = (0x1 << (i*3)); /* SEARCH */
2720 mask = (0x6 << (i*3)); /* READ + WRITE */
2722 if ((perm & mask) == mask)
2726 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2727 "unix control '%s' allows access "
2728 "to everyone", path);
2729 } else if (i == 3) {
2730 cfg_obj_log(control, logctx, ISC_LOG_WARNING,
2731 "unix control '%s' allows access "
2734 tresult = bind9_check_controlskeys(control, keylist,
2736 if (tresult != ISC_R_SUCCESS)
2740 cfg_aclconfctx_detach(&actx);
2745 bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
2748 const cfg_obj_t *options = NULL;
2749 const cfg_obj_t *views = NULL;
2750 const cfg_obj_t *acls = NULL;
2751 const cfg_obj_t *kals = NULL;
2752 const cfg_obj_t *obj;
2753 const cfg_listelt_t *velement;
2754 isc_result_t result = ISC_R_SUCCESS;
2755 isc_result_t tresult;
2756 isc_symtab_t *symtab = NULL;
2758 static const char *builtin[] = { "localhost", "localnets",
2761 (void)cfg_map_get(config, "options", &options);
2763 if (options != NULL &&
2764 check_options(options, logctx, mctx,
2765 optlevel_options) != ISC_R_SUCCESS)
2766 result = ISC_R_FAILURE;
2768 if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
2769 result = ISC_R_FAILURE;
2771 if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
2772 result = ISC_R_FAILURE;
2774 if (options != NULL &&
2775 check_order(options, logctx) != ISC_R_SUCCESS)
2776 result = ISC_R_FAILURE;
2778 (void)cfg_map_get(config, "view", &views);
2780 if (views != NULL && options != NULL)
2781 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
2782 result = ISC_R_FAILURE;
2784 if (views == NULL) {
2785 if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
2786 logctx, mctx) != ISC_R_SUCCESS)
2787 result = ISC_R_FAILURE;
2789 const cfg_obj_t *zones = NULL;
2791 (void)cfg_map_get(config, "zone", &zones);
2792 if (zones != NULL) {
2793 cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
2794 "when using 'view' statements, "
2795 "all zones must be in views");
2796 result = ISC_R_FAILURE;
2800 tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
2801 if (tresult != ISC_R_SUCCESS)
2803 for (velement = cfg_list_first(views);
2805 velement = cfg_list_next(velement))
2807 const cfg_obj_t *view = cfg_listelt_value(velement);
2808 const cfg_obj_t *vname = cfg_tuple_get(view, "name");
2809 const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
2810 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
2811 dns_rdataclass_t vclass = dns_rdataclass_in;
2812 isc_result_t tresult = ISC_R_SUCCESS;
2813 const char *key = cfg_obj_asstring(vname);
2814 isc_symvalue_t symvalue;
2816 if (cfg_obj_isstring(vclassobj)) {
2819 DE_CONST(cfg_obj_asstring(vclassobj), r.base);
2820 r.length = strlen(r.base);
2821 tresult = dns_rdataclass_fromtext(&vclass, &r);
2822 if (tresult != ISC_R_SUCCESS)
2823 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
2824 "view '%s': invalid class %s",
2825 cfg_obj_asstring(vname), r.base);
2827 if (tresult == ISC_R_SUCCESS && symtab != NULL) {
2828 symvalue.as_cpointer = view;
2829 tresult = isc_symtab_define(symtab, key, vclass,
2831 isc_symexists_reject);
2832 if (tresult == ISC_R_EXISTS) {
2835 RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
2836 vclass, &symvalue) == ISC_R_SUCCESS);
2837 file = cfg_obj_file(symvalue.as_cpointer);
2838 line = cfg_obj_line(symvalue.as_cpointer);
2839 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2840 "view '%s': already exists "
2841 "previous definition: %s:%u",
2844 } else if (tresult != ISC_R_SUCCESS) {
2846 } else if ((strcasecmp(key, "_bind") == 0 &&
2847 vclass == dns_rdataclass_ch) ||
2848 (strcasecmp(key, "_default") == 0 &&
2849 vclass == dns_rdataclass_in)) {
2850 cfg_obj_log(view, logctx, ISC_LOG_ERROR,
2851 "attempt to redefine builtin view "
2853 result = ISC_R_EXISTS;
2856 if (tresult == ISC_R_SUCCESS)
2857 tresult = check_viewconf(config, voptions, key,
2858 vclass, logctx, mctx);
2859 if (tresult != ISC_R_SUCCESS)
2860 result = ISC_R_FAILURE;
2863 isc_symtab_destroy(&symtab);
2865 if (views != NULL && options != NULL) {
2867 tresult = cfg_map_get(options, "cache-file", &obj);
2868 if (tresult == ISC_R_SUCCESS) {
2869 cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2870 "'cache-file' cannot be a global "
2871 "option if views are present");
2872 result = ISC_R_FAILURE;
2876 cfg_map_get(config, "acl", &acls);
2879 const cfg_listelt_t *elt;
2880 const cfg_listelt_t *elt2;
2881 const char *aclname;
2883 for (elt = cfg_list_first(acls);
2885 elt = cfg_list_next(elt)) {
2886 const cfg_obj_t *acl = cfg_listelt_value(elt);
2887 unsigned int line = cfg_obj_line(acl);
2890 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2892 i < sizeof(builtin) / sizeof(builtin[0]);
2894 if (strcasecmp(aclname, builtin[i]) == 0) {
2895 cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
2896 "attempt to redefine "
2899 result = ISC_R_FAILURE;
2903 for (elt2 = cfg_list_next(elt);
2905 elt2 = cfg_list_next(elt2)) {
2906 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2908 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2910 if (strcasecmp(aclname, name) == 0) {
2911 const char *file = cfg_obj_file(acl);
2914 file = "<unknown file>";
2916 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2917 "attempt to redefine "
2918 "acl '%s' previous "
2919 "definition: %s:%u",
2921 result = ISC_R_FAILURE;
2927 tresult = cfg_map_get(config, "kal", &kals);
2928 if (tresult == ISC_R_SUCCESS) {
2929 const cfg_listelt_t *elt;
2930 const cfg_listelt_t *elt2;
2931 const char *aclname;
2933 for (elt = cfg_list_first(kals);
2935 elt = cfg_list_next(elt)) {
2936 const cfg_obj_t *acl = cfg_listelt_value(elt);
2938 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2940 for (elt2 = cfg_list_next(elt);
2942 elt2 = cfg_list_next(elt2)) {
2943 const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2945 name = cfg_obj_asstring(cfg_tuple_get(acl2,
2947 if (strcasecmp(aclname, name) == 0) {
2948 const char *file = cfg_obj_file(acl);
2949 unsigned int line = cfg_obj_line(acl);
2952 file = "<unknown file>";
2954 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2955 "attempt to redefine "
2956 "kal '%s' previous "
2957 "definition: %s:%u",
2959 result = ISC_R_FAILURE;