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

Merge branch 'zonemd_flush' into 'master'

Zonemd flush

Closes #758

See merge request !1358
parents 3fa5366b 0250ad1f
No related branches found
No related tags found
1 merge request!1358Zonemd flush
Pipeline #87846 passed
......@@ -1949,24 +1949,13 @@ On each zone update, calculate ZONEMD and put it into the zone.
Possible values:
.INDENT 0.0
.IP \(bu 2
\fBnone\fP – No ZONEMD is generated.
\fBnone\fP – No action regarding ZONEMD.
.IP \(bu 2
\fBzonemd\-sha384\fP – Generate ZONEMD using SHA384 algorithm.
.IP \(bu 2
\fBzonemd\-sha512\fP – Generate ZONEMD using SHA512 algorithm.
.UNINDENT
.sp
\fBWARNING:\fP
.INDENT 0.0
.INDENT 3.5
After this configuration is changed, it\(aqs possible that new ZONEMD
won\(aqt be generated until some other update/change to the zone appears.
If DNSSEC is enabled, it\(aqs recommended to force re\-sign the zone
after setting this option to generating ZONEMD, or after changing
the algorithm.
.UNINDENT
.UNINDENT
.sp
\fIDefault:\fP none
.SS serial\-policy
.sp
......
......@@ -2098,17 +2098,10 @@ On each zone update, calculate ZONEMD and put it into the zone.
Possible values:
- ``none`` – No ZONEMD is generated.
- ``none`` – No action regarding ZONEMD.
- ``zonemd-sha384`` – Generate ZONEMD using SHA384 algorithm.
- ``zonemd-sha512`` – Generate ZONEMD using SHA512 algorithm.
.. WARNING::
After this configuration is changed, it's possible that new ZONEMD
won't be generated until some other update/change to the zone appears.
If DNSSEC is enabled, it's recommended to force re-sign the zone
after setting this option to generating ZONEMD, or after changing
the algorithm.
*Default:* none
.. _zone_serial-policy:
......
......@@ -405,8 +405,8 @@ static const yp_item_t desc_policy[] = {
{ C_DNSSEC_VALIDATION, YP_TBOOL, YP_VNONE, FLAGS }, \
{ C_DNSSEC_POLICY, YP_TREF, YP_VREF = { C_POLICY }, FLAGS, { check_ref_dflt } }, \
{ C_SERIAL_POLICY, YP_TOPT, YP_VOPT = { serial_policies, SERIAL_POLICY_INCREMENT } }, \
{ C_ZONEMD_GENERATE, YP_TOPT, YP_VOPT = { zone_digest, ZONE_DIGEST_NONE } }, \
{ C_ZONEMD_VERIFY, YP_TBOOL, YP_VNONE }, \
{ C_ZONEMD_GENERATE, YP_TOPT, YP_VOPT = { zone_digest, ZONE_DIGEST_NONE }, FLAGS }, \
{ C_ZONEMD_VERIFY, YP_TBOOL, YP_VNONE, FLAGS }, \
{ C_REFRESH_MIN_INTERVAL,YP_TINT, YP_VINT = { 2, UINT32_MAX, 2, YP_STIME } }, \
{ C_REFRESH_MAX_INTERVAL,YP_TINT, YP_VINT = { 2, UINT32_MAX, UINT32_MAX, YP_STIME } }, \
{ C_CATALOG_ROLE, YP_TOPT, YP_VOPT = { catalog_roles, CATALOG_ROLE_NONE }, FLAGS }, \
......
......@@ -884,8 +884,17 @@ 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
// yes, computing hash twice, but in rare situation: cold start & exists & invalid
if (zone_contents_digest_exists(update->new_cont, digest_alg, false)) {
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) {
......
......@@ -173,6 +173,24 @@ 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, bool no_verify)
{
if (alg == 0) {
return true;
}
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;
}
if (no_verify) {
return true;
}
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)
{
......
......@@ -31,6 +31,15 @@
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.
* \param no_verify Don't verify the validness of the digest in ZONEMD.
*/
bool zone_contents_digest_exists(const zone_contents_t *contents, uint8_t alg, bool no_verify);
/*!
* \brief Verify zone dgest in ZONEMD record.
*
......
......@@ -23,6 +23,7 @@
#include "knot/conf/module.h"
#include "knot/events/replan.h"
#include "knot/journal/journal_metadata.h"
#include "knot/zone/digest.h"
#include "knot/zone/timers.h"
#include "knot/zone/zone-load.h"
#include "knot/zone/zone.h"
......@@ -100,6 +101,11 @@ static zone_t *create_zone_reload(conf_t *conf, const knot_dname_t *name,
bool conf_updated = (old_zone->change_type & CONF_IO_TRELOAD);
conf_val_t digest = conf_zone_get(conf, C_ZONEMD_GENERATE, name);
if (zone->contents != NULL && !zone_contents_digest_exists(zone->contents, conf_opt(&digest), true)) {
conf_updated = true;
}
if ((zone_file_updated(conf, old_zone, name) || conf_updated) && !zone_expired(zone)) {
replan_load_updated(zone, old_zone);
} else {
......
#!/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()
serial = master.zones_wait(zone)
t.sleep(4)
check_zonemd(master, zone, "1")
master.zonemd_generate = "zonemd-sha512"
master.gen_confile()
master.reload()
master.zones_wait(zone, serial)
t.sleep(4)
check_zonemd(master, zone, "2")
t.end()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment