Skip to content
Snippets Groups Projects
Commit d350ef1b authored by Daniel Salzman's avatar Daniel Salzman
Browse files

Merge branch 'ixfr_history_check' into 'master'

Add check on the last journal SOA serial and current zone SOA serial equality

See merge request !1457
parents 4576d72c d920d68e
Branches
Tags
1 merge request!1457Add check on the last journal SOA serial and current zone SOA serial equality
Pipeline #99992 passed with stages
in 9 minutes and 22 seconds
......@@ -51,17 +51,20 @@ static int ixfr_put_chg_part(knot_pkt_t *pkt, struct ixfr_proc *ixfr,
if (!knot_rrset_empty(&ixfr->cur_rr)) {
IXFR_SAFE_PUT(pkt, &ixfr->cur_rr);
if (ixfr->cur_rr.type == KNOT_RRTYPE_SOA) {
ixfr->in_remove_section = !ixfr->in_remove_section;
}
journal_read_clear_rrset(&ixfr->cur_rr);
}
while (journal_read_rrset(read, &ixfr->cur_rr, true)) {
if (ixfr->cur_rr.type == KNOT_RRTYPE_SOA &&
!ixfr->in_remove_section &&
knot_soa_serial(ixfr->cur_rr.rrs.rdata) == ixfr->soa_to) {
break;
if (ixfr->cur_rr.type == KNOT_RRTYPE_SOA) {
ixfr->in_remove_section = !ixfr->in_remove_section;
if (ixfr->in_remove_section) {
if (knot_soa_serial(ixfr->cur_rr.rrs.rdata) == ixfr->soa_to) {
break;
}
} else {
ixfr->soa_last = knot_soa_serial(ixfr->cur_rr.rrs.rdata);
}
}
if (pkt->size > KNOT_WIRE_PTR_MAX) {
......@@ -71,9 +74,6 @@ static int ixfr_put_chg_part(knot_pkt_t *pkt, struct ixfr_proc *ixfr,
}
IXFR_SAFE_PUT(pkt, &ixfr->cur_rr);
if (ixfr->cur_rr.type == KNOT_RRTYPE_SOA) {
ixfr->in_remove_section = !ixfr->in_remove_section;
}
journal_read_clear_rrset(&ixfr->cur_rr);
}
......@@ -207,6 +207,7 @@ static int ixfr_answer_init(knotd_qdata_t *qdata, uint32_t *serial_from)
xfer->soa_from = knot_soa_serial(their_soa->rrs.rdata);
xfer->soa_to = zone_contents_serial(qdata->extra->contents);
xfer->soa_last = xfer->soa_from;
qdata->extra->ext = xfer;
qdata->extra->ext_cleanup = &ixfr_answer_cleanup;
......@@ -306,6 +307,10 @@ int ixfr_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
case KNOT_ESPACE: /* Couldn't write more, send packet and continue. */
return KNOT_STATE_PRODUCE; /* Check for more. */
case KNOT_EOK: /* Last response. */
if (ixfr->soa_last != ixfr->soa_to) {
IXFROUT_LOG(LOG_ERR, qdata, "failed (inconsistent history)");
return KNOT_STATE_FAIL;
}
xfr_stats_end(&ixfr->proc.stats);
xfr_log_finished(ZONE_NAME(qdata), LOG_OPERATION_IXFR, LOG_DIRECTION_OUT,
REMOTE(qdata), false, &ixfr->proc.stats);
......
/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -50,6 +50,7 @@ struct ixfr_proc {
knot_mm_t *mm;
uint32_t soa_from;
uint32_t soa_to;
uint32_t soa_last;
};
/*!
......
$ORIGIN example.com.
$TTL 3600
@ SOA dns1 hostmaster 2010111201 10800 3600 1209600 7200
NS dns1
NS dns2
MX 10 mail
dns1 A 192.0.2.1
AAAA 2001:DB8::1
dns2 A 192.0.2.2
AAAA 2001:DB8::2
mail A 192.0.2.3
AAAA 2001:DB8::3
$ORIGIN example.com.
$TTL 3600
@ SOA dns1 hostmaster 2010111202 10800 3600 1209600 7200
NS dns1
NS dns2
MX 10 mail
dns1 A 192.0.2.2
AAAA 2001:DB8::1
dns2 A 192.0.2.2
AAAA 2001:DB8::2
mail A 192.0.2.3
AAAA 2001:DB8::3
$ORIGIN example.com.
$TTL 3600
@ SOA dns1 hostmaster 2010111203 10800 3600 1209600 7200
NS dns1
NS dns2
MX 10 mail
dns1 A 192.0.2.3
AAAA 2001:DB8::1
dns2 A 192.0.2.2
AAAA 2001:DB8::2
mail A 192.0.2.3
AAAA 2001:DB8::3
#!/usr/bin/env python3
'''Test for failed IXFR with inconsistent history'''
from dnstest.test import Test
t = Test()
master = t.server("knot")
slave = t.server("knot")
zone = t.zone("example.com.", storage=".")
t.link(zone, master, slave, ixfr=True)
master.disable_notify = True
slave.disable_notify = True
t.start()
# Start both servers with the initial zone
serial = master.zone_wait(zone)
slave.zone_wait(zone)
# Add some zone history on the master only
master.update_zonefile(zone, version=1)
master.reload()
serial = master.zone_wait(zone, serial)
# Update the zone in a wrong way (zonefile-load: difference, journal-contents: changes, restart)
# -> missing a changeset in the journal
master.update_zonefile(zone, version=2)
master.stop()
master.start()
# Try to refresh slave, IXFR should fail, AXFR ok
slave.ctl("zone-refresh", wait=True)
master.zone_wait(zone, serial)
slave.zone_wait(zone, serial)
# Check that slave has the actual zone
resp = slave.dig("dns1.example.com.", "A")
resp.check()
resp.check_record(name="dns1.example.com.", rtype="A", rdata="192.0.2.3")
t.end()
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