zonemd, dnssec verification routines.

This commit is contained in:
W.C.A. Wijngaards 2020-10-14 13:34:50 +02:00
parent efc01c928c
commit 22e82765f9
3 changed files with 541 additions and 33 deletions

View file

@ -69,6 +69,8 @@
#include "validator/val_nsec3.h" #include "validator/val_nsec3.h"
#include "validator/val_secalgo.h" #include "validator/val_secalgo.h"
#include "validator/val_sigcrypt.h" #include "validator/val_sigcrypt.h"
#include "validator/val_anchor.h"
#include "validator/val_utils.h"
#include <ctype.h> #include <ctype.h>
/** bytes to use for NSEC3 hash buffer. 20 for sha1 */ /** bytes to use for NSEC3 hash buffer. 20 for sha1 */
@ -1789,46 +1791,39 @@ static int zonemd_fetch_parameters(struct auth_rrset* zonemd_rrset, size_t i,
* it can warn or fail on that. Checks the hash of the ZONEMD. * it can warn or fail on that. Checks the hash of the ZONEMD.
* @param z: auth zone to check for. * @param z: auth zone to check for.
* caller must hold lock on zone. * caller must hold lock on zone.
* @param cfg: config file options * @param env: module env for temp buffers.
* @param reason: returned on failure.
* @return false on failure, true if hash checks out.
*/ */
void auth_zone_zonemd_check_hash(struct auth_zone* z /*, struct config_file* cfg*/) static int auth_zone_zonemd_check_hash(struct auth_zone* z,
struct module_env* env, char** reason)
{ {
/* loop over ZONEMDs and see which one is valid. if not print /* loop over ZONEMDs and see which one is valid. if not print
* failure (depending on config) */ * failure (depending on config) */
struct auth_data* apex; struct auth_data* apex;
struct auth_rrset* zonemd_rrset; struct auth_rrset* zonemd_rrset;
size_t i; size_t i;
char* reason = NULL;
struct regional* region = NULL; struct regional* region = NULL;
struct sldns_buffer* buf = NULL; struct sldns_buffer* buf = NULL;
char zstr[255+1]; char zstr[255+1];
uint32_t soa_serial = 0; uint32_t soa_serial = 0;
region = regional_create(); region = env->scratch;
if(!region) { regional_free_all(region);
return; buf = env->scratch_buffer;
}
buf = sldns_buffer_new(65535);
if(!buf) {
regional_destroy(region);
return;
}
if(!auth_zone_get_serial(z, &soa_serial)) { if(!auth_zone_get_serial(z, &soa_serial)) {
regional_destroy(region); *reason = "zone has no SOA serial";
sldns_buffer_free(buf); return 0;
return;
} }
apex = az_find_name(z, z->name, z->namelen); apex = az_find_name(z, z->name, z->namelen);
if(!apex) { if(!apex) {
regional_destroy(region); *reason = "zone has no apex";
sldns_buffer_free(buf); return 0;
return;
} }
zonemd_rrset = az_domain_rrset(apex, LDNS_RR_TYPE_ZONEMD); zonemd_rrset = az_domain_rrset(apex, LDNS_RR_TYPE_ZONEMD);
if(!zonemd_rrset || zonemd_rrset->data->count==0) { if(!zonemd_rrset || zonemd_rrset->data->count==0) {
regional_destroy(region); *reason = "zone has no ZONEMD";
sldns_buffer_free(buf); return 0; /* no RRset or no RRs in rrset */
return; /* no RRset or no RRs in rrset */
} }
/* we have a ZONEMD, check if it is correct */ /* we have a ZONEMD, check if it is correct */
@ -1840,34 +1835,31 @@ void auth_zone_zonemd_check_hash(struct auth_zone* z /*, struct config_file* cfg
if(!zonemd_fetch_parameters(zonemd_rrset, i, &serial, &scheme, if(!zonemd_fetch_parameters(zonemd_rrset, i, &serial, &scheme,
&hashalgo, &hash, &hashlen)) { &hashalgo, &hash, &hashlen)) {
/* malformed RR */ /* malformed RR */
reason = "ZONEMD rdata malformed"; *reason = "ZONEMD rdata malformed";
continue; continue;
} }
regional_free_all(region);
if(serial != soa_serial) { if(serial != soa_serial) {
reason = "ZONEMD serial is wrong"; *reason = "ZONEMD serial is wrong";
continue; continue;
} }
if(auth_zone_generate_zonemd_check(z, scheme, hashalgo, if(auth_zone_generate_zonemd_check(z, scheme, hashalgo,
hash, hashlen, region, buf, &reason)) { hash, hashlen, region, buf, reason)) {
/* success */ /* success */
if(verbosity >= VERB_ALGO) { if(verbosity >= VERB_ALGO) {
dname_str(z->name, zstr); dname_str(z->name, zstr);
verbose(VERB_ALGO, "auth-zone %s ZONEMD hash is correct", zstr); verbose(VERB_ALGO, "auth-zone %s ZONEMD hash is correct", zstr);
} }
regional_destroy(region); return 1;
sldns_buffer_free(buf);
return;
} }
/* try next one */ /* try next one */
} }
/* fail, we may have reason */ /* fail, we may have reason */
if(!reason) if(!*reason)
reason = "no ZONEMD records found"; *reason = "no ZONEMD records found";
dname_str(z->name, zstr); dname_str(z->name, zstr);
log_warn("auth-zone %s ZONEMD failed: %s", zstr, reason); log_warn("auth-zone %s ZONEMD failed: %s", zstr, *reason);
return 0;
regional_destroy(region);
sldns_buffer_free(buf);
} }
/** find serial number of zone or false if none */ /** find serial number of zone or false if none */
@ -7501,12 +7493,509 @@ int auth_zone_generate_zonemd_check(struct auth_zone* z, int scheme,
/* check digest length */ /* check digest length */
if(hashlen != genlen) { if(hashlen != genlen) {
*reason = "incorrect digest length"; *reason = "incorrect digest length";
if(verbosity >= VERB_ALGO) {
verbose(VERB_ALGO, "zonemd scheme=%d hashalgo=%d",
scheme, hashalgo);
log_hex("ZONEMD should be ", gen, genlen);
log_hex("ZONEMD to check is", hash, hashlen);
}
return 0; return 0;
} }
/* check digest */ /* check digest */
if(memcmp(hash, gen, genlen) != 0) { if(memcmp(hash, gen, genlen) != 0) {
*reason = "incorrect digest"; *reason = "incorrect digest";
if(verbosity >= VERB_ALGO) {
verbose(VERB_ALGO, "zonemd scheme=%d hashalgo=%d",
scheme, hashalgo);
log_hex("ZONEMD should be ", gen, genlen);
log_hex("ZONEMD to check is", hash, hashlen);
}
return 0; return 0;
} }
return 1; return 1;
} }
/** log auth zone message with zone name in front. */
static void auth_zone_log(uint8_t* name, enum verbosity_value level, const char* format, ...) ATTR_FORMAT(printf, 3, 4);
static void auth_zone_log(uint8_t* name, enum verbosity_value level, const char* format, ...)
{
va_list args;
va_start(args, format);
if(verbosity >= level) {
char str[255+1];
char msg[MAXSYSLOGMSGLEN];
dname_str(name, str);
vsnprintf(msg, sizeof(msg), format, args);
verbose(level, "auth zone %s %s", str, msg);
}
va_end(args);
}
/** ZONEMD, dnssec verify the rrset with the dnskey */
static int zonemd_dnssec_verify(struct auth_zone* z, struct module_env* env,
struct ub_packed_rrset_key* dnskey, struct auth_rrset* rrset)
{
struct ub_packed_rrset_key pk;
enum sec_status sec;
struct val_env* ve;
int m;
char* why_bogus = NULL;
m = modstack_find(&env->mesh->mods, "validator");
if(m == -1) {
auth_zone_log(z->name, VERB_ALGO, "zonemd dnssec verify: have "
"trust anchor, but no validator module");
return 0;
}
ve = (struct val_env*)env->modinfo[m];
memset(&pk, 0, sizeof(pk));
pk.entry.key = &pk;
pk.entry.data = rrset->data;
pk.rk.dname = z->name;
pk.rk.dname_len = z->namelen;
pk.rk.type = htons(rrset->type);
pk.rk.rrset_class = htons(z->dclass);
auth_zone_log(z->name, VERB_ALGO,
"zonemd: verify RRset with DNSKEY");
/* pass NULL for qstate, it is only used for qtype NSEC to realloc
* a new name in the qstate region */
sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, NULL, &why_bogus,
LDNS_SECTION_ANSWER, NULL);
regional_free_all(env->scratch);
if(sec == sec_status_secure) {
return 1;
}
if(why_bogus)
auth_zone_log(z->name, VERB_ALGO, "DNSSEC verify was bogus: %s", why_bogus);
return 0;
}
/** Verify the absence of ZONEMD with DNSSEC by checking NSEC, NSEC3 type flag.
* return false on failure, reason contains description of failure. */
static int zonemd_check_dnssec_absence(struct auth_zone* z,
struct module_env* env, struct ub_packed_rrset_key* dnskey,
struct auth_data* apex, char** reason)
{
struct auth_rrset* nsec = NULL;
if(!apex) {
*reason = "zone has no apex domain but ZONEMD missing";
return 0;
}
nsec = az_domain_rrset(apex, LDNS_RR_TYPE_NSEC);
if(nsec) {
/* dnssec verify the NSEC */
if(!zonemd_dnssec_verify(z, env, dnskey, nsec)) {
*reason = "DNSSEC verify failed for NSEC RRset";
return 0;
}
/* check type bitmap */
} else {
/* NSEC3 perhaps ? */
int algo;
size_t iter, saltlen;
uint8_t* salt;
struct auth_rrset* nsec3param = az_domain_rrset(apex,
LDNS_RR_TYPE_NSEC3PARAM);
struct auth_data* match;
struct auth_rrset* nsec3;
if(!nsec3param) {
*reason = "zone has no NSEC information but ZONEMD missing";
return 0;
}
if(!az_nsec3_param(z, &algo, &iter, &salt, &saltlen)) {
*reason = "zone has no NSEC information but ZONEMD missing";
return 0;
}
/* find the NSEC3 record */
match = az_nsec3_find_exact(z, z->name, z->namelen, algo,
iter, salt, saltlen);
if(!match) {
*reason = "zone has no NSEC3 domain for the apex but ZONEMD missing";
return 0;
}
nsec3 = az_domain_rrset(match, LDNS_RR_TYPE_NSEC3);
if(!nsec3) {
*reason = "zone has no NSEC3 RRset for the apex but ZONEMD missing";
return 0;
}
/* dnssec verify the NSEC3 */
if(!zonemd_dnssec_verify(z, env, dnskey, nsec3)) {
*reason = "DNSSEC verify failed for NSEC3 RRset";
return 0;
}
/* check type bitmap */
}
return 1;
}
/** Verify the SOA and ZONEMD DNSSEC signatures.
* return false on failure, reason contains description of failure. */
static int zonemd_check_dnssec_soazonemd(struct auth_zone* z,
struct module_env* env, struct ub_packed_rrset_key* dnskey,
struct auth_data* apex, struct auth_rrset* zonemd_rrset,
char** reason)
{
struct auth_rrset* soa;
if(!apex) {
*reason = "zone has no apex domain";
return 0;
}
soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
if(!soa) {
*reason = "zone has no SOA RRset";
return 0;
}
if(!zonemd_dnssec_verify(z, env, dnskey, soa)) {
*reason = "DNSSEC verify failed for SOA RRset";
return 0;
}
if(!zonemd_dnssec_verify(z, env, dnskey, zonemd_rrset)) {
*reason = "DNSSEC verify failed for ZONEMD RRset";
return 0;
}
auth_zone_log(z->name, VERB_ALGO, "zonemd DNSSEC verification of SOA and ZONEMD RRsets secure");
return 1;
}
/**
* Fail the ZONEMD verification.
* @param z: auth zone that fails.
* @param env: environment with config, to ignore failure or not.
* @param reason: failure string description.
*/
static void auth_zone_zonemd_fail(struct auth_zone* z, struct module_env* env,
char* reason)
{
char zstr[255+1];
/* if fail: log reason, and depending on config also take action
* and drop the zone, eg. it is gone from memory, set zone_expired */
dname_str(z->name, zstr);
if(!reason) reason = "verification failed";
log_warn("auth zone %s: ZONEMD verification failed: %s", zstr, reason);
/* expired means the zone gives servfail and is not used by
* lookup if fallback_enabled*/
z->zone_expired = 1;
}
/**
* Verify the zonemd with DNSSEC and hash check, with given key.
* @param z: auth zone.
* @param env: environment with config and temp buffers.
* @param dnskey: dnskey that we can use, or NULL. If nonnull, the key
* has been verified and is the start of the chain of trust.
* @param is_insecure: if true, the dnskey is not used, the zone is insecure.
* And dnssec is not used. It is DNSSEC secure insecure or not under
* a trust anchor.
*/
static void
auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env,
struct ub_packed_rrset_key* dnskey, int is_insecure)
{
char* reason = NULL;
struct auth_data* apex = NULL;
struct auth_rrset* zonemd_rrset = NULL;
int zonemd_absent = 0;
/* see if ZONEMD is present or absent. */
apex = az_find_name(z, z->name, z->namelen);
if(!apex) {
zonemd_absent = 1;
} else {
zonemd_rrset = az_domain_rrset(apex, LDNS_RR_TYPE_ZONEMD);
if(!zonemd_rrset || zonemd_rrset->data->count==0) {
zonemd_absent = 1;
zonemd_rrset = NULL;
}
}
/* if no ZONEMD, and no DNSSEC, done. */
/* if no ZONEMD, and DNSSEC, use DNSKEY to verify NSEC or NSEC3 for
* zone apex. Check ZONEMD bit is turned off or else fail */
/* if ZONEMD, and DNSSEC, check DNSSEC signature on SOA and ZONEMD,
* or else fail */
if(!zonemd_rrset && is_insecure) {
/* success, zonemd is absent */
} else if(!zonemd_rrset) {
/* fetch, DNSSEC verify, and check NSEC/NSEC3 */
if(!zonemd_check_dnssec_absence(z, env, dnskey, apex,
&reason)) {
auth_zone_zonemd_fail(z, env, reason);
return;
}
} else if(zonemd_rrset && dnskey) {
/* check DNSSEC verify of SOA and ZONEMD */
if(!zonemd_check_dnssec_soazonemd(z, env, dnskey, apex,
zonemd_rrset, &reason)) {
auth_zone_zonemd_fail(z, env, reason);
return;
}
}
/* check ZONEMD checksum and report or else fail. */
if(!auth_zone_zonemd_check_hash(z, env, &reason)) {
auth_zone_zonemd_fail(z, env, reason);
return;
}
if(zonemd_absent)
auth_zone_zonemd_fail(z, env, "ZONEMD absent and that is not allowed by config");
/* success! log the success */
auth_zone_log(z->name, VERB_ALGO, "ZONEMD verification successful");
}
/**
* verify the zone DNSKEY rrset from the trust anchor
* This is possible because the anchor is for the zone itself, and can
* thus apply straight to the zone DNSKEY set.
* @param z: the auth zone.
* @param env: environment with time and temp buffers.
* @param anchor: trust anchor to use
* @param is_insecure: returned, true if the zone is securely insecure.
* @param reason: if the routine fails, returns the failure reason.
* @param keystorage: where to store the ub_packed_rrset_key that is created
* on success. A pointer to it is returned on success.
* @return the dnskey RRset, reference to zone data and keystorage, or
* NULL on failure.
*/
static struct ub_packed_rrset_key*
zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env,
struct trust_anchor* anchor, int* is_insecure, char** reason,
struct ub_packed_rrset_key* keystorage)
{
struct auth_data* apex;
struct auth_rrset* dnskey_rrset;
enum sec_status sec;
struct val_env* ve;
int m;
apex = az_find_name(z, z->name, z->namelen);
if(!apex) {
*reason = "have trust anchor, but zone has no apex domain for DNSKEY";
return 0;
}
dnskey_rrset = az_domain_rrset(apex, LDNS_RR_TYPE_DNSKEY);
if(!dnskey_rrset || dnskey_rrset->data->count==0) {
*reason = "have trust anchor, but zone has no DNSKEY";
return 0;
}
m = modstack_find(&env->mesh->mods, "validator");
if(m == -1) {
*reason = "have trust anchor, but no validator module";
return 0;
}
ve = (struct val_env*)env->modinfo[m];
memset(keystorage, 0, sizeof(*keystorage));
keystorage->entry.key = keystorage;
keystorage->entry.data = dnskey_rrset->data;
keystorage->rk.dname = apex->name;
keystorage->rk.dname_len = apex->namelen;
keystorage->rk.type = htons(LDNS_RR_TYPE_DNSKEY);
keystorage->rk.rrset_class = htons(z->dclass);
auth_zone_log(z->name, VERB_QUERY,
"zonemd: verify DNSKEY RRset with trust anchor");
/* pass NULL for qstate, it is only used when type NSEC needs a
* name reallocated to get the qstate region for that */
sec = val_verify_DNSKEY_with_TA(env, ve, keystorage, anchor->ds_rrset,
anchor->dnskey_rrset, NULL, reason, NULL);
regional_free_all(env->scratch);
if(sec == sec_status_secure) {
/* success */
*is_insecure = 0;
return keystorage;
} else if(sec == sec_status_insecure) {
/* insecure */
*is_insecure = 1;
} else {
/* bogus */
*is_insecure = 0;
}
return NULL;
}
/** callback for ZONEMD lookup of DNSKEY */
void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited))
{
struct auth_zone* z = (struct auth_zone*)arg;
struct module_env* env;
char* reason = NULL;
struct ub_packed_rrset_key* dnskey = NULL;
int is_insecure = 0;
lock_rw_wrlock(&z->lock);
env = z->zonemd_callback_env;
/* release the env variable so another worker can pick up the
* ZONEMD verification task if it wants to */
z->zonemd_callback_env = NULL;
if(!env || env->outnet->want_to_quit) {
lock_rw_unlock(&z->lock);
return; /* stop on quit */
}
/* process result */
if(sec == sec_status_bogus) {
reason = why_bogus;
if(!reason)
reason = "lookup of DNSKEY was bogus";
auth_zone_log(z->name, VERB_ALGO,
"zonemd lookup of DNSKEY was bogus: %s", why_bogus);
} else if(rcode == LDNS_RCODE_NOERROR) {
uint16_t wanted_qtype = LDNS_RR_TYPE_DNSKEY;
struct regional* temp = env->scratch;
struct query_info rq;
struct reply_info* rep;
memset(&rq, 0, sizeof(rq));
rep = parse_reply_in_temp_region(buf, temp, &rq);
if(rep && rq.qtype == wanted_qtype &&
FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR) {
/* parsed successfully */
struct ub_packed_rrset_key* answer =
reply_find_answer_rrset(&rq, rep);
if(answer && sec == sec_status_secure) {
dnskey = answer;
auth_zone_log(z->name, VERB_ALGO,
"zonemd lookup of DNSKEY was secure");
} else if(sec == sec_status_secure && !answer) {
is_insecure = 1;
auth_zone_log(z->name, VERB_ALGO,
"zonemd lookup of DNSKEY has no content, but is secure, treat as insecure");
} else if(sec == sec_status_insecure) {
is_insecure = 1;
auth_zone_log(z->name, VERB_ALGO,
"zonemd lookup of DNSKEY was insecure");
} else if(sec == sec_status_indeterminate) {
is_insecure = 1;
auth_zone_log(z->name, VERB_ALGO,
"zonemd lookup of DNSKEY was indeterminate, treat as insecure");
} else {
auth_zone_log(z->name, VERB_ALGO,
"zonemd lookup of DNSKEY has nodata");
reason = "lookup of DNSKEY has nodata";
}
} else {
auth_zone_log(z->name, VERB_ALGO,
"zonemd lookup of DNSKEY has no answer");
reason = "lookup of DNSKEY has no answer";
}
} else {
auth_zone_log(z->name, VERB_ALGO,
"zonemd lookup of DNSKEY failed");
reason = "lookup of DNSKEY failed";
}
if(reason) {
auth_zone_zonemd_fail(z, env, reason);
lock_rw_unlock(&z->lock);
return;
}
auth_zone_verify_zonemd_with_key(z, env, dnskey, is_insecure);
lock_rw_unlock(&z->lock);
}
/** lookup DNSKEY for ZONEMD verification */
static int
zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
{
struct query_info qinfo;
uint16_t qflags = BIT_RD;
struct edns_data edns;
sldns_buffer* buf = env->scratch_buffer;
if(z->zonemd_callback_env) {
/* another worker is already working on the callback
* for the DNSKEY lookup for ZONEMD verification.
* We do not also have to do ZONEMD verification, let that
* worker do it */
auth_zone_log(z->name, VERB_ALGO,
"zonemd needs lookup of DNSKEY and that already worked on by another worker");
return 1;
}
/* use mesh_new_callback to lookup the DNSKEY,
* and then wait for them to be looked up (in cache, or query) */
qinfo.qname_len = z->namelen;
qinfo.qname = z->name;
qinfo.qclass = z->dclass;
qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
qinfo.local_alias = NULL;
if(verbosity >= VERB_ALGO) {
char buf1[512];
char buf2[LDNS_MAX_DOMAINLEN+1];
dname_str(z->name, buf2);
snprintf(buf1, sizeof(buf1), "auth zone %s: lookup DNSKEY "
"for zonemd verification", buf2);
log_query_info(VERB_ALGO, buf1, &qinfo);
}
edns.edns_present = 1;
edns.ext_rcode = 0;
edns.edns_version = 0;
edns.bits = EDNS_DO;
edns.opt_list = NULL;
if(sldns_buffer_capacity(buf) < 65535)
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
else edns.udp_size = 65535;
/* store the worker-specific module env for the callback.
* We can then reference this when the callback executes */
z->zonemd_callback_env = env;
/* the callback can be called straight away */
lock_rw_unlock(&z->lock);
if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
&auth_zonemd_dnskey_lookup_callback, z)) {
lock_rw_wrlock(&z->lock);
log_err("out of memory lookup up dnskey for zonemd");
return 0;
}
lock_rw_wrlock(&z->lock);
return 1;
}
void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env)
{
char* reason = NULL;
struct trust_anchor* anchor = NULL;
struct ub_packed_rrset_key* dnskey = NULL;
struct ub_packed_rrset_key keystorage;
int is_insecure = 0;
/* verify the ZONEMD if present.
* If not present check if absence is allowed by DNSSEC */
/* if zone is under a trustanchor */
/* is it equal to trustanchor - get dnskey's verified */
/* else, find chain of trust by fetching DNSKEYs lookup for zone */
/* result if that, if insecure, means no DNSSEC for the ZONEMD,
* otherwise we have the zone DNSKEY for the DNSSEC verification. */
anchor = anchors_lookup(env->anchors, z->name, z->namelen, z->dclass);
if(anchor && query_dname_compare(z->name, anchor->name) == 0) {
/* equal to trustanchor, no need for online lookups */
dnskey = zonemd_get_dnskey_from_anchor(z, env, anchor,
&is_insecure, &reason, &keystorage);
if(!dnskey && !reason) {
reason = "dnskey verify with anchor failed";
}
} else if(anchor) {
/* perform online lookups */
/* setup online lookups, and wait for them */
if(zonemd_lookup_dnskey(z, env)) {
/* wait for the lookup */
return;
}
reason = "could not lookup DNSKEY for chain of trust";
} else {
/* the zone is not under a trust anchor */
dnskey = NULL;
is_insecure = 1;
}
if(reason) {
auth_zone_zonemd_fail(z, env, reason);
return;
}
auth_zone_verify_zonemd_with_key(z, env, dnskey, is_insecure);
}

View file

@ -134,6 +134,11 @@ struct auth_zone {
int for_upstream; int for_upstream;
/** RPZ zones */ /** RPZ zones */
struct rpz* rpz; struct rpz* rpz;
/** store the env (worker thread specific) for the zonemd callbacks
* from the mesh with the results of the lookup, if nonNULL, some
* worker has already picked up the zonemd verification task and
* this worked does not have to do it as well. */
struct module_env* zonemd_callback_env;
/** zone has been deleted */ /** zone has been deleted */
int zone_deleted; int zone_deleted;
/** deletelist pointer, unused normally except during delete */ /** deletelist pointer, unused normally except during delete */
@ -733,4 +738,17 @@ int auth_zone_generate_zonemd_check(struct auth_zone* z, int scheme,
int hashalgo, uint8_t* hash, size_t hashlen, struct regional* region, int hashalgo, uint8_t* hash, size_t hashlen, struct regional* region,
struct sldns_buffer* buf, char** reason); struct sldns_buffer* buf, char** reason);
/**
* Perform ZONEMD checks and verification for the auth zone.
* This includes DNSSEC verification if applicable.
* @param z: auth zone to check. Caller holds lock. wrlock.
* @param env: with temp region, buffer and config.
*/
void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env);
/** mesh callback for zonemd on lookup of dnskey */
void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode,
struct sldns_buffer* buf, enum sec_status sec, char* why_bogus,
int was_ratelimited);
#endif /* SERVICES_AUTHZONE_H */ #endif /* SERVICES_AUTHZONE_H */

View file

@ -581,6 +581,7 @@ int fptr_whitelist_mesh_cb(mesh_cb_func_type fptr)
else if(fptr == &probe_answer_cb) return 1; else if(fptr == &probe_answer_cb) return 1;
else if(fptr == &auth_xfer_probe_lookup_callback) return 1; else if(fptr == &auth_xfer_probe_lookup_callback) return 1;
else if(fptr == &auth_xfer_transfer_lookup_callback) return 1; else if(fptr == &auth_xfer_transfer_lookup_callback) return 1;
else if(fptr == &auth_zonemd_dnskey_lookup_callback) return 1;
return 0; return 0;
} }