2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 01:59:26 +00:00

Add support for zone templates

A "template" statement can contain the same configuration clauses
as a "zone" statement.  A "zone" statement can now reference a
template, and all the clauses in that template will be used as
default values for the zone. For example:

    template primary {
        type primary;
        file "$name.db";
        initial-file "primary.db";
    };

    zone example.com {
        template primary;
        file "different-name.db"; // overrides the template
    };
This commit is contained in:
Evan Hunt 2025-04-15 13:39:57 -07:00
parent 598ae3f63c
commit b8f325ae01
30 changed files with 742 additions and 207 deletions

View File

@ -387,6 +387,23 @@ named_config_get(cfg_obj_t const *const *maps, const char *name,
return ISC_R_NOTFOUND;
}
isc_result_t
named_config_findopt(const cfg_obj_t *opts1, const cfg_obj_t *opts2,
const char *name, const cfg_obj_t **objp) {
isc_result_t result = ISC_R_NOTFOUND;
REQUIRE(*objp == NULL);
if (opts1 != NULL) {
result = cfg_map_get(opts1, name, objp);
}
if (*objp == NULL && opts2 != NULL) {
result = cfg_map_get(opts2, name, objp);
}
return result;
}
isc_result_t
named_checknames_get(const cfg_obj_t **maps, const char *const names[],
const cfg_obj_t **obj) {

View File

@ -67,3 +67,7 @@ named_config_getport(const cfg_obj_t *config, const char *type,
isc_result_t
named_config_getkeyalgorithm(const char *str, unsigned int *typep,
uint16_t *digestbits);
isc_result_t
named_config_findopt(const cfg_obj_t *opts1, const cfg_obj_t *opts2,
const char *name, const cfg_obj_t **objp);

View File

@ -63,7 +63,7 @@ named_zone_inlinesigning(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
isc_result_t
named_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone,
dns_rdataclass_t rdclass, dns_name_t *name);
/*%>
/*%<
* configure a DLZ zone, setting up the database methods and calling
* postload to load the origin values
*
@ -73,3 +73,11 @@ named_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone,
* \li 'rdclass' to be a valid rdataclass
* \li 'name' to be a valid zone origin name
*/
const cfg_obj_t *
named_zone_templateopts(const cfg_obj_t *config, const cfg_obj_t *zoptions);
/*%<
* If a zone with options `zoptions` specifies a zone template, look
* the template options and return them. If no such template is found,
* return NULL.
*/

View File

@ -3097,12 +3097,12 @@ cleanup:
static isc_result_t
create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
const cfg_obj_t *zonelist, const char **empty_dbtype,
int empty_dbtypec, dns_zonestat_level_t statlevel) {
const cfg_obj_t *config, const cfg_obj_t *voptions,
const char **empty_dbtype, int empty_dbtypec,
dns_zonestat_level_t statlevel) {
char namebuf[DNS_NAME_FORMATSIZE];
const cfg_obj_t *obj = NULL;
const cfg_obj_t *zconfig = NULL;
const cfg_obj_t *zoptions = NULL;
const cfg_obj_t *zonelist = NULL;
const char *default_dbtype[4] = { ZONEDB_DEFAULT };
const char *sep = ": view ";
const char *str = NULL;
@ -3126,12 +3126,20 @@ create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
ns = dns_fixedname_initname(&nsfixed);
contact = dns_fixedname_initname(&cfixed);
if (voptions != NULL) {
(void)cfg_map_get(voptions, "zone", &zonelist);
} else {
(void)cfg_map_get(config, "zone", &zonelist);
}
/*
* Look for forward "zones" beneath this empty zone and if so
* create a custom db for the empty zone.
*/
CFG_LIST_FOREACH (zonelist, element) {
zconfig = cfg_listelt_value(element);
const cfg_obj_t *zconfig = cfg_listelt_value(element);
const cfg_obj_t *zoptions = cfg_tuple_get(zconfig, "options");
const cfg_obj_t *toptions = NULL;
str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
CHECK(dns_name_fromstring(zname, str, dns_rootname, 0, NULL));
namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
@ -3139,15 +3147,16 @@ create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
continue;
}
zoptions = cfg_tuple_get(zconfig, "options");
toptions = named_zone_templateopts(config, zoptions);
obj = NULL;
(void)cfg_map_get(zoptions, "type", &obj);
(void)named_config_findopt(zoptions, toptions, "type", &obj);
if (obj != NULL &&
strcasecmp(cfg_obj_asstring(obj), "forward") == 0)
{
obj = NULL;
(void)cfg_map_get(zoptions, "forward", &obj);
(void)named_config_findopt(zoptions, toptions,
"forward", &obj);
if (obj == NULL) {
continue;
}
@ -5468,9 +5477,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
dns_view_detach(&pview);
}
CHECK(create_empty_zone(zone, name, view, zonelist,
empty_dbtype, empty_dbtypec,
statlevel));
CHECK(create_empty_zone(zone, name, view, config,
voptions, empty_dbtype,
empty_dbtypec, statlevel));
if (zone != NULL) {
dns_zone_detach(&zone);
}
@ -6151,6 +6160,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
dns_zone_t *dupzone = NULL;
const cfg_obj_t *options = NULL;
const cfg_obj_t *zoptions = NULL;
const cfg_obj_t *toptions = NULL;
const cfg_obj_t *typeobj = NULL;
const cfg_obj_t *forwarders = NULL;
const cfg_obj_t *forwardtype = NULL;
@ -6160,10 +6170,10 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
isc_result_t tresult;
isc_buffer_t buffer;
dns_fixedname_t fixorigin;
dns_name_t *origin;
const char *zname;
dns_name_t *origin = NULL;
const char *zname = NULL;
dns_rdataclass_t zclass;
const char *ztypestr;
const char *ztypestr = NULL;
dns_rpz_num_t rpz_num;
bool zone_is_catz = false;
bool zone_maybe_inline = false;
@ -6174,6 +6184,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
(void)cfg_map_get(config, "options", &options);
zoptions = cfg_tuple_get(zconfig, "options");
toptions = named_zone_templateopts(config, zoptions);
/*
* Get the zone origin as a dns_name_t.
@ -6258,7 +6269,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
goto cleanup;
}
(void)cfg_map_get(zoptions, "type", &typeobj);
(void)named_config_findopt(zoptions, toptions, "type", &typeobj);
if (typeobj == NULL) {
cfg_obj_log(zconfig, ISC_LOG_ERROR,
"zone '%s' 'type' not specified", zname);
@ -6273,7 +6284,9 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
*/
if (strcasecmp(ztypestr, "hint") == 0) {
const cfg_obj_t *fileobj = NULL;
if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
(void)named_config_findopt(zoptions, toptions, "file",
&fileobj);
if (fileobj == NULL) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
"zone '%s': 'file' not specified", zname);
@ -6303,8 +6316,10 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
forwardtype = NULL;
forwarders = NULL;
(void)cfg_map_get(zoptions, "forward", &forwardtype);
(void)cfg_map_get(zoptions, "forwarders", &forwarders);
(void)named_config_findopt(zoptions, toptions, "forward",
&forwardtype);
(void)named_config_findopt(zoptions, toptions, "forwarders",
&forwarders);
CHECK(configure_forward(config, view, origin, forwarders,
forwardtype));
goto cleanup;
@ -6463,9 +6478,11 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
* selective forwarding.
*/
forwarders = NULL;
if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS) {
named_config_findopt(zoptions, toptions, "forwarders", &forwarders);
if (forwarders != NULL) {
forwardtype = NULL;
(void)cfg_map_get(zoptions, "forward", &forwardtype);
named_config_findopt(zoptions, toptions, "forward",
&forwardtype);
CHECK(configure_forward(config, view, origin, forwarders,
forwardtype));
}
@ -6497,9 +6514,9 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
dns_zone_setstats(raw, named_g_server->zonestats);
CHECK(dns_zone_link(zone, raw));
}
if (cfg_map_get(zoptions, "ixfr-from-differences",
&ixfrfromdiffs) == ISC_R_SUCCESS)
{
named_config_findopt(zoptions, toptions,
"ixfr-from-differences", &ixfrfromdiffs);
if (ixfrfromdiffs != NULL) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
"zone '%s': 'ixfr-from-differences' is "
@ -12459,11 +12476,9 @@ nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
}
} else {
/* We're creating or overwriting the zone */
const cfg_obj_t *zoptions;
const cfg_obj_t *zoptions = cfg_tuple_get(zconfig, "options");
isc_buffer_allocate(view->mctx, &text, 256);
zoptions = cfg_tuple_get(zconfig, "options");
if (zoptions == NULL) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
@ -12785,16 +12800,14 @@ load_nzf(dns_view_t *view, ns_cfgctx_t *nzcfg) {
isc_buffer_allocate(view->mctx, &text, 256);
CFG_LIST_FOREACH (zonelist, element) {
const cfg_obj_t *zconfig;
const cfg_obj_t *zconfig = cfg_listelt_value(element);
const cfg_obj_t *zoptions;
char zname[DNS_NAME_FORMATSIZE];
dns_fixedname_t fname;
dns_name_t *name;
const char *origin;
dns_name_t *name = NULL;
const char *origin = NULL;
isc_buffer_t b;
zconfig = cfg_listelt_value(element);
origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
if (origin == NULL) {
result = ISC_R_FAILURE;
@ -12943,10 +12956,15 @@ newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
if (obj != NULL) {
(void)putstr(text, "'in-view' zones not supported by ");
(void)putstr(text, bn);
} else {
(void)putstr(text, "zone type not specified");
CHECK(ISC_R_FAILURE);
}
(void)cfg_map_get(zoptions, "template", &obj);
if (obj == NULL) {
(void)putstr(text, "no zone type or "
"template specified");
CHECK(ISC_R_FAILURE);
}
CHECK(ISC_R_FAILURE);
}
if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
@ -13518,14 +13536,12 @@ named_server_changezone(named_server_t *server, char *command,
(void)putstr(text, "Not allowing new zones in view '");
(void)putstr(text, view->name);
(void)putstr(text, "'");
result = ISC_R_NOPERM;
goto cleanup;
CHECK(ISC_R_NOPERM);
}
cfg = (ns_cfgctx_t *)view->new_zone_config;
if (cfg == NULL) {
result = ISC_R_FAILURE;
goto cleanup;
CHECK(ISC_R_FAILURE);
}
zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
@ -13922,12 +13938,16 @@ find_name_in_list_from_map(const cfg_obj_t *config,
if (result == ISC_R_SUCCESS &&
dns_name_equal(name1, name2))
{
const cfg_obj_t *zoptions;
const cfg_obj_t *zoptions =
cfg_tuple_get(obj, "options");
const cfg_obj_t *typeobj = NULL;
zoptions = cfg_tuple_get(obj, "options");
if (zoptions != NULL) {
cfg_map_get(zoptions, "type", &typeobj);
const cfg_obj_t *toptions =
named_zone_templateopts(
config, zoptions);
named_config_findopt(zoptions, toptions,
"type", &typeobj);
}
if (redirect && typeobj != NULL &&
strcasecmp(cfg_obj_asstring(typeobj),

View File

@ -77,12 +77,12 @@ configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
void (*setzacl)(dns_zone_t *, dns_acl_t *),
void (*clearzacl)(dns_zone_t *)) {
isc_result_t result;
const cfg_obj_t *maps[5] = { NULL, NULL, NULL, NULL, NULL };
const cfg_obj_t *maps[6] = { 0 };
const cfg_obj_t *aclobj = NULL;
int i = 0;
dns_acl_t **aclp = NULL, *acl = NULL;
const char *aclname;
dns_view_t *view;
dns_view_t *view = NULL;
view = dns_zone_getview(zone);
@ -129,7 +129,7 @@ configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
/* First check to see if ACL is defined within the zone */
if (zconfig != NULL) {
maps[0] = cfg_tuple_get(zconfig, "options");
maps[i] = cfg_tuple_get(zconfig, "options");
(void)named_config_get(maps, aclname, &aclobj);
if (aclobj != NULL) {
aclp = NULL;
@ -137,6 +137,14 @@ configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
}
}
if (config != NULL && maps[i] != NULL) {
const cfg_obj_t *toptions = named_zone_templateopts(config,
maps[i]);
if (toptions != NULL) {
maps[i++] = toptions;
}
}
/* Failing that, see if there's a default ACL already in the view */
if (aclp != NULL && *aclp != NULL) {
(*setzacl)(zone, *aclp);
@ -187,8 +195,8 @@ parse_acl:
* 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) {
configure_zone_ssutable(const cfg_obj_t *zconfig, const cfg_obj_t *tconfig,
dns_zone_t *zone, const char *zname) {
const cfg_obj_t *updatepolicy = NULL;
dns_ssutable_t *table = NULL;
isc_mem_t *mctx = dns_zone_getmctx(zone);
@ -200,8 +208,8 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
isc_buffer_init(&dbuf, debug, sizeof(debug));
isc_buffer_setmctx(&dbuf, mctx);
(void)cfg_map_get(zconfig, "update-policy", &updatepolicy);
(void)named_config_findopt(zconfig, tconfig, "update-policy",
&updatepolicy);
if (updatepolicy == NULL) {
dns_zone_setssutable(zone, NULL);
return ISC_R_SUCCESS;
@ -540,8 +548,8 @@ configure_staticstub_servernames(const cfg_obj_t *zconfig, dns_zone_t *zone,
* Configure static-stub zone.
*/
static isc_result_t
configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone,
const char *zname, const char *dbtype) {
configure_staticstub(const cfg_obj_t *zconfig, const cfg_obj_t *tconfig,
dns_zone_t *zone, const char *zname, const char *dbtype) {
int i = 0;
const cfg_obj_t *obj;
isc_mem_t *mctx = dns_zone_getmctx(zone);
@ -583,18 +591,16 @@ configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone,
/* Prepare zone RRs from the configuration */
obj = NULL;
result = cfg_map_get(zconfig, "server-addresses", &obj);
if (result == ISC_R_SUCCESS) {
INSIST(obj != NULL);
(void)named_config_findopt(zconfig, tconfig, "server-addresses", &obj);
if (obj != NULL) {
CHECK(configure_staticstub_serveraddrs(obj, zone, &rdatalist_ns,
&rdatalist_a,
&rdatalist_aaaa));
}
obj = NULL;
result = cfg_map_get(zconfig, "server-names", &obj);
if (result == ISC_R_SUCCESS) {
INSIST(obj != NULL);
(void)named_config_findopt(zconfig, tconfig, "server-names", &obj);
if (obj != NULL) {
CHECK(configure_staticstub_servernames(obj, zone, &rdatalist_ns,
zname));
}
@ -682,12 +688,11 @@ cleanup:
* Convert a config file zone type into a server zone type.
*/
static dns_zonetype_t
zonetype_fromconfig(const cfg_obj_t *map) {
zonetype_fromconfig(const cfg_obj_t *zmap, const cfg_obj_t *tmap) {
const cfg_obj_t *obj = NULL;
isc_result_t result;
result = cfg_map_get(map, "type", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
(void)named_config_findopt(zmap, tmap, "type", &obj);
INSIST(obj != NULL);
return named_config_getzonetype(obj);
}
@ -872,11 +877,13 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
const char *zname;
dns_rdataclass_t zclass;
dns_rdataclass_t vclass;
const cfg_obj_t *maps[5];
const cfg_obj_t *nodefault[4];
const cfg_obj_t *maps[6];
const cfg_obj_t *nodefault[5];
const cfg_obj_t *nooptions[3];
const cfg_obj_t *zoptions = NULL;
const cfg_obj_t *toptions = NULL;
const cfg_obj_t *options = NULL;
const cfg_obj_t *obj;
const cfg_obj_t *obj = NULL;
const char *filename = NULL;
const char *initial_file = NULL;
const char *kaspname = NULL;
@ -910,23 +917,34 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
bool transferinsecs = ns_server_getoption(named_g_server->sctx,
NS_SERVER_TRANSFERINSECS);
REQUIRE(config != NULL);
REQUIRE(zconfig != NULL);
i = 0;
if (zconfig != NULL) {
zoptions = cfg_tuple_get(zconfig, "options");
nodefault[i] = maps[i] = zoptions;
zoptions = cfg_tuple_get(zconfig, "options");
INSIST(zoptions != NULL);
nodefault[i] = nooptions[i] = maps[i] = zoptions;
i++;
toptions = named_zone_templateopts(config, zoptions);
if (toptions != NULL) {
nodefault[i] = nooptions[i] = maps[i] = toptions;
i++;
}
nooptions[i] = NULL;
if (vconfig != NULL) {
nodefault[i] = maps[i] = cfg_tuple_get(vconfig, "options");
i++;
}
if (config != NULL) {
(void)cfg_map_get(config, "options", &options);
if (options != NULL) {
nodefault[i] = maps[i] = options;
i++;
}
(void)cfg_map_get(config, "options", &options);
if (options != NULL) {
nodefault[i] = maps[i] = options;
i++;
}
nodefault[i] = NULL;
maps[i++] = named_g_defaults;
maps[i] = NULL;
@ -951,7 +969,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
dns_zone_setclass(raw, zclass);
}
ztype = zonetype_fromconfig(zoptions);
ztype = zonetype_fromconfig(zoptions, toptions);
if (raw != NULL) {
dns_zone_settype(raw, ztype);
dns_zone_settype(zone, dns_zone_primary);
@ -960,13 +978,13 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
}
obj = NULL;
result = cfg_map_get(zoptions, "database", &obj);
result = named_config_get(nooptions, "database", &obj);
if (result == ISC_R_SUCCESS) {
cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
}
obj = NULL;
result = cfg_map_get(zoptions, "dlz", &obj);
result = named_config_get(nooptions, "dlz", &obj);
if (result == ISC_R_SUCCESS) {
const char *dlzname = cfg_obj_asstring(obj);
size_t len = strlen(dlzname) + 5;
@ -992,13 +1010,13 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
}
obj = NULL;
result = cfg_map_get(zoptions, "file", &obj);
result = named_config_get(nooptions, "file", &obj);
if (result == ISC_R_SUCCESS) {
filename = cfg_obj_asstring(obj);
}
obj = NULL;
result = cfg_map_get(zoptions, "initial-file", &obj);
result = named_config_get(nooptions, "initial-file", &obj);
if (result == ISC_R_SUCCESS) {
initial_file = cfg_obj_asstring(obj);
}
@ -1074,7 +1092,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
}
obj = NULL;
result = cfg_map_get(zoptions, "journal", &obj);
result = named_config_get(nooptions, "journal", &obj);
if (result == ISC_R_SUCCESS) {
dns_zone_setjournal(mayberaw, cfg_obj_asstring(obj));
}
@ -1433,7 +1451,8 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
cfg_obj_asboolean(obj));
obj = NULL;
result = cfg_map_get(zoptions, "log-report-channel", &obj);
result = named_config_get(nooptions, "log-report-channel",
&obj);
if (result == ISC_R_SUCCESS) {
logreports = cfg_obj_asboolean(obj);
dns_zone_setoption(zone, DNS_ZONEOPT_LOGREPORTS,
@ -1533,7 +1552,8 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
zname);
}
CHECK(configure_zone_ssutable(zoptions, mayberaw, zname));
CHECK(configure_zone_ssutable(zoptions, toptions, mayberaw,
zname));
}
/*
@ -1618,7 +1638,8 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
*/
if (ztype == dns_zone_primary || ztype == dns_zone_secondary) {
const cfg_obj_t *parentals = NULL;
(void)cfg_map_get(zoptions, "parental-agents", &parentals);
(void)named_config_get(nooptions, "parental-agents",
&parentals);
if (parentals != NULL) {
dns_ipkeylist_t ipkl;
dns_ipkeylist_init(&ipkl);
@ -1769,7 +1790,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
* are explicitly enabled by zone configuration.
*/
obj = NULL;
(void)cfg_map_get(zoptions, "allow-transfer", &obj);
(void)named_config_get(nooptions, "allow-transfer", &obj);
if (obj == NULL) {
dns_acl_t *none;
CHECK(dns_acl_none(mctx, &none));
@ -1782,9 +1803,9 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
case dns_zone_redirect:
count = 0;
obj = NULL;
(void)cfg_map_get(zoptions, "primaries", &obj);
(void)named_config_get(nooptions, "primaries", &obj);
if (obj == NULL) {
(void)cfg_map_get(zoptions, "masters", &obj);
(void)named_config_get(nooptions, "masters", &obj);
}
/*
@ -1886,7 +1907,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
break;
case dns_zone_staticstub:
CHECK(configure_staticstub(zoptions, zone, zname,
CHECK(configure_staticstub(zoptions, toptions, zone, zname,
default_dbtype));
break;
@ -1927,20 +1948,22 @@ named_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig,
const cfg_obj_t *vconfig, const cfg_obj_t *config,
dns_kasplist_t *kasplist) {
const cfg_obj_t *zoptions = NULL;
const cfg_obj_t *toptions = NULL;
const cfg_obj_t *obj = NULL;
const char *cfilename;
const char *zfilename;
const char *cfilename = NULL;
const char *zfilename = NULL;
dns_zone_t *raw = NULL;
bool has_raw, inline_signing;
dns_zonetype_t ztype;
zoptions = cfg_tuple_get(zconfig, "options");
toptions = named_zone_templateopts(config, zoptions);
/*
* We always reconfigure a static-stub zone for simplicity, assuming
* the amount of data to be loaded is small.
*/
if (zonetype_fromconfig(zoptions) == dns_zone_staticstub) {
if (zonetype_fromconfig(zoptions, toptions) == dns_zone_staticstub) {
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"not reusable: staticstub");
return false;
@ -1971,14 +1994,14 @@ named_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig,
return false;
}
if (zonetype_fromconfig(zoptions) != ztype) {
if (zonetype_fromconfig(zoptions, toptions) != ztype) {
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"not reusable: type mismatch");
return false;
}
obj = NULL;
(void)cfg_map_get(zoptions, "file", &obj);
(void)named_config_findopt(zoptions, toptions, "file", &obj);
if (obj != NULL) {
cfilename = cfg_obj_asstring(obj);
} else {
@ -1999,15 +2022,27 @@ named_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig,
bool
named_zone_inlinesigning(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
const cfg_obj_t *config, dns_kasplist_t *kasplist) {
const cfg_obj_t *maps[4];
const cfg_obj_t *maps[5] = { 0 }, *noopts[3] = { 0 };
const cfg_obj_t *signing = NULL;
const cfg_obj_t *policy = NULL;
const cfg_obj_t *toptions = NULL;
dns_kasp_t *kasp = NULL;
isc_result_t res;
bool inline_signing = false;
int i = 0;
maps[i++] = cfg_tuple_get(zconfig, "options");
noopts[i] = maps[i] = cfg_tuple_get(zconfig, "options");
i++;
if (config != NULL) {
toptions = named_zone_templateopts(config, maps[0]);
if (toptions != NULL) {
noopts[i] = maps[i] = toptions;
i++;
}
}
noopts[i] = NULL;
if (vconfig != NULL) {
maps[i++] = cfg_tuple_get(vconfig, "options");
}
@ -2041,13 +2076,35 @@ named_zone_inlinesigning(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
/*
* The zone option 'inline-signing' may override the value in
* dnssec-policy. This is a zone-only option, so look in maps[0]
* only.
* dnssec-policy. This is a zone-only option, so look in the
* zone and template blocks only.
*/
res = cfg_map_get(maps[0], "inline-signing", &signing);
res = named_config_get(noopts, "inline-signing", &signing);
if (res == ISC_R_SUCCESS && cfg_obj_isboolean(signing)) {
return cfg_obj_asboolean(signing);
}
return inline_signing;
}
const cfg_obj_t *
named_zone_templateopts(const cfg_obj_t *config, const cfg_obj_t *zoptions) {
const cfg_obj_t *templates = NULL;
const cfg_obj_t *obj = NULL;
(void)cfg_map_get(config, "template", &templates);
(void)cfg_map_get(zoptions, "template", &obj);
if (obj != NULL && templates != NULL) {
const char *tmplname = cfg_obj_asstring(obj);
CFG_LIST_FOREACH (templates, e) {
const cfg_obj_t *t = cfg_tuple_get(cfg_listelt_value(e),
"name");
if (strcasecmp(cfg_obj_asstring(t), tmplname) == 0) {
return cfg_tuple_get(cfg_listelt_value(e),
"options");
}
}
}
return NULL;
}

View File

@ -9,7 +9,6 @@
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
;$ORIGIN added.example.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
1 ; serial

View File

@ -28,6 +28,12 @@ controls {
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
template primary {
type primary;
file "$view-$name.db";
initial-file "added.db";
};
zone "." {
type hint;
file "../../_common/root.hint";

View File

@ -27,6 +27,12 @@ options {
dnssec-validation no;
};
template primary {
type primary;
file "$view-$name.db";
initial-file "added.db";
};
view internal {
match-clients { 10.53.0.2; };
allow-new-zones no;

View File

@ -27,6 +27,12 @@ options {
dnssec-validation no;
};
template primary {
type primary;
file "$view-$name.db";
initial-file "added.db";
};
view internal {
match-clients { 10.53.0.2; };
allow-new-zones no;

View File

@ -745,5 +745,29 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking addzone with zone template (primary) ($n)"
ret=0
$RNDCCMD 10.53.0.2 addzone 'template.example in external { template primary; };' 2>&1 | sed 's/^/I:ns2 /'
$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.template.example a >dig.out.ns2.int.$n || ret=1
grep 'status: NOERROR' dig.out.ns2.int.$n >/dev/null || ret=1
grep 'ANSWER: 0' dig.out.ns2.int.$n >/dev/null || ret=1
$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.4 a.template.example a >dig.out.ns2.ext.$n || ret=1
grep 'status: NOERROR' dig.out.ns2.ext.$n >/dev/null || ret=1
grep 'ANSWER: 1' dig.out.ns2.ext.$n >/dev/null || ret=1
test -f ns2/external-template.example.db
n=$((n + 1))
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "checking addzone with nonexistent template ($n)"
ret=0
nextpart ns2/named.run >/dev/null
$RNDCCMD 10.53.0.2 addzone 'wrong.example in external { template nope; };' 2>&1 | grep -qF "failure" || ret=1
nextpart ns2/named.run | grep -qF "zone 'wrong.example': template 'nope' not found" || ret=1
test -f ns2/wrong-template.example.db && ret=1
n=$((n + 1))
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View File

@ -26,6 +26,7 @@ pytestmark = pytest.mark.extra_artifacts(
"ns2/K*.private",
"ns2/K*.state",
"ns2/external.nzd",
"ns2/external-template.example.db",
"ns2/extra.nzd",
"ns2/inline.db.jbk",
"ns2/inline.db.signed",

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
template a {
type primary;
file "$name.db";
initial-file "template.db";
};
zone example {
template a;
type secondary;
};

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
template a {
type primary;
file "$name.db";
initial-file "template.db";
};
template b {
template a;
};

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
template a {
type primary;
file "$name.db";
initial-file "template.db";
};
zone example.com {
# specify an undefined template
template c;
};

View File

@ -0,0 +1,17 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
zone example.com {
# specify a template, but there are no templates
template c;
};

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
template a {
type primary;
file "$name.db";
initial-file "template.db";
};
zone example {
template a;
file "othername.db";
};

View File

@ -34,14 +34,23 @@ zone "." {
file "../../_common/root.hint";
};
zone "example" {
template primary {
type primary;
file "$name.db";
};
zone "example" {
template primary;
};
zone "missing" {
type primary;
file "$name.db";
template primary;
};
zone "different" {
template primary;
initial-file "example.db";
file "alternate.db";
};
zone "initial" {

View File

@ -17,7 +17,9 @@ import dns.zone
import isctest
import pytest
pytestmark = pytest.mark.extra_artifacts(["ns2/copied.db", "ns2/present.db"])
pytestmark = pytest.mark.extra_artifacts(
["ns2/copied.db", "ns2/present.db", "ns2/alternate.db"]
)
def test_masterfile_include_semantics():
@ -91,7 +93,20 @@ example. 300 IN SOA mname1. . 2010042407 20 20 1814400 3600
def test_masterfile_initial_file():
"""Test zone configuration with initial template files"""
"""Test zone configurations with initial template files"""
# example inherited its configuration from the template,
# make sure it works
msg_soa = dns.message.make_query("example.", "SOA")
res_soa = isctest.query.tcp(msg_soa, "10.53.0.2")
expected_soa_rr = """;ANSWER
example. 300 IN SOA mname1. . 2010042407 20 20 1814400 3600
"""
expected = dns.message.from_text(expected_soa_rr)
isctest.check.rrsets_equal(res_soa.answer, expected.answer)
# initial uses an initial-file option with the "file"
# option set to "copied.db". make sure it works and that
# copied.db has been populated.
msg_soa = dns.message.make_query("initial.", "SOA")
res_soa = isctest.query.tcp(msg_soa, "10.53.0.2")
expected_soa_rr = """;ANSWER
@ -101,13 +116,30 @@ initial. 300 IN SOA mname1. . 2010042407 20 20 1814400 3600
isctest.check.rrsets_equal(res_soa.answer, expected.answer)
isctest.check.file_contents_equal("ns2/example.db", "ns2/copied.db")
# the 'present.db' file already existed and shouldn't load
# present uses an initial-file option, but the file 'present.db'
# already exists and is empty, so the initial-file should not be
# copied into place and the zone should not load.
msg_soa = dns.message.make_query("present.", "SOA")
res_soa = isctest.query.tcp(msg_soa, "10.53.0.2")
isctest.check.servfail(res_soa)
isctest.check.file_empty("ns2/present.db")
def test_masterfile_template_override():
"""Test zone configurations with overridden template options"""
# different inherited configuration from the template, but
# overrides the "file" option to 'alternate.db'.
msg_soa = dns.message.make_query("different.", "SOA")
res_soa = isctest.query.tcp(msg_soa, "10.53.0.2")
expected_soa_rr = """;ANSWER
different. 300 IN SOA mname1. . 2010042407 20 20 1814400 3600
"""
expected = dns.message.from_text(expected_soa_rr)
isctest.check.rrsets_equal(res_soa.answer, expected.answer)
isctest.check.file_contents_equal("ns2/example.db", "ns2/alternate.db")
assert not os.path.exists("ns2/different.db")
def test_masterfile_missing_master_file_servfail():
"""Test nameserver returning SERVFAIL for a missing master file"""
msg_soa = dns.message.make_query("missing.", "SOA")

View File

@ -7038,6 +7038,13 @@ mid-1970s. Zone data for it can be specified with the ``CHAOS`` class.
Zone Options
^^^^^^^^^^^^
.. namedconf:statement:: template
:tags: zone
:short: Specifies a template to use for zone configuration.
This specifies a zone template from which to import other zone options.
See :ref:`zone_templates` for details.
:any:`allow-notify`
See the description of :any:`allow-notify` in :ref:`access_control`.
@ -7377,6 +7384,52 @@ Zone Options
:any:`send-report-channel`
See the description of :any:`send-report-channel` in :namedconf:ref:`options`.
.. _zone_templates:
Zone Templates
^^^^^^^^^^^^^^
To simplify the configuration of multiple similar zones, BIND 9
supports a zone template mechanism. ``template`` blocks can be
defined at the top level of the configuration; these blocks can
contain any set of options that could be set in a :any:`zone`
statement, with the exceptions of :any:`in-view` and :any:`template`.
Once a template has been defined, it can be referenced in a
:any:`zone` statement; the zone is then configured using the
options specified in the :any:`template` as defaults.
Options that are locally defined within the :any:`zone` statement
override the template.
For example, the following configuration would define two primary
and two secondary zones:
::
template primary {
type primary;
file "$type/$name.db";
initial-file "initial.db";
};
template secondary {
type secondary;
file "$type/$name.db";
primaries { 192.0.2.1; };
};
zone example.com { template primary; };
zone example.org { template primary; };
zone example.net { template secondary; };
zone example.edu { template secondary; };
Templates can also be used for zones that are added using
``rndc addzone`` (see :any:`allow-new-zones`):
::
$ rndc addzone example.biz '{ template secondary; };'
.. _dynamic_update_policies:
Dynamic Update Policies

View File

@ -2,4 +2,5 @@ zone <string> [ <class> ] {
type forward;
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
template <string>;
};

View File

@ -2,4 +2,5 @@ zone <string> [ <class> ] {
type hint;
check-names ( fail | warn | ignore );
file <quoted_string>;
template <string>;
};

View File

@ -38,6 +38,7 @@ zone <string> [ <class> ] {
request-expire <boolean>;
request-ixfr <boolean>;
request-ixfr-max-diffs <integer>;
template <string>;
transfer-source ( <ipv4_address> | * );
transfer-source-v6 ( <ipv6_address> | * );
try-tcp-refresh <boolean>;

View File

@ -362,6 +362,93 @@ statistics-channels {
inet ( <ipv4_address> | <ipv6_address> | * ) [ port ( <integer> | * ) ] [ allow { <address_match_element>; ... } ]; // may occur multiple times
}; // optional (only available if configured), may occur multiple times
template <string> {
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <boolean>;
check-mx ( fail | warn | ignore );
check-mx-cname ( fail | warn | ignore );
check-names ( fail | warn | ignore );
check-sibling <boolean>;
check-spf ( warn | ignore );
check-srv-cname ( fail | warn | ignore );
check-svcb <boolean>;
check-wildcard <boolean>;
checkds ( explicit | <boolean> );
database <string>;
dlz <string>;
dnskey-sig-validity <integer>; // obsolete
dnssec-dnskey-kskonly <boolean>; // obsolete
dnssec-loadkeys-interval <integer>;
dnssec-policy <string>;
dnssec-secure-to-insecure <boolean>; // obsolete
dnssec-update-mode ( maintain | no-resign ); // obsolete
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
initial-file <quoted_string>;
inline-signing <boolean>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
key-directory <quoted_string>;
log-report-channel <boolean>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-records-per-type <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> ); // deprecated
min-refresh-time <integer>;
min-retry-time <integer>;
min-transfer-rate-in <integer> <integer>;
multi-master <boolean>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-defer <integer>;
notify-delay <integer>;
notify-source ( <ipv4_address> | * );
notify-source-v6 ( <ipv6_address> | * );
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
parental-agents [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
parental-source ( <ipv4_address> | * );
parental-source-v6 ( <ipv6_address> | * );
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
provide-zoneversion <boolean>;
request-expire <boolean>;
request-ixfr <boolean>;
request-ixfr-max-diffs <integer>;
send-report-channel <string>;
serial-update-method ( date | increment | unixtime );
server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
server-names { <string>; ... };
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ]; // obsolete
transfer-source ( <ipv4_address> | * );
transfer-source-v6 ( <ipv6_address> | * );
try-tcp-refresh <boolean>;
type ( primary | master | secondary | slave | mirror | forward | hint | redirect | static-stub | stub );
update-check-ksk <boolean>; // obsolete
update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... } );
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
}; // may occur multiple times
tls <string> {
ca-file <quoted_string>;
cert-file <quoted_string>;

View File

@ -60,6 +60,7 @@ zone <string> [ <class> ] {
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ]; // obsolete
template <string>;
update-check-ksk <boolean>; // obsolete
update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... } );
zero-no-soa-ttl <boolean>;

View File

@ -11,5 +11,6 @@ zone <string> [ <class> ] {
max-types-per-name <integer>;
max-zone-ttl ( unlimited | <duration> ); // deprecated
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
template <string>;
zone-statistics ( full | terse | none | <boolean> );
};

View File

@ -60,6 +60,7 @@ zone <string> [ <class> ] {
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ]; // obsolete
template <string>;
transfer-source ( <ipv4_address> | * );
transfer-source-v6 ( <ipv6_address> | * );
try-tcp-refresh <boolean>;

View File

@ -9,5 +9,6 @@ zone <string> [ <class> ] {
max-types-per-name <integer>;
server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
server-names { <string>; ... };
template <string>;
zone-statistics ( full | terse | none | <boolean> );
};

View File

@ -21,6 +21,7 @@ zone <string> [ <class> ] {
min-transfer-rate-in <integer> <integer>;
multi-master <boolean>;
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
template <string>;
transfer-source ( <ipv4_address> | * );
transfer-source-v6 ( <ipv6_address> | * );
zone-statistics ( full | terse | none | <boolean> );

View File

@ -2923,14 +2923,15 @@ check:
}
/*
* Try to find a zone option in one of up to three levels of options:
* for example, the zone, view, and global option blocks.
* Try to find a zone option in one of up to four levels of options:
* for example, the zone, template, view, and global option blocks.
* (Fewer levels can be specified for options that aren't defined at
* all three levels.)
* all four levels.)
*/
static isc_result_t
get_zoneopt(const cfg_obj_t *opts1, const cfg_obj_t *opts2,
const cfg_obj_t *opts3, const char *name, const cfg_obj_t **objp) {
const cfg_obj_t *opts3, const cfg_obj_t *opts4, const char *name,
const cfg_obj_t **objp) {
isc_result_t result = ISC_R_NOTFOUND;
REQUIRE(*objp == NULL);
@ -2944,6 +2945,9 @@ get_zoneopt(const cfg_obj_t *opts1, const cfg_obj_t *opts2,
if (*objp == NULL && opts3 != NULL) {
result = cfg_map_get(opts3, name, objp);
}
if (*objp == NULL && opts4 != NULL) {
result = cfg_map_get(opts4, name, objp);
}
return result;
}
@ -2958,13 +2962,14 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
const char *znamestr = NULL;
const char *typestr = NULL;
const char *target = NULL;
const char *tmplname = NULL;
int ztype;
const cfg_obj_t *zoptions, *goptions = NULL;
const cfg_obj_t *zoptions = NULL, *toptions = NULL, *goptions = NULL;
const cfg_obj_t *obj = NULL, *kasp = NULL;
const cfg_obj_t *inviewobj = NULL;
const cfg_obj_t *templates = NULL, *inviewobj = NULL;
isc_result_t result = ISC_R_SUCCESS;
isc_result_t tresult;
unsigned int i;
unsigned int i = 0;
dns_rdataclass_t zclass;
dns_fixedname_t fixedname;
dns_name_t *zname = NULL; /* NULL if parsing of zone name fails. */
@ -2976,6 +2981,7 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
bool ddns = false;
bool has_dnssecpolicy = false;
bool kasp_inlinesigning = false;
bool inline_signing = false;
const void *clauses = NULL;
const char *option = NULL;
const char *kaspname = NULL;
@ -2995,14 +3001,37 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
cfg_map_get(config, "options", &goptions);
}
inviewobj = NULL;
/* If the zone specifies a template, find it too */
(void)cfg_map_get(config, "template", &templates);
(void)cfg_map_get(zoptions, "template", &obj);
if (obj != NULL) {
tmplname = cfg_obj_asstring(obj);
CFG_LIST_FOREACH (templates, e) {
const cfg_obj_t *t = cfg_tuple_get(cfg_listelt_value(e),
"name");
if (strcasecmp(cfg_obj_asstring(t), tmplname) == 0) {
toptions = cfg_tuple_get(cfg_listelt_value(e),
"options");
break;
}
}
if (toptions == NULL) {
cfg_obj_log(zconfig, ISC_LOG_ERROR,
"zone '%s': template '%s' not found",
znamestr, tmplname);
return ISC_R_FAILURE;
}
}
(void)cfg_map_get(zoptions, "in-view", &inviewobj);
if (inviewobj != NULL) {
target = cfg_obj_asstring(inviewobj);
ztype = CFG_ZONE_INVIEW;
} else {
obj = NULL;
(void)cfg_map_get(zoptions, "type", &obj);
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "type", &obj);
if (obj == NULL) {
cfg_obj_log(zconfig, ISC_LOG_ERROR,
"zone '%s': type not present", znamestr);
@ -3195,7 +3224,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
* Check if a dnssec-policy is set.
*/
obj = NULL;
(void)get_zoneopt(zoptions, voptions, goptions, "dnssec-policy", &obj);
(void)get_zoneopt(zoptions, toptions, voptions, goptions,
"dnssec-policy", &obj);
if (obj != NULL) {
kaspname = cfg_obj_asstring(obj);
if (strcmp(kaspname, "default") == 0) {
@ -3258,8 +3288,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
* */
if (has_dnssecpolicy) {
obj = NULL;
(void)get_zoneopt(zoptions, voptions, goptions, "max-zone-ttl",
&obj);
(void)get_zoneopt(zoptions, toptions, voptions, goptions,
"max-zone-ttl", &obj);
if (obj != NULL) {
cfg_obj_log(obj, ISC_LOG_ERROR,
"zone '%s': option 'max-zone-ttl' "
@ -3278,13 +3308,19 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
option = cfg_map_firstclause(&cfg_type_zoneopts, &clauses, &i);
while (option != NULL) {
obj = NULL;
if (cfg_map_get(zoptions, option, &obj) == ISC_R_SUCCESS &&
obj != NULL && !cfg_clause_validforzone(option, ztype))
{
bool topt = false;
(void)cfg_map_get(zoptions, option, &obj);
if (obj == NULL && toptions != NULL) {
(void)cfg_map_get(toptions, option, &obj);
topt = true;
}
if (obj != NULL && !cfg_clause_validforzone(option, ztype)) {
cfg_obj_log(obj, ISC_LOG_WARNING,
"option '%s' is not allowed "
"in '%s' zone '%s'",
option, typestr, znamestr);
"in '%s' zone '%s'%s%s%s",
option, typestr, znamestr,
topt ? " (referencing template '" : "",
topt ? tmplname : "", topt ? "')" : "");
result = ISC_R_FAILURE;
}
option = cfg_map_nextclause(&cfg_type_zoneopts, &clauses, &i);
@ -3321,9 +3357,9 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
bool donotify = true;
obj = NULL;
tresult = get_zoneopt(zoptions, voptions, goptions, "notify",
&obj);
if (tresult == ISC_R_SUCCESS) {
(void)get_zoneopt(zoptions, toptions, voptions, goptions,
"notify", &obj);
if (obj != NULL) {
if (cfg_obj_isboolean(obj)) {
donotify = cfg_obj_asboolean(obj);
} else {
@ -3338,18 +3374,19 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
obj = NULL;
tresult = cfg_map_get(zoptions, "also-notify", &obj);
if (tresult == ISC_R_SUCCESS && !donotify) {
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "also-notify",
&obj);
if (obj != NULL && !donotify) {
cfg_obj_log(zoptions, ISC_LOG_WARNING,
"zone '%s': 'also-notify' set but "
"'notify' is disabled",
znamestr);
}
if (tresult != ISC_R_SUCCESS) {
tresult = get_zoneopt(voptions, goptions, NULL,
"also-notify", &obj);
if (obj == NULL) {
(void)get_zoneopt(voptions, goptions, NULL, NULL,
"also-notify", &obj);
}
if (tresult == ISC_R_SUCCESS && donotify) {
if (obj != NULL && donotify) {
uint32_t count;
tresult = validate_remotes(obj, config, &count, mctx);
if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
@ -3370,15 +3407,18 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
!dns_name_equal(zname, dns_rootname)))
{
obj = NULL;
(void)cfg_map_get(zoptions, "primaries", &obj);
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "primaries",
&obj);
if (obj == NULL) {
/* If "primaries" was unset, check for "masters" */
(void)cfg_map_get(zoptions, "masters", &obj);
(void)get_zoneopt(zoptions, toptions, NULL, NULL,
"masters", &obj);
} else {
const cfg_obj_t *obj2 = NULL;
/* ...bug if it was set, "masters" must not be. */
(void)cfg_map_get(zoptions, "masters", &obj2);
(void)get_zoneopt(zoptions, toptions, NULL, NULL,
"masters", &obj2);
if (obj2 != NULL) {
cfg_obj_log(obj, ISC_LOG_ERROR,
"'primaries' and 'masters' cannot "
@ -3414,7 +3454,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
*/
if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY) {
obj = NULL;
(void)cfg_map_get(zoptions, "parental-agents", &obj);
(void)get_zoneopt(zoptions, toptions, NULL, NULL,
"parental-agents", &obj);
if (obj != NULL) {
uint32_t count;
tresult = validate_remotes(obj, config, &count, mctx);
@ -3451,22 +3492,22 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
*/
if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY) {
bool signing = false;
isc_result_t res1, res2, res3;
const cfg_obj_t *au = NULL;
const cfg_obj_t *au = NULL, *up = NULL;
obj = NULL;
res1 = cfg_map_get(zoptions, "allow-update", &au);
obj = NULL;
res2 = cfg_map_get(zoptions, "update-policy", &obj);
if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
cfg_obj_log(obj, ISC_LOG_ERROR,
(void)get_zoneopt(zoptions, toptions, NULL, NULL,
"allow-update", &au);
(void)get_zoneopt(zoptions, toptions, NULL, NULL,
"update-policy", &up);
if (au != NULL && up != NULL) {
cfg_obj_log(au, ISC_LOG_ERROR,
"zone '%s': 'allow-update' is ignored "
"when 'update-policy' is present",
znamestr);
result = ISC_R_FAILURE;
} else if (res2 == ISC_R_SUCCESS) {
res3 = check_update_policy(obj);
if (res3 != ISC_R_SUCCESS) {
} else if (up != NULL) {
tresult = check_update_policy(up);
if (tresult != ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
}
}
@ -3476,18 +3517,18 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
* we should also check for allow-update at the
* view and options levels.
*/
if (res1 != ISC_R_SUCCESS) {
res1 = get_zoneopt(voptions, goptions, NULL,
"allow-update", &au);
if (au == NULL) {
(void)get_zoneopt(voptions, goptions, NULL, NULL,
"allow-update", &au);
}
if (res2 == ISC_R_SUCCESS) {
if (up != NULL) {
ddns = true;
} else if (res1 == ISC_R_SUCCESS) {
} else if (au != NULL) {
dns_acl_t *acl = NULL;
res1 = cfg_acl_fromconfig(au, config, actx, mctx, 0,
&acl);
if (res1 != ISC_R_SUCCESS) {
tresult = cfg_acl_fromconfig(au, config, actx, mctx, 0,
&acl);
if (tresult != ISC_R_SUCCESS) {
cfg_obj_log(au, ISC_LOG_ERROR,
"acl expansion failed: %s",
isc_result_totext(result));
@ -3501,9 +3542,10 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
obj = NULL;
res1 = cfg_map_get(zoptions, "inline-signing", &obj);
if (res1 == ISC_R_SUCCESS) {
signing = cfg_obj_asboolean(obj);
(void)get_zoneopt(zoptions, toptions, NULL, NULL,
"inline-signing", &obj);
if (obj != NULL) {
inline_signing = signing = cfg_obj_asboolean(obj);
} else if (has_dnssecpolicy) {
signing = kasp_inlinesigning;
}
@ -3527,8 +3569,9 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
obj = NULL;
res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
if (res1 == ISC_R_SUCCESS) {
(void)get_zoneopt(zoptions, toptions, NULL, NULL,
"sig-signing-type", &obj);
if (obj != NULL) {
uint32_t type = cfg_obj_asuint32(obj);
if (type < 0xff00U || type > 0xffffU) {
cfg_obj_log(obj, ISC_LOG_ERROR,
@ -3540,10 +3583,9 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
obj = NULL;
res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SECONDARY &&
!signing)
{
(void)get_zoneopt(zoptions, toptions, NULL, NULL,
"dnssec-loadkeys-interval", &obj);
if (obj != NULL && ztype == CFG_ZONE_SECONDARY && !signing) {
cfg_obj_log(obj, ISC_LOG_ERROR,
"dnssec-loadkeys-interval: requires "
"inline-signing when used in secondary "
@ -3557,7 +3599,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
*/
obj = NULL;
if (root) {
(void)get_zoneopt(voptions, goptions, NULL, "forwarders", &obj);
(void)get_zoneopt(voptions, goptions, NULL, NULL, "forwarders",
&obj);
}
if (check_forward(config, zoptions, obj) != ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
@ -3569,13 +3612,15 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
*/
if (ztype == CFG_ZONE_FORWARD && (rfc1918 || ula)) {
obj = NULL;
(void)cfg_map_get(zoptions, "forward", &obj);
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "forward",
&obj);
if (obj == NULL) {
/*
* Forward mode not explicitly configured.
* Forward mode not explicitly configured
* at the zone or template level.
*/
(void)get_zoneopt(voptions, goptions, NULL, "forward",
&obj);
(void)get_zoneopt(voptions, goptions, NULL, NULL,
"forward", &obj);
if (obj == NULL ||
strcasecmp(cfg_obj_asstring(obj), "first") == 0)
{
@ -3593,7 +3638,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
* Check validity of static stub server addresses.
*/
obj = NULL;
(void)cfg_map_get(zoptions, "server-addresses", &obj);
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "server-addresses",
&obj);
if (ztype == CFG_ZONE_STATICSTUB && obj != NULL) {
CFG_LIST_FOREACH (obj, element) {
isc_sockaddr_t sa;
@ -3616,7 +3662,7 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
* Check validity of static stub server names.
*/
obj = NULL;
(void)cfg_map_get(zoptions, "server-names", &obj);
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "server-names", &obj);
if (zname != NULL && ztype == CFG_ZONE_STATICSTUB && obj != NULL) {
CFG_LIST_FOREACH (obj, element) {
const char *snamestr = NULL;
@ -3649,7 +3695,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
obj = NULL;
(void)cfg_map_get(zoptions, "send-report-channel", &obj);
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "send-report-channel",
&obj);
if (obj != NULL) {
const char *str = cfg_obj_asstring(obj);
dns_fixedname_t fad;
@ -3677,7 +3724,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
* Warn if key-directory doesn't exist
*/
obj = NULL;
(void)get_zoneopt(zoptions, voptions, goptions, "key-directory", &obj);
(void)get_zoneopt(zoptions, toptions, voptions, goptions,
"key-directory", &obj);
if (obj != NULL) {
dir = cfg_obj_asstring(obj);
@ -3726,8 +3774,9 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
*/
if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY) {
obj = NULL;
tresult = cfg_map_get(zoptions, "log-report-channel", &obj);
if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(obj) &&
(void)get_zoneopt(zoptions, toptions, NULL, NULL,
"log-report-channel", &obj);
if (obj != NULL && cfg_obj_asboolean(obj) &&
dns_name_equal(zname, dns_rootname))
{
cfg_obj_log(zconfig, ISC_LOG_ERROR,
@ -3754,14 +3803,14 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
*/
obj = NULL;
dlz = false;
tresult = cfg_map_get(zoptions, "dlz", &obj);
if (tresult == ISC_R_SUCCESS) {
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "dlz", &obj);
if (obj != NULL) {
dlz = true;
}
obj = NULL;
tresult = cfg_map_get(zoptions, "database", &obj);
if (dlz && tresult == ISC_R_SUCCESS) {
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "database", &obj);
if (dlz && obj != NULL) {
cfg_obj_log(zconfig, ISC_LOG_ERROR,
"zone '%s': cannot specify both 'dlz' "
"and 'database'",
@ -3769,28 +3818,23 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
if (result == ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
}
} else if (!dlz &&
(tresult == ISC_R_NOTFOUND ||
(tresult == ISC_R_SUCCESS &&
strcmp(ZONEDB_DEFAULT, cfg_obj_asstring(obj)) == 0)))
} else if (!dlz && (obj == NULL ||
strcmp(ZONEDB_DEFAULT, cfg_obj_asstring(obj)) == 0))
{
isc_result_t res1;
const cfg_obj_t *fileobj = NULL;
tresult = cfg_map_get(zoptions, "file", &fileobj);
obj = NULL;
res1 = cfg_map_get(zoptions, "inline-signing", &obj);
if (tresult != ISC_R_SUCCESS &&
(void)get_zoneopt(zoptions, toptions, NULL, NULL, "file",
&fileobj);
if (fileobj == NULL &&
(ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_HINT ||
(ztype == CFG_ZONE_SECONDARY && res1 == ISC_R_SUCCESS &&
cfg_obj_asboolean(obj))))
(ztype == CFG_ZONE_SECONDARY && inline_signing)))
{
cfg_obj_log(zconfig, ISC_LOG_ERROR,
"zone '%s': missing 'file' entry",
znamestr);
if (result == ISC_R_SUCCESS) {
result = tresult;
result = ISC_R_FAILURE;
}
} else if (tresult == ISC_R_SUCCESS && files != NULL &&
} else if (fileobj != NULL && files != NULL &&
(ztype == CFG_ZONE_SECONDARY ||
ztype == CFG_ZONE_MIRROR || ddns ||
has_dnssecpolicy))
@ -3800,7 +3844,7 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
{
result = tresult;
}
} else if (tresult == ISC_R_SUCCESS && files != NULL &&
} else if (fileobj != NULL && files != NULL &&
(ztype == CFG_ZONE_PRIMARY ||
ztype == CFG_ZONE_HINT))
{
@ -3817,13 +3861,13 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
* consistent.
*/
obj = NULL;
tresult = get_zoneopt(zoptions, voptions, goptions, "masterfile-format",
&obj);
tresult = get_zoneopt(zoptions, toptions, voptions, goptions,
"masterfile-format", &obj);
if (tresult == ISC_R_SUCCESS &&
strcasecmp(cfg_obj_asstring(obj), "raw") == 0)
{
obj = NULL;
tresult = get_zoneopt(zoptions, voptions, goptions,
tresult = get_zoneopt(zoptions, toptions, voptions, goptions,
"masterfile-style", &obj);
if (tresult == ISC_R_SUCCESS) {
cfg_obj_log(obj, ISC_LOG_ERROR,
@ -3838,8 +3882,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
obj = NULL;
(void)get_zoneopt(zoptions, voptions, goptions, "max-journal-size",
&obj);
(void)get_zoneopt(zoptions, toptions, voptions, goptions,
"max-journal-size", &obj);
if (obj != NULL && cfg_obj_isuint64(obj)) {
uint64_t value = cfg_obj_asuint64(obj);
if (value > DNS_JOURNAL_SIZE_MAX) {
@ -3854,8 +3898,8 @@ isccfg_check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
obj = NULL;
(void)get_zoneopt(zoptions, voptions, goptions, "min-transfer-rate-in",
&obj);
(void)get_zoneopt(zoptions, toptions, voptions, goptions,
"min-transfer-rate-in", &obj);
if (obj != NULL) {
uint32_t traffic_bytes =
cfg_obj_asuint32(cfg_tuple_get(obj, "traffic_bytes"));

View File

@ -143,6 +143,8 @@ static cfg_type_t cfg_type_sizeval;
static cfg_type_t cfg_type_sockaddr4wild;
static cfg_type_t cfg_type_sockaddr6wild;
static cfg_type_t cfg_type_statschannels;
static cfg_type_t cfg_type_template;
static cfg_type_t cfg_type_templateopts;
static cfg_type_t cfg_type_tlsconf;
static cfg_type_t cfg_type_view;
static cfg_type_t cfg_type_viewopts;
@ -471,6 +473,18 @@ static cfg_type_t cfg_type_zone = { "zone", cfg_parse_tuple,
cfg_print_tuple, cfg_doc_tuple,
&cfg_rep_tuple, zone_fields };
/*%
* A zone statement.
*/
static cfg_tuplefielddef_t template_fields[] = {
{ "name", &cfg_type_astring, 0 },
{ "options", &cfg_type_templateopts, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_template = { "template", cfg_parse_tuple,
cfg_print_tuple, cfg_doc_tuple,
&cfg_rep_tuple, template_fields };
/*%
* A dnssec-policy statement.
*/
@ -1155,6 +1169,7 @@ static cfg_clausedef_t namedconf_clauses[] = {
{ "statistics-channels", &cfg_type_statschannels,
CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_NOTCONFIGURED },
#endif
{ "template", &cfg_type_template, CFG_CLAUSEFLAG_MULTI },
{ "tls", &cfg_type_tlsconf, CFG_CLAUSEFLAG_MULTI },
{ "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
{ NULL, NULL, 0 }
@ -2429,7 +2444,6 @@ static cfg_clausedef_t zone_only_clauses[] = {
{ "file", &cfg_type_qstring,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR |
CFG_ZONE_STUB | CFG_ZONE_HINT | CFG_ZONE_REDIRECT },
{ "in-view", &cfg_type_astring, CFG_ZONE_INVIEW },
{ "initial-file", &cfg_type_qstring, CFG_ZONE_PRIMARY },
{ "inline-signing", &cfg_type_boolean,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
@ -2457,6 +2471,15 @@ static cfg_clausedef_t zone_only_clauses[] = {
{ NULL, NULL, 0 }
};
static cfg_clausedef_t non_template_clauses[] = {
{ "in-view", &cfg_type_astring, CFG_ZONE_INVIEW },
{ "template", &cfg_type_astring,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR |
CFG_ZONE_STUB | CFG_ZONE_STATICSTUB | CFG_ZONE_DELEGATION |
CFG_ZONE_HINT | CFG_ZONE_REDIRECT | CFG_ZONE_FORWARD },
{ NULL, NULL, 0 }
};
/*% The top-level named.conf syntax. */
static cfg_clausedef_t *namedconf_clausesets[] = { namedconf_clauses,
@ -2493,11 +2516,24 @@ static cfg_type_t cfg_type_viewopts = { "view", cfg_parse_map,
/*% The "zone" statement syntax. */
static cfg_clausedef_t *zone_clausesets[] = { zone_only_clauses, zone_clauses,
static cfg_clausedef_t *zone_clausesets[] = { non_template_clauses,
zone_only_clauses, zone_clauses,
NULL };
cfg_type_t cfg_type_zoneopts = { "zoneopts", cfg_parse_map, cfg_print_map,
cfg_doc_map, &cfg_rep_map, zone_clausesets };
/*%
* The "template" statement syntax: any clause that "zone" can take,
* except that zones can have a "template" option and templates cannot.
*/
static cfg_clausedef_t *template_clausesets[] = { zone_only_clauses,
zone_clauses, NULL };
static cfg_type_t cfg_type_templateopts = {
"templateopts", cfg_parse_map, cfg_print_map,
cfg_doc_map, &cfg_rep_map, template_clausesets
};
/*% The "dnssec-policy" statement syntax. */
static cfg_clausedef_t *dnssecpolicy_clausesets[] = { dnssecpolicy_clauses,
NULL };
@ -3845,6 +3881,14 @@ cfg_clause_validforzone(const char *name, unsigned int ztype) {
}
valid = true;
}
for (clause = non_template_clauses; clause->name != NULL; clause++) {
if ((clause->flags & ztype) == 0 ||
strcmp(clause->name, name) != 0)
{
continue;
}
valid = true;
}
return valid;
}
@ -3853,23 +3897,25 @@ void
cfg_print_zonegrammar(const unsigned int zonetype, unsigned int flags,
void (*f)(void *closure, const char *text, int textlen),
void *closure) {
#define NCLAUSES \
(((sizeof(zone_clauses) + sizeof(zone_only_clauses)) / \
sizeof(clause[0])) - \
1)
#define NCLAUSES \
ARRAY_SIZE(non_template_clauses) + ARRAY_SIZE(zone_clauses) + \
ARRAY_SIZE(zone_only_clauses) - 2
cfg_printer_t pctx;
cfg_clausedef_t *clause = NULL;
cfg_clausedef_t clauses[NCLAUSES];
cfg_clausedef_t *clause = clauses;
pctx.f = f;
pctx.closure = closure;
pctx.indent = 0;
pctx.flags = flags;
memmove(clauses, zone_clauses, sizeof(zone_clauses));
memmove(clauses + sizeof(zone_clauses) / sizeof(zone_clauses[0]) - 1,
zone_only_clauses, sizeof(zone_only_clauses));
memmove(clause, zone_clauses, sizeof(zone_clauses));
clause += ARRAY_SIZE(zone_clauses) - 1;
memmove(clause, zone_only_clauses, sizeof(zone_only_clauses));
clause += ARRAY_SIZE(zone_only_clauses) - 1;
memmove(clause, non_template_clauses, sizeof(non_template_clauses));
qsort(clauses, NCLAUSES - 1, sizeof(clause[0]), cmp_clause);
cfg_print_cstr(&pctx, "zone <string> [ <class> ] {\n");