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