aclconf.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2002  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 #include <config.h>
00021 
00022 #include <isc/mem.h>
00023 #include <isc/string.h>         /* Required for HP/UX (and others?) */
00024 #include <isc/util.h>
00025 
00026 #include <isccfg/namedconf.h>
00027 #include <isccfg/aclconf.h>
00028 
00029 #include <dns/acl.h>
00030 #include <dns/iptable.h>
00031 #include <dns/fixedname.h>
00032 #include <dns/log.h>
00033 
00034 #ifdef HAVE_GEOIP
00035 #include <stdlib.h>
00036 #include <math.h>
00037 #endif /* HAVE_GEOIP */
00038 
00039 #define LOOP_MAGIC ISC_MAGIC('L','O','O','P')
00040 
00041 isc_result_t
00042 cfg_aclconfctx_create(isc_mem_t *mctx, cfg_aclconfctx_t **ret) {
00043         isc_result_t result;
00044         cfg_aclconfctx_t *actx;
00045 
00046         REQUIRE(mctx != NULL);
00047         REQUIRE(ret != NULL && *ret == NULL);
00048 
00049         actx = isc_mem_get(mctx, sizeof(*actx));
00050         if (actx == NULL)
00051                 return (ISC_R_NOMEMORY);
00052 
00053         result = isc_refcount_init(&actx->references, 1);
00054         if (result != ISC_R_SUCCESS)
00055                 goto cleanup;
00056 
00057         actx->mctx = NULL;
00058         isc_mem_attach(mctx, &actx->mctx);
00059         ISC_LIST_INIT(actx->named_acl_cache);
00060 
00061 #ifdef HAVE_GEOIP
00062         actx->geoip = NULL;
00063 #endif
00064 
00065         *ret = actx;
00066         return (ISC_R_SUCCESS);
00067 
00068  cleanup:
00069         isc_mem_put(mctx, actx, sizeof(*actx));
00070         return (result);
00071 }
00072 
00073 void
00074 cfg_aclconfctx_attach(cfg_aclconfctx_t *src, cfg_aclconfctx_t **dest) {
00075         REQUIRE(src != NULL);
00076         REQUIRE(dest != NULL && *dest == NULL);
00077 
00078         isc_refcount_increment(&src->references, NULL);
00079         *dest = src;
00080 }
00081 
00082 void
00083 cfg_aclconfctx_detach(cfg_aclconfctx_t **actxp) {
00084         cfg_aclconfctx_t *actx;
00085         dns_acl_t *dacl, *next;
00086         unsigned int refs;
00087 
00088         REQUIRE(actxp != NULL && *actxp != NULL);
00089 
00090         actx = *actxp;
00091 
00092         isc_refcount_decrement(&actx->references, &refs);
00093         if (refs == 0) {
00094                 for (dacl = ISC_LIST_HEAD(actx->named_acl_cache);
00095                      dacl != NULL;
00096                      dacl = next)
00097                 {
00098                         next = ISC_LIST_NEXT(dacl, nextincache);
00099                         ISC_LIST_UNLINK(actx->named_acl_cache, dacl,
00100                                         nextincache);
00101                         dns_acl_detach(&dacl);
00102                 }
00103                 isc_mem_putanddetach(&actx->mctx, actx, sizeof(*actx));
00104         }
00105 
00106         *actxp = NULL;
00107 }
00108 
00109 /*
00110  * Find the definition of the named acl whose name is "name".
00111  */
00112 static isc_result_t
00113 get_acl_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
00114         isc_result_t result;
00115         const cfg_obj_t *acls = NULL;
00116         const cfg_listelt_t *elt;
00117 
00118         result = cfg_map_get(cctx, "acl", &acls);
00119         if (result != ISC_R_SUCCESS)
00120                 return (result);
00121         for (elt = cfg_list_first(acls);
00122              elt != NULL;
00123              elt = cfg_list_next(elt)) {
00124                 const cfg_obj_t *acl = cfg_listelt_value(elt);
00125                 const char *aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
00126                 if (strcasecmp(aclname, name) == 0) {
00127                         if (ret != NULL) {
00128                                 *ret = cfg_tuple_get(acl, "value");
00129                         }
00130                         return (ISC_R_SUCCESS);
00131                 }
00132         }
00133         return (ISC_R_NOTFOUND);
00134 }
00135 
00136 static isc_result_t
00137 convert_named_acl(const cfg_obj_t *nameobj, const cfg_obj_t *cctx,
00138                   isc_log_t *lctx, cfg_aclconfctx_t *ctx,
00139                   isc_mem_t *mctx, unsigned int nest_level,
00140                   dns_acl_t **target)
00141 {
00142         isc_result_t result;
00143         const cfg_obj_t *cacl = NULL;
00144         dns_acl_t *dacl;
00145         dns_acl_t loop;
00146         const char *aclname = cfg_obj_asstring(nameobj);
00147 
00148         /* Look for an already-converted version. */
00149         for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache);
00150              dacl != NULL;
00151              dacl = ISC_LIST_NEXT(dacl, nextincache))
00152         {
00153                 if (strcasecmp(aclname, dacl->name) == 0) {
00154                         if (ISC_MAGIC_VALID(dacl, LOOP_MAGIC)) {
00155                                 cfg_obj_log(nameobj, lctx, ISC_LOG_ERROR,
00156                                             "acl loop detected: %s", aclname);
00157                                 return (ISC_R_FAILURE);
00158                         }
00159                         dns_acl_attach(dacl, target);
00160                         return (ISC_R_SUCCESS);
00161                 }
00162         }
00163         /* Not yet converted.  Convert now. */
00164         result = get_acl_def(cctx, aclname, &cacl);
00165         if (result != ISC_R_SUCCESS) {
00166                 cfg_obj_log(nameobj, lctx, ISC_LOG_WARNING,
00167                             "undefined ACL '%s'", aclname);
00168                 return (result);
00169         }
00170         /*
00171          * Add a loop detection element.
00172          */
00173         memset(&loop, 0, sizeof(loop));
00174         ISC_LINK_INIT(&loop, nextincache);
00175         DE_CONST(aclname, loop.name);
00176         loop.magic = LOOP_MAGIC;
00177         ISC_LIST_APPEND(ctx->named_acl_cache, &loop, nextincache);
00178         result = cfg_acl_fromconfig(cacl, cctx, lctx, ctx, mctx,
00179                                     nest_level, &dacl);
00180         ISC_LIST_UNLINK(ctx->named_acl_cache, &loop, nextincache);
00181         loop.magic = 0;
00182         loop.name = NULL;
00183         if (result != ISC_R_SUCCESS)
00184                 return (result);
00185         dacl->name = isc_mem_strdup(dacl->mctx, aclname);
00186         if (dacl->name == NULL)
00187                 return (ISC_R_NOMEMORY);
00188         ISC_LIST_APPEND(ctx->named_acl_cache, dacl, nextincache);
00189         dns_acl_attach(dacl, target);
00190         return (ISC_R_SUCCESS);
00191 }
00192 
00193 static isc_result_t
00194 convert_keyname(const cfg_obj_t *keyobj, isc_log_t *lctx, isc_mem_t *mctx,
00195                 dns_name_t *dnsname)
00196 {
00197         isc_result_t result;
00198         isc_buffer_t buf;
00199         dns_fixedname_t fixname;
00200         unsigned int keylen;
00201         const char *txtname = cfg_obj_asstring(keyobj);
00202 
00203         keylen = strlen(txtname);
00204         isc_buffer_constinit(&buf, txtname, keylen);
00205         isc_buffer_add(&buf, keylen);
00206         dns_fixedname_init(&fixname);
00207         result = dns_name_fromtext(dns_fixedname_name(&fixname), &buf,
00208                                    dns_rootname, 0, NULL);
00209         if (result != ISC_R_SUCCESS) {
00210                 cfg_obj_log(keyobj, lctx, ISC_LOG_WARNING,
00211                             "key name '%s' is not a valid domain name",
00212                             txtname);
00213                 return (result);
00214         }
00215         return (dns_name_dup(dns_fixedname_name(&fixname), mctx, dnsname));
00216 }
00217 
00218 /*
00219  * Recursively pre-parse an ACL definition to find the total number
00220  * of non-IP-prefix elements (localhost, localnets, key) in all nested
00221  * ACLs, so that the parent will have enough space allocated for the
00222  * elements table after all the nested ACLs have been merged in to the
00223  * parent.
00224  */
00225 static isc_result_t
00226 count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx,
00227                    isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx,
00228                    isc_uint32_t *count, isc_boolean_t *has_negative)
00229 {
00230         const cfg_listelt_t *elt;
00231         isc_result_t result;
00232         isc_uint32_t n = 0;
00233 
00234         REQUIRE(count != NULL);
00235 
00236         if (has_negative != NULL)
00237                 *has_negative = ISC_FALSE;
00238 
00239         for (elt = cfg_list_first(caml);
00240              elt != NULL;
00241              elt = cfg_list_next(elt)) {
00242                 const cfg_obj_t *ce = cfg_listelt_value(elt);
00243 
00244                 /* might be a negated element, in which case get the value. */
00245                 if (cfg_obj_istuple(ce)) {
00246                         const cfg_obj_t *negated =
00247                                 cfg_tuple_get(ce, "negated");
00248                         if (! cfg_obj_isvoid(negated)) {
00249                                 ce = negated;
00250                                 if (has_negative != NULL)
00251                                         *has_negative = ISC_TRUE;
00252                         }
00253                 }
00254 
00255                 if (cfg_obj_istype(ce, &cfg_type_keyref)) {
00256                         n++;
00257                 } else if (cfg_obj_islist(ce)) {
00258                         isc_boolean_t negative;
00259                         isc_uint32_t sub;
00260                         result = count_acl_elements(ce, cctx, lctx, ctx, mctx,
00261                                                     &sub, &negative);
00262                         if (result != ISC_R_SUCCESS)
00263                                 return (result);
00264                         n += sub;
00265                         if (negative)
00266                                 n++;
00267 #ifdef HAVE_GEOIP
00268                 } else if (cfg_obj_istuple(ce) &&
00269                            cfg_obj_isvoid(cfg_tuple_get(ce, "negated")))
00270                 {
00271                         n++;
00272 #endif /* HAVE_GEOIP */
00273                 } else if (cfg_obj_isstring(ce)) {
00274                         const char *name = cfg_obj_asstring(ce);
00275                         if (strcasecmp(name, "localhost") == 0 ||
00276                             strcasecmp(name, "localnets") == 0) {
00277                                 n++;
00278                         } else if (strcasecmp(name, "any") != 0 &&
00279                                    strcasecmp(name, "none") != 0) {
00280                                 dns_acl_t *inneracl = NULL;
00281                                 /*
00282                                  * Convert any named acls we reference now if
00283                                  * they have not already been converted.
00284                                  */
00285                                 result = convert_named_acl(ce, cctx, lctx, ctx,
00286                                                            mctx, 0, &inneracl);
00287                                 if (result == ISC_R_SUCCESS) {
00288                                         if (inneracl->has_negatives)
00289                                                 n++;
00290                                         else
00291                                                 n += inneracl->length;
00292                                         dns_acl_detach(&inneracl);
00293                                 } else
00294                                         return (result);
00295                         }
00296                 }
00297         }
00298 
00299         *count = n;
00300         return (ISC_R_SUCCESS);
00301 }
00302 
00303 #ifdef HAVE_GEOIP
00304 static dns_geoip_subtype_t
00305 get_subtype(const cfg_obj_t *obj, isc_log_t *lctx,
00306             dns_geoip_subtype_t subtype, const char *dbname)
00307 {
00308         if (dbname == NULL)
00309                 return (subtype);
00310 
00311         switch (subtype) {
00312         case dns_geoip_countrycode:
00313                 if (strcasecmp(dbname, "city") == 0)
00314                         return (dns_geoip_city_countrycode);
00315                 else if (strcasecmp(dbname, "region") == 0)
00316                         return (dns_geoip_region_countrycode);
00317                 else if (strcasecmp(dbname, "country") == 0)
00318                         return (dns_geoip_country_code);
00319                 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
00320                             "invalid GeoIP DB specified for "
00321                             "country search: ignored");
00322                 return (subtype);
00323         case dns_geoip_countrycode3:
00324                 if (strcasecmp(dbname, "city") == 0)
00325                         return (dns_geoip_city_countrycode3);
00326                 else if (strcasecmp(dbname, "country") == 0)
00327                         return (dns_geoip_country_code3);
00328                 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
00329                             "invalid GeoIP DB specified for "
00330                             "country search: ignored");
00331                 return (subtype);
00332         case dns_geoip_countryname:
00333                 if (strcasecmp(dbname, "city") == 0)
00334                         return (dns_geoip_city_countryname);
00335                 else if (strcasecmp(dbname, "country") == 0)
00336                         return (dns_geoip_country_name);
00337                 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
00338                             "invalid GeoIP DB specified for "
00339                             "country search: ignored");
00340                 return (subtype);
00341         case dns_geoip_region:
00342                 if (strcasecmp(dbname, "city") == 0)
00343                         return (dns_geoip_city_region);
00344                 else if (strcasecmp(dbname, "region") == 0)
00345                         return (dns_geoip_region_code);
00346                 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
00347                             "invalid GeoIP DB specified for "
00348                             "region search: ignored");
00349                 return (subtype);
00350         case dns_geoip_regionname:
00351                 if (strcasecmp(dbname, "city") == 0)
00352                         return (dns_geoip_city_region);
00353                 else if (strcasecmp(dbname, "region") == 0)
00354                         return (dns_geoip_region_name);
00355                 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
00356                             "invalid GeoIP DB specified for "
00357                             "region search: ignored");
00358                 return (subtype);
00359 
00360         /*
00361          * Log a warning if the wrong database was specified
00362          * on an unambiguous query
00363          */
00364         case dns_geoip_city_name:
00365         case dns_geoip_city_postalcode:
00366         case dns_geoip_city_metrocode:
00367         case dns_geoip_city_areacode:
00368         case dns_geoip_city_continentcode:
00369         case dns_geoip_city_timezonecode:
00370                 if (strcasecmp(dbname, "city") != 0)
00371                         cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
00372                                     "invalid GeoIP DB specified for "
00373                                     "a 'city'-only search type: ignoring");
00374                 return (subtype);
00375         case dns_geoip_isp_name:
00376                 if (strcasecmp(dbname, "isp") != 0)
00377                         cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
00378                                     "invalid GeoIP DB specified for "
00379                                     "an 'isp' search: ignoring");
00380                 return (subtype);
00381         case dns_geoip_org_name:
00382                 if (strcasecmp(dbname, "org") != 0)
00383                         cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
00384                                     "invalid GeoIP DB specified for "
00385                                     "an 'org' search: ignoring");
00386                 return (subtype);
00387         case dns_geoip_as_asnum:
00388                 if (strcasecmp(dbname, "asnum") != 0)
00389                         cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
00390                                     "invalid GeoIP DB specified for "
00391                                     "an 'asnum' search: ignoring");
00392                 return (subtype);
00393         case dns_geoip_domain_name:
00394                 if (strcasecmp(dbname, "domain") != 0)
00395                         cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
00396                                     "invalid GeoIP DB specified for "
00397                                     "a 'domain' search: ignoring");
00398                 return (subtype);
00399         case dns_geoip_netspeed_id:
00400                 if (strcasecmp(dbname, "netspeed") != 0)
00401                         cfg_obj_log(obj, lctx, ISC_LOG_WARNING,
00402                                     "invalid GeoIP DB specified for "
00403                                     "a 'netspeed' search: ignoring");
00404                 return (subtype);
00405         default:
00406                 INSIST(0);
00407         }
00408 }
00409 
00410 static isc_boolean_t
00411 geoip_can_answer(dns_aclelement_t *elt, cfg_aclconfctx_t *ctx) {
00412         if (ctx->geoip == NULL)
00413                 return (ISC_TRUE);
00414 
00415         switch (elt->geoip_elem.subtype) {
00416         case dns_geoip_countrycode:
00417         case dns_geoip_countrycode3:
00418         case dns_geoip_countryname:
00419                 if (ctx->geoip->city_v4 != NULL ||
00420                     ctx->geoip->city_v6 != NULL ||
00421                     ctx->geoip->country_v4 != NULL ||
00422                     ctx->geoip->country_v6 != NULL ||
00423                     ctx->geoip->region != NULL)
00424                         return (ISC_TRUE);
00425         case dns_geoip_region:
00426         case dns_geoip_regionname:
00427                 if (ctx->geoip->city_v4 != NULL ||
00428                     ctx->geoip->city_v6 != NULL ||
00429                     ctx->geoip->region != NULL)
00430                         return (ISC_TRUE);
00431         case dns_geoip_country_code:
00432         case dns_geoip_country_code3:
00433         case dns_geoip_country_name:
00434                 if (ctx->geoip->country_v4 != NULL ||
00435                     ctx->geoip->country_v6 != NULL)
00436                         return (ISC_TRUE);
00437         case dns_geoip_region_countrycode:
00438         case dns_geoip_region_code:
00439         case dns_geoip_region_name:
00440                 if (ctx->geoip->region != NULL)
00441                         return (ISC_TRUE);
00442         case dns_geoip_city_countrycode:
00443         case dns_geoip_city_countrycode3:
00444         case dns_geoip_city_countryname:
00445         case dns_geoip_city_region:
00446         case dns_geoip_city_regionname:
00447         case dns_geoip_city_name:
00448         case dns_geoip_city_postalcode:
00449         case dns_geoip_city_metrocode:
00450         case dns_geoip_city_areacode:
00451         case dns_geoip_city_continentcode:
00452         case dns_geoip_city_timezonecode:
00453                 if (ctx->geoip->city_v4 != NULL ||
00454                     ctx->geoip->city_v6 != NULL)
00455                         return (ISC_TRUE);
00456         case dns_geoip_isp_name:
00457                 if (ctx->geoip->isp != NULL)
00458                         return (ISC_TRUE);
00459         case dns_geoip_org_name:
00460                 if (ctx->geoip->org != NULL)
00461                         return (ISC_TRUE);
00462         case dns_geoip_as_asnum:
00463                 if (ctx->geoip->as != NULL)
00464                         return (ISC_TRUE);
00465         case dns_geoip_domain_name:
00466                 if (ctx->geoip->domain != NULL)
00467                         return (ISC_TRUE);
00468         case dns_geoip_netspeed_id:
00469                 if (ctx->geoip->netspeed != NULL)
00470                         return (ISC_TRUE);
00471         }
00472 
00473         return (ISC_FALSE);
00474 }
00475 
00476 static isc_result_t
00477 parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx,
00478                     cfg_aclconfctx_t *ctx, dns_aclelement_t *dep)
00479 {
00480         const cfg_obj_t *ge;
00481         const char *dbname = NULL;
00482         const char *stype, *search;
00483         dns_geoip_subtype_t subtype;
00484         dns_aclelement_t de;
00485         size_t len;
00486 
00487         REQUIRE(dep != NULL);
00488 
00489         de = *dep;
00490 
00491         ge = cfg_tuple_get(obj, "db");
00492         if (!cfg_obj_isvoid(ge))
00493                 dbname = cfg_obj_asstring(ge);
00494 
00495         stype = cfg_obj_asstring(cfg_tuple_get(obj, "subtype"));
00496         search = cfg_obj_asstring(cfg_tuple_get(obj, "search"));
00497         len = strlen(search);
00498 
00499         if (len == 0) {
00500                 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
00501                             "zero-length geoip search field");
00502                 return (ISC_R_FAILURE);
00503         }
00504 
00505         if (strcasecmp(stype, "country") == 0 && len == 2) {
00506                 /* Two-letter country code */
00507                 subtype = dns_geoip_countrycode;
00508                 strlcpy(de.geoip_elem.as_string, search,
00509                         sizeof(de.geoip_elem.as_string));
00510         } else if (strcasecmp(stype, "country") == 0 && len == 3) {
00511                 /* Three-letter country code */
00512                 subtype = dns_geoip_countrycode3;
00513                 strlcpy(de.geoip_elem.as_string, search,
00514                         sizeof(de.geoip_elem.as_string));
00515         } else if (strcasecmp(stype, "country") == 0) {
00516                 /* Country name */
00517                 subtype = dns_geoip_countryname;
00518                 strlcpy(de.geoip_elem.as_string, search,
00519                         sizeof(de.geoip_elem.as_string));
00520         } else if (strcasecmp(stype, "region") == 0 && len == 2) {
00521                 /* Two-letter region code */
00522                 subtype = dns_geoip_region;
00523                 strlcpy(de.geoip_elem.as_string, search,
00524                         sizeof(de.geoip_elem.as_string));
00525         } else if (strcasecmp(stype, "region") == 0) {
00526                 /* Region name */
00527                 subtype = dns_geoip_regionname;
00528                 strlcpy(de.geoip_elem.as_string, search,
00529                         sizeof(de.geoip_elem.as_string));
00530         } else if (strcasecmp(stype, "city") == 0) {
00531                 /* City name */
00532                 subtype = dns_geoip_city_name;
00533                 strlcpy(de.geoip_elem.as_string, search,
00534                         sizeof(de.geoip_elem.as_string));
00535         } else if (strcasecmp(stype, "postal") == 0 && len < 7) {
00536                 subtype = dns_geoip_city_postalcode;
00537                 strlcpy(de.geoip_elem.as_string, search,
00538                         sizeof(de.geoip_elem.as_string));
00539         } else if (strcasecmp(stype, "postal") == 0) {
00540                 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
00541                             "geoiop postal code (%s) too long", search);
00542                 return (ISC_R_FAILURE);
00543         } else if (strcasecmp(stype, "metro") == 0) {
00544                 subtype = dns_geoip_city_metrocode;
00545                 de.geoip_elem.as_int = atoi(search);
00546         } else if (strcasecmp(stype, "area") == 0) {
00547                 subtype = dns_geoip_city_areacode;
00548                 de.geoip_elem.as_int = atoi(search);
00549         } else if (strcasecmp(stype, "tz") == 0) {
00550                 subtype = dns_geoip_city_timezonecode;
00551                 strlcpy(de.geoip_elem.as_string, search,
00552                         sizeof(de.geoip_elem.as_string));
00553         } else if (strcasecmp(stype, "continent") == 0 && len == 2) {
00554                 /* Two-letter continent code */
00555                 subtype = dns_geoip_city_continentcode;
00556                 strlcpy(de.geoip_elem.as_string, search,
00557                         sizeof(de.geoip_elem.as_string));
00558         } else if (strcasecmp(stype, "continent") == 0) {
00559                 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
00560                             "geoiop continent code (%s) too long", search);
00561                 return (ISC_R_FAILURE);
00562         } else if (strcasecmp(stype, "isp") == 0) {
00563                 subtype = dns_geoip_isp_name;
00564                 strlcpy(de.geoip_elem.as_string, search,
00565                         sizeof(de.geoip_elem.as_string));
00566         } else if (strcasecmp(stype, "asnum") == 0) {
00567                 subtype = dns_geoip_as_asnum;
00568                 strlcpy(de.geoip_elem.as_string, search,
00569                         sizeof(de.geoip_elem.as_string));
00570         } else if (strcasecmp(stype, "org") == 0) {
00571                 subtype = dns_geoip_org_name;
00572                 strlcpy(de.geoip_elem.as_string, search,
00573                         sizeof(de.geoip_elem.as_string));
00574         } else if (strcasecmp(stype, "domain") == 0) {
00575                 subtype = dns_geoip_domain_name;
00576                 strlcpy(de.geoip_elem.as_string, search,
00577                         sizeof(de.geoip_elem.as_string));
00578         } else if (strcasecmp(stype, "netspeed") == 0) {
00579                 subtype = dns_geoip_netspeed_id;
00580                 de.geoip_elem.as_int = atoi(search);
00581         } else
00582                 INSIST(0);
00583 
00584         de.geoip_elem.subtype = get_subtype(obj, lctx, subtype, dbname);
00585 
00586         if (! geoip_can_answer(&de, ctx)) {
00587                 cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
00588                             "no GeoIP database installed which can answer "
00589                             "queries of type '%s'", stype);
00590                 return (ISC_R_FAILURE);
00591         }
00592 
00593         *dep = de;
00594 
00595         return (ISC_R_SUCCESS);
00596 }
00597 #endif
00598 
00599 isc_result_t
00600 cfg_acl_fromconfig(const cfg_obj_t *caml, const cfg_obj_t *cctx,
00601                    isc_log_t *lctx, cfg_aclconfctx_t *ctx,
00602                    isc_mem_t *mctx, unsigned int nest_level,
00603                    dns_acl_t **target)
00604 {
00605         return (cfg_acl_fromconfig2(caml, cctx, lctx, ctx, mctx,
00606                                     nest_level, 0, target));
00607 }
00608 
00609 isc_result_t
00610 cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx,
00611                    isc_log_t *lctx, cfg_aclconfctx_t *ctx,
00612                    isc_mem_t *mctx, unsigned int nest_level,
00613                    isc_uint16_t family, dns_acl_t **target)
00614 {
00615         isc_result_t result;
00616         dns_acl_t *dacl = NULL, *inneracl = NULL;
00617         dns_aclelement_t *de;
00618         const cfg_listelt_t *elt;
00619         dns_iptable_t *iptab;
00620         int new_nest_level = 0;
00621 
00622         if (nest_level != 0)
00623                 new_nest_level = nest_level - 1;
00624 
00625         REQUIRE(target != NULL);
00626         REQUIRE(*target == NULL || DNS_ACL_VALID(*target));
00627 
00628         if (*target != NULL) {
00629                 /*
00630                  * If target already points to an ACL, then we're being
00631                  * called recursively to configure a nested ACL.  The
00632                  * nested ACL's contents should just be absorbed into its
00633                  * parent ACL.
00634                  */
00635                 dns_acl_attach(*target, &dacl);
00636                 dns_acl_detach(target);
00637         } else {
00638                 /*
00639                  * Need to allocate a new ACL structure.  Count the items
00640                  * in the ACL definition that will require space in the
00641                  * elements table.  (Note that if nest_level is nonzero,
00642                  * *everything* goes in the elements table.)
00643                  */
00644                 isc_uint32_t nelem;
00645 
00646                 if (nest_level == 0) {
00647                         result = count_acl_elements(caml, cctx, lctx, ctx,
00648                                                     mctx, &nelem, NULL);
00649                         if (result != ISC_R_SUCCESS)
00650                                 return (result);
00651                 } else
00652                         nelem = cfg_list_length(caml, ISC_FALSE);
00653 
00654                 result = dns_acl_create(mctx, nelem, &dacl);
00655                 if (result != ISC_R_SUCCESS)
00656                         return (result);
00657         }
00658 
00659         de = dacl->elements;
00660         for (elt = cfg_list_first(caml);
00661              elt != NULL;
00662              elt = cfg_list_next(elt)) {
00663                 const cfg_obj_t *ce = cfg_listelt_value(elt);
00664                 isc_boolean_t neg = ISC_FALSE;
00665 
00666                 INSIST(dacl->length <= dacl->alloc);
00667 
00668                 if (cfg_obj_istuple(ce)) {
00669                         /* Might be a negated element */
00670                         const cfg_obj_t *negated =
00671                                 cfg_tuple_get(ce, "negated");
00672                         if (! cfg_obj_isvoid(negated)) {
00673                                 neg = ISC_TRUE;
00674                                 dacl->has_negatives = ISC_TRUE;
00675                                 ce = negated;
00676                         }
00677                 }
00678 
00679                 /*
00680                  * If nest_level is nonzero, then every element is
00681                  * to be stored as a separate, nested ACL rather than
00682                  * merged into the main iptable.
00683                  */
00684                 iptab = dacl->iptable;
00685 
00686                 if (nest_level != 0) {
00687                         result = dns_acl_create(mctx,
00688                                                 cfg_list_length(ce, ISC_FALSE),
00689                                                 &de->nestedacl);
00690                         if (result != ISC_R_SUCCESS)
00691                                 goto cleanup;
00692                         iptab = de->nestedacl->iptable;
00693                 }
00694 
00695                 if (cfg_obj_isnetprefix(ce)) {
00696                         /* Network prefix */
00697                         isc_netaddr_t   addr;
00698                         unsigned int    bitlen;
00699                         isc_boolean_t   setpos, setecs;
00700 
00701                         cfg_obj_asnetprefix(ce, &addr, &bitlen);
00702                         if (family != 0 && family != addr.family) {
00703                                 char buf[ISC_NETADDR_FORMATSIZE + 1];
00704                                 isc_netaddr_format(&addr, buf, sizeof(buf));
00705                                 cfg_obj_log(ce, lctx, ISC_LOG_WARNING,
00706                                             "'%s': incorrect address family; "
00707                                             "ignoring", buf);
00708                                 if (nest_level != 0)
00709                                         dns_acl_detach(&de->nestedacl);
00710                                 continue;
00711                         }
00712 
00713                         /*
00714                          * If nesting ACLs (nest_level != 0), we negate
00715                          * the nestedacl element, not the iptable entry.
00716                          */
00717                         setpos = ISC_TF(nest_level != 0 || !neg);
00718                         setecs = cfg_obj_istype(ce, &cfg_type_ecsprefix);
00719                         result = dns_iptable_addprefix2(iptab, &addr, bitlen,
00720                                                         setpos, setecs);
00721                         if (result != ISC_R_SUCCESS)
00722                                 goto cleanup;
00723 
00724                         if (nest_level > 0) {
00725                                 INSIST(dacl->length < dacl->alloc);
00726                                 de->type = dns_aclelementtype_nestedacl;
00727                                 de->negative = neg;
00728                         } else
00729                                 continue;
00730                 } else if (cfg_obj_islist(ce)) {
00731                         /*
00732                          * If we're nesting ACLs, put the nested
00733                          * ACL onto the elements list; otherwise
00734                          * merge it into *this* ACL.  We nest ACLs
00735                          * in two cases: 1) sortlist, 2) if the
00736                          * nested ACL contains negated members.
00737                          */
00738                         if (inneracl != NULL)
00739                                 dns_acl_detach(&inneracl);
00740                         result = cfg_acl_fromconfig(ce, cctx, lctx,
00741                                                     ctx, mctx, new_nest_level,
00742                                                     &inneracl);
00743                         if (result != ISC_R_SUCCESS)
00744                                 goto cleanup;
00745 nested_acl:
00746                         if (nest_level > 0 || inneracl->has_negatives) {
00747                                 INSIST(dacl->length < dacl->alloc);
00748                                 de->type = dns_aclelementtype_nestedacl;
00749                                 de->negative = neg;
00750                                 if (de->nestedacl != NULL)
00751                                         dns_acl_detach(&de->nestedacl);
00752                                 dns_acl_attach(inneracl,
00753                                                &de->nestedacl);
00754                                 dns_acl_detach(&inneracl);
00755                                 /* Fall through. */
00756                         } else {
00757                                 INSIST(dacl->length + inneracl->length
00758                                        <= dacl->alloc);
00759                                 dns_acl_merge(dacl, inneracl,
00760                                               ISC_TF(!neg));
00761                                 de += inneracl->length;  /* elements added */
00762                                 dns_acl_detach(&inneracl);
00763                                 INSIST(dacl->length <= dacl->alloc);
00764                                 continue;
00765                         }
00766                 } else if (cfg_obj_istype(ce, &cfg_type_keyref)) {
00767                         /* Key name. */
00768                         INSIST(dacl->length < dacl->alloc);
00769                         de->type = dns_aclelementtype_keyname;
00770                         de->negative = neg;
00771                         dns_name_init(&de->keyname, NULL);
00772                         result = convert_keyname(ce, lctx, mctx,
00773                                                  &de->keyname);
00774                         if (result != ISC_R_SUCCESS)
00775                                 goto cleanup;
00776 #ifdef HAVE_GEOIP
00777                 } else if (cfg_obj_istuple(ce) &&
00778                            cfg_obj_isvoid(cfg_tuple_get(ce, "negated")))
00779                 {
00780                         INSIST(dacl->length < dacl->alloc);
00781                         result = parse_geoip_element(ce, lctx, ctx, de);
00782                         if (result != ISC_R_SUCCESS)
00783                                 goto cleanup;
00784                         de->type = dns_aclelementtype_geoip;
00785                         de->negative = neg;
00786 #endif /* HAVE_GEOIP */
00787                 } else if (cfg_obj_isstring(ce)) {
00788                         /* ACL name. */
00789                         const char *name = cfg_obj_asstring(ce);
00790                         if (strcasecmp(name, "any") == 0) {
00791                                 /* Iptable entry with zero bit length. */
00792                                 result = dns_iptable_addprefix(iptab, NULL, 0,
00793                                               ISC_TF(nest_level != 0 || !neg));
00794                                 if (result != ISC_R_SUCCESS)
00795                                         goto cleanup;
00796 
00797                                 if (nest_level != 0) {
00798                                         INSIST(dacl->length < dacl->alloc);
00799                                         de->type = dns_aclelementtype_nestedacl;
00800                                         de->negative = neg;
00801                                 } else
00802                                         continue;
00803                         } else if (strcasecmp(name, "none") == 0) {
00804                                 /* none == !any */
00805                                 /*
00806                                  * We don't unconditional set
00807                                  * dacl->has_negatives and
00808                                  * de->negative to true so we can handle
00809                                  * "!none;".
00810                                  */
00811                                 result = dns_iptable_addprefix(iptab, NULL, 0,
00812                                               ISC_TF(nest_level != 0 || neg));
00813                                 if (result != ISC_R_SUCCESS)
00814                                         goto cleanup;
00815 
00816                                 if (!neg)
00817                                         dacl->has_negatives = !neg;
00818 
00819                                 if (nest_level != 0) {
00820                                         INSIST(dacl->length < dacl->alloc);
00821                                         de->type = dns_aclelementtype_nestedacl;
00822                                         de->negative = !neg;
00823                                 } else
00824                                         continue;
00825                         } else if (strcasecmp(name, "localhost") == 0) {
00826                                 INSIST(dacl->length < dacl->alloc);
00827                                 de->type = dns_aclelementtype_localhost;
00828                                 de->negative = neg;
00829                         } else if (strcasecmp(name, "localnets") == 0) {
00830                                 INSIST(dacl->length < dacl->alloc);
00831                                 de->type = dns_aclelementtype_localnets;
00832                                 de->negative = neg;
00833                         } else {
00834                                 if (inneracl != NULL)
00835                                         dns_acl_detach(&inneracl);
00836                                 /*
00837                                  * This call should just find the cached
00838                                  * of the named acl.
00839                                  */
00840                                 result = convert_named_acl(ce, cctx, lctx, ctx,
00841                                                            mctx, new_nest_level,
00842                                                            &inneracl);
00843                                 if (result != ISC_R_SUCCESS)
00844                                         goto cleanup;
00845 
00846                                 goto nested_acl;
00847                         }
00848                 } else {
00849                         cfg_obj_log(ce, lctx, ISC_LOG_WARNING,
00850                                     "address match list contains "
00851                                     "unsupported element type");
00852                         result = ISC_R_FAILURE;
00853                         goto cleanup;
00854                 }
00855 
00856                 /*
00857                  * This should only be reached for localhost, localnets
00858                  * and keyname elements, and nested ACLs if nest_level is
00859                  * nonzero (i.e., in sortlists).
00860                  */
00861                 if (de->nestedacl != NULL &&
00862                     de->type != dns_aclelementtype_nestedacl)
00863                         dns_acl_detach(&de->nestedacl);
00864 
00865                 dacl->node_count++;
00866                 de->node_num = dacl->node_count;
00867 
00868                 dacl->length++;
00869                 de++;
00870                 INSIST(dacl->length <= dacl->alloc);
00871         }
00872 
00873         dns_acl_attach(dacl, target);
00874         result = ISC_R_SUCCESS;
00875 
00876  cleanup:
00877         if (inneracl != NULL)
00878                 dns_acl_detach(&inneracl);
00879         dns_acl_detach(&dacl);
00880         return (result);
00881 }

Generated on Tue Apr 28 17:41:06 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha