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