Commit ec2112cc authored by Daniel Salzman's avatar Daniel Salzman

knot: don't fail if TTL mismatch, unify TTL processing

parent 014a4436
......@@ -816,7 +816,7 @@ static int get_ttl(zone_t *zone, ctl_args_t *args, uint32_t *ttl)
const zone_node_t *node = zone_update_get_node(zone->control_update, owner);
if (node == NULL) {
return KNOT_ETTL;
return KNOT_EINVAL;
}
uint16_t type;
......@@ -928,11 +928,6 @@ static int zone_txn_set(zone_t *zone, ctl_args_t *args)
ret = zone_update_add(zone->control_update, rrset);
knot_rrset_free(&rrset, NULL);
// Silently update TTL.
if (ret == KNOT_ETTL) {
ret = KNOT_EOK;
}
return ret;
}
......
......@@ -175,7 +175,7 @@ static int process_normal(conf_t *conf, zone_t *zone, list_t *requests)
ret = zone_update_commit(conf, &up);
zone_update_clear(&up);
if (ret != KNOT_EOK) {
if (ret == KNOT_ETTL || ret == KNOT_EZONESIZE) {
if (ret == KNOT_EZONESIZE) {
set_rcodes(requests, KNOT_RCODE_REFUSED);
} else {
set_rcodes(requests, KNOT_RCODE_SERVFAIL);
......
......@@ -299,7 +299,7 @@ int apply_add_rr(apply_ctx_t *ctx, const knot_rrset_t *rr)
knot_rrtype_to_string(rr->type, type, sizeof(type));
log_zone_notice(contents->apex->owner,
"TTL mismatch, owner %s, type %s, "
"TTL updated to %u", owner, type, rr->ttl);
"TTL set to %u", owner, type, rr->ttl);
return KNOT_EOK;
}
}
......
......@@ -48,7 +48,9 @@ static int add_rr_to_contents(zone_contents_t *z, const knot_rrset_t *rrset)
zone_node_t *n = NULL;
int ret = zone_contents_add_rr(z, rrset, &n);
UNUSED(n);
return ret;
// We don't care of TTLs.
return ret == KNOT_ETTL ? KNOT_EOK : ret;
}
/*! \brief Cleans up trie iterations. */
......@@ -341,12 +343,9 @@ int changeset_add_removal(changeset_t *ch, const knot_rrset_t *rrset, changeset_
if (flags & CHANGESET_CHECK) {
knot_rrset_free((knot_rrset_t **)&rrset, NULL);
}
knot_rrset_free(&rrset_cancelout, NULL);
// we don't care of TTLs at removals anyway (updates/apply.c/can_remove()/compare_ttls)
// in practice, this happens at merging changesets
return (ret == KNOT_ETTL ? KNOT_EOK : ret);
return ret;
}
int changeset_remove_addition(changeset_t *ch, const knot_rrset_t *rrset)
......
......@@ -692,7 +692,7 @@ static uint16_t ret_to_rcode(int ret)
{
if (ret == KNOT_EMALF) {
return KNOT_RCODE_FORMERR;
} else if (ret == KNOT_EDENIED || ret == KNOT_ETTL) {
} else if (ret == KNOT_EDENIED) {
return KNOT_RCODE_REFUSED;
} else {
return KNOT_RCODE_SERVFAIL;
......
......@@ -87,7 +87,12 @@ static int replace_soa(zone_contents_t *contents, const knot_rrset_t *rr)
return ret;
}
return zone_contents_add_rr(contents, rr, &n);
ret = zone_contents_add_rr(contents, rr, &n);
if (ret == KNOT_ETTL) {
return KNOT_EOK;
}
return ret;
}
/* ------------------------------- API -------------------------------------- */
......@@ -326,7 +331,22 @@ int zone_update_add(zone_update_t *update, const knot_rrset_t *rrset)
}
zone_node_t *n = NULL;
return zone_contents_add_rr(update->new_cont, rrset, &n);
int ret = zone_contents_add_rr(update->new_cont, rrset, &n);
if (ret == KNOT_ETTL) {
char buff[KNOT_DNAME_TXT_MAXLEN + 1];
char *owner = knot_dname_to_str(buff, rrset->owner, sizeof(buff));
if (owner == NULL) {
owner = "";
}
char type[16] = { '\0' };
knot_rrtype_to_string(rrset->type, type, sizeof(type));
log_zone_notice(update->new_cont->apex->owner,
"TTL mismatch, owner %s, type %s, "
"TTL set to %u", owner, type, rrset->ttl);
return KNOT_EOK;
}
return ret;
} else {
return KNOT_EINVAL;
}
......
......@@ -74,13 +74,12 @@ static int add_rrset_no_merge(zone_node_t *node, const knot_rrset_t *rrset,
}
/*! \brief Checks if the added RR has the same TTL as the first RR in the node. */
static bool ttl_error(struct rr_data *node_data, const knot_rrset_t *rrset)
static bool ttl_changed(struct rr_data *node_data, const knot_rrset_t *rrset)
{
if (rrset->type == KNOT_RRTYPE_RRSIG || node_data->rrs.rr_count == 0) {
return false;
}
// Return error if TTLs don't match.
return rrset->ttl != node_data->ttl;
}
......@@ -178,8 +177,8 @@ int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, knot_mm_t *mm)
for (uint16_t i = 0; i < node->rrset_count; ++i) {
if (node->rrs[i].type == rrset->type) {
struct rr_data *node_data = &node->rrs[i];
const bool ttl_err = ttl_error(node_data, rrset);
if (ttl_err) {
const bool ttl_change = ttl_changed(node_data, rrset);
if (ttl_change) {
node_data->ttl = rrset->ttl;
}
......@@ -188,7 +187,7 @@ int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, knot_mm_t *mm)
if (ret != KNOT_EOK) {
return ret;
} else {
return ttl_err ? KNOT_ETTL : KNOT_EOK;
return ttl_change ? KNOT_ETTL : KNOT_EOK;
}
}
}
......
......@@ -138,6 +138,7 @@ zone_node_t *node_shallow_copy(const zone_node_t *src, knot_mm_t *mm);
* \param mm Memory context to use.
*
* \return KNOT_E*
* \retval KNOT_ETTL RRSet TTL was updated.
*/
int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, knot_mm_t *mm);
......
......@@ -36,7 +36,7 @@
#define ERROR(zone, fmt, ...) log_zone_error(zone, "zone loader, " fmt, ##__VA_ARGS__)
#define WARNING(zone, fmt, ...) log_zone_warning(zone, "zone loader, " fmt, ##__VA_ARGS__)
#define INFO(zone, fmt, ...) log_zone_info(zone, "zone loader, " fmt, ##__VA_ARGS__)
#define NOTICE(zone, fmt, ...) log_zone_notice(zone, "zone loader, " fmt, ##__VA_ARGS__)
static void process_error(zs_scanner_t *s)
{
......@@ -65,15 +65,9 @@ static bool handle_err(zcreator_t *zc, const knot_rrset_t *rr, int ret, bool mas
} else if (ret == KNOT_ETTL) {
char type[16] = { '\0' };
knot_rrtype_to_string(rr->type, type, sizeof(type));
if (master) {
WARNING(zname, "TTL mismatch, owner %s, type %s",
owner, type);
} else {
WARNING(zname, "TTL mismatch, owner %s, type %s, "
"TTL set to %u", owner, type, rr->ttl);
}
// Fail if we're the master for this zone.
return !master;
NOTICE(zname, "TTL mismatch, owner %s, type %s, TTL set to %u",
owner, type, rr->ttl);
return true;
} else {
ERROR(zname, "failed to process record, owner %s", owner);
return false;
......@@ -99,10 +93,6 @@ int zcreator_step(zcreator_t *zc, const knot_rrset_t *rr)
// Fatal error
return ret;
}
if (ret == KNOT_EOUTOFZONE) {
// Skip out-of-zone record
return KNOT_EOK;
}
}
return KNOT_EOK;
......@@ -350,4 +340,4 @@ void err_handler_logger(sem_handler_t *handler, const zone_contents_t *zone,
#undef ERROR
#undef WARNING
#undef INFO
#undef NOTICE
......@@ -27,16 +27,17 @@ resp.check_record(section="answer", rtype="A", ttl="1000", rdata="192.0.2.3")
resp.check_record(section="answer", rtype="A", ttl="1000", rdata="1.2.3.4")
# Try to add two RRs belonging to one RRSet, but with different TTLs
# The UPDATE should be REFUSED
# This also tests rollback in case of addition
# The UPDATE should be accepted and all TTLs should change to be the same value
check_log("Add RRSet with incoherent TTLs")
up = master.update(zone)
up.add("test.example.com.", 1000, "A", "1.2.3.4")
up.add("test.example.com.", 2000, "A", "2.3.4.5")
up.send("REFUSED")
up.send("NOERROR")
resp = master.dig("test.example.com.", "A")
resp.check(rcode="NXDOMAIN")
resp.check(rcode="NOERROR")
resp.check_record(section="answer", rtype="A", ttl="2000", rdata="1.2.3.4")
resp.check_record(section="answer", rtype="A", ttl="2000", rdata="2.3.4.5")
# First, delete RRSet already in zone, then add new RR with different TTL
# The UPDATE should be accepted and the new RR should be present in the zone
......
$ORIGIN ttl-mismatch.
$TTL 3600
@ SOA dns1 hostmaster 2010111201 10800 3600 1209600 7200
NS dns1
NS dns2
MX 10 mail
ttl A 192.0.2.1
A 192.0.3.1
7200 A 192.0.4.1
AAAA 2001:DB8::1
AAAA 2001:DB9::1
#!/usr/bin/env python3
'''Test for mismatched TTLs handling on slave zone load.'''
'''NOTE: dnspython can't keep different TTLs in one rrset. So we can't check
the slave server properly.'''
from dnstest.test import Test
t = Test()
master = t.server("dummy")
slave = t.server("knot")
zone = t.zone("ttl-mismatch.", storage=".", exists=False)
t.link(zone, master, slave)
# Create invalid zone file.
slave.update_zonefile(zone, version=1)
t.start()
# Check if the zone was loaded.
resp = slave.dig("ttl.ttl-mismatch.", "A")
resp.check(rcode="NOERROR", flags="QR AA", noflags="TC AD RA")
t.end()
#!/usr/bin/env python3
'''Test for loading of zone containing mismatched TTLs'''
'''Test for loading of zone containing mismatched TTLs in RRSet'''
from dnstest.test import Test
t = Test()
master = t.server("knot")
zone = t.zone("ttl-mismatch", storage=".")
t.link(zone, master)
t.start()
# Just check if the zone was loaded. It should be unloadable on master.
resp = master.dig(zone, "SOA")
resp.check(rcode="SERVFAIL", flags="QR", noflags="AA TC AD RA")
master.zones_wait(zone)
resp = master.dig("ttl.ttl-mismatch.", "A")
resp.check(rcode="NOERROR", flags="QR AA", noflags="TC AD RA", ttl=7200)
t.end()
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