From: W.C.A. Wijngaards Date: Thu, 22 Oct 2020 10:10:46 +0000 (+0200) Subject: zonemd, zonemds are checked at start X-Git-Tag: release-1.13.2rc1~269^2~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e09873e0c8c167434667a882708cc91298c8f16e;p=thirdparty%2Funbound.git zonemd, zonemds are checked at start --- diff --git a/daemon/daemon.c b/daemon/daemon.c index f480c94e6..83a30def7 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -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. */ diff --git a/daemon/worker.c b/daemon/worker.c index 458afa04e..9e4ad7c75 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -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 diff --git a/libunbound/context.c b/libunbound/context.c index 713259c71..914855470 100644 --- a/libunbound/context.c +++ b/libunbound/context.c @@ -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; diff --git a/services/authzone.c b/services/authzone.c index 727add003..4adf90c4f 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -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); +} diff --git a/services/authzone.h b/services/authzone.h index c00598ad1..9ddc756f9 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -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 */ diff --git a/smallapp/unbound-checkconf.c b/smallapp/unbound-checkconf.c index b1b7ae7ef..34a1f5bb4 100644 --- a/smallapp/unbound-checkconf.c +++ b/smallapp/unbound-checkconf.c @@ -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); diff --git a/testcode/unitzonemd.c b/testcode/unitzonemd.c index a20a6b0b2..10c40c630 100644 --- a/testcode/unitzonemd.c +++ b/testcode/unitzonemd.c @@ -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,