"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/isccfg/aclconf.c" (4 Sep 2020, 25511 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "aclconf.c" see the Fossies "Dox" file reference documentation.

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