Commit 97c12e12 authored by Dominik Taborsky's avatar Dominik Taborsky

apply: add strict option for IXFR, issue 466

parent c0e422bd
......@@ -82,7 +82,7 @@ int event_dnssec(conf_t *conf, zone_t *zone)
if (zone_changed) {
/* Apply change. */
apply_ctx_t a_ctx = { { 0 } };
apply_init_ctx(&a_ctx);
apply_init_ctx(&a_ctx, APPLY_STRICT);
zone_contents_t *new_contents = NULL;
int ret = apply_changeset(&a_ctx, zone, &ch, &new_contents);
......
......@@ -373,7 +373,7 @@ static int ixfrin_finalize(struct answer_data *adata)
assert(ixfr->state == IXFR_DONE);
apply_ctx_t a_ctx = { { 0 } };
apply_init_ctx(&a_ctx);
apply_init_ctx(&a_ctx, APPLY_STRICT);
zone_contents_t *new_contents;
int ret = apply_changesets(&a_ctx, ixfr->zone, &ixfr->changesets, &new_contents);
......
......@@ -201,7 +201,13 @@ static int apply_remove(apply_ctx_t *ctx, zone_contents_t *contents, changeset_t
// Find node for this owner
zone_node_t *node = zone_contents_find_node_for_rr(contents, &rr);
if (!can_remove(node, &rr)) {
// Nothing to remove from, skip.
// Cannot be removed, either no node or nonexistent RR
if (ctx->flags & APPLY_STRICT) {
// Don't ignore missing RR if strict. Required for IXFR.
changeset_iter_clear(&itt);
return KNOT_ENORECORD;
}
rr = changeset_iter_next(&itt);
continue;
}
......@@ -369,12 +375,14 @@ static int prepare_zone_copy(zone_contents_t *old_contents,
/* ------------------------------- API -------------------------------------- */
void apply_init_ctx(apply_ctx_t *ctx)
void apply_init_ctx(apply_ctx_t *ctx, uint32_t flags)
{
assert(ctx);
init_list(&ctx->old_data);
init_list(&ctx->new_data);
ctx->flags = flags;
}
int apply_changesets(apply_ctx_t *ctx, zone_t *zone, list_t *chsets, zone_contents_t **new_contents)
......
......@@ -28,10 +28,15 @@
#include "knot/updates/changesets.h"
#include "contrib/ucw/lists.h"
enum {
APPLY_STRICT = 1 << 0, /* Apply strictly, don't ignore removing non-existent RRs. */
};
struct apply_ctx {
list_t old_data; /*!< Old data, to be freed after successful update. */
list_t new_data; /*!< New data, to be freed after failed update. */
zone_node_t *apex;
uint32_t flags;
};
typedef struct apply_ctx apply_ctx_t;
......@@ -41,7 +46,7 @@ typedef struct apply_ctx apply_ctx_t;
*
* \param ctx Context to be initialized.
*/
void apply_init_ctx(apply_ctx_t *ctx);
void apply_init_ctx(apply_ctx_t *ctx, uint32_t flags);
/*!
* \brief Applies changesets *with* zone shallow copy.
......
......@@ -242,7 +242,7 @@ int zone_update_init(zone_update_t *update, zone_t *zone, zone_update_flags_t fl
memset(update, 0, sizeof(*update));
update->zone = zone;
apply_init_ctx(&update->a_ctx);
apply_init_ctx(&update->a_ctx, 0);
mm_ctx_mempool(&update->mm, MM_DEFAULT_BLKSIZE);
update->flags = flags;
......
......@@ -129,7 +129,7 @@ int zone_load_journal(conf_t *conf, zone_t *zone, zone_contents_t *contents)
/* Apply changesets. */
apply_ctx_t a_ctx = { { 0 } };
apply_init_ctx(&a_ctx);
apply_init_ctx(&a_ctx, 0);
ret = apply_changesets_directly(&a_ctx, contents, &chgs);
if (ret == KNOT_EOK) {
......@@ -175,7 +175,7 @@ int zone_load_post(conf_t *conf, zone_t *zone, zone_contents_t *contents,
/* Apply DNSSEC changes. */
if (!changeset_empty(&change)) {
apply_ctx_t a_ctx = { { 0 } };
apply_init_ctx(&a_ctx);
apply_init_ctx(&a_ctx, APPLY_STRICT);
ret = apply_changeset_directly(&a_ctx, contents, &change);
update_cleanup(&a_ctx);
......
......@@ -66,6 +66,7 @@ enum knot_error {
KNOT_EZONENOENT,
KNOT_ENOZONE,
KNOT_ENONODE,
KNOT_ENORECORD,
KNOT_ENOMASTER,
KNOT_EDNAMEPTR,
KNOT_EPAYLOAD,
......
......@@ -65,6 +65,7 @@ static const struct error errors[] = {
{ KNOT_EZONENOENT, "zone file not found" },
{ KNOT_ENOZONE, "no such zone found" },
{ KNOT_ENONODE, "no such node in zone found" },
{ KNOT_ENORECORD, "no such record in zone found" },
{ KNOT_ENOMASTER, "no usable master" },
{ KNOT_EDNAMEPTR, "domain name pointer larger than allowed" },
{ KNOT_EPAYLOAD, "invalid EDNS payload size" },
......
......@@ -3,6 +3,7 @@
'''Test for record removal over IXFR to slave zone which doesn't contain this record'''
from dnstest.test import Test
from dnstest.utils import *
t = Test()
......@@ -26,6 +27,10 @@ slave.zone_wait(zone)
master.update_zonefile(zone, version=1)
master.reload()
if not slave.log_search("no such record in zone found") or not slave.log_search("fallback to AXFR"):
detail_log("IXFR ignored a removal of a nonexistent RR and did not fall back to AXFR")
set_err("IXFR ERROR")
# Wait for zones and compare them.
master.zone_wait(zone, serial)
slave.zone_wait(zone, serial)
......
......@@ -526,6 +526,13 @@ class Server(object):
raise Failed("Can't send RAW data (%d bytes) to server='%s'" %
(len(data), self.name))
def log_search(self, pattern):
with open(self.fout) as log:
for line in log:
if pattern in line:
return True
return False
def zone_wait(self, zone, serial=None, equal=False, greater=True):
'''Try to get SOA record. With an optional serial number and given
relation (equal or/and greater).'''
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment