1 /* $NetBSD: config.c,v 1.20 2026/01/29 18:36:27 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 <bind.keys.h> 19 #include <inttypes.h> 20 #include <stdlib.h> 21 22 #include <isc/buffer.h> 23 #include <isc/log.h> 24 #include <isc/mem.h> 25 #include <isc/netmgr.h> 26 #include <isc/parseint.h> 27 #include <isc/region.h> 28 #include <isc/result.h> 29 #include <isc/sockaddr.h> 30 #include <isc/string.h> 31 #include <isc/util.h> 32 33 #include <dns/fixedname.h> 34 #include <dns/kasp.h> 35 #include <dns/name.h> 36 #include <dns/rdataclass.h> 37 #include <dns/rdatatype.h> 38 #include <dns/tsig.h> 39 #include <dns/zone.h> 40 41 #include <dst/dst.h> 42 43 #include <isccfg/grammar.h> 44 #include <isccfg/namedconf.h> 45 46 #include <named/config.h> 47 #include <named/globals.h> 48 49 /*% default configuration */ 50 static char defaultconf[] = "\ 51 options {\n\ 52 answer-cookie true;\n\ 53 automatic-interface-scan yes;\n\ 54 # blackhole {none;};\n\ 55 cookie-algorithm siphash24;\n\ 56 # directory <none>\n\ 57 dnssec-policy \"none\";\n\ 58 dump-file \"named_dump.db\";\n\ 59 edns-udp-size 1232;\n" 60 #if defined(HAVE_GEOIP2) 61 "\ 62 geoip-directory \"" MAXMINDDB_PREFIX "/share/GeoIP\";\n" 63 #elif defined(HAVE_GEOIP2) 64 "\ 65 geoip-directory \".\";\n" 66 #endif /* if defined(HAVE_GEOIP2) */ 67 "\ 68 heartbeat-interval 60;\n\ 69 interface-interval 60m;\n \ 70 listen-on {any;};\n\ 71 listen-on-v6 {any;};\n\ 72 match-mapped-addresses no;\n\ 73 max-ixfr-ratio 100%;\n\ 74 max-rsa-exponent-size 0; /* no limit */\n\ 75 max-udp-size 1232;\n\ 76 memstatistics-file \"named.memstats\";\n\ 77 nocookie-udp-size 4096;\n\ 78 notify-rate 20;\n\ 79 nta-lifetime 3600;\n\ 80 nta-recheck 300;\n\ 81 # pid-file \"" NAMED_LOCALSTATEDIR "/run/named/named.pid\"; \n\ 82 port 53;\n" 83 #if HAVE_SO_REUSEPORT_LB 84 "\ 85 reuseport yes;\n" 86 #else 87 "\ 88 reuseport no;\n" 89 #endif 90 "\ 91 tls-port 853;\n" 92 #if HAVE_LIBNGHTTP2 93 "\ 94 http-port 80;\n\ 95 https-port 443;\n\ 96 http-listener-clients 300;\n\ 97 http-streams-per-connection 100;\n" 98 #endif 99 "\ 100 prefetch 2 9;\n\ 101 # querylog <boolean>;\n\ 102 recursing-file \"named.recursing\";\n\ 103 recursive-clients 1000;\n\ 104 request-nsid false;\n\ 105 resolver-query-timeout 10;\n\ 106 # responselog <boolean>;\n\ 107 rrset-order { order random; };\n\ 108 secroots-file \"named.secroots\";\n\ 109 send-cookie true;\n\ 110 serial-query-rate 20;\n\ 111 server-id none;\n\ 112 session-keyalg hmac-sha256;\n\ 113 # session-keyfile \"" NAMED_LOCALSTATEDIR "/run/named/session.key\";\n\ 114 session-keyname local-ddns;\n\ 115 startup-notify-rate 20;\n\ 116 sig0checks-quota 1;\n\ 117 sig0key-checks-limit 16;\n\ 118 sig0message-checks-limit 2;\n\ 119 statistics-file \"named.stats\";\n\ 120 tcp-advertised-timeout 300;\n\ 121 tcp-clients 150;\n\ 122 tcp-idle-timeout 300;\n\ 123 tcp-initial-timeout 300;\n\ 124 tcp-keepalive-timeout 300;\n\ 125 tcp-listen-queue 10;\n\ 126 tcp-receive-buffer 0;\n\ 127 tcp-send-buffer 0;\n\ 128 # tkey-gssapi-credential <none>\n\ 129 transfer-message-size 20480;\n\ 130 transfers-in 10;\n\ 131 transfers-out 10;\n\ 132 transfers-per-ns 2;\n\ 133 trust-anchor-telemetry yes;\n\ 134 udp-receive-buffer 0;\n\ 135 udp-send-buffer 0;\n\ 136 update-quota 100;\n\ 137 \n\ 138 /* view */\n\ 139 allow-new-zones no;\n\ 140 allow-notify {none;};\n\ 141 allow-proxy {none;};\n\ 142 allow-proxy-on {any;};\n\ 143 allow-query-cache { localnets; localhost; };\n\ 144 allow-query-cache-on { any; };\n\ 145 allow-recursion { localnets; localhost; };\n\ 146 allow-recursion-on { any; };\n\ 147 allow-update-forwarding {none;};\n\ 148 auth-nxdomain false;\n\ 149 check-dup-records warn;\n\ 150 check-mx warn;\n\ 151 check-names primary fail;\n\ 152 check-names response ignore;\n\ 153 check-names secondary warn;\n\ 154 check-spf warn;\n\ 155 check-svcb yes;\n\ 156 clients-per-query 10;\n\ 157 dnssec-accept-expired no;\n\ 158 dnssec-validation " VALIDATION_DEFAULT "; \n" 159 #ifdef USE_DNSRPS 160 " dnsrps-library \"" DNSRPS_LIBRPZ_PATH "\";\n" 161 #endif /* ifdef USE_DNSRPS */ 162 #ifdef HAVE_DNSTAP 163 " dnstap-identity hostname;\n" 164 #endif /* ifdef HAVE_DNSTAP */ 165 "\ 166 fetch-quota-params 100 0.1 0.3 0.7;\n\ 167 fetches-per-server 0;\n\ 168 fetches-per-zone 0;\n\ 169 lame-ttl 0;\n" 170 #ifdef HAVE_LMDB 171 " lmdb-mapsize 32M;\n" 172 #endif /* ifdef HAVE_LMDB */ 173 " max-cache-size default;\n\ 174 max-cache-ttl 604800; /* 1 week */\n\ 175 max-clients-per-query 100;\n\ 176 max-ncache-ttl 10800; /* 3 hours */\n\ 177 max-recursion-depth 7;\n\ 178 max-recursion-queries 50;\n\ 179 max-query-count 200;\n\ 180 max-query-restarts 11;\n\ 181 max-stale-ttl 86400; /* 1 day */\n\ 182 message-compression yes;\n\ 183 min-ncache-ttl 0; /* 0 hours */\n\ 184 min-cache-ttl 0; /* 0 seconds */\n\ 185 minimal-any false;\n\ 186 minimal-responses no-auth-recursive;\n\ 187 notify-source *;\n\ 188 notify-source-v6 *;\n\ 189 nsec3-test-zone no;\n\ 190 parental-source *;\n\ 191 parental-source-v6 *;\n\ 192 provide-ixfr true;\n\ 193 response-padding { none; } block-size 0;\n\ 194 qname-minimization relaxed;\n\ 195 query-source address *;\n\ 196 query-source-v6 address *;\n\ 197 recursion true;\n\ 198 request-expire true;\n\ 199 request-ixfr true;\n\ 200 require-server-cookie no;\n\ 201 root-key-sentinel yes;\n\ 202 servfail-ttl 1;\n\ 203 # sortlist <none>\n\ 204 stale-answer-client-timeout off;\n\ 205 stale-answer-enable false;\n\ 206 stale-answer-ttl 30; /* 30 seconds */\n\ 207 stale-cache-enable false;\n\ 208 stale-refresh-time 30; /* 30 seconds */\n\ 209 synth-from-dnssec yes;\n\ 210 # topology <none>\n\ 211 transfer-format many-answers;\n\ 212 resolver-use-dns64 false;\n\ 213 v6-bias 50;\n\ 214 zero-no-soa-ttl-cache no;\n\ 215 \n\ 216 /* zone */\n\ 217 allow-query {any;};\n\ 218 allow-query-on {any;};\n\ 219 allow-transfer {none;};\n\ 220 # also-notify <none>\n\ 221 check-integrity yes;\n\ 222 check-mx-cname warn;\n\ 223 check-sibling yes;\n\ 224 check-srv-cname warn;\n\ 225 check-wildcard yes;\n\ 226 dialup no;\n\ 227 dnssec-loadkeys-interval 60;\n\ 228 # forward <none>\n\ 229 # forwarders <none>\n\ 230 # inline-signing no;\n\ 231 ixfr-from-differences false;\n\ 232 max-journal-size default;\n\ 233 max-records 0;\n\ 234 max-records-per-type 100;\n\ 235 max-refresh-time 2419200; /* 4 weeks */\n\ 236 max-retry-time 1209600; /* 2 weeks */\n\ 237 max-types-per-name 100;\n\ 238 max-transfer-idle-in 60;\n\ 239 max-transfer-idle-out 60;\n\ 240 max-transfer-time-in 120;\n\ 241 max-transfer-time-out 120;\n\ 242 min-refresh-time 300;\n\ 243 min-retry-time 500;\n\ 244 min-transfer-rate-in 10240 5;\n\ 245 multi-master no;\n\ 246 notify yes;\n\ 247 notify-defer 0;\n\ 248 notify-delay 5;\n\ 249 notify-to-soa no;\n\ 250 serial-update-method increment;\n\ 251 sig-signing-nodes 100;\n\ 252 sig-signing-signatures 10;\n\ 253 sig-signing-type 65534;\n\ 254 transfer-source *;\n\ 255 transfer-source-v6 *;\n\ 256 try-tcp-refresh yes; /* BIND 8 compat */\n\ 257 zero-no-soa-ttl yes;\n\ 258 zone-statistics terse;\n\ 259 };\n\ 260 " 261 262 "#\n\ 263 # Zones in the \"_bind\" view are NOT counted in the count of zones.\n\ 264 #\n\ 265 view \"_bind\" chaos {\n\ 266 recursion no;\n\ 267 notify no;\n\ 268 allow-new-zones no;\n\ 269 max-cache-size 2M;\n\ 270 \n\ 271 # Prevent use of this zone in DNS amplified reflection DoS attacks\n\ 272 rate-limit {\n\ 273 responses-per-second 3;\n\ 274 slip 0;\n\ 275 min-table-size 10;\n\ 276 };\n\ 277 \n\ 278 zone \"version.bind\" chaos {\n\ 279 type primary;\n\ 280 database \"_builtin version\";\n\ 281 };\n\ 282 \n\ 283 zone \"hostname.bind\" chaos {\n\ 284 type primary;\n\ 285 database \"_builtin hostname\";\n\ 286 };\n\ 287 \n\ 288 zone \"authors.bind\" chaos {\n\ 289 type primary;\n\ 290 database \"_builtin authors\";\n\ 291 };\n\ 292 \n\ 293 zone \"id.server\" chaos {\n\ 294 type primary;\n\ 295 database \"_builtin id\";\n\ 296 };\n\ 297 };\n\ 298 " 299 "#\n\ 300 # Built-in DNSSEC key and signing policies.\n\ 301 #\n\ 302 dnssec-policy \"default\" {\n\ 303 keys {\n\ 304 csk key-directory lifetime unlimited algorithm 13;\n\ 305 };\n\ 306 \n\ 307 cdnskey yes;\n\ 308 cds-digest-types { 2; };\n\ 309 dnskey-ttl " DNS_KASP_KEY_TTL ";\n\ 310 inline-signing yes;\n\ 311 manual-mode no;\n\ 312 offline-ksk no;\n\ 313 publish-safety " DNS_KASP_PUBLISH_SAFETY "; \n\ 314 retire-safety " DNS_KASP_RETIRE_SAFETY "; \n\ 315 purge-keys " DNS_KASP_PURGE_KEYS "; \n\ 316 signatures-jitter " DNS_KASP_SIG_JITTER "; \n\ 317 signatures-refresh " DNS_KASP_SIG_REFRESH "; \n\ 318 signatures-validity " DNS_KASP_SIG_VALIDITY "; \n\ 319 signatures-validity-dnskey " DNS_KASP_SIG_VALIDITY_DNSKEY "; \n\ 320 max-zone-ttl " DNS_KASP_ZONE_MAXTTL "; \n\ 321 zone-propagation-delay " DNS_KASP_ZONE_PROPDELAY "; \n\ 322 parent-ds-ttl " DNS_KASP_DS_TTL "; \n\ 323 parent-propagation-delay " DNS_KASP_PARENT_PROPDELAY "; \n\ 324 };\n\ 325 \n\ 326 dnssec-policy \"insecure\" {\n\ 327 max-zone-ttl 0; \n\ 328 keys { };\n\ 329 inline-signing yes;\n\ 330 manual-mode no;\n\ 331 };\n\ 332 \n\ 333 " 334 "#\n\ 335 # Default trusted key(s), used if \n\ 336 # \"dnssec-validation auto;\" is set and\n\ 337 # " NAMED_SYSCONFDIR "/bind.keys doesn't exist).\n\ 338 #\n\ 339 # BEGIN TRUST ANCHORS\n" 340 341 /* Imported from bind.keys.h: */ 342 TRUST_ANCHORS 343 344 "# END TRUST ANCHORS\n\ 345 \n\ 346 remote-servers " DEFAULT_IANA_ROOT_ZONE_PRIMARIES " {\n\ 347 2801:1b8:10::b; # b.root-servers.net\n\ 348 2001:500:2::c; # c.root-servers.net\n\ 349 2001:500:2f::f; # f.root-servers.net\n\ 350 2001:500:12::d0d; # g.root-servers.net\n\ 351 2001:7fd::1; # k.root-servers.net\n\ 352 2620:0:2830:202::132; # xfr.cjr.dns.icann.org\n\ 353 2620:0:2d0:202::132; # xfr.lax.dns.icann.org\n\ 354 170.247.170.2; # b.root-servers.net\n\ 355 192.33.4.12; # c.root-servers.net\n\ 356 192.5.5.241; # f.root-servers.net\n\ 357 192.112.36.4; # g.root-servers.net\n\ 358 193.0.14.129; # k.root-servers.net\n\ 359 192.0.47.132; # xfr.cjr.dns.icann.org\n\ 360 192.0.32.132; # xfr.lax.dns.icann.org\n\ 361 };\n\ 362 "; 363 364 isc_result_t 365 named_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) { 366 isc_buffer_t b; 367 368 isc_buffer_init(&b, defaultconf, sizeof(defaultconf) - 1); 369 isc_buffer_add(&b, sizeof(defaultconf) - 1); 370 return cfg_parse_buffer(parser, &b, __FILE__, 0, &cfg_type_namedconf, 371 CFG_PCTX_NODEPRECATED | CFG_PCTX_NOOBSOLETE | 372 CFG_PCTX_NOEXPERIMENTAL, 373 conf); 374 } 375 376 const char * 377 named_config_getdefault(void) { 378 return defaultconf; 379 } 380 381 isc_result_t 382 named_config_get(cfg_obj_t const *const *maps, const char *name, 383 const cfg_obj_t **obj) { 384 int i; 385 386 for (i = 0; maps[i] != NULL; i++) { 387 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) { 388 return ISC_R_SUCCESS; 389 } 390 } 391 return ISC_R_NOTFOUND; 392 } 393 394 isc_result_t 395 named_checknames_get(const cfg_obj_t **maps, const char *const names[], 396 const cfg_obj_t **obj) { 397 const cfg_listelt_t *element; 398 const cfg_obj_t *checknames; 399 const cfg_obj_t *type; 400 const cfg_obj_t *value; 401 int i; 402 403 REQUIRE(maps != NULL); 404 REQUIRE(names != NULL); 405 REQUIRE(obj != NULL && *obj == NULL); 406 407 for (i = 0; maps[i] != NULL; i++) { 408 checknames = NULL; 409 if (cfg_map_get(maps[i], "check-names", &checknames) == 410 ISC_R_SUCCESS) 411 { 412 /* 413 * Zone map entry is not a list. 414 */ 415 if (checknames != NULL && !cfg_obj_islist(checknames)) { 416 *obj = checknames; 417 return ISC_R_SUCCESS; 418 } 419 for (element = cfg_list_first(checknames); 420 element != NULL; element = cfg_list_next(element)) 421 { 422 value = cfg_listelt_value(element); 423 type = cfg_tuple_get(value, "type"); 424 425 for (size_t j = 0; names[j] != NULL; j++) { 426 if (strcasecmp(cfg_obj_asstring(type), 427 names[j]) == 0) 428 { 429 *obj = cfg_tuple_get(value, 430 "mode"); 431 return ISC_R_SUCCESS; 432 } 433 } 434 } 435 } 436 } 437 return ISC_R_NOTFOUND; 438 } 439 440 int 441 named_config_listcount(const cfg_obj_t *list) { 442 const cfg_listelt_t *e; 443 int i = 0; 444 445 for (e = cfg_list_first(list); e != NULL; e = cfg_list_next(e)) { 446 i++; 447 } 448 449 return i; 450 } 451 452 isc_result_t 453 named_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass, 454 dns_rdataclass_t *classp) { 455 isc_textregion_t r; 456 isc_result_t result; 457 458 if (!cfg_obj_isstring(classobj)) { 459 *classp = defclass; 460 return ISC_R_SUCCESS; 461 } 462 r.base = UNCONST(cfg_obj_asstring(classobj)); 463 r.length = strlen(r.base); 464 result = dns_rdataclass_fromtext(classp, &r); 465 if (result != ISC_R_SUCCESS) { 466 cfg_obj_log(classobj, named_g_lctx, ISC_LOG_ERROR, 467 "unknown class '%s'", r.base); 468 } 469 return result; 470 } 471 472 isc_result_t 473 named_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype, 474 dns_rdatatype_t *typep) { 475 isc_textregion_t r; 476 isc_result_t result; 477 478 if (!cfg_obj_isstring(typeobj)) { 479 *typep = deftype; 480 return ISC_R_SUCCESS; 481 } 482 r.base = UNCONST(cfg_obj_asstring(typeobj)); 483 r.length = strlen(r.base); 484 result = dns_rdatatype_fromtext(typep, &r); 485 if (result != ISC_R_SUCCESS) { 486 cfg_obj_log(typeobj, named_g_lctx, ISC_LOG_ERROR, 487 "unknown type '%s'", r.base); 488 } 489 return result; 490 } 491 492 dns_zonetype_t 493 named_config_getzonetype(const cfg_obj_t *zonetypeobj) { 494 dns_zonetype_t ztype = dns_zone_none; 495 const char *str; 496 497 str = cfg_obj_asstring(zonetypeobj); 498 if (strcasecmp(str, "primary") == 0 || strcasecmp(str, "master") == 0) { 499 ztype = dns_zone_primary; 500 } else if (strcasecmp(str, "secondary") == 0 || 501 strcasecmp(str, "slave") == 0) 502 { 503 ztype = dns_zone_secondary; 504 } else if (strcasecmp(str, "mirror") == 0) { 505 ztype = dns_zone_mirror; 506 } else if (strcasecmp(str, "stub") == 0) { 507 ztype = dns_zone_stub; 508 } else if (strcasecmp(str, "static-stub") == 0) { 509 ztype = dns_zone_staticstub; 510 } else if (strcasecmp(str, "redirect") == 0) { 511 ztype = dns_zone_redirect; 512 } else { 513 UNREACHABLE(); 514 } 515 return ztype; 516 } 517 518 isc_result_t 519 named_config_getremotesdef(const cfg_obj_t *cctx, const char *list, 520 const char *name, const cfg_obj_t **ret) { 521 isc_result_t result; 522 const cfg_obj_t *obj = NULL; 523 const cfg_listelt_t *elt; 524 525 REQUIRE(cctx != NULL); 526 REQUIRE(name != NULL); 527 REQUIRE(ret != NULL && *ret == NULL); 528 529 result = cfg_map_get(cctx, list, &obj); 530 if (result != ISC_R_SUCCESS) { 531 return result; 532 } 533 elt = cfg_list_first(obj); 534 while (elt != NULL) { 535 obj = cfg_listelt_value(elt); 536 if (strcasecmp(cfg_obj_asstring(cfg_tuple_get(obj, "name")), 537 name) == 0) 538 { 539 *ret = obj; 540 return ISC_R_SUCCESS; 541 } 542 elt = cfg_list_next(elt); 543 } 544 return ISC_R_NOTFOUND; 545 } 546 547 static isc_result_t 548 named_config_getname(isc_mem_t *mctx, const cfg_obj_t *obj, 549 dns_name_t **namep) { 550 REQUIRE(namep != NULL && *namep == NULL); 551 552 const char *objstr; 553 isc_result_t result; 554 isc_buffer_t b; 555 dns_fixedname_t fname; 556 557 if (!cfg_obj_isstring(obj)) { 558 *namep = NULL; 559 return ISC_R_SUCCESS; 560 } 561 562 *namep = isc_mem_get(mctx, sizeof(**namep)); 563 dns_name_init(*namep, NULL); 564 565 objstr = cfg_obj_asstring(obj); 566 isc_buffer_constinit(&b, objstr, strlen(objstr)); 567 isc_buffer_add(&b, strlen(objstr)); 568 dns_fixedname_init(&fname); 569 result = dns_name_fromtext(dns_fixedname_name(&fname), &b, dns_rootname, 570 0, NULL); 571 if (result != ISC_R_SUCCESS) { 572 isc_mem_put(mctx, *namep, sizeof(**namep)); 573 *namep = NULL; 574 return result; 575 } 576 dns_name_dup(dns_fixedname_name(&fname), mctx, *namep); 577 578 return ISC_R_SUCCESS; 579 } 580 581 #define grow_array(mctx, array, newlen, oldlen) \ 582 if (newlen >= oldlen) { \ 583 array = isc_mem_creget(mctx, array, oldlen, newlen + 16, \ 584 sizeof(array[0])); \ 585 oldlen = newlen + 16; \ 586 } 587 588 #define shrink_array(mctx, array, newlen, oldlen) \ 589 if (newlen < oldlen) { \ 590 array = isc_mem_creget(mctx, array, oldlen, newlen, \ 591 sizeof(array[0])); \ 592 oldlen = newlen; \ 593 } 594 595 static const char *remotesnames[4] = { "remote-servers", "parental-agents", 596 "primaries", "masters" }; 597 598 typedef struct { 599 isc_sockaddr_t *addrs; 600 size_t addrsallocated; 601 602 isc_sockaddr_t *sources; 603 size_t sourcesallocated; 604 605 dns_name_t **keys; 606 size_t keysallocated; 607 608 dns_name_t **tlss; 609 size_t tlssallocated; 610 611 size_t count; /* common to addrs, sources, keys and tlss */ 612 613 const char **seen; 614 size_t seencount; 615 size_t seenallocated; 616 } getipandkeylist_state_t; 617 618 static isc_result_t 619 getipandkeylist(in_port_t defport, in_port_t deftlsport, 620 const cfg_obj_t *config, const cfg_obj_t *list, 621 in_port_t listport, const cfg_obj_t *listkey, 622 const cfg_obj_t *listtls, isc_mem_t *mctx, 623 getipandkeylist_state_t *s) { 624 const cfg_obj_t *addrlist = cfg_tuple_get(list, "addresses"); 625 const cfg_obj_t *portobj = cfg_tuple_get(list, "port"); 626 const cfg_obj_t *src4obj = cfg_tuple_get(list, "source"); 627 const cfg_obj_t *src6obj = cfg_tuple_get(list, "source-v6"); 628 in_port_t port = (in_port_t)0; 629 isc_sockaddr_t src4; 630 isc_sockaddr_t src6; 631 isc_result_t result = ISC_R_SUCCESS; 632 633 if (cfg_obj_isuint32(portobj)) { 634 uint32_t val = cfg_obj_asuint32(portobj); 635 if (val > UINT16_MAX) { 636 cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR, 637 "port '%u' out of range", val); 638 return ISC_R_RANGE; 639 } 640 port = (in_port_t)val; 641 } else if (listport > 0) { 642 /* 643 * No port in the current list, but it is a list named elsewhere 644 * where the port is defined, i.e: 645 * 646 * remote-servers bar { 10.53.0.4; }; 647 * remote-servers foo port 5555 { bar; 10.54.0.3; }; 648 * ^^^ 649 * 650 * The current list is the list `bar`, and the server 651 * `10.53.0.4` has the port `5555` defined. 652 */ 653 port = listport; 654 } 655 656 if (src4obj != NULL && cfg_obj_issockaddr(src4obj)) { 657 src4 = *cfg_obj_assockaddr(src4obj); 658 } else { 659 isc_sockaddr_any(&src4); 660 } 661 662 if (src6obj != NULL && cfg_obj_issockaddr(src6obj)) { 663 src6 = *cfg_obj_assockaddr(src6obj); 664 } else { 665 isc_sockaddr_any6(&src6); 666 } 667 668 for (const cfg_listelt_t *element = cfg_list_first(addrlist); 669 element != NULL; element = cfg_list_next(element)) 670 { 671 const cfg_obj_t *addr; 672 const cfg_obj_t *key; 673 const cfg_obj_t *tls; 674 675 skiplist: 676 addr = cfg_tuple_get(cfg_listelt_value(element), 677 "remoteselement"); 678 key = cfg_tuple_get(cfg_listelt_value(element), "key"); 679 tls = cfg_tuple_get(cfg_listelt_value(element), "tls"); 680 681 /* 682 * If this is not an address, this is the name of a nested list, 683 * i.e. 684 * 685 * remote-servers nestedlist { 10.53.0.4; }; 686 * remote-servers list { nestedlist key foo; 10.54.0.6; }; 687 * ^^^^^^^^^^^^^^^^^^ 688 * 689 * We are currently in the list `list`, and `addr` is the name 690 * `nestedlist`, so we'll immediately recurse to process 691 * `nestedlist` before processing the next element of `list`. 692 */ 693 if (!cfg_obj_issockaddr(addr)) { 694 const char *listname = cfg_obj_asstring(addr); 695 const cfg_obj_t *nestedlist = NULL; 696 isc_result_t tresult; 697 698 for (size_t i = 0; i < s->seencount; i++) { 699 if (strcasecmp(s->seen[i], listname) == 0) { 700 element = cfg_list_next(element); 701 goto skiplist; 702 } 703 } 704 705 grow_array(mctx, s->seen, s->seencount, 706 s->seenallocated); 707 s->seen[s->seencount] = listname; 708 709 for (size_t i = 0; i < ARRAY_SIZE(remotesnames); i++) { 710 tresult = named_config_getremotesdef( 711 config, remotesnames[i], listname, 712 &nestedlist); 713 if (tresult == ISC_R_SUCCESS) { 714 break; 715 } 716 } 717 718 if (tresult != ISC_R_SUCCESS) { 719 cfg_obj_log(addr, named_g_lctx, ISC_LOG_ERROR, 720 "remote-servers \"%s\" not found", 721 listname); 722 return tresult; 723 } 724 725 result = getipandkeylist(defport, deftlsport, config, 726 nestedlist, port, key, tls, 727 mctx, s); 728 if (result != ISC_R_SUCCESS) { 729 goto out; 730 } 731 continue; 732 } 733 734 grow_array(mctx, s->addrs, s->count, s->addrsallocated); 735 grow_array(mctx, s->keys, s->count, s->keysallocated); 736 grow_array(mctx, s->tlss, s->count, s->tlssallocated); 737 grow_array(mctx, s->sources, s->count, s->sourcesallocated); 738 739 s->addrs[s->count] = *cfg_obj_assockaddr(addr); 740 741 result = named_config_getname(mctx, key, &s->keys[s->count]); 742 if (result != ISC_R_SUCCESS) { 743 goto out; 744 } 745 746 /* 747 * The `key` is not provided for this address, so, if we're 748 * inside a named list, get the `key` provided at the point the 749 * list is used. 750 */ 751 if (s->keys[s->count] == NULL && listkey != NULL) { 752 result = named_config_getname(mctx, listkey, 753 &s->keys[s->count]); 754 if (result != ISC_R_SUCCESS) { 755 goto out; 756 } 757 } 758 759 result = named_config_getname(mctx, tls, &s->tlss[s->count]); 760 if (result != ISC_R_SUCCESS) { 761 goto out; 762 } 763 764 /* 765 * The `tls` is not provided for this address, so, if we're 766 * inside a named list, get the `tls` provided at the point the 767 * named list is used. 768 */ 769 if (s->tlss[s->count] == NULL && listtls != NULL) { 770 result = named_config_getname(mctx, listtls, 771 &s->tlss[s->count]); 772 } 773 774 /* If the port is unset, take it from one of the upper levels */ 775 if (isc_sockaddr_getport(&s->addrs[s->count]) == 0) { 776 in_port_t addr_port = port; 777 778 /* If unset, use the default port or tls-port */ 779 if (addr_port == 0) { 780 if (s->tlss[s->count] != NULL) { 781 addr_port = deftlsport; 782 } else { 783 addr_port = defport; 784 } 785 } 786 787 isc_sockaddr_setport(&s->addrs[s->count], addr_port); 788 } 789 790 switch (isc_sockaddr_pf(&s->addrs[s->count])) { 791 case PF_INET: 792 s->sources[s->count] = src4; 793 break; 794 case PF_INET6: 795 s->sources[s->count] = src6; 796 break; 797 default: 798 result = ISC_R_NOTIMPLEMENTED; 799 goto out; 800 } 801 802 s->count++; 803 } 804 805 out: 806 if (result != ISC_R_SUCCESS) { 807 /* 808 * Reaching this point without success means we were in the 809 * middle of adding a new entry, so it needs to be counted for 810 * correctly free `s.keys` and `s.tlss` (as they potentially 811 * added a new element right before something fails) 812 */ 813 s->count++; 814 } 815 return result; 816 } 817 818 isc_result_t 819 named_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, 820 isc_mem_t *mctx, dns_ipkeylist_t *ipkl) { 821 isc_result_t result; 822 in_port_t def_port; 823 in_port_t def_tlsport; 824 getipandkeylist_state_t s = {}; 825 826 REQUIRE(ipkl != NULL); 827 REQUIRE(ipkl->count == 0); 828 REQUIRE(ipkl->addrs == NULL); 829 REQUIRE(ipkl->keys == NULL); 830 REQUIRE(ipkl->tlss == NULL); 831 REQUIRE(ipkl->labels == NULL); 832 REQUIRE(ipkl->allocated == 0); 833 834 /* 835 * Get system defaults. 836 */ 837 result = named_config_getport(config, "port", &def_port); 838 if (result != ISC_R_SUCCESS) { 839 goto cleanup; 840 } 841 842 result = named_config_getport(config, "tls-port", &def_tlsport); 843 if (result != ISC_R_SUCCESS) { 844 goto cleanup; 845 } 846 847 /* 848 * Process the (nested) list(s). 849 */ 850 result = getipandkeylist(def_port, def_tlsport, config, list, 851 (in_port_t)0, NULL, NULL, mctx, &s); 852 if (result != ISC_R_SUCCESS) { 853 goto cleanup; 854 } 855 856 shrink_array(mctx, s.addrs, s.count, s.addrsallocated); 857 shrink_array(mctx, s.keys, s.count, s.keysallocated); 858 shrink_array(mctx, s.tlss, s.count, s.tlssallocated); 859 shrink_array(mctx, s.sources, s.count, s.sourcesallocated); 860 861 ipkl->addrs = s.addrs; 862 ipkl->keys = s.keys; 863 ipkl->tlss = s.tlss; 864 ipkl->sources = s.sources; 865 ipkl->count = s.count; 866 867 INSIST(s.addrsallocated == s.keysallocated); 868 INSIST(s.addrsallocated == s.tlssallocated); 869 INSIST(s.addrsallocated == s.sourcesallocated); 870 ipkl->allocated = s.addrsallocated; 871 872 if (s.seen != NULL) { 873 /* 874 * `s.seen` is not shrinked (no point, as it's deleted right 875 * away anyway), so we need to use `s.seenallocated` to 876 * correctly free the array. 877 */ 878 isc_mem_cput(mctx, s.seen, s.seenallocated, sizeof(s.seen[0])); 879 } 880 881 return ISC_R_SUCCESS; 882 883 cleanup: 884 /* 885 * Because we didn't shrinked the array back in this path, we need to 886 * use `s.*allocated` to correctly free the allocated arrays. 887 */ 888 if (s.addrs != NULL) { 889 isc_mem_cput(mctx, s.addrs, s.count, sizeof(s.addrs[0])); 890 } 891 if (s.keys != NULL) { 892 for (size_t i = 0; i < s.count; i++) { 893 if (s.keys[i] == NULL) { 894 continue; 895 } 896 if (dns_name_dynamic(s.keys[i])) { 897 dns_name_free(s.keys[i], mctx); 898 } 899 isc_mem_put(mctx, s.keys[i], sizeof(*s.keys[i])); 900 } 901 isc_mem_cput(mctx, s.keys, s.keysallocated, sizeof(s.keys[0])); 902 } 903 if (s.tlss != NULL) { 904 for (size_t i = 0; i < s.count; i++) { 905 if (s.tlss[i] == NULL) { 906 continue; 907 } 908 if (dns_name_dynamic(s.tlss[i])) { 909 dns_name_free(s.tlss[i], mctx); 910 } 911 isc_mem_put(mctx, s.tlss[i], sizeof(*s.tlss[i])); 912 } 913 isc_mem_cput(mctx, s.tlss, s.tlssallocated, sizeof(s.tlss[0])); 914 } 915 if (s.sources != NULL) { 916 isc_mem_cput(mctx, s.sources, s.sourcesallocated, 917 sizeof(s.sources[0])); 918 } 919 if (s.seen != NULL) { 920 isc_mem_cput(mctx, s.seen, s.seenallocated, sizeof(s.seen[0])); 921 } 922 923 return result; 924 } 925 926 isc_result_t 927 named_config_getport(const cfg_obj_t *config, const char *type, 928 in_port_t *portp) { 929 const cfg_obj_t *maps[3]; 930 const cfg_obj_t *options = NULL; 931 const cfg_obj_t *portobj = NULL; 932 isc_result_t result; 933 int i; 934 935 (void)cfg_map_get(config, "options", &options); 936 i = 0; 937 if (options != NULL) { 938 maps[i++] = options; 939 } 940 maps[i++] = named_g_defaults; 941 maps[i] = NULL; 942 943 result = named_config_get(maps, type, &portobj); 944 INSIST(result == ISC_R_SUCCESS); 945 if (cfg_obj_asuint32(portobj) >= UINT16_MAX) { 946 cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR, 947 "port '%u' out of range", 948 cfg_obj_asuint32(portobj)); 949 return ISC_R_RANGE; 950 } 951 *portp = (in_port_t)cfg_obj_asuint32(portobj); 952 return ISC_R_SUCCESS; 953 } 954 955 struct keyalgorithms { 956 const char *str; 957 enum { 958 hmacnone, 959 hmacmd5, 960 hmacsha1, 961 hmacsha224, 962 hmacsha256, 963 hmacsha384, 964 hmacsha512 965 } hmac; 966 unsigned int type; 967 uint16_t size; 968 } algorithms[] = { { "hmac-md5", hmacmd5, DST_ALG_HMACMD5, 128 }, 969 { "hmac-md5.sig-alg.reg.int", hmacmd5, DST_ALG_HMACMD5, 0 }, 970 { "hmac-md5.sig-alg.reg.int.", hmacmd5, DST_ALG_HMACMD5, 0 }, 971 { "hmac-sha1", hmacsha1, DST_ALG_HMACSHA1, 160 }, 972 { "hmac-sha224", hmacsha224, DST_ALG_HMACSHA224, 224 }, 973 { "hmac-sha256", hmacsha256, DST_ALG_HMACSHA256, 256 }, 974 { "hmac-sha384", hmacsha384, DST_ALG_HMACSHA384, 384 }, 975 { "hmac-sha512", hmacsha512, DST_ALG_HMACSHA512, 512 }, 976 { NULL, hmacnone, DST_ALG_UNKNOWN, 0 } }; 977 978 isc_result_t 979 named_config_getkeyalgorithm(const char *str, unsigned int *typep, 980 uint16_t *digestbits) { 981 int i; 982 size_t len = 0; 983 uint16_t bits; 984 isc_result_t result; 985 986 for (i = 0; algorithms[i].str != NULL; i++) { 987 len = strlen(algorithms[i].str); 988 if (strncasecmp(algorithms[i].str, str, len) == 0 && 989 (str[len] == '\0' || 990 (algorithms[i].size != 0 && str[len] == '-'))) 991 { 992 break; 993 } 994 } 995 if (algorithms[i].str == NULL) { 996 return ISC_R_NOTFOUND; 997 } 998 if (str[len] == '-') { 999 result = isc_parse_uint16(&bits, str + len + 1, 10); 1000 if (result != ISC_R_SUCCESS) { 1001 return result; 1002 } 1003 if (bits > algorithms[i].size) { 1004 return ISC_R_RANGE; 1005 } 1006 } else if (algorithms[i].size == 0) { 1007 bits = 128; 1008 } else { 1009 bits = algorithms[i].size; 1010 } 1011 SET_IF_NOT_NULL(typep, algorithms[i].type); 1012 SET_IF_NOT_NULL(digestbits, bits); 1013 return ISC_R_SUCCESS; 1014 } 1015