1 /* $NetBSD: aclconf.c,v 1.11 2025/01/26 16:25:45 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 #include <inttypes.h> 17 #include <stdbool.h> 18 #include <stdlib.h> 19 20 #include <isc/mem.h> 21 #include <isc/string.h> 22 #include <isc/util.h> 23 24 #include <dns/acl.h> 25 #include <dns/fixedname.h> 26 #include <dns/iptable.h> 27 #include <dns/log.h> 28 29 #include <isccfg/aclconf.h> 30 #include <isccfg/namedconf.h> 31 32 #define LOOP_MAGIC ISC_MAGIC('L', 'O', 'O', 'P') 33 34 #if defined(HAVE_GEOIP2) 35 static const char *geoip_dbnames[] = { 36 "country", "city", "asnum", "isp", "domain", NULL, 37 }; 38 #endif /* if defined(HAVE_GEOIP2) */ 39 40 isc_result_t 41 cfg_aclconfctx_create(isc_mem_t *mctx, cfg_aclconfctx_t **ret) { 42 cfg_aclconfctx_t *actx; 43 44 REQUIRE(mctx != NULL); 45 REQUIRE(ret != NULL && *ret == NULL); 46 47 actx = isc_mem_get(mctx, sizeof(*actx)); 48 49 isc_refcount_init(&actx->references, 1); 50 51 actx->mctx = NULL; 52 isc_mem_attach(mctx, &actx->mctx); 53 ISC_LIST_INIT(actx->named_acl_cache); 54 55 #if defined(HAVE_GEOIP2) 56 actx->geoip = NULL; 57 #endif /* if defined(HAVE_GEOIP2) */ 58 59 *ret = actx; 60 return ISC_R_SUCCESS; 61 } 62 63 void 64 cfg_aclconfctx_attach(cfg_aclconfctx_t *src, cfg_aclconfctx_t **dest) { 65 REQUIRE(src != NULL); 66 REQUIRE(dest != NULL && *dest == NULL); 67 68 isc_refcount_increment(&src->references); 69 *dest = src; 70 } 71 72 void 73 cfg_aclconfctx_detach(cfg_aclconfctx_t **actxp) { 74 REQUIRE(actxp != NULL && *actxp != NULL); 75 cfg_aclconfctx_t *actx = *actxp; 76 *actxp = NULL; 77 78 if (isc_refcount_decrement(&actx->references) == 1) { 79 dns_acl_t *dacl, *next; 80 isc_refcount_destroy(&actx->references); 81 for (dacl = ISC_LIST_HEAD(actx->named_acl_cache); dacl != NULL; 82 dacl = next) 83 { 84 next = ISC_LIST_NEXT(dacl, nextincache); 85 ISC_LIST_UNLINK(actx->named_acl_cache, dacl, 86 nextincache); 87 dns_acl_detach(&dacl); 88 } 89 isc_mem_putanddetach(&actx->mctx, actx, sizeof(*actx)); 90 } 91 } 92 93 /* 94 * Find the definition of the named acl whose name is "name". 95 */ 96 static isc_result_t 97 get_acl_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) { 98 isc_result_t result; 99 const cfg_obj_t *acls = NULL; 100 const cfg_listelt_t *elt; 101 102 result = cfg_map_get(cctx, "acl", &acls); 103 if (result != ISC_R_SUCCESS) { 104 return result; 105 } 106 for (elt = cfg_list_first(acls); elt != NULL; elt = cfg_list_next(elt)) 107 { 108 const cfg_obj_t *acl = cfg_listelt_value(elt); 109 const char *aclname = 110 cfg_obj_asstring(cfg_tuple_get(acl, "name")); 111 if (strcasecmp(aclname, name) == 0) { 112 if (ret != NULL) { 113 *ret = cfg_tuple_get(acl, "value"); 114 } 115 return ISC_R_SUCCESS; 116 } 117 } 118 return ISC_R_NOTFOUND; 119 } 120 121 static isc_result_t 122 convert_named_acl(const cfg_obj_t *nameobj, const cfg_obj_t *cctx, 123 isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx, 124 unsigned int nest_level, dns_acl_t **target) { 125 isc_result_t result; 126 const cfg_obj_t *cacl = NULL; 127 dns_acl_t *dacl; 128 dns_acl_t loop; 129 const char *aclname = cfg_obj_asstring(nameobj); 130 131 /* Look for an already-converted version. */ 132 for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache); dacl != NULL; 133 dacl = ISC_LIST_NEXT(dacl, nextincache)) 134 { 135 if (strcasecmp(aclname, dacl->name) == 0) { 136 if (ISC_MAGIC_VALID(dacl, LOOP_MAGIC)) { 137 cfg_obj_log(nameobj, lctx, ISC_LOG_ERROR, 138 "acl loop detected: %s", aclname); 139 return ISC_R_FAILURE; 140 } 141 dns_acl_attach(dacl, target); 142 return ISC_R_SUCCESS; 143 } 144 } 145 /* Not yet converted. Convert now. */ 146 result = get_acl_def(cctx, aclname, &cacl); 147 if (result != ISC_R_SUCCESS) { 148 cfg_obj_log(nameobj, lctx, ISC_LOG_WARNING, 149 "undefined ACL '%s'", aclname); 150 return result; 151 } 152 /* 153 * Add a loop detection element. 154 */ 155 memset(&loop, 0, sizeof(loop)); 156 ISC_LINK_INIT(&loop, nextincache); 157 loop.name = UNCONST(aclname); 158 loop.magic = LOOP_MAGIC; 159 ISC_LIST_APPEND(ctx->named_acl_cache, &loop, nextincache); 160 result = cfg_acl_fromconfig(cacl, cctx, lctx, ctx, mctx, nest_level, 161 &dacl); 162 ISC_LIST_UNLINK(ctx->named_acl_cache, &loop, nextincache); 163 loop.magic = 0; 164 loop.name = NULL; 165 if (result != ISC_R_SUCCESS) { 166 return result; 167 } 168 dacl->name = isc_mem_strdup(dacl->mctx, aclname); 169 ISC_LIST_APPEND(ctx->named_acl_cache, dacl, nextincache); 170 dns_acl_attach(dacl, target); 171 return ISC_R_SUCCESS; 172 } 173 174 static isc_result_t 175 convert_keyname(const cfg_obj_t *keyobj, isc_log_t *lctx, isc_mem_t *mctx, 176 dns_name_t *dnsname) { 177 isc_result_t result; 178 isc_buffer_t buf; 179 dns_fixedname_t fixname; 180 unsigned int keylen; 181 const char *txtname = cfg_obj_asstring(keyobj); 182 183 keylen = strlen(txtname); 184 isc_buffer_constinit(&buf, txtname, keylen); 185 isc_buffer_add(&buf, keylen); 186 dns_fixedname_init(&fixname); 187 result = dns_name_fromtext(dns_fixedname_name(&fixname), &buf, 188 dns_rootname, 0, NULL); 189 if (result != ISC_R_SUCCESS) { 190 cfg_obj_log(keyobj, lctx, ISC_LOG_WARNING, 191 "key name '%s' is not a valid domain name", 192 txtname); 193 return result; 194 } 195 dns_name_dup(dns_fixedname_name(&fixname), mctx, dnsname); 196 return ISC_R_SUCCESS; 197 } 198 199 /* 200 * Recursively pre-parse an ACL definition to find the total number 201 * of non-IP-prefix elements (localhost, localnets, key) in all nested 202 * ACLs, so that the parent will have enough space allocated for the 203 * elements table after all the nested ACLs have been merged in to the 204 * parent. 205 */ 206 static isc_result_t 207 count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx, 208 isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx, 209 uint32_t *count, bool *has_negative) { 210 const cfg_listelt_t *elt; 211 isc_result_t result; 212 uint32_t n = 0; 213 214 REQUIRE(count != NULL); 215 216 if (has_negative != NULL) { 217 *has_negative = false; 218 } 219 220 for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) 221 { 222 const cfg_obj_t *ce = cfg_listelt_value(elt); 223 224 /* might be a negated element, in which case get the value. */ 225 if (cfg_obj_istuple(ce)) { 226 const cfg_obj_t *negated = cfg_tuple_get(ce, "negated"); 227 if (!cfg_obj_isvoid(negated)) { 228 ce = negated; 229 if (has_negative != NULL) { 230 *has_negative = true; 231 } 232 } 233 } 234 235 if (cfg_obj_istype(ce, &cfg_type_keyref)) { 236 n++; 237 } else if (cfg_obj_islist(ce)) { 238 bool negative; 239 uint32_t sub; 240 result = count_acl_elements(ce, cctx, lctx, ctx, mctx, 241 &sub, &negative); 242 if (result != ISC_R_SUCCESS) { 243 return result; 244 } 245 n += sub; 246 if (negative) { 247 n++; 248 } 249 #if defined(HAVE_GEOIP2) 250 } else if (cfg_obj_istuple(ce) && 251 cfg_obj_isvoid(cfg_tuple_get(ce, "negated"))) 252 { 253 n++; 254 #endif /* HAVE_GEOIP2 */ 255 } else if (cfg_obj_isstring(ce)) { 256 const char *name = cfg_obj_asstring(ce); 257 if (strcasecmp(name, "localhost") == 0 || 258 strcasecmp(name, "localnets") == 0 || 259 strcasecmp(name, "none") == 0) 260 { 261 n++; 262 } else if (strcasecmp(name, "any") != 0) { 263 dns_acl_t *inneracl = NULL; 264 /* 265 * Convert any named acls we reference now if 266 * they have not already been converted. 267 */ 268 result = convert_named_acl(ce, cctx, lctx, ctx, 269 mctx, 0, &inneracl); 270 if (result == ISC_R_SUCCESS) { 271 if (inneracl->has_negatives) { 272 n++; 273 } else { 274 n += inneracl->length; 275 } 276 dns_acl_detach(&inneracl); 277 } else { 278 return result; 279 } 280 } 281 } 282 } 283 284 *count = n; 285 return ISC_R_SUCCESS; 286 } 287 288 #if defined(HAVE_GEOIP2) 289 static dns_geoip_subtype_t 290 get_subtype(const cfg_obj_t *obj, isc_log_t *lctx, dns_geoip_subtype_t subtype, 291 const char *dbname) { 292 if (dbname == NULL) { 293 return subtype; 294 } 295 296 switch (subtype) { 297 case dns_geoip_countrycode: 298 if (strcasecmp(dbname, "city") == 0) { 299 return dns_geoip_city_countrycode; 300 } else if (strcasecmp(dbname, "country") == 0) { 301 return dns_geoip_country_code; 302 } 303 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 304 "invalid database specified for " 305 "country search: ignored"); 306 return subtype; 307 case dns_geoip_countryname: 308 if (strcasecmp(dbname, "city") == 0) { 309 return dns_geoip_city_countryname; 310 } else if (strcasecmp(dbname, "country") == 0) { 311 return dns_geoip_country_name; 312 } 313 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 314 "invalid database specified for " 315 "country search: ignored"); 316 return subtype; 317 case dns_geoip_continentcode: 318 if (strcasecmp(dbname, "city") == 0) { 319 return dns_geoip_city_continentcode; 320 } else if (strcasecmp(dbname, "country") == 0) { 321 return dns_geoip_country_continentcode; 322 } 323 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 324 "invalid database specified for " 325 "continent search: ignored"); 326 return subtype; 327 case dns_geoip_continent: 328 if (strcasecmp(dbname, "city") == 0) { 329 return dns_geoip_city_continent; 330 } else if (strcasecmp(dbname, "country") == 0) { 331 return dns_geoip_country_continent; 332 } 333 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 334 "invalid database specified for " 335 "continent search: ignored"); 336 return subtype; 337 case dns_geoip_region: 338 if (strcasecmp(dbname, "city") == 0) { 339 return dns_geoip_city_region; 340 } 341 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 342 "invalid database specified for " 343 "region/subdivision search: ignored"); 344 return subtype; 345 case dns_geoip_regionname: 346 if (strcasecmp(dbname, "city") == 0) { 347 return dns_geoip_city_regionname; 348 } 349 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 350 "invalid database specified for " 351 "region/subdivision search: ignored"); 352 return subtype; 353 354 /* 355 * Log a warning if the wrong database was specified 356 * on an unambiguous query 357 */ 358 case dns_geoip_city_name: 359 case dns_geoip_city_postalcode: 360 case dns_geoip_city_metrocode: 361 case dns_geoip_city_areacode: 362 case dns_geoip_city_timezonecode: 363 if (strcasecmp(dbname, "city") != 0) { 364 cfg_obj_log(obj, lctx, ISC_LOG_WARNING, 365 "invalid database specified for " 366 "a 'city'-only search type: ignoring"); 367 } 368 return subtype; 369 case dns_geoip_isp_name: 370 if (strcasecmp(dbname, "isp") != 0) { 371 cfg_obj_log(obj, lctx, ISC_LOG_WARNING, 372 "invalid database specified for " 373 "an 'isp' search: ignoring"); 374 } 375 return subtype; 376 case dns_geoip_org_name: 377 if (strcasecmp(dbname, "org") != 0) { 378 cfg_obj_log(obj, lctx, ISC_LOG_WARNING, 379 "invalid database specified for " 380 "an 'org' search: ignoring"); 381 } 382 return subtype; 383 case dns_geoip_as_asnum: 384 if (strcasecmp(dbname, "asnum") != 0) { 385 cfg_obj_log(obj, lctx, ISC_LOG_WARNING, 386 "invalid database specified for " 387 "an 'asnum' search: ignoring"); 388 } 389 return subtype; 390 case dns_geoip_domain_name: 391 if (strcasecmp(dbname, "domain") != 0) { 392 cfg_obj_log(obj, lctx, ISC_LOG_WARNING, 393 "invalid database specified for " 394 "a 'domain' search: ignoring"); 395 } 396 return subtype; 397 case dns_geoip_netspeed_id: 398 if (strcasecmp(dbname, "netspeed") != 0) { 399 cfg_obj_log(obj, lctx, ISC_LOG_WARNING, 400 "invalid database specified for " 401 "a 'netspeed' search: ignoring"); 402 } 403 return subtype; 404 default: 405 UNREACHABLE(); 406 } 407 } 408 409 static bool 410 geoip_can_answer(dns_aclelement_t *elt, cfg_aclconfctx_t *ctx) { 411 if (ctx->geoip == NULL) { 412 return true; 413 } 414 415 switch (elt->geoip_elem.subtype) { 416 case dns_geoip_countrycode: 417 case dns_geoip_countryname: 418 case dns_geoip_continentcode: 419 case dns_geoip_continent: 420 if (ctx->geoip->country != NULL || ctx->geoip->city != NULL) { 421 return true; 422 } 423 break; 424 case dns_geoip_country_code: 425 case dns_geoip_country_name: 426 case dns_geoip_country_continentcode: 427 case dns_geoip_country_continent: 428 if (ctx->geoip->country != NULL) { 429 return true; 430 } 431 /* city db can answer these too, so: */ 432 FALLTHROUGH; 433 case dns_geoip_region: 434 case dns_geoip_regionname: 435 case dns_geoip_city_countrycode: 436 case dns_geoip_city_countryname: 437 case dns_geoip_city_region: 438 case dns_geoip_city_regionname: 439 case dns_geoip_city_name: 440 case dns_geoip_city_postalcode: 441 case dns_geoip_city_metrocode: 442 case dns_geoip_city_areacode: 443 case dns_geoip_city_continentcode: 444 case dns_geoip_city_continent: 445 case dns_geoip_city_timezonecode: 446 if (ctx->geoip->city != NULL) { 447 return true; 448 } 449 break; 450 case dns_geoip_isp_name: 451 if (ctx->geoip->isp != NULL) { 452 return true; 453 } 454 break; 455 case dns_geoip_as_asnum: 456 case dns_geoip_org_name: 457 if (ctx->geoip->as != NULL) { 458 return true; 459 } 460 break; 461 case dns_geoip_domain_name: 462 if (ctx->geoip->domain != NULL) { 463 return true; 464 } 465 break; 466 default: 467 break; 468 } 469 470 return false; 471 } 472 473 static isc_result_t 474 parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx, 475 cfg_aclconfctx_t *ctx, dns_aclelement_t *dep) { 476 const cfg_obj_t *ge; 477 const char *dbname = NULL; 478 const char *stype = NULL, *search = NULL; 479 dns_geoip_subtype_t subtype; 480 dns_aclelement_t de; 481 size_t len; 482 483 REQUIRE(dep != NULL); 484 485 de = *dep; 486 487 ge = cfg_tuple_get(obj, "db"); 488 if (!cfg_obj_isvoid(ge)) { 489 int i; 490 491 dbname = cfg_obj_asstring(ge); 492 493 for (i = 0; geoip_dbnames[i] != NULL; i++) { 494 if (strcasecmp(dbname, geoip_dbnames[i]) == 0) { 495 break; 496 } 497 } 498 if (geoip_dbnames[i] == NULL) { 499 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 500 "database '%s' is not defined for GeoIP2", 501 dbname); 502 return ISC_R_UNEXPECTED; 503 } 504 } 505 506 stype = cfg_obj_asstring(cfg_tuple_get(obj, "subtype")); 507 search = cfg_obj_asstring(cfg_tuple_get(obj, "search")); 508 len = strlen(search); 509 510 if (len == 0) { 511 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 512 "zero-length geoip search field"); 513 return ISC_R_FAILURE; 514 } 515 516 if (strcasecmp(stype, "country") == 0 && len == 2) { 517 /* Two-letter country code */ 518 subtype = dns_geoip_countrycode; 519 strlcpy(de.geoip_elem.as_string, search, 520 sizeof(de.geoip_elem.as_string)); 521 } else if (strcasecmp(stype, "country") == 0 && len == 3) { 522 /* Three-letter country code */ 523 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 524 "three-letter country codes are unavailable " 525 "in GeoIP2 databases"); 526 return ISC_R_FAILURE; 527 } else if (strcasecmp(stype, "country") == 0) { 528 /* Country name */ 529 subtype = dns_geoip_countryname; 530 strlcpy(de.geoip_elem.as_string, search, 531 sizeof(de.geoip_elem.as_string)); 532 } else if (strcasecmp(stype, "continent") == 0 && len == 2) { 533 /* Two-letter continent code */ 534 subtype = dns_geoip_continentcode; 535 strlcpy(de.geoip_elem.as_string, search, 536 sizeof(de.geoip_elem.as_string)); 537 } else if (strcasecmp(stype, "continent") == 0) { 538 subtype = dns_geoip_continent; 539 strlcpy(de.geoip_elem.as_string, search, 540 sizeof(de.geoip_elem.as_string)); 541 } else if ((strcasecmp(stype, "region") == 0 || 542 strcasecmp(stype, "subdivision") == 0) && 543 len == 2) 544 { 545 /* Two-letter region code */ 546 subtype = dns_geoip_region; 547 strlcpy(de.geoip_elem.as_string, search, 548 sizeof(de.geoip_elem.as_string)); 549 } else if (strcasecmp(stype, "region") == 0 || 550 strcasecmp(stype, "subdivision") == 0) 551 { 552 /* Region name */ 553 subtype = dns_geoip_regionname; 554 strlcpy(de.geoip_elem.as_string, search, 555 sizeof(de.geoip_elem.as_string)); 556 } else if (strcasecmp(stype, "city") == 0) { 557 /* City name */ 558 subtype = dns_geoip_city_name; 559 strlcpy(de.geoip_elem.as_string, search, 560 sizeof(de.geoip_elem.as_string)); 561 } else if (strcasecmp(stype, "postal") == 0 || 562 strcasecmp(stype, "postalcode") == 0) 563 { 564 if (len < 7) { 565 subtype = dns_geoip_city_postalcode; 566 strlcpy(de.geoip_elem.as_string, search, 567 sizeof(de.geoip_elem.as_string)); 568 } else { 569 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 570 "geoiop postal code (%s) too long", search); 571 return ISC_R_FAILURE; 572 } 573 } else if (strcasecmp(stype, "metro") == 0 || 574 strcasecmp(stype, "metrocode") == 0) 575 { 576 subtype = dns_geoip_city_metrocode; 577 de.geoip_elem.as_int = atoi(search); 578 } else if (strcasecmp(stype, "tz") == 0 || 579 strcasecmp(stype, "timezone") == 0) 580 { 581 subtype = dns_geoip_city_timezonecode; 582 strlcpy(de.geoip_elem.as_string, search, 583 sizeof(de.geoip_elem.as_string)); 584 } else if (strcasecmp(stype, "isp") == 0) { 585 subtype = dns_geoip_isp_name; 586 strlcpy(de.geoip_elem.as_string, search, 587 sizeof(de.geoip_elem.as_string)); 588 } else if (strcasecmp(stype, "asnum") == 0) { 589 subtype = dns_geoip_as_asnum; 590 strlcpy(de.geoip_elem.as_string, search, 591 sizeof(de.geoip_elem.as_string)); 592 } else if (strcasecmp(stype, "org") == 0) { 593 subtype = dns_geoip_org_name; 594 strlcpy(de.geoip_elem.as_string, search, 595 sizeof(de.geoip_elem.as_string)); 596 } else if (strcasecmp(stype, "domain") == 0) { 597 subtype = dns_geoip_domain_name; 598 strlcpy(de.geoip_elem.as_string, search, 599 sizeof(de.geoip_elem.as_string)); 600 } else { 601 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 602 "type '%s' is unavailable " 603 "in GeoIP2 databases", 604 stype); 605 return ISC_R_FAILURE; 606 } 607 608 de.geoip_elem.subtype = get_subtype(obj, lctx, subtype, dbname); 609 610 if (!geoip_can_answer(&de, ctx)) { 611 cfg_obj_log(obj, lctx, ISC_LOG_ERROR, 612 "no GeoIP2 database installed which can answer " 613 "queries of type '%s'", 614 stype); 615 return ISC_R_FAILURE; 616 } 617 618 *dep = de; 619 620 return ISC_R_SUCCESS; 621 } 622 #endif /* HAVE_GEOIP2 */ 623 624 isc_result_t 625 cfg_acl_fromconfig(const cfg_obj_t *acl_data, const cfg_obj_t *cctx, 626 isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx, 627 unsigned int nest_level, dns_acl_t **target) { 628 isc_result_t result; 629 dns_acl_t *dacl = NULL, *inneracl = NULL; 630 dns_aclelement_t *de; 631 const cfg_listelt_t *elt; 632 dns_iptable_t *iptab; 633 int new_nest_level = 0; 634 bool setpos; 635 const cfg_obj_t *caml = NULL; 636 const cfg_obj_t *obj_acl_tuple = NULL; 637 const cfg_obj_t *obj_port = NULL, *obj_transport = NULL; 638 bool is_tuple = false; 639 640 if (nest_level != 0) { 641 new_nest_level = nest_level - 1; 642 } 643 644 REQUIRE(ctx != NULL); 645 REQUIRE(target != NULL); 646 REQUIRE(*target == NULL || DNS_ACL_VALID(*target)); 647 648 REQUIRE(acl_data != NULL); 649 if (cfg_obj_islist(acl_data)) { 650 caml = acl_data; 651 } else { 652 INSIST(cfg_obj_istuple(acl_data)); 653 caml = cfg_tuple_get(acl_data, "aml"); 654 INSIST(caml != NULL); 655 obj_acl_tuple = cfg_tuple_get(acl_data, "port-transport"); 656 INSIST(obj_acl_tuple != NULL); 657 obj_port = cfg_tuple_get(obj_acl_tuple, "port"); 658 obj_transport = cfg_tuple_get(obj_acl_tuple, "transport"); 659 is_tuple = true; 660 } 661 662 if (*target != NULL) { 663 /* 664 * If target already points to an ACL, then we're being 665 * called recursively to configure a nested ACL. The 666 * nested ACL's contents should just be absorbed into its 667 * parent ACL. 668 */ 669 dns_acl_attach(*target, &dacl); 670 dns_acl_detach(target); 671 } else { 672 /* 673 * Need to allocate a new ACL structure. Count the items 674 * in the ACL definition that will require space in the 675 * elements table. (Note that if nest_level is nonzero, 676 * *everything* goes in the elements table.) 677 */ 678 uint32_t nelem; 679 680 if (nest_level == 0) { 681 result = count_acl_elements(caml, cctx, lctx, ctx, mctx, 682 &nelem, NULL); 683 if (result != ISC_R_SUCCESS) { 684 return result; 685 } 686 } else { 687 nelem = cfg_list_length(caml, false); 688 } 689 690 dns_acl_create(mctx, nelem, &dacl); 691 } 692 693 if (is_tuple) { 694 uint16_t port = 0; 695 uint32_t transports = 0; 696 bool encrypted = false; 697 698 if (obj_port != NULL && cfg_obj_isuint32(obj_port)) { 699 port = (uint16_t)cfg_obj_asuint32(obj_port); 700 } 701 702 if (obj_transport != NULL && cfg_obj_isstring(obj_transport)) { 703 if (strcasecmp(cfg_obj_asstring(obj_transport), 704 "udp") == 0) 705 { 706 transports = isc_nm_udpsocket | 707 isc_nm_proxyudpsocket; 708 encrypted = false; 709 } else if (strcasecmp(cfg_obj_asstring(obj_transport), 710 "tcp") == 0) 711 { 712 transports = isc_nm_streamdnssocket; 713 encrypted = false; 714 } else if (strcasecmp(cfg_obj_asstring(obj_transport), 715 "udp-tcp") == 0) 716 { 717 /* Good ol' DNS over port 53 */ 718 transports = isc_nm_streamdnssocket | 719 isc_nm_udpsocket | 720 isc_nm_proxyudpsocket; 721 encrypted = false; 722 } else if (strcasecmp(cfg_obj_asstring(obj_transport), 723 "tls") == 0) 724 { 725 transports = isc_nm_streamdnssocket; 726 encrypted = true; 727 } else if (strcasecmp(cfg_obj_asstring(obj_transport), 728 "http") == 0) 729 { 730 transports = isc_nm_httpsocket; 731 encrypted = true; 732 } else if (strcasecmp(cfg_obj_asstring(obj_transport), 733 "http-plain") == 0) 734 { 735 transports = isc_nm_httpsocket; 736 encrypted = false; 737 } else { 738 result = ISC_R_FAILURE; 739 goto cleanup; 740 } 741 } 742 743 if (port != 0 || transports != 0) { 744 dns_acl_add_port_transports(dacl, port, transports, 745 encrypted, false); 746 } 747 } 748 749 de = dacl->elements; 750 for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) 751 { 752 const cfg_obj_t *ce = cfg_listelt_value(elt); 753 bool neg = false; 754 755 INSIST(dacl->length <= dacl->alloc); 756 757 if (cfg_obj_istuple(ce)) { 758 /* Might be a negated element */ 759 const cfg_obj_t *negated = cfg_tuple_get(ce, "negated"); 760 if (!cfg_obj_isvoid(negated)) { 761 neg = true; 762 dacl->has_negatives = true; 763 ce = negated; 764 } 765 } 766 767 /* 768 * If nest_level is nonzero, then every element is 769 * to be stored as a separate, nested ACL rather than 770 * merged into the main iptable. 771 */ 772 iptab = dacl->iptable; 773 774 if (nest_level != 0) { 775 dns_acl_create(mctx, cfg_list_length(ce, false), 776 &de->nestedacl); 777 iptab = de->nestedacl->iptable; 778 } 779 780 if (cfg_obj_isnetprefix(ce)) { 781 /* Network prefix */ 782 isc_netaddr_t addr; 783 unsigned int bitlen; 784 785 cfg_obj_asnetprefix(ce, &addr, &bitlen); 786 result = isc_netaddr_prefixok(&addr, bitlen); 787 if (result != ISC_R_SUCCESS) { 788 char buf[ISC_NETADDR_FORMATSIZE + 1]; 789 isc_netaddr_format(&addr, buf, sizeof(buf)); 790 cfg_obj_log(ce, lctx, ISC_LOG_ERROR, 791 "'%s/%u': address/prefix length " 792 "mismatch", 793 buf, bitlen); 794 goto cleanup; 795 } 796 797 /* 798 * If nesting ACLs (nest_level != 0), we negate 799 * the nestedacl element, not the iptable entry. 800 */ 801 setpos = (nest_level != 0 || !neg); 802 result = dns_iptable_addprefix(iptab, &addr, bitlen, 803 setpos); 804 if (result != ISC_R_SUCCESS) { 805 goto cleanup; 806 } 807 808 if (nest_level > 0) { 809 INSIST(dacl->length < dacl->alloc); 810 de->type = dns_aclelementtype_nestedacl; 811 de->negative = neg; 812 } else { 813 continue; 814 } 815 } else if (cfg_obj_islist(ce)) { 816 /* 817 * If we're nesting ACLs, put the nested 818 * ACL onto the elements list; otherwise 819 * merge it into *this* ACL. We nest ACLs 820 * in two cases: 1) sortlist, 2) if the 821 * nested ACL contains negated members. 822 */ 823 if (inneracl != NULL) { 824 dns_acl_detach(&inneracl); 825 } 826 result = cfg_acl_fromconfig(ce, cctx, lctx, ctx, mctx, 827 new_nest_level, &inneracl); 828 if (result != ISC_R_SUCCESS) { 829 goto cleanup; 830 } 831 nested_acl: 832 if (nest_level > 0 || inneracl->has_negatives) { 833 INSIST(dacl->length < dacl->alloc); 834 de->type = dns_aclelementtype_nestedacl; 835 de->negative = neg; 836 if (de->nestedacl != NULL) { 837 dns_acl_detach(&de->nestedacl); 838 } 839 /* 840 * Merge the port-transports entries from the 841 * nested ACL into its parent. 842 */ 843 dns_acl_merge_ports_transports(dacl, inneracl, 844 !neg); 845 dns_acl_attach(inneracl, &de->nestedacl); 846 dns_acl_detach(&inneracl); 847 /* Fall through. */ 848 } else { 849 INSIST(dacl->length + inneracl->length <= 850 dacl->alloc); 851 dns_acl_merge(dacl, inneracl, !neg); 852 de += inneracl->length; /* elements added */ 853 dns_acl_detach(&inneracl); 854 INSIST(dacl->length <= dacl->alloc); 855 continue; 856 } 857 } else if (cfg_obj_istype(ce, &cfg_type_keyref)) { 858 /* Key name. */ 859 INSIST(dacl->length < dacl->alloc); 860 de->type = dns_aclelementtype_keyname; 861 de->negative = neg; 862 dns_name_init(&de->keyname, NULL); 863 result = convert_keyname(ce, lctx, mctx, &de->keyname); 864 if (result != ISC_R_SUCCESS) { 865 goto cleanup; 866 } 867 #if defined(HAVE_GEOIP2) 868 } else if (cfg_obj_istuple(ce) && 869 cfg_obj_isvoid(cfg_tuple_get(ce, "negated"))) 870 { 871 INSIST(dacl->length < dacl->alloc); 872 result = parse_geoip_element(ce, lctx, ctx, de); 873 if (result != ISC_R_SUCCESS) { 874 goto cleanup; 875 } 876 de->type = dns_aclelementtype_geoip; 877 de->negative = neg; 878 #endif /* HAVE_GEOIP2 */ 879 } else if (cfg_obj_isstring(ce)) { 880 /* ACL name. */ 881 const char *name = cfg_obj_asstring(ce); 882 if (strcasecmp(name, "any") == 0) { 883 /* Iptable entry with zero bit length. */ 884 setpos = (nest_level != 0 || !neg); 885 result = dns_iptable_addprefix(iptab, NULL, 0, 886 setpos); 887 if (result != ISC_R_SUCCESS) { 888 goto cleanup; 889 } 890 891 if (nest_level != 0) { 892 INSIST(dacl->length < dacl->alloc); 893 de->type = dns_aclelementtype_nestedacl; 894 de->negative = neg; 895 } else { 896 continue; 897 } 898 } else if (strcasecmp(name, "none") == 0) { 899 /* none == !any */ 900 /* 901 * We don't unconditional set 902 * dacl->has_negatives and 903 * de->negative to true so we can handle 904 * "!none;". 905 */ 906 setpos = (nest_level != 0 || neg); 907 result = dns_iptable_addprefix(iptab, NULL, 0, 908 setpos); 909 if (result != ISC_R_SUCCESS) { 910 goto cleanup; 911 } 912 913 if (!neg) { 914 dacl->has_negatives = !neg; 915 } 916 917 if (nest_level != 0) { 918 INSIST(dacl->length < dacl->alloc); 919 de->type = dns_aclelementtype_nestedacl; 920 de->negative = !neg; 921 } else { 922 continue; 923 } 924 } else if (strcasecmp(name, "localhost") == 0) { 925 INSIST(dacl->length < dacl->alloc); 926 de->type = dns_aclelementtype_localhost; 927 de->negative = neg; 928 } else if (strcasecmp(name, "localnets") == 0) { 929 INSIST(dacl->length < dacl->alloc); 930 de->type = dns_aclelementtype_localnets; 931 de->negative = neg; 932 } else { 933 if (inneracl != NULL) { 934 dns_acl_detach(&inneracl); 935 } 936 /* 937 * This call should just find the cached 938 * of the named acl. 939 */ 940 result = convert_named_acl(ce, cctx, lctx, ctx, 941 mctx, new_nest_level, 942 &inneracl); 943 if (result != ISC_R_SUCCESS) { 944 goto cleanup; 945 } 946 947 goto nested_acl; 948 } 949 } else { 950 cfg_obj_log(ce, lctx, ISC_LOG_WARNING, 951 "address match list contains " 952 "unsupported element type"); 953 result = ISC_R_FAILURE; 954 goto cleanup; 955 } 956 957 /* 958 * This should only be reached for localhost, localnets 959 * and keyname elements, and nested ACLs if nest_level is 960 * nonzero (i.e., in sortlists). 961 */ 962 if (de->nestedacl != NULL && 963 de->type != dns_aclelementtype_nestedacl) 964 { 965 dns_acl_detach(&de->nestedacl); 966 } 967 968 dns_acl_node_count(dacl)++; 969 de->node_num = dns_acl_node_count(dacl); 970 971 dacl->length++; 972 de++; 973 INSIST(dacl->length <= dacl->alloc); 974 } 975 976 dns_acl_attach(dacl, target); 977 result = ISC_R_SUCCESS; 978 979 cleanup: 980 if (inneracl != NULL) { 981 dns_acl_detach(&inneracl); 982 } 983 dns_acl_detach(&dacl); 984 return result; 985 } 986