Home | History | Annotate | Line # | Download | only in isccfg
aclconf.c revision 1.1.2.2
      1 /*	$NetBSD: aclconf.c,v 1.1.2.2 2024/02/24 13:07:32 martin 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