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) {
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);
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
*
* \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.
+ */
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;
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);
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;
}
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);
}
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;
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;
(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.
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);
*/
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);
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;
* 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));
}
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 "
}
} 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,
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;
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 ||
(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"));
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),
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);
/* 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;
}
}
+ 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);
* 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);
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;
* 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);
/* 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));
}
* 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);
}
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;
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;
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);
}
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;
}
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);
}
}
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));
}
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,
zname);
}
- CHECK(configure_zone_ssutable(zoptions, mayberaw, zname));
+ CHECK(configure_zone_ssutable(zoptions, toptions, mayberaw,
+ zname));
}
/*
*/
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);
* 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));
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);
}
/*
break;
case dns_zone_staticstub:
- CHECK(configure_staticstub(zoptions, zone, zname,
+ CHECK(configure_staticstub(zoptions, toptions, zone, zname,
default_dbtype));
break;
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;
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 {
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");
}
/*
* 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;
+}
; 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
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";
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;
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;
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
"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",
--- /dev/null
+/*
+ * 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;
+};
--- /dev/null
+/*
+ * 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;
+};
--- /dev/null
+/*
+ * 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;
+};
--- /dev/null
+/*
+ * 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;
+};
--- /dev/null
+/*
+ * 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";
+};
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" {
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():
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
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")
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`.
: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
type forward;
forward ( first | only );
forwarders [ port <integer> ] [ tls <string> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ tls <string> ]; ... };
+ template <string>;
};
type hint;
check-names ( fail | warn | ignore );
file <quoted_string>;
+ template <string>;
};
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>;
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>;
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>;
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> );
};
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>;
max-types-per-name <integer>;
server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
server-names { <string>; ... };
+ template <string>;
zone-statistics ( full | terse | none | <boolean> );
};
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> );
}
/*
- * 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);
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;
}
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. */
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;
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);
* 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) {
* */
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' "
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);
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 {
}
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)
!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 "
*/
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);
*/
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;
}
}
* 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));
}
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;
}
}
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,
}
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 "
*/
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;
*/
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)
{
* 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;
* 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;
}
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;
* 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);
*/
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,
*/
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'",
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))
{
result = tresult;
}
- } else if (tresult == ISC_R_SUCCESS && files != NULL &&
+ } else if (fileobj != NULL && files != NULL &&
(ztype == CFG_ZONE_PRIMARY ||
ztype == CFG_ZONE_HINT))
{
* 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,
}
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) {
}
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"));
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;
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.
*/
{ "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 }
{ "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 },
{ 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,
/*% 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 };
}
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;
}
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");