zonemd, zonemds are checked at start

This commit is contained in:
W.C.A. Wijngaards 2020-10-22 12:10:46 +02:00
parent 5d7e001c63
commit e09873e0c8
7 changed files with 117 additions and 14 deletions

View file

@ -632,19 +632,19 @@ daemon_fork(struct daemon* daemon)
fatal_exit("Could not set up per-view response IP sets");
daemon->use_response_ip = !respip_set_is_empty(daemon->respip_set) ||
have_view_respip_cfg;
/* setup modules */
daemon_setup_modules(daemon);
/* read auth zonefiles */
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1,
&daemon->use_rpz))
&daemon->use_rpz, daemon->env, &daemon->mods))
fatal_exit("auth_zones could not be setup");
/* Set-up EDNS tags */
if(!edns_tags_apply_cfg(daemon->env->edns_tags, daemon->cfg))
fatal_exit("Could not set up EDNS tags");
/* setup modules */
daemon_setup_modules(daemon);
/* response-ip-xxx options don't work as expected without the respip
* module. To avoid run-time operational surprise we reject such
* configuration. */

View file

@ -1906,6 +1906,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
#endif
) {
auth_xfer_pickup_initial(worker->env.auth_zones, &worker->env);
auth_zones_pickup_zonemd_verify(worker->env.auth_zones,
&worker->env);
}
#ifdef USE_DNSTAP
if(worker->daemon->cfg->dnstap

View file

@ -78,7 +78,8 @@ context_finalize(struct ub_ctx* ctx)
return UB_NOMEM;
if(!local_zones_apply_cfg(ctx->local_zones, cfg))
return UB_INITFAIL;
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz))
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz,
ctx->env, &ctx->mods))
return UB_INITFAIL;
if(!edns_tags_apply_cfg(ctx->env->edns_tags, cfg))
return UB_INITFAIL;

View file

@ -1745,9 +1745,47 @@ int auth_zone_write_file(struct auth_zone* z, const char* fname)
return 1;
}
/** offline verify for zonemd, while reading a zone file to immediately
* spot bad hashes in zonefile as they are read.
* Creates temp buffers, but uses anchors and validation environment
* from the module_env. */
static void
zonemd_offline_verify(struct auth_zone* z, struct module_env* env_for_val,
struct module_stack* mods)
{
struct module_env env;
struct mesh_area mesh;
time_t now = 0;
env = *env_for_val;
env.scratch_buffer = sldns_buffer_new(env.cfg->msg_buffer_size);
if(!env.scratch_buffer) {
log_err("out of memory");
goto clean_exit;
}
env.scratch = regional_create();
memset(&mesh, 0, sizeof(mesh));
mesh.mods = *mods;
env.mesh = &mesh;
if(!env.now) {
env.now = &now;
now = time(NULL);
}
if(!env.scratch) {
log_err("out of memory");
goto clean_exit;
}
auth_zone_verify_zonemd(z, &env, NULL, 1, 0);
clean_exit:
/* clean up and exit */
sldns_buffer_free(env.scratch_buffer);
regional_destroy(env.scratch);
}
/** read all auth zones from file (if they have) */
static int
auth_zones_read_zones(struct auth_zones* az, struct config_file* cfg)
auth_zones_read_zones(struct auth_zones* az, struct config_file* cfg,
struct module_env* env, struct module_stack* mods)
{
struct auth_zone* z;
lock_rw_wrlock(&az->lock);
@ -1758,6 +1796,8 @@ auth_zones_read_zones(struct auth_zones* az, struct config_file* cfg)
lock_rw_unlock(&az->lock);
return 0;
}
if(z->zonefile && z->zonefile[0]!=0 && env)
zonemd_offline_verify(z, env, mods);
lock_rw_unlock(&z->lock);
}
lock_rw_unlock(&az->lock);
@ -2103,7 +2143,8 @@ az_delete_deleted_zones(struct auth_zones* az)
}
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
int setup, int* is_rpz)
int setup, int* is_rpz, struct module_env* env,
struct module_stack* mods)
{
struct config_auth* p;
az_setall_deleted(az);
@ -2119,7 +2160,7 @@ int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
}
}
az_delete_deleted_zones(az);
if(!auth_zones_read_zones(az, cfg))
if(!auth_zones_read_zones(az, cfg, env, mods))
return 0;
if(setup) {
if(!auth_zones_setup_zones(az))
@ -8044,7 +8085,7 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
}
void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
char** result)
char** result, int offline, int only_online)
{
char* reason = NULL, *why_bogus = NULL;
struct trust_anchor* anchor = NULL;
@ -8061,6 +8102,10 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
* 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) {
if(only_online) {
lock_basic_unlock(&anchor->lock);
return;
}
/* equal to trustanchor, no need for online lookups */
dnskey = zonemd_get_dnskey_from_anchor(z, env, anchor,
&is_insecure, &why_bogus, &keystorage);
@ -8071,6 +8116,8 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
} else if(anchor) {
lock_basic_unlock(&anchor->lock);
/* perform online lookups */
if(offline)
return;
/* setup online lookups, and wait for them */
if(zonemd_lookup_dnskey(z, env)) {
/* wait for the lookup */
@ -8079,6 +8126,8 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
reason = "could not lookup DNSKEY for chain of trust";
} else {
/* the zone is not under a trust anchor */
if(only_online)
return;
dnskey = NULL;
is_insecure = 1;
}
@ -8091,3 +8140,37 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
auth_zone_verify_zonemd_with_key(z, env, dnskey, is_insecure, result);
regional_free_all(env->scratch);
}
void auth_zones_pickup_zonemd_verify(struct auth_zones* az,
struct module_env* env)
{
struct auth_zone key;
uint8_t savezname[255+1];
size_t savezname_len;
struct auth_zone* z;
key.node.key = &key;
lock_rw_rdlock(&az->lock);
RBTREE_FOR(z, struct auth_zone*, &az->ztree) {
lock_rw_wrlock(&z->lock);
key.dclass = z->dclass;
key.namelabs = z->namelabs;
if(z->namelen > sizeof(savezname)) {
lock_rw_unlock(&z->lock);
log_err("auth_zones_pickup_zonemd_verify: zone name too long");
continue;
}
savezname_len = z->namelen;
memmove(savezname, z->name, z->namelen);
lock_rw_unlock(&az->lock);
auth_zone_verify_zonemd(z, env, NULL, 0, 1);
lock_rw_unlock(&z->lock);
lock_rw_rdlock(&az->lock);
/* find the zone we had before, it is not deleted,
* because we have a flag for that that is processed at
* apply_cfg time */
key.namelen = savezname_len;
key.name = savezname;
z = (struct auth_zone*)rbtree_search(&az->ztree, &key);
}
lock_rw_unlock(&az->lock);
}

View file

@ -479,10 +479,13 @@ struct auth_zones* auth_zones_create(void);
* @param cfg: config to apply.
* @param setup: if true, also sets up values in the auth zones structure
* @param is_rpz: set to 1 if at least one RPZ zone is configured.
* @param env: environment for offline verification.
* @param mods: modules in environment.
* @return false on failure.
*/
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
int setup, int* is_rpz);
int setup, int* is_rpz, struct module_env* env,
struct module_stack* mods);
/** initial pick up of worker timeouts, ties events to worker event loop
* @param az: auth zones structure
@ -744,13 +747,27 @@ int auth_zone_generate_zonemd_check(struct auth_zone* z, int scheme,
* @param z: auth zone to check. Caller holds lock. wrlock.
* @param env: with temp region, buffer and config.
* @param result: if not NULL, result string strdupped in here.
* @param offline: if true, there is no spawned lookup when online is needed.
* Those zones are skipped for ZONEMD checking.
* @param only_online: if true, only for ZONEMD that need online lookup
* of DNSKEY chain of trust are processed.
*/
void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
char** result);
char** result, int offline, int only_online);
/** 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);
/**
* Check the ZONEMD records that need online DNSSEC chain lookups,
* for them spawn the lookup process to get it checked out.
* Attaches the lookup process to the worker event base and mesh state.
* @param az: auth zones, every zones is checked.
* @param env: env of the worker where the task is attached.
*/
void auth_zones_pickup_zonemd_verify(struct auth_zones* az,
struct module_env* env);
#endif /* SERVICES_AUTHZONE_H */

View file

@ -851,7 +851,7 @@ check_auth(struct config_file* cfg)
{
int is_rpz = 0;
struct auth_zones* az = auth_zones_create();
if(!az || !auth_zones_apply_cfg(az, cfg, 0, &is_rpz)) {
if(!az || !auth_zones_apply_cfg(az, cfg, 0, &is_rpz, NULL, NULL)) {
fatal_exit("Could not setup authority zones");
}
auth_zones_delete(az);

View file

@ -291,7 +291,7 @@ static void zonemd_verify_test(char* zname, char* zfile, char* tastr,
/* test */
lock_rw_wrlock(&z->lock);
auth_zone_verify_zonemd(z, &env, &result);
auth_zone_verify_zonemd(z, &env, &result, 1, 0);
lock_rw_unlock(&z->lock);
if(verbosity >= VERB_ALGO) {
printf("auth zone %s: ZONEMD verification %s: %s\n", zname,