1 /* $NetBSD: check.c,v 1.12 2015/07/08 17:28:58 christos Exp $ */
4 * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2001-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
26 #include <isc/base64.h>
27 #include <isc/buffer.h>
32 #include <isc/netaddr.h>
33 #include <isc/parseint.h>
34 #include <isc/platform.h>
35 #include <isc/region.h>
36 #include <isc/result.h>
37 #include <isc/sockaddr.h>
38 #include <isc/string.h>
39 #include <isc/symtab.h>
42 #ifdef ISC_PLATFORM_USESIT
49 #ifdef HMAC_SHA256_SIT
55 #include <dns/fixedname.h>
56 #include <dns/rdataclass.h>
57 #include <dns/rdatatype.h>
58 #include <dns/secalg.h>
62 #include <isccfg/aclconf.h>
63 #include <isccfg/cfg.h>
65 #include <bind9/check.h>
68 fileexist(const cfg_obj_t
*obj
, isc_symtab_t
*symtab
, isc_boolean_t writeable
,
69 isc_log_t
*logctxlogc
);
72 freekey(char *key
, unsigned int type
, isc_symvalue_t value
, void *userarg
) {
75 isc_mem_free(userarg
, key
);
79 check_orderent(const cfg_obj_t
*ent
, isc_log_t
*logctx
) {
80 isc_result_t result
= ISC_R_SUCCESS
;
83 dns_fixedname_t fixed
;
85 dns_rdataclass_t rdclass
;
86 dns_rdatatype_t rdtype
;
90 dns_fixedname_init(&fixed
);
91 obj
= cfg_tuple_get(ent
, "class");
92 if (cfg_obj_isstring(obj
)) {
94 DE_CONST(cfg_obj_asstring(obj
), r
.base
);
95 r
.length
= strlen(r
.base
);
96 tresult
= dns_rdataclass_fromtext(&rdclass
, &r
);
97 if (tresult
!= ISC_R_SUCCESS
) {
98 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
99 "rrset-order: invalid class '%s'",
101 result
= ISC_R_FAILURE
;
105 obj
= cfg_tuple_get(ent
, "type");
106 if (cfg_obj_isstring(obj
)) {
107 DE_CONST(cfg_obj_asstring(obj
), r
.base
);
108 r
.length
= strlen(r
.base
);
109 tresult
= dns_rdatatype_fromtext(&rdtype
, &r
);
110 if (tresult
!= ISC_R_SUCCESS
) {
111 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
112 "rrset-order: invalid type '%s'",
114 result
= ISC_R_FAILURE
;
118 obj
= cfg_tuple_get(ent
, "name");
119 if (cfg_obj_isstring(obj
)) {
120 str
= cfg_obj_asstring(obj
);
121 isc_buffer_constinit(&b
, str
, strlen(str
));
122 isc_buffer_add(&b
, strlen(str
));
123 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
124 dns_rootname
, 0, NULL
);
125 if (tresult
!= ISC_R_SUCCESS
) {
126 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
127 "rrset-order: invalid name '%s'", str
);
128 result
= ISC_R_FAILURE
;
132 obj
= cfg_tuple_get(ent
, "order");
133 if (!cfg_obj_isstring(obj
) ||
134 strcasecmp("order", cfg_obj_asstring(obj
)) != 0) {
135 cfg_obj_log(ent
, logctx
, ISC_LOG_ERROR
,
136 "rrset-order: keyword 'order' missing");
137 result
= ISC_R_FAILURE
;
140 obj
= cfg_tuple_get(ent
, "ordering");
141 if (!cfg_obj_isstring(obj
)) {
142 cfg_obj_log(ent
, logctx
, ISC_LOG_ERROR
,
143 "rrset-order: missing ordering");
144 result
= ISC_R_FAILURE
;
145 } else if (strcasecmp(cfg_obj_asstring(obj
), "fixed") == 0) {
146 #if !DNS_RDATASET_FIXED
147 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
148 "rrset-order: order 'fixed' was disabled at "
151 } else if (strcasecmp(cfg_obj_asstring(obj
), "random") != 0 &&
152 strcasecmp(cfg_obj_asstring(obj
), "cyclic") != 0) {
153 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
154 "rrset-order: invalid order '%s'",
155 cfg_obj_asstring(obj
));
156 result
= ISC_R_FAILURE
;
162 check_order(const cfg_obj_t
*options
, isc_log_t
*logctx
) {
163 isc_result_t result
= ISC_R_SUCCESS
;
164 isc_result_t tresult
;
165 const cfg_listelt_t
*element
;
166 const cfg_obj_t
*obj
= NULL
;
168 if (cfg_map_get(options
, "rrset-order", &obj
) != ISC_R_SUCCESS
)
171 for (element
= cfg_list_first(obj
);
173 element
= cfg_list_next(element
))
175 tresult
= check_orderent(cfg_listelt_value(element
), logctx
);
176 if (tresult
!= ISC_R_SUCCESS
)
183 check_dual_stack(const cfg_obj_t
*options
, isc_log_t
*logctx
) {
184 const cfg_listelt_t
*element
;
185 const cfg_obj_t
*alternates
= NULL
;
186 const cfg_obj_t
*value
;
187 const cfg_obj_t
*obj
;
189 dns_fixedname_t fixed
;
192 isc_result_t result
= ISC_R_SUCCESS
;
193 isc_result_t tresult
;
195 (void)cfg_map_get(options
, "dual-stack-servers", &alternates
);
197 if (alternates
== NULL
)
198 return (ISC_R_SUCCESS
);
200 obj
= cfg_tuple_get(alternates
, "port");
201 if (cfg_obj_isuint32(obj
)) {
202 isc_uint32_t val
= cfg_obj_asuint32(obj
);
203 if (val
> ISC_UINT16_MAX
) {
204 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
205 "port '%u' out of range", val
);
206 result
= ISC_R_FAILURE
;
209 obj
= cfg_tuple_get(alternates
, "addresses");
210 for (element
= cfg_list_first(obj
);
212 element
= cfg_list_next(element
)) {
213 value
= cfg_listelt_value(element
);
214 if (cfg_obj_issockaddr(value
))
216 obj
= cfg_tuple_get(value
, "name");
217 str
= cfg_obj_asstring(obj
);
218 isc_buffer_constinit(&buffer
, str
, strlen(str
));
219 isc_buffer_add(&buffer
, strlen(str
));
220 dns_fixedname_init(&fixed
);
221 name
= dns_fixedname_name(&fixed
);
222 tresult
= dns_name_fromtext(name
, &buffer
, dns_rootname
,
224 if (tresult
!= ISC_R_SUCCESS
) {
225 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
226 "bad name '%s'", str
);
227 result
= ISC_R_FAILURE
;
229 obj
= cfg_tuple_get(value
, "port");
230 if (cfg_obj_isuint32(obj
)) {
231 isc_uint32_t val
= cfg_obj_asuint32(obj
);
232 if (val
> ISC_UINT16_MAX
) {
233 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
234 "port '%u' out of range", val
);
235 result
= ISC_R_FAILURE
;
243 check_forward(const cfg_obj_t
*options
, const cfg_obj_t
*global
,
246 const cfg_obj_t
*forward
= NULL
;
247 const cfg_obj_t
*forwarders
= NULL
;
249 (void)cfg_map_get(options
, "forward", &forward
);
250 (void)cfg_map_get(options
, "forwarders", &forwarders
);
252 if (forwarders
!= NULL
&& global
!= NULL
) {
253 const char *file
= cfg_obj_file(global
);
254 unsigned int line
= cfg_obj_line(global
);
255 cfg_obj_log(forwarders
, logctx
, ISC_LOG_ERROR
,
256 "forwarders declared in root zone and "
257 "in general configuration: %s:%u",
259 return (ISC_R_FAILURE
);
261 if (forward
!= NULL
&& forwarders
== NULL
) {
262 cfg_obj_log(forward
, logctx
, ISC_LOG_ERROR
,
263 "no matching 'forwarders' statement");
264 return (ISC_R_FAILURE
);
266 return (ISC_R_SUCCESS
);
270 disabled_algorithms(const cfg_obj_t
*disabled
, isc_log_t
*logctx
) {
271 isc_result_t result
= ISC_R_SUCCESS
;
272 isc_result_t tresult
;
273 const cfg_listelt_t
*element
;
276 dns_fixedname_t fixed
;
278 const cfg_obj_t
*obj
;
280 dns_fixedname_init(&fixed
);
281 name
= dns_fixedname_name(&fixed
);
282 obj
= cfg_tuple_get(disabled
, "name");
283 str
= cfg_obj_asstring(obj
);
284 isc_buffer_constinit(&b
, str
, strlen(str
));
285 isc_buffer_add(&b
, strlen(str
));
286 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
, 0, NULL
);
287 if (tresult
!= ISC_R_SUCCESS
) {
288 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
289 "bad domain name '%s'", str
);
293 obj
= cfg_tuple_get(disabled
, "algorithms");
295 for (element
= cfg_list_first(obj
);
297 element
= cfg_list_next(element
))
302 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element
)), r
.base
);
303 r
.length
= strlen(r
.base
);
305 tresult
= dns_secalg_fromtext(&alg
, &r
);
306 if (tresult
!= ISC_R_SUCCESS
) {
307 cfg_obj_log(cfg_listelt_value(element
), logctx
,
308 ISC_LOG_ERROR
, "invalid algorithm '%s'",
317 disabled_ds_digests(const cfg_obj_t
*disabled
, isc_log_t
*logctx
) {
318 isc_result_t result
= ISC_R_SUCCESS
;
319 isc_result_t tresult
;
320 const cfg_listelt_t
*element
;
323 dns_fixedname_t fixed
;
325 const cfg_obj_t
*obj
;
327 dns_fixedname_init(&fixed
);
328 name
= dns_fixedname_name(&fixed
);
329 obj
= cfg_tuple_get(disabled
, "name");
330 str
= cfg_obj_asstring(obj
);
331 isc_buffer_constinit(&b
, str
, strlen(str
));
332 isc_buffer_add(&b
, strlen(str
));
333 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
, 0, NULL
);
334 if (tresult
!= ISC_R_SUCCESS
) {
335 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
336 "bad domain name '%s'", str
);
340 obj
= cfg_tuple_get(disabled
, "digests");
342 for (element
= cfg_list_first(obj
);
344 element
= cfg_list_next(element
))
347 dns_dsdigest_t digest
;
349 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element
)), r
.base
);
350 r
.length
= strlen(r
.base
);
352 /* works with a numeric argument too */
353 tresult
= dns_dsdigest_fromtext(&digest
, &r
);
354 if (tresult
!= ISC_R_SUCCESS
) {
355 cfg_obj_log(cfg_listelt_value(element
), logctx
,
356 ISC_LOG_ERROR
, "invalid digest type '%s'",
365 nameexist(const cfg_obj_t
*obj
, const char *name
, int value
,
366 isc_symtab_t
*symtab
, const char *fmt
, isc_log_t
*logctx
,
373 isc_symvalue_t symvalue
;
375 key
= isc_mem_strdup(mctx
, name
);
377 return (ISC_R_NOMEMORY
);
378 symvalue
.as_cpointer
= obj
;
379 result
= isc_symtab_define(symtab
, key
, value
, symvalue
,
380 isc_symexists_reject
);
381 if (result
== ISC_R_EXISTS
) {
382 RUNTIME_CHECK(isc_symtab_lookup(symtab
, key
, value
,
383 &symvalue
) == ISC_R_SUCCESS
);
384 file
= cfg_obj_file(symvalue
.as_cpointer
);
385 line
= cfg_obj_line(symvalue
.as_cpointer
);
388 file
= "<unknown file>";
389 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
, fmt
, key
, file
, line
);
390 isc_mem_free(mctx
, key
);
391 result
= ISC_R_EXISTS
;
392 } else if (result
!= ISC_R_SUCCESS
) {
393 isc_mem_free(mctx
, key
);
399 mustbesecure(const cfg_obj_t
*secure
, isc_symtab_t
*symtab
, isc_log_t
*logctx
,
402 const cfg_obj_t
*obj
;
403 char namebuf
[DNS_NAME_FORMATSIZE
];
405 dns_fixedname_t fixed
;
408 isc_result_t result
= ISC_R_SUCCESS
;
410 dns_fixedname_init(&fixed
);
411 name
= dns_fixedname_name(&fixed
);
412 obj
= cfg_tuple_get(secure
, "name");
413 str
= cfg_obj_asstring(obj
);
414 isc_buffer_constinit(&b
, str
, strlen(str
));
415 isc_buffer_add(&b
, strlen(str
));
416 result
= dns_name_fromtext(name
, &b
, dns_rootname
, 0, NULL
);
417 if (result
!= ISC_R_SUCCESS
) {
418 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
419 "bad domain name '%s'", str
);
421 dns_name_format(name
, namebuf
, sizeof(namebuf
));
422 result
= nameexist(secure
, namebuf
, 1, symtab
,
423 "dnssec-must-be-secure '%s': already "
424 "exists previous definition: %s:%u",
431 checkacl(const char *aclname
, cfg_aclconfctx_t
*actx
, const cfg_obj_t
*zconfig
,
432 const cfg_obj_t
*voptions
, const cfg_obj_t
*config
,
433 isc_log_t
*logctx
, isc_mem_t
*mctx
)
436 const cfg_obj_t
*aclobj
= NULL
;
437 const cfg_obj_t
*options
;
438 dns_acl_t
*acl
= NULL
;
440 if (zconfig
!= NULL
) {
441 options
= cfg_tuple_get(zconfig
, "options");
442 cfg_map_get(options
, aclname
, &aclobj
);
444 if (voptions
!= NULL
&& aclobj
== NULL
)
445 cfg_map_get(voptions
, aclname
, &aclobj
);
446 if (config
!= NULL
&& aclobj
== NULL
) {
448 cfg_map_get(config
, "options", &options
);
450 cfg_map_get(options
, aclname
, &aclobj
);
453 return (ISC_R_SUCCESS
);
454 result
= cfg_acl_fromconfig(aclobj
, config
, logctx
,
455 actx
, mctx
, 0, &acl
);
457 dns_acl_detach(&acl
);
462 check_viewacls(cfg_aclconfctx_t
*actx
, const cfg_obj_t
*voptions
,
463 const cfg_obj_t
*config
, isc_log_t
*logctx
, isc_mem_t
*mctx
)
465 isc_result_t result
= ISC_R_SUCCESS
, tresult
;
468 static const char *acls
[] = { "allow-query", "allow-query-on",
469 "allow-query-cache", "allow-query-cache-on",
470 "blackhole", "match-clients", "match-destinations",
471 "sortlist", "filter-aaaa", NULL
};
473 while (acls
[i
] != NULL
) {
474 tresult
= checkacl(acls
[i
++], actx
, NULL
, voptions
, config
,
476 if (tresult
!= ISC_R_SUCCESS
)
482 static const unsigned char zeros
[16];
485 check_dns64(cfg_aclconfctx_t
*actx
, const cfg_obj_t
*voptions
,
486 const cfg_obj_t
*config
, isc_log_t
*logctx
, isc_mem_t
*mctx
)
488 isc_result_t result
= ISC_R_SUCCESS
;
489 const cfg_obj_t
*dns64
= NULL
;
490 const cfg_obj_t
*options
;
491 const cfg_listelt_t
*element
;
492 const cfg_obj_t
*map
, *obj
;
493 isc_netaddr_t na
, sa
;
494 unsigned int prefixlen
;
498 static const char *acls
[] = { "clients", "exclude", "mapped", NULL
};
500 if (voptions
!= NULL
)
501 cfg_map_get(voptions
, "dns64", &dns64
);
502 if (config
!= NULL
&& dns64
== NULL
) {
504 cfg_map_get(config
, "options", &options
);
506 cfg_map_get(options
, "dns64", &dns64
);
509 return (ISC_R_SUCCESS
);
511 for (element
= cfg_list_first(dns64
);
513 element
= cfg_list_next(element
))
515 map
= cfg_listelt_value(element
);
516 obj
= cfg_map_getname(map
);
518 cfg_obj_asnetprefix(obj
, &na
, &prefixlen
);
519 if (na
.family
!= AF_INET6
) {
520 cfg_obj_log(map
, logctx
, ISC_LOG_ERROR
,
521 "dns64 requires a IPv6 prefix");
522 result
= ISC_R_FAILURE
;
526 if (prefixlen
!= 32 && prefixlen
!= 40 && prefixlen
!= 48 &&
527 prefixlen
!= 56 && prefixlen
!= 64 && prefixlen
!= 96) {
528 cfg_obj_log(map
, logctx
, ISC_LOG_ERROR
,
529 "bad prefix length %u [32/40/48/56/64/96]",
531 result
= ISC_R_FAILURE
;
535 for (i
= 0; acls
[i
] != NULL
; i
++) {
537 (void)cfg_map_get(map
, acls
[i
], &obj
);
539 dns_acl_t
*acl
= NULL
;
540 isc_result_t tresult
;
542 tresult
= cfg_acl_fromconfig(obj
, config
,
546 dns_acl_detach(&acl
);
547 if (tresult
!= ISC_R_SUCCESS
)
553 (void)cfg_map_get(map
, "suffix", &obj
);
555 isc_netaddr_fromsockaddr(&sa
, cfg_obj_assockaddr(obj
));
556 if (sa
.family
!= AF_INET6
) {
557 cfg_obj_log(map
, logctx
, ISC_LOG_ERROR
,
558 "dns64 requires a IPv6 suffix");
559 result
= ISC_R_FAILURE
;
562 nbytes
= prefixlen
/ 8 + 4;
563 if (prefixlen
>= 32 && prefixlen
<= 64)
565 if (memcmp(sa
.type
.in6
.s6_addr
, zeros
, nbytes
) != 0) {
566 char netaddrbuf
[ISC_NETADDR_FORMATSIZE
];
567 isc_netaddr_format(&sa
, netaddrbuf
,
569 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
570 "bad suffix '%s' leading "
571 "%u octets not zeros",
573 result
= ISC_R_FAILURE
;
583 * Check allow-recursion and allow-recursion-on acls, and also log a
584 * warning if they're inconsistent with the "recursion" option.
587 check_recursionacls(cfg_aclconfctx_t
*actx
, const cfg_obj_t
*voptions
,
588 const char *viewname
, const cfg_obj_t
*config
,
589 isc_log_t
*logctx
, isc_mem_t
*mctx
)
591 const cfg_obj_t
*options
, *aclobj
, *obj
= NULL
;
592 dns_acl_t
*acl
= NULL
;
593 isc_result_t result
= ISC_R_SUCCESS
, tresult
;
594 isc_boolean_t recursion
;
595 const char *forview
= " for view ";
598 static const char *acls
[] = { "allow-recursion", "allow-recursion-on",
601 if (voptions
!= NULL
)
602 cfg_map_get(voptions
, "recursion", &obj
);
603 if (obj
== NULL
&& config
!= NULL
) {
605 cfg_map_get(config
, "options", &options
);
607 cfg_map_get(options
, "recursion", &obj
);
610 recursion
= ISC_TRUE
;
612 recursion
= cfg_obj_asboolean(obj
);
614 if (viewname
== NULL
) {
619 for (i
= 0; acls
[i
] != NULL
; i
++) {
620 aclobj
= options
= NULL
;
623 if (voptions
!= NULL
)
624 cfg_map_get(voptions
, acls
[i
], &aclobj
);
625 if (config
!= NULL
&& aclobj
== NULL
) {
627 cfg_map_get(config
, "options", &options
);
629 cfg_map_get(options
, acls
[i
], &aclobj
);
634 tresult
= cfg_acl_fromconfig(aclobj
, config
, logctx
,
635 actx
, mctx
, 0, &acl
);
637 if (tresult
!= ISC_R_SUCCESS
)
643 if (recursion
== ISC_FALSE
&& !dns_acl_isnone(acl
)) {
644 cfg_obj_log(aclobj
, logctx
, ISC_LOG_WARNING
,
645 "both \"recursion no;\" and "
647 acls
[i
], forview
, viewname
);
651 dns_acl_detach(&acl
);
658 check_filteraaaa(cfg_aclconfctx_t
*actx
, const cfg_obj_t
*voptions
,
659 const char *viewname
, const cfg_obj_t
*config
,
660 isc_log_t
*logctx
, isc_mem_t
*mctx
)
662 const cfg_obj_t
*options
, *aclobj
, *obj
;
663 dns_acl_t
*acl
= NULL
;
664 isc_result_t result
= ISC_R_SUCCESS
;
665 dns_aaaa_t filter4
, filter6
;
666 const char *forview
= " for view ";
668 if (viewname
== NULL
) {
673 aclobj
= options
= NULL
;
676 if (voptions
!= NULL
)
677 cfg_map_get(voptions
, "filter-aaaa", &aclobj
);
678 if (config
!= NULL
&& aclobj
== NULL
) {
680 cfg_map_get(config
, "options", &options
);
682 cfg_map_get(options
, "filter-aaaa", &aclobj
);
687 result
= cfg_acl_fromconfig(aclobj
, config
, logctx
,
688 actx
, mctx
, 0, &acl
);
689 if (result
!= ISC_R_SUCCESS
)
693 if (voptions
!= NULL
)
694 cfg_map_get(voptions
, "filter-aaaa-on-v4", &obj
);
695 if (obj
== NULL
&& config
!= NULL
) {
697 cfg_map_get(config
, "options", &options
);
699 cfg_map_get(options
, "filter-aaaa-on-v4", &obj
);
703 filter4
= dns_aaaa_ok
; /* default */
704 else if (cfg_obj_isboolean(obj
))
705 filter4
= cfg_obj_asboolean(obj
) ? dns_aaaa_filter
:
708 filter4
= dns_aaaa_break_dnssec
; /* break-dnssec */
711 if (voptions
!= NULL
)
712 cfg_map_get(voptions
, "filter-aaaa-on-v6", &obj
);
713 if (obj
== NULL
&& config
!= NULL
) {
715 cfg_map_get(config
, "options", &options
);
717 cfg_map_get(options
, "filter-aaaa-on-v6", &obj
);
721 filter6
= dns_aaaa_ok
; /* default */
722 else if (cfg_obj_isboolean(obj
))
723 filter6
= cfg_obj_asboolean(obj
) ? dns_aaaa_filter
:
726 filter6
= dns_aaaa_break_dnssec
; /* break-dnssec */
728 if ((filter4
!= dns_aaaa_ok
|| filter6
!= dns_aaaa_ok
) &&
731 cfg_obj_log(aclobj
, logctx
, ISC_LOG_WARNING
,
732 "\"filter-aaaa\" is 'none;' but "
733 "either filter-aaaa-on-v4 or filter-aaaa-on-v6 "
734 "is enabled%s%s", forview
, viewname
);
735 result
= ISC_R_FAILURE
;
736 } else if (filter4
== dns_aaaa_ok
&& filter6
== dns_aaaa_ok
&&
737 !dns_acl_isnone(acl
))
739 cfg_obj_log(aclobj
, logctx
, ISC_LOG_WARNING
,
740 "\"filter-aaaa\" is set but "
741 "neither filter-aaaa-on-v4 or filter-aaaa-on-v6 "
742 "is enabled%s%s", forview
, viewname
);
743 result
= ISC_R_FAILURE
;
748 dns_acl_detach(&acl
);
767 check_dscp(const cfg_obj_t
*options
, isc_log_t
*logctx
) {
768 isc_result_t result
= ISC_R_SUCCESS
;
769 const cfg_obj_t
*obj
= NULL
;
772 * Check that DSCP setting is within range
775 (void)cfg_map_get(options
, "dscp", &obj
);
777 isc_uint32_t dscp
= cfg_obj_asuint32(obj
);
779 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
780 "'dscp' out of range (0-63)");
781 result
= ISC_R_FAILURE
;
789 check_name(const char *str
) {
790 dns_fixedname_t fixed
;
792 dns_fixedname_init(&fixed
);
793 return (dns_name_fromstring(dns_fixedname_name(&fixed
), str
, 0, NULL
));
797 check_options(const cfg_obj_t
*options
, isc_log_t
*logctx
, isc_mem_t
*mctx
,
800 isc_result_t result
= ISC_R_SUCCESS
;
801 isc_result_t tresult
;
803 const cfg_obj_t
*obj
= NULL
;
804 const cfg_obj_t
*resignobj
= NULL
;
805 const cfg_listelt_t
*element
;
806 isc_symtab_t
*symtab
= NULL
;
807 dns_fixedname_t fixed
;
810 #ifdef ISC_PLATFORM_USESIT
814 static intervaltable intervals
[] = {
815 { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
816 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
817 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
818 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
819 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
820 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
821 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
822 { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
825 static const char *server_contact
[] = {
826 "empty-server", "empty-contact",
827 "dns64-server", "dns64-contact",
832 * Check that fields specified in units of time other than seconds
833 * have reasonable values.
835 for (i
= 0; i
< sizeof(intervals
) / sizeof(intervals
[0]); i
++) {
838 (void)cfg_map_get(options
, intervals
[i
].name
, &obj
);
841 val
= cfg_obj_asuint32(obj
);
842 if (val
> intervals
[i
].max
) {
843 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
844 "%s '%u' is out of range (0..%u)",
845 intervals
[i
].name
, val
,
847 result
= ISC_R_RANGE
;
848 } else if (val
> (ISC_UINT32_MAX
/ intervals
[i
].scale
)) {
849 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
850 "%s '%d' is out of range",
851 intervals
[i
].name
, val
);
852 result
= ISC_R_RANGE
;
857 cfg_map_get(options
, "max-rsa-exponent-size", &obj
);
861 val
= cfg_obj_asuint32(obj
);
862 if (val
!= 0 && (val
< 35 || val
> 4096)) {
863 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
864 "max-rsa-exponent-size '%u' is out of "
865 "range (35..4096)", val
);
866 result
= ISC_R_RANGE
;
871 cfg_map_get(options
, "sig-validity-interval", &obj
);
873 isc_uint32_t validity
, resign
= 0;
875 validity
= cfg_obj_asuint32(cfg_tuple_get(obj
, "validity"));
876 resignobj
= cfg_tuple_get(obj
, "re-sign");
877 if (!cfg_obj_isvoid(resignobj
))
878 resign
= cfg_obj_asuint32(resignobj
);
880 if (validity
> 3660 || validity
== 0) { /* 10 years */
881 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
882 "%s '%u' is out of range (1..3660)",
883 "sig-validity-interval", validity
);
884 result
= ISC_R_RANGE
;
887 if (!cfg_obj_isvoid(resignobj
)) {
888 if (resign
> 3660 || resign
== 0) { /* 10 years */
889 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
890 "%s '%u' is out of range (1..3660)",
891 "sig-validity-interval (re-sign)",
893 result
= ISC_R_RANGE
;
894 } else if ((validity
> 7 && validity
< resign
) ||
895 (validity
<= 7 && validity
* 24 < resign
)) {
896 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
897 "validity interval (%u days) "
898 "less than re-signing interval "
899 "(%u %s)", validity
, resign
,
900 (validity
> 7) ? "days" : "hours");
901 result
= ISC_R_RANGE
;
907 (void)cfg_map_get(options
, "preferred-glue", &obj
);
909 str
= cfg_obj_asstring(obj
);
910 if (strcasecmp(str
, "a") != 0 &&
911 strcasecmp(str
, "aaaa") != 0 &&
912 strcasecmp(str
, "none") != 0)
913 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
914 "preferred-glue unexpected value '%s'",
919 (void)cfg_map_get(options
, "root-delegation-only", &obj
);
921 if (!cfg_obj_isvoid(obj
)) {
922 for (element
= cfg_list_first(obj
);
924 element
= cfg_list_next(element
)) {
925 const cfg_obj_t
*exclude
;
927 exclude
= cfg_listelt_value(element
);
928 str
= cfg_obj_asstring(exclude
);
929 tresult
= check_name(str
);
930 if (tresult
!= ISC_R_SUCCESS
) {
931 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
932 "bad domain name '%s'",
941 * Set supported DNSSEC algorithms.
944 (void)cfg_map_get(options
, "disable-algorithms", &obj
);
946 for (element
= cfg_list_first(obj
);
948 element
= cfg_list_next(element
))
950 obj
= cfg_listelt_value(element
);
951 tresult
= disabled_algorithms(obj
, logctx
);
952 if (tresult
!= ISC_R_SUCCESS
)
958 * Set supported DS/DLV digest types.
961 (void)cfg_map_get(options
, "disable-ds-digests", &obj
);
963 for (element
= cfg_list_first(obj
);
965 element
= cfg_list_next(element
))
967 obj
= cfg_listelt_value(element
);
968 tresult
= disabled_ds_digests(obj
, logctx
);
969 if (tresult
!= ISC_R_SUCCESS
)
974 dns_fixedname_init(&fixed
);
975 name
= dns_fixedname_name(&fixed
);
978 * Check the DLV zone name.
981 (void)cfg_map_get(options
, "dnssec-lookaside", &obj
);
983 tresult
= isc_symtab_create(mctx
, 100, freekey
, mctx
,
985 if (tresult
!= ISC_R_SUCCESS
)
987 for (element
= cfg_list_first(obj
);
989 element
= cfg_list_next(element
))
992 const cfg_obj_t
*dlvobj
, *anchor
;
994 obj
= cfg_listelt_value(element
);
996 anchor
= cfg_tuple_get(obj
, "trust-anchor");
997 dlvobj
= cfg_tuple_get(obj
, "domain");
998 dlv
= cfg_obj_asstring(dlvobj
);
1001 * If domain is "auto" or "no" and trust anchor
1002 * is missing, skip remaining tests
1004 if (cfg_obj_isvoid(anchor
)) {
1005 if (!strcasecmp(dlv
, "no") ||
1006 !strcasecmp(dlv
, "auto"))
1010 tresult
= dns_name_fromstring(name
, dlv
, 0, NULL
);
1011 if (tresult
!= ISC_R_SUCCESS
) {
1012 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1013 "bad domain name '%s'", dlv
);
1017 if (symtab
!= NULL
) {
1018 tresult
= nameexist(obj
, dlv
, 1, symtab
,
1019 "dnssec-lookaside '%s': "
1020 "already exists previous "
1021 "definition: %s:%u",
1023 if (tresult
!= ISC_R_SUCCESS
&&
1024 result
== ISC_R_SUCCESS
)
1029 * XXXMPA to be removed when multiple lookaside
1030 * namespaces are supported.
1032 if (!dns_name_equal(dns_rootname
, name
)) {
1033 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1034 "dnssec-lookaside '%s': "
1035 "non-root not yet supported", dlv
);
1036 if (result
== ISC_R_SUCCESS
)
1037 result
= ISC_R_FAILURE
;
1040 if (!cfg_obj_isvoid(anchor
)) {
1041 dlv
= cfg_obj_asstring(anchor
);
1042 tresult
= check_name(dlv
);
1043 if (tresult
!= ISC_R_SUCCESS
) {
1044 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1045 "bad domain name '%s'",
1047 if (result
== ISC_R_SUCCESS
)
1051 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1052 "dnssec-lookaside requires "
1053 "either 'auto' or 'no', or a "
1054 "domain and trust anchor");
1055 if (result
== ISC_R_SUCCESS
)
1056 result
= ISC_R_FAILURE
;
1061 isc_symtab_destroy(&symtab
);
1065 * Check auto-dnssec at the view/options level
1068 (void)cfg_map_get(options
, "auto-dnssec", &obj
);
1070 const char *arg
= cfg_obj_asstring(obj
);
1071 if (optlevel
!= optlevel_zone
&& strcasecmp(arg
, "off") != 0) {
1072 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1073 "auto-dnssec may only be activated at the "
1075 result
= ISC_R_FAILURE
;
1080 * Check dnssec-must-be-secure.
1083 (void)cfg_map_get(options
, "dnssec-must-be-secure", &obj
);
1085 tresult
= isc_symtab_create(mctx
, 100, freekey
, mctx
,
1086 ISC_FALSE
, &symtab
);
1087 if (tresult
!= ISC_R_SUCCESS
)
1089 for (element
= cfg_list_first(obj
);
1091 element
= cfg_list_next(element
))
1093 obj
= cfg_listelt_value(element
);
1094 tresult
= mustbesecure(obj
, symtab
, logctx
, mctx
);
1095 if (tresult
!= ISC_R_SUCCESS
)
1099 isc_symtab_destroy(&symtab
);
1103 * Check server/contacts for syntactic validity.
1105 for (i
= 0; server_contact
[i
] != NULL
; i
++) {
1107 (void)cfg_map_get(options
, server_contact
[i
], &obj
);
1109 str
= cfg_obj_asstring(obj
);
1110 if (check_name(str
) != ISC_R_SUCCESS
) {
1111 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1112 "%s: invalid name '%s'",
1113 server_contact
[i
], str
);
1114 result
= ISC_R_FAILURE
;
1120 * Check empty zone configuration.
1123 (void)cfg_map_get(options
, "disable-empty-zone", &obj
);
1124 for (element
= cfg_list_first(obj
);
1126 element
= cfg_list_next(element
))
1128 obj
= cfg_listelt_value(element
);
1129 str
= cfg_obj_asstring(obj
);
1130 if (check_name(str
) != ISC_R_SUCCESS
) {
1131 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1132 "disable-empty-zone: invalid name '%s'",
1134 result
= ISC_R_FAILURE
;
1139 * Check that server-id is not too long.
1140 * 1024 bytes should be big enough.
1143 (void)cfg_map_get(options
, "server-id", &obj
);
1144 if (obj
!= NULL
&& cfg_obj_isstring(obj
) &&
1145 strlen(cfg_obj_asstring(obj
)) > 1024U) {
1146 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1147 "'server-id' too big (>1024 bytes)");
1148 result
= ISC_R_FAILURE
;
1151 tresult
= check_dscp(options
, logctx
);
1152 if (tresult
!= ISC_R_SUCCESS
)
1155 #ifdef ISC_PLATFORM_USESIT
1157 (void) cfg_map_get(options
, "sit-secret", &obj
);
1159 unsigned char secret
[32];
1161 memset(secret
, 0, sizeof(secret
));
1162 isc_buffer_init(&b
, secret
, sizeof(secret
));
1163 tresult
= isc_hex_decodestring(cfg_obj_asstring(obj
), &b
);
1164 if (tresult
== ISC_R_NOSPACE
) {
1165 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1166 "sit-secret: too long");
1167 } else if (tresult
!= ISC_R_SUCCESS
) {
1168 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1169 "sit-secret: invalid hex string");
1171 if (tresult
!= ISC_R_SUCCESS
)
1174 if (tresult
== ISC_R_SUCCESS
&&
1175 isc_buffer_usedlength(&b
) != ISC_AES128_KEYLENGTH
) {
1176 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1177 "AES sit-secret must be on 128 bits");
1178 result
= ISC_R_RANGE
;
1181 #ifdef HMAC_SHA1_SIT
1182 if (tresult
== ISC_R_SUCCESS
&&
1183 isc_buffer_usedlength(&b
) != ISC_SHA1_DIGESTLENGTH
) {
1184 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1185 "SHA1 sit-secret must be on 160 bits");
1186 result
= ISC_R_RANGE
;
1189 #ifdef HMAC_SHA256_SIT
1190 if (tresult
== ISC_R_SUCCESS
&&
1191 isc_buffer_usedlength(&b
) != ISC_SHA256_DIGESTLENGTH
) {
1192 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1193 "SHA256 sit-secret must be on 256 bits");
1194 result
= ISC_R_RANGE
;
1204 get_masters_def(const cfg_obj_t
*cctx
, const char *name
, const cfg_obj_t
**ret
) {
1205 isc_result_t result
;
1206 const cfg_obj_t
*masters
= NULL
;
1207 const cfg_listelt_t
*elt
;
1209 result
= cfg_map_get(cctx
, "masters", &masters
);
1210 if (result
!= ISC_R_SUCCESS
)
1212 for (elt
= cfg_list_first(masters
);
1214 elt
= cfg_list_next(elt
)) {
1215 const cfg_obj_t
*list
;
1216 const char *listname
;
1218 list
= cfg_listelt_value(elt
);
1219 listname
= cfg_obj_asstring(cfg_tuple_get(list
, "name"));
1221 if (strcasecmp(listname
, name
) == 0) {
1223 return (ISC_R_SUCCESS
);
1226 return (ISC_R_NOTFOUND
);
1230 validate_masters(const cfg_obj_t
*obj
, const cfg_obj_t
*config
,
1231 isc_uint32_t
*countp
, isc_log_t
*logctx
, isc_mem_t
*mctx
)
1233 isc_result_t result
= ISC_R_SUCCESS
;
1234 isc_result_t tresult
;
1235 isc_uint32_t count
= 0;
1236 isc_symtab_t
*symtab
= NULL
;
1237 isc_symvalue_t symvalue
;
1238 const cfg_listelt_t
*element
;
1239 const cfg_listelt_t
**stack
= NULL
;
1240 isc_uint32_t stackcount
= 0, pushed
= 0;
1241 const cfg_obj_t
*list
;
1243 REQUIRE(countp
!= NULL
);
1244 result
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_FALSE
, &symtab
);
1245 if (result
!= ISC_R_SUCCESS
) {
1251 list
= cfg_tuple_get(obj
, "addresses");
1252 element
= cfg_list_first(list
);
1256 element
= cfg_list_next(element
))
1258 const char *listname
;
1259 const cfg_obj_t
*addr
;
1260 const cfg_obj_t
*key
;
1262 addr
= cfg_tuple_get(cfg_listelt_value(element
),
1264 key
= cfg_tuple_get(cfg_listelt_value(element
), "key");
1266 if (cfg_obj_issockaddr(addr
)) {
1270 if (!cfg_obj_isvoid(key
)) {
1271 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
1272 "unexpected token '%s'",
1273 cfg_obj_asstring(key
));
1274 if (result
== ISC_R_SUCCESS
)
1275 result
= ISC_R_FAILURE
;
1277 listname
= cfg_obj_asstring(addr
);
1278 symvalue
.as_cpointer
= addr
;
1279 tresult
= isc_symtab_define(symtab
, listname
, 1, symvalue
,
1280 isc_symexists_reject
);
1281 if (tresult
== ISC_R_EXISTS
)
1283 tresult
= get_masters_def(config
, listname
, &obj
);
1284 if (tresult
!= ISC_R_SUCCESS
) {
1285 if (result
== ISC_R_SUCCESS
)
1287 cfg_obj_log(addr
, logctx
, ISC_LOG_ERROR
,
1288 "unable to find masters list '%s'",
1293 if (stackcount
== pushed
) {
1295 isc_uint32_t newlen
= stackcount
+ 16;
1296 size_t newsize
, oldsize
;
1298 newsize
= newlen
* sizeof(*stack
);
1299 oldsize
= stackcount
* sizeof(*stack
);
1300 new = isc_mem_get(mctx
, newsize
);
1303 if (stackcount
!= 0) {
1306 DE_CONST(stack
, ptr
);
1307 memmove(new, stack
, oldsize
);
1308 isc_mem_put(mctx
, ptr
, oldsize
);
1311 stackcount
= newlen
;
1313 stack
[pushed
++] = cfg_list_next(element
);
1317 element
= stack
[--pushed
];
1321 if (stack
!= NULL
) {
1324 DE_CONST(stack
, ptr
);
1325 isc_mem_put(mctx
, ptr
, stackcount
* sizeof(*stack
));
1327 isc_symtab_destroy(&symtab
);
1333 check_update_policy(const cfg_obj_t
*policy
, isc_log_t
*logctx
) {
1334 isc_result_t result
= ISC_R_SUCCESS
;
1335 isc_result_t tresult
;
1336 const cfg_listelt_t
*element
;
1337 const cfg_listelt_t
*element2
;
1338 dns_fixedname_t fixed
;
1342 /* Check for "update-policy local;" */
1343 if (cfg_obj_isstring(policy
) &&
1344 strcmp("local", cfg_obj_asstring(policy
)) == 0)
1345 return (ISC_R_SUCCESS
);
1347 /* Now check the grant policy */
1348 for (element
= cfg_list_first(policy
);
1350 element
= cfg_list_next(element
))
1352 const cfg_obj_t
*stmt
= cfg_listelt_value(element
);
1353 const cfg_obj_t
*identity
= cfg_tuple_get(stmt
, "identity");
1354 const cfg_obj_t
*matchtype
= cfg_tuple_get(stmt
, "matchtype");
1355 const cfg_obj_t
*dname
= cfg_tuple_get(stmt
, "name");
1356 const cfg_obj_t
*typelist
= cfg_tuple_get(stmt
, "types");
1358 dns_fixedname_init(&fixed
);
1359 str
= cfg_obj_asstring(identity
);
1360 isc_buffer_constinit(&b
, str
, strlen(str
));
1361 isc_buffer_add(&b
, strlen(str
));
1362 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
), &b
,
1363 dns_rootname
, 0, NULL
);
1364 if (tresult
!= ISC_R_SUCCESS
) {
1365 cfg_obj_log(identity
, logctx
, ISC_LOG_ERROR
,
1366 "'%s' is not a valid name", str
);
1370 if (tresult
== ISC_R_SUCCESS
&&
1371 strcasecmp(cfg_obj_asstring(matchtype
), "zonesub") != 0) {
1372 dns_fixedname_init(&fixed
);
1373 str
= cfg_obj_asstring(dname
);
1374 isc_buffer_constinit(&b
, str
, strlen(str
));
1375 isc_buffer_add(&b
, strlen(str
));
1376 tresult
= dns_name_fromtext(dns_fixedname_name(&fixed
),
1377 &b
, dns_rootname
, 0, NULL
);
1378 if (tresult
!= ISC_R_SUCCESS
) {
1379 cfg_obj_log(dname
, logctx
, ISC_LOG_ERROR
,
1380 "'%s' is not a valid name", str
);
1385 if (tresult
== ISC_R_SUCCESS
&&
1386 strcasecmp(cfg_obj_asstring(matchtype
), "wildcard") == 0 &&
1387 !dns_name_iswildcard(dns_fixedname_name(&fixed
))) {
1388 cfg_obj_log(identity
, logctx
, ISC_LOG_ERROR
,
1389 "'%s' is not a wildcard", str
);
1390 result
= ISC_R_FAILURE
;
1393 for (element2
= cfg_list_first(typelist
);
1395 element2
= cfg_list_next(element2
))
1397 const cfg_obj_t
*typeobj
;
1399 dns_rdatatype_t type
;
1401 typeobj
= cfg_listelt_value(element2
);
1402 DE_CONST(cfg_obj_asstring(typeobj
), r
.base
);
1403 r
.length
= strlen(r
.base
);
1405 tresult
= dns_rdatatype_fromtext(&type
, &r
);
1406 if (tresult
!= ISC_R_SUCCESS
) {
1407 cfg_obj_log(typeobj
, logctx
, ISC_LOG_ERROR
,
1408 "'%s' is not a valid type", r
.base
);
1416 #define MASTERZONE 1
1420 #define FORWARDZONE 16
1421 #define DELEGATIONZONE 32
1422 #define STATICSTUBZONE 64
1423 #define REDIRECTZONE 128
1424 #define STREDIRECTZONE 0 /* Set to REDIRECTZONE to allow xfr-in. */
1425 #define CHECKACL 512
1433 check_nonzero(const cfg_obj_t
*options
, isc_log_t
*logctx
) {
1434 isc_result_t result
= ISC_R_SUCCESS
;
1435 const cfg_obj_t
*obj
= NULL
;
1438 static const char *nonzero
[] = { "max-retry-time", "min-retry-time",
1439 "max-refresh-time", "min-refresh-time" };
1441 * Check if value is zero.
1443 for (i
= 0; i
< sizeof(nonzero
) / sizeof(nonzero
[0]); i
++) {
1445 if (cfg_map_get(options
, nonzero
[i
], &obj
) == ISC_R_SUCCESS
&&
1446 cfg_obj_asuint32(obj
) == 0) {
1447 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1448 "'%s' must not be zero", nonzero
[i
]);
1449 result
= ISC_R_FAILURE
;
1456 check_zoneconf(const cfg_obj_t
*zconfig
, const cfg_obj_t
*voptions
,
1457 const cfg_obj_t
*config
, isc_symtab_t
*symtab
,
1458 isc_symtab_t
*files
, dns_rdataclass_t defclass
,
1459 cfg_aclconfctx_t
*actx
, isc_log_t
*logctx
, isc_mem_t
*mctx
)
1461 const char *znamestr
;
1462 const char *typestr
;
1464 const cfg_obj_t
*zoptions
, *goptions
= NULL
;
1465 const cfg_obj_t
*obj
= NULL
;
1466 isc_result_t result
= ISC_R_SUCCESS
;
1467 isc_result_t tresult
;
1469 dns_rdataclass_t zclass
;
1470 dns_fixedname_t fixedname
;
1471 dns_name_t
*zname
= NULL
;
1473 isc_boolean_t root
= ISC_FALSE
;
1474 const cfg_listelt_t
*element
;
1476 dns_masterformat_t masterformat
;
1477 isc_boolean_t ddns
= ISC_FALSE
;
1479 static optionstable options
[] = {
1480 { "allow-notify", SLAVEZONE
| CHECKACL
},
1481 { "allow-query", MASTERZONE
| SLAVEZONE
| STUBZONE
| REDIRECTZONE
|
1482 CHECKACL
| STATICSTUBZONE
},
1483 { "allow-transfer", MASTERZONE
| SLAVEZONE
| CHECKACL
},
1484 { "allow-update", MASTERZONE
| CHECKACL
},
1485 { "allow-update-forwarding", SLAVEZONE
| CHECKACL
},
1486 { "also-notify", MASTERZONE
| SLAVEZONE
},
1487 { "auto-dnssec", MASTERZONE
| SLAVEZONE
},
1488 { "check-dup-records", MASTERZONE
},
1489 { "check-mx", MASTERZONE
},
1490 { "check-mx-cname", MASTERZONE
},
1491 { "check-srv-cname", MASTERZONE
},
1492 { "check-wildcard", MASTERZONE
},
1493 { "database", MASTERZONE
| SLAVEZONE
| STUBZONE
| REDIRECTZONE
},
1494 { "delegation-only", HINTZONE
| STUBZONE
| FORWARDZONE
|
1496 { "dialup", MASTERZONE
| SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1497 { "dnssec-dnskey-kskonly", MASTERZONE
| SLAVEZONE
},
1498 { "dnssec-loadkeys-interval", MASTERZONE
| SLAVEZONE
},
1499 { "dnssec-secure-to-insecure", MASTERZONE
},
1500 { "file", MASTERZONE
| SLAVEZONE
| STUBZONE
| HINTZONE
| REDIRECTZONE
},
1501 { "forward", MASTERZONE
| SLAVEZONE
| STUBZONE
| STATICSTUBZONE
|
1503 { "forwarders", MASTERZONE
| SLAVEZONE
| STUBZONE
| STATICSTUBZONE
|
1505 { "integrity-check", MASTERZONE
},
1506 { "ixfr-base", MASTERZONE
| SLAVEZONE
},
1507 { "ixfr-tmp-file", MASTERZONE
| SLAVEZONE
},
1508 { "journal", MASTERZONE
| SLAVEZONE
| STREDIRECTZONE
},
1509 { "key-directory", MASTERZONE
| SLAVEZONE
},
1510 { "maintain-ixfr-base", MASTERZONE
| SLAVEZONE
| STREDIRECTZONE
},
1511 { "masterfile-format", MASTERZONE
| SLAVEZONE
| STUBZONE
|
1513 { "masters", SLAVEZONE
| STUBZONE
| REDIRECTZONE
},
1514 { "max-ixfr-log-size", MASTERZONE
| SLAVEZONE
| STREDIRECTZONE
},
1515 { "max-refresh-time", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1516 { "max-retry-time", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1517 { "max-transfer-idle-in", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1518 { "max-transfer-idle-out", MASTERZONE
| SLAVEZONE
},
1519 { "max-transfer-time-in", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1520 { "max-transfer-time-out", MASTERZONE
| SLAVEZONE
},
1521 { "max-zone-ttl", MASTERZONE
| REDIRECTZONE
},
1522 { "min-refresh-time", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1523 { "min-retry-time", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1524 { "notify", MASTERZONE
| SLAVEZONE
},
1525 { "notify-source", MASTERZONE
| SLAVEZONE
},
1526 { "notify-source-v6", MASTERZONE
| SLAVEZONE
},
1527 { "pubkey", MASTERZONE
| SLAVEZONE
| STUBZONE
},
1528 { "request-ixfr", SLAVEZONE
| REDIRECTZONE
},
1529 { "server-addresses", STATICSTUBZONE
},
1530 { "server-names", STATICSTUBZONE
},
1531 { "sig-re-signing-interval", MASTERZONE
| SLAVEZONE
},
1532 { "sig-signing-nodes", MASTERZONE
| SLAVEZONE
},
1533 { "sig-signing-signatures", MASTERZONE
| SLAVEZONE
},
1534 { "sig-signing-type", MASTERZONE
| SLAVEZONE
},
1535 { "sig-validity-interval", MASTERZONE
| SLAVEZONE
},
1536 { "signing", MASTERZONE
| SLAVEZONE
},
1537 { "transfer-source", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1538 { "transfer-source-v6", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1539 { "try-tcp-refresh", SLAVEZONE
| STREDIRECTZONE
},
1540 { "update-check-ksk", MASTERZONE
| SLAVEZONE
},
1541 { "update-policy", MASTERZONE
},
1542 { "zone-statistics", MASTERZONE
| SLAVEZONE
| STUBZONE
|
1543 STATICSTUBZONE
| REDIRECTZONE
},
1546 static optionstable dialups
[] = {
1547 { "notify", MASTERZONE
| SLAVEZONE
| STREDIRECTZONE
},
1548 { "notify-passive", SLAVEZONE
| STREDIRECTZONE
},
1549 { "refresh", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1550 { "passive", SLAVEZONE
| STUBZONE
| STREDIRECTZONE
},
1553 znamestr
= cfg_obj_asstring(cfg_tuple_get(zconfig
, "name"));
1555 zoptions
= cfg_tuple_get(zconfig
, "options");
1558 cfg_map_get(config
, "options", &goptions
);
1561 (void)cfg_map_get(zoptions
, "in-view", &obj
);
1563 const cfg_obj_t
*fwd
= NULL
;
1564 unsigned int maxopts
= 1;
1565 (void)cfg_map_get(zoptions
, "forward", &fwd
);
1569 (void)cfg_map_get(zoptions
, "forwarders", &fwd
);
1572 if (cfg_map_count(zoptions
) > maxopts
) {
1573 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1574 "zone '%s': 'in-view' used "
1575 "with incompatible zone options",
1577 return (ISC_R_FAILURE
);
1579 return (ISC_R_SUCCESS
);
1583 (void)cfg_map_get(zoptions
, "type", &obj
);
1585 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1586 "zone '%s': type not present", znamestr
);
1587 return (ISC_R_FAILURE
);
1590 typestr
= cfg_obj_asstring(obj
);
1591 if (strcasecmp(typestr
, "master") == 0)
1593 else if (strcasecmp(typestr
, "slave") == 0)
1595 else if (strcasecmp(typestr
, "stub") == 0)
1597 else if (strcasecmp(typestr
, "static-stub") == 0)
1598 ztype
= STATICSTUBZONE
;
1599 else if (strcasecmp(typestr
, "forward") == 0)
1600 ztype
= FORWARDZONE
;
1601 else if (strcasecmp(typestr
, "hint") == 0)
1603 else if (strcasecmp(typestr
, "delegation-only") == 0)
1604 ztype
= DELEGATIONZONE
;
1605 else if (strcasecmp(typestr
, "redirect") == 0)
1606 ztype
= REDIRECTZONE
;
1608 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1609 "zone '%s': invalid type %s",
1611 return (ISC_R_FAILURE
);
1614 if (ztype
== REDIRECTZONE
&& strcmp(znamestr
, ".") != 0) {
1615 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1616 "redirect zones must be called \".\"");
1617 return (ISC_R_FAILURE
);
1619 obj
= cfg_tuple_get(zconfig
, "class");
1620 if (cfg_obj_isstring(obj
)) {
1623 DE_CONST(cfg_obj_asstring(obj
), r
.base
);
1624 r
.length
= strlen(r
.base
);
1625 result
= dns_rdataclass_fromtext(&zclass
, &r
);
1626 if (result
!= ISC_R_SUCCESS
) {
1627 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1628 "zone '%s': invalid class %s",
1630 return (ISC_R_FAILURE
);
1632 if (zclass
!= defclass
) {
1633 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1634 "zone '%s': class '%s' does not "
1635 "match view/default class",
1637 return (ISC_R_FAILURE
);
1642 * Look for an already existing zone.
1643 * We need to make this canonical as isc_symtab_define()
1644 * deals with strings.
1646 dns_fixedname_init(&fixedname
);
1647 isc_buffer_constinit(&b
, znamestr
, strlen(znamestr
));
1648 isc_buffer_add(&b
, strlen(znamestr
));
1649 tresult
= dns_name_fromtext(dns_fixedname_name(&fixedname
), &b
,
1650 dns_rootname
, DNS_NAME_DOWNCASE
, NULL
);
1651 if (tresult
!= ISC_R_SUCCESS
) {
1652 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1653 "zone '%s': is not a valid name", znamestr
);
1654 result
= ISC_R_FAILURE
;
1656 char namebuf
[DNS_NAME_FORMATSIZE
];
1658 zname
= dns_fixedname_name(&fixedname
);
1659 dns_name_format(zname
, namebuf
, sizeof(namebuf
));
1660 tresult
= nameexist(zconfig
, namebuf
, ztype
== HINTZONE
? 1 :
1661 ztype
== REDIRECTZONE
? 2 : 3,
1662 symtab
, "zone '%s': already exists "
1663 "previous definition: %s:%u", logctx
, mctx
);
1664 if (tresult
!= ISC_R_SUCCESS
)
1666 if (dns_name_equal(zname
, dns_rootname
))
1671 * Check if value is zero.
1673 if (check_nonzero(zoptions
, logctx
) != ISC_R_SUCCESS
)
1674 result
= ISC_R_FAILURE
;
1677 * Look for inappropriate options for the given zone type.
1678 * Check that ACLs expand correctly.
1680 for (i
= 0; i
< sizeof(options
) / sizeof(options
[0]); i
++) {
1682 if ((options
[i
].allowed
& ztype
) == 0 &&
1683 cfg_map_get(zoptions
, options
[i
].name
, &obj
) ==
1686 if (strcmp(options
[i
].name
, "allow-update") != 0 ||
1687 ztype
!= SLAVEZONE
) {
1688 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1689 "option '%s' is not allowed "
1690 "in '%s' zone '%s'",
1691 options
[i
].name
, typestr
,
1693 result
= ISC_R_FAILURE
;
1695 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
1696 "option '%s' is not allowed "
1697 "in '%s' zone '%s'",
1698 options
[i
].name
, typestr
,
1702 if ((options
[i
].allowed
& ztype
) != 0 &&
1703 (options
[i
].allowed
& CHECKACL
) != 0) {
1705 tresult
= checkacl(options
[i
].name
, actx
, zconfig
,
1706 voptions
, config
, logctx
, mctx
);
1707 if (tresult
!= ISC_R_SUCCESS
)
1714 * Master & slave zones may have an "also-notify" field, but
1715 * shouldn't if notify is disabled.
1717 if (ztype
== MASTERZONE
|| ztype
== SLAVEZONE
) {
1718 isc_boolean_t donotify
= ISC_TRUE
;
1721 tresult
= cfg_map_get(zoptions
, "notify", &obj
);
1722 if (tresult
!= ISC_R_SUCCESS
&& voptions
!= NULL
)
1723 tresult
= cfg_map_get(voptions
, "notify", &obj
);
1724 if (tresult
!= ISC_R_SUCCESS
&& goptions
!= NULL
)
1725 tresult
= cfg_map_get(goptions
, "notify", &obj
);
1726 if (tresult
== ISC_R_SUCCESS
) {
1727 if (cfg_obj_isboolean(obj
))
1728 donotify
= cfg_obj_asboolean(obj
);
1730 const char *notifystr
= cfg_obj_asstring(obj
);
1731 if (ztype
!= MASTERZONE
&&
1732 strcasecmp(notifystr
, "master-only") == 0)
1733 donotify
= ISC_FALSE
;
1738 tresult
= cfg_map_get(zoptions
, "also-notify", &obj
);
1739 if (tresult
== ISC_R_SUCCESS
&& !donotify
) {
1740 cfg_obj_log(zoptions
, logctx
, ISC_LOG_WARNING
,
1741 "zone '%s': 'also-notify' set but "
1742 "'notify' is disabled", znamestr
);
1743 } else if (tresult
== ISC_R_SUCCESS
) {
1745 tresult
= validate_masters(obj
, config
, &count
,
1747 if (tresult
!= ISC_R_SUCCESS
&& result
== ISC_R_SUCCESS
)
1753 * Slave & stub zones must have a "masters" field.
1755 if (ztype
== SLAVEZONE
|| ztype
== STUBZONE
) {
1757 if (cfg_map_get(zoptions
, "masters", &obj
) != ISC_R_SUCCESS
) {
1758 cfg_obj_log(zoptions
, logctx
, ISC_LOG_ERROR
,
1759 "zone '%s': missing 'masters' entry",
1761 result
= ISC_R_FAILURE
;
1764 tresult
= validate_masters(obj
, config
, &count
,
1766 if (tresult
!= ISC_R_SUCCESS
&& result
== ISC_R_SUCCESS
)
1768 if (tresult
== ISC_R_SUCCESS
&& count
== 0) {
1769 cfg_obj_log(zoptions
, logctx
, ISC_LOG_ERROR
,
1770 "zone '%s': empty 'masters' entry",
1772 result
= ISC_R_FAILURE
;
1778 * Master zones can't have both "allow-update" and "update-policy".
1780 if (ztype
== MASTERZONE
|| ztype
== SLAVEZONE
) {
1781 isc_boolean_t signing
= ISC_FALSE
;
1782 isc_result_t res1
, res2
, res3
;
1783 const cfg_obj_t
*au
= NULL
;
1787 res1
= cfg_map_get(zoptions
, "allow-update", &au
);
1789 res2
= cfg_map_get(zoptions
, "update-policy", &obj
);
1790 if (res1
== ISC_R_SUCCESS
&& res2
== ISC_R_SUCCESS
) {
1791 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1792 "zone '%s': 'allow-update' is ignored "
1793 "when 'update-policy' is present",
1795 result
= ISC_R_FAILURE
;
1796 } else if (res2
== ISC_R_SUCCESS
) {
1797 res3
= check_update_policy(obj
, logctx
);
1798 if (res3
!= ISC_R_SUCCESS
)
1799 result
= ISC_R_FAILURE
;
1803 * To determine whether auto-dnssec is allowed,
1804 * we should also check for allow-update at the
1805 * view and options levels.
1807 if (res1
!= ISC_R_SUCCESS
&& voptions
!= NULL
)
1808 res1
= cfg_map_get(voptions
, "allow-update", &au
);
1809 if (res1
!= ISC_R_SUCCESS
&& goptions
!= NULL
)
1810 res1
= cfg_map_get(goptions
, "allow-update", &au
);
1812 if (res2
== ISC_R_SUCCESS
)
1814 else if (res1
== ISC_R_SUCCESS
) {
1815 dns_acl_t
*acl
= NULL
;
1816 res1
= cfg_acl_fromconfig(au
, config
, logctx
,
1817 actx
, mctx
, 0, &acl
);
1818 if (res1
!= ISC_R_SUCCESS
) {
1819 cfg_obj_log(au
, logctx
, ISC_LOG_ERROR
,
1820 "acl expansion failed: %s",
1821 isc_result_totext(result
));
1822 result
= ISC_R_FAILURE
;
1823 } else if (acl
!= NULL
) {
1824 if (!dns_acl_isnone(acl
))
1826 dns_acl_detach(&acl
);
1831 res1
= cfg_map_get(zoptions
, "inline-signing", &obj
);
1832 if (res1
== ISC_R_SUCCESS
)
1833 signing
= cfg_obj_asboolean(obj
);
1837 res3
= cfg_map_get(zoptions
, "auto-dnssec", &obj
);
1838 if (res3
== ISC_R_SUCCESS
)
1839 arg
= cfg_obj_asstring(obj
);
1840 if (strcasecmp(arg
, "off") != 0 && !ddns
&& !signing
) {
1841 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1842 "'auto-dnssec %s;' requires%s "
1843 "inline-signing to be configured for "
1845 (ztype
== MASTERZONE
) ?
1846 " dynamic DNS or" : "");
1847 result
= ISC_R_FAILURE
;
1851 res1
= cfg_map_get(zoptions
, "sig-signing-type", &obj
);
1852 if (res1
== ISC_R_SUCCESS
) {
1853 isc_uint32_t type
= cfg_obj_asuint32(obj
);
1854 if (type
< 0xff00U
|| type
> 0xffffU
)
1855 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1856 "sig-signing-type: %u out of "
1857 "range [%u..%u]", type
,
1859 result
= ISC_R_FAILURE
;
1863 res1
= cfg_map_get(zoptions
, "dnssec-dnskey-kskonly", &obj
);
1864 if (res1
== ISC_R_SUCCESS
&& ztype
== SLAVEZONE
&& !signing
) {
1865 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1866 "dnssec-dnskey-kskonly: requires "
1867 "inline-signing when used in slave zone");
1868 result
= ISC_R_FAILURE
;
1872 res1
= cfg_map_get(zoptions
, "dnssec-loadkeys-interval", &obj
);
1873 if (res1
== ISC_R_SUCCESS
&& ztype
== SLAVEZONE
&& !signing
) {
1874 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1875 "dnssec-loadkeys-interval: requires "
1876 "inline-signing when used in slave zone");
1877 result
= ISC_R_FAILURE
;
1881 res1
= cfg_map_get(zoptions
, "update-check-ksk", &obj
);
1882 if (res1
== ISC_R_SUCCESS
&& ztype
== SLAVEZONE
&& !signing
) {
1883 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1884 "update-check-ksk: requires "
1885 "inline-signing when used in slave zone");
1886 result
= ISC_R_FAILURE
;
1891 * Check the excessively complicated "dialup" option.
1893 if (ztype
== MASTERZONE
|| ztype
== SLAVEZONE
|| ztype
== STUBZONE
) {
1894 const cfg_obj_t
*dialup
= NULL
;
1895 (void)cfg_map_get(zoptions
, "dialup", &dialup
);
1896 if (dialup
!= NULL
&& cfg_obj_isstring(dialup
)) {
1897 const char *str
= cfg_obj_asstring(dialup
);
1899 i
< sizeof(dialups
) / sizeof(dialups
[0]);
1902 if (strcasecmp(dialups
[i
].name
, str
) != 0)
1904 if ((dialups
[i
].allowed
& ztype
) == 0) {
1905 cfg_obj_log(obj
, logctx
,
1907 "dialup type '%s' is not "
1910 str
, typestr
, znamestr
);
1911 result
= ISC_R_FAILURE
;
1915 if (i
== sizeof(dialups
) / sizeof(dialups
[0])) {
1916 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1917 "invalid dialup type '%s' in zone "
1918 "'%s'", str
, znamestr
);
1919 result
= ISC_R_FAILURE
;
1925 * Check that forwarding is reasonable.
1929 if (voptions
!= NULL
)
1930 (void)cfg_map_get(voptions
, "forwarders", &obj
);
1931 if (obj
== NULL
&& goptions
!= NULL
)
1932 (void)cfg_map_get(goptions
, "forwarders", &obj
);
1934 if (check_forward(zoptions
, obj
, logctx
) != ISC_R_SUCCESS
)
1935 result
= ISC_R_FAILURE
;
1938 * Check validity of static stub server addresses.
1941 (void)cfg_map_get(zoptions
, "server-addresses", &obj
);
1942 if (ztype
== STATICSTUBZONE
&& obj
!= NULL
) {
1943 for (element
= cfg_list_first(obj
);
1945 element
= cfg_list_next(element
))
1949 obj
= cfg_listelt_value(element
);
1950 sa
= *cfg_obj_assockaddr(obj
);
1952 if (isc_sockaddr_getport(&sa
) != 0) {
1953 result
= ISC_R_FAILURE
;
1954 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1955 "port is not configurable for "
1956 "static stub server-addresses");
1959 isc_netaddr_fromsockaddr(&na
, &sa
);
1960 if (isc_netaddr_getzone(&na
) != 0) {
1961 result
= ISC_R_FAILURE
;
1962 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
1963 "scoped address is not allowed "
1965 "server-addresses");
1971 * Check validity of static stub server names.
1974 (void)cfg_map_get(zoptions
, "server-names", &obj
);
1975 if (zname
!= NULL
&& ztype
== STATICSTUBZONE
&& obj
!= NULL
) {
1976 for (element
= cfg_list_first(obj
);
1978 element
= cfg_list_next(element
))
1980 const char *snamestr
;
1981 dns_fixedname_t fixed_sname
;
1985 obj
= cfg_listelt_value(element
);
1986 snamestr
= cfg_obj_asstring(obj
);
1988 dns_fixedname_init(&fixed_sname
);
1989 isc_buffer_constinit(&b2
, snamestr
, strlen(snamestr
));
1990 isc_buffer_add(&b2
, strlen(snamestr
));
1991 sname
= dns_fixedname_name(&fixed_sname
);
1992 tresult
= dns_name_fromtext(sname
, &b2
, dns_rootname
,
1994 if (tresult
!= ISC_R_SUCCESS
) {
1995 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
1996 "server-name '%s' is not a valid "
1998 result
= ISC_R_FAILURE
;
1999 } else if (dns_name_issubdomain(sname
, zname
)) {
2000 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
2001 "server-name '%s' must not be a "
2002 "subdomain of zone name '%s'",
2003 snamestr
, znamestr
);
2004 result
= ISC_R_FAILURE
;
2011 * Check that max-zone-ttl isn't used with masterfile-format map
2013 masterformat
= dns_masterformat_text
;
2015 (void)cfg_map_get(zoptions
, "masterfile-format", &obj
);
2017 const char *masterformatstr
= cfg_obj_asstring(obj
);
2018 if (strcasecmp(masterformatstr
, "text") == 0)
2019 masterformat
= dns_masterformat_text
;
2020 else if (strcasecmp(masterformatstr
, "raw") == 0)
2021 masterformat
= dns_masterformat_raw
;
2022 else if (strcasecmp(masterformatstr
, "map") == 0)
2023 masterformat
= dns_masterformat_map
;
2028 if (masterformat
== dns_masterformat_map
) {
2030 (void)cfg_map_get(zoptions
, "max-zone-ttl", &obj
);
2031 if (obj
== NULL
&& voptions
!= NULL
)
2032 (void)cfg_map_get(voptions
, "max-zone-ttl", &obj
);
2033 if (obj
== NULL
&& goptions
!=NULL
)
2034 (void)cfg_map_get(goptions
, "max-zone-ttl", &obj
);
2036 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
2037 "zone '%s': 'max-zone-ttl' is not "
2038 "compatible with 'masterfile-format map'",
2040 result
= ISC_R_FAILURE
;
2045 * Warn if key-directory doesn't exist
2048 tresult
= cfg_map_get(zoptions
, "key-directory", &obj
);
2049 if (tresult
== ISC_R_SUCCESS
) {
2050 const char *dir
= cfg_obj_asstring(obj
);
2051 tresult
= isc_file_isdirectory(dir
);
2055 case ISC_R_FILENOTFOUND
:
2056 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
2057 "key-directory: '%s' does not exist",
2060 case ISC_R_INVALIDFILE
:
2061 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
2062 "key-directory: '%s' is not a directory",
2066 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
2067 "key-directory: '%s' %s",
2068 dir
, isc_result_totext(tresult
));
2074 * Check various options.
2076 tresult
= check_options(zoptions
, logctx
, mctx
, optlevel_zone
);
2077 if (tresult
!= ISC_R_SUCCESS
)
2081 * If the zone type is rbt/rbt64 then master/hint zones
2082 * require file clauses.
2083 * If inline signing is used, then slave zones require a
2084 * file clause as well
2088 tresult
= cfg_map_get(zoptions
, "dlz", &obj
);
2089 if (tresult
== ISC_R_SUCCESS
)
2093 tresult
= cfg_map_get(zoptions
, "database", &obj
);
2094 if (dlz
&& tresult
== ISC_R_SUCCESS
) {
2095 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
2096 "zone '%s': cannot specify both 'dlz' "
2097 "and 'database'", znamestr
);
2098 result
= ISC_R_FAILURE
;
2100 (tresult
== ISC_R_NOTFOUND
||
2101 (tresult
== ISC_R_SUCCESS
&&
2102 (strcmp("rbt", cfg_obj_asstring(obj
)) == 0 ||
2103 strcmp("rbt64", cfg_obj_asstring(obj
)) == 0))))
2106 const cfg_obj_t
*fileobj
= NULL
;
2107 tresult
= cfg_map_get(zoptions
, "file", &fileobj
);
2109 res1
= cfg_map_get(zoptions
, "inline-signing", &obj
);
2110 if ((tresult
!= ISC_R_SUCCESS
&&
2111 (ztype
== MASTERZONE
|| ztype
== HINTZONE
||
2112 (ztype
== SLAVEZONE
&& res1
== ISC_R_SUCCESS
&&
2113 cfg_obj_asboolean(obj
))))) {
2114 cfg_obj_log(zconfig
, logctx
, ISC_LOG_ERROR
,
2115 "zone '%s': missing 'file' entry",
2118 } else if (tresult
== ISC_R_SUCCESS
&&
2119 (ztype
== SLAVEZONE
|| ddns
)) {
2120 tresult
= fileexist(fileobj
, files
, ISC_TRUE
, logctx
);
2121 if (tresult
!= ISC_R_SUCCESS
)
2123 } else if (tresult
== ISC_R_SUCCESS
&&
2124 (ztype
== MASTERZONE
|| ztype
== HINTZONE
)) {
2125 tresult
= fileexist(fileobj
, files
, ISC_FALSE
, logctx
);
2126 if (tresult
!= ISC_R_SUCCESS
)
2135 typedef struct keyalgorithms
{
2141 bind9_check_key(const cfg_obj_t
*key
, isc_log_t
*logctx
) {
2142 const cfg_obj_t
*algobj
= NULL
;
2143 const cfg_obj_t
*secretobj
= NULL
;
2144 const char *keyname
= cfg_obj_asstring(cfg_map_getname(key
));
2145 const char *algorithm
;
2148 isc_result_t result
;
2150 unsigned char secretbuf
[1024];
2151 static const algorithmtable algorithms
[] = {
2152 { "hmac-md5", 128 },
2153 { "hmac-md5.sig-alg.reg.int", 0 },
2154 { "hmac-md5.sig-alg.reg.int.", 0 },
2155 { "hmac-sha1", 160 },
2156 { "hmac-sha224", 224 },
2157 { "hmac-sha256", 256 },
2158 { "hmac-sha384", 384 },
2159 { "hmac-sha512", 512 },
2163 (void)cfg_map_get(key
, "algorithm", &algobj
);
2164 (void)cfg_map_get(key
, "secret", &secretobj
);
2165 if (secretobj
== NULL
|| algobj
== NULL
) {
2166 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
2167 "key '%s' must have both 'secret' and "
2168 "'algorithm' defined",
2170 return (ISC_R_FAILURE
);
2173 isc_buffer_init(&buf
, secretbuf
, sizeof(secretbuf
));
2174 result
= isc_base64_decodestring(cfg_obj_asstring(secretobj
), &buf
);
2175 if (result
!= ISC_R_SUCCESS
) {
2176 cfg_obj_log(secretobj
, logctx
, ISC_LOG_ERROR
,
2177 "bad secret '%s'", isc_result_totext(result
));
2181 algorithm
= cfg_obj_asstring(algobj
);
2182 for (i
= 0; algorithms
[i
].name
!= NULL
; i
++) {
2183 len
= strlen(algorithms
[i
].name
);
2184 if (strncasecmp(algorithms
[i
].name
, algorithm
, len
) == 0 &&
2185 (algorithm
[len
] == '\0' ||
2186 (algorithms
[i
].size
!= 0 && algorithm
[len
] == '-')))
2189 if (algorithms
[i
].name
== NULL
) {
2190 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
2191 "unknown algorithm '%s'", algorithm
);
2192 return (ISC_R_NOTFOUND
);
2194 if (algorithm
[len
] == '-') {
2195 isc_uint16_t digestbits
;
2196 result
= isc_parse_uint16(&digestbits
, algorithm
+ len
+ 1, 10);
2197 if (result
== ISC_R_SUCCESS
|| result
== ISC_R_RANGE
) {
2198 if (result
== ISC_R_RANGE
||
2199 digestbits
> algorithms
[i
].size
) {
2200 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
2201 "key '%s' digest-bits too large "
2202 "[%u..%u]", keyname
,
2203 algorithms
[i
].size
/ 2,
2204 algorithms
[i
].size
);
2205 return (ISC_R_RANGE
);
2207 if ((digestbits
% 8) != 0) {
2208 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
2209 "key '%s' digest-bits not multiple"
2211 return (ISC_R_RANGE
);
2214 * Recommended minima for hmac algorithms.
2216 if ((digestbits
< (algorithms
[i
].size
/ 2U) ||
2217 (digestbits
< 80U)))
2218 cfg_obj_log(algobj
, logctx
, ISC_LOG_WARNING
,
2219 "key '%s' digest-bits too small "
2221 algorithms
[i
].size
/2);
2223 cfg_obj_log(algobj
, logctx
, ISC_LOG_ERROR
,
2224 "key '%s': unable to parse digest-bits",
2229 return (ISC_R_SUCCESS
);
2233 fileexist(const cfg_obj_t
*obj
, isc_symtab_t
*symtab
, isc_boolean_t writeable
,
2236 isc_result_t result
;
2237 isc_symvalue_t symvalue
;
2241 result
= isc_symtab_lookup(symtab
, cfg_obj_asstring(obj
), 0, &symvalue
);
2242 if (result
== ISC_R_SUCCESS
) {
2244 file
= cfg_obj_file(symvalue
.as_cpointer
);
2245 line
= cfg_obj_line(symvalue
.as_cpointer
);
2246 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
2247 "writeable file '%s': already in use: "
2248 "%s:%u", cfg_obj_asstring(obj
),
2250 return (ISC_R_EXISTS
);
2252 result
= isc_symtab_lookup(symtab
, cfg_obj_asstring(obj
), 2,
2254 if (result
== ISC_R_SUCCESS
) {
2255 file
= cfg_obj_file(symvalue
.as_cpointer
);
2256 line
= cfg_obj_line(symvalue
.as_cpointer
);
2257 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
2258 "writeable file '%s': already in use: "
2259 "%s:%u", cfg_obj_asstring(obj
),
2261 return (ISC_R_EXISTS
);
2263 return (ISC_R_SUCCESS
);
2266 symvalue
.as_cpointer
= obj
;
2267 result
= isc_symtab_define(symtab
, cfg_obj_asstring(obj
),
2268 writeable
? 2 : 1, symvalue
,
2269 isc_symexists_reject
);
2274 * Check key list for duplicates key names and that the key names
2275 * are valid domain names as these keys are used for TSIG.
2277 * Check the key contents for validity.
2280 check_keylist(const cfg_obj_t
*keys
, isc_symtab_t
*symtab
,
2281 isc_mem_t
*mctx
, isc_log_t
*logctx
)
2283 char namebuf
[DNS_NAME_FORMATSIZE
];
2284 dns_fixedname_t fname
;
2286 isc_result_t result
= ISC_R_SUCCESS
;
2287 isc_result_t tresult
;
2288 const cfg_listelt_t
*element
;
2290 dns_fixedname_init(&fname
);
2291 name
= dns_fixedname_name(&fname
);
2292 for (element
= cfg_list_first(keys
);
2294 element
= cfg_list_next(element
))
2296 const cfg_obj_t
*key
= cfg_listelt_value(element
);
2297 const char *keyid
= cfg_obj_asstring(cfg_map_getname(key
));
2298 isc_symvalue_t symvalue
;
2302 isc_buffer_constinit(&b
, keyid
, strlen(keyid
));
2303 isc_buffer_add(&b
, strlen(keyid
));
2304 tresult
= dns_name_fromtext(name
, &b
, dns_rootname
,
2306 if (tresult
!= ISC_R_SUCCESS
) {
2307 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
2308 "key '%s': bad key name", keyid
);
2312 tresult
= bind9_check_key(key
, logctx
);
2313 if (tresult
!= ISC_R_SUCCESS
)
2316 dns_name_format(name
, namebuf
, sizeof(namebuf
));
2317 keyname
= isc_mem_strdup(mctx
, namebuf
);
2318 if (keyname
== NULL
)
2319 return (ISC_R_NOMEMORY
);
2320 symvalue
.as_cpointer
= key
;
2321 tresult
= isc_symtab_define(symtab
, keyname
, 1, symvalue
,
2322 isc_symexists_reject
);
2323 if (tresult
== ISC_R_EXISTS
) {
2327 RUNTIME_CHECK(isc_symtab_lookup(symtab
, keyname
,
2328 1, &symvalue
) == ISC_R_SUCCESS
);
2329 file
= cfg_obj_file(symvalue
.as_cpointer
);
2330 line
= cfg_obj_line(symvalue
.as_cpointer
);
2333 file
= "<unknown file>";
2334 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
2335 "key '%s': already exists "
2336 "previous definition: %s:%u",
2338 isc_mem_free(mctx
, keyname
);
2340 } else if (tresult
!= ISC_R_SUCCESS
) {
2341 isc_mem_free(mctx
, keyname
);
2352 { "transfer-source", "transfer-source-v6" },
2353 { "notify-source", "notify-source-v6" },
2354 { "query-source", "query-source-v6" },
2359 * RNDC keys are not normalised unlike TSIG keys.
2361 * "foo." is different to "foo".
2363 static isc_boolean_t
2364 rndckey_exists(const cfg_obj_t
*keylist
, const char *keyname
) {
2365 const cfg_listelt_t
*element
;
2366 const cfg_obj_t
*obj
;
2369 if (keylist
== NULL
)
2372 for (element
= cfg_list_first(keylist
);
2374 element
= cfg_list_next(element
))
2376 obj
= cfg_listelt_value(element
);
2377 str
= cfg_obj_asstring(cfg_map_getname(obj
));
2378 if (!strcasecmp(str
, keyname
))
2385 check_servers(const cfg_obj_t
*config
, const cfg_obj_t
*voptions
,
2386 isc_symtab_t
*symtab
, isc_log_t
*logctx
)
2388 dns_fixedname_t fname
;
2389 isc_result_t result
= ISC_R_SUCCESS
;
2390 isc_result_t tresult
;
2391 const cfg_listelt_t
*e1
, *e2
;
2392 const cfg_obj_t
*v1
, *v2
, *keys
;
2393 const cfg_obj_t
*servers
;
2394 isc_netaddr_t n1
, n2
;
2395 unsigned int p1
, p2
;
2396 const cfg_obj_t
*obj
;
2397 char buf
[ISC_NETADDR_FORMATSIZE
];
2398 char namebuf
[DNS_NAME_FORMATSIZE
];
2403 dns_name_t
*keyname
;
2406 if (voptions
!= NULL
)
2407 (void)cfg_map_get(voptions
, "server", &servers
);
2408 if (servers
== NULL
)
2409 (void)cfg_map_get(config
, "server", &servers
);
2410 if (servers
== NULL
)
2411 return (ISC_R_SUCCESS
);
2413 for (e1
= cfg_list_first(servers
); e1
!= NULL
; e1
= cfg_list_next(e1
)) {
2414 v1
= cfg_listelt_value(e1
);
2415 cfg_obj_asnetprefix(cfg_map_getname(v1
), &n1
, &p1
);
2417 * Check that unused bits are zero.
2419 tresult
= isc_netaddr_prefixok(&n1
, p1
);
2420 if (tresult
!= ISC_R_SUCCESS
) {
2421 INSIST(tresult
== ISC_R_FAILURE
);
2422 isc_netaddr_format(&n1
, buf
, sizeof(buf
));
2423 cfg_obj_log(v1
, logctx
, ISC_LOG_ERROR
,
2424 "server '%s/%u': invalid prefix "
2425 "(extra bits specified)", buf
, p1
);
2431 if (n1
.family
== AF_INET
)
2432 xfr
= sources
[source
].v6
;
2434 xfr
= sources
[source
].v4
;
2435 (void)cfg_map_get(v1
, xfr
, &obj
);
2437 isc_netaddr_format(&n1
, buf
, sizeof(buf
));
2438 cfg_obj_log(v1
, logctx
, ISC_LOG_ERROR
,
2439 "server '%s/%u': %s not legal",
2441 result
= ISC_R_FAILURE
;
2443 } while (sources
[++source
].v4
!= NULL
);
2445 while ((e2
= cfg_list_next(e2
)) != NULL
) {
2446 v2
= cfg_listelt_value(e2
);
2447 cfg_obj_asnetprefix(cfg_map_getname(v2
), &n2
, &p2
);
2448 if (p1
== p2
&& isc_netaddr_equal(&n1
, &n2
)) {
2449 const char *file
= cfg_obj_file(v1
);
2450 unsigned int line
= cfg_obj_line(v1
);
2453 file
= "<unknown file>";
2455 isc_netaddr_format(&n2
, buf
, sizeof(buf
));
2456 cfg_obj_log(v2
, logctx
, ISC_LOG_ERROR
,
2457 "server '%s/%u': already exists "
2458 "previous definition: %s:%u",
2459 buf
, p2
, file
, line
);
2460 result
= ISC_R_FAILURE
;
2464 cfg_map_get(v1
, "keys", &keys
);
2467 * Normalize key name.
2469 keyval
= cfg_obj_asstring(keys
);
2470 dns_fixedname_init(&fname
);
2471 isc_buffer_constinit(&b
, keyval
, strlen(keyval
));
2472 isc_buffer_add(&b
, strlen(keyval
));
2473 keyname
= dns_fixedname_name(&fname
);
2474 tresult
= dns_name_fromtext(keyname
, &b
, dns_rootname
,
2476 if (tresult
!= ISC_R_SUCCESS
) {
2477 cfg_obj_log(keys
, logctx
, ISC_LOG_ERROR
,
2478 "bad key name '%s'", keyval
);
2479 result
= ISC_R_FAILURE
;
2482 dns_name_format(keyname
, namebuf
, sizeof(namebuf
));
2483 tresult
= isc_symtab_lookup(symtab
, namebuf
, 1, NULL
);
2484 if (tresult
!= ISC_R_SUCCESS
) {
2485 cfg_obj_log(keys
, logctx
, ISC_LOG_ERROR
,
2486 "unknown key '%s'", keyval
);
2487 result
= ISC_R_FAILURE
;
2495 check_trusted_key(const cfg_obj_t
*key
, isc_boolean_t managed
,
2498 const char *keystr
, *keynamestr
;
2499 dns_fixedname_t fkeyname
;
2500 dns_name_t
*keyname
;
2503 isc_result_t result
= ISC_R_SUCCESS
;
2504 isc_result_t tresult
;
2505 isc_uint32_t flags
, proto
, alg
;
2506 unsigned char keydata
[4096];
2508 flags
= cfg_obj_asuint32(cfg_tuple_get(key
, "flags"));
2509 proto
= cfg_obj_asuint32(cfg_tuple_get(key
, "protocol"));
2510 alg
= cfg_obj_asuint32(cfg_tuple_get(key
, "algorithm"));
2512 dns_fixedname_init(&fkeyname
);
2513 keyname
= dns_fixedname_name(&fkeyname
);
2514 keynamestr
= cfg_obj_asstring(cfg_tuple_get(key
, "name"));
2516 isc_buffer_constinit(&b
, keynamestr
, strlen(keynamestr
));
2517 isc_buffer_add(&b
, strlen(keynamestr
));
2518 result
= dns_name_fromtext(keyname
, &b
, dns_rootname
, 0, NULL
);
2519 if (result
!= ISC_R_SUCCESS
) {
2520 cfg_obj_log(key
, logctx
, ISC_LOG_WARNING
, "bad key name: %s\n",
2521 isc_result_totext(result
));
2522 result
= ISC_R_FAILURE
;
2525 if (flags
> 0xffff) {
2526 cfg_obj_log(key
, logctx
, ISC_LOG_WARNING
,
2527 "flags too big: %u\n", flags
);
2528 result
= ISC_R_FAILURE
;
2531 cfg_obj_log(key
, logctx
, ISC_LOG_WARNING
,
2532 "protocol too big: %u\n", proto
);
2533 result
= ISC_R_FAILURE
;
2536 cfg_obj_log(key
, logctx
, ISC_LOG_WARNING
,
2537 "algorithm too big: %u\n", alg
);
2538 result
= ISC_R_FAILURE
;
2542 const char *initmethod
;
2543 initmethod
= cfg_obj_asstring(cfg_tuple_get(key
, "init"));
2545 if (strcasecmp(initmethod
, "initial-key") != 0) {
2546 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
2547 "managed key '%s': "
2548 "invalid initialization method '%s'",
2549 keynamestr
, initmethod
);
2550 result
= ISC_R_FAILURE
;
2554 isc_buffer_init(&b
, keydata
, sizeof(keydata
));
2556 keystr
= cfg_obj_asstring(cfg_tuple_get(key
, "key"));
2557 tresult
= isc_base64_decodestring(keystr
, &b
);
2559 if (tresult
!= ISC_R_SUCCESS
) {
2560 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
2561 "%s", isc_result_totext(tresult
));
2562 result
= ISC_R_FAILURE
;
2564 isc_buffer_usedregion(&b
, &r
);
2566 if ((alg
== DST_ALG_RSASHA1
|| alg
== DST_ALG_RSAMD5
) &&
2567 r
.length
> 1 && r
.base
[0] == 1 && r
.base
[1] == 3)
2568 cfg_obj_log(key
, logctx
, ISC_LOG_WARNING
,
2569 "%s key '%s' has a weak exponent",
2570 managed
? "managed" : "trusted",
2578 check_viewconf(const cfg_obj_t
*config
, const cfg_obj_t
*voptions
,
2579 const char *viewname
, dns_rdataclass_t vclass
,
2580 isc_symtab_t
*files
, isc_log_t
*logctx
, isc_mem_t
*mctx
)
2582 const cfg_obj_t
*zones
= NULL
;
2583 const cfg_obj_t
*keys
= NULL
;
2584 const cfg_listelt_t
*element
, *element2
;
2585 isc_symtab_t
*symtab
= NULL
;
2586 isc_result_t result
= ISC_R_SUCCESS
;
2587 isc_result_t tresult
= ISC_R_SUCCESS
;
2588 cfg_aclconfctx_t
*actx
= NULL
;
2589 const cfg_obj_t
*obj
;
2590 const cfg_obj_t
*options
= NULL
;
2591 isc_boolean_t enablednssec
, enablevalidation
;
2592 const char *valstr
= "no";
2595 * Get global options block
2597 (void)cfg_map_get(config
, "options", &options
);
2600 * Check that all zone statements are syntactically correct and
2601 * there are no duplicate zones.
2603 tresult
= isc_symtab_create(mctx
, 1000, freekey
, mctx
,
2604 ISC_FALSE
, &symtab
);
2605 if (tresult
!= ISC_R_SUCCESS
)
2606 return (ISC_R_NOMEMORY
);
2608 cfg_aclconfctx_create(mctx
, &actx
);
2610 if (voptions
!= NULL
)
2611 (void)cfg_map_get(voptions
, "zone", &zones
);
2613 (void)cfg_map_get(config
, "zone", &zones
);
2615 for (element
= cfg_list_first(zones
);
2617 element
= cfg_list_next(element
))
2619 const cfg_obj_t
*zone
= cfg_listelt_value(element
);
2621 tresult
= check_zoneconf(zone
, voptions
, config
, symtab
,
2622 files
, vclass
, actx
, logctx
,
2624 if (tresult
!= ISC_R_SUCCESS
)
2625 result
= ISC_R_FAILURE
;
2628 isc_symtab_destroy(&symtab
);
2631 * Check that forwarding is reasonable.
2633 if (voptions
== NULL
) {
2634 if (options
!= NULL
)
2635 if (check_forward(options
, NULL
,
2636 logctx
) != ISC_R_SUCCESS
)
2637 result
= ISC_R_FAILURE
;
2639 if (check_forward(voptions
, NULL
, logctx
) != ISC_R_SUCCESS
)
2640 result
= ISC_R_FAILURE
;
2644 * Check non-zero options at the global and view levels.
2646 if (options
!= NULL
&& check_nonzero(options
, logctx
) != ISC_R_SUCCESS
)
2647 result
= ISC_R_FAILURE
;
2648 if (voptions
!= NULL
&&check_nonzero(voptions
, logctx
) != ISC_R_SUCCESS
)
2649 result
= ISC_R_FAILURE
;
2652 * Check that dual-stack-servers is reasonable.
2654 if (voptions
== NULL
) {
2655 if (options
!= NULL
)
2656 if (check_dual_stack(options
, logctx
) != ISC_R_SUCCESS
)
2657 result
= ISC_R_FAILURE
;
2659 if (check_dual_stack(voptions
, logctx
) != ISC_R_SUCCESS
)
2660 result
= ISC_R_FAILURE
;
2664 * Check that rrset-order is reasonable.
2666 if (voptions
!= NULL
) {
2667 if (check_order(voptions
, logctx
) != ISC_R_SUCCESS
)
2668 result
= ISC_R_FAILURE
;
2672 * Check that all key statements are syntactically correct and
2673 * there are no duplicate keys.
2675 tresult
= isc_symtab_create(mctx
, 1000, freekey
, mctx
,
2676 ISC_FALSE
, &symtab
);
2677 if (tresult
!= ISC_R_SUCCESS
)
2680 (void)cfg_map_get(config
, "key", &keys
);
2681 tresult
= check_keylist(keys
, symtab
, mctx
, logctx
);
2682 if (tresult
== ISC_R_EXISTS
)
2683 result
= ISC_R_FAILURE
;
2684 else if (tresult
!= ISC_R_SUCCESS
) {
2689 if (voptions
!= NULL
) {
2691 (void)cfg_map_get(voptions
, "key", &keys
);
2692 tresult
= check_keylist(keys
, symtab
, mctx
, logctx
);
2693 if (tresult
== ISC_R_EXISTS
)
2694 result
= ISC_R_FAILURE
;
2695 else if (tresult
!= ISC_R_SUCCESS
) {
2702 * Global servers can refer to keys in views.
2704 if (check_servers(config
, voptions
, symtab
, logctx
) != ISC_R_SUCCESS
)
2705 result
= ISC_R_FAILURE
;
2707 isc_symtab_destroy(&symtab
);
2710 * Check that dnssec-enable/dnssec-validation are sensible.
2713 if (voptions
!= NULL
)
2714 (void)cfg_map_get(voptions
, "dnssec-enable", &obj
);
2715 if (obj
== NULL
&& options
!= NULL
)
2716 (void)cfg_map_get(options
, "dnssec-enable", &obj
);
2718 enablednssec
= ISC_TRUE
;
2720 enablednssec
= cfg_obj_asboolean(obj
);
2723 if (voptions
!= NULL
)
2724 (void)cfg_map_get(voptions
, "dnssec-validation", &obj
);
2725 if (obj
== NULL
&& options
!= NULL
)
2726 (void)cfg_map_get(options
, "dnssec-validation", &obj
);
2728 enablevalidation
= enablednssec
;
2730 } else if (cfg_obj_isboolean(obj
)) {
2731 enablevalidation
= cfg_obj_asboolean(obj
);
2732 valstr
= enablevalidation
? "yes" : "no";
2734 enablevalidation
= ISC_TRUE
;
2738 if (enablevalidation
&& !enablednssec
)
2739 cfg_obj_log(obj
, logctx
, ISC_LOG_WARNING
,
2740 "'dnssec-validation %s;' and 'dnssec-enable no;'",
2744 * Check trusted-keys and managed-keys.
2747 if (voptions
!= NULL
)
2748 (void)cfg_map_get(voptions
, "trusted-keys", &keys
);
2750 (void)cfg_map_get(config
, "trusted-keys", &keys
);
2752 for (element
= cfg_list_first(keys
);
2754 element
= cfg_list_next(element
))
2756 const cfg_obj_t
*keylist
= cfg_listelt_value(element
);
2757 for (element2
= cfg_list_first(keylist
);
2759 element2
= cfg_list_next(element2
)) {
2760 obj
= cfg_listelt_value(element2
);
2761 tresult
= check_trusted_key(obj
, ISC_FALSE
, logctx
);
2762 if (tresult
!= ISC_R_SUCCESS
)
2768 if (voptions
!= NULL
)
2769 (void)cfg_map_get(voptions
, "managed-keys", &keys
);
2771 (void)cfg_map_get(config
, "managed-keys", &keys
);
2773 for (element
= cfg_list_first(keys
);
2775 element
= cfg_list_next(element
))
2777 const cfg_obj_t
*keylist
= cfg_listelt_value(element
);
2778 for (element2
= cfg_list_first(keylist
);
2780 element2
= cfg_list_next(element2
)) {
2781 obj
= cfg_listelt_value(element2
);
2782 tresult
= check_trusted_key(obj
, ISC_TRUE
, logctx
);
2783 if (tresult
!= ISC_R_SUCCESS
)
2791 if (voptions
!= NULL
)
2792 tresult
= check_options(voptions
, logctx
, mctx
,
2795 tresult
= check_options(config
, logctx
, mctx
,
2797 if (tresult
!= ISC_R_SUCCESS
)
2800 tresult
= check_viewacls(actx
, voptions
, config
, logctx
, mctx
);
2801 if (tresult
!= ISC_R_SUCCESS
)
2804 tresult
= check_recursionacls(actx
, voptions
, viewname
,
2805 config
, logctx
, mctx
);
2806 if (tresult
!= ISC_R_SUCCESS
)
2809 tresult
= check_filteraaaa(actx
, voptions
, viewname
, config
,
2811 if (tresult
!= ISC_R_SUCCESS
)
2814 tresult
= check_dns64(actx
, voptions
, config
, logctx
, mctx
);
2815 if (tresult
!= ISC_R_SUCCESS
)
2820 isc_symtab_destroy(&symtab
);
2822 cfg_aclconfctx_detach(&actx
);
2828 default_channels
[] = {
2837 bind9_check_logging(const cfg_obj_t
*config
, isc_log_t
*logctx
,
2840 const cfg_obj_t
*categories
= NULL
;
2841 const cfg_obj_t
*category
;
2842 const cfg_obj_t
*channels
= NULL
;
2843 const cfg_obj_t
*channel
;
2844 const cfg_listelt_t
*element
;
2845 const cfg_listelt_t
*delement
;
2846 const char *channelname
;
2847 const char *catname
;
2848 const cfg_obj_t
*fileobj
= NULL
;
2849 const cfg_obj_t
*syslogobj
= NULL
;
2850 const cfg_obj_t
*nullobj
= NULL
;
2851 const cfg_obj_t
*stderrobj
= NULL
;
2852 const cfg_obj_t
*logobj
= NULL
;
2853 isc_result_t result
= ISC_R_SUCCESS
;
2854 isc_result_t tresult
;
2855 isc_symtab_t
*symtab
= NULL
;
2856 isc_symvalue_t symvalue
;
2859 (void)cfg_map_get(config
, "logging", &logobj
);
2861 return (ISC_R_SUCCESS
);
2863 result
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_FALSE
, &symtab
);
2864 if (result
!= ISC_R_SUCCESS
)
2867 symvalue
.as_cpointer
= NULL
;
2868 for (i
= 0; default_channels
[i
] != NULL
; i
++) {
2869 tresult
= isc_symtab_define(symtab
, default_channels
[i
], 1,
2870 symvalue
, isc_symexists_replace
);
2871 if (tresult
!= ISC_R_SUCCESS
)
2875 cfg_map_get(logobj
, "channel", &channels
);
2877 for (element
= cfg_list_first(channels
);
2879 element
= cfg_list_next(element
))
2881 channel
= cfg_listelt_value(element
);
2882 channelname
= cfg_obj_asstring(cfg_map_getname(channel
));
2883 fileobj
= syslogobj
= nullobj
= stderrobj
= NULL
;
2884 (void)cfg_map_get(channel
, "file", &fileobj
);
2885 (void)cfg_map_get(channel
, "syslog", &syslogobj
);
2886 (void)cfg_map_get(channel
, "null", &nullobj
);
2887 (void)cfg_map_get(channel
, "stderr", &stderrobj
);
2889 if (fileobj
!= NULL
)
2891 if (syslogobj
!= NULL
)
2893 if (nullobj
!= NULL
)
2895 if (stderrobj
!= NULL
)
2898 cfg_obj_log(channel
, logctx
, ISC_LOG_ERROR
,
2899 "channel '%s': exactly one of file, syslog, "
2900 "null, and stderr must be present",
2902 result
= ISC_R_FAILURE
;
2904 tresult
= isc_symtab_define(symtab
, channelname
, 1,
2905 symvalue
, isc_symexists_replace
);
2906 if (tresult
!= ISC_R_SUCCESS
)
2910 cfg_map_get(logobj
, "category", &categories
);
2912 for (element
= cfg_list_first(categories
);
2914 element
= cfg_list_next(element
))
2916 category
= cfg_listelt_value(element
);
2917 catname
= cfg_obj_asstring(cfg_tuple_get(category
, "name"));
2918 if (isc_log_categorybyname(logctx
, catname
) == NULL
) {
2919 cfg_obj_log(category
, logctx
, ISC_LOG_ERROR
,
2920 "undefined category: '%s'", catname
);
2921 result
= ISC_R_FAILURE
;
2923 channels
= cfg_tuple_get(category
, "destinations");
2924 for (delement
= cfg_list_first(channels
);
2926 delement
= cfg_list_next(delement
))
2928 channel
= cfg_listelt_value(delement
);
2929 channelname
= cfg_obj_asstring(channel
);
2930 tresult
= isc_symtab_lookup(symtab
, channelname
, 1,
2932 if (tresult
!= ISC_R_SUCCESS
) {
2933 cfg_obj_log(channel
, logctx
, ISC_LOG_ERROR
,
2934 "undefined channel: '%s'",
2940 isc_symtab_destroy(&symtab
);
2945 bind9_check_controlskeys(const cfg_obj_t
*control
, const cfg_obj_t
*keylist
,
2948 isc_result_t result
= ISC_R_SUCCESS
;
2949 const cfg_obj_t
*control_keylist
;
2950 const cfg_listelt_t
*element
;
2951 const cfg_obj_t
*key
;
2954 control_keylist
= cfg_tuple_get(control
, "keys");
2955 if (cfg_obj_isvoid(control_keylist
))
2956 return (ISC_R_SUCCESS
);
2958 for (element
= cfg_list_first(control_keylist
);
2960 element
= cfg_list_next(element
))
2962 key
= cfg_listelt_value(element
);
2963 keyval
= cfg_obj_asstring(key
);
2965 if (!rndckey_exists(keylist
, keyval
)) {
2966 cfg_obj_log(key
, logctx
, ISC_LOG_ERROR
,
2967 "unknown key '%s'", keyval
);
2968 result
= ISC_R_NOTFOUND
;
2975 bind9_check_controls(const cfg_obj_t
*config
, isc_log_t
*logctx
,
2978 isc_result_t result
= ISC_R_SUCCESS
, tresult
;
2979 cfg_aclconfctx_t
*actx
= NULL
;
2980 const cfg_listelt_t
*element
, *element2
;
2981 const cfg_obj_t
*allow
;
2982 const cfg_obj_t
*control
;
2983 const cfg_obj_t
*controls
;
2984 const cfg_obj_t
*controlslist
= NULL
;
2985 const cfg_obj_t
*inetcontrols
;
2986 const cfg_obj_t
*unixcontrols
;
2987 const cfg_obj_t
*keylist
= NULL
;
2989 isc_uint32_t perm
, mask
;
2990 dns_acl_t
*acl
= NULL
;
2991 isc_sockaddr_t addr
;
2994 (void)cfg_map_get(config
, "controls", &controlslist
);
2995 if (controlslist
== NULL
)
2996 return (ISC_R_SUCCESS
);
2998 (void)cfg_map_get(config
, "key", &keylist
);
3000 cfg_aclconfctx_create(mctx
, &actx
);
3003 * INET: Check allow clause.
3004 * UNIX: Check "perm" for sanity, check path length.
3006 for (element
= cfg_list_first(controlslist
);
3008 element
= cfg_list_next(element
)) {
3009 controls
= cfg_listelt_value(element
);
3010 unixcontrols
= NULL
;
3011 inetcontrols
= NULL
;
3012 (void)cfg_map_get(controls
, "unix", &unixcontrols
);
3013 (void)cfg_map_get(controls
, "inet", &inetcontrols
);
3014 for (element2
= cfg_list_first(inetcontrols
);
3016 element2
= cfg_list_next(element2
)) {
3017 control
= cfg_listelt_value(element2
);
3018 allow
= cfg_tuple_get(control
, "allow");
3019 tresult
= cfg_acl_fromconfig(allow
, config
, logctx
,
3020 actx
, mctx
, 0, &acl
);
3022 dns_acl_detach(&acl
);
3023 if (tresult
!= ISC_R_SUCCESS
)
3025 tresult
= bind9_check_controlskeys(control
, keylist
,
3027 if (tresult
!= ISC_R_SUCCESS
)
3030 for (element2
= cfg_list_first(unixcontrols
);
3032 element2
= cfg_list_next(element2
)) {
3033 control
= cfg_listelt_value(element2
);
3034 path
= cfg_obj_asstring(cfg_tuple_get(control
, "path"));
3035 tresult
= isc_sockaddr_frompath(&addr
, path
);
3036 if (tresult
== ISC_R_NOSPACE
) {
3037 cfg_obj_log(control
, logctx
, ISC_LOG_ERROR
,
3038 "unix control '%s': path too long",
3040 result
= ISC_R_NOSPACE
;
3042 perm
= cfg_obj_asuint32(cfg_tuple_get(control
, "perm"));
3043 for (i
= 0; i
< 3; i
++) {
3044 #ifdef NEED_SECURE_DIRECTORY
3045 mask
= (0x1 << (i
*3)); /* SEARCH */
3047 mask
= (0x6 << (i
*3)); /* READ + WRITE */
3049 if ((perm
& mask
) == mask
)
3053 cfg_obj_log(control
, logctx
, ISC_LOG_WARNING
,
3054 "unix control '%s' allows access "
3055 "to everyone", path
);
3056 } else if (i
== 3) {
3057 cfg_obj_log(control
, logctx
, ISC_LOG_WARNING
,
3058 "unix control '%s' allows access "
3061 tresult
= bind9_check_controlskeys(control
, keylist
,
3063 if (tresult
!= ISC_R_SUCCESS
)
3067 cfg_aclconfctx_detach(&actx
);
3072 bind9_check_namedconf(const cfg_obj_t
*config
, isc_log_t
*logctx
,
3075 const cfg_obj_t
*options
= NULL
;
3076 const cfg_obj_t
*views
= NULL
;
3077 const cfg_obj_t
*acls
= NULL
;
3078 const cfg_obj_t
*kals
= NULL
;
3079 const cfg_obj_t
*obj
;
3080 const cfg_listelt_t
*velement
;
3081 isc_result_t result
= ISC_R_SUCCESS
;
3082 isc_result_t tresult
;
3083 isc_symtab_t
*symtab
= NULL
;
3084 isc_symtab_t
*files
= NULL
;
3086 static const char *builtin
[] = { "localhost", "localnets",
3089 (void)cfg_map_get(config
, "options", &options
);
3091 if (options
!= NULL
&&
3092 check_options(options
, logctx
, mctx
,
3093 optlevel_options
) != ISC_R_SUCCESS
)
3094 result
= ISC_R_FAILURE
;
3096 if (bind9_check_logging(config
, logctx
, mctx
) != ISC_R_SUCCESS
)
3097 result
= ISC_R_FAILURE
;
3099 if (bind9_check_controls(config
, logctx
, mctx
) != ISC_R_SUCCESS
)
3100 result
= ISC_R_FAILURE
;
3102 if (options
!= NULL
&&
3103 check_order(options
, logctx
) != ISC_R_SUCCESS
)
3104 result
= ISC_R_FAILURE
;
3106 (void)cfg_map_get(config
, "view", &views
);
3108 if (views
!= NULL
&& options
!= NULL
)
3109 if (check_dual_stack(options
, logctx
) != ISC_R_SUCCESS
)
3110 result
= ISC_R_FAILURE
;
3113 * Use case insensitve comparision as not all file systems are
3114 * case sensitive. This will prevent people using FOO.DB and foo.db
3115 * on case sensitive file systems but that shouldn't be a major issue.
3117 tresult
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_FALSE
,
3119 if (tresult
!= ISC_R_SUCCESS
)
3122 if (views
== NULL
) {
3123 if (check_viewconf(config
, NULL
, NULL
, dns_rdataclass_in
,
3124 files
, logctx
, mctx
) != ISC_R_SUCCESS
)
3125 result
= ISC_R_FAILURE
;
3127 const cfg_obj_t
*zones
= NULL
;
3129 (void)cfg_map_get(config
, "zone", &zones
);
3130 if (zones
!= NULL
) {
3131 cfg_obj_log(zones
, logctx
, ISC_LOG_ERROR
,
3132 "when using 'view' statements, "
3133 "all zones must be in views");
3134 result
= ISC_R_FAILURE
;
3138 tresult
= isc_symtab_create(mctx
, 100, NULL
, NULL
, ISC_TRUE
, &symtab
);
3139 if (tresult
!= ISC_R_SUCCESS
)
3141 for (velement
= cfg_list_first(views
);
3143 velement
= cfg_list_next(velement
))
3145 const cfg_obj_t
*view
= cfg_listelt_value(velement
);
3146 const cfg_obj_t
*vname
= cfg_tuple_get(view
, "name");
3147 const cfg_obj_t
*voptions
= cfg_tuple_get(view
, "options");
3148 const cfg_obj_t
*vclassobj
= cfg_tuple_get(view
, "class");
3149 dns_rdataclass_t vclass
= dns_rdataclass_in
;
3150 const char *key
= cfg_obj_asstring(vname
);
3151 isc_symvalue_t symvalue
;
3153 tresult
= ISC_R_SUCCESS
;
3154 if (cfg_obj_isstring(vclassobj
)) {
3157 DE_CONST(cfg_obj_asstring(vclassobj
), r
.base
);
3158 r
.length
= strlen(r
.base
);
3159 tresult
= dns_rdataclass_fromtext(&vclass
, &r
);
3160 if (tresult
!= ISC_R_SUCCESS
)
3161 cfg_obj_log(vclassobj
, logctx
, ISC_LOG_ERROR
,
3162 "view '%s': invalid class %s",
3163 cfg_obj_asstring(vname
), r
.base
);
3165 if (tresult
== ISC_R_SUCCESS
&& symtab
!= NULL
) {
3166 symvalue
.as_cpointer
= view
;
3167 tresult
= isc_symtab_define(symtab
, key
, vclass
,
3169 isc_symexists_reject
);
3170 if (tresult
== ISC_R_EXISTS
) {
3173 RUNTIME_CHECK(isc_symtab_lookup(symtab
, key
,
3174 vclass
, &symvalue
) == ISC_R_SUCCESS
);
3175 file
= cfg_obj_file(symvalue
.as_cpointer
);
3176 line
= cfg_obj_line(symvalue
.as_cpointer
);
3177 cfg_obj_log(view
, logctx
, ISC_LOG_ERROR
,
3178 "view '%s': already exists "
3179 "previous definition: %s:%u",
3182 } else if (tresult
!= ISC_R_SUCCESS
) {
3184 } else if ((strcasecmp(key
, "_bind") == 0 &&
3185 vclass
== dns_rdataclass_ch
) ||
3186 (strcasecmp(key
, "_default") == 0 &&
3187 vclass
== dns_rdataclass_in
)) {
3188 cfg_obj_log(view
, logctx
, ISC_LOG_ERROR
,
3189 "attempt to redefine builtin view "
3191 result
= ISC_R_EXISTS
;
3194 if (tresult
== ISC_R_SUCCESS
)
3195 tresult
= check_viewconf(config
, voptions
, key
, vclass
,
3196 files
, logctx
, mctx
);
3197 if (tresult
!= ISC_R_SUCCESS
)
3198 result
= ISC_R_FAILURE
;
3201 isc_symtab_destroy(&symtab
);
3203 isc_symtab_destroy(&files
);
3205 if (views
!= NULL
&& options
!= NULL
) {
3207 tresult
= cfg_map_get(options
, "cache-file", &obj
);
3208 if (tresult
== ISC_R_SUCCESS
) {
3209 cfg_obj_log(obj
, logctx
, ISC_LOG_ERROR
,
3210 "'cache-file' cannot be a global "
3211 "option if views are present");
3212 result
= ISC_R_FAILURE
;
3216 cfg_map_get(config
, "acl", &acls
);
3219 const cfg_listelt_t
*elt
;
3220 const cfg_listelt_t
*elt2
;
3221 const char *aclname
;
3223 for (elt
= cfg_list_first(acls
);
3225 elt
= cfg_list_next(elt
)) {
3226 const cfg_obj_t
*acl
= cfg_listelt_value(elt
);
3227 unsigned int line
= cfg_obj_line(acl
);
3230 aclname
= cfg_obj_asstring(cfg_tuple_get(acl
, "name"));
3232 i
< sizeof(builtin
) / sizeof(builtin
[0]);
3234 if (strcasecmp(aclname
, builtin
[i
]) == 0) {
3235 cfg_obj_log(acl
, logctx
, ISC_LOG_ERROR
,
3236 "attempt to redefine "
3239 result
= ISC_R_FAILURE
;
3243 for (elt2
= cfg_list_next(elt
);
3245 elt2
= cfg_list_next(elt2
)) {
3246 const cfg_obj_t
*acl2
= cfg_listelt_value(elt2
);
3248 name
= cfg_obj_asstring(cfg_tuple_get(acl2
,
3250 if (strcasecmp(aclname
, name
) == 0) {
3251 const char *file
= cfg_obj_file(acl
);
3254 file
= "<unknown file>";
3256 cfg_obj_log(acl2
, logctx
, ISC_LOG_ERROR
,
3257 "attempt to redefine "
3258 "acl '%s' previous "
3259 "definition: %s:%u",
3261 result
= ISC_R_FAILURE
;
3267 tresult
= cfg_map_get(config
, "kal", &kals
);
3268 if (tresult
== ISC_R_SUCCESS
) {
3269 const cfg_listelt_t
*elt
;
3270 const cfg_listelt_t
*elt2
;
3271 const char *aclname
;
3273 for (elt
= cfg_list_first(kals
);
3275 elt
= cfg_list_next(elt
)) {
3276 const cfg_obj_t
*acl
= cfg_listelt_value(elt
);
3278 aclname
= cfg_obj_asstring(cfg_tuple_get(acl
, "name"));
3280 for (elt2
= cfg_list_next(elt
);
3282 elt2
= cfg_list_next(elt2
)) {
3283 const cfg_obj_t
*acl2
= cfg_listelt_value(elt2
);
3285 name
= cfg_obj_asstring(cfg_tuple_get(acl2
,
3287 if (strcasecmp(aclname
, name
) == 0) {
3288 const char *file
= cfg_obj_file(acl
);
3289 unsigned int line
= cfg_obj_line(acl
);
3292 file
= "<unknown file>";
3294 cfg_obj_log(acl2
, logctx
, ISC_LOG_ERROR
,
3295 "attempt to redefine "
3296 "kal '%s' previous "
3297 "definition: %s:%u",
3299 result
= ISC_R_FAILURE
;