1 /* $NetBSD: check.c,v 1.4 2026/01/29 18:37:55 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #include <ctype.h> 19 #include <inttypes.h> 20 #include <stdbool.h> 21 #include <stdint.h> 22 #include <stdlib.h> 23 24 #include <openssl/opensslv.h> 25 26 #ifdef HAVE_DNSTAP 27 #include <fstrm.h> 28 #endif 29 30 #include <isc/base64.h> 31 #include <isc/buffer.h> 32 #include <isc/dir.h> 33 #include <isc/file.h> 34 #include <isc/hex.h> 35 #include <isc/log.h> 36 #include <isc/md.h> 37 #include <isc/mem.h> 38 #include <isc/netaddr.h> 39 #include <isc/parseint.h> 40 #include <isc/region.h> 41 #include <isc/result.h> 42 #include <isc/siphash.h> 43 #include <isc/sockaddr.h> 44 #include <isc/string.h> 45 #include <isc/symtab.h> 46 #include <isc/util.h> 47 48 #include <dns/acl.h> 49 #include <dns/dnstap.h> 50 #include <dns/fixedname.h> 51 #include <dns/kasp.h> 52 #include <dns/keymgr.h> 53 #include <dns/keystore.h> 54 #include <dns/keyvalues.h> 55 #include <dns/peer.h> 56 #include <dns/rbt.h> 57 #include <dns/rdataclass.h> 58 #include <dns/rdatatype.h> 59 #include <dns/rpz.h> 60 #include <dns/rrl.h> 61 #include <dns/secalg.h> 62 #include <dns/ssu.h> 63 64 #include <dst/dst.h> 65 66 #include <isccfg/aclconf.h> 67 #include <isccfg/cfg.h> 68 #include <isccfg/check.h> 69 #include <isccfg/grammar.h> 70 #include <isccfg/kaspconf.h> 71 #include <isccfg/namedconf.h> 72 73 #include <ns/hooks.h> 74 75 #define NAMED_CONTROL_PORT 953 76 77 static in_port_t dnsport = 53; 78 79 static isc_result_t 80 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable, 81 isc_log_t *logctxlogc); 82 83 static isc_result_t 84 keydirexist(const cfg_obj_t *zcgf, const char *optname, dns_name_t *zname, 85 const char *dirname, const char *kaspnamestr, isc_symtab_t *symtab, 86 isc_log_t *logctx, isc_mem_t *mctx); 87 88 static const cfg_obj_t * 89 find_maplist(const cfg_obj_t *config, const char *listname, const char *name); 90 91 static isc_result_t 92 validate_remotes(const cfg_obj_t *obj, const cfg_obj_t *config, 93 uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx); 94 static void 95 freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) { 96 UNUSED(type); 97 UNUSED(value); 98 isc_mem_free(userarg, key); 99 } 100 101 static isc_result_t 102 check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) { 103 isc_result_t result = ISC_R_SUCCESS; 104 isc_result_t tresult; 105 isc_textregion_t r; 106 dns_fixedname_t fixed; 107 const cfg_obj_t *obj; 108 dns_rdataclass_t rdclass; 109 dns_rdatatype_t rdtype; 110 isc_buffer_t b; 111 const char *str; 112 113 dns_fixedname_init(&fixed); 114 obj = cfg_tuple_get(ent, "class"); 115 if (cfg_obj_isstring(obj)) { 116 r.base = UNCONST(cfg_obj_asstring(obj)); 117 r.length = strlen(r.base); 118 tresult = dns_rdataclass_fromtext(&rdclass, &r); 119 if (tresult != ISC_R_SUCCESS) { 120 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 121 "rrset-order: invalid class '%s'", r.base); 122 if (result == ISC_R_SUCCESS) { 123 result = ISC_R_FAILURE; 124 } 125 } 126 } 127 128 obj = cfg_tuple_get(ent, "type"); 129 if (cfg_obj_isstring(obj)) { 130 r.base = UNCONST(cfg_obj_asstring(obj)); 131 r.length = strlen(r.base); 132 tresult = dns_rdatatype_fromtext(&rdtype, &r); 133 if (tresult != ISC_R_SUCCESS) { 134 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 135 "rrset-order: invalid type '%s'", r.base); 136 if (result == ISC_R_SUCCESS) { 137 result = ISC_R_FAILURE; 138 } 139 } 140 } 141 142 obj = cfg_tuple_get(ent, "name"); 143 if (cfg_obj_isstring(obj)) { 144 str = cfg_obj_asstring(obj); 145 isc_buffer_constinit(&b, str, strlen(str)); 146 isc_buffer_add(&b, strlen(str)); 147 tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b, 148 dns_rootname, 0, NULL); 149 if (tresult != ISC_R_SUCCESS) { 150 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 151 "rrset-order: invalid name '%s'", str); 152 if (result == ISC_R_SUCCESS) { 153 result = ISC_R_FAILURE; 154 } 155 } 156 } 157 158 obj = cfg_tuple_get(ent, "order"); 159 if (!cfg_obj_isstring(obj) || 160 strcasecmp("order", cfg_obj_asstring(obj)) != 0) 161 { 162 cfg_obj_log(ent, logctx, ISC_LOG_ERROR, 163 "rrset-order: keyword 'order' missing"); 164 if (result == ISC_R_SUCCESS) { 165 result = ISC_R_FAILURE; 166 } 167 } 168 169 obj = cfg_tuple_get(ent, "ordering"); 170 if (!cfg_obj_isstring(obj)) { 171 cfg_obj_log(ent, logctx, ISC_LOG_ERROR, 172 "rrset-order: missing ordering"); 173 if (result == ISC_R_SUCCESS) { 174 result = ISC_R_FAILURE; 175 } 176 } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) { 177 #if DNS_RDATASET_FIXED 178 if ((ent->pctx->flags & CFG_PCTX_NODEPRECATED) == 0) { 179 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 180 "rrset-order: order 'fixed' is deprecated"); 181 } 182 #else 183 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 184 "rrset-order: order 'fixed' was disabled at " 185 "compilation time"); 186 #endif /* if !DNS_RDATASET_FIXED */ 187 } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 && 188 strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0 && 189 strcasecmp(cfg_obj_asstring(obj), "none") != 0) 190 { 191 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 192 "rrset-order: invalid order '%s'", 193 cfg_obj_asstring(obj)); 194 if (result == ISC_R_SUCCESS) { 195 result = ISC_R_FAILURE; 196 } 197 } 198 return result; 199 } 200 201 static isc_result_t 202 check_order(const cfg_obj_t *options, isc_log_t *logctx) { 203 isc_result_t result = ISC_R_SUCCESS; 204 isc_result_t tresult; 205 const cfg_listelt_t *element; 206 const cfg_obj_t *obj = NULL; 207 208 if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS) { 209 return result; 210 } 211 212 for (element = cfg_list_first(obj); element != NULL; 213 element = cfg_list_next(element)) 214 { 215 tresult = check_orderent(cfg_listelt_value(element), logctx); 216 if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) { 217 result = tresult; 218 } 219 } 220 return result; 221 } 222 223 static isc_result_t 224 check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) { 225 const cfg_listelt_t *element; 226 const cfg_obj_t *alternates = NULL; 227 const cfg_obj_t *value; 228 const cfg_obj_t *obj; 229 const char *str; 230 dns_fixedname_t fixed; 231 dns_name_t *name; 232 isc_buffer_t buffer; 233 isc_result_t result = ISC_R_SUCCESS; 234 isc_result_t tresult; 235 236 (void)cfg_map_get(options, "dual-stack-servers", &alternates); 237 238 if (alternates == NULL) { 239 return ISC_R_SUCCESS; 240 } 241 242 obj = cfg_tuple_get(alternates, "port"); 243 if (cfg_obj_isuint32(obj)) { 244 uint32_t val = cfg_obj_asuint32(obj); 245 if (val > UINT16_MAX) { 246 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 247 "port '%u' out of range", val); 248 if (result == ISC_R_SUCCESS) { 249 result = ISC_R_RANGE; 250 } 251 } 252 } 253 obj = cfg_tuple_get(alternates, "addresses"); 254 for (element = cfg_list_first(obj); element != NULL; 255 element = cfg_list_next(element)) 256 { 257 value = cfg_listelt_value(element); 258 if (cfg_obj_issockaddr(value)) { 259 continue; 260 } 261 obj = cfg_tuple_get(value, "name"); 262 str = cfg_obj_asstring(obj); 263 isc_buffer_constinit(&buffer, str, strlen(str)); 264 isc_buffer_add(&buffer, strlen(str)); 265 name = dns_fixedname_initname(&fixed); 266 tresult = dns_name_fromtext(name, &buffer, dns_rootname, 0, 267 NULL); 268 if (tresult != ISC_R_SUCCESS) { 269 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad name '%s'", 270 str); 271 if (result == ISC_R_SUCCESS) { 272 result = tresult; 273 } 274 } 275 obj = cfg_tuple_get(value, "port"); 276 if (cfg_obj_isuint32(obj)) { 277 uint32_t val = cfg_obj_asuint32(obj); 278 if (val > UINT16_MAX) { 279 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 280 "port '%u' out of range", val); 281 if (result == ISC_R_SUCCESS) { 282 result = ISC_R_RANGE; 283 } 284 } 285 } 286 } 287 return result; 288 } 289 290 static isc_result_t 291 validate_tls(const cfg_obj_t *config, const cfg_obj_t *obj, isc_log_t *logctx, 292 const char *str) { 293 dns_fixedname_t fname; 294 dns_name_t *nm = dns_fixedname_initname(&fname); 295 isc_result_t result = dns_name_fromstring(nm, str, dns_rootname, 0, 296 NULL); 297 298 if (result != ISC_R_SUCCESS) { 299 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 300 "'%s' is not a valid name", str); 301 return result; 302 } 303 304 if (strcasecmp(str, "ephemeral") != 0) { 305 const cfg_obj_t *tlsmap = find_maplist(config, "tls", str); 306 307 if (tlsmap == NULL) { 308 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 309 "tls '%s' is not defined", str); 310 return ISC_R_FAILURE; 311 } 312 } 313 314 return ISC_R_SUCCESS; 315 } 316 317 static isc_result_t 318 check_forward(const cfg_obj_t *config, const cfg_obj_t *options, 319 const cfg_obj_t *global, isc_log_t *logctx) { 320 const cfg_obj_t *forward = NULL; 321 const cfg_obj_t *forwarders = NULL; 322 const cfg_obj_t *faddresses = NULL; 323 const cfg_listelt_t *element; 324 325 (void)cfg_map_get(options, "forward", &forward); 326 (void)cfg_map_get(options, "forwarders", &forwarders); 327 328 if (forwarders != NULL && global != NULL) { 329 const char *file = cfg_obj_file(global); 330 unsigned int line = cfg_obj_line(global); 331 cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR, 332 "forwarders declared in root zone and " 333 "in general configuration: %s:%u", 334 file, line); 335 return ISC_R_FAILURE; 336 } 337 if (forward != NULL && forwarders == NULL) { 338 cfg_obj_log(forward, logctx, ISC_LOG_ERROR, 339 "no matching 'forwarders' statement"); 340 return ISC_R_FAILURE; 341 } 342 if (forwarders != NULL) { 343 isc_result_t result = ISC_R_SUCCESS; 344 const cfg_obj_t *tlspobj = cfg_tuple_get(forwarders, "tls"); 345 346 if (tlspobj != NULL && cfg_obj_isstring(tlspobj)) { 347 const char *tls = cfg_obj_asstring(tlspobj); 348 if (tls != NULL) { 349 result = validate_tls(config, tlspobj, logctx, 350 tls); 351 if (result != ISC_R_SUCCESS) { 352 return result; 353 } 354 } 355 } 356 357 faddresses = cfg_tuple_get(forwarders, "addresses"); 358 for (element = cfg_list_first(faddresses); element != NULL; 359 element = cfg_list_next(element)) 360 { 361 const cfg_obj_t *forwarder = cfg_listelt_value(element); 362 const char *tls = cfg_obj_getsockaddrtls(forwarder); 363 if (tls != NULL) { 364 result = validate_tls(config, faddresses, 365 logctx, tls); 366 if (result != ISC_R_SUCCESS) { 367 return result; 368 } 369 } 370 } 371 } 372 373 return ISC_R_SUCCESS; 374 } 375 376 static isc_result_t 377 disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) { 378 isc_result_t result = ISC_R_SUCCESS; 379 isc_result_t tresult; 380 const cfg_listelt_t *element; 381 const char *str; 382 isc_buffer_t b; 383 dns_fixedname_t fixed; 384 dns_name_t *name; 385 const cfg_obj_t *obj; 386 387 name = dns_fixedname_initname(&fixed); 388 obj = cfg_tuple_get(disabled, "name"); 389 str = cfg_obj_asstring(obj); 390 isc_buffer_constinit(&b, str, strlen(str)); 391 isc_buffer_add(&b, strlen(str)); 392 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 393 if (tresult != ISC_R_SUCCESS) { 394 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", 395 str); 396 result = tresult; 397 } 398 399 obj = cfg_tuple_get(disabled, "algorithms"); 400 401 for (element = cfg_list_first(obj); element != NULL; 402 element = cfg_list_next(element)) 403 { 404 isc_textregion_t r; 405 dns_secalg_t alg; 406 407 r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element))); 408 r.length = strlen(r.base); 409 410 tresult = dns_secalg_fromtext(&alg, &r); 411 if (tresult != ISC_R_SUCCESS) { 412 cfg_obj_log(cfg_listelt_value(element), logctx, 413 ISC_LOG_ERROR, "invalid algorithm '%s'", 414 r.base); 415 result = tresult; 416 } 417 } 418 return result; 419 } 420 421 static isc_result_t 422 disabled_ds_digests(const cfg_obj_t *disabled, isc_log_t *logctx) { 423 isc_result_t result = ISC_R_SUCCESS; 424 isc_result_t tresult; 425 const cfg_listelt_t *element; 426 const char *str; 427 isc_buffer_t b; 428 dns_fixedname_t fixed; 429 dns_name_t *name; 430 const cfg_obj_t *obj; 431 432 name = dns_fixedname_initname(&fixed); 433 obj = cfg_tuple_get(disabled, "name"); 434 str = cfg_obj_asstring(obj); 435 isc_buffer_constinit(&b, str, strlen(str)); 436 isc_buffer_add(&b, strlen(str)); 437 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 438 if (tresult != ISC_R_SUCCESS) { 439 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", 440 str); 441 result = tresult; 442 } 443 444 obj = cfg_tuple_get(disabled, "digests"); 445 446 for (element = cfg_list_first(obj); element != NULL; 447 element = cfg_list_next(element)) 448 { 449 isc_textregion_t r; 450 dns_dsdigest_t digest; 451 452 r.base = UNCONST(cfg_obj_asstring(cfg_listelt_value(element))); 453 r.length = strlen(r.base); 454 455 /* works with a numeric argument too */ 456 tresult = dns_dsdigest_fromtext(&digest, &r); 457 if (tresult != ISC_R_SUCCESS) { 458 cfg_obj_log(cfg_listelt_value(element), logctx, 459 ISC_LOG_ERROR, "invalid digest type '%s'", 460 r.base); 461 result = tresult; 462 } 463 } 464 return result; 465 } 466 467 static isc_result_t 468 exists(const cfg_obj_t *obj, const char *name, int value, isc_symtab_t *symtab, 469 const char *fmt, isc_log_t *logctx, isc_mem_t *mctx) { 470 char *key; 471 const char *file; 472 unsigned int line; 473 isc_result_t result; 474 isc_symvalue_t symvalue; 475 476 key = isc_mem_strdup(mctx, name); 477 symvalue.as_cpointer = obj; 478 result = isc_symtab_define(symtab, key, value, symvalue, 479 isc_symexists_reject); 480 if (result == ISC_R_EXISTS) { 481 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value, 482 &symvalue) == ISC_R_SUCCESS); 483 file = cfg_obj_file(symvalue.as_cpointer); 484 line = cfg_obj_line(symvalue.as_cpointer); 485 486 if (file == NULL) { 487 file = "<unknown file>"; 488 } 489 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line); 490 isc_mem_free(mctx, key); 491 result = ISC_R_EXISTS; 492 } 493 return result; 494 } 495 496 static isc_result_t 497 mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx, 498 isc_mem_t *mctx) { 499 const cfg_obj_t *obj; 500 char namebuf[DNS_NAME_FORMATSIZE]; 501 const char *str; 502 dns_fixedname_t fixed; 503 dns_name_t *name; 504 isc_buffer_t b; 505 isc_result_t result = ISC_R_SUCCESS; 506 507 name = dns_fixedname_initname(&fixed); 508 obj = cfg_tuple_get(secure, "name"); 509 str = cfg_obj_asstring(obj); 510 isc_buffer_constinit(&b, str, strlen(str)); 511 isc_buffer_add(&b, strlen(str)); 512 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 513 if (result != ISC_R_SUCCESS) { 514 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "bad domain name '%s'", 515 str); 516 } else { 517 dns_name_format(name, namebuf, sizeof(namebuf)); 518 result = exists(secure, namebuf, 1, symtab, 519 "dnssec-must-be-secure '%s': already exists " 520 "previous definition: %s:%u", 521 logctx, mctx); 522 } 523 return result; 524 } 525 526 static isc_result_t 527 checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig, 528 const cfg_obj_t *voptions, const cfg_obj_t *config, isc_log_t *logctx, 529 isc_mem_t *mctx) { 530 isc_result_t result; 531 const cfg_obj_t *aclobj = NULL; 532 const cfg_obj_t *options; 533 dns_acl_t *acl = NULL; 534 535 if (zconfig != NULL) { 536 options = cfg_tuple_get(zconfig, "options"); 537 cfg_map_get(options, aclname, &aclobj); 538 } 539 if (voptions != NULL && aclobj == NULL) { 540 cfg_map_get(voptions, aclname, &aclobj); 541 } 542 if (config != NULL && aclobj == NULL) { 543 options = NULL; 544 cfg_map_get(config, "options", &options); 545 if (options != NULL) { 546 cfg_map_get(options, aclname, &aclobj); 547 } 548 } 549 if (aclobj == NULL) { 550 return ISC_R_SUCCESS; 551 } 552 result = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, 0, 553 &acl); 554 if (acl != NULL) { 555 dns_acl_detach(&acl); 556 } 557 558 if (strcasecmp(aclname, "allow-transfer") == 0 && 559 cfg_obj_istuple(aclobj)) 560 { 561 const cfg_obj_t *obj_port = cfg_tuple_get( 562 cfg_tuple_get(aclobj, "port-transport"), "port"); 563 const cfg_obj_t *obj_proto = cfg_tuple_get( 564 cfg_tuple_get(aclobj, "port-transport"), "transport"); 565 566 if (cfg_obj_isuint32(obj_port) && 567 cfg_obj_asuint32(obj_port) >= UINT16_MAX) 568 { 569 cfg_obj_log(obj_port, logctx, ISC_LOG_ERROR, 570 "port value '%u' is out of range", 571 572 cfg_obj_asuint32(obj_port)); 573 if (result == ISC_R_SUCCESS) { 574 result = ISC_R_RANGE; 575 } 576 } 577 578 if (cfg_obj_isstring(obj_proto)) { 579 const char *allowed[] = { "tcp", "tls" }; 580 const char *transport = cfg_obj_asstring(obj_proto); 581 bool found = false; 582 for (size_t i = 0; i < ARRAY_SIZE(allowed); i++) { 583 if (strcasecmp(transport, allowed[i]) == 0) { 584 found = true; 585 } 586 } 587 588 if (!found) { 589 cfg_obj_log(obj_proto, logctx, ISC_LOG_ERROR, 590 "'%s' is not a valid transport " 591 "protocol for " 592 "zone " 593 "transfers. Please specify either " 594 "'tcp' or 'tls'", 595 transport); 596 result = ISC_R_FAILURE; 597 } 598 } 599 } 600 return result; 601 } 602 603 static isc_result_t 604 check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, 605 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { 606 isc_result_t result = ISC_R_SUCCESS, tresult; 607 int i = 0; 608 609 static const char *acls[] = { "allow-proxy", 610 "allow-proxy-on", 611 "allow-query", 612 "allow-query-on", 613 "allow-query-cache", 614 "allow-query-cache-on", 615 "blackhole", 616 "match-clients", 617 "match-destinations", 618 "sortlist", 619 NULL }; 620 621 while (acls[i] != NULL) { 622 tresult = checkacl(acls[i++], actx, NULL, voptions, config, 623 logctx, mctx); 624 if (tresult != ISC_R_SUCCESS) { 625 result = tresult; 626 } 627 } 628 return result; 629 } 630 631 static void 632 dns64_error(const cfg_obj_t *obj, isc_log_t *logctx, isc_netaddr_t *netaddr, 633 unsigned int prefixlen, const char *message) { 634 char buf[ISC_NETADDR_FORMATSIZE + 1]; 635 isc_netaddr_format(netaddr, buf, sizeof(buf)); 636 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "dns64 prefix %s/%u %s", buf, 637 prefixlen, message); 638 } 639 640 static isc_result_t 641 check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, 642 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { 643 isc_result_t result = ISC_R_SUCCESS; 644 const cfg_obj_t *dns64 = NULL; 645 const cfg_obj_t *options; 646 const cfg_listelt_t *element; 647 const cfg_obj_t *map, *obj; 648 isc_netaddr_t na, sa; 649 unsigned int prefixlen; 650 int nbytes; 651 int i; 652 653 static const char *acls[] = { "clients", "exclude", "mapped", NULL }; 654 655 if (voptions != NULL) { 656 cfg_map_get(voptions, "dns64", &dns64); 657 } 658 if (config != NULL && dns64 == NULL) { 659 options = NULL; 660 cfg_map_get(config, "options", &options); 661 if (options != NULL) { 662 cfg_map_get(options, "dns64", &dns64); 663 } 664 } 665 if (dns64 == NULL) { 666 return ISC_R_SUCCESS; 667 } 668 669 for (element = cfg_list_first(dns64); element != NULL; 670 element = cfg_list_next(element)) 671 { 672 map = cfg_listelt_value(element); 673 obj = cfg_map_getname(map); 674 675 cfg_obj_asnetprefix(obj, &na, &prefixlen); 676 if (na.family != AF_INET6) { 677 dns64_error(map, logctx, &na, prefixlen, 678 "must be IPv6"); 679 result = ISC_R_FAILURE; 680 continue; 681 } 682 683 if (na.type.in6.s6_addr[8] != 0) { 684 dns64_error(map, logctx, &na, prefixlen, 685 "bits [64..71] must be zero"); 686 result = ISC_R_FAILURE; 687 continue; 688 } 689 690 if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 && 691 prefixlen != 56 && prefixlen != 64 && prefixlen != 96) 692 { 693 dns64_error(map, logctx, &na, prefixlen, 694 "length is not 32/40/48/56/64/96"); 695 result = ISC_R_FAILURE; 696 continue; 697 } 698 699 for (i = 0; acls[i] != NULL; i++) { 700 obj = NULL; 701 (void)cfg_map_get(map, acls[i], &obj); 702 if (obj != NULL) { 703 dns_acl_t *acl = NULL; 704 isc_result_t tresult; 705 706 tresult = cfg_acl_fromconfig(obj, config, 707 logctx, actx, mctx, 708 0, &acl); 709 if (acl != NULL) { 710 dns_acl_detach(&acl); 711 } 712 if (tresult != ISC_R_SUCCESS) { 713 result = tresult; 714 } 715 } 716 } 717 718 obj = NULL; 719 (void)cfg_map_get(map, "suffix", &obj); 720 if (obj != NULL) { 721 static const unsigned char zeros[16]; 722 isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj)); 723 if (sa.family != AF_INET6) { 724 cfg_obj_log(map, logctx, ISC_LOG_ERROR, 725 "dns64 requires a IPv6 suffix"); 726 result = ISC_R_FAILURE; 727 continue; 728 } 729 nbytes = prefixlen / 8 + 4; 730 if (prefixlen <= 64) { 731 nbytes++; 732 } 733 if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) { 734 char netaddrbuf[ISC_NETADDR_FORMATSIZE]; 735 isc_netaddr_format(&sa, netaddrbuf, 736 sizeof(netaddrbuf)); 737 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 738 "bad suffix '%s' leading " 739 "%u octets not zeros", 740 netaddrbuf, nbytes); 741 result = ISC_R_FAILURE; 742 } 743 } 744 } 745 746 return result; 747 } 748 749 #define CHECK_RRL(cond, pat, val1, val2) \ 750 do { \ 751 if (!(cond)) { \ 752 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, pat, val1, \ 753 val2); \ 754 if (result == ISC_R_SUCCESS) \ 755 result = ISC_R_RANGE; \ 756 } \ 757 } while (0) 758 759 #define CHECK_RRL_RATE(rate, def, max_rate, name) \ 760 do { \ 761 obj = NULL; \ 762 mresult = cfg_map_get(map, name, &obj); \ 763 if (mresult == ISC_R_SUCCESS) { \ 764 rate = cfg_obj_asuint32(obj); \ 765 CHECK_RRL(rate <= max_rate, name " %d > %d", rate, \ 766 max_rate); \ 767 } \ 768 } while (0) 769 770 static isc_result_t 771 check_ratelimit(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, 772 const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { 773 isc_result_t result = ISC_R_SUCCESS; 774 isc_result_t mresult; 775 const cfg_obj_t *map = NULL; 776 const cfg_obj_t *options; 777 const cfg_obj_t *obj; 778 int min_entries, i; 779 int all_per_second; 780 int errors_per_second; 781 int nodata_per_second; 782 int nxdomains_per_second; 783 int referrals_per_second; 784 int responses_per_second; 785 int slip; 786 787 if (voptions != NULL) { 788 cfg_map_get(voptions, "rate-limit", &map); 789 } 790 if (config != NULL && map == NULL) { 791 options = NULL; 792 cfg_map_get(config, "options", &options); 793 if (options != NULL) { 794 cfg_map_get(options, "rate-limit", &map); 795 } 796 } 797 if (map == NULL) { 798 return ISC_R_SUCCESS; 799 } 800 801 min_entries = 500; 802 obj = NULL; 803 mresult = cfg_map_get(map, "min-table-size", &obj); 804 if (mresult == ISC_R_SUCCESS) { 805 min_entries = cfg_obj_asuint32(obj); 806 if (min_entries < 1) { 807 min_entries = 1; 808 } 809 } 810 811 obj = NULL; 812 mresult = cfg_map_get(map, "max-table-size", &obj); 813 if (mresult == ISC_R_SUCCESS) { 814 i = cfg_obj_asuint32(obj); 815 CHECK_RRL(i >= min_entries, 816 "max-table-size %d < min-table-size %d", i, 817 min_entries); 818 } 819 820 CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE, 821 "responses-per-second"); 822 823 CHECK_RRL_RATE(referrals_per_second, responses_per_second, 824 DNS_RRL_MAX_RATE, "referrals-per-second"); 825 CHECK_RRL_RATE(nodata_per_second, responses_per_second, 826 DNS_RRL_MAX_RATE, "nodata-per-second"); 827 CHECK_RRL_RATE(nxdomains_per_second, responses_per_second, 828 DNS_RRL_MAX_RATE, "nxdomains-per-second"); 829 CHECK_RRL_RATE(errors_per_second, responses_per_second, 830 DNS_RRL_MAX_RATE, "errors-per-second"); 831 832 CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second"); 833 834 CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip"); 835 836 obj = NULL; 837 mresult = cfg_map_get(map, "window", &obj); 838 if (mresult == ISC_R_SUCCESS) { 839 i = cfg_obj_asuint32(obj); 840 CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW, 841 "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW); 842 } 843 844 obj = NULL; 845 mresult = cfg_map_get(map, "qps-scale", &obj); 846 if (mresult == ISC_R_SUCCESS) { 847 i = cfg_obj_asuint32(obj); 848 CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, ""); 849 } 850 851 obj = NULL; 852 mresult = cfg_map_get(map, "ipv4-prefix-length", &obj); 853 if (mresult == ISC_R_SUCCESS) { 854 i = cfg_obj_asuint32(obj); 855 CHECK_RRL(i >= 8 && i <= 32, 856 "invalid 'ipv4-prefix-length %d'%s", i, ""); 857 } 858 859 obj = NULL; 860 mresult = cfg_map_get(map, "ipv6-prefix-length", &obj); 861 if (mresult == ISC_R_SUCCESS) { 862 i = cfg_obj_asuint32(obj); 863 CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX, 864 "ipv6-prefix-length %d < 16 or > %d", i, 865 DNS_RRL_MAX_PREFIX); 866 } 867 868 obj = NULL; 869 (void)cfg_map_get(map, "exempt-clients", &obj); 870 if (obj != NULL) { 871 dns_acl_t *acl = NULL; 872 isc_result_t tresult; 873 874 tresult = cfg_acl_fromconfig(obj, config, logctx, actx, mctx, 0, 875 &acl); 876 if (acl != NULL) { 877 dns_acl_detach(&acl); 878 } 879 if (result == ISC_R_SUCCESS) { 880 result = tresult; 881 } 882 } 883 884 return result; 885 } 886 887 static isc_result_t 888 check_fetchlimit(const cfg_obj_t *voptions, const cfg_obj_t *config, 889 isc_log_t *logctx) { 890 const cfg_obj_t *map = NULL; 891 const cfg_obj_t *options = NULL; 892 const cfg_obj_t *obj = NULL; 893 double low, high, discount; 894 895 if (voptions != NULL) { 896 cfg_map_get(voptions, "fetch-quota-params", &map); 897 } 898 if (config != NULL && map == NULL) { 899 options = NULL; 900 cfg_map_get(config, "options", &options); 901 if (options != NULL) { 902 cfg_map_get(options, "fetch-quota-params", &map); 903 } 904 } 905 if (map == NULL) { 906 return ISC_R_SUCCESS; 907 } 908 909 obj = cfg_tuple_get(map, "low"); 910 low = (double)cfg_obj_asfixedpoint(obj) / 100.0; 911 if (low < 0.0 || low > 1.0) { 912 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 913 "fetch-quota-param low value (%0.1f) " 914 "out of range", 915 low); 916 return ISC_R_RANGE; 917 } 918 919 obj = cfg_tuple_get(map, "high"); 920 high = (double)cfg_obj_asfixedpoint(obj) / 100.0; 921 if (high < 0.0 || high > 1.0) { 922 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 923 "fetch-quota-param high value (%0.1f) " 924 "out of range", 925 high); 926 return ISC_R_RANGE; 927 } 928 929 obj = cfg_tuple_get(map, "discount"); 930 discount = (double)cfg_obj_asfixedpoint(obj) / 100.0; 931 if (discount < 0.0 || discount > 1.0) { 932 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 933 "fetch-quota-param discount value (%0.1f) " 934 "out of range", 935 discount); 936 return ISC_R_RANGE; 937 } 938 939 return ISC_R_SUCCESS; 940 } 941 942 /* 943 * Check allow-recursion and allow-recursion-on acls, and also log a 944 * warning if they're inconsistent with the "recursion" option. 945 */ 946 static isc_result_t 947 check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, 948 const char *viewname, const cfg_obj_t *config, 949 isc_log_t *logctx, isc_mem_t *mctx) { 950 const cfg_obj_t *options, *aclobj, *obj = NULL; 951 dns_acl_t *acl = NULL; 952 isc_result_t result = ISC_R_SUCCESS, tresult; 953 bool recursion; 954 const char *forview = " for view "; 955 int i = 0; 956 957 static const char *acls[] = { "allow-recursion", "allow-recursion-on", 958 NULL }; 959 960 if (voptions != NULL) { 961 cfg_map_get(voptions, "recursion", &obj); 962 } 963 if (obj == NULL && config != NULL) { 964 options = NULL; 965 cfg_map_get(config, "options", &options); 966 if (options != NULL) { 967 cfg_map_get(options, "recursion", &obj); 968 } 969 } 970 if (obj == NULL) { 971 recursion = true; 972 } else { 973 recursion = cfg_obj_asboolean(obj); 974 } 975 976 if (viewname == NULL) { 977 viewname = ""; 978 forview = ""; 979 } 980 981 for (i = 0; acls[i] != NULL; i++) { 982 aclobj = options = NULL; 983 acl = NULL; 984 985 if (voptions != NULL) { 986 cfg_map_get(voptions, acls[i], &aclobj); 987 } 988 if (config != NULL && aclobj == NULL) { 989 options = NULL; 990 cfg_map_get(config, "options", &options); 991 if (options != NULL) { 992 cfg_map_get(options, acls[i], &aclobj); 993 } 994 } 995 if (aclobj == NULL) { 996 continue; 997 } 998 999 tresult = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, 1000 0, &acl); 1001 1002 if (tresult != ISC_R_SUCCESS) { 1003 result = tresult; 1004 } 1005 1006 if (acl == NULL) { 1007 continue; 1008 } 1009 1010 if (!recursion && !dns_acl_isnone(acl)) { 1011 cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING, 1012 "both \"recursion no;\" and " 1013 "\"%s\" active%s%s", 1014 acls[i], forview, viewname); 1015 } 1016 1017 if (acl != NULL) { 1018 dns_acl_detach(&acl); 1019 } 1020 } 1021 1022 return result; 1023 } 1024 1025 typedef struct { 1026 const char *name; 1027 unsigned int scale; 1028 unsigned int max; 1029 } intervaltable; 1030 1031 #ifdef HAVE_DNSTAP 1032 typedef struct { 1033 const char *name; 1034 unsigned int min; 1035 unsigned int max; 1036 } fstrmtable; 1037 #endif /* ifdef HAVE_DNSTAP */ 1038 1039 typedef enum { 1040 optlevel_config, 1041 optlevel_options, 1042 optlevel_view, 1043 optlevel_zone 1044 } optlevel_t; 1045 1046 static isc_result_t 1047 check_name(const char *str) { 1048 dns_fixedname_t fixed; 1049 1050 dns_fixedname_init(&fixed); 1051 return dns_name_fromstring(dns_fixedname_name(&fixed), str, 1052 dns_rootname, 0, NULL); 1053 } 1054 1055 static bool 1056 kasp_name_allowed(const cfg_listelt_t *element) { 1057 const char *name = cfg_obj_asstring( 1058 cfg_tuple_get(cfg_listelt_value(element), "name")); 1059 1060 if (strcmp("none", name) == 0) { 1061 return false; 1062 } 1063 if (strcmp("default", name) == 0) { 1064 return false; 1065 } 1066 if (strcmp("insecure", name) == 0) { 1067 return false; 1068 } 1069 return true; 1070 } 1071 1072 static const cfg_obj_t * 1073 find_maplist(const cfg_obj_t *config, const char *listname, const char *name) { 1074 isc_result_t result; 1075 const cfg_obj_t *maplist = NULL; 1076 const cfg_listelt_t *elt = NULL; 1077 1078 REQUIRE(config != NULL); 1079 REQUIRE(name != NULL); 1080 1081 result = cfg_map_get(config, listname, &maplist); 1082 if (result != ISC_R_SUCCESS) { 1083 return NULL; 1084 } 1085 1086 for (elt = cfg_list_first(maplist); elt != NULL; 1087 elt = cfg_list_next(elt)) 1088 { 1089 const cfg_obj_t *map = cfg_listelt_value(elt); 1090 if (strcasecmp(cfg_obj_asstring(cfg_map_getname(map)), name) == 1091 0) 1092 { 1093 return map; 1094 } 1095 } 1096 1097 return NULL; 1098 } 1099 1100 static isc_result_t 1101 check_listener(const cfg_obj_t *listener, const cfg_obj_t *config, 1102 cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx) { 1103 isc_result_t tresult, result = ISC_R_SUCCESS; 1104 const cfg_obj_t *ltup = NULL; 1105 const cfg_obj_t *tlsobj = NULL, *httpobj = NULL; 1106 const cfg_obj_t *portobj = NULL; 1107 const cfg_obj_t *http_server = NULL; 1108 const cfg_obj_t *proxyobj = NULL; 1109 bool do_tls = false, no_tls = false; 1110 dns_acl_t *acl = NULL; 1111 1112 ltup = cfg_tuple_get(listener, "tuple"); 1113 RUNTIME_CHECK(ltup != NULL); 1114 1115 tlsobj = cfg_tuple_get(ltup, "tls"); 1116 if (tlsobj != NULL && cfg_obj_isstring(tlsobj)) { 1117 const char *tlsname = cfg_obj_asstring(tlsobj); 1118 1119 if (strcasecmp(tlsname, "none") == 0) { 1120 no_tls = true; 1121 } else if (strcasecmp(tlsname, "ephemeral") == 0) { 1122 do_tls = true; 1123 } else { 1124 const cfg_obj_t *tlsmap = NULL; 1125 1126 do_tls = true; 1127 1128 tlsmap = find_maplist(config, "tls", tlsname); 1129 if (tlsmap == NULL) { 1130 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 1131 "tls '%s' is not defined", 1132 cfg_obj_asstring(tlsobj)); 1133 result = ISC_R_FAILURE; 1134 } 1135 } 1136 } 1137 1138 httpobj = cfg_tuple_get(ltup, "http"); 1139 if (httpobj != NULL && cfg_obj_isstring(httpobj)) { 1140 const char *httpname = cfg_obj_asstring(httpobj); 1141 1142 if (!do_tls && !no_tls) { 1143 cfg_obj_log(httpobj, logctx, ISC_LOG_ERROR, 1144 "http must specify a 'tls' " 1145 "statement, 'tls ephemeral', or " 1146 "'tls none'"); 1147 result = ISC_R_FAILURE; 1148 } 1149 1150 http_server = find_maplist(config, "http", httpname); 1151 if (http_server == NULL && strcasecmp(httpname, "default") != 0) 1152 { 1153 cfg_obj_log(httpobj, logctx, ISC_LOG_ERROR, 1154 "http '%s' is not defined", 1155 cfg_obj_asstring(httpobj)); 1156 result = ISC_R_FAILURE; 1157 } 1158 } 1159 1160 portobj = cfg_tuple_get(ltup, "port"); 1161 if (cfg_obj_isuint32(portobj) && 1162 cfg_obj_asuint32(portobj) >= UINT16_MAX) 1163 { 1164 cfg_obj_log(portobj, logctx, ISC_LOG_ERROR, 1165 "port value '%u' is out of range", 1166 1167 cfg_obj_asuint32(portobj)); 1168 if (result == ISC_R_SUCCESS) { 1169 result = ISC_R_RANGE; 1170 } 1171 } 1172 1173 proxyobj = cfg_tuple_get(ltup, "proxy"); 1174 if (proxyobj != NULL && cfg_obj_isstring(proxyobj)) { 1175 const char *proxyval = cfg_obj_asstring(proxyobj); 1176 if (proxyval == NULL || 1177 (strcasecmp(proxyval, "encrypted") != 0 && 1178 strcasecmp(proxyval, "plain") != 0)) 1179 { 1180 cfg_obj_log(proxyobj, logctx, ISC_LOG_ERROR, 1181 "'proxy' must have one of the following " 1182 "values: 'plain', 'encrypted'"); 1183 1184 if (result == ISC_R_SUCCESS) { 1185 result = ISC_R_FAILURE; 1186 } 1187 } 1188 1189 if (proxyval != NULL && 1190 strcasecmp(proxyval, "encrypted") == 0 && !do_tls) 1191 { 1192 cfg_obj_log(proxyobj, logctx, ISC_LOG_ERROR, 1193 "'proxy encrypted' can be used only when " 1194 "encryption is enabled by setting 'tls' to " 1195 "a defined value or to 'ephemeral'"); 1196 1197 if (result == ISC_R_SUCCESS) { 1198 result = ISC_R_FAILURE; 1199 } 1200 } 1201 } 1202 1203 tresult = cfg_acl_fromconfig(cfg_tuple_get(listener, "acl"), config, 1204 logctx, actx, mctx, 0, &acl); 1205 if (result == ISC_R_SUCCESS) { 1206 result = tresult; 1207 } 1208 1209 if (acl != NULL) { 1210 dns_acl_detach(&acl); 1211 } 1212 1213 return result; 1214 } 1215 1216 static isc_result_t 1217 check_listeners(const cfg_obj_t *list, const cfg_obj_t *config, 1218 cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx) { 1219 isc_result_t tresult, result = ISC_R_SUCCESS; 1220 const cfg_listelt_t *elt = NULL; 1221 1222 for (elt = cfg_list_first(list); elt != NULL; elt = cfg_list_next(elt)) 1223 { 1224 const cfg_obj_t *obj = cfg_listelt_value(elt); 1225 tresult = check_listener(obj, config, actx, logctx, mctx); 1226 if (result == ISC_R_SUCCESS) { 1227 result = tresult; 1228 } 1229 } 1230 1231 return result; 1232 } 1233 1234 static isc_result_t 1235 check_port(const cfg_obj_t *options, isc_log_t *logctx, const char *type, 1236 in_port_t *portp) { 1237 const cfg_obj_t *portobj = NULL; 1238 isc_result_t result; 1239 1240 result = cfg_map_get(options, type, &portobj); 1241 if (result != ISC_R_SUCCESS) { 1242 return ISC_R_SUCCESS; 1243 } 1244 1245 if (cfg_obj_asuint32(portobj) >= UINT16_MAX) { 1246 cfg_obj_log(portobj, logctx, ISC_LOG_ERROR, 1247 "port '%u' out of range", 1248 cfg_obj_asuint32(portobj)); 1249 return ISC_R_RANGE; 1250 } 1251 1252 SET_IF_NOT_NULL(portp, (in_port_t)cfg_obj_asuint32(portobj)); 1253 return ISC_R_SUCCESS; 1254 } 1255 1256 static isc_result_t 1257 check_options(const cfg_obj_t *options, const cfg_obj_t *config, 1258 bool check_algorithms, isc_log_t *logctx, isc_mem_t *mctx, 1259 optlevel_t optlevel) { 1260 isc_result_t result = ISC_R_SUCCESS; 1261 isc_result_t tresult; 1262 unsigned int i; 1263 const cfg_obj_t *obj = NULL; 1264 const cfg_listelt_t *element; 1265 isc_symtab_t *symtab = NULL; 1266 const char *str; 1267 isc_buffer_t b; 1268 uint32_t lifetime = 3600; 1269 dns_keystorelist_t kslist; 1270 dns_keystore_t *ks = NULL, *ks_next = NULL; 1271 const char *ccalg = "siphash24"; 1272 cfg_aclconfctx_t *actx = NULL; 1273 static const char *sources[] = { 1274 "query-source", 1275 "query-source-v6", 1276 }; 1277 1278 /* 1279 * { "name", scale, value } 1280 * (scale * value) <= UINT32_MAX 1281 */ 1282 static intervaltable intervals[] = { 1283 { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */ 1284 { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */ 1285 { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */ 1286 { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */ 1287 { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */ 1288 { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */ 1289 1290 /* minimum and maximum cache and negative cache TTLs */ 1291 { "min-cache-ttl", 1, MAX_MIN_CACHE_TTL }, /* 90 secs */ 1292 { "max-cache-ttl", 1, UINT32_MAX }, /* no limit */ 1293 { "min-ncache-ttl", 1, MAX_MIN_NCACHE_TTL }, /* 90 secs */ 1294 { "max-ncache-ttl", 1, MAX_MAX_NCACHE_TTL }, /* 7 days */ 1295 }; 1296 1297 static const char *server_contact[] = { "empty-server", "empty-contact", 1298 "dns64-server", "dns64-contact", 1299 NULL }; 1300 1301 #ifdef HAVE_DNSTAP 1302 static fstrmtable fstrm[] = { 1303 { "fstrm-set-buffer-hint", FSTRM_IOTHR_BUFFER_HINT_MIN, 1304 FSTRM_IOTHR_BUFFER_HINT_MAX }, 1305 { "fstrm-set-flush-timeout", FSTRM_IOTHR_FLUSH_TIMEOUT_MIN, 1306 FSTRM_IOTHR_FLUSH_TIMEOUT_MAX }, 1307 { "fstrm-set-input-queue-size", 1308 FSTRM_IOTHR_INPUT_QUEUE_SIZE_MIN, 1309 FSTRM_IOTHR_INPUT_QUEUE_SIZE_MAX }, 1310 { "fstrm-set-output-notify-threshold", 1311 FSTRM_IOTHR_QUEUE_NOTIFY_THRESHOLD_MIN, 0 }, 1312 { "fstrm-set-output-queue-size", 1313 FSTRM_IOTHR_OUTPUT_QUEUE_SIZE_MIN, 1314 FSTRM_IOTHR_OUTPUT_QUEUE_SIZE_MAX }, 1315 { "fstrm-set-reopen-interval", FSTRM_IOTHR_REOPEN_INTERVAL_MIN, 1316 FSTRM_IOTHR_REOPEN_INTERVAL_MAX } 1317 }; 1318 #endif /* ifdef HAVE_DNSTAP */ 1319 1320 if (optlevel == optlevel_options) { 1321 /* 1322 * Check port values, and record "port" for later use. 1323 */ 1324 tresult = check_port(options, logctx, "port", &dnsport); 1325 if (tresult != ISC_R_SUCCESS) { 1326 result = tresult; 1327 } 1328 tresult = check_port(options, logctx, "tls-port", NULL); 1329 if (tresult != ISC_R_SUCCESS) { 1330 result = tresult; 1331 } 1332 tresult = check_port(options, logctx, "http-port", NULL); 1333 if (tresult != ISC_R_SUCCESS) { 1334 result = tresult; 1335 } 1336 tresult = check_port(options, logctx, "https-port", NULL); 1337 if (tresult != ISC_R_SUCCESS) { 1338 result = tresult; 1339 } 1340 } 1341 1342 if (optlevel == optlevel_options || optlevel == optlevel_view) { 1343 /* 1344 * Warn if query-source or query-source-v6 options specify 1345 * a port, and fail if they specify the DNS port. 1346 */ 1347 unsigned int none_found = false; 1348 1349 for (i = 0; i < ARRAY_SIZE(sources); i++) { 1350 obj = NULL; 1351 (void)cfg_map_get(options, sources[i], &obj); 1352 if (obj != NULL) { 1353 if (cfg_obj_issockaddr(obj)) { 1354 const isc_sockaddr_t *sa = 1355 cfg_obj_assockaddr(obj); 1356 in_port_t port = 1357 isc_sockaddr_getport(sa); 1358 if (port == dnsport) { 1359 cfg_obj_log(obj, logctx, 1360 ISC_LOG_ERROR, 1361 "'%s' cannot " 1362 "specify the " 1363 "DNS listener port " 1364 "(%d)", 1365 sources[i], port); 1366 result = ISC_R_FAILURE; 1367 } else if (port != 0) { 1368 cfg_obj_log( 1369 obj, logctx, 1370 ISC_LOG_WARNING, 1371 "'%s': specifying a " 1372 "port " 1373 "is not recommended", 1374 sources[i]); 1375 } 1376 } else if (cfg_obj_isvoid(obj)) { 1377 none_found++; 1378 1379 if (none_found > 1) { 1380 cfg_obj_log(obj, logctx, 1381 ISC_LOG_ERROR, 1382 "query-source and " 1383 "query-source-v6 " 1384 "can't be " 1385 "none at the same " 1386 "time."); 1387 result = ISC_R_FAILURE; 1388 break; 1389 } 1390 } 1391 } 1392 } 1393 } 1394 1395 /* 1396 * Check that fields specified in units of time other than seconds 1397 * have reasonable values. 1398 */ 1399 for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) { 1400 uint32_t val; 1401 obj = NULL; 1402 (void)cfg_map_get(options, intervals[i].name, &obj); 1403 if (obj == NULL) { 1404 continue; 1405 } 1406 if (cfg_obj_isduration(obj)) { 1407 val = cfg_obj_asduration(obj); 1408 } else { 1409 val = cfg_obj_asuint32(obj); 1410 } 1411 if (val > intervals[i].max) { 1412 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1413 "%s '%u' is out of range (0..%u)", 1414 intervals[i].name, val, intervals[i].max); 1415 result = ISC_R_RANGE; 1416 } else if (val > (UINT32_MAX / intervals[i].scale)) { 1417 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1418 "%s '%d' is out of range", 1419 intervals[i].name, val); 1420 result = ISC_R_RANGE; 1421 } 1422 } 1423 1424 /* 1425 * Check key-store. 1426 */ 1427 ISC_LIST_INIT(kslist); 1428 1429 obj = NULL; 1430 (void)cfg_map_get(options, "key-store", &obj); 1431 if (obj != NULL) { 1432 if (optlevel != optlevel_config) { 1433 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1434 "may only be configured at the top level"); 1435 if (result == ISC_R_SUCCESS) { 1436 result = ISC_R_FAILURE; 1437 } 1438 } else if (cfg_obj_islist(obj)) { 1439 for (element = cfg_list_first(obj); element != NULL; 1440 element = cfg_list_next(element)) 1441 { 1442 isc_result_t ret; 1443 const char *val; 1444 cfg_obj_t *kconfig = cfg_listelt_value(element); 1445 const cfg_obj_t *kopt; 1446 const cfg_obj_t *kobj = NULL; 1447 if (!cfg_obj_istuple(kconfig)) { 1448 continue; 1449 } 1450 val = cfg_obj_asstring( 1451 cfg_tuple_get(kconfig, "name")); 1452 if (strcmp(DNS_KEYSTORE_KEYDIRECTORY, val) == 0) 1453 { 1454 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1455 "name '%s' not allowed", 1456 DNS_KEYSTORE_KEYDIRECTORY); 1457 if (result == ISC_R_SUCCESS) { 1458 result = ISC_R_FAILURE; 1459 continue; 1460 } 1461 } 1462 1463 kopt = cfg_tuple_get(kconfig, "options"); 1464 if (cfg_map_get(kopt, "directory", &kobj) == 1465 ISC_R_SUCCESS) 1466 { 1467 val = cfg_obj_asstring(kobj); 1468 ret = isc_file_isdirectory(val); 1469 switch (ret) { 1470 case ISC_R_SUCCESS: 1471 break; 1472 case ISC_R_FILENOTFOUND: 1473 cfg_obj_log( 1474 obj, logctx, 1475 ISC_LOG_WARNING, 1476 "key-store directory: " 1477 "'%s' does not exist", 1478 val); 1479 break; 1480 case ISC_R_INVALIDFILE: 1481 cfg_obj_log( 1482 obj, logctx, 1483 ISC_LOG_WARNING, 1484 "key-store directory: " 1485 "'%s' is not a " 1486 "directory", 1487 val); 1488 break; 1489 default: 1490 cfg_obj_log( 1491 obj, logctx, 1492 ISC_LOG_WARNING, 1493 "key-store directory: " 1494 "'%s' %s", 1495 val, 1496 isc_result_totext(ret)); 1497 if (result == ISC_R_SUCCESS) { 1498 result = ret; 1499 } 1500 } 1501 } 1502 1503 ret = cfg_keystore_fromconfig(kconfig, mctx, 1504 logctx, NULL, 1505 &kslist, NULL); 1506 if (ret != ISC_R_SUCCESS) { 1507 if (result == ISC_R_SUCCESS) { 1508 result = ret; 1509 } 1510 } 1511 } 1512 } 1513 } 1514 1515 /* 1516 * Add default key-store "key-directory". 1517 */ 1518 tresult = cfg_keystore_fromconfig(NULL, mctx, logctx, NULL, &kslist, 1519 NULL); 1520 if (tresult != ISC_R_SUCCESS) { 1521 if (result == ISC_R_SUCCESS) { 1522 result = tresult; 1523 } 1524 } 1525 1526 /* 1527 * Check dnssec-policy. 1528 */ 1529 obj = NULL; 1530 (void)cfg_map_get(options, "dnssec-policy", &obj); 1531 if (obj != NULL) { 1532 bool bad_kasp = false; 1533 bool bad_name = false; 1534 unsigned int kaspopts = (ISCCFG_KASPCONF_CHECK_KEYLIST | 1535 ISCCFG_KASPCONF_LOG_ERRORS); 1536 if (check_algorithms) { 1537 kaspopts |= ISCCFG_KASPCONF_CHECK_ALGORITHMS; 1538 } 1539 1540 if (optlevel != optlevel_config && !cfg_obj_isstring(obj)) { 1541 bad_kasp = true; 1542 } else if (optlevel == optlevel_config) { 1543 dns_kasplist_t list; 1544 dns_kasp_t *kasp = NULL, *kasp_next = NULL; 1545 1546 ISC_LIST_INIT(list); 1547 1548 if (cfg_obj_islist(obj)) { 1549 for (element = cfg_list_first(obj); 1550 element != NULL; 1551 element = cfg_list_next(element)) 1552 { 1553 isc_result_t ret; 1554 cfg_obj_t *kconfig = 1555 cfg_listelt_value(element); 1556 1557 if (!cfg_obj_istuple(kconfig)) { 1558 bad_kasp = true; 1559 continue; 1560 } 1561 if (!kasp_name_allowed(element)) { 1562 bad_name = true; 1563 continue; 1564 } 1565 1566 ret = cfg_kasp_fromconfig( 1567 kconfig, NULL, kaspopts, mctx, 1568 logctx, &kslist, &list, &kasp); 1569 if (ret != ISC_R_SUCCESS) { 1570 if (result == ISC_R_SUCCESS) { 1571 result = ret; 1572 } 1573 } 1574 1575 if (kasp != NULL) { 1576 dns_kasp_detach(&kasp); 1577 } 1578 } 1579 } 1580 1581 for (kasp = ISC_LIST_HEAD(list); kasp != NULL; 1582 kasp = kasp_next) 1583 { 1584 kasp_next = ISC_LIST_NEXT(kasp, link); 1585 ISC_LIST_UNLINK(list, kasp, link); 1586 dns_kasp_detach(&kasp); 1587 } 1588 } 1589 1590 if (bad_kasp) { 1591 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1592 "dnssec-policy may only be configured at " 1593 "the top level, please use name reference " 1594 "at the zone level"); 1595 if (result == ISC_R_SUCCESS) { 1596 result = ISC_R_FAILURE; 1597 } 1598 } else if (bad_name) { 1599 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1600 "dnssec-policy name may not be 'insecure', " 1601 "'none', or 'default' (which are built-in " 1602 "policies)"); 1603 if (result == ISC_R_SUCCESS) { 1604 result = ISC_R_FAILURE; 1605 } 1606 } 1607 } 1608 1609 /* 1610 * Cleanup key-store. 1611 */ 1612 for (ks = ISC_LIST_HEAD(kslist); ks != NULL; ks = ks_next) { 1613 ks_next = ISC_LIST_NEXT(ks, link); 1614 ISC_LIST_UNLINK(kslist, ks, link); 1615 dns_keystore_detach(&ks); 1616 } 1617 1618 /* 1619 * Other checks. 1620 */ 1621 obj = NULL; 1622 cfg_map_get(options, "max-rsa-exponent-size", &obj); 1623 if (obj != NULL) { 1624 uint32_t val; 1625 1626 val = cfg_obj_asuint32(obj); 1627 if (val != 0 && (val < 35 || val > 4096)) { 1628 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1629 "max-rsa-exponent-size '%u' is out of " 1630 "range (35..4096)", 1631 val); 1632 result = ISC_R_RANGE; 1633 } 1634 } 1635 1636 obj = NULL; 1637 (void)cfg_map_get(options, "preferred-glue", &obj); 1638 if (obj != NULL) { 1639 str = cfg_obj_asstring(obj); 1640 if (strcasecmp(str, "a") != 0 && strcasecmp(str, "aaaa") != 0 && 1641 strcasecmp(str, "none") != 0) 1642 { 1643 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1644 "preferred-glue unexpected value '%s'", 1645 str); 1646 } 1647 } 1648 1649 /* 1650 * Set supported DNSSEC algorithms. 1651 */ 1652 obj = NULL; 1653 (void)cfg_map_get(options, "disable-algorithms", &obj); 1654 if (obj != NULL) { 1655 for (element = cfg_list_first(obj); element != NULL; 1656 element = cfg_list_next(element)) 1657 { 1658 obj = cfg_listelt_value(element); 1659 tresult = disabled_algorithms(obj, logctx); 1660 if (tresult != ISC_R_SUCCESS) { 1661 result = tresult; 1662 } 1663 } 1664 } 1665 1666 /* 1667 * Set supported DS digest types. 1668 */ 1669 obj = NULL; 1670 (void)cfg_map_get(options, "disable-ds-digests", &obj); 1671 if (obj != NULL) { 1672 for (element = cfg_list_first(obj); element != NULL; 1673 element = cfg_list_next(element)) 1674 { 1675 obj = cfg_listelt_value(element); 1676 tresult = disabled_ds_digests(obj, logctx); 1677 if (tresult != ISC_R_SUCCESS) { 1678 result = tresult; 1679 } 1680 } 1681 } 1682 1683 /* 1684 * Check dnssec-must-be-secure. 1685 */ 1686 obj = NULL; 1687 (void)cfg_map_get(options, "dnssec-must-be-secure", &obj); 1688 if (obj != NULL) { 1689 tresult = isc_symtab_create(mctx, 100, freekey, mctx, false, 1690 &symtab); 1691 if (tresult != ISC_R_SUCCESS) { 1692 result = tresult; 1693 } else { 1694 for (element = cfg_list_first(obj); element != NULL; 1695 element = cfg_list_next(element)) 1696 { 1697 obj = cfg_listelt_value(element); 1698 tresult = mustbesecure(obj, symtab, logctx, 1699 mctx); 1700 if (result == ISC_R_SUCCESS && 1701 tresult != ISC_R_SUCCESS) 1702 { 1703 result = tresult; 1704 } 1705 } 1706 } 1707 if (symtab != NULL) { 1708 isc_symtab_destroy(&symtab); 1709 } 1710 } 1711 1712 /* 1713 * Check server/contacts for syntactic validity. 1714 */ 1715 for (i = 0; server_contact[i] != NULL; i++) { 1716 obj = NULL; 1717 (void)cfg_map_get(options, server_contact[i], &obj); 1718 if (obj != NULL) { 1719 str = cfg_obj_asstring(obj); 1720 if (check_name(str) != ISC_R_SUCCESS) { 1721 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1722 "%s: invalid name '%s'", 1723 server_contact[i], str); 1724 if (result == ISC_R_SUCCESS) { 1725 result = ISC_R_FAILURE; 1726 } 1727 } 1728 } 1729 } 1730 1731 /* 1732 * Check empty zone configuration. 1733 */ 1734 obj = NULL; 1735 (void)cfg_map_get(options, "disable-empty-zone", &obj); 1736 for (element = cfg_list_first(obj); element != NULL; 1737 element = cfg_list_next(element)) 1738 { 1739 obj = cfg_listelt_value(element); 1740 str = cfg_obj_asstring(obj); 1741 if (check_name(str) != ISC_R_SUCCESS) { 1742 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1743 "disable-empty-zone: invalid name '%s'", 1744 str); 1745 if (result == ISC_R_SUCCESS) { 1746 result = ISC_R_FAILURE; 1747 } 1748 } 1749 } 1750 1751 /* 1752 * Check that server-id is not too long. 1753 * 1024 bytes should be big enough. 1754 */ 1755 obj = NULL; 1756 (void)cfg_map_get(options, "server-id", &obj); 1757 if (obj != NULL && cfg_obj_isstring(obj) && 1758 strlen(cfg_obj_asstring(obj)) > 1024U) 1759 { 1760 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1761 "'server-id' too big (>1024 bytes)"); 1762 if (result == ISC_R_SUCCESS) { 1763 result = ISC_R_FAILURE; 1764 } 1765 } 1766 1767 obj = NULL; 1768 (void)cfg_map_get(options, "nta-lifetime", &obj); 1769 if (obj != NULL) { 1770 lifetime = cfg_obj_asduration(obj); 1771 if (lifetime > 604800) { /* 7 days */ 1772 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1773 "'nta-lifetime' cannot exceed one week"); 1774 if (result == ISC_R_SUCCESS) { 1775 result = ISC_R_RANGE; 1776 } 1777 } else if (lifetime == 0) { 1778 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1779 "'nta-lifetime' may not be zero"); 1780 if (result == ISC_R_SUCCESS) { 1781 result = ISC_R_RANGE; 1782 } 1783 } 1784 } 1785 1786 obj = NULL; 1787 (void)cfg_map_get(options, "nta-recheck", &obj); 1788 if (obj != NULL) { 1789 uint32_t recheck = cfg_obj_asduration(obj); 1790 if (recheck > 604800) { /* 7 days */ 1791 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1792 "'nta-recheck' cannot exceed one week"); 1793 if (result == ISC_R_SUCCESS) { 1794 result = ISC_R_RANGE; 1795 } 1796 } 1797 1798 if (recheck > lifetime) { 1799 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 1800 "'nta-recheck' (%d seconds) is " 1801 "greater than 'nta-lifetime' " 1802 "(%d seconds)", 1803 recheck, lifetime); 1804 } 1805 } 1806 1807 obj = NULL; 1808 (void)cfg_map_get(options, "cookie-algorithm", &obj); 1809 if (obj != NULL) { 1810 ccalg = cfg_obj_asstring(obj); 1811 if (strcasecmp(ccalg, "aes") == 0) { 1812 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 1813 "cookie-algorithm 'aes' is obsolete and " 1814 "should be removed"); 1815 if (result == ISC_R_SUCCESS) { 1816 result = ISC_R_FAILURE; 1817 } 1818 } 1819 } 1820 1821 obj = NULL; 1822 (void)cfg_map_get(options, "cookie-secret", &obj); 1823 if (obj != NULL) { 1824 unsigned char secret[32]; 1825 1826 for (element = cfg_list_first(obj); element != NULL; 1827 element = cfg_list_next(element)) 1828 { 1829 unsigned int usedlength; 1830 1831 obj = cfg_listelt_value(element); 1832 str = cfg_obj_asstring(obj); 1833 1834 memset(secret, 0, sizeof(secret)); 1835 isc_buffer_init(&b, secret, sizeof(secret)); 1836 tresult = isc_hex_decodestring(str, &b); 1837 if (tresult == ISC_R_NOSPACE) { 1838 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1839 "cookie-secret: too long"); 1840 } else if (tresult != ISC_R_SUCCESS) { 1841 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1842 "cookie-secret: invalid hex " 1843 "string"); 1844 } 1845 if (tresult != ISC_R_SUCCESS) { 1846 if (result == ISC_R_SUCCESS) { 1847 result = tresult; 1848 } 1849 continue; 1850 } 1851 1852 usedlength = isc_buffer_usedlength(&b); 1853 if (strcasecmp(ccalg, "siphash24") == 0 && 1854 usedlength != ISC_SIPHASH24_KEY_LENGTH) 1855 { 1856 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1857 "SipHash-2-4 cookie-secret must be " 1858 "128 bits"); 1859 if (result == ISC_R_SUCCESS) { 1860 result = ISC_R_RANGE; 1861 } 1862 } 1863 } 1864 } 1865 1866 #ifdef HAVE_DNSTAP 1867 for (i = 0; i < sizeof(fstrm) / sizeof(fstrm[0]); i++) { 1868 uint32_t value; 1869 1870 obj = NULL; 1871 (void)cfg_map_get(options, fstrm[i].name, &obj); 1872 if (obj == NULL) { 1873 continue; 1874 } 1875 1876 if (cfg_obj_isduration(obj)) { 1877 value = cfg_obj_asduration(obj); 1878 } else { 1879 value = cfg_obj_asuint32(obj); 1880 } 1881 if (value < fstrm[i].min || 1882 (fstrm[i].max != 0U && value > fstrm[i].max)) 1883 { 1884 if (fstrm[i].max != 0U) { 1885 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1886 "%s '%u' out of range (%u..%u)", 1887 fstrm[i].name, value, fstrm[i].min, 1888 fstrm[i].max); 1889 } else { 1890 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1891 "%s out of range (%u < %u)", 1892 fstrm[i].name, value, fstrm[i].min); 1893 } 1894 if (result == ISC_R_SUCCESS) { 1895 result = ISC_R_RANGE; 1896 } 1897 } 1898 1899 if (strcmp(fstrm[i].name, "fstrm-set-input-queue-size") == 0) { 1900 int bits = 0; 1901 do { 1902 bits += value & 0x1; 1903 value >>= 1; 1904 } while (value != 0U); 1905 if (bits != 1) { 1906 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1907 "%s '%u' not a power-of-2", 1908 fstrm[i].name, 1909 cfg_obj_asuint32(obj)); 1910 if (result == ISC_R_SUCCESS) { 1911 result = ISC_R_RANGE; 1912 } 1913 } 1914 } 1915 } 1916 1917 /* Check that dnstap-ouput values are consistent */ 1918 obj = NULL; 1919 (void)cfg_map_get(options, "dnstap-output", &obj); 1920 if (obj != NULL) { 1921 const cfg_obj_t *obj2; 1922 dns_dtmode_t dmode; 1923 1924 obj2 = cfg_tuple_get(obj, "mode"); 1925 if (obj2 == NULL) { 1926 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1927 "dnstap-output mode not found"); 1928 if (result == ISC_R_SUCCESS) { 1929 result = ISC_R_FAILURE; 1930 } 1931 } else { 1932 if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0) { 1933 dmode = dns_dtmode_file; 1934 } else { 1935 dmode = dns_dtmode_unix; 1936 } 1937 1938 obj2 = cfg_tuple_get(obj, "size"); 1939 if (obj2 != NULL && !cfg_obj_isvoid(obj2) && 1940 dmode == dns_dtmode_unix) 1941 { 1942 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1943 "dnstap-output size " 1944 "cannot be set with mode unix"); 1945 if (result == ISC_R_SUCCESS) { 1946 result = ISC_R_FAILURE; 1947 } 1948 } 1949 1950 obj2 = cfg_tuple_get(obj, "versions"); 1951 if (obj2 != NULL && !cfg_obj_isvoid(obj2) && 1952 dmode == dns_dtmode_unix) 1953 { 1954 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1955 "dnstap-output versions " 1956 "cannot be set with mode unix"); 1957 if (result == ISC_R_SUCCESS) { 1958 result = ISC_R_FAILURE; 1959 } 1960 } 1961 1962 obj2 = cfg_tuple_get(obj, "suffix"); 1963 if (obj2 != NULL && !cfg_obj_isvoid(obj2) && 1964 dmode == dns_dtmode_unix) 1965 { 1966 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1967 "dnstap-output suffix " 1968 "cannot be set with mode unix"); 1969 if (result == ISC_R_SUCCESS) { 1970 result = ISC_R_FAILURE; 1971 } 1972 } 1973 } 1974 } 1975 #endif /* ifdef HAVE_DNSTAP */ 1976 1977 obj = NULL; 1978 (void)cfg_map_get(options, "lmdb-mapsize", &obj); 1979 if (obj != NULL) { 1980 uint64_t mapsize = cfg_obj_asuint64(obj); 1981 1982 if (mapsize < (1ULL << 20)) { /* 1 megabyte */ 1983 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1984 "'lmdb-mapsize " 1985 "%" PRId64 "' " 1986 "is too small", 1987 mapsize); 1988 if (result == ISC_R_SUCCESS) { 1989 result = ISC_R_RANGE; 1990 } 1991 } else if (mapsize > (1ULL << 40)) { /* 1 terabyte */ 1992 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 1993 "'lmdb-mapsize " 1994 "%" PRId64 "' " 1995 "is too large", 1996 mapsize); 1997 if (result == ISC_R_SUCCESS) { 1998 result = ISC_R_RANGE; 1999 } 2000 } 2001 } 2002 2003 obj = NULL; 2004 (void)cfg_map_get(options, "max-ixfr-ratio", &obj); 2005 if (obj != NULL && cfg_obj_ispercentage(obj)) { 2006 uint32_t percent = cfg_obj_aspercentage(obj); 2007 if (percent == 0) { 2008 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2009 "'ixfr-max-ratio' must be a nonzero " 2010 "percentage or 'unlimited')"); 2011 if (result == ISC_R_SUCCESS) { 2012 result = ISC_R_RANGE; 2013 } 2014 } else if (percent > 100) { 2015 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 2016 "'ixfr-max-ratio %d%%' exceeds 100%%", 2017 percent); 2018 } 2019 } 2020 2021 obj = NULL; 2022 (void)cfg_map_get(options, "check-names", &obj); 2023 if (obj != NULL && !cfg_obj_islist(obj)) { 2024 obj = NULL; 2025 } 2026 if (obj != NULL) { 2027 /* Note: SEC is defined in <sys/time.h> on some platforms. */ 2028 enum { MAS = 1, PRI = 2, SLA = 4, SCN = 8 } values = 0; 2029 for (const cfg_listelt_t *el = cfg_list_first(obj); el != NULL; 2030 el = cfg_list_next(el)) 2031 { 2032 const cfg_obj_t *tuple = cfg_listelt_value(el); 2033 const cfg_obj_t *type = cfg_tuple_get(tuple, "type"); 2034 const char *keyword = cfg_obj_asstring(type); 2035 if (strcasecmp(keyword, "primary") == 0) { 2036 if ((values & PRI) == PRI) { 2037 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2038 "'check-names primary' " 2039 "duplicated"); 2040 if (result == ISC_R_SUCCESS) { 2041 result = ISC_R_FAILURE; 2042 } 2043 } 2044 values |= PRI; 2045 } else if (strcasecmp(keyword, "master") == 0) { 2046 if ((values & MAS) == MAS) { 2047 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2048 "'check-names master' " 2049 "duplicated"); 2050 if (result == ISC_R_SUCCESS) { 2051 result = ISC_R_FAILURE; 2052 } 2053 } 2054 values |= MAS; 2055 } else if (strcasecmp(keyword, "secondary") == 0) { 2056 if ((values & SCN) == SCN) { 2057 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2058 "'check-names secondary' " 2059 "duplicated"); 2060 if (result == ISC_R_SUCCESS) { 2061 result = ISC_R_FAILURE; 2062 } 2063 } 2064 values |= SCN; 2065 } else if (strcasecmp(keyword, "slave") == 0) { 2066 if ((values & SLA) == SLA) { 2067 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2068 "'check-names slave' " 2069 "duplicated"); 2070 if (result == ISC_R_SUCCESS) { 2071 result = ISC_R_FAILURE; 2072 } 2073 } 2074 values |= SLA; 2075 } 2076 } 2077 2078 if ((values & (PRI | MAS)) == (PRI | MAS)) { 2079 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2080 "'check-names' cannot take both " 2081 "'primary' and 'master'"); 2082 if (result == ISC_R_SUCCESS) { 2083 result = ISC_R_FAILURE; 2084 } 2085 } 2086 2087 if ((values & (SCN | SLA)) == (SCN | SLA)) { 2088 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2089 "'check-names' cannot take both " 2090 "'secondary' and 'slave'"); 2091 if (result == ISC_R_SUCCESS) { 2092 result = ISC_R_FAILURE; 2093 } 2094 } 2095 } 2096 2097 obj = NULL; 2098 (void)cfg_map_get(options, "stale-refresh-time", &obj); 2099 if (obj != NULL) { 2100 uint32_t refresh_time = cfg_obj_asduration(obj); 2101 if (refresh_time > 0 && refresh_time < 30) { 2102 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 2103 "'stale-refresh-time' should either be 0 " 2104 "or otherwise 30 seconds or higher"); 2105 } 2106 } 2107 2108 cfg_aclconfctx_create(mctx, &actx); 2109 2110 obj = NULL; 2111 (void)cfg_map_get(options, "sig0checks-quota-exempt", &obj); 2112 if (obj != NULL) { 2113 dns_acl_t *acl = NULL; 2114 2115 tresult = cfg_acl_fromconfig(obj, config, logctx, actx, mctx, 0, 2116 &acl); 2117 if (acl != NULL) { 2118 dns_acl_detach(&acl); 2119 } 2120 if (result == ISC_R_SUCCESS) { 2121 result = tresult; 2122 } 2123 } 2124 2125 obj = NULL; 2126 (void)cfg_map_get(options, "listen-on", &obj); 2127 if (obj != NULL) { 2128 INSIST(config != NULL); 2129 tresult = check_listeners(obj, config, actx, logctx, mctx); 2130 if (result == ISC_R_SUCCESS) { 2131 result = tresult; 2132 } 2133 } 2134 2135 obj = NULL; 2136 (void)cfg_map_get(options, "listen-on-v6", &obj); 2137 if (obj != NULL) { 2138 INSIST(config != NULL); 2139 tresult = check_listeners(obj, config, actx, logctx, mctx); 2140 if (result == ISC_R_SUCCESS) { 2141 result = tresult; 2142 } 2143 } 2144 2145 obj = NULL; 2146 (void)cfg_map_get(options, "max-query-restarts", &obj); 2147 if (obj != NULL) { 2148 uint32_t restarts = cfg_obj_asuint32(obj); 2149 if (restarts == 0 || restarts > 255) { 2150 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2151 "'max-query-restarts' is out of " 2152 "range 1..255)"); 2153 if (result == ISC_R_SUCCESS) { 2154 result = ISC_R_RANGE; 2155 } 2156 } 2157 } 2158 2159 if (actx != NULL) { 2160 cfg_aclconfctx_detach(&actx); 2161 } 2162 2163 return result; 2164 } 2165 2166 /* 2167 * Check "remote-servers" style list. 2168 */ 2169 static isc_result_t 2170 check_remoteserverlist(const cfg_obj_t *cctx, const char *list, 2171 isc_log_t *logctx, isc_symtab_t *symtab, 2172 isc_mem_t *mctx) { 2173 isc_symvalue_t symvalue; 2174 isc_result_t result, tresult; 2175 const cfg_obj_t *obj = NULL; 2176 const cfg_listelt_t *elt; 2177 2178 result = cfg_map_get(cctx, list, &obj); 2179 if (result != ISC_R_SUCCESS) { 2180 return ISC_R_SUCCESS; 2181 } 2182 2183 elt = cfg_list_first(obj); 2184 while (elt != NULL) { 2185 char *tmp; 2186 const char *name; 2187 2188 obj = cfg_listelt_value(elt); 2189 name = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 2190 2191 tmp = isc_mem_strdup(mctx, name); 2192 symvalue.as_cpointer = obj; 2193 tresult = isc_symtab_define(symtab, tmp, 1, symvalue, 2194 isc_symexists_reject); 2195 if (tresult == ISC_R_EXISTS) { 2196 const char *file = NULL; 2197 unsigned int line; 2198 2199 RUNTIME_CHECK( 2200 isc_symtab_lookup(symtab, tmp, 1, &symvalue) == 2201 ISC_R_SUCCESS); 2202 file = cfg_obj_file(symvalue.as_cpointer); 2203 line = cfg_obj_line(symvalue.as_cpointer); 2204 2205 if (file == NULL) { 2206 file = "<unknown file>"; 2207 } 2208 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2209 "%s list '%s' is duplicated: " 2210 "also defined at %s:%u", 2211 list, name, file, line); 2212 isc_mem_free(mctx, tmp); 2213 result = tresult; 2214 break; 2215 } 2216 2217 uint32_t dummy = 0; 2218 result = validate_remotes(obj, cctx, &dummy, logctx, mctx); 2219 if (result != ISC_R_SUCCESS) { 2220 break; 2221 } 2222 2223 elt = cfg_list_next(elt); 2224 } 2225 return result; 2226 } 2227 2228 /* 2229 * Check remote-server lists for duplicates. 2230 */ 2231 static isc_result_t 2232 check_remoteserverlists(const cfg_obj_t *cctx, isc_log_t *logctx, 2233 isc_mem_t *mctx) { 2234 isc_result_t result, tresult; 2235 isc_symtab_t *symtab = NULL; 2236 2237 result = isc_symtab_create(mctx, 100, freekey, mctx, false, &symtab); 2238 if (result != ISC_R_SUCCESS) { 2239 return result; 2240 } 2241 tresult = check_remoteserverlist(cctx, "remote-servers", logctx, symtab, 2242 mctx); 2243 if (tresult != ISC_R_SUCCESS) { 2244 result = tresult; 2245 } 2246 /* parental-agents, primaries, masters are treated as synonyms */ 2247 tresult = check_remoteserverlist(cctx, "parental-agents", logctx, 2248 symtab, mctx); 2249 if (tresult != ISC_R_SUCCESS) { 2250 result = tresult; 2251 } 2252 tresult = check_remoteserverlist(cctx, "primaries", logctx, symtab, 2253 mctx); 2254 if (tresult != ISC_R_SUCCESS) { 2255 result = tresult; 2256 } 2257 tresult = check_remoteserverlist(cctx, "masters", logctx, symtab, mctx); 2258 if (tresult != ISC_R_SUCCESS) { 2259 result = tresult; 2260 } 2261 isc_symtab_destroy(&symtab); 2262 return result; 2263 } 2264 2265 #if HAVE_LIBNGHTTP2 2266 static isc_result_t 2267 check_httpserver(const cfg_obj_t *http, isc_log_t *logctx, 2268 isc_symtab_t *symtab) { 2269 isc_result_t result, tresult; 2270 const char *name = cfg_obj_asstring(cfg_map_getname(http)); 2271 const cfg_obj_t *eps = NULL; 2272 const cfg_listelt_t *elt = NULL; 2273 isc_symvalue_t symvalue; 2274 2275 if (strcasecmp(name, "default") == 0) { 2276 cfg_obj_log(http, logctx, ISC_LOG_ERROR, 2277 "'http' name cannot be '%s' (which is a " 2278 "built-in configuration)", 2279 name); 2280 result = ISC_R_FAILURE; 2281 } else { 2282 /* Check for duplicates */ 2283 symvalue.as_cpointer = http; 2284 result = isc_symtab_define(symtab, name, 1, symvalue, 2285 isc_symexists_reject); 2286 if (result == ISC_R_EXISTS) { 2287 const char *file = NULL; 2288 unsigned int line; 2289 2290 tresult = isc_symtab_lookup(symtab, name, 1, &symvalue); 2291 RUNTIME_CHECK(tresult == ISC_R_SUCCESS); 2292 2293 line = cfg_obj_line(symvalue.as_cpointer); 2294 file = cfg_obj_file(symvalue.as_cpointer); 2295 if (file == NULL) { 2296 file = "<unknown file>"; 2297 } 2298 2299 cfg_obj_log(http, logctx, ISC_LOG_ERROR, 2300 "http '%s' is duplicated: " 2301 "also defined at %s:%u", 2302 name, file, line); 2303 } 2304 } 2305 2306 /* Check endpoints are valid */ 2307 tresult = cfg_map_get(http, "endpoints", &eps); 2308 if (tresult == ISC_R_SUCCESS) { 2309 for (elt = cfg_list_first(eps); elt != NULL; 2310 elt = cfg_list_next(elt)) 2311 { 2312 const cfg_obj_t *ep = cfg_listelt_value(elt); 2313 const char *path = cfg_obj_asstring(ep); 2314 if (!isc_nm_http_path_isvalid(path)) { 2315 cfg_obj_log(eps, logctx, ISC_LOG_ERROR, 2316 "endpoint '%s' is not a " 2317 "valid absolute HTTP path", 2318 path); 2319 if (result == ISC_R_SUCCESS) { 2320 result = ISC_R_FAILURE; 2321 } 2322 } 2323 } 2324 } 2325 2326 return result; 2327 } 2328 2329 static isc_result_t 2330 check_httpservers(const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { 2331 isc_result_t result, tresult; 2332 const cfg_obj_t *obj = NULL; 2333 const cfg_listelt_t *elt = NULL; 2334 isc_symtab_t *symtab = NULL; 2335 2336 result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab); 2337 if (result != ISC_R_SUCCESS) { 2338 return result; 2339 } 2340 2341 result = cfg_map_get(config, "http", &obj); 2342 if (result != ISC_R_SUCCESS) { 2343 result = ISC_R_SUCCESS; 2344 goto done; 2345 } 2346 2347 for (elt = cfg_list_first(obj); elt != NULL; elt = cfg_list_next(elt)) { 2348 obj = cfg_listelt_value(elt); 2349 tresult = check_httpserver(obj, logctx, symtab); 2350 if (result == ISC_R_SUCCESS) { 2351 result = tresult; 2352 } 2353 } 2354 2355 done: 2356 isc_symtab_destroy(&symtab); 2357 return result; 2358 } 2359 #endif /* HAVE_LIBNGHTTP2 */ 2360 2361 static isc_result_t 2362 check_tls_defintion(const cfg_obj_t *tlsobj, const char *name, 2363 isc_log_t *logctx, isc_symtab_t *symtab) { 2364 isc_result_t result, tresult; 2365 const cfg_obj_t *tls_proto_list = NULL, *tls_key = NULL, 2366 *tls_cert = NULL, *tls_ciphers = NULL, 2367 *tls_cipher_suites = NULL; 2368 uint32_t tls_protos = 0; 2369 isc_symvalue_t symvalue; 2370 2371 if (strcasecmp(name, "ephemeral") == 0 || strcasecmp(name, "none") == 0) 2372 { 2373 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 2374 "tls clause name '%s' is reserved for internal use", 2375 name); 2376 result = ISC_R_FAILURE; 2377 } else { 2378 /* Check for duplicates */ 2379 symvalue.as_cpointer = tlsobj; 2380 result = isc_symtab_define(symtab, name, 1, symvalue, 2381 isc_symexists_reject); 2382 if (result == ISC_R_EXISTS) { 2383 const char *file = NULL; 2384 unsigned int line; 2385 2386 tresult = isc_symtab_lookup(symtab, name, 1, &symvalue); 2387 RUNTIME_CHECK(tresult == ISC_R_SUCCESS); 2388 2389 line = cfg_obj_line(symvalue.as_cpointer); 2390 file = cfg_obj_file(symvalue.as_cpointer); 2391 if (file == NULL) { 2392 file = "<unknown file>"; 2393 } 2394 2395 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 2396 "tls clause '%s' is duplicated: " 2397 "also defined at %s:%u", 2398 name, file, line); 2399 } 2400 } 2401 2402 (void)cfg_map_get(tlsobj, "key-file", &tls_key); 2403 (void)cfg_map_get(tlsobj, "cert-file", &tls_cert); 2404 if ((tls_key == NULL && tls_cert != NULL) || 2405 (tls_cert == NULL && tls_key != NULL)) 2406 { 2407 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 2408 "tls '%s': 'cert-file' and 'key-file' must " 2409 "both be specified, or both omitted", 2410 name); 2411 result = ISC_R_FAILURE; 2412 } 2413 2414 /* Check protocols are valid */ 2415 tresult = cfg_map_get(tlsobj, "protocols", &tls_proto_list); 2416 if (tresult == ISC_R_SUCCESS) { 2417 const cfg_listelt_t *proto = NULL; 2418 INSIST(tls_proto_list != NULL); 2419 for (proto = cfg_list_first(tls_proto_list); proto != 0; 2420 proto = cfg_list_next(proto)) 2421 { 2422 const cfg_obj_t *tls_proto_obj = 2423 cfg_listelt_value(proto); 2424 const char *tls_sver = cfg_obj_asstring(tls_proto_obj); 2425 const isc_tls_protocol_version_t ver = 2426 isc_tls_protocol_name_to_version(tls_sver); 2427 2428 if (ver == ISC_TLS_PROTO_VER_UNDEFINED) { 2429 cfg_obj_log(tls_proto_obj, logctx, 2430 ISC_LOG_ERROR, 2431 "'%s' is not a valid " 2432 "TLS protocol version", 2433 tls_sver); 2434 result = ISC_R_FAILURE; 2435 continue; 2436 } else if (!isc_tls_protocol_supported(ver)) { 2437 cfg_obj_log(tls_proto_obj, logctx, 2438 ISC_LOG_ERROR, 2439 "'%s' is not " 2440 "supported by the " 2441 "cryptographic library version in " 2442 "use (%s)", 2443 tls_sver, OPENSSL_VERSION_TEXT); 2444 result = ISC_R_FAILURE; 2445 } 2446 2447 if ((tls_protos & ver) != 0) { 2448 cfg_obj_log(tls_proto_obj, logctx, 2449 ISC_LOG_WARNING, 2450 "'%s' is specified more than once " 2451 "in '%s'", 2452 tls_sver, name); 2453 result = ISC_R_FAILURE; 2454 } 2455 2456 tls_protos |= ver; 2457 } 2458 2459 if (tls_protos == 0) { 2460 cfg_obj_log(tlsobj, logctx, ISC_LOG_ERROR, 2461 "tls '%s' does not contain any valid " 2462 "TLS protocol versions definitions", 2463 name); 2464 result = ISC_R_FAILURE; 2465 } 2466 } 2467 2468 /* Check cipher list string is valid */ 2469 tresult = cfg_map_get(tlsobj, "ciphers", &tls_ciphers); 2470 if (tresult == ISC_R_SUCCESS) { 2471 const char *ciphers = cfg_obj_asstring(tls_ciphers); 2472 if (!isc_tls_cipherlist_valid(ciphers)) { 2473 cfg_obj_log(tls_ciphers, logctx, ISC_LOG_ERROR, 2474 "'ciphers' in the 'tls' clause '%s' is " 2475 "not a " 2476 "valid cipher list string", 2477 name); 2478 result = ISC_R_FAILURE; 2479 } 2480 } 2481 2482 /* Check if the cipher suites string is valid */ 2483 tresult = cfg_map_get(tlsobj, "cipher-suites", &tls_cipher_suites); 2484 if (tresult == ISC_R_SUCCESS) { 2485 const char *cipher_suites = cfg_obj_asstring(tls_cipher_suites); 2486 if (!isc_tls_cipher_suites_valid(cipher_suites)) { 2487 cfg_obj_log( 2488 tls_cipher_suites, logctx, ISC_LOG_ERROR, 2489 "'cipher-suites' in the 'tls' clause '%s' is " 2490 "not a valid cipher suites string", 2491 name); 2492 result = ISC_R_FAILURE; 2493 } 2494 } 2495 2496 return result; 2497 } 2498 2499 static isc_result_t 2500 check_tls_definitions(const cfg_obj_t *config, isc_log_t *logctx, 2501 isc_mem_t *mctx) { 2502 isc_result_t result, tresult; 2503 const cfg_obj_t *obj = NULL; 2504 const cfg_listelt_t *elt = NULL; 2505 isc_symtab_t *symtab = NULL; 2506 2507 result = cfg_map_get(config, "tls", &obj); 2508 if (result != ISC_R_SUCCESS) { 2509 result = ISC_R_SUCCESS; 2510 return result; 2511 } 2512 2513 result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab); 2514 if (result != ISC_R_SUCCESS) { 2515 return result; 2516 } 2517 2518 for (elt = cfg_list_first(obj); elt != NULL; elt = cfg_list_next(elt)) { 2519 const char *name; 2520 obj = cfg_listelt_value(elt); 2521 name = cfg_obj_asstring(cfg_map_getname(obj)); 2522 tresult = check_tls_defintion(obj, name, logctx, symtab); 2523 if (result == ISC_R_SUCCESS) { 2524 result = tresult; 2525 } 2526 } 2527 2528 isc_symtab_destroy(&symtab); 2529 2530 return result; 2531 } 2532 2533 static isc_result_t 2534 get_remotes(const cfg_obj_t *cctx, const char *list, const char *name, 2535 const cfg_obj_t **ret) { 2536 isc_result_t result; 2537 const cfg_obj_t *obj = NULL; 2538 const cfg_listelt_t *elt = NULL; 2539 2540 result = cfg_map_get(cctx, list, &obj); 2541 if (result != ISC_R_SUCCESS) { 2542 return result; 2543 } 2544 2545 elt = cfg_list_first(obj); 2546 while (elt != NULL) { 2547 const char *listname; 2548 2549 obj = cfg_listelt_value(elt); 2550 listname = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 2551 2552 if (strcasecmp(listname, name) == 0) { 2553 *ret = obj; 2554 return ISC_R_SUCCESS; 2555 } 2556 2557 elt = cfg_list_next(elt); 2558 } 2559 2560 return ISC_R_NOTFOUND; 2561 } 2562 2563 static isc_result_t 2564 get_remoteservers_def(const char *name, const cfg_obj_t *cctx, 2565 const cfg_obj_t **ret) { 2566 isc_result_t result; 2567 2568 result = get_remotes(cctx, "remote-servers", name, ret); 2569 if (result == ISC_R_SUCCESS) { 2570 return result; 2571 } 2572 result = get_remotes(cctx, "primaries", name, ret); 2573 if (result == ISC_R_SUCCESS) { 2574 return result; 2575 } 2576 result = get_remotes(cctx, "parental-agents", name, ret); 2577 if (result == ISC_R_SUCCESS) { 2578 return result; 2579 } 2580 return get_remotes(cctx, "masters", name, ret); 2581 } 2582 2583 static isc_result_t 2584 validate_remotes_key(const cfg_obj_t *config, const cfg_obj_t *key, 2585 isc_log_t *logctx) { 2586 isc_result_t result = ISC_R_SUCCESS; 2587 2588 if (cfg_obj_isstring(key)) { 2589 const cfg_obj_t *keys = NULL; 2590 const char *str = cfg_obj_asstring(key); 2591 dns_fixedname_t fname; 2592 dns_name_t *nm = dns_fixedname_initname(&fname); 2593 bool found = false; 2594 2595 result = dns_name_fromstring(nm, str, dns_rootname, 0, NULL); 2596 if (result != ISC_R_SUCCESS) { 2597 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 2598 "'%s' is not a valid name", str); 2599 } 2600 2601 result = cfg_map_get(config, "key", &keys); 2602 2603 for (const cfg_listelt_t *elt = cfg_list_first(keys); 2604 elt != NULL; elt = cfg_list_next(elt)) 2605 { 2606 /* 2607 * `key` are normalized TSIG which must be 2608 * identified by a domain name, so this is 2609 * needed. Otherwise, with a raw string 2610 * comparison we could have: 2611 * 2612 * remote-servers { x.y.z.s key foo }; 2613 * key foo. { 2614 * ... 2615 * }; 2616 * 2617 * This would otherwise fail, even though the 2618 * key exists. 2619 */ 2620 const cfg_obj_t *foundkey = cfg_listelt_value(elt); 2621 const char *foundkeystr = 2622 cfg_obj_asstring(cfg_map_getname(foundkey)); 2623 dns_fixedname_t foundfname; 2624 dns_name_t *foundkeyname = 2625 dns_fixedname_initname(&foundfname); 2626 2627 result = dns_name_fromstring(foundkeyname, foundkeystr, 2628 dns_rootname, 0, NULL); 2629 2630 if (dns_name_equal(nm, foundkeyname)) { 2631 found = true; 2632 break; 2633 } 2634 } 2635 2636 if (!found) { 2637 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 2638 "key '%s' is not defined", 2639 cfg_obj_asstring(key)); 2640 result = ISC_R_FAILURE; 2641 } 2642 } 2643 2644 return result; 2645 } 2646 2647 static isc_result_t 2648 validate_remotes_tls(const cfg_obj_t *config, const cfg_obj_t *tls, 2649 isc_log_t *logctx) { 2650 isc_result_t result = ISC_R_SUCCESS; 2651 2652 if (cfg_obj_isstring(tls)) { 2653 const char *str = cfg_obj_asstring(tls); 2654 dns_fixedname_t fname; 2655 dns_name_t *nm = dns_fixedname_initname(&fname); 2656 2657 result = dns_name_fromstring(nm, str, dns_rootname, 0, NULL); 2658 if (result != ISC_R_SUCCESS) { 2659 cfg_obj_log(tls, logctx, ISC_LOG_ERROR, 2660 "'%s' is not a valid name", str); 2661 } 2662 2663 if (strcasecmp(str, "ephemeral") != 0) { 2664 const cfg_obj_t *tlsmap = NULL; 2665 2666 tlsmap = find_maplist(config, "tls", str); 2667 if (tlsmap == NULL) { 2668 cfg_obj_log(tls, logctx, ISC_LOG_ERROR, 2669 "tls '%s' is not defined", 2670 cfg_obj_asstring(tls)); 2671 result = ISC_R_FAILURE; 2672 } 2673 } 2674 } 2675 2676 return result; 2677 } 2678 2679 static isc_result_t 2680 validate_remotes(const cfg_obj_t *obj, const cfg_obj_t *config, 2681 uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx) { 2682 isc_result_t result = ISC_R_SUCCESS; 2683 isc_result_t tresult; 2684 uint32_t count = 0; 2685 isc_symtab_t *symtab = NULL; 2686 isc_symvalue_t symvalue; 2687 const cfg_listelt_t *element; 2688 cfg_listelt_t **stack = NULL; 2689 uint32_t stackcount = 0, pushed = 0; 2690 const cfg_obj_t *listobj; 2691 2692 REQUIRE(countp != NULL); 2693 result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab); 2694 if (result != ISC_R_SUCCESS) { 2695 *countp = count; 2696 return result; 2697 } 2698 2699 newlist: 2700 listobj = cfg_tuple_get(obj, "addresses"); 2701 element = cfg_list_first(listobj); 2702 resume: 2703 for (; element != NULL; element = cfg_list_next(element)) { 2704 const char *listname; 2705 const cfg_obj_t *addr; 2706 const cfg_obj_t *key; 2707 const cfg_obj_t *tls; 2708 2709 addr = cfg_tuple_get(cfg_listelt_value(element), 2710 "remoteselement"); 2711 key = cfg_tuple_get(cfg_listelt_value(element), "key"); 2712 tls = cfg_tuple_get(cfg_listelt_value(element), "tls"); 2713 2714 result = validate_remotes_key(config, key, logctx); 2715 if (result != ISC_R_SUCCESS) { 2716 goto out; 2717 } 2718 2719 result = validate_remotes_tls(config, tls, logctx); 2720 if (result != ISC_R_SUCCESS) { 2721 goto out; 2722 } 2723 2724 if (cfg_obj_issockaddr(addr)) { 2725 count++; 2726 2727 continue; 2728 } 2729 listname = cfg_obj_asstring(addr); 2730 symvalue.as_cpointer = addr; 2731 tresult = isc_symtab_define(symtab, listname, 1, symvalue, 2732 isc_symexists_reject); 2733 if (tresult == ISC_R_EXISTS) { 2734 continue; 2735 } 2736 tresult = get_remoteservers_def(listname, config, &obj); 2737 if (tresult != ISC_R_SUCCESS) { 2738 if (result == ISC_R_SUCCESS) { 2739 result = tresult; 2740 } 2741 cfg_obj_log(addr, logctx, ISC_LOG_ERROR, 2742 "unable to find remote-servers list '%s'", 2743 listname); 2744 continue; 2745 } 2746 /* Grow stack? */ 2747 if (stackcount == pushed) { 2748 stack = isc_mem_creget(mctx, stack, stackcount, 2749 stackcount + 16, 2750 sizeof(stack[0])); 2751 stackcount += 16; 2752 } 2753 stack[pushed++] = UNCONST(cfg_list_next(element)); 2754 goto newlist; 2755 } 2756 if (pushed != 0) { 2757 element = stack[--pushed]; 2758 goto resume; 2759 } 2760 2761 *countp = count; 2762 2763 out: 2764 if (stack != NULL) { 2765 isc_mem_cput(mctx, stack, stackcount, sizeof(*stack)); 2766 } 2767 isc_symtab_destroy(&symtab); 2768 return result; 2769 } 2770 2771 static isc_result_t 2772 check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) { 2773 isc_result_t result = ISC_R_SUCCESS; 2774 isc_result_t tresult; 2775 const cfg_listelt_t *element; 2776 const cfg_listelt_t *element2; 2777 dns_fixedname_t fixed_id, fixed_name; 2778 dns_name_t *id, *name; 2779 const char *str; 2780 isc_textregion_t r; 2781 dns_rdatatype_t type; 2782 2783 /* Check for "update-policy local;" */ 2784 if (cfg_obj_isstring(policy) && 2785 strcmp("local", cfg_obj_asstring(policy)) == 0) 2786 { 2787 return ISC_R_SUCCESS; 2788 } 2789 2790 /* Now check the grant policy */ 2791 for (element = cfg_list_first(policy); element != NULL; 2792 element = cfg_list_next(element)) 2793 { 2794 const cfg_obj_t *stmt = cfg_listelt_value(element); 2795 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity"); 2796 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype"); 2797 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name"); 2798 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types"); 2799 dns_ssumatchtype_t mtype; 2800 2801 id = dns_fixedname_initname(&fixed_id); 2802 name = dns_fixedname_initname(&fixed_name); 2803 2804 tresult = dns_ssu_mtypefromstring(cfg_obj_asstring(matchtype), 2805 &mtype); 2806 if (tresult != ISC_R_SUCCESS) { 2807 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2808 "has a bad match-type"); 2809 } 2810 2811 str = cfg_obj_asstring(identity); 2812 tresult = dns_name_fromstring(id, str, dns_rootname, 1, NULL); 2813 if (tresult != ISC_R_SUCCESS) { 2814 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2815 "'%s' is not a valid name", str); 2816 result = tresult; 2817 } 2818 2819 /* 2820 * There is no name field for subzone and dname is void 2821 */ 2822 if (mtype == dns_ssumatchtype_subdomain && 2823 cfg_obj_isvoid(dname)) 2824 { 2825 str = "."; /* Use "." as a replacement. */ 2826 } else { 2827 str = cfg_obj_asstring(dname); 2828 } 2829 if (tresult == ISC_R_SUCCESS) { 2830 tresult = dns_name_fromstring(name, str, dns_rootname, 2831 0, NULL); 2832 if (tresult != ISC_R_SUCCESS) { 2833 cfg_obj_log(dname, logctx, ISC_LOG_ERROR, 2834 "'%s' is not a valid name", str); 2835 result = tresult; 2836 } 2837 } 2838 2839 if (tresult == ISC_R_SUCCESS && 2840 mtype == dns_ssumatchtype_wildcard && 2841 !dns_name_iswildcard(name)) 2842 { 2843 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2844 "'%s' is not a wildcard", str); 2845 result = ISC_R_FAILURE; 2846 } 2847 2848 /* 2849 * For some match types, the name should be a placeholder 2850 * value, either "." or the same as identity. 2851 */ 2852 switch (mtype) { 2853 case dns_ssumatchtype_self: 2854 case dns_ssumatchtype_selfsub: 2855 case dns_ssumatchtype_selfwild: 2856 if (tresult == ISC_R_SUCCESS && 2857 (!dns_name_equal(id, name) && 2858 !dns_name_equal(dns_rootname, name))) 2859 { 2860 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2861 "identity and name fields are not " 2862 "the same"); 2863 result = ISC_R_FAILURE; 2864 } 2865 break; 2866 case dns_ssumatchtype_selfkrb5: 2867 case dns_ssumatchtype_selfms: 2868 case dns_ssumatchtype_selfsubkrb5: 2869 case dns_ssumatchtype_selfsubms: 2870 case dns_ssumatchtype_tcpself: 2871 case dns_ssumatchtype_6to4self: 2872 if (tresult == ISC_R_SUCCESS && 2873 !dns_name_equal(dns_rootname, name)) 2874 { 2875 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2876 "name field not set to " 2877 "placeholder value '.'"); 2878 result = ISC_R_FAILURE; 2879 } 2880 break; 2881 case dns_ssumatchtype_name: 2882 case dns_ssumatchtype_subdomain: /* also zonesub */ 2883 case dns_ssumatchtype_subdomainms: 2884 case dns_ssumatchtype_subdomainselfmsrhs: 2885 case dns_ssumatchtype_subdomainkrb5: 2886 case dns_ssumatchtype_subdomainselfkrb5rhs: 2887 case dns_ssumatchtype_wildcard: 2888 case dns_ssumatchtype_external: 2889 case dns_ssumatchtype_local: 2890 if (tresult == ISC_R_SUCCESS) { 2891 r.base = UNCONST(str); 2892 r.length = strlen(str); 2893 tresult = dns_rdatatype_fromtext(&type, &r); 2894 } 2895 if (tresult == ISC_R_SUCCESS) { 2896 cfg_obj_log(identity, logctx, ISC_LOG_ERROR, 2897 "missing name field type '%s' " 2898 "found", 2899 str); 2900 result = ISC_R_FAILURE; 2901 break; 2902 } 2903 break; 2904 default: 2905 UNREACHABLE(); 2906 } 2907 2908 for (element2 = cfg_list_first(typelist); element2 != NULL; 2909 element2 = cfg_list_next(element2)) 2910 { 2911 const cfg_obj_t *typeobj; 2912 const char *bracket; 2913 2914 typeobj = cfg_listelt_value(element2); 2915 r.base = UNCONST(cfg_obj_asstring(typeobj)); 2916 2917 bracket = strchr(r.base, '(' /*)*/); 2918 if (bracket != NULL) { 2919 char *end = NULL; 2920 unsigned long max; 2921 2922 r.length = bracket - r.base; 2923 max = strtoul(bracket + 1, &end, 10); 2924 if (max > 0xffff || end[0] != /*(*/ ')' || 2925 end[1] != 0) 2926 { 2927 cfg_obj_log(typeobj, logctx, 2928 ISC_LOG_ERROR, 2929 "'%s' is not a valid count", 2930 bracket); 2931 result = DNS_R_SYNTAX; 2932 } 2933 } else { 2934 r.length = strlen(r.base); 2935 } 2936 2937 tresult = dns_rdatatype_fromtext(&type, &r); 2938 if (tresult != ISC_R_SUCCESS) { 2939 cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR, 2940 "'%.*s' is not a valid type", 2941 (int)r.length, r.base); 2942 result = tresult; 2943 } 2944 } 2945 } 2946 return result; 2947 } 2948 2949 typedef struct { 2950 const char *name; 2951 unsigned int allowed; 2952 } optionstable; 2953 2954 static isc_result_t 2955 check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) { 2956 isc_result_t result = ISC_R_SUCCESS; 2957 const cfg_obj_t *obj = NULL; 2958 unsigned int i; 2959 2960 static const char *nonzero[] = { "max-retry-time", "min-retry-time", 2961 "max-refresh-time", 2962 "min-refresh-time" }; 2963 /* 2964 * Check if value is zero. 2965 */ 2966 for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) { 2967 obj = NULL; 2968 if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS && 2969 cfg_obj_asuint32(obj) == 0) 2970 { 2971 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 2972 "'%s' must not be zero", nonzero[i]); 2973 result = ISC_R_FAILURE; 2974 } 2975 } 2976 return result; 2977 } 2978 2979 /*% 2980 * Check whether NOTIFY configuration at the zone level is acceptable for a 2981 * mirror zone. Return true if it is; return false otherwise. 2982 */ 2983 static bool 2984 check_mirror_zone_notify(const cfg_obj_t *zoptions, const char *znamestr, 2985 isc_log_t *logctx) { 2986 bool notify_configuration_ok = true; 2987 const cfg_obj_t *obj = NULL; 2988 2989 (void)cfg_map_get(zoptions, "notify", &obj); 2990 if (obj == NULL) { 2991 /* 2992 * "notify" not set at zone level. This is fine. 2993 */ 2994 return true; 2995 } 2996 2997 if (cfg_obj_isboolean(obj)) { 2998 if (cfg_obj_asboolean(obj)) { 2999 /* 3000 * "notify yes;" set at zone level. This is an error. 3001 */ 3002 notify_configuration_ok = false; 3003 } 3004 } else { 3005 const char *notifystr = cfg_obj_asstring(obj); 3006 if (strcasecmp(notifystr, "explicit") != 0) { 3007 /* 3008 * Something else than "notify explicit;" set at zone 3009 * level. This is an error. 3010 */ 3011 notify_configuration_ok = false; 3012 } 3013 } 3014 3015 if (!notify_configuration_ok) { 3016 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 3017 "zone '%s': mirror zones can only be used with " 3018 "'notify no;' or 'notify explicit;'", 3019 znamestr); 3020 } 3021 3022 return notify_configuration_ok; 3023 } 3024 3025 /*% 3026 * Try to determine whether recursion is available in a view without resorting 3027 * to extraordinary measures: just check the "recursion" and "allow-recursion" 3028 * settings. The point is to prevent accidental mirror zone misuse rather than 3029 * to enforce some sort of policy. Recursion is assumed to be allowed by 3030 * default if it is not explicitly disabled. 3031 */ 3032 static bool 3033 check_recursion(const cfg_obj_t *config, const cfg_obj_t *voptions, 3034 const cfg_obj_t *goptions, isc_log_t *logctx, 3035 cfg_aclconfctx_t *actx, isc_mem_t *mctx) { 3036 dns_acl_t *acl = NULL; 3037 const cfg_obj_t *obj; 3038 isc_result_t result; 3039 bool retval = true; 3040 3041 /* 3042 * Check the "recursion" option first. 3043 */ 3044 obj = NULL; 3045 result = ISC_R_NOTFOUND; 3046 if (voptions != NULL) { 3047 result = cfg_map_get(voptions, "recursion", &obj); 3048 } 3049 if (result != ISC_R_SUCCESS && goptions != NULL) { 3050 result = cfg_map_get(goptions, "recursion", &obj); 3051 } 3052 if (result == ISC_R_SUCCESS && !cfg_obj_asboolean(obj)) { 3053 retval = false; 3054 goto cleanup; 3055 } 3056 3057 /* 3058 * If recursion is not disabled by the "recursion" option, check 3059 * whether it is disabled by the "allow-recursion" ACL. 3060 */ 3061 obj = NULL; 3062 result = ISC_R_NOTFOUND; 3063 if (voptions != NULL) { 3064 result = cfg_map_get(voptions, "allow-recursion", &obj); 3065 } 3066 if (result != ISC_R_SUCCESS && goptions != NULL) { 3067 result = cfg_map_get(goptions, "allow-recursion", &obj); 3068 } 3069 if (result == ISC_R_SUCCESS) { 3070 result = cfg_acl_fromconfig(obj, config, logctx, actx, mctx, 0, 3071 &acl); 3072 if (result != ISC_R_SUCCESS) { 3073 goto cleanup; 3074 } 3075 retval = !dns_acl_isnone(acl); 3076 } 3077 3078 cleanup: 3079 if (acl != NULL) { 3080 dns_acl_detach(&acl); 3081 } 3082 3083 return retval; 3084 } 3085 3086 static isc_result_t 3087 check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig, 3088 dns_name_t *origin, const char *zname, const char *name, 3089 const char *keydir, isc_symtab_t *keydirs, isc_log_t *logctx, 3090 isc_mem_t *mctx, bool check_keys) { 3091 const char *dir = keydir; 3092 const cfg_listelt_t *element; 3093 isc_result_t ret, result = ISC_R_SUCCESS; 3094 bool keystore = false; 3095 const cfg_obj_t *kasps = NULL; 3096 dns_kasp_t *kasp = NULL, *kasp_next = NULL; 3097 const cfg_obj_t *kaspobj = NULL; 3098 const cfg_obj_t *obj = NULL; 3099 dns_kasp_t *default_kasp = NULL; 3100 dns_kasplist_t kasplist; 3101 3102 const cfg_obj_t *keystores = NULL; 3103 dns_keystore_t *ks = NULL, *ks_next = NULL; 3104 dns_keystorelist_t kslist; 3105 isc_time_t timenow; 3106 isc_stdtime_t now; 3107 3108 timenow = isc_time_now(); 3109 now = isc_time_seconds(&timenow); 3110 3111 (void)cfg_map_get(config, "dnssec-policy", &kasps); 3112 (void)cfg_map_get(config, "key-store", &keystores); 3113 ISC_LIST_INIT(kasplist); 3114 ISC_LIST_INIT(kslist); 3115 3116 /* 3117 * Build the keystore list. 3118 */ 3119 for (element = cfg_list_first(keystores); element != NULL; 3120 element = cfg_list_next(element)) 3121 { 3122 cfg_obj_t *kcfg = cfg_listelt_value(element); 3123 (void)cfg_keystore_fromconfig(kcfg, mctx, logctx, NULL, &kslist, 3124 NULL); 3125 } 3126 (void)cfg_keystore_fromconfig(NULL, mctx, logctx, NULL, &kslist, NULL); 3127 3128 /* 3129 * dnssec-policy "default". 3130 */ 3131 ret = cfg_kasp_builtinconfig(mctx, "default", &kslist, &kasplist, 3132 &default_kasp); 3133 if (ret != ISC_R_SUCCESS) { 3134 cfg_obj_log(config, logctx, ISC_LOG_ERROR, 3135 "failed to load the 'default' dnssec-policy: %s", 3136 isc_result_totext(ret)); 3137 result = ret; 3138 goto check; 3139 } 3140 dns_kasp_freeze(default_kasp); 3141 3142 /* 3143 * dnssec-policy "insecure". 3144 */ 3145 ret = cfg_kasp_builtinconfig(mctx, "insecure", &kslist, &kasplist, 3146 &kasp); 3147 if (ret != ISC_R_SUCCESS) { 3148 cfg_obj_log(config, logctx, ISC_LOG_ERROR, 3149 "failed to load the 'insecure' dnssec-policy: %s", 3150 isc_result_totext(ret)); 3151 result = ret; 3152 goto check; 3153 } 3154 dns_kasp_freeze(kasp); 3155 dns_kasp_detach(&kasp); 3156 3157 /* 3158 * Configured dnssec-policy clauses. 3159 */ 3160 for (element = cfg_list_first(kasps); element != NULL; 3161 element = cfg_list_next(element)) 3162 { 3163 cfg_obj_t *kconfig = cfg_listelt_value(element); 3164 obj = NULL; 3165 3166 if (!cfg_obj_istuple(kconfig)) { 3167 continue; 3168 } 3169 3170 obj = cfg_tuple_get(kconfig, "name"); 3171 ret = cfg_kasp_fromconfig(kconfig, default_kasp, 0, mctx, 3172 logctx, &kslist, &kasplist, &kasp); 3173 if (ret != ISC_R_SUCCESS) { 3174 result = ret; 3175 goto check; 3176 } 3177 3178 if (strcmp(name, cfg_obj_asstring(obj)) == 0) { 3179 kaspobj = obj; 3180 dns_kasp_freeze(kasp); 3181 } 3182 dns_kasp_detach(&kasp); 3183 } 3184 3185 /* 3186 * Look for the dnssec-policy by name, which is the dnssec-policy 3187 * for the zone in question. 3188 */ 3189 ret = dns_kasplist_find(&kasplist, name, &kasp); 3190 if (ret != ISC_R_SUCCESS) { 3191 cfg_obj_log(config, logctx, ISC_LOG_ERROR, 3192 "no dnssec-policy found for zone '%s'", zname); 3193 result = ISC_R_NOTFOUND; 3194 goto check; 3195 } 3196 INSIST(kasp != NULL); 3197 3198 if (kaspobj == NULL) { 3199 kaspobj = kasps == NULL ? config : kasps; 3200 } 3201 3202 if (strcmp(name, "insecure") == 0 || strcmp(name, "default") == 0) { 3203 ret = keydirexist(zconfig, "key-directory", origin, dir, name, 3204 keydirs, logctx, mctx); 3205 if (ret != ISC_R_SUCCESS) { 3206 result = ret; 3207 } 3208 } 3209 3210 /* Check key-stores of keys */ 3211 for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); 3212 kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link)) 3213 { 3214 dns_keystore_t *kks = dns_kasp_key_keystore(kkey); 3215 dir = dns_keystore_directory(kks, keydir); 3216 keystore = (kks != NULL && strcmp(DNS_KEYSTORE_KEYDIRECTORY, 3217 dns_keystore_name(kks)) != 0); 3218 3219 ret = keydirexist(zconfig, 3220 keystore ? "key-store directory" 3221 : "key-directory", 3222 origin, dir, name, keydirs, logctx, mctx); 3223 if (ret != ISC_R_SUCCESS) { 3224 result = ret; 3225 } 3226 } 3227 3228 if (check_keys) { 3229 /* Find matching key files. */ 3230 dns_dnsseckeylist_t keys; 3231 int numkaspkeys = 0; 3232 int numkeyfiles = 0; 3233 3234 ISC_LIST_INIT(keys); 3235 ret = dns_dnssec_findmatchingkeys(origin, kasp, keydir, &kslist, 3236 now, false, mctx, &keys); 3237 if (ret != ISC_R_SUCCESS) { 3238 result = ret; 3239 } 3240 3241 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(keys); dkey != NULL; 3242 dkey = ISC_LIST_NEXT(dkey, link)) 3243 { 3244 numkeyfiles++; 3245 } 3246 3247 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(keys); dkey != NULL; 3248 dkey = ISC_LIST_NEXT(dkey, link)) 3249 { 3250 bool found_match = false; 3251 3252 dns_keymgr_key_init(dkey, kasp, now, numkeyfiles == 1); 3253 3254 for (dns_kasp_key_t *kkey = 3255 ISC_LIST_HEAD(dns_kasp_keys(kasp)); 3256 kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link)) 3257 { 3258 if (dns_kasp_key_match(kkey, dkey)) { 3259 found_match = true; 3260 break; 3261 } 3262 } 3263 3264 if (!found_match) { 3265 char keystr[DST_KEY_FORMATSIZE]; 3266 dst_key_format(dkey->key, keystr, 3267 sizeof(keystr)); 3268 cfg_obj_log(kaspobj, logctx, ISC_LOG_ERROR, 3269 "zone '%s': key file '%s' does not " 3270 "match dnssec-policy %s", 3271 zname, keystr, 3272 dns_kasp_getname(kasp)); 3273 result = ISC_R_NOTFOUND; 3274 } 3275 } 3276 3277 for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); 3278 kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link)) 3279 { 3280 bool found_match = false; 3281 3282 numkaspkeys++; 3283 3284 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(keys); 3285 dkey != NULL; dkey = ISC_LIST_NEXT(dkey, link)) 3286 { 3287 if (dns_kasp_key_match(kkey, dkey)) { 3288 found_match = true; 3289 break; 3290 } 3291 } 3292 3293 if (!found_match) { 3294 char keystr[DNS_KASP_KEY_FORMATSIZE]; 3295 dns_kasp_key_format(kkey, keystr, 3296 sizeof(keystr)); 3297 3298 cfg_obj_log( 3299 kaspobj, logctx, ISC_LOG_ERROR, 3300 "zone '%s': no key file found matching " 3301 "dnssec-policy %s key:'%s'", 3302 zname, dns_kasp_getname(kasp), keystr); 3303 result = ISC_R_NOTFOUND; 3304 } 3305 } 3306 3307 if (numkaspkeys != numkeyfiles) { 3308 cfg_obj_log(kaspobj, logctx, ISC_LOG_ERROR, 3309 "zone '%s': wrong number of key files (%d, " 3310 "expected %d)", 3311 zname, numkeyfiles, numkaspkeys); 3312 result = ISC_R_FAILURE; 3313 } 3314 3315 dns_dnsseckey_t *dkey_next = NULL; 3316 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(keys); dkey != NULL; 3317 dkey = dkey_next) 3318 { 3319 dkey_next = ISC_LIST_NEXT(dkey, link); 3320 ISC_LIST_UNLINK(keys, dkey, link); 3321 dns_dnsseckey_destroy(mctx, &dkey); 3322 } 3323 } 3324 3325 check: 3326 if (default_kasp != NULL) { 3327 dns_kasp_detach(&default_kasp); 3328 } 3329 if (kasp != NULL) { 3330 dns_kasp_detach(&kasp); 3331 } 3332 for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) { 3333 kasp_next = ISC_LIST_NEXT(kasp, link); 3334 ISC_LIST_UNLINK(kasplist, kasp, link); 3335 dns_kasp_detach(&kasp); 3336 } 3337 for (ks = ISC_LIST_HEAD(kslist); ks != NULL; ks = ks_next) { 3338 ks_next = ISC_LIST_NEXT(ks, link); 3339 ISC_LIST_UNLINK(kslist, ks, link); 3340 dns_keystore_detach(&ks); 3341 } 3342 3343 return result; 3344 } 3345 3346 static isc_result_t 3347 check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, 3348 const cfg_obj_t *config, isc_symtab_t *symtab, 3349 isc_symtab_t *files, isc_symtab_t *keydirs, isc_symtab_t *inview, 3350 const char *viewname, dns_rdataclass_t defclass, 3351 unsigned int flags, cfg_aclconfctx_t *actx, isc_log_t *logctx, 3352 isc_mem_t *mctx) { 3353 const char *znamestr; 3354 const char *typestr = NULL; 3355 const char *target = NULL; 3356 unsigned int ztype; 3357 const cfg_obj_t *zoptions, *goptions = NULL; 3358 const cfg_obj_t *obj = NULL, *kasp = NULL; 3359 const cfg_obj_t *inviewobj = NULL; 3360 isc_result_t result = ISC_R_SUCCESS; 3361 isc_result_t tresult; 3362 unsigned int i; 3363 dns_rdataclass_t zclass; 3364 dns_fixedname_t fixedname; 3365 dns_name_t *zname = NULL; /* NULL if parsing of zone name fails. */ 3366 isc_buffer_t b; 3367 bool root = false; 3368 bool rfc1918 = false; 3369 bool ula = false; 3370 const cfg_listelt_t *element; 3371 bool dlz; 3372 bool ddns = false; 3373 bool has_dnssecpolicy = false; 3374 bool kasp_inlinesigning = false; 3375 bool check_keys = (flags & BIND_CHECK_KEYS) != 0; 3376 const void *clauses = NULL; 3377 const char *option = NULL; 3378 const char *kaspname = NULL; 3379 const char *dir = NULL; 3380 static const char *acls[] = { 3381 "allow-notify", 3382 "allow-transfer", 3383 "allow-update", 3384 "allow-update-forwarding", 3385 }; 3386 static optionstable dialups[] = { 3387 { "notify", CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY }, 3388 { "notify-passive", CFG_ZONE_SECONDARY }, 3389 { "passive", CFG_ZONE_SECONDARY | CFG_ZONE_STUB }, 3390 { "refresh", CFG_ZONE_SECONDARY | CFG_ZONE_STUB }, 3391 }; 3392 static const char *sources[] = { 3393 "transfer-source", "transfer-source-v6", "notify-source", 3394 "notify-source-v6", "parental-source", "parental-source-v6", 3395 }; 3396 3397 znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); 3398 3399 zoptions = cfg_tuple_get(zconfig, "options"); 3400 3401 if (config != NULL) { 3402 cfg_map_get(config, "options", &goptions); 3403 } 3404 3405 inviewobj = NULL; 3406 (void)cfg_map_get(zoptions, "in-view", &inviewobj); 3407 if (inviewobj != NULL) { 3408 target = cfg_obj_asstring(inviewobj); 3409 ztype = CFG_ZONE_INVIEW; 3410 } else { 3411 obj = NULL; 3412 (void)cfg_map_get(zoptions, "type", &obj); 3413 if (obj == NULL) { 3414 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3415 "zone '%s': type not present", znamestr); 3416 return ISC_R_FAILURE; 3417 } 3418 3419 typestr = cfg_obj_asstring(obj); 3420 if (strcasecmp(typestr, "master") == 0 || 3421 strcasecmp(typestr, "primary") == 0) 3422 { 3423 ztype = CFG_ZONE_PRIMARY; 3424 } else if (strcasecmp(typestr, "slave") == 0 || 3425 strcasecmp(typestr, "secondary") == 0) 3426 { 3427 ztype = CFG_ZONE_SECONDARY; 3428 } else if (strcasecmp(typestr, "mirror") == 0) { 3429 ztype = CFG_ZONE_MIRROR; 3430 } else if (strcasecmp(typestr, "stub") == 0) { 3431 ztype = CFG_ZONE_STUB; 3432 } else if (strcasecmp(typestr, "static-stub") == 0) { 3433 ztype = CFG_ZONE_STATICSTUB; 3434 } else if (strcasecmp(typestr, "forward") == 0) { 3435 ztype = CFG_ZONE_FORWARD; 3436 } else if (strcasecmp(typestr, "hint") == 0) { 3437 ztype = CFG_ZONE_HINT; 3438 } else if (strcasecmp(typestr, "redirect") == 0) { 3439 ztype = CFG_ZONE_REDIRECT; 3440 } else { 3441 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3442 "zone '%s': invalid type %s", znamestr, 3443 typestr); 3444 return ISC_R_FAILURE; 3445 } 3446 3447 if (ztype == CFG_ZONE_REDIRECT && strcmp(znamestr, ".") != 0) { 3448 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3449 "redirect zones must be called \".\""); 3450 return ISC_R_FAILURE; 3451 } 3452 } 3453 3454 obj = cfg_tuple_get(zconfig, "class"); 3455 if (cfg_obj_isstring(obj)) { 3456 isc_textregion_t r; 3457 3458 r.base = UNCONST(cfg_obj_asstring(obj)); 3459 r.length = strlen(r.base); 3460 result = dns_rdataclass_fromtext(&zclass, &r); 3461 if (result != ISC_R_SUCCESS) { 3462 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3463 "zone '%s': invalid class %s", znamestr, 3464 r.base); 3465 return ISC_R_FAILURE; 3466 } 3467 if (zclass != defclass) { 3468 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3469 "zone '%s': class '%s' does not " 3470 "match view/default class", 3471 znamestr, r.base); 3472 return ISC_R_FAILURE; 3473 } 3474 } else { 3475 zclass = defclass; 3476 } 3477 3478 /* 3479 * Look for an already existing zone. 3480 * We need to make this canonical as isc_symtab_define() 3481 * deals with strings. 3482 */ 3483 dns_fixedname_init(&fixedname); 3484 isc_buffer_constinit(&b, znamestr, strlen(znamestr)); 3485 isc_buffer_add(&b, strlen(znamestr)); 3486 tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b, 3487 dns_rootname, DNS_NAME_DOWNCASE, NULL); 3488 if (tresult != ISC_R_SUCCESS) { 3489 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3490 "zone '%s': is not a valid name", znamestr); 3491 result = ISC_R_FAILURE; 3492 } else { 3493 char namebuf[DNS_NAME_FORMATSIZE]; 3494 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 3495 char *key = NULL; 3496 const char *vname = NULL; 3497 size_t len = 0; 3498 int n; 3499 3500 zname = dns_fixedname_name(&fixedname); 3501 dns_name_format(zname, namebuf, sizeof(namebuf)); 3502 dns_rdataclass_format(zclass, classbuf, sizeof(classbuf)); 3503 3504 tresult = exists( 3505 zconfig, namebuf, 3506 ztype == CFG_ZONE_HINT ? 1 3507 : ztype == CFG_ZONE_REDIRECT ? 2 3508 : 3, 3509 symtab, 3510 "zone '%s': already exists previous definition: %s:%u", 3511 logctx, mctx); 3512 if (tresult != ISC_R_SUCCESS) { 3513 result = tresult; 3514 } 3515 if (dns_name_equal(zname, dns_rootname)) { 3516 root = true; 3517 } else if (dns_name_isrfc1918(zname)) { 3518 rfc1918 = true; 3519 } else if (dns_name_isula(zname)) { 3520 ula = true; 3521 } 3522 vname = (ztype == CFG_ZONE_INVIEW) ? target 3523 : (viewname != NULL) ? viewname 3524 : "_default"; 3525 len = strlen(namebuf) + strlen(classbuf) + strlen(vname) + 3; 3526 key = isc_mem_get(mctx, len); 3527 n = snprintf(key, len, "%s/%s/%s", namebuf, classbuf, vname); 3528 RUNTIME_CHECK(n > 0 && (size_t)n < len); 3529 switch (ztype) { 3530 case CFG_ZONE_INVIEW: 3531 tresult = isc_symtab_lookup(inview, key, 0, NULL); 3532 if (tresult != ISC_R_SUCCESS) { 3533 cfg_obj_log(inviewobj, logctx, ISC_LOG_ERROR, 3534 "'in-view' zone '%s' " 3535 "does not exist in view '%s', " 3536 "or view '%s' is not yet defined", 3537 znamestr, target, target); 3538 if (result == ISC_R_SUCCESS) { 3539 result = tresult; 3540 } 3541 } 3542 break; 3543 3544 case CFG_ZONE_FORWARD: 3545 case CFG_ZONE_REDIRECT: 3546 case CFG_ZONE_DELEGATION: 3547 break; 3548 3549 case CFG_ZONE_PRIMARY: 3550 case CFG_ZONE_SECONDARY: 3551 case CFG_ZONE_MIRROR: 3552 case CFG_ZONE_HINT: 3553 case CFG_ZONE_STUB: 3554 case CFG_ZONE_STATICSTUB: { 3555 char *tmp = isc_mem_strdup(mctx, key); 3556 isc_symvalue_t symvalue; 3557 symvalue.as_cpointer = NULL; 3558 tresult = isc_symtab_define(inview, tmp, 1, symvalue, 3559 isc_symexists_replace); 3560 RUNTIME_CHECK(tresult == ISC_R_SUCCESS); 3561 } break; 3562 3563 default: 3564 UNREACHABLE(); 3565 } 3566 isc_mem_put(mctx, key, len); 3567 } 3568 3569 if (ztype == CFG_ZONE_INVIEW) { 3570 const cfg_obj_t *fwd = NULL; 3571 unsigned int maxopts = 1; 3572 3573 (void)cfg_map_get(zoptions, "forward", &fwd); 3574 if (fwd != NULL) { 3575 maxopts++; 3576 } 3577 fwd = NULL; 3578 (void)cfg_map_get(zoptions, "forwarders", &fwd); 3579 if (fwd != NULL) { 3580 maxopts++; 3581 } 3582 if (cfg_map_count(zoptions) > maxopts) { 3583 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3584 "zone '%s': 'in-view' used " 3585 "with incompatible zone options", 3586 znamestr); 3587 if (result == ISC_R_SUCCESS) { 3588 result = ISC_R_FAILURE; 3589 } 3590 } 3591 return result; 3592 } 3593 3594 /* 3595 * Check if value is zero. 3596 */ 3597 if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS) { 3598 result = ISC_R_FAILURE; 3599 } 3600 3601 /* 3602 * Check if a dnssec-policy is set. 3603 */ 3604 obj = NULL; 3605 (void)cfg_map_get(zoptions, "dnssec-policy", &obj); 3606 if (obj == NULL && voptions != NULL) { 3607 (void)cfg_map_get(voptions, "dnssec-policy", &obj); 3608 } 3609 if (obj == NULL && goptions != NULL) { 3610 (void)cfg_map_get(goptions, "dnssec-policy", &obj); 3611 } 3612 if (obj != NULL) { 3613 kaspname = cfg_obj_asstring(obj); 3614 if (strcmp(kaspname, "default") == 0) { 3615 has_dnssecpolicy = true; 3616 kasp_inlinesigning = true; 3617 } else if (strcmp(kaspname, "insecure") == 0) { 3618 has_dnssecpolicy = true; 3619 kasp_inlinesigning = true; 3620 } else if (strcmp(kaspname, "none") == 0) { 3621 has_dnssecpolicy = false; 3622 kasp_inlinesigning = false; 3623 } else { 3624 const cfg_obj_t *kasps = NULL; 3625 (void)cfg_map_get(config, "dnssec-policy", &kasps); 3626 for (element = cfg_list_first(kasps); element != NULL; 3627 element = cfg_list_next(element)) 3628 { 3629 const cfg_obj_t *kobj = cfg_tuple_get( 3630 cfg_listelt_value(element), "name"); 3631 if (strcmp(kaspname, cfg_obj_asstring(kobj)) == 3632 0) 3633 { 3634 const cfg_obj_t *inlinesigning = NULL; 3635 const cfg_obj_t *kopt = cfg_tuple_get( 3636 cfg_listelt_value(element), 3637 "options"); 3638 if (cfg_map_get(kopt, "inline-signing", 3639 &inlinesigning) == 3640 ISC_R_SUCCESS) 3641 { 3642 kasp_inlinesigning = 3643 cfg_obj_asboolean( 3644 inlinesigning); 3645 } else { 3646 /* By default true */ 3647 kasp_inlinesigning = true; 3648 } 3649 3650 has_dnssecpolicy = true; 3651 break; 3652 } 3653 } 3654 3655 if (!has_dnssecpolicy) { 3656 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 3657 "zone '%s': option " 3658 "'dnssec-policy %s' has no " 3659 "matching dnssec-policy config", 3660 znamestr, kaspname); 3661 if (result == ISC_R_SUCCESS) { 3662 result = ISC_R_FAILURE; 3663 } 3664 } 3665 } 3666 if (has_dnssecpolicy) { 3667 kasp = obj; 3668 } 3669 } 3670 3671 /* 3672 * Reject zones with both dnssec-policy and max-zone-ttl 3673 * */ 3674 if (has_dnssecpolicy) { 3675 obj = NULL; 3676 (void)cfg_map_get(zoptions, "max-zone-ttl", &obj); 3677 if (obj == NULL && voptions != NULL) { 3678 (void)cfg_map_get(voptions, "max-zone-ttl", &obj); 3679 } 3680 if (obj == NULL && goptions != NULL) { 3681 (void)cfg_map_get(goptions, "max-zone-ttl", &obj); 3682 } 3683 if (obj != NULL) { 3684 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3685 "zone '%s': option 'max-zone-ttl' " 3686 "cannot be used together with " 3687 "'dnssec-policy'", 3688 znamestr); 3689 if (result == ISC_R_SUCCESS) { 3690 result = ISC_R_FAILURE; 3691 } 3692 } 3693 } 3694 3695 /* 3696 * Check validity of the zone options. 3697 */ 3698 option = cfg_map_firstclause(&cfg_type_zoneopts, &clauses, &i); 3699 while (option != NULL) { 3700 obj = NULL; 3701 if (cfg_map_get(zoptions, option, &obj) == ISC_R_SUCCESS && 3702 obj != NULL && !cfg_clause_validforzone(option, ztype)) 3703 { 3704 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 3705 "option '%s' is not allowed " 3706 "in '%s' zone '%s'", 3707 option, typestr, znamestr); 3708 result = ISC_R_FAILURE; 3709 } 3710 option = cfg_map_nextclause(&cfg_type_zoneopts, &clauses, &i); 3711 } 3712 3713 /* 3714 * Check that ACLs expand correctly. 3715 */ 3716 for (i = 0; i < ARRAY_SIZE(acls); i++) { 3717 tresult = checkacl(acls[i], actx, zconfig, voptions, config, 3718 logctx, mctx); 3719 if (tresult != ISC_R_SUCCESS) { 3720 result = tresult; 3721 } 3722 } 3723 3724 /* 3725 * Only a limited subset of all possible "notify" settings can be used 3726 * at the zone level for mirror zones. 3727 */ 3728 if (ztype == CFG_ZONE_MIRROR && 3729 !check_mirror_zone_notify(zoptions, znamestr, logctx)) 3730 { 3731 result = ISC_R_FAILURE; 3732 } 3733 3734 /* 3735 * Primary, secondary, and mirror zones may have an "also-notify" 3736 * field, but shouldn't if notify is disabled. 3737 */ 3738 if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY || 3739 ztype == CFG_ZONE_MIRROR) 3740 { 3741 bool donotify = true; 3742 3743 obj = NULL; 3744 tresult = cfg_map_get(zoptions, "notify", &obj); 3745 if (tresult != ISC_R_SUCCESS && voptions != NULL) { 3746 tresult = cfg_map_get(voptions, "notify", &obj); 3747 } 3748 if (tresult != ISC_R_SUCCESS && goptions != NULL) { 3749 tresult = cfg_map_get(goptions, "notify", &obj); 3750 } 3751 if (tresult == ISC_R_SUCCESS) { 3752 if (cfg_obj_isboolean(obj)) { 3753 donotify = cfg_obj_asboolean(obj); 3754 } else { 3755 const char *str = cfg_obj_asstring(obj); 3756 if (ztype != CFG_ZONE_PRIMARY && 3757 (strcasecmp(str, "master-only") == 0 || 3758 strcasecmp(str, "primary-only") == 0)) 3759 { 3760 donotify = false; 3761 } 3762 } 3763 } 3764 3765 obj = NULL; 3766 tresult = cfg_map_get(zoptions, "also-notify", &obj); 3767 if (tresult == ISC_R_SUCCESS && !donotify) { 3768 cfg_obj_log(zoptions, logctx, ISC_LOG_WARNING, 3769 "zone '%s': 'also-notify' set but " 3770 "'notify' is disabled", 3771 znamestr); 3772 } 3773 if (tresult != ISC_R_SUCCESS && voptions != NULL) { 3774 tresult = cfg_map_get(voptions, "also-notify", &obj); 3775 } 3776 if (tresult != ISC_R_SUCCESS && goptions != NULL) { 3777 tresult = cfg_map_get(goptions, "also-notify", &obj); 3778 } 3779 if (tresult == ISC_R_SUCCESS && donotify) { 3780 uint32_t count; 3781 tresult = validate_remotes(obj, config, &count, logctx, 3782 mctx); 3783 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) 3784 { 3785 result = tresult; 3786 } 3787 } 3788 } 3789 3790 /* 3791 * Secondary, mirror, and stub zones must have a "primaries" field, 3792 * with one exception: when mirroring the root zone, a default, 3793 * built-in primary server list is used in the absence of one 3794 * explicitly specified. 3795 */ 3796 if (ztype == CFG_ZONE_SECONDARY || ztype == CFG_ZONE_STUB || 3797 (ztype == CFG_ZONE_MIRROR && zname != NULL && 3798 !dns_name_equal(zname, dns_rootname))) 3799 { 3800 obj = NULL; 3801 (void)cfg_map_get(zoptions, "primaries", &obj); 3802 if (obj == NULL) { 3803 /* If "primaries" was unset, check for "masters" */ 3804 (void)cfg_map_get(zoptions, "masters", &obj); 3805 } else { 3806 const cfg_obj_t *obj2 = NULL; 3807 3808 /* ...bug if it was set, "masters" must not be. */ 3809 (void)cfg_map_get(zoptions, "masters", &obj2); 3810 if (obj2 != NULL) { 3811 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3812 "'primaries' and 'masters' cannot " 3813 "both be used in the same zone"); 3814 result = ISC_R_FAILURE; 3815 } 3816 } 3817 if (obj == NULL) { 3818 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 3819 "zone '%s': missing 'primaries' entry", 3820 znamestr); 3821 result = ISC_R_FAILURE; 3822 } else { 3823 uint32_t count; 3824 tresult = validate_remotes(obj, config, &count, logctx, 3825 mctx); 3826 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) 3827 { 3828 result = tresult; 3829 } 3830 if (tresult == ISC_R_SUCCESS && count == 0) { 3831 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 3832 "zone '%s': " 3833 "empty 'primaries' entry", 3834 znamestr); 3835 result = ISC_R_FAILURE; 3836 } 3837 } 3838 } 3839 3840 /* 3841 * Warn if *-source and *-source-v6 options specify a port, 3842 * and fail if they specify the default listener port. 3843 */ 3844 for (i = 0; i < ARRAY_SIZE(sources); i++) { 3845 obj = NULL; 3846 (void)cfg_map_get(zoptions, sources[i], &obj); 3847 if (obj == NULL && goptions != NULL) { 3848 (void)cfg_map_get(goptions, sources[i], &obj); 3849 } 3850 if (obj != NULL) { 3851 in_port_t port = 3852 isc_sockaddr_getport(cfg_obj_assockaddr(obj)); 3853 if (port == dnsport) { 3854 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3855 "'%s' cannot specify the " 3856 "DNS listener port (%d)", 3857 sources[i], port); 3858 result = ISC_R_FAILURE; 3859 } else if (port != 0) { 3860 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 3861 "'%s': specifying a port is " 3862 "not recommended", 3863 sources[i]); 3864 } 3865 } 3866 } 3867 3868 /* 3869 * Primary and secondary zones that have a "parental-agents" field, 3870 * must have a corresponding "parental-agents" clause. 3871 */ 3872 if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY) { 3873 obj = NULL; 3874 (void)cfg_map_get(zoptions, "parental-agents", &obj); 3875 if (obj != NULL) { 3876 uint32_t count; 3877 tresult = validate_remotes(obj, config, &count, logctx, 3878 mctx); 3879 if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) 3880 { 3881 result = tresult; 3882 } 3883 if (tresult == ISC_R_SUCCESS && count == 0) { 3884 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 3885 "zone '%s': " 3886 "empty 'parental-agents' entry", 3887 znamestr); 3888 result = ISC_R_FAILURE; 3889 } 3890 } 3891 } 3892 3893 /* 3894 * Configuring a mirror zone and disabling recursion at the same time 3895 * contradicts the purpose of the former. 3896 */ 3897 if (ztype == CFG_ZONE_MIRROR && 3898 !check_recursion(config, voptions, goptions, logctx, actx, mctx)) 3899 { 3900 cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR, 3901 "zone '%s': mirror zones cannot be used if " 3902 "recursion is disabled", 3903 znamestr); 3904 result = ISC_R_FAILURE; 3905 } 3906 3907 /* 3908 * Primary zones can't have both "allow-update" and "update-policy". 3909 */ 3910 if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY) { 3911 bool signing = false; 3912 isc_result_t res1, res2, res3; 3913 const cfg_obj_t *au = NULL; 3914 3915 obj = NULL; 3916 res1 = cfg_map_get(zoptions, "allow-update", &au); 3917 obj = NULL; 3918 res2 = cfg_map_get(zoptions, "update-policy", &obj); 3919 if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) { 3920 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3921 "zone '%s': 'allow-update' is ignored " 3922 "when 'update-policy' is present", 3923 znamestr); 3924 result = ISC_R_FAILURE; 3925 } else if (res2 == ISC_R_SUCCESS) { 3926 res3 = check_update_policy(obj, logctx); 3927 if (res3 != ISC_R_SUCCESS) { 3928 result = ISC_R_FAILURE; 3929 } 3930 } 3931 3932 /* 3933 * To determine whether dnssec-policy is allowed, 3934 * we should also check for allow-update at the 3935 * view and options levels. 3936 */ 3937 if (res1 != ISC_R_SUCCESS && voptions != NULL) { 3938 res1 = cfg_map_get(voptions, "allow-update", &au); 3939 } 3940 if (res1 != ISC_R_SUCCESS && goptions != NULL) { 3941 res1 = cfg_map_get(goptions, "allow-update", &au); 3942 } 3943 3944 if (res2 == ISC_R_SUCCESS) { 3945 ddns = true; 3946 } else if (res1 == ISC_R_SUCCESS) { 3947 dns_acl_t *acl = NULL; 3948 res1 = cfg_acl_fromconfig(au, config, logctx, actx, 3949 mctx, 0, &acl); 3950 if (res1 != ISC_R_SUCCESS) { 3951 cfg_obj_log(au, logctx, ISC_LOG_ERROR, 3952 "acl expansion failed: %s", 3953 isc_result_totext(result)); 3954 result = ISC_R_FAILURE; 3955 } else if (acl != NULL) { 3956 if (!dns_acl_isnone(acl)) { 3957 ddns = true; 3958 } 3959 dns_acl_detach(&acl); 3960 } 3961 } 3962 3963 obj = NULL; 3964 res1 = cfg_map_get(zoptions, "inline-signing", &obj); 3965 if (res1 == ISC_R_SUCCESS) { 3966 signing = cfg_obj_asboolean(obj); 3967 } else if (has_dnssecpolicy) { 3968 signing = kasp_inlinesigning; 3969 } 3970 3971 if (has_dnssecpolicy) { 3972 if (!ddns && !signing) { 3973 cfg_obj_log(kasp, logctx, ISC_LOG_ERROR, 3974 "'inline-signing yes;' must also " 3975 "be configured explicitly for " 3976 "zones using dnssec-policy%s. See " 3977 "https://kb.isc.org/docs/" 3978 "dnssec-policy-requires-dynamic-" 3979 "dns-or-inline-signing", 3980 (ztype == CFG_ZONE_PRIMARY) 3981 ? " without a configured " 3982 "'allow-update' or " 3983 "'update-policy'" 3984 : ""); 3985 result = ISC_R_FAILURE; 3986 } 3987 } 3988 3989 obj = NULL; 3990 res1 = cfg_map_get(zoptions, "sig-signing-type", &obj); 3991 if (res1 == ISC_R_SUCCESS) { 3992 uint32_t type = cfg_obj_asuint32(obj); 3993 if (type < 0xff00U || type > 0xffffU) { 3994 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 3995 "sig-signing-type: %u out of " 3996 "range [%u..%u]", 3997 type, 0xff00U, 0xffffU); 3998 result = ISC_R_FAILURE; 3999 } 4000 } 4001 4002 obj = NULL; 4003 res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj); 4004 if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SECONDARY && 4005 !signing) 4006 { 4007 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4008 "dnssec-loadkeys-interval: requires " 4009 "inline-signing when used in secondary " 4010 "zone"); 4011 result = ISC_R_FAILURE; 4012 } 4013 } 4014 4015 /* 4016 * Check the excessively complicated "dialup" option. 4017 */ 4018 if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY || 4019 ztype == CFG_ZONE_STUB) 4020 { 4021 obj = NULL; 4022 (void)cfg_map_get(zoptions, "dialup", &obj); 4023 if (obj != NULL && cfg_obj_isstring(obj)) { 4024 const char *str = cfg_obj_asstring(obj); 4025 for (i = 0; i < sizeof(dialups) / sizeof(dialups[0]); 4026 i++) 4027 { 4028 if (strcasecmp(dialups[i].name, str) != 0) { 4029 continue; 4030 } 4031 if ((dialups[i].allowed & ztype) == 0) { 4032 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4033 "dialup type '%s' is not " 4034 "allowed in '%s' " 4035 "zone '%s'", 4036 str, typestr, znamestr); 4037 result = ISC_R_FAILURE; 4038 } 4039 break; 4040 } 4041 if (i == sizeof(dialups) / sizeof(dialups[0])) { 4042 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4043 "invalid dialup type '%s' in zone " 4044 "'%s'", 4045 str, znamestr); 4046 result = ISC_R_FAILURE; 4047 } 4048 } 4049 } 4050 4051 /* 4052 * Check that forwarding is reasonable. 4053 */ 4054 obj = NULL; 4055 if (root) { 4056 if (voptions != NULL) { 4057 (void)cfg_map_get(voptions, "forwarders", &obj); 4058 } 4059 if (obj == NULL && goptions != NULL) { 4060 (void)cfg_map_get(goptions, "forwarders", &obj); 4061 } 4062 } 4063 if (check_forward(config, zoptions, obj, logctx) != ISC_R_SUCCESS) { 4064 result = ISC_R_FAILURE; 4065 } 4066 4067 /* 4068 * Check that a RFC 1918 / ULA reverse zone is not forward first 4069 * unless explicitly configured to be so. 4070 */ 4071 if (ztype == CFG_ZONE_FORWARD && (rfc1918 || ula)) { 4072 obj = NULL; 4073 (void)cfg_map_get(zoptions, "forward", &obj); 4074 if (obj == NULL) { 4075 /* 4076 * Forward mode not explicitly configured. 4077 */ 4078 if (voptions != NULL) { 4079 cfg_map_get(voptions, "forward", &obj); 4080 } 4081 if (obj == NULL && goptions != NULL) { 4082 cfg_map_get(goptions, "forward", &obj); 4083 } 4084 if (obj == NULL || 4085 strcasecmp(cfg_obj_asstring(obj), "first") == 0) 4086 { 4087 cfg_obj_log(zconfig, logctx, ISC_LOG_WARNING, 4088 "inherited 'forward first;' for " 4089 "%s zone '%s' - did you want " 4090 "'forward only;'?", 4091 rfc1918 ? "rfc1918" : "ula", 4092 znamestr); 4093 } 4094 } 4095 } 4096 4097 /* 4098 * Check validity of static stub server addresses. 4099 */ 4100 obj = NULL; 4101 (void)cfg_map_get(zoptions, "server-addresses", &obj); 4102 if (ztype == CFG_ZONE_STATICSTUB && obj != NULL) { 4103 for (element = cfg_list_first(obj); element != NULL; 4104 element = cfg_list_next(element)) 4105 { 4106 isc_sockaddr_t sa; 4107 isc_netaddr_t na; 4108 obj = cfg_listelt_value(element); 4109 sa = *cfg_obj_assockaddr(obj); 4110 4111 isc_netaddr_fromsockaddr(&na, &sa); 4112 if (isc_netaddr_getzone(&na) != 0) { 4113 result = ISC_R_FAILURE; 4114 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4115 "scoped address is not allowed " 4116 "for static stub " 4117 "server-addresses"); 4118 } 4119 } 4120 } 4121 4122 /* 4123 * Check validity of static stub server names. 4124 */ 4125 obj = NULL; 4126 (void)cfg_map_get(zoptions, "server-names", &obj); 4127 if (zname != NULL && ztype == CFG_ZONE_STATICSTUB && obj != NULL) { 4128 for (element = cfg_list_first(obj); element != NULL; 4129 element = cfg_list_next(element)) 4130 { 4131 const char *snamestr; 4132 dns_fixedname_t fixed_sname; 4133 isc_buffer_t b2; 4134 dns_name_t *sname; 4135 4136 obj = cfg_listelt_value(element); 4137 snamestr = cfg_obj_asstring(obj); 4138 4139 isc_buffer_constinit(&b2, snamestr, strlen(snamestr)); 4140 isc_buffer_add(&b2, strlen(snamestr)); 4141 sname = dns_fixedname_initname(&fixed_sname); 4142 tresult = dns_name_fromtext(sname, &b2, dns_rootname, 0, 4143 NULL); 4144 if (tresult != ISC_R_SUCCESS) { 4145 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 4146 "server-name '%s' is not a valid " 4147 "name", 4148 snamestr); 4149 result = ISC_R_FAILURE; 4150 } else if (dns_name_issubdomain(sname, zname)) { 4151 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 4152 "server-name '%s' must not be a " 4153 "subdomain of zone name '%s'", 4154 snamestr, znamestr); 4155 result = ISC_R_FAILURE; 4156 } 4157 } 4158 } 4159 4160 /* 4161 * Warn if key-directory doesn't exist 4162 */ 4163 obj = NULL; 4164 (void)cfg_map_get(zoptions, "key-directory", &obj); 4165 if (obj == NULL && voptions != NULL) { 4166 (void)cfg_map_get(voptions, "key-directory", &obj); 4167 } 4168 if (obj == NULL && goptions != NULL) { 4169 (void)cfg_map_get(goptions, "key-directory", &obj); 4170 } 4171 if (obj != NULL) { 4172 dir = cfg_obj_asstring(obj); 4173 4174 tresult = isc_file_isdirectory(dir); 4175 switch (tresult) { 4176 case ISC_R_SUCCESS: 4177 break; 4178 case ISC_R_FILENOTFOUND: 4179 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 4180 "key-directory: '%s' does not exist", dir); 4181 break; 4182 case ISC_R_INVALIDFILE: 4183 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 4184 "key-directory: '%s' is not a directory", 4185 dir); 4186 break; 4187 default: 4188 cfg_obj_log(obj, logctx, ISC_LOG_WARNING, 4189 "key-directory: '%s' %s", dir, 4190 isc_result_totext(tresult)); 4191 result = tresult; 4192 } 4193 } 4194 4195 /* 4196 * Make sure there is no other zone with the same key directory (from 4197 * (key-directory or key-store/directory) and a different dnssec-policy. 4198 */ 4199 if (zname != NULL) { 4200 if (has_dnssecpolicy) { 4201 tresult = check_keydir(config, zconfig, zname, znamestr, 4202 kaspname, dir, keydirs, logctx, 4203 mctx, check_keys); 4204 } else { 4205 tresult = keydirexist(zconfig, "key-directory", zname, 4206 dir, kaspname, keydirs, logctx, 4207 mctx); 4208 } 4209 if (tresult != ISC_R_SUCCESS) { 4210 result = tresult; 4211 } 4212 } 4213 4214 /* 4215 * Check various options. 4216 */ 4217 tresult = check_options(zoptions, config, false, logctx, mctx, 4218 optlevel_zone); 4219 if (tresult != ISC_R_SUCCESS) { 4220 result = tresult; 4221 } 4222 4223 /* 4224 * If the zone type is rbt then primary/hint zones require file 4225 * clauses. If inline-signing is used, then secondary zones require a 4226 * file clause as well. 4227 */ 4228 obj = NULL; 4229 dlz = false; 4230 tresult = cfg_map_get(zoptions, "dlz", &obj); 4231 if (tresult == ISC_R_SUCCESS) { 4232 dlz = true; 4233 } 4234 4235 obj = NULL; 4236 tresult = cfg_map_get(zoptions, "database", &obj); 4237 if (dlz && tresult == ISC_R_SUCCESS) { 4238 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 4239 "zone '%s': cannot specify both 'dlz' " 4240 "and 'database'", 4241 znamestr); 4242 result = ISC_R_FAILURE; 4243 } else if (!dlz && 4244 (tresult == ISC_R_NOTFOUND || 4245 (tresult == ISC_R_SUCCESS && 4246 strcmp(ZONEDB_DEFAULT, cfg_obj_asstring(obj)) == 0))) 4247 { 4248 isc_result_t res1; 4249 const cfg_obj_t *fileobj = NULL; 4250 tresult = cfg_map_get(zoptions, "file", &fileobj); 4251 obj = NULL; 4252 res1 = cfg_map_get(zoptions, "inline-signing", &obj); 4253 if (tresult != ISC_R_SUCCESS && 4254 (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_HINT || 4255 (ztype == CFG_ZONE_SECONDARY && res1 == ISC_R_SUCCESS && 4256 cfg_obj_asboolean(obj)))) 4257 { 4258 cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR, 4259 "zone '%s': missing 'file' entry", 4260 znamestr); 4261 result = tresult; 4262 } else if (tresult == ISC_R_SUCCESS && 4263 (ztype == CFG_ZONE_SECONDARY || 4264 ztype == CFG_ZONE_MIRROR || ddns || 4265 has_dnssecpolicy)) 4266 { 4267 tresult = fileexist(fileobj, files, true, logctx); 4268 if (tresult != ISC_R_SUCCESS) { 4269 result = tresult; 4270 } 4271 } else if (tresult == ISC_R_SUCCESS && 4272 (ztype == CFG_ZONE_PRIMARY || 4273 ztype == CFG_ZONE_HINT)) 4274 { 4275 tresult = fileexist(fileobj, files, false, logctx); 4276 if (tresult != ISC_R_SUCCESS) { 4277 result = tresult; 4278 } 4279 } 4280 } 4281 4282 return result; 4283 } 4284 4285 typedef struct keyalgorithms { 4286 const char *name; 4287 uint16_t size; 4288 } algorithmtable; 4289 4290 isc_result_t 4291 isccfg_check_key(const cfg_obj_t *key, isc_log_t *logctx) { 4292 const cfg_obj_t *algobj = NULL; 4293 const cfg_obj_t *secretobj = NULL; 4294 const char *keyname = cfg_obj_asstring(cfg_map_getname(key)); 4295 const char *algorithm; 4296 int i; 4297 size_t len = 0; 4298 isc_result_t result; 4299 isc_buffer_t buf; 4300 unsigned char secretbuf[1024]; 4301 static const algorithmtable algorithms[] = { 4302 { "hmac-md5", 128 }, 4303 { "hmac-md5.sig-alg.reg.int", 0 }, 4304 { "hmac-md5.sig-alg.reg.int.", 0 }, 4305 { "hmac-sha1", 160 }, 4306 { "hmac-sha224", 224 }, 4307 { "hmac-sha256", 256 }, 4308 { "hmac-sha384", 384 }, 4309 { "hmac-sha512", 512 }, 4310 { NULL, 0 } 4311 }; 4312 4313 (void)cfg_map_get(key, "algorithm", &algobj); 4314 (void)cfg_map_get(key, "secret", &secretobj); 4315 if (secretobj == NULL || algobj == NULL) { 4316 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4317 "key '%s' must have both 'secret' and " 4318 "'algorithm' defined", 4319 keyname); 4320 return ISC_R_FAILURE; 4321 } 4322 4323 isc_buffer_init(&buf, secretbuf, sizeof(secretbuf)); 4324 result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf); 4325 if (result != ISC_R_SUCCESS) { 4326 cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR, "bad secret '%s'", 4327 isc_result_totext(result)); 4328 return result; 4329 } 4330 4331 algorithm = cfg_obj_asstring(algobj); 4332 for (i = 0; algorithms[i].name != NULL; i++) { 4333 len = strlen(algorithms[i].name); 4334 if (strncasecmp(algorithms[i].name, algorithm, len) == 0 && 4335 (algorithm[len] == '\0' || 4336 (algorithms[i].size != 0 && algorithm[len] == '-'))) 4337 { 4338 break; 4339 } 4340 } 4341 if (algorithms[i].name == NULL) { 4342 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, 4343 "unknown algorithm '%s'", algorithm); 4344 return ISC_R_NOTFOUND; 4345 } 4346 if (algorithm[len] == '-') { 4347 uint16_t digestbits; 4348 result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10); 4349 if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) { 4350 if (result == ISC_R_RANGE || 4351 digestbits > algorithms[i].size) 4352 { 4353 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, 4354 "key '%s' digest-bits too large " 4355 "[%u..%u]", 4356 keyname, algorithms[i].size / 2, 4357 algorithms[i].size); 4358 return ISC_R_RANGE; 4359 } 4360 if ((digestbits % 8) != 0) { 4361 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, 4362 "key '%s' digest-bits not multiple" 4363 " of 8", 4364 keyname); 4365 return ISC_R_RANGE; 4366 } 4367 /* 4368 * Recommended minima for hmac algorithms. 4369 */ 4370 if (digestbits < (algorithms[i].size / 2U) || 4371 (digestbits < 80U)) 4372 { 4373 cfg_obj_log(algobj, logctx, ISC_LOG_WARNING, 4374 "key '%s' digest-bits too small " 4375 "[<%u]", 4376 keyname, algorithms[i].size / 2); 4377 } 4378 } else { 4379 cfg_obj_log(algobj, logctx, ISC_LOG_ERROR, 4380 "key '%s': unable to parse digest-bits", 4381 keyname); 4382 return result; 4383 } 4384 } 4385 return ISC_R_SUCCESS; 4386 } 4387 4388 static isc_result_t 4389 fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable, 4390 isc_log_t *logctx) { 4391 isc_result_t result; 4392 isc_symvalue_t symvalue; 4393 unsigned int line; 4394 const char *file; 4395 4396 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 0, &symvalue); 4397 if (result == ISC_R_SUCCESS) { 4398 if (writeable) { 4399 file = cfg_obj_file(symvalue.as_cpointer); 4400 line = cfg_obj_line(symvalue.as_cpointer); 4401 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4402 "writeable file '%s': already in use: " 4403 "%s:%u", 4404 cfg_obj_asstring(obj), file, line); 4405 return ISC_R_EXISTS; 4406 } 4407 result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 2, 4408 &symvalue); 4409 if (result == ISC_R_SUCCESS) { 4410 file = cfg_obj_file(symvalue.as_cpointer); 4411 line = cfg_obj_line(symvalue.as_cpointer); 4412 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4413 "writeable file '%s': already in use: " 4414 "%s:%u", 4415 cfg_obj_asstring(obj), file, line); 4416 return ISC_R_EXISTS; 4417 } 4418 return ISC_R_SUCCESS; 4419 } 4420 4421 symvalue.as_cpointer = obj; 4422 result = isc_symtab_define(symtab, cfg_obj_asstring(obj), 4423 writeable ? 2 : 1, symvalue, 4424 isc_symexists_reject); 4425 return result; 4426 } 4427 4428 static isc_result_t 4429 keydirexist(const cfg_obj_t *zcfg, const char *optname, dns_name_t *zname, 4430 const char *dirname, const char *kaspnamestr, isc_symtab_t *symtab, 4431 isc_log_t *logctx, isc_mem_t *mctx) { 4432 isc_result_t result; 4433 isc_symvalue_t symvalue; 4434 char *symkey; 4435 char keydirbuf[DNS_NAME_FORMATSIZE + 128]; 4436 char *keydir = keydirbuf; 4437 size_t len = sizeof(keydirbuf); 4438 size_t n; 4439 4440 if (kaspnamestr == NULL || strcmp(kaspnamestr, "none") == 0) { 4441 return ISC_R_SUCCESS; 4442 } 4443 4444 dns_name_format(zname, keydirbuf, sizeof(keydirbuf)); 4445 len -= strlen(keydir); 4446 keydir += strlen(keydir); 4447 n = snprintf(keydir, len, "/%s", (dirname == NULL) ? "." : dirname); 4448 if (n > len) { 4449 cfg_obj_log(zcfg, logctx, ISC_LOG_WARNING, 4450 "%s '%s' truncated because too long, may cause " 4451 "false positives in key directory in use checks", 4452 optname, (dirname == NULL) ? "." : dirname); 4453 } 4454 keydir = keydirbuf; 4455 4456 result = isc_symtab_lookup(symtab, keydir, 0, &symvalue); 4457 if (result == ISC_R_SUCCESS) { 4458 const cfg_obj_t *kasp = NULL; 4459 const cfg_obj_t *exist = symvalue.as_cpointer; 4460 const char *file = cfg_obj_file(exist); 4461 unsigned int line = cfg_obj_line(exist); 4462 4463 /* 4464 * Having the same key-directory for the same zone is fine 4465 * iff the zone is using the same policy, or has no policy. 4466 */ 4467 (void)cfg_map_get(cfg_tuple_get(exist, "options"), 4468 "dnssec-policy", &kasp); 4469 if (kasp == NULL || 4470 strcmp(cfg_obj_asstring(kasp), "none") == 0 || 4471 strcmp(cfg_obj_asstring(kasp), kaspnamestr) == 0) 4472 { 4473 return ISC_R_SUCCESS; 4474 } 4475 4476 cfg_obj_log(zcfg, logctx, ISC_LOG_ERROR, 4477 "%s '%s' already in use by zone %s with " 4478 "policy %s: %s:%u", 4479 optname, keydir, 4480 cfg_obj_asstring(cfg_tuple_get(exist, "name")), 4481 cfg_obj_asstring(kasp), file, line); 4482 return ISC_R_EXISTS; 4483 } 4484 4485 /* 4486 * Add the new zone plus key-directory. 4487 */ 4488 symkey = isc_mem_strdup(mctx, keydir); 4489 symvalue.as_cpointer = zcfg; 4490 result = isc_symtab_define(symtab, symkey, 2, symvalue, 4491 isc_symexists_reject); 4492 RUNTIME_CHECK(result == ISC_R_SUCCESS); 4493 return result; 4494 } 4495 4496 /* 4497 * Check key list for duplicates key names and that the key names 4498 * are valid domain names as these keys are used for TSIG. 4499 * 4500 * Check the key contents for validity. 4501 */ 4502 static isc_result_t 4503 check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab, isc_mem_t *mctx, 4504 isc_log_t *logctx) { 4505 char namebuf[DNS_NAME_FORMATSIZE]; 4506 dns_fixedname_t fname; 4507 dns_name_t *name; 4508 isc_result_t result = ISC_R_SUCCESS; 4509 isc_result_t tresult; 4510 const cfg_listelt_t *element; 4511 4512 name = dns_fixedname_initname(&fname); 4513 for (element = cfg_list_first(keys); element != NULL; 4514 element = cfg_list_next(element)) 4515 { 4516 const cfg_obj_t *key = cfg_listelt_value(element); 4517 const char *keyid = cfg_obj_asstring(cfg_map_getname(key)); 4518 isc_symvalue_t symvalue; 4519 isc_buffer_t b; 4520 char *keyname; 4521 4522 isc_buffer_constinit(&b, keyid, strlen(keyid)); 4523 isc_buffer_add(&b, strlen(keyid)); 4524 tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL); 4525 if (tresult != ISC_R_SUCCESS) { 4526 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4527 "key '%s': bad key name", keyid); 4528 result = tresult; 4529 continue; 4530 } 4531 tresult = isccfg_check_key(key, logctx); 4532 if (tresult != ISC_R_SUCCESS) { 4533 return tresult; 4534 } 4535 4536 dns_name_format(name, namebuf, sizeof(namebuf)); 4537 keyname = isc_mem_strdup(mctx, namebuf); 4538 symvalue.as_cpointer = key; 4539 tresult = isc_symtab_define(symtab, keyname, 1, symvalue, 4540 isc_symexists_reject); 4541 if (tresult == ISC_R_EXISTS) { 4542 const char *file; 4543 unsigned int line; 4544 4545 RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname, 1, 4546 &symvalue) == 4547 ISC_R_SUCCESS); 4548 file = cfg_obj_file(symvalue.as_cpointer); 4549 line = cfg_obj_line(symvalue.as_cpointer); 4550 4551 if (file == NULL) { 4552 file = "<unknown file>"; 4553 } 4554 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4555 "key '%s': already exists " 4556 "previous definition: %s:%u", 4557 keyid, file, line); 4558 isc_mem_free(mctx, keyname); 4559 result = tresult; 4560 } else if (tresult != ISC_R_SUCCESS) { 4561 isc_mem_free(mctx, keyname); 4562 return tresult; 4563 } 4564 } 4565 return result; 4566 } 4567 4568 /* 4569 * RNDC keys are not normalised unlike TSIG keys. 4570 * 4571 * "foo." is different to "foo". 4572 */ 4573 static bool 4574 rndckey_exists(const cfg_obj_t *keylist, const char *keyname) { 4575 const cfg_listelt_t *element; 4576 const cfg_obj_t *obj; 4577 const char *str; 4578 4579 if (keylist == NULL) { 4580 return false; 4581 } 4582 4583 for (element = cfg_list_first(keylist); element != NULL; 4584 element = cfg_list_next(element)) 4585 { 4586 obj = cfg_listelt_value(element); 4587 str = cfg_obj_asstring(cfg_map_getname(obj)); 4588 if (!strcasecmp(str, keyname)) { 4589 return true; 4590 } 4591 } 4592 return false; 4593 } 4594 4595 static struct { 4596 const char *v4; 4597 const char *v6; 4598 } sources[] = { { "transfer-source", "transfer-source-v6" }, 4599 { "notify-source", "notify-source-v6" }, 4600 { "parental-source", "parental-source-v6" }, 4601 { "query-source", "query-source-v6" }, 4602 { NULL, NULL } }; 4603 4604 static struct { 4605 const char *name; 4606 isc_result_t (*set)(dns_peer_t *peer, bool newval); 4607 } bools[] = { 4608 { "bogus", dns_peer_setbogus }, 4609 { "edns", dns_peer_setsupportedns }, 4610 { "provide-ixfr", dns_peer_setprovideixfr }, 4611 { "request-expire", dns_peer_setrequestexpire }, 4612 { "request-ixfr", dns_peer_setrequestixfr }, 4613 { "request-nsid", dns_peer_setrequestnsid }, 4614 { "send-cookie", dns_peer_setsendcookie }, 4615 { "tcp-keepalive", dns_peer_settcpkeepalive }, 4616 { "tcp-only", dns_peer_setforcetcp }, 4617 }; 4618 4619 static isc_result_t 4620 check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions, 4621 isc_symtab_t *symtab, isc_mem_t *mctx, isc_log_t *logctx) { 4622 dns_fixedname_t fname; 4623 isc_result_t result = ISC_R_SUCCESS; 4624 isc_result_t tresult; 4625 const cfg_listelt_t *e1, *e2; 4626 const cfg_obj_t *v1, *v2, *keys; 4627 const cfg_obj_t *servers; 4628 isc_netaddr_t n1, n2; 4629 unsigned int p1, p2; 4630 const cfg_obj_t *obj; 4631 char buf[ISC_NETADDR_FORMATSIZE]; 4632 char namebuf[DNS_NAME_FORMATSIZE]; 4633 const char *xfr; 4634 const char *keyval; 4635 isc_buffer_t b; 4636 int source; 4637 dns_name_t *keyname; 4638 4639 servers = NULL; 4640 if (voptions != NULL) { 4641 (void)cfg_map_get(voptions, "server", &servers); 4642 } 4643 if (servers == NULL) { 4644 (void)cfg_map_get(config, "server", &servers); 4645 } 4646 if (servers == NULL) { 4647 return ISC_R_SUCCESS; 4648 } 4649 4650 for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) { 4651 dns_peer_t *peer = NULL; 4652 size_t i; 4653 v1 = cfg_listelt_value(e1); 4654 cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1); 4655 /* 4656 * Check that unused bits are zero. 4657 */ 4658 tresult = isc_netaddr_prefixok(&n1, p1); 4659 if (tresult != ISC_R_SUCCESS) { 4660 INSIST(tresult == ISC_R_FAILURE); 4661 isc_netaddr_format(&n1, buf, sizeof(buf)); 4662 cfg_obj_log(v1, logctx, ISC_LOG_ERROR, 4663 "server '%s/%u': invalid prefix " 4664 "(extra bits specified)", 4665 buf, p1); 4666 result = tresult; 4667 } 4668 source = 0; 4669 do { 4670 /* 4671 * For a v6 server we can't specify a v4 source, 4672 * and vice versa. 4673 */ 4674 obj = NULL; 4675 if (n1.family == AF_INET) { 4676 xfr = sources[source].v6; 4677 } else { 4678 xfr = sources[source].v4; 4679 } 4680 (void)cfg_map_get(v1, xfr, &obj); 4681 if (obj != NULL) { 4682 isc_netaddr_format(&n1, buf, sizeof(buf)); 4683 cfg_obj_log(v1, logctx, ISC_LOG_ERROR, 4684 "server '%s/%u': %s not legal", buf, 4685 p1, xfr); 4686 result = ISC_R_FAILURE; 4687 } 4688 4689 /* 4690 * Check that we aren't using the DNS 4691 * listener port (i.e. 53, or whatever was set 4692 * as "port" in options) as a source port. 4693 */ 4694 obj = NULL; 4695 if (n1.family == AF_INET) { 4696 xfr = sources[source].v4; 4697 } else { 4698 xfr = sources[source].v6; 4699 } 4700 (void)cfg_map_get(v1, xfr, &obj); 4701 if (obj != NULL) { 4702 if (cfg_obj_issockaddr(obj)) { 4703 const isc_sockaddr_t *sa = 4704 cfg_obj_assockaddr(obj); 4705 in_port_t port = 4706 isc_sockaddr_getport(sa); 4707 if (port == dnsport) { 4708 cfg_obj_log(obj, logctx, 4709 ISC_LOG_ERROR, 4710 "'%s' cannot " 4711 "specify the " 4712 "DNS listener port " 4713 "(%d)", 4714 xfr, port); 4715 result = ISC_R_FAILURE; 4716 } 4717 } else { 4718 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 4719 "'none' is not a legal " 4720 "'%s' parameter in a " 4721 "server block", 4722 xfr); 4723 result = ISC_R_FAILURE; 4724 } 4725 } 4726 } while (sources[++source].v4 != NULL); 4727 e2 = e1; 4728 while ((e2 = cfg_list_next(e2)) != NULL) { 4729 v2 = cfg_listelt_value(e2); 4730 cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2); 4731 if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) { 4732 const char *file = cfg_obj_file(v1); 4733 unsigned int line = cfg_obj_line(v1); 4734 4735 if (file == NULL) { 4736 file = "<unknown file>"; 4737 } 4738 4739 isc_netaddr_format(&n2, buf, sizeof(buf)); 4740 cfg_obj_log(v2, logctx, ISC_LOG_ERROR, 4741 "server '%s/%u': already exists " 4742 "previous definition: %s:%u", 4743 buf, p2, file, line); 4744 result = ISC_R_FAILURE; 4745 } 4746 } 4747 keys = NULL; 4748 cfg_map_get(v1, "keys", &keys); 4749 if (keys != NULL) { 4750 /* 4751 * Normalize key name. 4752 */ 4753 keyval = cfg_obj_asstring(keys); 4754 isc_buffer_constinit(&b, keyval, strlen(keyval)); 4755 isc_buffer_add(&b, strlen(keyval)); 4756 keyname = dns_fixedname_initname(&fname); 4757 tresult = dns_name_fromtext(keyname, &b, dns_rootname, 4758 0, NULL); 4759 if (tresult != ISC_R_SUCCESS) { 4760 cfg_obj_log(keys, logctx, ISC_LOG_ERROR, 4761 "bad key name '%s'", keyval); 4762 result = ISC_R_FAILURE; 4763 continue; 4764 } 4765 dns_name_format(keyname, namebuf, sizeof(namebuf)); 4766 tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL); 4767 if (tresult != ISC_R_SUCCESS) { 4768 cfg_obj_log(keys, logctx, ISC_LOG_ERROR, 4769 "unknown key '%s'", keyval); 4770 result = ISC_R_FAILURE; 4771 } 4772 } 4773 (void)dns_peer_newprefix(mctx, &n1, p1, &peer); 4774 for (i = 0; i < ARRAY_SIZE(bools); i++) { 4775 const cfg_obj_t *opt = NULL; 4776 cfg_map_get(v1, bools[i].name, &opt); 4777 if (opt != NULL) { 4778 tresult = (bools[i].set)( 4779 peer, cfg_obj_asboolean(opt)); 4780 if (tresult != ISC_R_SUCCESS) { 4781 cfg_obj_log(opt, logctx, ISC_LOG_ERROR, 4782 "setting server option " 4783 "'%s' failed: %s", 4784 bools[i].name, 4785 isc_result_totext(tresult)); 4786 result = ISC_R_FAILURE; 4787 } 4788 } 4789 } 4790 dns_peer_detach(&peer); 4791 } 4792 return result; 4793 } 4794 4795 #define ROOT_KSK_STATIC 0x01 4796 #define ROOT_KSK_MANAGED 0x02 4797 #define ROOT_KSK_ANY 0x03 4798 #define ROOT_KSK_2010 0x04 4799 #define ROOT_KSK_2017 0x08 4800 4801 static isc_result_t 4802 check_trust_anchor(const cfg_obj_t *key, bool managed, unsigned int *flagsp, 4803 isc_log_t *logctx) { 4804 const char *str = NULL, *namestr = NULL; 4805 dns_fixedname_t fkeyname; 4806 dns_name_t *keyname = NULL; 4807 isc_buffer_t b; 4808 isc_region_t r; 4809 isc_result_t result = ISC_R_SUCCESS; 4810 isc_result_t tresult; 4811 uint32_t rdata1, rdata2, rdata3; 4812 unsigned char data[4096]; 4813 const char *atstr = NULL; 4814 enum { 4815 INIT_DNSKEY, 4816 STATIC_DNSKEY, 4817 INIT_DS, 4818 STATIC_DS, 4819 TRUSTED 4820 } anchortype; 4821 4822 /* 4823 * The 2010 and 2017 IANA root keys - these are used below 4824 * to check the contents of trusted, initial and 4825 * static trust anchor configurations. 4826 */ 4827 static const unsigned char root_ksk_2010[] = { 4828 0x03, 0x01, 0x00, 0x01, 0xa8, 0x00, 0x20, 0xa9, 0x55, 0x66, 4829 0xba, 0x42, 0xe8, 0x86, 0xbb, 0x80, 0x4c, 0xda, 0x84, 0xe4, 4830 0x7e, 0xf5, 0x6d, 0xbd, 0x7a, 0xec, 0x61, 0x26, 0x15, 0x55, 4831 0x2c, 0xec, 0x90, 0x6d, 0x21, 0x16, 0xd0, 0xef, 0x20, 0x70, 4832 0x28, 0xc5, 0x15, 0x54, 0x14, 0x4d, 0xfe, 0xaf, 0xe7, 0xc7, 4833 0xcb, 0x8f, 0x00, 0x5d, 0xd1, 0x82, 0x34, 0x13, 0x3a, 0xc0, 4834 0x71, 0x0a, 0x81, 0x18, 0x2c, 0xe1, 0xfd, 0x14, 0xad, 0x22, 4835 0x83, 0xbc, 0x83, 0x43, 0x5f, 0x9d, 0xf2, 0xf6, 0x31, 0x32, 4836 0x51, 0x93, 0x1a, 0x17, 0x6d, 0xf0, 0xda, 0x51, 0xe5, 0x4f, 4837 0x42, 0xe6, 0x04, 0x86, 0x0d, 0xfb, 0x35, 0x95, 0x80, 0x25, 4838 0x0f, 0x55, 0x9c, 0xc5, 0x43, 0xc4, 0xff, 0xd5, 0x1c, 0xbe, 4839 0x3d, 0xe8, 0xcf, 0xd0, 0x67, 0x19, 0x23, 0x7f, 0x9f, 0xc4, 4840 0x7e, 0xe7, 0x29, 0xda, 0x06, 0x83, 0x5f, 0xa4, 0x52, 0xe8, 4841 0x25, 0xe9, 0xa1, 0x8e, 0xbc, 0x2e, 0xcb, 0xcf, 0x56, 0x34, 4842 0x74, 0x65, 0x2c, 0x33, 0xcf, 0x56, 0xa9, 0x03, 0x3b, 0xcd, 4843 0xf5, 0xd9, 0x73, 0x12, 0x17, 0x97, 0xec, 0x80, 0x89, 0x04, 4844 0x1b, 0x6e, 0x03, 0xa1, 0xb7, 0x2d, 0x0a, 0x73, 0x5b, 0x98, 4845 0x4e, 0x03, 0x68, 0x73, 0x09, 0x33, 0x23, 0x24, 0xf2, 0x7c, 4846 0x2d, 0xba, 0x85, 0xe9, 0xdb, 0x15, 0xe8, 0x3a, 0x01, 0x43, 4847 0x38, 0x2e, 0x97, 0x4b, 0x06, 0x21, 0xc1, 0x8e, 0x62, 0x5e, 4848 0xce, 0xc9, 0x07, 0x57, 0x7d, 0x9e, 0x7b, 0xad, 0xe9, 0x52, 4849 0x41, 0xa8, 0x1e, 0xbb, 0xe8, 0xa9, 0x01, 0xd4, 0xd3, 0x27, 4850 0x6e, 0x40, 0xb1, 0x14, 0xc0, 0xa2, 0xe6, 0xfc, 0x38, 0xd1, 4851 0x9c, 0x2e, 0x6a, 0xab, 0x02, 0x64, 0x4b, 0x28, 0x13, 0xf5, 4852 0x75, 0xfc, 0x21, 0x60, 0x1e, 0x0d, 0xee, 0x49, 0xcd, 0x9e, 4853 0xe9, 0x6a, 0x43, 0x10, 0x3e, 0x52, 0x4d, 0x62, 0x87, 0x3d 4854 }; 4855 static const unsigned char root_ksk_2017[] = { 4856 0x03, 0x01, 0x00, 0x01, 0xac, 0xff, 0xb4, 0x09, 0xbc, 0xc9, 4857 0x39, 0xf8, 0x31, 0xf7, 0xa1, 0xe5, 0xec, 0x88, 0xf7, 0xa5, 4858 0x92, 0x55, 0xec, 0x53, 0x04, 0x0b, 0xe4, 0x32, 0x02, 0x73, 4859 0x90, 0xa4, 0xce, 0x89, 0x6d, 0x6f, 0x90, 0x86, 0xf3, 0xc5, 4860 0xe1, 0x77, 0xfb, 0xfe, 0x11, 0x81, 0x63, 0xaa, 0xec, 0x7a, 4861 0xf1, 0x46, 0x2c, 0x47, 0x94, 0x59, 0x44, 0xc4, 0xe2, 0xc0, 4862 0x26, 0xbe, 0x5e, 0x98, 0xbb, 0xcd, 0xed, 0x25, 0x97, 0x82, 4863 0x72, 0xe1, 0xe3, 0xe0, 0x79, 0xc5, 0x09, 0x4d, 0x57, 0x3f, 4864 0x0e, 0x83, 0xc9, 0x2f, 0x02, 0xb3, 0x2d, 0x35, 0x13, 0xb1, 4865 0x55, 0x0b, 0x82, 0x69, 0x29, 0xc8, 0x0d, 0xd0, 0xf9, 0x2c, 4866 0xac, 0x96, 0x6d, 0x17, 0x76, 0x9f, 0xd5, 0x86, 0x7b, 0x64, 4867 0x7c, 0x3f, 0x38, 0x02, 0x9a, 0xbd, 0xc4, 0x81, 0x52, 0xeb, 4868 0x8f, 0x20, 0x71, 0x59, 0xec, 0xc5, 0xd2, 0x32, 0xc7, 0xc1, 4869 0x53, 0x7c, 0x79, 0xf4, 0xb7, 0xac, 0x28, 0xff, 0x11, 0x68, 4870 0x2f, 0x21, 0x68, 0x1b, 0xf6, 0xd6, 0xab, 0xa5, 0x55, 0x03, 4871 0x2b, 0xf6, 0xf9, 0xf0, 0x36, 0xbe, 0xb2, 0xaa, 0xa5, 0xb3, 4872 0x77, 0x8d, 0x6e, 0xeb, 0xfb, 0xa6, 0xbf, 0x9e, 0xa1, 0x91, 4873 0xbe, 0x4a, 0xb0, 0xca, 0xea, 0x75, 0x9e, 0x2f, 0x77, 0x3a, 4874 0x1f, 0x90, 0x29, 0xc7, 0x3e, 0xcb, 0x8d, 0x57, 0x35, 0xb9, 4875 0x32, 0x1d, 0xb0, 0x85, 0xf1, 0xb8, 0xe2, 0xd8, 0x03, 0x8f, 4876 0xe2, 0x94, 0x19, 0x92, 0x54, 0x8c, 0xee, 0x0d, 0x67, 0xdd, 4877 0x45, 0x47, 0xe1, 0x1d, 0xd6, 0x3a, 0xf9, 0xc9, 0xfc, 0x1c, 4878 0x54, 0x66, 0xfb, 0x68, 0x4c, 0xf0, 0x09, 0xd7, 0x19, 0x7c, 4879 0x2c, 0xf7, 0x9e, 0x79, 0x2a, 0xb5, 0x01, 0xe6, 0xa8, 0xa1, 4880 0xca, 0x51, 0x9a, 0xf2, 0xcb, 0x9b, 0x5f, 0x63, 0x67, 0xe9, 4881 0x4c, 0x0d, 0x47, 0x50, 0x24, 0x51, 0x35, 0x7b, 0xe1, 0xb5 4882 }; 4883 static const unsigned char root_ds_1_2017[] = { 4884 0xae, 0x1e, 0xa5, 0xb9, 0x74, 0xd4, 0xc8, 0x58, 0xb7, 0x40, 4885 0xbd, 0x03, 0xe3, 0xce, 0xd7, 0xeb, 0xfc, 0xbd, 0x17, 0x24 4886 }; 4887 static const unsigned char root_ds_2_2017[] = { 4888 0xe0, 0x6d, 0x44, 0xb8, 0x0b, 0x8f, 0x1d, 0x39, 4889 0xa9, 0x5c, 0x0b, 0x0d, 0x7c, 0x65, 0xd0, 0x84, 4890 0x58, 0xe8, 0x80, 0x40, 0x9b, 0xbc, 0x68, 0x34, 4891 0x57, 0x10, 0x42, 0x37, 0xc7, 0xf8, 0xec, 0x8D 4892 }; 4893 4894 /* if DNSKEY, flags; if DS, key tag */ 4895 rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1")); 4896 4897 /* if DNSKEY, protocol; if DS, algorithm */ 4898 rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2")); 4899 4900 /* if DNSKEY, algorithm; if DS, digest type */ 4901 rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3")); 4902 4903 namestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); 4904 4905 keyname = dns_fixedname_initname(&fkeyname); 4906 isc_buffer_constinit(&b, namestr, strlen(namestr)); 4907 isc_buffer_add(&b, strlen(namestr)); 4908 result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL); 4909 if (result != ISC_R_SUCCESS) { 4910 cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n", 4911 isc_result_totext(result)); 4912 result = ISC_R_FAILURE; 4913 } 4914 4915 if (managed) { 4916 atstr = cfg_obj_asstring(cfg_tuple_get(key, "anchortype")); 4917 4918 if (strcasecmp(atstr, "static-key") == 0) { 4919 managed = false; 4920 anchortype = STATIC_DNSKEY; 4921 } else if (strcasecmp(atstr, "static-ds") == 0) { 4922 managed = false; 4923 anchortype = STATIC_DS; 4924 } else if (strcasecmp(atstr, "initial-key") == 0) { 4925 anchortype = INIT_DNSKEY; 4926 } else if (strcasecmp(atstr, "initial-ds") == 0) { 4927 anchortype = INIT_DS; 4928 } else { 4929 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4930 "key '%s': " 4931 "invalid initialization method '%s'", 4932 namestr, atstr); 4933 result = ISC_R_FAILURE; 4934 4935 /* 4936 * We can't interpret the trust anchor, so 4937 * we skip all other checks. 4938 */ 4939 goto cleanup; 4940 } 4941 } else { 4942 atstr = "trusted-key"; 4943 anchortype = TRUSTED; 4944 } 4945 4946 switch (anchortype) { 4947 case INIT_DNSKEY: 4948 case STATIC_DNSKEY: 4949 case TRUSTED: 4950 if (rdata1 > 0xffff) { 4951 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4952 "flags too big: %u", rdata1); 4953 result = ISC_R_RANGE; 4954 } 4955 if (rdata1 & DNS_KEYFLAG_REVOKE) { 4956 cfg_obj_log(key, logctx, ISC_LOG_WARNING, 4957 "key flags revoke bit set"); 4958 } 4959 if (rdata2 > 0xff) { 4960 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4961 "protocol too big: %u", rdata2); 4962 result = ISC_R_RANGE; 4963 } 4964 if (rdata3 > 0xff) { 4965 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 4966 "algorithm too big: %u\n", rdata3); 4967 result = ISC_R_RANGE; 4968 } 4969 4970 isc_buffer_init(&b, data, sizeof(data)); 4971 4972 str = cfg_obj_asstring(cfg_tuple_get(key, "data")); 4973 tresult = isc_base64_decodestring(str, &b); 4974 4975 if (tresult != ISC_R_SUCCESS) { 4976 cfg_obj_log(key, logctx, ISC_LOG_ERROR, "%s", 4977 isc_result_totext(tresult)); 4978 result = ISC_R_FAILURE; 4979 } else { 4980 isc_buffer_usedregion(&b, &r); 4981 4982 if ((rdata3 == DST_ALG_RSASHA1) && r.length > 1 && 4983 r.base[0] == 1 && r.base[1] == 3) 4984 { 4985 cfg_obj_log(key, logctx, ISC_LOG_WARNING, 4986 "%s '%s' has a weak exponent", 4987 atstr, namestr); 4988 } 4989 } 4990 4991 if (result == ISC_R_SUCCESS && 4992 dns_name_equal(keyname, dns_rootname)) 4993 { 4994 /* 4995 * Flag any use of a root key, regardless of content. 4996 */ 4997 *flagsp |= (managed ? ROOT_KSK_MANAGED 4998 : ROOT_KSK_STATIC); 4999 5000 if (rdata1 == 257 && rdata2 == 3 && rdata3 == 8 && 5001 (isc_buffer_usedlength(&b) == 5002 sizeof(root_ksk_2010)) && 5003 memcmp(data, root_ksk_2010, 5004 sizeof(root_ksk_2010)) == 0) 5005 { 5006 *flagsp |= ROOT_KSK_2010; 5007 } 5008 5009 if (rdata1 == 257 && rdata2 == 3 && rdata3 == 8 && 5010 (isc_buffer_usedlength(&b) == 5011 sizeof(root_ksk_2017)) && 5012 memcmp(data, root_ksk_2017, 5013 sizeof(root_ksk_2017)) == 0) 5014 { 5015 *flagsp |= ROOT_KSK_2017; 5016 } 5017 } 5018 break; 5019 5020 case INIT_DS: 5021 case STATIC_DS: 5022 if (rdata1 > 0xffff) { 5023 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 5024 "key tag too big: %u", rdata1); 5025 result = ISC_R_RANGE; 5026 } 5027 if (rdata2 > 0xff) { 5028 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 5029 "algorithm too big: %u\n", rdata2); 5030 result = ISC_R_RANGE; 5031 } 5032 if (rdata3 > 0xff) { 5033 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 5034 "digest type too big: %u", rdata3); 5035 result = ISC_R_RANGE; 5036 } 5037 5038 isc_buffer_init(&b, data, sizeof(data)); 5039 5040 str = cfg_obj_asstring(cfg_tuple_get(key, "data")); 5041 tresult = isc_hex_decodestring(str, &b); 5042 5043 if (tresult != ISC_R_SUCCESS) { 5044 cfg_obj_log(key, logctx, ISC_LOG_ERROR, "%s", 5045 isc_result_totext(tresult)); 5046 result = ISC_R_FAILURE; 5047 } 5048 if (result == ISC_R_SUCCESS && 5049 dns_name_equal(keyname, dns_rootname)) 5050 { 5051 /* 5052 * Flag any use of a root key, regardless of content. 5053 */ 5054 *flagsp |= (managed ? ROOT_KSK_MANAGED 5055 : ROOT_KSK_STATIC); 5056 5057 if (rdata1 == 20326 && rdata2 == 8 && rdata3 == 1 && 5058 (isc_buffer_usedlength(&b) == 5059 sizeof(root_ds_1_2017)) && 5060 memcmp(data, root_ds_1_2017, 5061 sizeof(root_ds_1_2017)) == 0) 5062 { 5063 *flagsp |= ROOT_KSK_2017; 5064 } 5065 5066 if (rdata1 == 20326 && rdata2 == 8 && rdata3 == 2 && 5067 (isc_buffer_usedlength(&b) == 5068 sizeof(root_ds_2_2017)) && 5069 memcmp(data, root_ds_2_2017, 5070 sizeof(root_ds_2_2017)) == 0) 5071 { 5072 *flagsp |= ROOT_KSK_2017; 5073 } 5074 } 5075 break; 5076 } 5077 5078 cleanup: 5079 return result; 5080 } 5081 5082 static isc_result_t 5083 record_static_keys(isc_symtab_t *symtab, isc_mem_t *mctx, 5084 const cfg_obj_t *keylist, isc_log_t *logctx, 5085 bool autovalidation) { 5086 isc_result_t result, ret = ISC_R_SUCCESS; 5087 const cfg_listelt_t *elt; 5088 dns_fixedname_t fixed; 5089 dns_name_t *name; 5090 char namebuf[DNS_NAME_FORMATSIZE], *p = NULL; 5091 5092 name = dns_fixedname_initname(&fixed); 5093 5094 for (elt = cfg_list_first(keylist); elt != NULL; 5095 elt = cfg_list_next(elt)) 5096 { 5097 const char *initmethod; 5098 const cfg_obj_t *init = NULL; 5099 const cfg_obj_t *obj = cfg_listelt_value(elt); 5100 const char *str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 5101 isc_symvalue_t symvalue; 5102 5103 result = dns_name_fromstring(name, str, dns_rootname, 0, NULL); 5104 if (result != ISC_R_SUCCESS) { 5105 continue; 5106 } 5107 5108 init = cfg_tuple_get(obj, "anchortype"); 5109 if (!cfg_obj_isvoid(init)) { 5110 initmethod = cfg_obj_asstring(init); 5111 if (strcasecmp(initmethod, "initial-key") == 0) { 5112 /* initializing key, skip it */ 5113 continue; 5114 } 5115 if (strcasecmp(initmethod, "initial-ds") == 0) { 5116 /* initializing key, skip it */ 5117 continue; 5118 } 5119 } 5120 5121 dns_name_format(name, namebuf, sizeof(namebuf)); 5122 symvalue.as_cpointer = obj; 5123 p = isc_mem_strdup(mctx, namebuf); 5124 result = isc_symtab_define(symtab, p, 1, symvalue, 5125 isc_symexists_reject); 5126 if (result == ISC_R_EXISTS) { 5127 isc_mem_free(mctx, p); 5128 } else if (result != ISC_R_SUCCESS) { 5129 isc_mem_free(mctx, p); 5130 ret = result; 5131 continue; 5132 } 5133 5134 if (autovalidation && dns_name_equal(name, dns_rootname)) { 5135 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 5136 "static trust anchor for root zone " 5137 "cannot be used with " 5138 "'dnssec-validation auto'."); 5139 ret = ISC_R_FAILURE; 5140 continue; 5141 } 5142 } 5143 5144 return ret; 5145 } 5146 5147 static isc_result_t 5148 check_initializing_keys(isc_symtab_t *symtab, const cfg_obj_t *keylist, 5149 isc_log_t *logctx) { 5150 isc_result_t result, ret = ISC_R_SUCCESS; 5151 const cfg_listelt_t *elt; 5152 dns_fixedname_t fixed; 5153 dns_name_t *name; 5154 char namebuf[DNS_NAME_FORMATSIZE]; 5155 5156 name = dns_fixedname_initname(&fixed); 5157 5158 for (elt = cfg_list_first(keylist); elt != NULL; 5159 elt = cfg_list_next(elt)) 5160 { 5161 const cfg_obj_t *obj = cfg_listelt_value(elt); 5162 const cfg_obj_t *init = NULL; 5163 const char *str; 5164 isc_symvalue_t symvalue; 5165 5166 init = cfg_tuple_get(obj, "anchortype"); 5167 if (cfg_obj_isvoid(init) || 5168 strcasecmp(cfg_obj_asstring(init), "static-key") == 0 || 5169 strcasecmp(cfg_obj_asstring(init), "static-ds") == 0) 5170 { 5171 /* static key, skip it */ 5172 continue; 5173 } 5174 5175 str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 5176 result = dns_name_fromstring(name, str, dns_rootname, 0, NULL); 5177 if (result != ISC_R_SUCCESS) { 5178 continue; 5179 } 5180 5181 dns_name_format(name, namebuf, sizeof(namebuf)); 5182 result = isc_symtab_lookup(symtab, namebuf, 1, &symvalue); 5183 if (result == ISC_R_SUCCESS) { 5184 const char *file = cfg_obj_file(symvalue.as_cpointer); 5185 unsigned int line = cfg_obj_line(symvalue.as_cpointer); 5186 if (file == NULL) { 5187 file = "<unknown file>"; 5188 } 5189 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 5190 "static and initializing keys " 5191 "cannot be used for the " 5192 "same domain. " 5193 "static key defined at " 5194 "%s:%u", 5195 file, line); 5196 5197 ret = ISC_R_FAILURE; 5198 } 5199 } 5200 5201 return ret; 5202 } 5203 5204 static isc_result_t 5205 record_ds_keys(isc_symtab_t *symtab, isc_mem_t *mctx, 5206 const cfg_obj_t *keylist) { 5207 isc_result_t result, ret = ISC_R_SUCCESS; 5208 const cfg_listelt_t *elt; 5209 dns_fixedname_t fixed; 5210 dns_name_t *name; 5211 char namebuf[DNS_NAME_FORMATSIZE], *p = NULL; 5212 5213 name = dns_fixedname_initname(&fixed); 5214 5215 for (elt = cfg_list_first(keylist); elt != NULL; 5216 elt = cfg_list_next(elt)) 5217 { 5218 const char *initmethod; 5219 const cfg_obj_t *init = NULL; 5220 const cfg_obj_t *obj = cfg_listelt_value(elt); 5221 const char *str = cfg_obj_asstring(cfg_tuple_get(obj, "name")); 5222 isc_symvalue_t symvalue; 5223 5224 result = dns_name_fromstring(name, str, dns_rootname, 0, NULL); 5225 if (result != ISC_R_SUCCESS) { 5226 continue; 5227 } 5228 5229 init = cfg_tuple_get(obj, "anchortype"); 5230 if (!cfg_obj_isvoid(init)) { 5231 initmethod = cfg_obj_asstring(init); 5232 if (strcasecmp(initmethod, "initial-key") == 0 || 5233 strcasecmp(initmethod, "static-key") == 0) 5234 { 5235 /* Key-style key, skip it */ 5236 continue; 5237 } 5238 } 5239 5240 dns_name_format(name, namebuf, sizeof(namebuf)); 5241 symvalue.as_cpointer = obj; 5242 p = isc_mem_strdup(mctx, namebuf); 5243 result = isc_symtab_define(symtab, p, 1, symvalue, 5244 isc_symexists_reject); 5245 if (result == ISC_R_EXISTS) { 5246 isc_mem_free(mctx, p); 5247 } 5248 } 5249 5250 return ret; 5251 } 5252 5253 /* 5254 * Check for conflicts between static and initialiizing keys. 5255 */ 5256 static isc_result_t 5257 check_ta_conflicts(const cfg_obj_t *global_ta, const cfg_obj_t *view_ta, 5258 const cfg_obj_t *global_tkeys, const cfg_obj_t *view_tkeys, 5259 bool autovalidation, isc_mem_t *mctx, isc_log_t *logctx) { 5260 isc_result_t result, tresult; 5261 const cfg_listelt_t *elt = NULL; 5262 const cfg_obj_t *keylist = NULL; 5263 isc_symtab_t *statictab = NULL, *dstab = NULL; 5264 5265 result = isc_symtab_create(mctx, 100, freekey, mctx, false, &statictab); 5266 if (result != ISC_R_SUCCESS) { 5267 goto cleanup; 5268 } 5269 5270 result = isc_symtab_create(mctx, 100, freekey, mctx, false, &dstab); 5271 if (result != ISC_R_SUCCESS) { 5272 goto cleanup; 5273 } 5274 5275 /* 5276 * First we record all the static keys (i.e., old-style 5277 * trusted-keys and trust-anchors configured with "static-key"), 5278 * and all the DS-style trust anchors. 5279 */ 5280 for (elt = cfg_list_first(global_ta); elt != NULL; 5281 elt = cfg_list_next(elt)) 5282 { 5283 keylist = cfg_listelt_value(elt); 5284 tresult = record_static_keys(statictab, mctx, keylist, logctx, 5285 autovalidation); 5286 if (result == ISC_R_SUCCESS) { 5287 result = tresult; 5288 } 5289 5290 tresult = record_ds_keys(dstab, mctx, keylist); 5291 if (result == ISC_R_SUCCESS) { 5292 result = tresult; 5293 } 5294 } 5295 5296 for (elt = cfg_list_first(view_ta); elt != NULL; 5297 elt = cfg_list_next(elt)) 5298 { 5299 keylist = cfg_listelt_value(elt); 5300 tresult = record_static_keys(statictab, mctx, keylist, logctx, 5301 autovalidation); 5302 if (result == ISC_R_SUCCESS) { 5303 result = tresult; 5304 } 5305 5306 tresult = record_ds_keys(dstab, mctx, keylist); 5307 if (result == ISC_R_SUCCESS) { 5308 result = tresult; 5309 } 5310 } 5311 5312 for (elt = cfg_list_first(global_tkeys); elt != NULL; 5313 elt = cfg_list_next(elt)) 5314 { 5315 keylist = cfg_listelt_value(elt); 5316 tresult = record_static_keys(statictab, mctx, keylist, logctx, 5317 autovalidation); 5318 if (result == ISC_R_SUCCESS) { 5319 result = tresult; 5320 } 5321 } 5322 5323 for (elt = cfg_list_first(view_tkeys); elt != NULL; 5324 elt = cfg_list_next(elt)) 5325 { 5326 keylist = cfg_listelt_value(elt); 5327 tresult = record_static_keys(statictab, mctx, keylist, logctx, 5328 autovalidation); 5329 if (result == ISC_R_SUCCESS) { 5330 result = tresult; 5331 } 5332 } 5333 5334 /* 5335 * Next, ensure that there's no conflict between the 5336 * static keys and the trust-anchors configured with "initial-key". 5337 */ 5338 for (elt = cfg_list_first(global_ta); elt != NULL; 5339 elt = cfg_list_next(elt)) 5340 { 5341 keylist = cfg_listelt_value(elt); 5342 tresult = check_initializing_keys(statictab, keylist, logctx); 5343 if (result == ISC_R_SUCCESS) { 5344 result = tresult; 5345 } 5346 } 5347 5348 for (elt = cfg_list_first(view_ta); elt != NULL; 5349 elt = cfg_list_next(elt)) 5350 { 5351 keylist = cfg_listelt_value(elt); 5352 tresult = check_initializing_keys(statictab, keylist, logctx); 5353 if (result == ISC_R_SUCCESS) { 5354 result = tresult; 5355 } 5356 } 5357 5358 cleanup: 5359 if (statictab != NULL) { 5360 isc_symtab_destroy(&statictab); 5361 } 5362 if (dstab != NULL) { 5363 isc_symtab_destroy(&dstab); 5364 } 5365 return result; 5366 } 5367 5368 typedef enum { special_zonetype_rpz, special_zonetype_catz } special_zonetype_t; 5369 5370 static isc_result_t 5371 check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj, 5372 const char *viewname, isc_symtab_t *symtab, isc_log_t *logctx, 5373 special_zonetype_t specialzonetype) { 5374 const cfg_listelt_t *element; 5375 const cfg_obj_t *obj, *nameobj, *zoneobj; 5376 const char *zonename, *zonetype; 5377 const char *forview = " for view "; 5378 isc_symvalue_t value; 5379 isc_result_t result, tresult; 5380 dns_fixedname_t fixed; 5381 dns_name_t *name; 5382 char namebuf[DNS_NAME_FORMATSIZE]; 5383 unsigned int num_zones = 0; 5384 5385 if (viewname == NULL) { 5386 viewname = ""; 5387 forview = ""; 5388 } 5389 result = ISC_R_SUCCESS; 5390 5391 name = dns_fixedname_initname(&fixed); 5392 obj = cfg_tuple_get(rpz_obj, "zone list"); 5393 5394 for (element = cfg_list_first(obj); element != NULL; 5395 element = cfg_list_next(element)) 5396 { 5397 obj = cfg_listelt_value(element); 5398 nameobj = cfg_tuple_get(obj, "zone name"); 5399 zonename = cfg_obj_asstring(nameobj); 5400 zonetype = ""; 5401 5402 if (specialzonetype == special_zonetype_rpz) { 5403 if (++num_zones > 64) { 5404 cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR, 5405 "more than 64 response policy " 5406 "zones in view '%s'", 5407 viewname); 5408 return ISC_R_FAILURE; 5409 } 5410 } 5411 5412 tresult = dns_name_fromstring(name, zonename, dns_rootname, 0, 5413 NULL); 5414 if (tresult != ISC_R_SUCCESS) { 5415 cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR, 5416 "bad domain name '%s'", zonename); 5417 if (result == ISC_R_SUCCESS) { 5418 result = tresult; 5419 } 5420 continue; 5421 } 5422 dns_name_format(name, namebuf, sizeof(namebuf)); 5423 tresult = isc_symtab_lookup(symtab, namebuf, 3, &value); 5424 if (tresult == ISC_R_SUCCESS) { 5425 obj = NULL; 5426 zoneobj = value.as_cpointer; 5427 if (zoneobj != NULL && cfg_obj_istuple(zoneobj)) { 5428 zoneobj = cfg_tuple_get(zoneobj, "options"); 5429 } 5430 if (zoneobj != NULL && cfg_obj_ismap(zoneobj)) { 5431 (void)cfg_map_get(zoneobj, "type", &obj); 5432 } 5433 if (obj != NULL) { 5434 zonetype = cfg_obj_asstring(obj); 5435 } 5436 } 5437 if (strcasecmp(zonetype, "primary") != 0 && 5438 strcasecmp(zonetype, "master") != 0 && 5439 strcasecmp(zonetype, "secondary") != 0 && 5440 strcasecmp(zonetype, "slave") != 0) 5441 { 5442 cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR, 5443 "%s '%s'%s%s is not a primary or secondary " 5444 "zone", 5445 rpz_catz, zonename, forview, viewname); 5446 if (result == ISC_R_SUCCESS) { 5447 result = ISC_R_FAILURE; 5448 } 5449 } 5450 } 5451 return result; 5452 } 5453 5454 static isc_result_t 5455 check_rpz(const cfg_obj_t *rpz_obj, isc_log_t *logctx) { 5456 const cfg_listelt_t *element; 5457 const cfg_obj_t *obj, *nameobj, *edeobj; 5458 const char *zonename; 5459 isc_result_t result = ISC_R_SUCCESS, tresult; 5460 dns_fixedname_t fixed; 5461 dns_name_t *name = dns_fixedname_initname(&fixed); 5462 5463 obj = cfg_tuple_get(rpz_obj, "zone list"); 5464 5465 for (element = cfg_list_first(obj); element != NULL; 5466 element = cfg_list_next(element)) 5467 { 5468 obj = cfg_listelt_value(element); 5469 nameobj = cfg_tuple_get(obj, "zone name"); 5470 zonename = cfg_obj_asstring(nameobj); 5471 5472 tresult = dns_name_fromstring(name, zonename, dns_rootname, 0, 5473 NULL); 5474 if (tresult != ISC_R_SUCCESS) { 5475 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 5476 "bad domain name '%s'", zonename); 5477 if (result == ISC_R_SUCCESS) { 5478 result = tresult; 5479 continue; 5480 } 5481 } 5482 5483 edeobj = cfg_tuple_get(obj, "ede"); 5484 if (edeobj != NULL && cfg_obj_isstring(edeobj)) { 5485 const char *str = cfg_obj_asstring(edeobj); 5486 5487 if (dns_rpz_str2ede(str) == UINT16_MAX) { 5488 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 5489 "unsupported EDE type '%s'", str); 5490 result = ISC_R_FAILURE; 5491 } 5492 } 5493 } 5494 5495 return result; 5496 } 5497 5498 static isc_result_t 5499 check_catz(const cfg_obj_t *catz_obj, const char *viewname, isc_mem_t *mctx, 5500 isc_log_t *logctx) { 5501 const cfg_listelt_t *element; 5502 const cfg_obj_t *obj, *nameobj, *primariesobj; 5503 const char *zonename; 5504 const char *forview = " for view "; 5505 isc_result_t result, tresult; 5506 isc_symtab_t *symtab = NULL; 5507 dns_fixedname_t fixed; 5508 dns_name_t *name = dns_fixedname_initname(&fixed); 5509 5510 if (viewname == NULL) { 5511 viewname = ""; 5512 forview = ""; 5513 } 5514 5515 result = isc_symtab_create(mctx, 100, freekey, mctx, false, &symtab); 5516 if (result != ISC_R_SUCCESS) { 5517 return result; 5518 } 5519 5520 obj = cfg_tuple_get(catz_obj, "zone list"); 5521 5522 for (element = cfg_list_first(obj); element != NULL; 5523 element = cfg_list_next(element)) 5524 { 5525 char namebuf[DNS_NAME_FORMATSIZE]; 5526 5527 obj = cfg_listelt_value(element); 5528 nameobj = cfg_tuple_get(obj, "zone name"); 5529 zonename = cfg_obj_asstring(nameobj); 5530 5531 tresult = dns_name_fromstring(name, zonename, dns_rootname, 0, 5532 NULL); 5533 if (tresult != ISC_R_SUCCESS) { 5534 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 5535 "bad domain name '%s'", zonename); 5536 if (result == ISC_R_SUCCESS) { 5537 result = tresult; 5538 continue; 5539 } 5540 } 5541 5542 dns_name_format(name, namebuf, sizeof(namebuf)); 5543 tresult = exists(nameobj, namebuf, 1, symtab, 5544 "catalog zone '%s': already added here %s:%u", 5545 logctx, mctx); 5546 if (tresult != ISC_R_SUCCESS) { 5547 result = tresult; 5548 continue; 5549 } 5550 5551 primariesobj = cfg_tuple_get(obj, "default-primaries"); 5552 if (primariesobj != NULL && cfg_obj_istuple(primariesobj)) { 5553 primariesobj = cfg_tuple_get(obj, "default-masters"); 5554 if (primariesobj != NULL && 5555 cfg_obj_istuple(primariesobj)) 5556 { 5557 cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR, 5558 "catalog zone '%s'%s%s: " 5559 "'default-primaries' and " 5560 "'default-masters' can not be both " 5561 "defined", 5562 zonename, forview, viewname); 5563 result = ISC_R_FAILURE; 5564 break; 5565 } 5566 } 5567 } 5568 5569 if (symtab != NULL) { 5570 isc_symtab_destroy(&symtab); 5571 } 5572 5573 return result; 5574 } 5575 5576 /*% 5577 * Data structure used for the 'callback_data' argument to check_one_plugin(). 5578 */ 5579 struct check_one_plugin_data { 5580 isc_mem_t *mctx; 5581 isc_log_t *lctx; 5582 cfg_aclconfctx_t *actx; 5583 isc_result_t *check_result; 5584 }; 5585 5586 /*% 5587 * A callback for the cfg_pluginlist_foreach() call in check_viewconf() below. 5588 * Since the point is to check configuration of all plugins even when 5589 * processing some of them fails, always return ISC_R_SUCCESS and indicate any 5590 * check failures through the 'check_result' variable passed in via the 5591 * 'callback_data' structure. 5592 */ 5593 static isc_result_t 5594 check_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj, 5595 const char *plugin_path, const char *parameters, 5596 void *callback_data) { 5597 struct check_one_plugin_data *data = callback_data; 5598 char full_path[PATH_MAX]; 5599 isc_result_t result; 5600 5601 result = ns_plugin_expandpath(plugin_path, full_path, 5602 sizeof(full_path)); 5603 if (result != ISC_R_SUCCESS) { 5604 cfg_obj_log(obj, data->lctx, ISC_LOG_ERROR, 5605 "%s: plugin check failed: " 5606 "unable to get full plugin path: %s", 5607 plugin_path, isc_result_totext(result)); 5608 return result; 5609 } 5610 5611 result = ns_plugin_check(full_path, parameters, config, 5612 cfg_obj_file(obj), cfg_obj_line(obj), 5613 data->mctx, data->lctx, data->actx); 5614 if (result != ISC_R_SUCCESS) { 5615 cfg_obj_log(obj, data->lctx, ISC_LOG_ERROR, 5616 "%s: plugin check failed: %s", full_path, 5617 isc_result_totext(result)); 5618 *data->check_result = result; 5619 } 5620 5621 return ISC_R_SUCCESS; 5622 } 5623 5624 static isc_result_t 5625 check_dnstap(const cfg_obj_t *voptions, const cfg_obj_t *config, 5626 isc_log_t *logctx) { 5627 #ifdef HAVE_DNSTAP 5628 const cfg_obj_t *options = NULL; 5629 const cfg_obj_t *obj = NULL; 5630 5631 if (config != NULL) { 5632 (void)cfg_map_get(config, "options", &options); 5633 } 5634 if (options != NULL) { 5635 (void)cfg_map_get(options, "dnstap-output", &obj); 5636 } 5637 if (obj == NULL) { 5638 if (voptions != NULL) { 5639 (void)cfg_map_get(voptions, "dnstap", &obj); 5640 } 5641 if (options != NULL && obj == NULL) { 5642 (void)cfg_map_get(options, "dnstap", &obj); 5643 } 5644 if (obj != NULL) { 5645 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 5646 "'dnstap-output' must be set if 'dnstap' " 5647 "is set"); 5648 return ISC_R_FAILURE; 5649 } 5650 } 5651 return ISC_R_SUCCESS; 5652 #else /* ifdef HAVE_DNSTAP */ 5653 UNUSED(voptions); 5654 UNUSED(config); 5655 UNUSED(logctx); 5656 5657 return ISC_R_SUCCESS; 5658 #endif /* ifdef HAVE_DNSTAP */ 5659 } 5660 5661 static isc_result_t 5662 check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, 5663 const char *viewname, dns_rdataclass_t vclass, 5664 isc_symtab_t *files, isc_symtab_t *keydirs, unsigned int flags, 5665 isc_symtab_t *inview, isc_log_t *logctx, isc_mem_t *mctx) { 5666 const cfg_obj_t *zones = NULL; 5667 const cfg_obj_t *view_tkeys = NULL, *global_tkeys = NULL; 5668 const cfg_obj_t *view_mkeys = NULL, *global_mkeys = NULL; 5669 const cfg_obj_t *view_ta = NULL, *global_ta = NULL; 5670 const cfg_obj_t *check_keys[2] = { NULL, NULL }; 5671 const cfg_obj_t *keys = NULL; 5672 const cfg_listelt_t *element, *element2; 5673 isc_symtab_t *symtab = NULL; 5674 isc_result_t result = ISC_R_SUCCESS; 5675 isc_result_t tresult = ISC_R_SUCCESS; 5676 cfg_aclconfctx_t *actx = NULL; 5677 const cfg_obj_t *obj; 5678 const cfg_obj_t *options = NULL; 5679 const cfg_obj_t *opts = NULL; 5680 const cfg_obj_t *plugin_list = NULL; 5681 bool autovalidation = false; 5682 unsigned int tflags = 0, dflags = 0; 5683 int i; 5684 bool check_plugins = (flags & BIND_CHECK_PLUGINS) != 0; 5685 bool check_algorithms = (flags & BIND_CHECK_ALGORITHMS) != 0; 5686 5687 /* 5688 * Get global options block 5689 */ 5690 (void)cfg_map_get(config, "options", &options); 5691 5692 /* 5693 * The most relevant options for this view 5694 */ 5695 if (voptions != NULL) { 5696 opts = voptions; 5697 } else { 5698 opts = options; 5699 } 5700 5701 /* 5702 * Check that all zone statements are syntactically correct and 5703 * there are no duplicate zones. 5704 */ 5705 tresult = isc_symtab_create(mctx, 1000, freekey, mctx, false, &symtab); 5706 if (tresult != ISC_R_SUCCESS) { 5707 return ISC_R_NOMEMORY; 5708 } 5709 5710 cfg_aclconfctx_create(mctx, &actx); 5711 5712 if (voptions != NULL) { 5713 (void)cfg_map_get(voptions, "zone", &zones); 5714 } else { 5715 (void)cfg_map_get(config, "zone", &zones); 5716 } 5717 5718 for (element = cfg_list_first(zones); element != NULL; 5719 element = cfg_list_next(element)) 5720 { 5721 const cfg_obj_t *zone = cfg_listelt_value(element); 5722 5723 tresult = check_zoneconf(zone, voptions, config, symtab, files, 5724 keydirs, inview, viewname, vclass, 5725 flags, actx, logctx, mctx); 5726 if (tresult != ISC_R_SUCCESS) { 5727 result = ISC_R_FAILURE; 5728 } 5729 } 5730 5731 /* 5732 * Check that the response-policy and catalog-zones options 5733 * refer to zones that exist. 5734 */ 5735 if (opts != NULL) { 5736 obj = NULL; 5737 if ((cfg_map_get(opts, "response-policy", &obj) == 5738 ISC_R_SUCCESS) && 5739 (check_rpz_catz("response-policy zone", obj, viewname, 5740 symtab, logctx, 5741 special_zonetype_rpz) != ISC_R_SUCCESS)) 5742 { 5743 result = ISC_R_FAILURE; 5744 } 5745 5746 obj = NULL; 5747 if ((cfg_map_get(opts, "catalog-zones", &obj) == 5748 ISC_R_SUCCESS) && 5749 (check_rpz_catz("catalog zone", obj, viewname, symtab, 5750 logctx, 5751 special_zonetype_catz) != ISC_R_SUCCESS)) 5752 { 5753 result = ISC_R_FAILURE; 5754 } 5755 } 5756 5757 /* 5758 * Check response-policy configuration. 5759 */ 5760 if (opts != NULL) { 5761 obj = NULL; 5762 if ((cfg_map_get(opts, "response-policy", &obj) == 5763 ISC_R_SUCCESS) && 5764 (check_rpz(obj, logctx) != ISC_R_SUCCESS)) 5765 { 5766 result = ISC_R_FAILURE; 5767 } 5768 } 5769 5770 /* 5771 * Check catalog-zones configuration. 5772 */ 5773 if (opts != NULL) { 5774 obj = NULL; 5775 if ((cfg_map_get(opts, "catalog-zones", &obj) == 5776 ISC_R_SUCCESS) && 5777 (check_catz(obj, viewname, mctx, logctx) != ISC_R_SUCCESS)) 5778 { 5779 result = ISC_R_FAILURE; 5780 } 5781 } 5782 5783 isc_symtab_destroy(&symtab); 5784 5785 /* 5786 * Check that forwarding is reasonable. 5787 */ 5788 if (opts != NULL && 5789 check_forward(config, opts, NULL, logctx) != ISC_R_SUCCESS) 5790 { 5791 result = ISC_R_FAILURE; 5792 } 5793 5794 /* 5795 * Check non-zero options at the global and view levels. 5796 */ 5797 if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS) 5798 { 5799 result = ISC_R_FAILURE; 5800 } 5801 if (voptions != NULL && 5802 check_nonzero(voptions, logctx) != ISC_R_SUCCESS) 5803 { 5804 result = ISC_R_FAILURE; 5805 } 5806 5807 /* 5808 * Check that dual-stack-servers is reasonable. 5809 */ 5810 if (opts != NULL && check_dual_stack(opts, logctx) != ISC_R_SUCCESS) { 5811 result = ISC_R_FAILURE; 5812 } 5813 5814 /* 5815 * Check that rrset-order is reasonable. 5816 */ 5817 if (opts != NULL && check_order(opts, logctx) != ISC_R_SUCCESS) { 5818 result = ISC_R_FAILURE; 5819 } 5820 5821 /* 5822 * Check that all key statements are syntactically correct and 5823 * there are no duplicate keys. 5824 */ 5825 tresult = isc_symtab_create(mctx, 1000, freekey, mctx, false, &symtab); 5826 if (tresult != ISC_R_SUCCESS) { 5827 goto cleanup; 5828 } 5829 5830 (void)cfg_map_get(config, "key", &keys); 5831 tresult = check_keylist(keys, symtab, mctx, logctx); 5832 if (tresult == ISC_R_EXISTS) { 5833 result = ISC_R_FAILURE; 5834 } else if (tresult != ISC_R_SUCCESS) { 5835 result = tresult; 5836 goto cleanup; 5837 } 5838 5839 if (voptions != NULL) { 5840 keys = NULL; 5841 (void)cfg_map_get(voptions, "key", &keys); 5842 tresult = check_keylist(keys, symtab, mctx, logctx); 5843 if (tresult == ISC_R_EXISTS) { 5844 result = ISC_R_FAILURE; 5845 } else if (tresult != ISC_R_SUCCESS) { 5846 result = tresult; 5847 goto cleanup; 5848 } 5849 } 5850 5851 /* 5852 * Global servers can refer to keys in views. 5853 */ 5854 if (check_servers(config, voptions, symtab, mctx, logctx) != 5855 ISC_R_SUCCESS) 5856 { 5857 result = ISC_R_FAILURE; 5858 } 5859 5860 isc_symtab_destroy(&symtab); 5861 5862 /* 5863 * Load all DNSSEC keys. 5864 */ 5865 if (voptions != NULL) { 5866 (void)cfg_map_get(voptions, "trusted-keys", &view_tkeys); 5867 (void)cfg_map_get(voptions, "trust-anchors", &view_ta); 5868 (void)cfg_map_get(voptions, "managed-keys", &view_mkeys); 5869 } 5870 (void)cfg_map_get(config, "trusted-keys", &global_tkeys); 5871 (void)cfg_map_get(config, "trust-anchors", &global_ta); 5872 (void)cfg_map_get(config, "managed-keys", &global_mkeys); 5873 5874 /* 5875 * Check trusted-keys. 5876 */ 5877 check_keys[0] = view_tkeys; 5878 check_keys[1] = global_tkeys; 5879 for (i = 0; i < 2; i++) { 5880 if (check_keys[i] != NULL) { 5881 unsigned int taflags = 0; 5882 5883 for (element = cfg_list_first(check_keys[i]); 5884 element != NULL; element = cfg_list_next(element)) 5885 { 5886 const cfg_obj_t *keylist = 5887 cfg_listelt_value(element); 5888 for (element2 = cfg_list_first(keylist); 5889 element2 != NULL; 5890 element2 = cfg_list_next(element2)) 5891 { 5892 obj = cfg_listelt_value(element2); 5893 tresult = check_trust_anchor( 5894 obj, false, &taflags, logctx); 5895 if (tresult != ISC_R_SUCCESS) { 5896 result = tresult; 5897 } 5898 } 5899 } 5900 5901 if ((taflags & ROOT_KSK_STATIC) != 0) { 5902 cfg_obj_log(check_keys[i], logctx, 5903 ISC_LOG_WARNING, 5904 "trusted-keys entry for the root " 5905 "zone WILL FAIL after key " 5906 "rollover - use trust-anchors " 5907 "with initial-key " 5908 "or initial-ds instead."); 5909 } 5910 5911 tflags |= taflags; 5912 } 5913 } 5914 5915 /* 5916 * Check dnssec/managed-keys. (Only one or the other can be used.) 5917 */ 5918 if ((view_mkeys != NULL || global_mkeys != NULL) && 5919 (view_ta != NULL || global_ta != NULL)) 5920 { 5921 keys = (view_mkeys != NULL) ? view_mkeys : global_mkeys; 5922 5923 cfg_obj_log(keys, logctx, ISC_LOG_ERROR, 5924 "use of managed-keys is not allowed when " 5925 "trust-anchors is also in use"); 5926 result = ISC_R_FAILURE; 5927 } 5928 5929 if (view_ta == NULL && global_ta == NULL) { 5930 view_ta = view_mkeys; 5931 global_ta = global_mkeys; 5932 } 5933 5934 check_keys[0] = view_ta; 5935 check_keys[1] = global_ta; 5936 for (i = 0; i < 2; i++) { 5937 if (check_keys[i] != NULL) { 5938 unsigned int taflags = 0; 5939 5940 for (element = cfg_list_first(check_keys[i]); 5941 element != NULL; element = cfg_list_next(element)) 5942 { 5943 const cfg_obj_t *keylist = 5944 cfg_listelt_value(element); 5945 for (element2 = cfg_list_first(keylist); 5946 element2 != NULL; 5947 element2 = cfg_list_next(element2)) 5948 { 5949 obj = cfg_listelt_value(element2); 5950 tresult = check_trust_anchor( 5951 obj, true, &taflags, logctx); 5952 if (tresult != ISC_R_SUCCESS) { 5953 result = tresult; 5954 } 5955 } 5956 } 5957 5958 if ((taflags & ROOT_KSK_STATIC) != 0) { 5959 cfg_obj_log(check_keys[i], logctx, 5960 ISC_LOG_WARNING, 5961 "static entry for the root " 5962 "zone WILL FAIL after key " 5963 "rollover - use trust-anchors " 5964 "with initial-key " 5965 "or initial-ds instead."); 5966 } 5967 5968 if ((taflags & ROOT_KSK_2010) != 0 && 5969 (taflags & ROOT_KSK_2017) == 0) 5970 { 5971 cfg_obj_log(check_keys[i], logctx, 5972 ISC_LOG_WARNING, 5973 "initial-key entry for the root " 5974 "zone uses the 2010 key without " 5975 "the updated 2017 key"); 5976 } 5977 5978 dflags |= taflags; 5979 } 5980 } 5981 5982 if ((tflags & ROOT_KSK_ANY) != 0 && (dflags & ROOT_KSK_ANY) != 0) { 5983 keys = (view_ta != NULL) ? view_ta : global_ta; 5984 cfg_obj_log(keys, logctx, ISC_LOG_WARNING, 5985 "both trusted-keys and trust-anchors " 5986 "for the root zone are present"); 5987 } 5988 5989 if ((dflags & ROOT_KSK_ANY) == ROOT_KSK_ANY) { 5990 keys = (view_ta != NULL) ? view_ta : global_ta; 5991 cfg_obj_log(keys, logctx, ISC_LOG_WARNING, 5992 "both initial and static entries for the " 5993 "root zone are present"); 5994 } 5995 5996 obj = NULL; 5997 if (voptions != NULL) { 5998 (void)cfg_map_get(voptions, "dnssec-validation", &obj); 5999 } 6000 if (obj == NULL && options != NULL) { 6001 (void)cfg_map_get(options, "dnssec-validation", &obj); 6002 } 6003 if (obj != NULL) { 6004 if (!cfg_obj_isboolean(obj)) { 6005 autovalidation = true; 6006 } else if (cfg_obj_asboolean(obj)) { 6007 if (global_ta == NULL && view_ta == NULL && 6008 global_tkeys == NULL && view_tkeys == NULL) 6009 { 6010 cfg_obj_log(obj, logctx, ISC_LOG_ERROR, 6011 "the 'dnssec-validation yes' " 6012 "option requires configured " 6013 "'trust-anchors'; consider using " 6014 "'dnssec-validation auto'."); 6015 result = ISC_R_FAILURE; 6016 } 6017 } 6018 } 6019 6020 tresult = check_ta_conflicts(global_ta, view_ta, global_tkeys, 6021 view_tkeys, autovalidation, mctx, logctx); 6022 if (tresult != ISC_R_SUCCESS) { 6023 result = tresult; 6024 } 6025 6026 /* 6027 * Check options. 6028 */ 6029 if (voptions != NULL) { 6030 tresult = check_options(voptions, NULL, check_algorithms, 6031 logctx, mctx, optlevel_view); 6032 } else { 6033 tresult = check_options(config, config, check_algorithms, 6034 logctx, mctx, optlevel_config); 6035 } 6036 if (tresult != ISC_R_SUCCESS) { 6037 result = tresult; 6038 } 6039 6040 tresult = check_dnstap(voptions, config, logctx); 6041 if (tresult != ISC_R_SUCCESS) { 6042 result = tresult; 6043 } 6044 6045 tresult = check_viewacls(actx, voptions, config, logctx, mctx); 6046 if (tresult != ISC_R_SUCCESS) { 6047 result = tresult; 6048 } 6049 6050 tresult = check_recursionacls(actx, voptions, viewname, config, logctx, 6051 mctx); 6052 if (tresult != ISC_R_SUCCESS) { 6053 result = tresult; 6054 } 6055 6056 tresult = check_dns64(actx, voptions, config, logctx, mctx); 6057 if (tresult != ISC_R_SUCCESS) { 6058 result = tresult; 6059 } 6060 6061 tresult = check_ratelimit(actx, voptions, config, logctx, mctx); 6062 if (tresult != ISC_R_SUCCESS) { 6063 result = tresult; 6064 } 6065 6066 tresult = check_fetchlimit(voptions, config, logctx); 6067 if (tresult != ISC_R_SUCCESS) { 6068 result = tresult; 6069 } 6070 6071 /* 6072 * Load plugins. 6073 */ 6074 if (check_plugins) { 6075 if (voptions != NULL) { 6076 (void)cfg_map_get(voptions, "plugin", &plugin_list); 6077 } else { 6078 (void)cfg_map_get(config, "plugin", &plugin_list); 6079 } 6080 } 6081 6082 { 6083 struct check_one_plugin_data check_one_plugin_data = { 6084 .mctx = mctx, 6085 .lctx = logctx, 6086 .actx = actx, 6087 .check_result = &tresult, 6088 }; 6089 6090 (void)cfg_pluginlist_foreach(config, plugin_list, logctx, 6091 check_one_plugin, 6092 &check_one_plugin_data); 6093 if (tresult != ISC_R_SUCCESS) { 6094 result = tresult; 6095 } 6096 } 6097 6098 cleanup: 6099 if (symtab != NULL) { 6100 isc_symtab_destroy(&symtab); 6101 } 6102 if (actx != NULL) { 6103 cfg_aclconfctx_detach(&actx); 6104 } 6105 6106 return result; 6107 } 6108 6109 static const char *default_channels[] = { "default_syslog", "default_stderr", 6110 "default_debug", "null", NULL }; 6111 6112 static isc_result_t 6113 check_logging(const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { 6114 const cfg_obj_t *categories = NULL; 6115 const cfg_obj_t *category; 6116 const cfg_obj_t *channels = NULL; 6117 const cfg_obj_t *channel; 6118 const cfg_listelt_t *element; 6119 const cfg_listelt_t *delement; 6120 const char *channelname; 6121 const char *catname; 6122 const cfg_obj_t *fileobj = NULL; 6123 const cfg_obj_t *syslogobj = NULL; 6124 const cfg_obj_t *nullobj = NULL; 6125 const cfg_obj_t *stderrobj = NULL; 6126 const cfg_obj_t *logobj = NULL; 6127 isc_result_t result = ISC_R_SUCCESS; 6128 isc_result_t tresult; 6129 isc_symtab_t *symtab = NULL; 6130 isc_symvalue_t symvalue; 6131 int i; 6132 6133 (void)cfg_map_get(config, "logging", &logobj); 6134 if (logobj == NULL) { 6135 return ISC_R_SUCCESS; 6136 } 6137 6138 result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab); 6139 if (result != ISC_R_SUCCESS) { 6140 return result; 6141 } 6142 6143 symvalue.as_cpointer = NULL; 6144 for (i = 0; default_channels[i] != NULL; i++) { 6145 tresult = isc_symtab_define(symtab, default_channels[i], 1, 6146 symvalue, isc_symexists_replace); 6147 RUNTIME_CHECK(tresult == ISC_R_SUCCESS); 6148 } 6149 6150 cfg_map_get(logobj, "channel", &channels); 6151 6152 for (element = cfg_list_first(channels); element != NULL; 6153 element = cfg_list_next(element)) 6154 { 6155 channel = cfg_listelt_value(element); 6156 channelname = cfg_obj_asstring(cfg_map_getname(channel)); 6157 fileobj = syslogobj = nullobj = stderrobj = NULL; 6158 (void)cfg_map_get(channel, "file", &fileobj); 6159 (void)cfg_map_get(channel, "syslog", &syslogobj); 6160 (void)cfg_map_get(channel, "null", &nullobj); 6161 (void)cfg_map_get(channel, "stderr", &stderrobj); 6162 i = 0; 6163 if (fileobj != NULL) { 6164 i++; 6165 } 6166 if (syslogobj != NULL) { 6167 i++; 6168 } 6169 if (nullobj != NULL) { 6170 i++; 6171 } 6172 if (stderrobj != NULL) { 6173 i++; 6174 } 6175 if (i != 1) { 6176 cfg_obj_log(channel, logctx, ISC_LOG_ERROR, 6177 "channel '%s': exactly one of file, " 6178 "syslog, " 6179 "null, and stderr must be present", 6180 channelname); 6181 result = ISC_R_FAILURE; 6182 } 6183 tresult = isc_symtab_define(symtab, channelname, 1, symvalue, 6184 isc_symexists_replace); 6185 RUNTIME_CHECK(tresult == ISC_R_SUCCESS); 6186 } 6187 6188 cfg_map_get(logobj, "category", &categories); 6189 6190 for (element = cfg_list_first(categories); element != NULL; 6191 element = cfg_list_next(element)) 6192 { 6193 category = cfg_listelt_value(element); 6194 catname = cfg_obj_asstring(cfg_tuple_get(category, "name")); 6195 if (isc_log_categorybyname(logctx, catname) == NULL) { 6196 cfg_obj_log(category, logctx, ISC_LOG_ERROR, 6197 "undefined category: '%s'", catname); 6198 result = ISC_R_FAILURE; 6199 } 6200 channels = cfg_tuple_get(category, "destinations"); 6201 for (delement = cfg_list_first(channels); delement != NULL; 6202 delement = cfg_list_next(delement)) 6203 { 6204 channel = cfg_listelt_value(delement); 6205 channelname = cfg_obj_asstring(channel); 6206 tresult = isc_symtab_lookup(symtab, channelname, 1, 6207 &symvalue); 6208 if (tresult != ISC_R_SUCCESS) { 6209 cfg_obj_log(channel, logctx, ISC_LOG_ERROR, 6210 "undefined channel: '%s'", 6211 channelname); 6212 result = tresult; 6213 } 6214 } 6215 } 6216 isc_symtab_destroy(&symtab); 6217 return result; 6218 } 6219 6220 static isc_result_t 6221 check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist, 6222 isc_log_t *logctx) { 6223 isc_result_t result = ISC_R_SUCCESS; 6224 const cfg_obj_t *control_keylist; 6225 const cfg_listelt_t *element; 6226 const cfg_obj_t *key; 6227 const char *keyval; 6228 6229 control_keylist = cfg_tuple_get(control, "keys"); 6230 if (cfg_obj_isvoid(control_keylist)) { 6231 return ISC_R_SUCCESS; 6232 } 6233 6234 for (element = cfg_list_first(control_keylist); element != NULL; 6235 element = cfg_list_next(element)) 6236 { 6237 key = cfg_listelt_value(element); 6238 keyval = cfg_obj_asstring(key); 6239 6240 if (!rndckey_exists(keylist, keyval)) { 6241 cfg_obj_log(key, logctx, ISC_LOG_ERROR, 6242 "unknown key '%s'", keyval); 6243 result = ISC_R_NOTFOUND; 6244 } 6245 } 6246 return result; 6247 } 6248 6249 static isc_result_t 6250 check_controls(const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx) { 6251 isc_result_t result = ISC_R_SUCCESS, tresult; 6252 cfg_aclconfctx_t *actx = NULL; 6253 const cfg_listelt_t *element, *element2; 6254 const cfg_obj_t *allow; 6255 const cfg_obj_t *control; 6256 const cfg_obj_t *controls; 6257 const cfg_obj_t *controlslist = NULL; 6258 const cfg_obj_t *inetcontrols; 6259 const cfg_obj_t *unixcontrols; 6260 const cfg_obj_t *keylist = NULL; 6261 const cfg_obj_t *obj = NULL; 6262 const char *path; 6263 dns_acl_t *acl = NULL; 6264 isc_symtab_t *symtab = NULL; 6265 6266 (void)cfg_map_get(config, "controls", &controlslist); 6267 if (controlslist == NULL) { 6268 return ISC_R_SUCCESS; 6269 } 6270 6271 (void)cfg_map_get(config, "key", &keylist); 6272 6273 cfg_aclconfctx_create(mctx, &actx); 6274 6275 result = isc_symtab_create(mctx, 100, freekey, mctx, true, &symtab); 6276 if (result != ISC_R_SUCCESS) { 6277 goto cleanup; 6278 } 6279 6280 /* 6281 * INET: Check allow clause. 6282 * UNIX: Not supported. 6283 */ 6284 for (element = cfg_list_first(controlslist); element != NULL; 6285 element = cfg_list_next(element)) 6286 { 6287 controls = cfg_listelt_value(element); 6288 unixcontrols = NULL; 6289 inetcontrols = NULL; 6290 (void)cfg_map_get(controls, "unix", &unixcontrols); 6291 (void)cfg_map_get(controls, "inet", &inetcontrols); 6292 for (element2 = cfg_list_first(inetcontrols); element2 != NULL; 6293 element2 = cfg_list_next(element2)) 6294 { 6295 char socktext[ISC_SOCKADDR_FORMATSIZE]; 6296 isc_sockaddr_t addr; 6297 6298 control = cfg_listelt_value(element2); 6299 allow = cfg_tuple_get(control, "allow"); 6300 tresult = cfg_acl_fromconfig(allow, config, logctx, 6301 actx, mctx, 0, &acl); 6302 if (acl != NULL) { 6303 dns_acl_detach(&acl); 6304 } 6305 if (tresult != ISC_R_SUCCESS) { 6306 result = tresult; 6307 } 6308 tresult = check_controlskeys(control, keylist, logctx); 6309 if (tresult != ISC_R_SUCCESS) { 6310 result = tresult; 6311 } 6312 obj = cfg_tuple_get(control, "address"); 6313 addr = *cfg_obj_assockaddr(obj); 6314 if (isc_sockaddr_getport(&addr) == 0) { 6315 isc_sockaddr_setport(&addr, NAMED_CONTROL_PORT); 6316 } 6317 isc_sockaddr_format(&addr, socktext, sizeof(socktext)); 6318 tresult = exists( 6319 obj, socktext, 1, symtab, 6320 "inet control socket '%s': already defined, " 6321 "previous definition: %s:%u", 6322 logctx, mctx); 6323 if (tresult != ISC_R_SUCCESS) { 6324 result = tresult; 6325 } 6326 } 6327 for (element2 = cfg_list_first(unixcontrols); element2 != NULL; 6328 element2 = cfg_list_next(element2)) 6329 { 6330 control = cfg_listelt_value(element2); 6331 path = cfg_obj_asstring(cfg_tuple_get(control, "path")); 6332 cfg_obj_log(control, logctx, ISC_LOG_ERROR, 6333 "unix control '%s': not supported", path); 6334 result = ISC_R_FAMILYNOSUPPORT; 6335 } 6336 } 6337 cleanup: 6338 cfg_aclconfctx_detach(&actx); 6339 if (symtab != NULL) { 6340 isc_symtab_destroy(&symtab); 6341 } 6342 return result; 6343 } 6344 6345 isc_result_t 6346 isccfg_check_namedconf(const cfg_obj_t *config, unsigned int flags, 6347 isc_log_t *logctx, isc_mem_t *mctx) { 6348 const cfg_obj_t *options = NULL; 6349 const cfg_obj_t *views = NULL; 6350 const cfg_obj_t *acls = NULL; 6351 const cfg_listelt_t *velement; 6352 isc_result_t result = ISC_R_SUCCESS; 6353 isc_result_t tresult; 6354 isc_symtab_t *symtab = NULL; 6355 isc_symtab_t *files = NULL; 6356 isc_symtab_t *keydirs = NULL; 6357 isc_symtab_t *inview = NULL; 6358 bool check_algorithms = (flags & BIND_CHECK_ALGORITHMS) != 0; 6359 6360 static const char *builtin[] = { "localhost", "localnets", "any", 6361 "none" }; 6362 6363 (void)cfg_map_get(config, "options", &options); 6364 6365 if (options != NULL && 6366 check_options(options, config, check_algorithms, logctx, mctx, 6367 optlevel_options) != ISC_R_SUCCESS) 6368 { 6369 result = ISC_R_FAILURE; 6370 } 6371 6372 if (check_logging(config, logctx, mctx) != ISC_R_SUCCESS) { 6373 result = ISC_R_FAILURE; 6374 } 6375 6376 if (check_controls(config, logctx, mctx) != ISC_R_SUCCESS) { 6377 result = ISC_R_FAILURE; 6378 } 6379 6380 if (check_remoteserverlists(config, logctx, mctx) != ISC_R_SUCCESS) { 6381 result = ISC_R_FAILURE; 6382 } 6383 6384 #if HAVE_LIBNGHTTP2 6385 if (check_httpservers(config, logctx, mctx) != ISC_R_SUCCESS) { 6386 result = ISC_R_FAILURE; 6387 } 6388 #endif /* HAVE_LIBNGHTTP2 */ 6389 6390 if (check_tls_definitions(config, logctx, mctx) != ISC_R_SUCCESS) { 6391 result = ISC_R_FAILURE; 6392 } 6393 6394 (void)cfg_map_get(config, "view", &views); 6395 6396 if (views != NULL && options != NULL) { 6397 if (check_dual_stack(options, logctx) != ISC_R_SUCCESS) { 6398 result = ISC_R_FAILURE; 6399 6400 /* 6401 * Use case insensitive comparison as not all file 6402 * systems are case sensitive. This will prevent people 6403 * using FOO.DB and foo.db on case sensitive file 6404 * systems but that shouldn't be a major issue. 6405 */ 6406 } 6407 } 6408 6409 /* 6410 * Use case insensitive comparison as not all file systems are 6411 * case sensitive. This will prevent people using FOO.DB and foo.db 6412 * on case sensitive file systems but that shouldn't be a major issue. 6413 */ 6414 tresult = isc_symtab_create(mctx, 100, NULL, NULL, false, &files); 6415 if (tresult != ISC_R_SUCCESS) { 6416 result = tresult; 6417 goto cleanup; 6418 } 6419 6420 tresult = isc_symtab_create(mctx, 100, freekey, mctx, false, &keydirs); 6421 if (tresult != ISC_R_SUCCESS) { 6422 result = tresult; 6423 goto cleanup; 6424 } 6425 6426 tresult = isc_symtab_create(mctx, 100, freekey, mctx, true, &inview); 6427 if (tresult != ISC_R_SUCCESS) { 6428 result = tresult; 6429 goto cleanup; 6430 } 6431 6432 if (views == NULL) { 6433 tresult = check_viewconf(config, NULL, NULL, dns_rdataclass_in, 6434 files, keydirs, flags, inview, logctx, 6435 mctx); 6436 if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) { 6437 result = ISC_R_FAILURE; 6438 } 6439 } else { 6440 const cfg_obj_t *zones = NULL; 6441 const cfg_obj_t *plugins = NULL; 6442 6443 (void)cfg_map_get(config, "zone", &zones); 6444 if (zones != NULL) { 6445 cfg_obj_log(zones, logctx, ISC_LOG_ERROR, 6446 "when using 'view' statements, " 6447 "all zones must be in views"); 6448 result = ISC_R_FAILURE; 6449 } 6450 6451 (void)cfg_map_get(config, "plugin", &plugins); 6452 if (plugins != NULL) { 6453 cfg_obj_log(plugins, logctx, ISC_LOG_ERROR, 6454 "when using 'view' statements, " 6455 "all plugins must be defined in views"); 6456 result = ISC_R_FAILURE; 6457 } 6458 } 6459 6460 tresult = isc_symtab_create(mctx, 100, NULL, NULL, true, &symtab); 6461 if (tresult != ISC_R_SUCCESS) { 6462 result = tresult; 6463 goto cleanup; 6464 } 6465 for (velement = cfg_list_first(views); velement != NULL; 6466 velement = cfg_list_next(velement)) 6467 { 6468 const cfg_obj_t *view = cfg_listelt_value(velement); 6469 const cfg_obj_t *vname = cfg_tuple_get(view, "name"); 6470 const cfg_obj_t *voptions = cfg_tuple_get(view, "options"); 6471 const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class"); 6472 dns_rdataclass_t vclass = dns_rdataclass_in; 6473 const char *key = cfg_obj_asstring(vname); 6474 isc_symvalue_t symvalue; 6475 unsigned int symtype; 6476 6477 tresult = ISC_R_SUCCESS; 6478 if (cfg_obj_isstring(vclassobj)) { 6479 isc_textregion_t r; 6480 6481 r.base = UNCONST(cfg_obj_asstring(vclassobj)); 6482 r.length = strlen(r.base); 6483 tresult = dns_rdataclass_fromtext(&vclass, &r); 6484 if (tresult != ISC_R_SUCCESS) { 6485 cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR, 6486 "view '%s': invalid class %s", 6487 cfg_obj_asstring(vname), r.base); 6488 } 6489 } 6490 symtype = vclass + 1; 6491 if (tresult == ISC_R_SUCCESS && symtab != NULL) { 6492 symvalue.as_cpointer = view; 6493 tresult = isc_symtab_define(symtab, key, symtype, 6494 symvalue, 6495 isc_symexists_reject); 6496 if (tresult == ISC_R_EXISTS) { 6497 const char *file; 6498 unsigned int line; 6499 RUNTIME_CHECK(isc_symtab_lookup(symtab, key, 6500 symtype, 6501 &symvalue) == 6502 ISC_R_SUCCESS); 6503 file = cfg_obj_file(symvalue.as_cpointer); 6504 line = cfg_obj_line(symvalue.as_cpointer); 6505 cfg_obj_log(view, logctx, ISC_LOG_ERROR, 6506 "view '%s': already exists " 6507 "previous definition: %s:%u", 6508 key, file, line); 6509 result = tresult; 6510 } else if ((strcasecmp(key, "_bind") == 0 && 6511 vclass == dns_rdataclass_ch) || 6512 (strcasecmp(key, "_default") == 0 && 6513 vclass == dns_rdataclass_in)) 6514 { 6515 cfg_obj_log(view, logctx, ISC_LOG_ERROR, 6516 "attempt to redefine builtin view " 6517 "'%s'", 6518 key); 6519 result = ISC_R_EXISTS; 6520 } 6521 } 6522 if (tresult == ISC_R_SUCCESS) { 6523 tresult = check_viewconf(config, voptions, key, vclass, 6524 files, keydirs, flags, inview, 6525 logctx, mctx); 6526 } 6527 if (tresult != ISC_R_SUCCESS) { 6528 result = ISC_R_FAILURE; 6529 } 6530 } 6531 6532 cfg_map_get(config, "acl", &acls); 6533 6534 if (acls != NULL) { 6535 const cfg_listelt_t *elt; 6536 const cfg_listelt_t *elt2; 6537 const char *aclname; 6538 6539 for (elt = cfg_list_first(acls); elt != NULL; 6540 elt = cfg_list_next(elt)) 6541 { 6542 const cfg_obj_t *acl = cfg_listelt_value(elt); 6543 unsigned int line = cfg_obj_line(acl); 6544 unsigned int i; 6545 6546 aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name")); 6547 for (i = 0; i < sizeof(builtin) / sizeof(builtin[0]); 6548 i++) 6549 { 6550 if (strcasecmp(aclname, builtin[i]) == 0) { 6551 { 6552 cfg_obj_log(acl, logctx, 6553 ISC_LOG_ERROR, 6554 "attempt to " 6555 "redefine " 6556 "builtin acl '%s'", 6557 aclname); 6558 result = ISC_R_FAILURE; 6559 break; 6560 } 6561 } 6562 } 6563 6564 for (elt2 = cfg_list_next(elt); elt2 != NULL; 6565 elt2 = cfg_list_next(elt2)) 6566 { 6567 const cfg_obj_t *acl2 = cfg_listelt_value(elt2); 6568 const char *name; 6569 name = cfg_obj_asstring( 6570 cfg_tuple_get(acl2, "name")); 6571 if (strcasecmp(aclname, name) == 0) { 6572 const char *file = cfg_obj_file(acl); 6573 6574 if (file == NULL) { 6575 file = "<unknown file>"; 6576 } 6577 6578 cfg_obj_log(acl2, logctx, ISC_LOG_ERROR, 6579 "attempt to redefine " 6580 "acl '%s' previous " 6581 "definition: %s:%u", 6582 name, file, line); 6583 result = ISC_R_FAILURE; 6584 } 6585 } 6586 } 6587 } 6588 6589 cleanup: 6590 if (symtab != NULL) { 6591 isc_symtab_destroy(&symtab); 6592 } 6593 if (inview != NULL) { 6594 isc_symtab_destroy(&inview); 6595 } 6596 if (files != NULL) { 6597 isc_symtab_destroy(&files); 6598 } 6599 if (keydirs != NULL) { 6600 isc_symtab_destroy(&keydirs); 6601 } 6602 6603 return result; 6604 } 6605