/*% * Configure an apex NS with an out-of-zone NS names for a static-stub zone. * For example, for the zone named "example.com", something like the following * RRs will be added to the zone DB: * example.com. NS ns.example.net. */ static isc_result_t configure_staticstub_servernames(const cfg_obj_t *zconfig, dns_zone_t *zone, dns_rdatalist_t *rdatalist, const char *zname) { const cfg_listelt_t *element; isc_mem_t *mctx = dns_zone_getmctx(zone); dns_rdata_t *rdata; isc_region_t sregion, region; isc_result_t result = ISC_R_SUCCESS; for (element = cfg_list_first(zconfig); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *obj; const char *str; dns_fixedname_t fixed_name; dns_name_t *nsname; isc_buffer_t b; obj = cfg_listelt_value(element); str = cfg_obj_asstring(obj); dns_fixedname_init(&fixed_name); nsname = dns_fixedname_name(&fixed_name); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); result = dns_name_fromtext(nsname, &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, "server-name '%s' is not a valid " "name", str); return (result); } if (dns_name_issubdomain(nsname, dns_zone_getorigin(zone))) { cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, "server-name '%s' must not be a " "subdomain of zone name '%s'", str, zname); return (ISC_R_FAILURE); } dns_name_toregion(nsname, &sregion); rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length); if (rdata == NULL) return (ISC_R_NOMEMORY); region.length = sregion.length; region.base = (unsigned char *)(rdata + 1); memcpy(region.base, sregion.base, region.length); dns_rdata_init(rdata); dns_rdata_fromregion(rdata, dns_zone_getclass(zone), dns_rdatatype_ns, ®ion); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); } return (result); }
static isc_result_t convert_named_acl(const cfg_obj_t *nameobj, const cfg_obj_t *cctx, isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx, unsigned int nest_level, dns_acl_t **target) { isc_result_t result; const cfg_obj_t *cacl = NULL; dns_acl_t *dacl; dns_acl_t loop; const char *aclname = cfg_obj_asstring(nameobj); /* Look for an already-converted version. */ for (dacl = ISC_LIST_HEAD(ctx->named_acl_cache); dacl != NULL; dacl = ISC_LIST_NEXT(dacl, nextincache)) { if (strcasecmp(aclname, dacl->name) == 0) { if (ISC_MAGIC_VALID(dacl, LOOP_MAGIC)) { cfg_obj_log(nameobj, lctx, ISC_LOG_ERROR, "acl loop detected: %s", aclname); return (ISC_R_FAILURE); } dns_acl_attach(dacl, target); return (ISC_R_SUCCESS); } } /* Not yet converted. Convert now. */ result = get_acl_def(cctx, aclname, &cacl); if (result != ISC_R_SUCCESS) { cfg_obj_log(nameobj, lctx, ISC_LOG_WARNING, "undefined ACL '%s'", aclname); return (result); } /* * Add a loop detection element. */ memset(&loop, 0, sizeof(loop)); ISC_LINK_INIT(&loop, nextincache); DE_CONST(aclname, loop.name); loop.magic = LOOP_MAGIC; ISC_LIST_APPEND(ctx->named_acl_cache, &loop, nextincache); result = cfg_acl_fromconfig(cacl, cctx, lctx, ctx, mctx, nest_level, &dacl); ISC_LIST_UNLINK(ctx->named_acl_cache, &loop, nextincache); loop.magic = 0; loop.name = NULL; if (result != ISC_R_SUCCESS) return (result); dacl->name = isc_mem_strdup(dacl->mctx, aclname); if (dacl->name == NULL) return (ISC_R_NOMEMORY); ISC_LIST_APPEND(ctx->named_acl_cache, dacl, nextincache); dns_acl_attach(dacl, target); return (ISC_R_SUCCESS); }
isc_result_t ns_config_getport(const cfg_obj_t *config, in_port_t *portp) { const cfg_obj_t *maps[3]; const cfg_obj_t *options = NULL; const cfg_obj_t *portobj = NULL; isc_result_t result; int i; (void)cfg_map_get(config, "options", &options); i = 0; if (options != NULL) maps[i++] = options; maps[i++] = ns_g_defaults; maps[i] = NULL; result = ns_config_get(maps, "port", &portobj); INSIST(result == ISC_R_SUCCESS); if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) { cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, "port '%u' out of range", cfg_obj_asuint32(portobj)); return (ISC_R_RANGE); } *portp = (in_port_t)cfg_obj_asuint32(portobj); return (ISC_R_SUCCESS); }
static void update_listener(ns_server_t *server, ns_statschannel_t **listenerp, const cfg_obj_t *listen_params, const cfg_obj_t *config, isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, const char *socktext) { ns_statschannel_t *listener; const cfg_obj_t *allow = NULL; dns_acl_t *new_acl = NULL; isc_result_t result = ISC_R_SUCCESS; for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL; listener = ISC_LIST_NEXT(listener, link)) if (isc_sockaddr_equal(addr, &listener->address)) break; if (listener == NULL) { *listenerp = NULL; return; } /* * Now, keep the old access list unless a new one can be made. */ allow = cfg_tuple_get(listen_params, "allow"); if (allow != NULL && cfg_obj_islist(allow)) { result = cfg_acl_fromconfig(allow, config, ns_g_lctx, aclconfctx, listener->mctx, 0, &new_acl); } else result = dns_acl_any(listener->mctx, &new_acl); if (result == ISC_R_SUCCESS) { LOCK(&listener->lock); dns_acl_detach(&listener->acl); dns_acl_attach(new_acl, &listener->acl); dns_acl_detach(&new_acl); UNLOCK(&listener->lock); } else { cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING, "couldn't install new acl for " "statistics channel %s: %s", socktext, isc_result_totext(result)); } *listenerp = listener; }
/*% * Set up a logging category according to the named.conf data * in 'ccat' and add it to 'logconfig'. */ static isc_result_t category_fromconf(const cfg_obj_t *ccat, isc_logconfig_t *logconfig) { isc_result_t result; const char *catname; isc_logcategory_t *category; isc_logmodule_t *module; const cfg_obj_t *destinations = NULL; const cfg_listelt_t *element = NULL; catname = cfg_obj_asstring(cfg_tuple_get(ccat, "name")); category = isc_log_categorybyname(ns_g_lctx, catname); if (category == NULL) { cfg_obj_log(ccat, ns_g_lctx, ISC_LOG_ERROR, "unknown logging category '%s' ignored", catname); /* * Allow further processing by returning success. */ return (ISC_R_SUCCESS); } if (logconfig == NULL) return (ISC_R_SUCCESS); module = NULL; destinations = cfg_tuple_get(ccat, "destinations"); for (element = cfg_list_first(destinations); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *channel = cfg_listelt_value(element); const char *channelname = cfg_obj_asstring(channel); result = isc_log_usechannel(logconfig, channelname, category, module); if (result != ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, CFG_LOGCATEGORY_CONFIG, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "logging channel '%s': %s", channelname, isc_result_totext(result)); return (result); } } return (ISC_R_SUCCESS); }
isc_result_t ns_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype, dns_rdatatype_t *typep) { isc_textregion_t r; isc_result_t result; if (!cfg_obj_isstring(typeobj)) { *typep = deftype; return (ISC_R_SUCCESS); } DE_CONST(cfg_obj_asstring(typeobj), r.base); r.length = strlen(r.base); result = dns_rdatatype_fromtext(typep, &r); if (result != ISC_R_SUCCESS) cfg_obj_log(typeobj, ns_g_lctx, ISC_LOG_ERROR, "unknown type '%s'", r.base); return (result); }
isc_result_t ns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass, dns_rdataclass_t *classp) { isc_textregion_t r; isc_result_t result; if (!cfg_obj_isstring(classobj)) { *classp = defclass; return (ISC_R_SUCCESS); } DE_CONST(cfg_obj_asstring(classobj), r.base); r.length = strlen(r.base); result = dns_rdataclass_fromtext(classp, &r); if (result != ISC_R_SUCCESS) cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR, "unknown class '%s'", r.base); return (result); }
static isc_result_t convert_keyname(cfg_obj_t *keyobj, isc_mem_t *mctx, dns_name_t *dnsname) { isc_result_t result; isc_buffer_t buf; dns_fixedname_t fixname; unsigned int keylen; const char *txtname = cfg_obj_asstring(keyobj); keylen = strlen(txtname); isc_buffer_init(&buf, txtname, keylen); isc_buffer_add(&buf, keylen); dns_fixedname_init(&fixname); result = dns_name_fromtext(dns_fixedname_name(&fixname), &buf, dns_rootname, ISC_FALSE, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(keyobj, dns_lctx, ISC_LOG_WARNING, "key name '%s' is not a valid domain name", txtname); return (result); } return (dns_name_dup(dns_fixedname_name(&fixname), mctx, dnsname)); }
isc_result_t ns_config_getdscp(const cfg_obj_t *config, isc_dscp_t *dscpp) { const cfg_obj_t *options = NULL; const cfg_obj_t *dscpobj = NULL; isc_result_t result; (void)cfg_map_get(config, "options", &options); if (options == NULL) return (ISC_R_SUCCESS); result = cfg_map_get(options, "dscp", &dscpobj); if (result != ISC_R_SUCCESS || dscpobj == NULL) { *dscpp = -1; return (ISC_R_SUCCESS); } if (cfg_obj_asuint32(dscpobj) >= 64) { cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR, "dscp '%u' out of range", cfg_obj_asuint32(dscpobj)); return (ISC_R_RANGE); } *dscpp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); return (ISC_R_SUCCESS); }
/*% directory callback */ static isc_result_t directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) { isc_result_t result; const char *directory; REQUIRE(strcasecmp("directory", clausename) == 0); UNUSED(arg); UNUSED(clausename); /* * Change directory. */ directory = cfg_obj_asstring(obj); result = isc_dir_chdir(directory); if (result != ISC_R_SUCCESS) { cfg_obj_log(obj, logc, ISC_LOG_ERROR, "change directory to '%s' failed: %s\n", directory, isc_result_totext(result)); return (result); } return (ISC_R_SUCCESS); }
/*% * Set up a logging channel according to the named.conf data * in 'cchan' and add it to 'logconfig'. */ static isc_result_t channel_fromconf(const cfg_obj_t *channel, isc_logconfig_t *logconfig) { isc_result_t result; isc_logdestination_t dest; unsigned int type; unsigned int flags = 0; int level; const char *channelname; const cfg_obj_t *fileobj = NULL; const cfg_obj_t *syslogobj = NULL; const cfg_obj_t *nullobj = NULL; const cfg_obj_t *stderrobj = NULL; const cfg_obj_t *severity = NULL; int i; channelname = cfg_obj_asstring(cfg_map_getname(channel)); (void)cfg_map_get(channel, "file", &fileobj); (void)cfg_map_get(channel, "syslog", &syslogobj); (void)cfg_map_get(channel, "null", &nullobj); (void)cfg_map_get(channel, "stderr", &stderrobj); i = 0; if (fileobj != NULL) i++; if (syslogobj != NULL) i++; if (nullobj != NULL) i++; if (stderrobj != NULL) i++; if (i != 1) { cfg_obj_log(channel, ns_g_lctx, ISC_LOG_ERROR, "channel '%s': exactly one of file, syslog, " "null, and stderr must be present", channelname); return (ISC_R_FAILURE); } type = ISC_LOG_TONULL; if (fileobj != NULL) { const cfg_obj_t *pathobj = cfg_tuple_get(fileobj, "file"); const cfg_obj_t *sizeobj = cfg_tuple_get(fileobj, "size"); const cfg_obj_t *versionsobj = cfg_tuple_get(fileobj, "versions"); isc_int32_t versions = ISC_LOG_ROLLNEVER; isc_offset_t size = 0; type = ISC_LOG_TOFILE; if (versionsobj != NULL && cfg_obj_isuint32(versionsobj)) versions = cfg_obj_asuint32(versionsobj); if (versionsobj != NULL && cfg_obj_isstring(versionsobj) && strcasecmp(cfg_obj_asstring(versionsobj), "unlimited") == 0) versions = ISC_LOG_ROLLINFINITE; if (sizeobj != NULL && cfg_obj_isuint64(sizeobj) && cfg_obj_asuint64(sizeobj) < ISC_OFFSET_MAXIMUM) size = (isc_offset_t)cfg_obj_asuint64(sizeobj); dest.file.stream = NULL; dest.file.name = cfg_obj_asstring(pathobj); dest.file.versions = versions; dest.file.maximum_size = size; } else if (syslogobj != NULL) { int facility = LOG_DAEMON; type = ISC_LOG_TOSYSLOG; if (cfg_obj_isstring(syslogobj)) { const char *facilitystr = cfg_obj_asstring(syslogobj); (void)isc_syslog_facilityfromstring(facilitystr, &facility); } dest.facility = facility; } else if (stderrobj != NULL) { type = ISC_LOG_TOFILEDESC; dest.file.stream = stderr; dest.file.name = NULL; dest.file.versions = ISC_LOG_ROLLNEVER; dest.file.maximum_size = 0; } /* * Munge flags. */ { const cfg_obj_t *printcat = NULL; const cfg_obj_t *printsev = NULL; const cfg_obj_t *printtime = NULL; const cfg_obj_t *buffered = NULL; (void)cfg_map_get(channel, "print-category", &printcat); (void)cfg_map_get(channel, "print-severity", &printsev); (void)cfg_map_get(channel, "print-time", &printtime); (void)cfg_map_get(channel, "buffered", &buffered); if (printcat != NULL && cfg_obj_asboolean(printcat)) flags |= ISC_LOG_PRINTCATEGORY; if (printtime != NULL && cfg_obj_asboolean(printtime)) flags |= ISC_LOG_PRINTTIME; if (printsev != NULL && cfg_obj_asboolean(printsev)) flags |= ISC_LOG_PRINTLEVEL; if (buffered != NULL && cfg_obj_asboolean(buffered)) flags |= ISC_LOG_BUFFERED; } level = ISC_LOG_INFO; if (cfg_map_get(channel, "severity", &severity) == ISC_R_SUCCESS) { if (cfg_obj_isstring(severity)) { const char *str = cfg_obj_asstring(severity); if (strcasecmp(str, "critical") == 0) level = ISC_LOG_CRITICAL; else if (strcasecmp(str, "error") == 0) level = ISC_LOG_ERROR; else if (strcasecmp(str, "warning") == 0) level = ISC_LOG_WARNING; else if (strcasecmp(str, "notice") == 0) level = ISC_LOG_NOTICE; else if (strcasecmp(str, "info") == 0) level = ISC_LOG_INFO; else if (strcasecmp(str, "dynamic") == 0) level = ISC_LOG_DYNAMIC; } else /* debug */ level = cfg_obj_asuint32(severity); } if (logconfig == NULL) result = ISC_R_SUCCESS; else result = isc_log_createchannel(logconfig, channelname, type, level, &dest, flags); if (result == ISC_R_SUCCESS && type == ISC_LOG_TOFILE) { FILE *fp; /* * Test to make sure that file is a plain file. * Fix defect #22771 */ result = isc_file_isplainfile(dest.file.name); if (result == ISC_R_SUCCESS || result == ISC_R_FILENOTFOUND) { /* * Test that the file can be opened, since * isc_log_open() can't effectively report * failures when called in isc_log_doit(). */ result = isc_stdio_open(dest.file.name, "a", &fp); if (result != ISC_R_SUCCESS) { if (logconfig != NULL && !ns_g_nosyslog) syslog(LOG_ERR, "isc_stdio_open '%s' failed: " "%s", dest.file.name, isc_result_totext(result)); fprintf(stderr, "isc_stdio_open '%s' failed: %s\n", dest.file.name, isc_result_totext(result)); } else (void)isc_stdio_close(fp); goto done; } if (logconfig != NULL && !ns_g_nosyslog) syslog(LOG_ERR, "isc_file_isplainfile '%s' failed: %s", dest.file.name, isc_result_totext(result)); fprintf(stderr, "isc_file_isplainfile '%s' failed: %s\n", dest.file.name, isc_result_totext(result)); } done: return (result); }
static dns_geoip_subtype_t get_subtype(const cfg_obj_t *obj, isc_log_t *lctx, dns_geoip_subtype_t subtype, const char *dbname) { if (dbname == NULL) return (subtype); switch (subtype) { case dns_geoip_countrycode: if (strcasecmp(dbname, "city") == 0) return (dns_geoip_city_countrycode); else if (strcasecmp(dbname, "region") == 0) return (dns_geoip_region_countrycode); else if (strcasecmp(dbname, "country") == 0) return (dns_geoip_country_code); cfg_obj_log(obj, lctx, ISC_LOG_ERROR, "invalid GeoIP DB specified for " "country search: ignored"); return (subtype); case dns_geoip_countrycode3: if (strcasecmp(dbname, "city") == 0) return (dns_geoip_city_countrycode3); else if (strcasecmp(dbname, "country") == 0) return (dns_geoip_country_code3); cfg_obj_log(obj, lctx, ISC_LOG_ERROR, "invalid GeoIP DB specified for " "country search: ignored"); return (subtype); case dns_geoip_countryname: if (strcasecmp(dbname, "city") == 0) return (dns_geoip_city_countryname); else if (strcasecmp(dbname, "country") == 0) return (dns_geoip_country_name); cfg_obj_log(obj, lctx, ISC_LOG_ERROR, "invalid GeoIP DB specified for " "country search: ignored"); return (subtype); case dns_geoip_region: if (strcasecmp(dbname, "city") == 0) return (dns_geoip_city_region); else if (strcasecmp(dbname, "region") == 0) return (dns_geoip_region_code); cfg_obj_log(obj, lctx, ISC_LOG_ERROR, "invalid GeoIP DB specified for " "region search: ignored"); return (subtype); case dns_geoip_regionname: if (strcasecmp(dbname, "city") == 0) return (dns_geoip_city_region); else if (strcasecmp(dbname, "region") == 0) return (dns_geoip_region_name); cfg_obj_log(obj, lctx, ISC_LOG_ERROR, "invalid GeoIP DB specified for " "region search: ignored"); return (subtype); /* * Log a warning if the wrong database was specified * on an unambiguous query */ case dns_geoip_city_name: case dns_geoip_city_postalcode: case dns_geoip_city_metrocode: case dns_geoip_city_areacode: case dns_geoip_city_continentcode: case dns_geoip_city_timezonecode: if (strcasecmp(dbname, "city") != 0) cfg_obj_log(obj, lctx, ISC_LOG_WARNING, "invalid GeoIP DB specified for " "a 'city'-only search type: ignoring"); return (subtype); case dns_geoip_isp_name: if (strcasecmp(dbname, "isp") != 0) cfg_obj_log(obj, lctx, ISC_LOG_WARNING, "invalid GeoIP DB specified for " "an 'isp' search: ignoring"); return (subtype); case dns_geoip_org_name: if (strcasecmp(dbname, "org") != 0) cfg_obj_log(obj, lctx, ISC_LOG_WARNING, "invalid GeoIP DB specified for " "an 'org' search: ignoring"); return (subtype); case dns_geoip_as_asnum: if (strcasecmp(dbname, "asnum") != 0) cfg_obj_log(obj, lctx, ISC_LOG_WARNING, "invalid GeoIP DB specified for " "an 'asnum' search: ignoring"); return (subtype); case dns_geoip_domain_name: if (strcasecmp(dbname, "domain") != 0) cfg_obj_log(obj, lctx, ISC_LOG_WARNING, "invalid GeoIP DB specified for " "a 'domain' search: ignoring"); return (subtype); case dns_geoip_netspeed_id: if (strcasecmp(dbname, "netspeed") != 0) cfg_obj_log(obj, lctx, ISC_LOG_WARNING, "invalid GeoIP DB specified for " "a 'netspeed' search: ignoring"); return (subtype); default: INSIST(0); } }
isc_result_t ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac, dns_zone_t *zone) { isc_result_t result; const char *zname; dns_rdataclass_t zclass; dns_rdataclass_t vclass; const cfg_obj_t *maps[5]; const cfg_obj_t *zoptions = NULL; const cfg_obj_t *options = NULL; const cfg_obj_t *obj; const char *filename = NULL; dns_notifytype_t notifytype = dns_notifytype_yes; isc_sockaddr_t *addrs; dns_name_t **keynames; isc_uint32_t count; char *cpval; unsigned int dbargc; char **dbargv; static char default_dbtype[] = "rbt"; isc_mem_t *mctx = dns_zone_getmctx(zone); dns_dialuptype_t dialup = dns_dialuptype_no; dns_zonetype_t ztype; int i; isc_int32_t journal_size; isc_boolean_t multi; isc_boolean_t alt; dns_view_t *view; isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE; isc_boolean_t warn = ISC_FALSE, ignore = ISC_FALSE; isc_boolean_t ixfrdiff; dns_masterformat_t masterformat; isc_stats_t *zoneqrystats; isc_boolean_t zonestats_on; int seconds; i = 0; if (zconfig != NULL) { zoptions = cfg_tuple_get(zconfig, "options"); maps[i++] = zoptions; } if (vconfig != NULL) maps[i++] = cfg_tuple_get(vconfig, "options"); if (config != NULL) { (void)cfg_map_get(config, "options", &options); if (options != NULL) maps[i++] = options; } maps[i++] = ns_g_defaults; maps[i] = NULL; if (vconfig != NULL) RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"), dns_rdataclass_in, &vclass)); else vclass = dns_rdataclass_in; /* * Configure values common to all zone types. */ zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name")); RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"), vclass, &zclass)); dns_zone_setclass(zone, zclass); ztype = zonetype_fromconfig(zoptions); dns_zone_settype(zone, ztype); obj = NULL; result = cfg_map_get(zoptions, "database", &obj); if (result == ISC_R_SUCCESS) cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj)); else cpval = default_dbtype; if (cpval == NULL) return(ISC_R_NOMEMORY); result = strtoargv(mctx, cpval, &dbargc, &dbargv); if (result != ISC_R_SUCCESS && cpval != default_dbtype) { isc_mem_free(mctx, cpval); return (result); } /* * ANSI C is strange here. There is no logical reason why (char **) * cannot be promoted automatically to (const char * const *) by the * compiler w/o generating a warning. */ result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv); isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv)); if (cpval != default_dbtype) isc_mem_free(mctx, cpval); if (result != ISC_R_SUCCESS) return (result); obj = NULL; result = cfg_map_get(zoptions, "file", &obj); if (result == ISC_R_SUCCESS) filename = cfg_obj_asstring(obj); /* * Unless we're using some alternative database, a master zone * will be needing a master file. */ if (ztype == dns_zone_master && cpval == default_dbtype && filename == NULL) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "zone '%s': 'file' not specified", zname); return (ISC_R_FAILURE); } masterformat = dns_masterformat_text; obj = NULL; result= ns_config_get(maps, "masterfile-format", &obj); if (result == ISC_R_SUCCESS) { const char *masterformatstr = cfg_obj_asstring(obj); if (strcasecmp(masterformatstr, "text") == 0) masterformat = dns_masterformat_text; else if (strcasecmp(masterformatstr, "raw") == 0) masterformat = dns_masterformat_raw; else INSIST(0); } RETERR(dns_zone_setfile2(zone, filename, masterformat)); obj = NULL; result = cfg_map_get(zoptions, "journal", &obj); if (result == ISC_R_SUCCESS) RETERR(dns_zone_setjournal(zone, cfg_obj_asstring(obj))); if (ztype == dns_zone_slave) RETERR(configure_zone_acl(zconfig, vconfig, config, allow_notify, ac, zone, dns_zone_setnotifyacl, dns_zone_clearnotifyacl)); /* * XXXAG This probably does not make sense for stubs. */ RETERR(configure_zone_acl(zconfig, vconfig, config, allow_query, ac, zone, dns_zone_setqueryacl, dns_zone_clearqueryacl)); obj = NULL; result = ns_config_get(maps, "dialup", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (cfg_obj_isboolean(obj)) { if (cfg_obj_asboolean(obj)) dialup = dns_dialuptype_yes; else dialup = dns_dialuptype_no; } else { const char *dialupstr = cfg_obj_asstring(obj); if (strcasecmp(dialupstr, "notify") == 0) dialup = dns_dialuptype_notify; else if (strcasecmp(dialupstr, "notify-passive") == 0) dialup = dns_dialuptype_notifypassive; else if (strcasecmp(dialupstr, "refresh") == 0) dialup = dns_dialuptype_refresh; else if (strcasecmp(dialupstr, "passive") == 0) dialup = dns_dialuptype_passive; else INSIST(0); } dns_zone_setdialup(zone, dialup); obj = NULL; result = ns_config_get(maps, "zone-statistics", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); zonestats_on = cfg_obj_asboolean(obj); zoneqrystats = NULL; if (zonestats_on) { RETERR(isc_stats_create(mctx, &zoneqrystats, dns_nsstatscounter_max)); } dns_zone_setrequeststats(zone, zoneqrystats); if (zoneqrystats != NULL) isc_stats_detach(&zoneqrystats); /* * Configure master functionality. This applies * to primary masters (type "master") and slaves * acting as masters (type "slave"), but not to stubs. */ if (ztype != dns_zone_stub && ztype != dns_zone_staticstub) { obj = NULL; result = ns_config_get(maps, "notify", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (cfg_obj_isboolean(obj)) { if (cfg_obj_asboolean(obj)) notifytype = dns_notifytype_yes; else notifytype = dns_notifytype_no; } else { const char *notifystr = cfg_obj_asstring(obj); if (strcasecmp(notifystr, "explicit") == 0) notifytype = dns_notifytype_explicit; else if (strcasecmp(notifystr, "master-only") == 0) notifytype = dns_notifytype_masteronly; else INSIST(0); } dns_zone_setnotifytype(zone, notifytype); obj = NULL; result = ns_config_get(maps, "also-notify", &obj); if (result == ISC_R_SUCCESS) { isc_sockaddr_t *addrs = NULL; isc_uint32_t addrcount; result = ns_config_getiplist(config, obj, 0, mctx, &addrs, &addrcount); if (result != ISC_R_SUCCESS) return (result); result = dns_zone_setalsonotify(zone, addrs, addrcount); ns_config_putiplist(mctx, &addrs, addrcount); if (result != ISC_R_SUCCESS) return (result); } else RETERR(dns_zone_setalsonotify(zone, NULL, 0)); obj = NULL; result = ns_config_get(maps, "notify-source", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "notify-source-v6", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "notify-to-soa", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA, cfg_obj_asboolean(obj)); dns_zone_setisself(zone, ns_client_isself, NULL); RETERR(configure_zone_acl(zconfig, vconfig, config, allow_transfer, ac, zone, dns_zone_setxfracl, dns_zone_clearxfracl)); obj = NULL; result = ns_config_get(maps, "max-transfer-time-out", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-transfer-idle-out", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-journal-size", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setjournalsize(zone, -1); if (cfg_obj_isstring(obj)) { const char *str = cfg_obj_asstring(obj); INSIST(strcasecmp(str, "unlimited") == 0); journal_size = ISC_UINT32_MAX / 2; } else { isc_resourcevalue_t value; value = cfg_obj_asuint64(obj); if (value > ISC_UINT32_MAX / 2) { cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, "'max-journal-size " "%" ISC_PRINT_QUADFORMAT "d' " "is too large", value); RETERR(ISC_R_RANGE); } journal_size = (isc_uint32_t)value; } dns_zone_setjournalsize(zone, journal_size); obj = NULL; result = ns_config_get(maps, "ixfr-from-differences", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (cfg_obj_isboolean(obj)) ixfrdiff = cfg_obj_asboolean(obj); else if (!strcasecmp(cfg_obj_asstring(obj), "master") && ztype == dns_zone_master) ixfrdiff = ISC_TRUE; else if (!strcasecmp(cfg_obj_asstring(obj), "slave") && ztype == dns_zone_slave) ixfrdiff = ISC_TRUE; else ixfrdiff = ISC_FALSE; dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, ixfrdiff); checknames(ztype, maps, &obj); INSIST(obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { fail = ISC_FALSE; check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { fail = check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { fail = check = ISC_FALSE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail); obj = NULL; result = ns_config_get(maps, "notify-delay", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "check-sibling", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "zero-no-soa-ttl", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "nsec3-test-zone", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE, cfg_obj_asboolean(obj)); } /* * Configure update-related options. These apply to * primary masters only. */ if (ztype == dns_zone_master) { dns_acl_t *updateacl; RETERR(configure_zone_acl(zconfig, vconfig, config, allow_update, ac, zone, dns_zone_setupdateacl, dns_zone_clearupdateacl)); updateacl = dns_zone_getupdateacl(zone); if (updateacl != NULL && dns_acl_isinsecure(updateacl)) isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_SERVER, ISC_LOG_WARNING, "zone '%s' allows updates by IP " "address, which is insecure", zname); RETERR(configure_zone_ssutable(zoptions, zone, zname)); obj = NULL; result = ns_config_get(maps, "sig-validity-interval", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); { const cfg_obj_t *validity, *resign; validity = cfg_tuple_get(obj, "validity"); seconds = cfg_obj_asuint32(validity) * 86400; dns_zone_setsigvalidityinterval(zone, seconds); resign = cfg_tuple_get(obj, "re-sign"); if (cfg_obj_isvoid(resign)) { seconds /= 4; } else { if (seconds > 7 * 86400) seconds = cfg_obj_asuint32(resign) * 86400; else seconds = cfg_obj_asuint32(resign) * 3600; } dns_zone_setsigresigninginterval(zone, seconds); } obj = NULL; result = ns_config_get(maps, "key-directory", &obj); if (result == ISC_R_SUCCESS) { filename = cfg_obj_asstring(obj); RETERR(dns_zone_setkeydirectory(zone, filename)); } obj = NULL; result = ns_config_get(maps, "sig-signing-signatures", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setsignatures(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "sig-signing-nodes", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setnodes(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "sig-signing-type", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "update-check-ksk", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "dnssec-dnskey-kskonly", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY, cfg_obj_asboolean(obj)); } else if (ztype == dns_zone_slave) { RETERR(configure_zone_acl(zconfig, vconfig, config, allow_update_forwarding, ac, zone, dns_zone_setforwardacl, dns_zone_clearforwardacl)); } /*% * Primary master functionality. */ if (ztype == dns_zone_master) { isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE; obj = NULL; result = ns_config_get(maps, "check-wildcard", &obj); if (result == ISC_R_SUCCESS) check = cfg_obj_asboolean(obj); else check = ISC_FALSE; dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check); obj = NULL; result = ns_config_get(maps, "check-dup-records", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { fail = ISC_FALSE; check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { fail = check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { fail = check = ISC_FALSE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRR, check); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRRFAIL, fail); obj = NULL; result = ns_config_get(maps, "check-mx", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { fail = ISC_FALSE; check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { fail = check = ISC_TRUE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { fail = check = ISC_FALSE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMX, check); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMXFAIL, fail); obj = NULL; result = ns_config_get(maps, "check-integrity", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_CHECKINTEGRITY, cfg_obj_asboolean(obj)); obj = NULL; result = ns_config_get(maps, "check-mx-cname", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { warn = ISC_TRUE; ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { warn = ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { warn = ignore = ISC_TRUE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_WARNMXCNAME, warn); dns_zone_setoption(zone, DNS_ZONEOPT_IGNOREMXCNAME, ignore); obj = NULL; result = ns_config_get(maps, "check-srv-cname", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) { warn = ISC_TRUE; ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) { warn = ignore = ISC_FALSE; } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) { warn = ignore = ISC_TRUE; } else INSIST(0); dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn); dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore); obj = NULL; result = ns_config_get(maps, "dnssec-secure-to-insecure", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setoption(zone, DNS_ZONEOPT_SECURETOINSECURE, cfg_obj_asboolean(obj)); obj = NULL; result = cfg_map_get(zoptions, "auto-dnssec", &obj); if (result == ISC_R_SUCCESS) { const char *arg = cfg_obj_asstring(obj); if (strcasecmp(arg, "allow") == 0) allow = ISC_TRUE; else if (strcasecmp(arg, "maintain") == 0) allow = maint = ISC_TRUE; else if (strcasecmp(arg, "off") == 0) ; else INSIST(0); dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow); dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint); } } /* * Configure slave functionality. */ switch (ztype) { case dns_zone_slave: case dns_zone_stub: count = 0; obj = NULL; (void)cfg_map_get(zoptions, "masters", &obj); if (obj != NULL) { addrs = NULL; keynames = NULL; RETERR(ns_config_getipandkeylist(config, obj, mctx, &addrs, &keynames, &count)); result = dns_zone_setmasterswithkeys(zone, addrs, keynames, count); ns_config_putipandkeylist(mctx, &addrs, &keynames, count); } else result = dns_zone_setmasters(zone, NULL, 0); RETERR(result); multi = ISC_FALSE; if (count > 1) { obj = NULL; result = ns_config_get(maps, "multi-master", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); multi = cfg_obj_asboolean(obj); } dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi); obj = NULL; result = ns_config_get(maps, "max-transfer-time-in", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-transfer-idle-in", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60); obj = NULL; result = ns_config_get(maps, "max-refresh-time", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "min-refresh-time", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "max-retry-time", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "min-retry-time", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj)); obj = NULL; result = ns_config_get(maps, "transfer-source", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "transfer-source-v6", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj))); ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj)); obj = NULL; result = ns_config_get(maps, "alt-transfer-source", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj))); obj = NULL; result = ns_config_get(maps, "alt-transfer-source-v6", &obj); INSIST(result == ISC_R_SUCCESS && obj != NULL); RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj))); obj = NULL; (void)ns_config_get(maps, "use-alt-transfer-source", &obj); if (obj == NULL) { /* * Default off when views are in use otherwise * on for BIND 8 compatibility. */ view = dns_zone_getview(zone); if (view != NULL && strcmp(view->name, "_default") == 0) alt = ISC_TRUE; else alt = ISC_FALSE; } else alt = cfg_obj_asboolean(obj); dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt); obj = NULL; (void)ns_config_get(maps, "try-tcp-refresh", &obj); dns_zone_setoption(zone, DNS_ZONEOPT_TRYTCPREFRESH, cfg_obj_asboolean(obj)); break; case dns_zone_staticstub: RETERR(configure_staticstub(zoptions, zone, zname, default_dbtype)); break; default: break; } return (ISC_R_SUCCESS); }
/*% * Configure an apex NS with glues for a static-stub zone. * For example, for the zone named "example.com", the following RRs will be * added to the zone DB: * example.com. NS example.com. * example.com. A 192.0.2.1 * example.com. AAAA 2001:db8::1 */ static isc_result_t configure_staticstub_serveraddrs(const cfg_obj_t *zconfig, dns_zone_t *zone, dns_rdatalist_t *rdatalist_ns, dns_rdatalist_t *rdatalist_a, dns_rdatalist_t *rdatalist_aaaa) { const cfg_listelt_t *element; isc_mem_t *mctx = dns_zone_getmctx(zone); isc_region_t region, sregion; dns_rdata_t *rdata; isc_result_t result = ISC_R_SUCCESS; for (element = cfg_list_first(zconfig); element != NULL; element = cfg_list_next(element)) { const isc_sockaddr_t* sa; isc_netaddr_t na; const cfg_obj_t *address = cfg_listelt_value(element); dns_rdatalist_t *rdatalist; sa = cfg_obj_assockaddr(address); if (isc_sockaddr_getport(sa) != 0) { cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, "port is not configurable for " "static stub server-addresses"); return (ISC_R_FAILURE); } isc_netaddr_fromsockaddr(&na, sa); if (isc_netaddr_getzone(&na) != 0) { cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR, "scoped address is not allowed " "for static stub " "server-addresses"); return (ISC_R_FAILURE); } switch (na.family) { case AF_INET: region.length = sizeof(na.type.in); rdatalist = rdatalist_a; break; default: INSIST(na.family == AF_INET6); region.length = sizeof(na.type.in6); rdatalist = rdatalist_aaaa; break; } rdata = isc_mem_get(mctx, sizeof(*rdata) + region.length); if (rdata == NULL) return (ISC_R_NOMEMORY); region.base = (unsigned char *)(rdata + 1); memcpy(region.base, &na.type, region.length); dns_rdata_init(rdata); dns_rdata_fromregion(rdata, dns_zone_getclass(zone), rdatalist->type, ®ion); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); } /* * If no address is specified (unlikely in this context, but possible), * there's nothing to do anymore. */ if (ISC_LIST_EMPTY(rdatalist_a->rdata) && ISC_LIST_EMPTY(rdatalist_aaaa->rdata)) { return (ISC_R_SUCCESS); } /* Add to the list an apex NS with the ns name being the origin name */ dns_name_toregion(dns_zone_getorigin(zone), &sregion); rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length); if (rdata == NULL) { /* * Already allocated data will be freed in the caller, so * we can simply return here. */ return (ISC_R_NOMEMORY); } region.length = sregion.length; region.base = (unsigned char *)(rdata + 1); memcpy(region.base, sregion.base, region.length); dns_rdata_init(rdata); dns_rdata_fromregion(rdata, dns_zone_getclass(zone), dns_rdatatype_ns, ®ion); ISC_LIST_APPEND(rdatalist_ns->rdata, rdata, link); return (result); }
static isc_result_t parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx, cfg_aclconfctx_t *ctx, dns_aclelement_t *dep) { const cfg_obj_t *ge; const char *dbname = NULL; const char *stype, *search; dns_geoip_subtype_t subtype; dns_aclelement_t de; size_t len; REQUIRE(dep != NULL); de = *dep; ge = cfg_tuple_get(obj, "db"); if (!cfg_obj_isvoid(ge)) dbname = cfg_obj_asstring(ge); stype = cfg_obj_asstring(cfg_tuple_get(obj, "subtype")); search = cfg_obj_asstring(cfg_tuple_get(obj, "search")); len = strlen(search); if (len == 0) { cfg_obj_log(obj, lctx, ISC_LOG_ERROR, "zero-length geoip search field"); return (ISC_R_FAILURE); } if (strcasecmp(stype, "country") == 0 && len == 2) { /* Two-letter country code */ subtype = dns_geoip_countrycode; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "country") == 0 && len == 3) { /* Three-letter country code */ subtype = dns_geoip_countrycode3; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "country") == 0) { /* Country name */ subtype = dns_geoip_countryname; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "region") == 0 && len == 2) { /* Two-letter region code */ subtype = dns_geoip_region; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "region") == 0) { /* Region name */ subtype = dns_geoip_regionname; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "city") == 0) { /* City name */ subtype = dns_geoip_city_name; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "postal") == 0 || strcasecmp(stype, "postalcode") == 0) { if (len < 7) { subtype = dns_geoip_city_postalcode; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else { cfg_obj_log(obj, lctx, ISC_LOG_ERROR, "geoiop postal code (%s) too long", search); return (ISC_R_FAILURE); } } else if (strcasecmp(stype, "metro") == 0 || strcasecmp(stype, "metrocode") == 0) { subtype = dns_geoip_city_metrocode; de.geoip_elem.as_int = atoi(search); } else if (strcasecmp(stype, "area") == 0 || strcasecmp(stype, "areacode") == 0) { subtype = dns_geoip_city_areacode; de.geoip_elem.as_int = atoi(search); } else if (strcasecmp(stype, "tz") == 0 || strcasecmp(stype, "timezone") == 0) { subtype = dns_geoip_city_timezonecode; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "continent") == 0 && len == 2) { /* Two-letter continent code */ subtype = dns_geoip_city_continentcode; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "continent") == 0) { cfg_obj_log(obj, lctx, ISC_LOG_ERROR, "geoiop continent code (%s) too long", search); return (ISC_R_FAILURE); } else if (strcasecmp(stype, "isp") == 0) { subtype = dns_geoip_isp_name; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "asnum") == 0) { subtype = dns_geoip_as_asnum; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "org") == 0) { subtype = dns_geoip_org_name; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "domain") == 0) { subtype = dns_geoip_domain_name; strlcpy(de.geoip_elem.as_string, search, sizeof(de.geoip_elem.as_string)); } else if (strcasecmp(stype, "netspeed") == 0) { subtype = dns_geoip_netspeed_id; de.geoip_elem.as_int = atoi(search); } else INSIST(0); de.geoip_elem.subtype = get_subtype(obj, lctx, subtype, dbname); if (! geoip_can_answer(&de, ctx)) { cfg_obj_log(obj, lctx, ISC_LOG_ERROR, "no GeoIP database installed which can answer " "queries of type '%s'", stype); return (ISC_R_FAILURE); } *dep = de; return (ISC_R_SUCCESS); }
static isc_result_t add_initial_keys(const cfg_obj_t *list, dns_tsig_keyring_t *ring, isc_mem_t *mctx) { dns_tsigkey_t *tsigkey = NULL; const cfg_listelt_t *element; const cfg_obj_t *key = NULL; const char *keyid = NULL; unsigned char *secret = NULL; int secretalloc = 0; int secretlen = 0; isc_result_t ret; isc_stdtime_t now; isc_uint16_t bits; for (element = cfg_list_first(list); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *algobj = NULL; const cfg_obj_t *secretobj = NULL; dns_name_t keyname; dns_name_t *alg; const char *algstr; char keynamedata[1024]; isc_buffer_t keynamesrc, keynamebuf; const char *secretstr; isc_buffer_t secretbuf; key = cfg_listelt_value(element); keyid = cfg_obj_asstring(cfg_map_getname(key)); algobj = NULL; secretobj = NULL; (void)cfg_map_get(key, "algorithm", &algobj); (void)cfg_map_get(key, "secret", &secretobj); INSIST(algobj != NULL && secretobj != NULL); /* * Create the key name. */ dns_name_init(&keyname, NULL); isc_buffer_init(&keynamesrc, keyid, strlen(keyid)); isc_buffer_add(&keynamesrc, strlen(keyid)); isc_buffer_init(&keynamebuf, keynamedata, sizeof(keynamedata)); ret = dns_name_fromtext(&keyname, &keynamesrc, dns_rootname, ISC_TRUE, &keynamebuf); if (ret != ISC_R_SUCCESS) goto failure; /* * Create the algorithm. */ algstr = cfg_obj_asstring(algobj); if (ns_config_getkeyalgorithm(algstr, &alg, &bits) != ISC_R_SUCCESS) { cfg_obj_log(algobj, ns_g_lctx, ISC_LOG_ERROR, "key '%s': has a unsupported algorithm '%s'", keyid, algstr); ret = DNS_R_BADALG; goto failure; } secretstr = cfg_obj_asstring(secretobj); secretalloc = secretlen = strlen(secretstr) * 3 / 4; secret = isc_mem_get(mctx, secretlen); if (secret == NULL) { ret = ISC_R_NOMEMORY; goto failure; } isc_buffer_init(&secretbuf, secret, secretlen); ret = isc_base64_decodestring(secretstr, &secretbuf); if (ret != ISC_R_SUCCESS) goto failure; secretlen = isc_buffer_usedlength(&secretbuf); isc_stdtime_get(&now); ret = dns_tsigkey_create(&keyname, alg, secret, secretlen, ISC_FALSE, NULL, now, now, mctx, ring, &tsigkey); isc_mem_put(mctx, secret, secretalloc); secret = NULL; if (ret != ISC_R_SUCCESS) goto failure; /* * Set digest bits. */ dst_key_setbits(tsigkey->key, bits); dns_tsigkey_detach(&tsigkey); } return (ISC_R_SUCCESS); failure: cfg_obj_log(key, ns_g_lctx, ISC_LOG_ERROR, "configuring key '%s': %s", keyid, isc_result_totext(ret)); if (secret != NULL) isc_mem_put(mctx, secret, secretalloc); return (ret); }
isc_result_t ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list, in_port_t defport, isc_mem_t *mctx, isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp, isc_uint32_t *countp) { int count, i = 0; const cfg_obj_t *addrlist; const cfg_obj_t *portobj, *dscpobj; const cfg_listelt_t *element; isc_sockaddr_t *addrs; in_port_t port; isc_dscp_t dscp = -1, *dscps = NULL; isc_result_t result; INSIST(addrsp != NULL && *addrsp == NULL); INSIST(dscpsp == NULL || *dscpsp == NULL); INSIST(countp != NULL); addrlist = cfg_tuple_get(list, "addresses"); count = ns_config_listcount(addrlist); portobj = cfg_tuple_get(list, "port"); if (cfg_obj_isuint32(portobj)) { isc_uint32_t val = cfg_obj_asuint32(portobj); if (val > ISC_UINT16_MAX) { cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, "port '%u' out of range", val); return (ISC_R_RANGE); } port = (in_port_t) val; } else if (defport != 0) port = defport; else { result = ns_config_getport(config, &port); if (result != ISC_R_SUCCESS) return (result); } if (dscpsp != NULL) { dscpobj = cfg_tuple_get(list, "dscp"); if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) { if (cfg_obj_asuint32(dscpobj) > 63) { cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR, "dscp value '%u' is out of range", cfg_obj_asuint32(dscpobj)); return (ISC_R_RANGE); } dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); } dscps = isc_mem_get(mctx, count * sizeof(isc_dscp_t)); if (dscps == NULL) return (ISC_R_NOMEMORY); } addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t)); if (addrs == NULL) { if (dscps != NULL) isc_mem_put(mctx, dscps, count * sizeof(isc_dscp_t)); return (ISC_R_NOMEMORY); } for (element = cfg_list_first(addrlist); element != NULL; element = cfg_list_next(element), i++) { const cfg_obj_t *addr; INSIST(i < count); addr = cfg_listelt_value(element); addrs[i] = *cfg_obj_assockaddr(addr); if (dscpsp != NULL) { isc_dscp_t innerdscp; innerdscp = cfg_obj_getdscp(addr); if (innerdscp == -1) innerdscp = dscp; dscps[i] = innerdscp; } if (isc_sockaddr_getport(&addrs[i]) == 0) isc_sockaddr_setport(&addrs[i], port); } INSIST(i == count); *addrsp = addrs; *countp = count; if (dscpsp != NULL) *dscpsp = dscps; return (ISC_R_SUCCESS); }
static isc_result_t key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { dns_rdata_dnskey_t keystruct; isc_uint32_t flags, proto, alg; const char *keystr, *keynamestr; unsigned char keydata[4096]; isc_buffer_t keydatabuf; unsigned char rrdata[4096]; isc_buffer_t rrdatabuf; isc_region_t r; dns_fixedname_t fkeyname; dns_name_t *keyname; isc_result_t result; isc_boolean_t match_root = ISC_FALSE, match_dlv = ISC_FALSE; keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); CHECK(convert_name(&fkeyname, &keyname, keynamestr)); if (!root_validation && !dlv_validation) return (ISC_R_SUCCESS); if (anchor_name) match_root = dns_name_equal(keyname, anchor_name); if (dlv_name) match_dlv = dns_name_equal(keyname, dlv_name); if (!match_root && !match_dlv) return (ISC_R_SUCCESS); if ((!root_validation && match_root) || (!dlv_validation && match_dlv)) return (ISC_R_SUCCESS); if (match_root) delv_log(ISC_LOG_DEBUG(3), "adding trust anchor %s", trust_anchor); if (match_dlv) delv_log(ISC_LOG_DEBUG(3), "adding DLV trust anchor %s", dlv_anchor); flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags")); proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol")); alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm")); keystruct.common.rdclass = dns_rdataclass_in; keystruct.common.rdtype = dns_rdatatype_dnskey; /* * The key data in keystruct is not dynamically allocated. */ keystruct.mctx = NULL; ISC_LINK_INIT(&keystruct.common, link); if (flags > 0xffff) CHECK(ISC_R_RANGE); if (proto > 0xff) CHECK(ISC_R_RANGE); if (alg > 0xff) CHECK(ISC_R_RANGE); keystruct.flags = (isc_uint16_t)flags; keystruct.protocol = (isc_uint8_t)proto; keystruct.algorithm = (isc_uint8_t)alg; isc_buffer_init(&keydatabuf, keydata, sizeof(keydata)); isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); keystr = cfg_obj_asstring(cfg_tuple_get(key, "key")); CHECK(isc_base64_decodestring(keystr, &keydatabuf)); isc_buffer_usedregion(&keydatabuf, &r); keystruct.datalen = r.length; keystruct.data = r.base; CHECK(dns_rdata_fromstruct(NULL, keystruct.common.rdclass, keystruct.common.rdtype, &keystruct, &rrdatabuf)); CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, keyname, &rrdatabuf)); trusted_keys++; cleanup: if (result == DST_R_NOCRYPTO) cfg_obj_log(key, lctx, ISC_LOG_ERROR, "no crypto support"); else if (result == DST_R_UNSUPPORTEDALG) { cfg_obj_log(key, lctx, ISC_LOG_WARNING, "skipping trusted key '%s': %s", keynamestr, isc_result_totext(result)); result = ISC_R_SUCCESS; } else if (result != ISC_R_SUCCESS) { cfg_obj_log(key, lctx, ISC_LOG_ERROR, "failed to add trusted key '%s': %s", keynamestr, isc_result_totext(result)); result = ISC_R_FAILURE; } return (result); }
isc_result_t ns_statschannels_configure(ns_server_t *server, const cfg_obj_t *config, cfg_aclconfctx_t *aclconfctx) { ns_statschannel_t *listener, *listener_next; ns_statschannellist_t new_listeners; const cfg_obj_t *statschannellist = NULL; const cfg_listelt_t *element, *element2; char socktext[ISC_SOCKADDR_FORMATSIZE]; RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); ISC_LIST_INIT(new_listeners); /* * Get the list of named.conf 'statistics-channels' statements. */ (void)cfg_map_get(config, "statistics-channels", &statschannellist); /* * Run through the new address/port list, noting sockets that are * already being listened on and moving them to the new list. * * Identifying duplicate addr/port combinations is left to either * the underlying config code, or to the bind attempt getting an * address-in-use error. */ if (statschannellist != NULL) { #ifndef HAVE_LIBXML2 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_WARNING, "statistics-channels specified but not effective " "due to missing XML library"); #endif for (element = cfg_list_first(statschannellist); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *statschannel; const cfg_obj_t *listenercfg = NULL; statschannel = cfg_listelt_value(element); (void)cfg_map_get(statschannel, "inet", &listenercfg); if (listenercfg == NULL) continue; for (element2 = cfg_list_first(listenercfg); element2 != NULL; element2 = cfg_list_next(element2)) { const cfg_obj_t *listen_params; const cfg_obj_t *obj; isc_sockaddr_t addr; listen_params = cfg_listelt_value(element2); obj = cfg_tuple_get(listen_params, "address"); addr = *cfg_obj_assockaddr(obj); if (isc_sockaddr_getport(&addr) == 0) isc_sockaddr_setport(&addr, NS_STATSCHANNEL_HTTPPORT); isc_sockaddr_format(&addr, socktext, sizeof(socktext)); isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(9), "processing statistics " "channel %s", socktext); update_listener(server, &listener, listen_params, config, &addr, aclconfctx, socktext); if (listener != NULL) { /* * Remove the listener from the old * list, so it won't be shut down. */ ISC_LIST_UNLINK(server->statschannels, listener, link); } else { /* * This is a new listener. */ isc_result_t r; r = add_listener(server, &listener, listen_params, config, &addr, aclconfctx, socktext); if (r != ISC_R_SUCCESS) { cfg_obj_log(listen_params, ns_g_lctx, ISC_LOG_WARNING, "couldn't allocate " "statistics channel" " %s: %s", socktext, isc_result_totext(r)); } } if (listener != NULL) ISC_LIST_APPEND(new_listeners, listener, link); } } } for (listener = ISC_LIST_HEAD(server->statschannels); listener != NULL; listener = listener_next) { listener_next = ISC_LIST_NEXT(listener, link); ISC_LIST_UNLINK(server->statschannels, listener, link); shutdown_listener(listener); } ISC_LIST_APPENDLIST(server->statschannels, new_listeners, link); return (ISC_R_SUCCESS); }
static isc_result_t get_rndckey(isc_mem_t *mctx, controlkeylist_t *keyids) { isc_result_t result; cfg_parser_t *pctx = NULL; cfg_obj_t *config = NULL; const cfg_obj_t *key = NULL; const cfg_obj_t *algobj = NULL; const cfg_obj_t *secretobj = NULL; const char *algstr = NULL; const char *secretstr = NULL; controlkey_t *keyid = NULL; char secret[1024]; unsigned int algtype; isc_buffer_t b; isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_INFO, "configuring command channel from '%s'", ns_g_keyfile); if (! isc_file_exists(ns_g_keyfile)) return (ISC_R_FILENOTFOUND); CHECK(cfg_parser_create(mctx, ns_g_lctx, &pctx)); CHECK(cfg_parse_file(pctx, ns_g_keyfile, &cfg_type_rndckey, &config)); CHECK(cfg_map_get(config, "key", &key)); keyid = isc_mem_get(mctx, sizeof(*keyid)); if (keyid == NULL) CHECK(ISC_R_NOMEMORY); keyid->keyname = isc_mem_strdup(mctx, cfg_obj_asstring(cfg_map_getname(key))); keyid->secret.base = NULL; keyid->secret.length = 0; keyid->algorithm = DST_ALG_UNKNOWN; ISC_LINK_INIT(keyid, link); if (keyid->keyname == NULL) CHECK(ISC_R_NOMEMORY); CHECK(bind9_check_key(key, ns_g_lctx)); (void)cfg_map_get(key, "algorithm", &algobj); (void)cfg_map_get(key, "secret", &secretobj); INSIST(algobj != NULL && secretobj != NULL); algstr = cfg_obj_asstring(algobj); secretstr = cfg_obj_asstring(secretobj); if (ns_config_getkeyalgorithm2(algstr, NULL, &algtype, NULL) != ISC_R_SUCCESS) { cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, "unsupported algorithm '%s' in " "key '%s' for use with command " "channel", algstr, keyid->keyname); goto cleanup; } keyid->algorithm = algtype; isc_buffer_init(&b, secret, sizeof(secret)); result = isc_base64_decodestring(secretstr, &b); if (result != ISC_R_SUCCESS) { cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, "secret for key '%s' on command channel: %s", keyid->keyname, isc_result_totext(result)); goto cleanup; } keyid->secret.length = isc_buffer_usedlength(&b); keyid->secret.base = isc_mem_get(mctx, keyid->secret.length); if (keyid->secret.base == NULL) { cfg_obj_log(key, ns_g_lctx, ISC_LOG_WARNING, "couldn't register key '%s': " "out of memory", keyid->keyname); CHECK(ISC_R_NOMEMORY); } memmove(keyid->secret.base, isc_buffer_base(&b), keyid->secret.length); ISC_LIST_APPEND(*keyids, keyid, link); keyid = NULL; result = ISC_R_SUCCESS; cleanup: if (keyid != NULL) free_controlkey(keyid, mctx); if (config != NULL) cfg_obj_destroy(pctx, &config); if (pctx != NULL) cfg_parser_destroy(&pctx); return (result); }
isc_result_t cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx, isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx, unsigned int nest_level, isc_uint16_t family, dns_acl_t **target) { isc_result_t result; dns_acl_t *dacl = NULL, *inneracl = NULL; dns_aclelement_t *de; const cfg_listelt_t *elt; dns_iptable_t *iptab; int new_nest_level = 0; if (nest_level != 0) new_nest_level = nest_level - 1; REQUIRE(target != NULL); REQUIRE(*target == NULL || DNS_ACL_VALID(*target)); if (*target != NULL) { /* * If target already points to an ACL, then we're being * called recursively to configure a nested ACL. The * nested ACL's contents should just be absorbed into its * parent ACL. */ dns_acl_attach(*target, &dacl); dns_acl_detach(target); } else { /* * Need to allocate a new ACL structure. Count the items * in the ACL definition that will require space in the * elements table. (Note that if nest_level is nonzero, * *everything* goes in the elements table.) */ isc_uint32_t nelem; if (nest_level == 0) { result = count_acl_elements(caml, cctx, lctx, ctx, mctx, &nelem, NULL); if (result != ISC_R_SUCCESS) return (result); } else nelem = cfg_list_length(caml, ISC_FALSE); result = dns_acl_create(mctx, nelem, &dacl); if (result != ISC_R_SUCCESS) return (result); } de = dacl->elements; for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) { const cfg_obj_t *ce = cfg_listelt_value(elt); isc_boolean_t neg = ISC_FALSE; INSIST(dacl->length <= dacl->alloc); if (cfg_obj_istuple(ce)) { /* Might be a negated element */ const cfg_obj_t *negated = cfg_tuple_get(ce, "negated"); if (! cfg_obj_isvoid(negated)) { neg = ISC_TRUE; dacl->has_negatives = ISC_TRUE; ce = negated; } } /* * If nest_level is nonzero, then every element is * to be stored as a separate, nested ACL rather than * merged into the main iptable. */ iptab = dacl->iptable; if (nest_level != 0) { result = dns_acl_create(mctx, cfg_list_length(ce, ISC_FALSE), &de->nestedacl); if (result != ISC_R_SUCCESS) goto cleanup; iptab = de->nestedacl->iptable; } if (cfg_obj_isnetprefix(ce)) { /* Network prefix */ isc_netaddr_t addr; unsigned int bitlen; cfg_obj_asnetprefix(ce, &addr, &bitlen); if (family != 0 && family != addr.family) { char buf[ISC_NETADDR_FORMATSIZE + 1]; isc_netaddr_format(&addr, buf, sizeof(buf)); cfg_obj_log(ce, lctx, ISC_LOG_WARNING, "'%s': incorrect address family; " "ignoring", buf); if (nest_level != 0) dns_acl_detach(&de->nestedacl); continue; } result = isc_netaddr_prefixok(&addr, bitlen); if (result != ISC_R_SUCCESS) { char buf[ISC_NETADDR_FORMATSIZE + 1]; isc_netaddr_format(&addr, buf, sizeof(buf)); cfg_obj_log(ce, lctx, ISC_LOG_WARNING, "'%s/%u': address/prefix length " "mismatch", buf, bitlen); } /* * If nesting ACLs (nest_level != 0), we negate * the nestedacl element, not the iptable entry. */ result = dns_iptable_addprefix(iptab, &addr, bitlen, ISC_TF(nest_level != 0 || !neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (nest_level > 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_nestedacl; de->negative = neg; } else continue; } else if (cfg_obj_islist(ce)) { /* * If we're nesting ACLs, put the nested * ACL onto the elements list; otherwise * merge it into *this* ACL. We nest ACLs * in two cases: 1) sortlist, 2) if the * nested ACL contains negated members. */ if (inneracl != NULL) dns_acl_detach(&inneracl); result = cfg_acl_fromconfig(ce, cctx, lctx, ctx, mctx, new_nest_level, &inneracl); if (result != ISC_R_SUCCESS) goto cleanup; nested_acl: if (nest_level > 0 || inneracl->has_negatives) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_nestedacl; de->negative = neg; if (de->nestedacl != NULL) dns_acl_detach(&de->nestedacl); dns_acl_attach(inneracl, &de->nestedacl); dns_acl_detach(&inneracl); /* Fall through. */ } else { INSIST(dacl->length + inneracl->length <= dacl->alloc); dns_acl_merge(dacl, inneracl, ISC_TF(!neg)); de += inneracl->length; /* elements added */ dns_acl_detach(&inneracl); INSIST(dacl->length <= dacl->alloc); continue; } } else if (cfg_obj_istype(ce, &cfg_type_keyref)) { /* Key name. */ INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_keyname; de->negative = neg; dns_name_init(&de->keyname, NULL); result = convert_keyname(ce, lctx, mctx, &de->keyname); if (result != ISC_R_SUCCESS) goto cleanup; #ifdef HAVE_GEOIP } else if (cfg_obj_istuple(ce) && cfg_obj_isvoid(cfg_tuple_get(ce, "negated"))) { INSIST(dacl->length < dacl->alloc); result = parse_geoip_element(ce, lctx, ctx, de); if (result != ISC_R_SUCCESS) goto cleanup; de->type = dns_aclelementtype_geoip; de->negative = neg; #endif /* HAVE_GEOIP */ } else if (cfg_obj_isstring(ce)) { /* ACL name. */ const char *name = cfg_obj_asstring(ce); if (strcasecmp(name, "any") == 0) { /* Iptable entry with zero bit length. */ result = dns_iptable_addprefix(iptab, NULL, 0, ISC_TF(nest_level != 0 || !neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (nest_level != 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_nestedacl; de->negative = neg; } else continue; } else if (strcasecmp(name, "none") == 0) { /* none == !any */ /* * We don't unconditional set * dacl->has_negatives and * de->negative to true so we can handle * "!none;". */ result = dns_iptable_addprefix(iptab, NULL, 0, ISC_TF(nest_level != 0 || neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (!neg) dacl->has_negatives = !neg; if (nest_level != 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_nestedacl; de->negative = !neg; } else continue; } else if (strcasecmp(name, "localhost") == 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_localhost; de->negative = neg; } else if (strcasecmp(name, "localnets") == 0) { INSIST(dacl->length < dacl->alloc); de->type = dns_aclelementtype_localnets; de->negative = neg; } else { if (inneracl != NULL) dns_acl_detach(&inneracl); /* * This call should just find the cached * of the named acl. */ result = convert_named_acl(ce, cctx, lctx, ctx, mctx, new_nest_level, &inneracl); if (result != ISC_R_SUCCESS) goto cleanup; goto nested_acl; } } else { cfg_obj_log(ce, lctx, ISC_LOG_WARNING, "address match list contains " "unsupported element type"); result = ISC_R_FAILURE; goto cleanup; } /* * This should only be reached for localhost, localnets * and keyname elements, and nested ACLs if nest_level is * nonzero (i.e., in sortlists). */ if (de->nestedacl != NULL && de->type != dns_aclelementtype_nestedacl) dns_acl_detach(&de->nestedacl); dacl->node_count++; de->node_num = dacl->node_count; dacl->length++; de++; INSIST(dacl->length <= dacl->alloc); } dns_acl_attach(dacl, target); result = ISC_R_SUCCESS; cleanup: if (inneracl != NULL) dns_acl_detach(&inneracl); dns_acl_detach(&dacl); return (result); }
isc_result_t ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, isc_mem_t *mctx, isc_sockaddr_t **addrsp, isc_dscp_t **dscpsp, dns_name_t ***keysp, isc_uint32_t *countp) { isc_uint32_t addrcount = 0, dscpcount = 0, keycount = 0, i = 0; isc_uint32_t listcount = 0, l = 0, j; isc_uint32_t stackcount = 0, pushed = 0; isc_result_t result; const cfg_listelt_t *element; const cfg_obj_t *addrlist; const cfg_obj_t *portobj; const cfg_obj_t *dscpobj; in_port_t port; isc_dscp_t dscp = -1; dns_fixedname_t fname; isc_sockaddr_t *addrs = NULL; isc_dscp_t *dscps = NULL; dns_name_t **keys = NULL; struct { const char *name; } *lists = NULL; struct { const cfg_listelt_t *element; in_port_t port; isc_dscp_t dscp; } *stack = NULL; REQUIRE(addrsp != NULL && *addrsp == NULL); REQUIRE(dscpsp != NULL && *dscpsp == NULL); REQUIRE(keysp != NULL && *keysp == NULL); REQUIRE(countp != NULL); /* * Get system defaults. */ result = ns_config_getport(config, &port); if (result != ISC_R_SUCCESS) goto cleanup; result = ns_config_getdscp(config, &dscp); if (result != ISC_R_SUCCESS) goto cleanup; newlist: addrlist = cfg_tuple_get(list, "addresses"); portobj = cfg_tuple_get(list, "port"); dscpobj = cfg_tuple_get(list, "dscp"); if (cfg_obj_isuint32(portobj)) { isc_uint32_t val = cfg_obj_asuint32(portobj); if (val > ISC_UINT16_MAX) { cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR, "port '%u' out of range", val); result = ISC_R_RANGE; goto cleanup; } port = (in_port_t) val; } if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) { if (cfg_obj_asuint32(dscpobj) > 63) { cfg_obj_log(dscpobj, ns_g_lctx, ISC_LOG_ERROR, "dscp value '%u' is out of range", cfg_obj_asuint32(dscpobj)); result = ISC_R_RANGE; goto cleanup; } dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj); } result = ISC_R_NOMEMORY; element = cfg_list_first(addrlist); resume: for ( ; element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *addr; const cfg_obj_t *key; const char *keystr; isc_buffer_t b; addr = cfg_tuple_get(cfg_listelt_value(element), "masterselement"); key = cfg_tuple_get(cfg_listelt_value(element), "key"); if (!cfg_obj_issockaddr(addr)) { const char *listname = cfg_obj_asstring(addr); isc_result_t tresult; /* Grow lists? */ if (listcount == l) { void * tmp; isc_uint32_t newlen = listcount + 16; size_t newsize, oldsize; newsize = newlen * sizeof(*lists); oldsize = listcount * sizeof(*lists); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (listcount != 0) { memmove(tmp, lists, oldsize); isc_mem_put(mctx, lists, oldsize); } lists = tmp; listcount = newlen; } /* Seen? */ for (j = 0; j < l; j++) if (strcasecmp(lists[j].name, listname) == 0) break; if (j < l) continue; tresult = get_masters_def(config, listname, &list); if (tresult == ISC_R_NOTFOUND) { cfg_obj_log(addr, ns_g_lctx, ISC_LOG_ERROR, "masters \"%s\" not found", listname); result = tresult; goto cleanup; } if (tresult != ISC_R_SUCCESS) goto cleanup; lists[l++].name = listname; /* Grow stack? */ if (stackcount == pushed) { void * tmp; isc_uint32_t newlen = stackcount + 16; size_t newsize, oldsize; newsize = newlen * sizeof(*stack); oldsize = stackcount * sizeof(*stack); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (stackcount != 0) { memmove(tmp, stack, oldsize); isc_mem_put(mctx, stack, oldsize); } stack = tmp; stackcount = newlen; } /* * We want to resume processing this list on the * next element. */ stack[pushed].element = cfg_list_next(element); stack[pushed].port = port; stack[pushed].dscp = dscp; pushed++; goto newlist; } if (i == addrcount) { void * tmp; isc_uint32_t newlen = addrcount + 16; size_t newsize, oldsize; newsize = newlen * sizeof(isc_sockaddr_t); oldsize = addrcount * sizeof(isc_sockaddr_t); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (addrcount != 0) { memmove(tmp, addrs, oldsize); isc_mem_put(mctx, addrs, oldsize); } addrs = tmp; addrcount = newlen; newsize = newlen * sizeof(isc_dscp_t); oldsize = dscpcount * sizeof(isc_dscp_t); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (dscpcount != 0) { memmove(tmp, dscps, oldsize); isc_mem_put(mctx, dscps, oldsize); } dscps = tmp; dscpcount = newlen; newsize = newlen * sizeof(dns_name_t *); oldsize = keycount * sizeof(dns_name_t *); tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; if (keycount != 0) { memmove(tmp, keys, oldsize); isc_mem_put(mctx, keys, oldsize); } keys = tmp; keycount = newlen; } addrs[i] = *cfg_obj_assockaddr(addr); if (isc_sockaddr_getport(&addrs[i]) == 0) isc_sockaddr_setport(&addrs[i], port); dscps[i] = cfg_obj_getdscp(addr); if (dscps[i] == -1) dscps[i] = dscp; keys[i] = NULL; i++; /* Increment here so that cleanup on error works. */ if (!cfg_obj_isstring(key)) continue; keys[i - 1] = isc_mem_get(mctx, sizeof(dns_name_t)); if (keys[i - 1] == NULL) goto cleanup; dns_name_init(keys[i - 1], NULL); keystr = cfg_obj_asstring(key); isc_buffer_constinit(&b, keystr, strlen(keystr)); isc_buffer_add(&b, strlen(keystr)); dns_fixedname_init(&fname); result = dns_name_fromtext(dns_fixedname_name(&fname), &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_name_dup(dns_fixedname_name(&fname), mctx, keys[i - 1]); if (result != ISC_R_SUCCESS) goto cleanup; } if (pushed != 0) { pushed--; element = stack[pushed].element; port = stack[pushed].port; dscp = stack[pushed].dscp; goto resume; } if (i < addrcount) { void * tmp; size_t newsize, oldsize; newsize = i * sizeof(isc_sockaddr_t); oldsize = addrcount * sizeof(isc_sockaddr_t); if (i != 0) { tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; memmove(tmp, addrs, newsize); } else tmp = NULL; isc_mem_put(mctx, addrs, oldsize); addrs = tmp; addrcount = i; newsize = i * sizeof(isc_dscp_t); oldsize = dscpcount * sizeof(isc_dscp_t); if (i != 0) { tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; memmove(tmp, dscps, newsize); } else tmp = NULL; isc_mem_put(mctx, dscps, oldsize); dscps = tmp; dscpcount = i; newsize = i * sizeof(dns_name_t *); oldsize = keycount * sizeof(dns_name_t *); if (i != 0) { tmp = isc_mem_get(mctx, newsize); if (tmp == NULL) goto cleanup; memmove(tmp, keys, newsize); } else tmp = NULL; isc_mem_put(mctx, keys, oldsize); keys = tmp; keycount = i; } if (lists != NULL) isc_mem_put(mctx, lists, listcount * sizeof(*lists)); if (stack != NULL) isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); INSIST(keycount == addrcount); *addrsp = addrs; *dscpsp = dscps; *keysp = keys; *countp = addrcount; return (ISC_R_SUCCESS); cleanup: if (addrs != NULL) isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t)); if (dscps != NULL) isc_mem_put(mctx, dscps, dscpcount * sizeof(isc_dscp_t)); if (keys != NULL) { for (j = 0; j < i; j++) { if (keys[j] == NULL) continue; if (dns_name_dynamic(keys[j])) dns_name_free(keys[j], mctx); isc_mem_put(mctx, keys[j], sizeof(dns_name_t)); } isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *)); } if (lists != NULL) isc_mem_put(mctx, lists, listcount * sizeof(*lists)); if (stack != NULL) isc_mem_put(mctx, stack, stackcount * sizeof(*stack)); return (result); }
static void add_listener(ns_controls_t *cp, controllistener_t **listenerp, const cfg_obj_t *control, const cfg_obj_t *config, isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, const char *socktext, isc_sockettype_t type) { isc_mem_t *mctx = cp->server->mctx; controllistener_t *listener; const cfg_obj_t *allow; const cfg_obj_t *global_keylist = NULL; const cfg_obj_t *control_keylist = NULL; dns_acl_t *new_acl = NULL; isc_result_t result = ISC_R_SUCCESS; listener = isc_mem_get(mctx, sizeof(*listener)); if (listener == NULL) result = ISC_R_NOMEMORY; if (result == ISC_R_SUCCESS) { listener->mctx = NULL; isc_mem_attach(mctx, &listener->mctx); listener->controls = cp; listener->task = cp->server->task; listener->address = *addr; listener->sock = NULL; listener->listening = ISC_FALSE; listener->exiting = ISC_FALSE; listener->acl = NULL; listener->type = type; listener->perm = 0; listener->owner = 0; listener->group = 0; ISC_LINK_INIT(listener, link); ISC_LIST_INIT(listener->keys); ISC_LIST_INIT(listener->connections); /* * Make the acl. */ if (control != NULL && type == isc_sockettype_tcp) { allow = cfg_tuple_get(control, "allow"); result = cfg_acl_fromconfig(allow, config, ns_g_lctx, aclconfctx, mctx, 0, &new_acl); } else { result = dns_acl_any(mctx, &new_acl); } } if (result == ISC_R_SUCCESS) { dns_acl_attach(new_acl, &listener->acl); dns_acl_detach(&new_acl); if (config != NULL) get_key_info(config, control, &global_keylist, &control_keylist); if (control_keylist != NULL) { result = controlkeylist_fromcfg(control_keylist, listener->mctx, &listener->keys); if (result == ISC_R_SUCCESS) register_keys(control, global_keylist, &listener->keys, listener->mctx, socktext); } else result = get_rndckey(mctx, &listener->keys); if (result != ISC_R_SUCCESS && control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't install keys for " "command channel %s: %s", socktext, isc_result_totext(result)); } if (result == ISC_R_SUCCESS) { int pf = isc_sockaddr_pf(&listener->address); if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || #ifdef ISC_PLATFORM_HAVESYSUNH (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) || #endif (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) result = ISC_R_FAMILYNOSUPPORT; } if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) isc_socket_cleanunix(&listener->address, ISC_FALSE); if (result == ISC_R_SUCCESS) result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(&listener->address), type, &listener->sock); if (result == ISC_R_SUCCESS) isc_socket_setname(listener->sock, "control", NULL); #ifndef ISC_ALLOW_MAPPED if (result == ISC_R_SUCCESS) isc_socket_ipv6only(listener->sock, ISC_TRUE); #endif if (result == ISC_R_SUCCESS) result = isc_socket_bind(listener->sock, &listener->address, ISC_SOCKET_REUSEADDRESS); if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { listener->perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); listener->owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); listener->group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); result = isc_socket_permunix(&listener->address, listener->perm, listener->owner, listener->group); } if (result == ISC_R_SUCCESS) result = control_listen(listener); if (result == ISC_R_SUCCESS) result = control_accept(listener); if (result == ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, "command channel listening on %s", socktext); *listenerp = listener; } else { if (listener != NULL) { listener->exiting = ISC_TRUE; free_listener(listener); } if (control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't add command channel %s: %s", socktext, isc_result_totext(result)); else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, "couldn't add command channel %s: %s", socktext, isc_result_totext(result)); *listenerp = NULL; } /* XXXDCL return error results? fail hard? */ }
/*% * Parse the zone update-policy statement. */ static isc_result_t configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone, const char *zname) { const cfg_obj_t *updatepolicy = NULL; const cfg_listelt_t *element, *element2; dns_ssutable_t *table = NULL; isc_mem_t *mctx = dns_zone_getmctx(zone); isc_boolean_t autoddns = ISC_FALSE; isc_result_t result; (void)cfg_map_get(zconfig, "update-policy", &updatepolicy); if (updatepolicy == NULL) { dns_zone_setssutable(zone, NULL); return (ISC_R_SUCCESS); } if (cfg_obj_isstring(updatepolicy) && strcmp("local", cfg_obj_asstring(updatepolicy)) == 0) { autoddns = ISC_TRUE; updatepolicy = NULL; } result = dns_ssutable_create(mctx, &table); if (result != ISC_R_SUCCESS) return (result); for (element = cfg_list_first(updatepolicy); element != NULL; element = cfg_list_next(element)) { const cfg_obj_t *stmt = cfg_listelt_value(element); const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode"); const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity"); const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype"); const cfg_obj_t *dname = cfg_tuple_get(stmt, "name"); const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types"); const char *str; isc_boolean_t grant = ISC_FALSE; isc_boolean_t usezone = ISC_FALSE; unsigned int mtype = DNS_SSUMATCHTYPE_NAME; dns_fixedname_t fname, fident; isc_buffer_t b; dns_rdatatype_t *types; unsigned int i, n; str = cfg_obj_asstring(mode); if (strcasecmp(str, "grant") == 0) grant = ISC_TRUE; else if (strcasecmp(str, "deny") == 0) grant = ISC_FALSE; else INSIST(0); str = cfg_obj_asstring(matchtype); if (strcasecmp(str, "name") == 0) mtype = DNS_SSUMATCHTYPE_NAME; else if (strcasecmp(str, "subdomain") == 0) mtype = DNS_SSUMATCHTYPE_SUBDOMAIN; else if (strcasecmp(str, "wildcard") == 0) mtype = DNS_SSUMATCHTYPE_WILDCARD; else if (strcasecmp(str, "self") == 0) mtype = DNS_SSUMATCHTYPE_SELF; else if (strcasecmp(str, "selfsub") == 0) mtype = DNS_SSUMATCHTYPE_SELFSUB; else if (strcasecmp(str, "selfwild") == 0) mtype = DNS_SSUMATCHTYPE_SELFWILD; else if (strcasecmp(str, "ms-self") == 0) mtype = DNS_SSUMATCHTYPE_SELFMS; else if (strcasecmp(str, "krb5-self") == 0) mtype = DNS_SSUMATCHTYPE_SELFKRB5; else if (strcasecmp(str, "ms-subdomain") == 0) mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS; else if (strcasecmp(str, "krb5-subdomain") == 0) mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5; else if (strcasecmp(str, "tcp-self") == 0) mtype = DNS_SSUMATCHTYPE_TCPSELF; else if (strcasecmp(str, "6to4-self") == 0) mtype = DNS_SSUMATCHTYPE_6TO4SELF; else if (strcasecmp(str, "zonesub") == 0) { mtype = DNS_SSUMATCHTYPE_SUBDOMAIN; usezone = ISC_TRUE; } else if (strcasecmp(str, "external") == 0) mtype = DNS_SSUMATCHTYPE_EXTERNAL; else INSIST(0); dns_fixedname_init(&fident); str = cfg_obj_asstring(identity); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); result = dns_name_fromtext(dns_fixedname_name(&fident), &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid name", str); goto cleanup; } dns_fixedname_init(&fname); if (usezone) { result = dns_name_copy(dns_zone_getorigin(zone), dns_fixedname_name(&fname), NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "error copying origin: %s", isc_result_totext(result)); goto cleanup; } } else { str = cfg_obj_asstring(dname); isc_buffer_init(&b, str, strlen(str)); isc_buffer_add(&b, strlen(str)); result = dns_name_fromtext(dns_fixedname_name(&fname), &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid name", str); goto cleanup; } } n = ns_config_listcount(typelist); if (n == 0) types = NULL; else { types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t)); if (types == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } i = 0; for (element2 = cfg_list_first(typelist); element2 != NULL; element2 = cfg_list_next(element2)) { const cfg_obj_t *typeobj; isc_textregion_t r; INSIST(i < n); typeobj = cfg_listelt_value(element2); str = cfg_obj_asstring(typeobj); DE_CONST(str, r.base); r.length = strlen(str); result = dns_rdatatype_fromtext(&types[i++], &r); if (result != ISC_R_SUCCESS) { cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR, "'%s' is not a valid type", str); isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t)); goto cleanup; } } INSIST(i == n); result = dns_ssutable_addrule(table, grant, dns_fixedname_name(&fident), mtype, dns_fixedname_name(&fname), n, types); if (types != NULL) isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t)); if (result != ISC_R_SUCCESS) { goto cleanup; } } /* * If "update-policy local;" and a session key exists, * then use the default policy, which is equivalent to: * update-policy { grant <session-keyname> zonesub any; }; */ if (autoddns) { dns_rdatatype_t any = dns_rdatatype_any; if (ns_g_server->session_keyname == NULL) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, "failed to enable auto DDNS policy " "for zone %s: session key not found", zname); result = ISC_R_NOTFOUND; goto cleanup; } result = dns_ssutable_addrule(table, ISC_TRUE, ns_g_server->session_keyname, DNS_SSUMATCHTYPE_SUBDOMAIN, dns_zone_getorigin(zone), 1, &any); if (result != ISC_R_SUCCESS) goto cleanup; } result = ISC_R_SUCCESS; dns_zone_setssutable(zone, table); cleanup: dns_ssutable_detach(&table); return (result); }
static void register_keys(const cfg_obj_t *control, const cfg_obj_t *keylist, controlkeylist_t *keyids, isc_mem_t *mctx, const char *socktext) { controlkey_t *keyid, *next; const cfg_obj_t *keydef; char secret[1024]; isc_buffer_t b; isc_result_t result; /* * Find the keys corresponding to the keyids used by this listener. */ for (keyid = ISC_LIST_HEAD(*keyids); keyid != NULL; keyid = next) { next = ISC_LIST_NEXT(keyid, link); result = cfgkeylist_find(keylist, keyid->keyname, &keydef); if (result != ISC_R_SUCCESS) { cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't find key '%s' for use with " "command channel %s", keyid->keyname, socktext); ISC_LIST_UNLINK(*keyids, keyid, link); free_controlkey(keyid, mctx); } else { const cfg_obj_t *algobj = NULL; const cfg_obj_t *secretobj = NULL; const char *algstr = NULL; const char *secretstr = NULL; unsigned int algtype; (void)cfg_map_get(keydef, "algorithm", &algobj); (void)cfg_map_get(keydef, "secret", &secretobj); INSIST(algobj != NULL && secretobj != NULL); algstr = cfg_obj_asstring(algobj); secretstr = cfg_obj_asstring(secretobj); if (ns_config_getkeyalgorithm2(algstr, NULL, &algtype, NULL) != ISC_R_SUCCESS) { cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "unsupported algorithm '%s' in " "key '%s' for use with command " "channel %s", algstr, keyid->keyname, socktext); ISC_LIST_UNLINK(*keyids, keyid, link); free_controlkey(keyid, mctx); continue; } keyid->algorithm = algtype; isc_buffer_init(&b, secret, sizeof(secret)); result = isc_base64_decodestring(secretstr, &b); if (result != ISC_R_SUCCESS) { cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, "secret for key '%s' on " "command channel %s: %s", keyid->keyname, socktext, isc_result_totext(result)); ISC_LIST_UNLINK(*keyids, keyid, link); free_controlkey(keyid, mctx); continue; } keyid->secret.length = isc_buffer_usedlength(&b); keyid->secret.base = isc_mem_get(mctx, keyid->secret.length); if (keyid->secret.base == NULL) { cfg_obj_log(keydef, ns_g_lctx, ISC_LOG_WARNING, "couldn't register key '%s': " "out of memory", keyid->keyname); ISC_LIST_UNLINK(*keyids, keyid, link); free_controlkey(keyid, mctx); break; } memmove(keyid->secret.base, isc_buffer_base(&b), keyid->secret.length); } } }
isc_result_t ns_acl_fromconfig(cfg_obj_t *caml, cfg_obj_t *cctx, ns_aclconfctx_t *ctx, isc_mem_t *mctx, dns_acl_t **target) { isc_result_t result; unsigned int count; dns_acl_t *dacl = NULL; dns_aclelement_t *de; cfg_listelt_t *elt; REQUIRE(target != NULL && *target == NULL); count = 0; for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) count++; result = dns_acl_create(mctx, count, &dacl); if (result != ISC_R_SUCCESS) return (result); de = dacl->elements; for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) { cfg_obj_t *ce = cfg_listelt_value(elt); if (cfg_obj_istuple(ce)) { /* This must be a negated element. */ ce = cfg_tuple_get(ce, "value"); de->negative = ISC_TRUE; } else { de->negative = ISC_FALSE; } if (cfg_obj_isnetprefix(ce)) { /* Network prefix */ de->type = dns_aclelementtype_ipprefix; cfg_obj_asnetprefix(ce, &de->u.ip_prefix.address, &de->u.ip_prefix.prefixlen); } else if (cfg_obj_istype(ce, &cfg_type_keyref)) { /* Key name */ de->type = dns_aclelementtype_keyname; dns_name_init(&de->u.keyname, NULL); result = convert_keyname(ce, mctx, &de->u.keyname); if (result != ISC_R_SUCCESS) goto cleanup; } else if (cfg_obj_islist(ce)) { /* Nested ACL */ de->type = dns_aclelementtype_nestedacl; result = ns_acl_fromconfig(ce, cctx, ctx, mctx, &de->u.nestedacl); if (result != ISC_R_SUCCESS) goto cleanup; } else if (cfg_obj_isstring(ce)) { /* ACL name */ char *name = cfg_obj_asstring(ce); if (strcasecmp(name, "localhost") == 0) { de->type = dns_aclelementtype_localhost; } else if (strcasecmp(name, "localnets") == 0) { de->type = dns_aclelementtype_localnets; } else if (strcasecmp(name, "any") == 0) { de->type = dns_aclelementtype_any; } else if (strcasecmp(name, "none") == 0) { de->type = dns_aclelementtype_any; de->negative = ISC_TF(! de->negative); } else { de->type = dns_aclelementtype_nestedacl; result = convert_named_acl(ce, cctx, ctx, mctx, &de->u.nestedacl); if (result != ISC_R_SUCCESS) goto cleanup; } } else { cfg_obj_log(ce, dns_lctx, ISC_LOG_WARNING, "address match list contains " "unsupported element type"); result = ISC_R_FAILURE; goto cleanup; } de++; dacl->length++; } *target = dacl; return (ISC_R_SUCCESS); cleanup: dns_acl_detach(&dacl); return (result); }
static void update_listener(ns_controls_t *cp, controllistener_t **listenerp, const cfg_obj_t *control, const cfg_obj_t *config, isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, const char *socktext, isc_sockettype_t type) { controllistener_t *listener; const cfg_obj_t *allow; const cfg_obj_t *global_keylist = NULL; const cfg_obj_t *control_keylist = NULL; dns_acl_t *new_acl = NULL; controlkeylist_t keys; isc_result_t result = ISC_R_SUCCESS; for (listener = ISC_LIST_HEAD(cp->listeners); listener != NULL; listener = ISC_LIST_NEXT(listener, link)) if (isc_sockaddr_equal(addr, &listener->address)) break; if (listener == NULL) { *listenerp = NULL; return; } /* * There is already a listener for this sockaddr. * Update the access list and key information. * * First try to deal with the key situation. There are a few * possibilities: * (a) It had an explicit keylist and still has an explicit keylist. * (b) It had an automagic key and now has an explicit keylist. * (c) It had an explicit keylist and now needs an automagic key. * (d) It has an automagic key and still needs the automagic key. * * (c) and (d) are the annoying ones. The caller needs to know * that it should use the automagic configuration for key information * in place of the named.conf configuration. * * XXXDCL There is one other hazard that has not been dealt with, * the problem that if a key change is being caused by a control * channel reload, then the response will be with the new key * and not able to be decrypted by the client. */ if (control != NULL) get_key_info(config, control, &global_keylist, &control_keylist); if (control_keylist != NULL) { INSIST(global_keylist != NULL); ISC_LIST_INIT(keys); result = controlkeylist_fromcfg(control_keylist, listener->mctx, &keys); if (result == ISC_R_SUCCESS) { free_controlkeylist(&listener->keys, listener->mctx); listener->keys = keys; register_keys(control, global_keylist, &listener->keys, listener->mctx, socktext); } } else { free_controlkeylist(&listener->keys, listener->mctx); result = get_rndckey(listener->mctx, &listener->keys); } if (result != ISC_R_SUCCESS && global_keylist != NULL) { /* * This message might be a little misleading since the * "new keys" might in fact be identical to the old ones, * but tracking whether they are identical just for the * sake of avoiding this message would be too much trouble. */ if (control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't install new keys for " "command channel %s: %s", socktext, isc_result_totext(result)); else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, "couldn't install new keys for " "command channel %s: %s", socktext, isc_result_totext(result)); } /* * Now, keep the old access list unless a new one can be made. */ if (control != NULL && type == isc_sockettype_tcp) { allow = cfg_tuple_get(control, "allow"); result = cfg_acl_fromconfig(allow, config, ns_g_lctx, aclconfctx, listener->mctx, 0, &new_acl); } else { result = dns_acl_any(listener->mctx, &new_acl); } if (result == ISC_R_SUCCESS) { dns_acl_detach(&listener->acl); dns_acl_attach(new_acl, &listener->acl); dns_acl_detach(&new_acl); /* XXXDCL say the old acl is still used? */ } else if (control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't install new acl for " "command channel %s: %s", socktext, isc_result_totext(result)); else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_WARNING, "couldn't install new acl for " "command channel %s: %s", socktext, isc_result_totext(result)); if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { isc_uint32_t perm, owner, group; perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); result = ISC_R_SUCCESS; if (listener->perm != perm || listener->owner != owner || listener->group != group) result = isc_socket_permunix(&listener->address, perm, owner, group); if (result == ISC_R_SUCCESS) { listener->perm = perm; listener->owner = owner; listener->group = group; } else if (control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't update ownership/permission for " "command channel %s", socktext); } *listenerp = listener; }
isc_result_t cfg_acl_fromconfig(const cfg_obj_t *caml, const cfg_obj_t *cctx, isc_log_t *lctx, cfg_aclconfctx_t *ctx, isc_mem_t *mctx, unsigned int nest_level, dns_acl_t **target) { isc_result_t result; dns_acl_t *dacl = NULL, *inneracl = NULL; dns_aclelement_t *de; const cfg_listelt_t *elt; dns_iptable_t *iptab; int new_nest_level = 0; if (nest_level != 0) new_nest_level = nest_level - 1; REQUIRE(target != NULL); REQUIRE(*target == NULL || DNS_ACL_VALID(*target)); if (*target != NULL) { /* * If target already points to an ACL, then we're being * called recursively to configure a nested ACL. The * nested ACL's contents should just be absorbed into its * parent ACL. */ dns_acl_attach(*target, &dacl); dns_acl_detach(target); } else { /* * Need to allocate a new ACL structure. Count the items * in the ACL definition that will require space in the * elements table. (Note that if nest_level is nonzero, * *everything* goes in the elements table.) */ int nelem; if (nest_level == 0) nelem = count_acl_elements(caml, cctx, NULL); else nelem = cfg_list_length(caml, ISC_FALSE); result = dns_acl_create(mctx, nelem, &dacl); if (result != ISC_R_SUCCESS) return (result); } de = dacl->elements; for (elt = cfg_list_first(caml); elt != NULL; elt = cfg_list_next(elt)) { const cfg_obj_t *ce = cfg_listelt_value(elt); isc_boolean_t neg; if (cfg_obj_istuple(ce)) { /* This must be a negated element. */ ce = cfg_tuple_get(ce, "value"); neg = ISC_TRUE; dacl->has_negatives = ISC_TRUE; } else neg = ISC_FALSE; /* * If nest_level is nonzero, then every element is * to be stored as a separate, nested ACL rather than * merged into the main iptable. */ iptab = dacl->iptable; if (nest_level != 0) { result = dns_acl_create(mctx, cfg_list_length(ce, ISC_FALSE), &de->nestedacl); if (result != ISC_R_SUCCESS) goto cleanup; iptab = de->nestedacl->iptable; } if (cfg_obj_isnetprefix(ce)) { /* Network prefix */ isc_netaddr_t addr; unsigned int bitlen; cfg_obj_asnetprefix(ce, &addr, &bitlen); /* * If nesting ACLs (nest_level != 0), we negate * the nestedacl element, not the iptable entry. */ result = dns_iptable_addprefix(iptab, &addr, bitlen, ISC_TF(nest_level != 0 || !neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (nest_level > 0) { de->type = dns_aclelementtype_nestedacl; de->negative = neg; } else continue; } else if (cfg_obj_islist(ce)) { /* * If we're nesting ACLs, put the nested * ACL onto the elements list; otherwise * merge it into *this* ACL. We nest ACLs * in two cases: 1) sortlist, 2) if the * nested ACL contains negated members. */ if (inneracl != NULL) dns_acl_detach(&inneracl); result = cfg_acl_fromconfig(ce, cctx, lctx, ctx, mctx, new_nest_level, &inneracl); if (result != ISC_R_SUCCESS) goto cleanup; nested_acl: if (nest_level > 0 || inneracl->has_negatives) { de->type = dns_aclelementtype_nestedacl; de->negative = neg; if (de->nestedacl != NULL) dns_acl_detach(&de->nestedacl); dns_acl_attach(inneracl, &de->nestedacl); dns_acl_detach(&inneracl); /* Fall through. */ } else { dns_acl_merge(dacl, inneracl, ISC_TF(!neg)); de += inneracl->length; /* elements added */ dns_acl_detach(&inneracl); continue; } } else if (cfg_obj_istype(ce, &cfg_type_keyref)) { /* Key name. */ de->type = dns_aclelementtype_keyname; de->negative = neg; dns_name_init(&de->keyname, NULL); result = convert_keyname(ce, lctx, mctx, &de->keyname); if (result != ISC_R_SUCCESS) goto cleanup; } else if (cfg_obj_isstring(ce)) { /* ACL name. */ const char *name = cfg_obj_asstring(ce); if (strcasecmp(name, "any") == 0) { /* Iptable entry with zero bit length. */ result = dns_iptable_addprefix(iptab, NULL, 0, ISC_TF(nest_level != 0 || !neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (nest_level != 0) { de->type = dns_aclelementtype_nestedacl; de->negative = neg; } else continue; } else if (strcasecmp(name, "none") == 0) { /* none == !any */ /* * We don't unconditional set * dacl->has_negatives and * de->negative to true so we can handle * "!none;". */ result = dns_iptable_addprefix(iptab, NULL, 0, ISC_TF(nest_level != 0 || neg)); if (result != ISC_R_SUCCESS) goto cleanup; if (!neg) dacl->has_negatives = !neg; if (nest_level != 0) { de->type = dns_aclelementtype_nestedacl; de->negative = !neg; } else continue; #ifdef SUPPORT_GEOIP } else if ((0 == (strncmp("country_", name, 8))) && (10 == strlen(name))) { /* It is a country code */ de->type = dns_aclelementtype_ipcountry; de->country[0] = name[8]; de->country[1] = name[9]; de->country[2] = '\0'; #endif } else if (strcasecmp(name, "localhost") == 0) { de->type = dns_aclelementtype_localhost; de->negative = neg; } else if (strcasecmp(name, "localnets") == 0) { de->type = dns_aclelementtype_localnets; de->negative = neg; } else { if (inneracl != NULL) dns_acl_detach(&inneracl); result = convert_named_acl(ce, cctx, lctx, ctx, mctx, new_nest_level, &inneracl); if (result != ISC_R_SUCCESS) goto cleanup; goto nested_acl; } } else { cfg_obj_log(ce, lctx, ISC_LOG_WARNING, "address match list contains " "unsupported element type"); result = ISC_R_FAILURE; goto cleanup; } /* * This should only be reached for localhost, localnets * and keyname elements, and nested ACLs if nest_level is * nonzero (i.e., in sortlists). */ if (de->nestedacl != NULL && de->type != dns_aclelementtype_nestedacl) dns_acl_detach(&de->nestedacl); dacl->node_count++; de->node_num = dacl->node_count; dacl->length++; de++; INSIST(dacl->length <= dacl->alloc); } dns_acl_attach(dacl, target); result = ISC_R_SUCCESS; cleanup: if (inneracl != NULL) dns_acl_detach(&inneracl); dns_acl_detach(&dacl); return (result); }