From: Libor Peltan Date: Fri, 20 Aug 2021 13:17:09 +0000 (+0200) Subject: zonemd: create hash and bump serial when turned on X-Git-Tag: v3.1.2~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=14b8b7b691bd40daada37be4eefcc69834ec204c;p=thirdparty%2Fknot-dns.git zonemd: create hash and bump serial when turned on --- diff --git a/src/knot/updates/zone-update.c b/src/knot/updates/zone-update.c index 4636b1bcd7..fac41fb465 100644 --- a/src/knot/updates/zone-update.c +++ b/src/knot/updates/zone-update.c @@ -884,8 +884,16 @@ int zone_update_commit(conf_t *conf, zone_update_t *update) 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) { diff --git a/src/knot/zone/digest.c b/src/knot/zone/digest.c index 8587c8be4f..81f44e0240 100644 --- a/src/knot/zone/digest.c +++ b/src/knot/zone/digest.c @@ -173,6 +173,16 @@ static int verify_zonemd(const knot_rdata_t *zonemd, const zone_contents_t *cont 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) { diff --git a/src/knot/zone/digest.h b/src/knot/zone/digest.h index f136476ae5..64f33acbda 100644 --- a/src/knot/zone/digest.h +++ b/src/knot/zone/digest.h @@ -31,6 +31,14 @@ 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. * diff --git a/tests-extra/tests/zone/zonemd_flush/test.py b/tests-extra/tests/zone/zonemd_flush/test.py new file mode 100644 index 0000000000..210c7b3b00 --- /dev/null +++ b/tests-extra/tests/zone/zonemd_flush/test.py @@ -0,0 +1,38 @@ +#!/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()