This allows overriding of corresponding non-empty template items.
An ordered list of references :ref:`remote<remote_id>` and
:ref:`remotes<remotes_id>` to zone primary servers
(formerly known as master servers).
+Empty value is allowed for template value overriding.
*Default:* not set
An ordered list of references :ref:`remote<remote_id>` and
:ref:`remotes<remotes_id>` to secondary servers to which notify
message is sent if the zone changes.
+Empty value is allowed for template value overriding.
*Default:* not set
-------
Per zone configuration of :ref:`policy_ds-push`. This option overrides possible
-per policy option.
+per policy option. Empty value is allowed for template value overriding.
*Default:* not set
conf_db_get(conf, txn, C_ZONE, key1_name, dname, dname_size, &val);
switch (val.code) {
case KNOT_EOK:
+ if (val.blob_len == 1 && (val.item->flags & CONF_REF_EMPTY)) {
+ static const conf_val_t empty = { .code = KNOT_ENOENT };
+ return empty;
+ }
return val;
default:
CONF_LOG_ZONE(LOG_ERR, dname, "failed to read '%s/%s' (%s)",
#define CONF_IO_FRLD_MOD YP_FUSR8 /*!< Reload global modules. */
#define CONF_IO_FRLD_ZONE YP_FUSR9 /*!< Reload a specific zone. */
#define CONF_IO_FRLD_ZONES YP_FUSR10 /*!< Reload all zones. */
+#define CONF_REF_EMPTY YP_FUSR11 /*!< Allow empty reference value for zone item. */
#define CONF_IO_FRLD_ALL (CONF_IO_FRLD_SRV | CONF_IO_FRLD_LOG | \
CONF_IO_FRLD_MOD | CONF_IO_FRLD_ZONES)
#define ZONE_ITEMS(FLAGS) \
{ C_STORAGE, YP_TSTR, YP_VSTR = { STORAGE_DIR }, FLAGS }, \
{ C_FILE, YP_TSTR, YP_VNONE, FLAGS }, \
- { C_MASTER, YP_TREF, YP_VREF = { C_RMT, C_RMTS }, YP_FMULTI, { check_ref } }, \
+ { C_MASTER, YP_TREF, YP_VREF = { C_RMT, C_RMTS }, YP_FMULTI | CONF_REF_EMPTY, \
+ { check_ref } }, \
{ C_DDNS_MASTER, YP_TREF, YP_VREF = { C_RMT }, YP_FNONE, { check_ref_empty } }, \
- { C_NOTIFY, YP_TREF, YP_VREF = { C_RMT, C_RMTS }, YP_FMULTI, { check_ref } }, \
+ { C_NOTIFY, YP_TREF, YP_VREF = { C_RMT, C_RMTS }, YP_FMULTI | CONF_REF_EMPTY, \
+ { check_ref } }, \
{ C_ACL, YP_TREF, YP_VREF = { C_ACL }, YP_FMULTI, { check_ref } }, \
{ C_MASTER_PIN_TOL, YP_TINT, YP_VINT = { 0, UINT32_MAX, 0, YP_STIME } }, \
{ C_PROVIDE_IXFR, YP_TBOOL, YP_VBOOL = { true } }, \
{ C_DNSSEC_SIGNING, YP_TBOOL, YP_VNONE, FLAGS }, \
{ C_DNSSEC_VALIDATION, YP_TBOOL, YP_VNONE, FLAGS }, \
{ C_DNSSEC_POLICY, YP_TREF, YP_VREF = { C_POLICY }, FLAGS, { check_ref_dflt } }, \
- { C_DS_PUSH, YP_TREF, YP_VREF = { C_RMT, C_RMTS }, YP_FMULTI | FLAGS, \
+ { C_DS_PUSH, YP_TREF, YP_VREF = { C_RMT, C_RMTS }, YP_FMULTI | CONF_REF_EMPTY | FLAGS, \
{ check_ref } }, \
{ C_REVERSE_GEN, YP_TDNAME,YP_VNONE, FLAGS | CONF_IO_FRLD_ZONES }, \
{ C_SERIAL_POLICY, YP_TOPT, YP_VOPT = { serial_policies, SERIAL_POLICY_INCREMENT } }, \
bool found1 = false, found2 = false;
+ // Check if allowed empty value for specific zone items.
+ if (args->data_len == 1 && (args->item->flags & CONF_REF_EMPTY) &&
+ args->item->parent->name[0] == C_ZONE[0] &&
+ memcmp(&args->item->parent->name[1], &C_ZONE[1], C_ZONE[0]) == 0) {
+ return KNOT_EOK;
+ }
+
// Try to find the id in the first section.
found1 = conf_rawid_exists_txn(args->extra->conf, args->extra->txn,
ref->name, args->data, args->data_len);
--- /dev/null
+#!/usr/bin/env python3
+
+'''Test for configuration zone templates'''
+
+import os
+
+from dnstest.libknot import libknot
+from dnstest.test import Test
+
+t = Test()
+
+master = t.server("knot")
+slave = t.server("knot")
+zones = t.zone_rnd(2, records=5, dnssec=False)
+for z in zones:
+ z.name = z.name.lower()
+
+t.link(zones, master, slave, ixfr=True)
+
+ctl = libknot.control.KnotCtl()
+
+t.start()
+
+serials_init = master.zones_wait(zones)
+slave.zones_wait(zones)
+
+ctl.connect(os.path.join(master.dir, "knot.sock"))
+ctl.send_block(cmd="conf-begin")
+resp = ctl.receive_block()
+
+# Move notify setting from zones to the default template.
+ctl.send_block(cmd="conf-get", section="zone", item="notify", identifier=zones[0].name)
+resp = ctl.receive_block()
+for val in resp['zone'][zones[0].name]['notify']:
+ ctl.send_block(cmd="conf-set", section="template", identifier="default", item="notify", data=val)
+ resp = ctl.receive_block()
+ctl.send_block(cmd="conf-unset", section="zone", item="notify")
+resp = ctl.receive_block()
+
+# Override template setting with the default (none) for the first zone.
+ctl.send_block(cmd="conf-set", section="zone", item="notify", identifier=zones[0].name, data="")
+resp = ctl.receive_block()
+
+ctl.send_block(cmd="conf-commit")
+resp = ctl.receive_block()
+ctl.send(libknot.control.KnotCtlType.END)
+ctl.close()
+
+# Modify the zones and check that notify doesn't work for the first zone.
+serials_prev = serials_init
+serial1 = serials_init[zones[0].name]
+for i in range(2):
+ for zone in zones:
+ master.update_zonefile(zone, random=True)
+ master.ctl('zone-reload')
+
+ serials_prev = master.zones_wait(zones, serials_prev)
+ slave.zone_wait(zones[1], serials_prev[zones[1].name], equal=True, greater=False)
+ t.sleep(1)
+ slave.zone_wait(zones[0], serial1, equal=True, greater=False)
+
+t.end()