xref: /minix/external/bsd/bind/dist/lib/isccfg/aclconf.c (revision bb9622b5)
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