bool dnssec = conf_bool(&val);
val = conf_zone_get(conf, C_ZONEMD_GENERATE, update->zone->name);
unsigned digest_alg = conf_opt(&val);
- if (digest_alg != ZONE_DIGEST_NONE && !dnssec && // in case of DNSSEC, digest is part of signing routine
- ((update->flags & UPDATE_FULL) || zone_update_to(update) != NULL)) {
+ bool do_digest = (digest_alg != ZONE_DIGEST_NONE && !dnssec); // in case of DNSSEC, digest is part of signing routine
+ if (do_digest && !(update->flags & UPDATE_FULL) && zone_update_to(update) == NULL) {
+ // cold start, decide if (digest & bump SOA) or NOOP
+ if (zone_contents_digest_exists(update->new_cont, digest_alg)) { // yes, computing hash twice, but in rare situation: cold start & exists & invalid
+ do_digest = false;
+ } else {
+ ret = zone_update_increment_soa(update, conf);
+ }
+ }
+ if (do_digest && ret == KNOT_EOK) {
ret = zone_update_add_digest(update, digest_alg, false);
}
if (ret != KNOT_EOK) {
return ret;
}
+bool zone_contents_digest_exists(const zone_contents_t *contents, uint8_t alg)
+{
+ knot_rdataset_t *zonemd = node_rdataset(contents->apex, KNOT_RRTYPE_ZONEMD);
+ if (zonemd == NULL || zonemd->count != 1 || knot_zonemd_algorithm(zonemd->rdata) != alg) {
+ return false;
+ }
+
+ return verify_zonemd(zonemd->rdata, contents) == KNOT_EOK;
+}
+
static bool check_duplicate_schalg(const knot_rdataset_t *zonemd, int check_upto,
uint8_t scheme, uint8_t alg)
{
int zone_contents_digest(const zone_contents_t *contents, int algorithm,
uint8_t **out_digest, size_t *out_size);
+/*!
+ * \brief Check whether exactly one ZONEMD exists in the zone, is valid and matches given algorithm.
+ *
+ * \param contents Zone contents to be verified.
+ * \param alg Required algorithm of the ZONEMD.
+ */
+bool zone_contents_digest_exists(const zone_contents_t *contents, uint8_t alg);
+
/*!
* \brief Verify zone dgest in ZONEMD record.
*
--- /dev/null
+#!/usr/bin/env python3
+
+'''Flushing the zone after ZONEMD generation.'''
+
+from dnstest.test import Test
+from dnstest.utils import *
+
+def has_zonemd(server, zone, alg):
+ zfn = server.zones[zone.name].zfile.path
+ with open(zfn) as zf:
+ for line in zf:
+ rr = line.split()
+ if rr[0].lower() == zone.name.lower() and rr[2] == "ZONEMD" and rr[5] == alg:
+ return True
+ return False
+
+def check_zonemd(server, zone, alg):
+ for z in zone:
+ if not has_zonemd(server, z, alg):
+ set_err("NO ZONEMD in %s" % z.name)
+
+t = Test()
+
+master = t.server("knot")
+
+zone = t.zone_rnd(2, dnssec=False, records=10)
+t.link(zone, master)
+
+master.zonefile_sync = 0
+master.zonemd_generate = "zonemd-sha384"
+
+t.start()
+
+master.zones_wait(zone)
+t.sleep(4)
+check_zonemd(master, zone, "1")
+
+t.end()