- Is slow for large zones (even when changing a little).
- Recomputes all reverse records upon any change in any of the reversed zones.
+In case of secondary zone (i.e. :ref:`zone_master` is specified) this option implies
+:ref:`zone_ixfr-from-axfr`: *on* and :ref:`zone_journal-content`: *all*, otherwise
+:ref:`zone_zonefile-load`: *difference-no-serial* and :ref:`zone_journal-content`: *all*.
+
*Default:* none
.. _zone_include-from:
all delegation-related records (including NS, SOA, ...) from both zones and copies
all other records from the subzone to this zone.
-This feature works analogously to :ref:`zone_reverse-generate` in the way that subzones'
-records are being imported while loading this zone's zone file, and that it implies
+In case of secondary zone (i.e. :ref:`zone_master` is specified) this option implies
+:ref:`zone_ixfr-from-axfr`: *on* and :ref:`zone_journal-content`: *all*, otherwise
:ref:`zone_zonefile-load`: *difference-no-serial* and :ref:`zone_journal-content`: *all*.
*Default:* none
val = conf_zone_get(conf, C_ZONEFILE_LOAD, zone->name);
unsigned zf_from = conf_opt(&val);
- // Note: zone->reverse_from!=NULL almost works, but we need to check if configured even when failed.
- if (conf_zone_get(conf, C_REVERSE_GEN, zone->name).code == KNOT_EOK ||
- conf_zone_get(conf, C_INCLUDE_FROM, zone->name).code == KNOT_EOK ||
- zone->cat_members != NULL) { // This should be equivalent to setting catalog-role:generate.
+ bool includes_configured = zone_includes_configured(conf, zone);
+
+ if (includes_configured || zone->cat_members != NULL) { // The latter should be equivalent to setting catalog-role:generate.
zf_from = ZONEFILE_LOAD_DIFSE;
load_from = JOURNAL_CONTENT_ALL;
}
// Attempt to load changes from database. If fails, load full zone from there later.
if (db_enabled && (old_contents_exist || journal_conts != NULL) &&
zone->cat_members == NULL && EMPTY_LIST(zone->include_from) &&
- zf_from != ZONEFILE_LOAD_DIFSE) {
+ zf_from != ZONEFILE_LOAD_DIFSE && !includes_configured) {
zone_redis_err_t err;
uint32_t db_serial = 0;
ret = zone_redis_serial(db_ctx, db_instance, zone->name, &db_serial, err);
zone->zonefile.exists = (zf_conts != NULL);
zone->zonefile.mtime = mtime;
-zonefile_loaded: ;
+zonefile_loaded:
// If configured, add reverse records to zone contents
- const knot_dname_t *fail_fwd = NULL;
- ret = zones_reverse(&zone->include_from, zf_conts, &fail_fwd);
- if (ret == KNOT_ETRYAGAIN) {
- knot_dname_txt_storage_t forw_str;
- (void)knot_dname_to_str(forw_str, fail_fwd, sizeof(forw_str));
- log_zone_warning(zone->name, "waiting for source forward zone '%s'", forw_str);
- goto cleanup;
- } else if (ret != KNOT_EOK) {
- log_zone_error(zone->name, "failed to generate reverse records");
- goto cleanup;
+ if (includes_configured) {
+ ret = zones_reverse_log(zone, zf_conts);
+ if (ret != KNOT_EOK) {
+ goto cleanup;
+ }
}
// If configured and possible, fix the SOA serial of zonefile.
#include "knot/updates/changesets.h"
#include "knot/zone/adjust.h"
#include "knot/zone/digest.h"
+#include "knot/zone/reverse.h"
#include "knot/zone/serial.h"
#include "knot/zone/zone.h"
#include "knot/zone/zonefile.h"
bool fallback_axfr; //!< Flag allowing fallback to AXFR,
bool ixfr_by_one; //!< Allow only single changeset within IXFR.
bool ixfr_from_axfr; //!< Diff computation of incremental update from AXFR allowed.
+ bool reverse_or_include; //!< Auto reverse generation or subzone inclusion configured.
uint32_t expire_timer; //!< Result: expire timer from answer EDNS.
// internal state, initialize with zeroes:
zone_skip_t skip = { 0 };
int ret = KNOT_EOK;
- if (dnssec_enable) {
+ if (dnssec_enable || data->reverse_or_include) {
axfr_slave_sign_serial(new_zone, data->zone, data->conf, &master_serial);
ret = zone_skip_add_dnssec_diff(&skip);
assert(ret == KNOT_EOK); // static size of zone_skip is enough to cover dnssec types
}
+ if (data->reverse_or_include) {
+ ret = zones_reverse_log(data->zone, new_zone);
+ if (ret != KNOT_EOK) {
+ data->fallback->remote = false;
+ return ret;
+ }
+ }
+
zone_update_t up = { 0 };
- if (data->ixfr_from_axfr && data->axfr_style_ixfr) {
+ // With ixfr-from-axfr configured, compute diff only when axfr-style-ixfr received. With include-from, do always.
+ if (data->ixfr_from_axfr && data->zone->contents != NULL &&
+ (data->axfr_style_ixfr || data->reverse_or_include)) {
ret = zone_update_from_differences(&up, data->zone, NULL, new_zone, UPDATE_INCREMENTAL | UPDATE_EVREQ, &skip);
} else {
ret = zone_update_from_contents(&up, data->zone, new_zone, UPDATE_FULL | UPDATE_EVREQ);
return ret;
}
- if (dnssec_enable) {
+ if (dnssec_enable || data->reverse_or_include) {
ret = zone_set_master_serial(data->zone, master_serial);
if (ret != KNOT_EOK) {
log_zone_warning(data->zone->name,
finalize_timers(data);
xfr_log_publish(data, old_serial, zone_contents_serial(data->zone->contents),
- master_serial, dnssec_enable, bootstrap);
+ master_serial, dnssec_enable || data->reverse_or_include, bootstrap);
data->fallback->remote = false;
zone_set_last_master(data->zone, (const struct sockaddr_storage *)data->remote);
bool send_notify;
bool ixfr_by_one;
bool ixfr_from_axfr;
+ bool reverse_or_include;
bool more_xfr;
} try_refresh_ctx_t;
.fallback_axfr = false, // will be set upon IXFR consume
.ixfr_by_one = trctx->ixfr_by_one,
.ixfr_from_axfr = trctx->ixfr_from_axfr,
+ .reverse_or_include = trctx->reverse_or_include,
};
knot_requestor_t requestor;
val = conf_zone_get(conf, C_IXFR_FROM_AXFR, zone->name);
trctx.ixfr_from_axfr = conf_bool(&val);
+ if (zone_includes_configured(conf, zone)) {
+ trctx.force_axfr = true;
+ zone->zonefile.retransfer = true;
+ trctx.ixfr_from_axfr = true;
+ trctx.reverse_or_include = true;
+ }
+
int ret = zone_master_try(conf, zone, try_refresh, &trctx, "refresh");
zone_clear_preferred_master(zone);
if (ret != KNOT_EOK) {
{
conf_val_t val = conf_zone_get(conf, C_JOURNAL_CONTENT, update->zone->name);
unsigned content = conf_opt(&val);
+
+ if (zone_includes_configured(conf, update->zone)){
+ content = JOURNAL_CONTENT_ALL;
+ }
+
int ret = KNOT_EOK;
if (update->flags & UPDATE_NO_CHSET) {
zone_diff_t diff;
log_zone_error(update->zone->name, "failed to deallocate unused memory");
}
- zone_local_notify(update->zone);
+ zone_local_notify(conf, update->zone);
/* Sync zonefile immediately if configured. */
val = conf_zone_get(conf, C_ZONEFILE_SYNC, update->zone->name);
#include <string.h>
#include <urcu.h>
+#include "knot/common/log.h"
#include "knot/zone/reverse.h"
static const uint8_t *reverse4postfix = (const uint8_t *)"\x07""in-addr""\x04""arpa";
}
return ret;
}
+
+int zones_reverse_log(zone_t *zone, zone_contents_t *to_conts)
+{
+ const knot_dname_t *fail_fwd = NULL;
+ int ret = zones_reverse(&zone->include_from, to_conts, &fail_fwd);
+ if (ret == KNOT_ETRYAGAIN) {
+ knot_dname_txt_storage_t forw_str;
+ (void)knot_dname_to_str(forw_str, fail_fwd, sizeof(forw_str));
+ log_zone_warning(zone->name, "waiting for source forward zone '%s'", forw_str);
+ } else if (ret != KNOT_EOK) {
+ log_zone_error(zone->name, "failed to generate reverse records");
+ }
+ return ret;
+}
* \return KNOT_E*
*/
int zones_reverse(list_t *zones, zone_contents_t *to_conts, const knot_dname_t **fail_fwd);
+
+/*!
+ * \brief Reverse/include from all configured zones (in zone->include_from) and log if failed.
+ *
+ * \param zone Zone to include records from others.
+ * \param to_conts Out: resulting reverse zone.
+ *
+ * \return KNOT_E*
+ */
+int zones_reverse_log(zone_t *zone, zone_contents_t *to_conts);
return zonefile_write_skip(target, zone->contents, conf);
}
+bool zone_includes_configured(conf_t *conf, zone_t *zone)
+{
+ return conf_zone_get(conf, C_REVERSE_GEN, zone->name).code == KNOT_EOK ||
+ conf_zone_get(conf, C_INCLUDE_FROM, zone->name).code == KNOT_EOK;
+}
+
int zone_includes_add(zone_t *zone, zone_t *include, zone_include_method_t method)
{
zone_include_t *n = calloc(1, sizeof(*n));
ptrlist_find_rem(&zone->internal_notify, subscribe, NULL);
}
-void zone_local_notify(zone_t *zone)
+void zone_local_notify(conf_t *conf, zone_t *zone)
{
ptrnode_t *n;
WALK_LIST(n, zone->internal_notify) {
- zone_events_schedule_now(n->d, ZONE_EVENT_LOAD);
+ zone_t *to_notify = n->d;
+ zone_events_schedule_now(to_notify, zone_is_slave(conf, to_notify) ? ZONE_EVENT_REFRESH : ZONE_EVENT_LOAD);
}
}
*serial = zone_contents_serial(zone->contents);
conf_val_t val = conf_zone_get(conf, C_DNSSEC_SIGNING, zone->name);
- if (conf_bool(&val)) {
+ if (conf_bool(&val) || zone_includes_configured(conf, zone)) {
ret = zone_get_master_serial(zone, serial);
}
/*!
* \brief Zone inclusion (reverse generation) related ops.
*/
+bool zone_includes_configured(conf_t *conf, zone_t *zone);
int zone_includes_add(zone_t *zone, zone_t *include, zone_include_method_t method);
void zone_includes_rem(zone_t *zone, zone_t *include);
void zone_includes_clear(zone_t *zone);
void zone_local_notify_subscribe(zone_t *zone, zone_t *subscribe);
void zone_local_notify_unsubscribe(zone_t *zone, zone_t *subscribe);
-void zone_local_notify(zone_t *zone);
+void zone_local_notify(conf_t *conf, zone_t *zone);
int zone_set_master_serial(zone_t *zone, uint32_t serial);
t = Test()
-master = t.server("knot") # only providing the subzones
+master = t.server("knot") # if not tld_axfr: only providing the subzones
flattener = t.server("knot")
slave = t.server("knot") # only slaving the flattened zone
parent = t.zone("cz.", storage=".")
childs = t.zone("com.cz.", storage=".") + t.zone("net.cz.", storage=".") + t.zone("org.cz.", storage=".")
+tld_axfr = random.choice([False, True])
+
t.link(childs, master, flattener)
t.link(parent, flattener, slave)
+if tld_axfr:
+ t.link(parent, master, flattener)
+
+parent_master = master if tld_axfr else flattener
+
flattener.zones[parent[0].name].include_from = childs
flattener.dnssec(parent).enable = random.choice([False, True])
r = slave.dig("dns1.com.cz.", "AAAA")
r.check(rcode="NOERROR", rdata="1::2")
-flattener.zones[parent[0].name].zfile.append_rndTXT("txt.cz.", rdata="added-txt")
-if random.choice([False, True]):
- flattener.ctl("zone-reload " + parent[0].name)
+parent_zf = parent_master.zones[parent[0].name].zfile
+parent_zf.append_rndTXT("txt.cz.", rdata="added-txt")
+parent_zf.update_soa()
+if tld_axfr or random.choice([False, True]):
+ parent_master.ctl("zone-reload " + parent[0].name)
else:
up = master.update(childs[1])
up.add("anything", 3600, "TXT", "dontcare")