mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-24 00:29:58 -05:00
zonemd, zonemds are checked at start
This commit is contained in:
parent
5d7e001c63
commit
e09873e0c8
7 changed files with 117 additions and 14 deletions
|
|
@ -632,19 +632,19 @@ daemon_fork(struct daemon* daemon)
|
||||||
fatal_exit("Could not set up per-view response IP sets");
|
fatal_exit("Could not set up per-view response IP sets");
|
||||||
daemon->use_response_ip = !respip_set_is_empty(daemon->respip_set) ||
|
daemon->use_response_ip = !respip_set_is_empty(daemon->respip_set) ||
|
||||||
have_view_respip_cfg;
|
have_view_respip_cfg;
|
||||||
|
|
||||||
|
/* setup modules */
|
||||||
|
daemon_setup_modules(daemon);
|
||||||
|
|
||||||
/* read auth zonefiles */
|
/* read auth zonefiles */
|
||||||
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1,
|
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");
|
fatal_exit("auth_zones could not be setup");
|
||||||
|
|
||||||
/* Set-up EDNS tags */
|
/* Set-up EDNS tags */
|
||||||
if(!edns_tags_apply_cfg(daemon->env->edns_tags, daemon->cfg))
|
if(!edns_tags_apply_cfg(daemon->env->edns_tags, daemon->cfg))
|
||||||
fatal_exit("Could not set up EDNS tags");
|
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
|
/* response-ip-xxx options don't work as expected without the respip
|
||||||
* module. To avoid run-time operational surprise we reject such
|
* module. To avoid run-time operational surprise we reject such
|
||||||
* configuration. */
|
* configuration. */
|
||||||
|
|
|
||||||
|
|
@ -1906,6 +1906,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
auth_xfer_pickup_initial(worker->env.auth_zones, &worker->env);
|
auth_xfer_pickup_initial(worker->env.auth_zones, &worker->env);
|
||||||
|
auth_zones_pickup_zonemd_verify(worker->env.auth_zones,
|
||||||
|
&worker->env);
|
||||||
}
|
}
|
||||||
#ifdef USE_DNSTAP
|
#ifdef USE_DNSTAP
|
||||||
if(worker->daemon->cfg->dnstap
|
if(worker->daemon->cfg->dnstap
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,8 @@ context_finalize(struct ub_ctx* ctx)
|
||||||
return UB_NOMEM;
|
return UB_NOMEM;
|
||||||
if(!local_zones_apply_cfg(ctx->local_zones, cfg))
|
if(!local_zones_apply_cfg(ctx->local_zones, cfg))
|
||||||
return UB_INITFAIL;
|
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;
|
return UB_INITFAIL;
|
||||||
if(!edns_tags_apply_cfg(ctx->env->edns_tags, cfg))
|
if(!edns_tags_apply_cfg(ctx->env->edns_tags, cfg))
|
||||||
return UB_INITFAIL;
|
return UB_INITFAIL;
|
||||||
|
|
|
||||||
|
|
@ -1745,9 +1745,47 @@ int auth_zone_write_file(struct auth_zone* z, const char* fname)
|
||||||
return 1;
|
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) */
|
/** read all auth zones from file (if they have) */
|
||||||
static int
|
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;
|
struct auth_zone* z;
|
||||||
lock_rw_wrlock(&az->lock);
|
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);
|
lock_rw_unlock(&az->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if(z->zonefile && z->zonefile[0]!=0 && env)
|
||||||
|
zonemd_offline_verify(z, env, mods);
|
||||||
lock_rw_unlock(&z->lock);
|
lock_rw_unlock(&z->lock);
|
||||||
}
|
}
|
||||||
lock_rw_unlock(&az->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 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;
|
struct config_auth* p;
|
||||||
az_setall_deleted(az);
|
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);
|
az_delete_deleted_zones(az);
|
||||||
if(!auth_zones_read_zones(az, cfg))
|
if(!auth_zones_read_zones(az, cfg, env, mods))
|
||||||
return 0;
|
return 0;
|
||||||
if(setup) {
|
if(setup) {
|
||||||
if(!auth_zones_setup_zones(az))
|
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,
|
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;
|
char* reason = NULL, *why_bogus = NULL;
|
||||||
struct trust_anchor* anchor = 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. */
|
* otherwise we have the zone DNSKEY for the DNSSEC verification. */
|
||||||
anchor = anchors_lookup(env->anchors, z->name, z->namelen, z->dclass);
|
anchor = anchors_lookup(env->anchors, z->name, z->namelen, z->dclass);
|
||||||
if(anchor && query_dname_compare(z->name, anchor->name) == 0) {
|
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 */
|
/* equal to trustanchor, no need for online lookups */
|
||||||
dnskey = zonemd_get_dnskey_from_anchor(z, env, anchor,
|
dnskey = zonemd_get_dnskey_from_anchor(z, env, anchor,
|
||||||
&is_insecure, &why_bogus, &keystorage);
|
&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) {
|
} else if(anchor) {
|
||||||
lock_basic_unlock(&anchor->lock);
|
lock_basic_unlock(&anchor->lock);
|
||||||
/* perform online lookups */
|
/* perform online lookups */
|
||||||
|
if(offline)
|
||||||
|
return;
|
||||||
/* setup online lookups, and wait for them */
|
/* setup online lookups, and wait for them */
|
||||||
if(zonemd_lookup_dnskey(z, env)) {
|
if(zonemd_lookup_dnskey(z, env)) {
|
||||||
/* wait for the lookup */
|
/* 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";
|
reason = "could not lookup DNSKEY for chain of trust";
|
||||||
} else {
|
} else {
|
||||||
/* the zone is not under a trust anchor */
|
/* the zone is not under a trust anchor */
|
||||||
|
if(only_online)
|
||||||
|
return;
|
||||||
dnskey = NULL;
|
dnskey = NULL;
|
||||||
is_insecure = 1;
|
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);
|
auth_zone_verify_zonemd_with_key(z, env, dnskey, is_insecure, result);
|
||||||
regional_free_all(env->scratch);
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -479,10 +479,13 @@ struct auth_zones* auth_zones_create(void);
|
||||||
* @param cfg: config to apply.
|
* @param cfg: config to apply.
|
||||||
* @param setup: if true, also sets up values in the auth zones structure
|
* @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 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.
|
* @return false on failure.
|
||||||
*/
|
*/
|
||||||
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
|
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
|
/** initial pick up of worker timeouts, ties events to worker event loop
|
||||||
* @param az: auth zones structure
|
* @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 z: auth zone to check. Caller holds lock. wrlock.
|
||||||
* @param env: with temp region, buffer and config.
|
* @param env: with temp region, buffer and config.
|
||||||
* @param result: if not NULL, result string strdupped in here.
|
* @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,
|
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 */
|
/** mesh callback for zonemd on lookup of dnskey */
|
||||||
void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode,
|
void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode,
|
||||||
struct sldns_buffer* buf, enum sec_status sec, char* why_bogus,
|
struct sldns_buffer* buf, enum sec_status sec, char* why_bogus,
|
||||||
int was_ratelimited);
|
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 */
|
#endif /* SERVICES_AUTHZONE_H */
|
||||||
|
|
|
||||||
|
|
@ -851,7 +851,7 @@ check_auth(struct config_file* cfg)
|
||||||
{
|
{
|
||||||
int is_rpz = 0;
|
int is_rpz = 0;
|
||||||
struct auth_zones* az = auth_zones_create();
|
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");
|
fatal_exit("Could not setup authority zones");
|
||||||
}
|
}
|
||||||
auth_zones_delete(az);
|
auth_zones_delete(az);
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,7 @@ static void zonemd_verify_test(char* zname, char* zfile, char* tastr,
|
||||||
|
|
||||||
/* test */
|
/* test */
|
||||||
lock_rw_wrlock(&z->lock);
|
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);
|
lock_rw_unlock(&z->lock);
|
||||||
if(verbosity >= VERB_ALGO) {
|
if(verbosity >= VERB_ALGO) {
|
||||||
printf("auth zone %s: ZONEMD verification %s: %s\n", zname,
|
printf("auth zone %s: ZONEMD verification %s: %s\n", zname,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue