Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / isccfg / aclconf.c
blob9459ea16100e7840d309b073a9bf727fecff22a2
1 /* $NetBSD: aclconf.c,v 1.8 2014/12/10 04:38:02 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2002 Internet Software Consortium.
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.
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.
20 /* Id */
22 #include <config.h>
24 #include <isc/mem.h>
25 #include <isc/string.h> /* Required for HP/UX (and others?) */
26 #include <isc/util.h>
28 #include <isccfg/namedconf.h>
29 #include <isccfg/aclconf.h>
31 #include <dns/acl.h>
32 #include <dns/iptable.h>
33 #include <dns/fixedname.h>
34 #include <dns/log.h>
36 #ifdef HAVE_GEOIP
37 #include <stdlib.h>
38 #include <math.h>
39 #endif /* HAVE_GEOIP */
41 #define LOOP_MAGIC ISC_MAGIC('L','O','O','P')
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;
48 REQUIRE(mctx != NULL);
49 REQUIRE(ret != NULL && *ret == NULL);
51 actx = isc_mem_get(mctx, sizeof(*actx));
52 if (actx == NULL)
53 return (ISC_R_NOMEMORY);
55 result = isc_refcount_init(&actx->references, 1);
56 if (result != ISC_R_SUCCESS)
57 goto cleanup;
59 actx->mctx = NULL;
60 isc_mem_attach(mctx, &actx->mctx);
61 ISC_LIST_INIT(actx->named_acl_cache);
63 #ifdef HAVE_GEOIP
64 actx->geoip = NULL;
65 #endif
67 *ret = actx;
68 return (ISC_R_SUCCESS);
70 cleanup:
71 isc_mem_put(mctx, actx, sizeof(*actx));
72 return (result);
75 void
76 cfg_aclconfctx_attach(cfg_aclconfctx_t *src, cfg_aclconfctx_t **dest) {
77 REQUIRE(src != NULL);
78 REQUIRE(dest != NULL && *dest == NULL);
80 isc_refcount_increment(&src->references, NULL);
81 *dest = src;
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;
90 REQUIRE(actxp != NULL && *actxp != NULL);
92 actx = *actxp;
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)
100 next = ISC_LIST_NEXT(dacl, nextincache);
101 ISC_LIST_UNLINK(actx->named_acl_cache, dacl,
102 nextincache);
103 dns_acl_detach(&dacl);
105 isc_mem_putanddetach(&actx->mctx, actx, sizeof(*actx));
108 *actxp = NULL;
112 * Find the definition of the named acl whose name is "name".
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;
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");
132 return (ISC_R_SUCCESS);
135 return (ISC_R_NOTFOUND);
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)
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);
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))
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);
161 dns_acl_attach(dacl, target);
162 return (ISC_R_SUCCESS);
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);
173 * Add a loop detection element.
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);
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)
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);
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);
217 return (dns_name_dup(dns_fixedname_name(&fixname), mctx, dnsname));
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.
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)
232 const cfg_listelt_t *elt;
233 isc_result_t result;
234 isc_uint32_t n = 0;
236 REQUIRE(count != NULL);
238 if (has_negative != NULL)
239 *has_negative = ISC_FALSE;
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);
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;
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")))
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;
284 * Convert any named acls we reference now if
285 * they have not already been converted.
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);
301 *count = n;
302 return (ISC_R_SUCCESS);
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)
310 if (dbname == NULL)
311 return (subtype);
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);
363 * Log a warning if the wrong database was specified
364 * on an unambiguous query
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);
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);
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);
475 return (ISC_FALSE);
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)
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;
489 REQUIRE(dep != NULL);
491 de = *dep;
493 ge = cfg_tuple_get(obj, "db");
494 if (!cfg_obj_isvoid(ge))
495 dbname = cfg_obj_asstring(ge);
497 stype = cfg_obj_asstring(cfg_tuple_get(obj, "subtype"));
498 search = cfg_obj_asstring(cfg_tuple_get(obj, "search"));
499 len = strlen(search);
501 if (len == 0) {
502 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
503 "zero-length geoip search field");
504 return (ISC_R_FAILURE);
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);
586 de.geoip_elem.subtype = get_subtype(obj, lctx, subtype, dbname);
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);
595 *dep = de;
597 return (ISC_R_SUCCESS);
599 #endif
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)
607 return (cfg_acl_fromconfig2(caml, cctx, lctx, ctx, mctx,
608 nest_level, 0, target));
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)
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;
624 if (nest_level != 0)
625 new_nest_level = nest_level - 1;
627 REQUIRE(target != NULL);
628 REQUIRE(*target == NULL || DNS_ACL_VALID(*target));
630 if (*target != NULL) {
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.
637 dns_acl_attach(*target, &dacl);
638 dns_acl_detach(target);
639 } else {
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.)
646 isc_uint32_t nelem;
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);
656 result = dns_acl_create(mctx, nelem, &dacl);
657 if (result != ISC_R_SUCCESS)
658 return (result);
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;
668 INSIST(dacl->length <= dacl->alloc);
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;
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.
686 iptab = dacl->iptable;
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;
697 if (cfg_obj_isnetprefix(ce)) {
698 /* Network prefix */
699 isc_netaddr_t addr;
700 unsigned int bitlen;
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;
715 * If nesting ACLs (nest_level != 0), we negate
716 * the nestedacl element, not the iptable entry.
718 result = dns_iptable_addprefix(iptab, &addr, bitlen,
719 ISC_TF(nest_level != 0 || !neg));
720 if (result != ISC_R_SUCCESS)
721 goto cleanup;
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)) {
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.
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;
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")))
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;
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 */
805 * We don't unconditional set
806 * dacl->has_negatives and
807 * de->negative to true so we can handle
808 * "!none;".
810 result = dns_iptable_addprefix(iptab, NULL, 0,
811 ISC_TF(nest_level != 0 || neg));
812 if (result != ISC_R_SUCCESS)
813 goto cleanup;
815 if (!neg)
816 dacl->has_negatives = !neg;
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);
836 * This call should just find the cached
837 * of the named acl.
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;
845 goto nested_acl;
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;
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).
860 if (de->nestedacl != NULL &&
861 de->type != dns_aclelementtype_nestedacl)
862 dns_acl_detach(&de->nestedacl);
864 dacl->node_count++;
865 de->node_num = dacl->node_count;
867 dacl->length++;
868 de++;
869 INSIST(dacl->length <= dacl->alloc);
872 dns_acl_attach(dacl, target);
873 result = ISC_R_SUCCESS;
875 cleanup:
876 if (inneracl != NULL)
877 dns_acl_detach(&inneracl);
878 dns_acl_detach(&dacl);
879 return (result);