As kn@ found out the hard way and otto@ analysed: We can not share a
cache between validating and resolving strategies.
The resolving only strategies mess up the negative cache by claiming
DNSKEY and DS records do not exist which confuses the validating
strategies.
This diff rearranges things in a way that the unified cache is only
hooked up to a context when we know that that strategy is validating.
I'm not yet sure if this is the best way to arrange things though, but
what we currently have is actually quite broken when faced with a
mixture of validating and resolving strategies.
Tests, OKs?
diff --git resolver.c resolver.c
index 892e173a5f5..f69462dbddb 100644
--- resolver.c
+++ resolver.c
@@ -151,7 +151,8 @@ void resolve_done(struct
uw_resolver *, void *, int, void *,
void ub_resolve_done(void *, int, void *, int, int, char *,
int);
void asr_resolve_done(struct asr_result *, void *);
-void new_resolver(enum uw_resolver_type);
+void new_resolver(enum uw_resolver_type,
+ enum uw_resolver_state);
struct uw_resolver *create_resolver(enum uw_resolver_type);
void setup_unified_caches(void);
void set_unified_cache(struct uw_resolver *);
@@ -653,7 +654,7 @@ resolver_dispatch_main(int fd, short event, void *bula)
nconf = NULL;
for (i = 0; i < UW_RES_NONE; i++)
if (restart[i])
- new_resolver(i);
+ new_resolver(i, UNKNOWN);
break;
default:
log_debug("%s: unexpected imsg %d", __func__,
@@ -707,7 +708,7 @@ setup_query(struct query_imsg *query_imsg)
find_force(&resolver_conf->force, query_imsg->qname, &res);
- if (res != NULL && res->state != DEAD) {
+ if (res != NULL && res->state != DEAD && res->state != UNKNOWN) {
rq->res_pref.len = 1;
rq->res_pref.types[0] = res->type;
} else if (sort_resolver_types(&rq->res_pref) == -1) {
@@ -756,7 +757,7 @@ try_next_resolver(struct running_query *rq)
while(rq->next_resolver < rq->res_pref.len &&
((res = resolvers[rq->res_pref.types[rq->next_resolver]]) == NULL ||
- res->state == DEAD))
+ res->state == DEAD || res->state == UNKNOWN))
rq->next_resolver++;
if (res == NULL) {
@@ -1042,7 +1043,7 @@ resolve_done(struct uw_resolver *res, void *arg, int
rcode,
}
void
-new_resolver(enum uw_resolver_type type)
+new_resolver(enum uw_resolver_type type, enum uw_resolver_state state)
{
free_resolver(resolvers[type]);
resolvers[type] = NULL;
@@ -1089,8 +1090,20 @@ new_resolver(enum uw_resolver_type type)
}
resolvers[type] = create_resolver(type);
- set_unified_cache(resolvers[type]);
- check_resolver(resolvers[type]);
+ switch (state) {
+ case UNKNOWN:
+ check_resolver(resolvers[type]);
+ break;
+ case VALIDATING:
+ set_unified_cache(resolvers[type]);
+ /* FALLTHROUGH */
+ case RESOLVING:
+ resolvers[type]->state = state;
+ break;
+ default:
+ fatalx("%s: invalid resolver state: %s", __func__,
+ uw_resolver_state_str[state]);
+ }
}
void
@@ -1099,6 +1112,17 @@ set_unified_cache(struct uw_resolver *res)
if (res == NULL || res->ctx == NULL)
return;
+ if (res->ctx->env->msg_cache != NULL) {
+ if (res->ctx->env->msg_cache != unified_msg_cache ||
+ res->ctx->env->rrset_cache != unified_rrset_cache ||
+ res->ctx->env->key_cache != unified_key_cache ||
+ res->ctx->env->neg_cache != unified_neg_cache)
+ fatalx("wrong unified cache set on resolver");
+ else
+ /* we are upgrading from UNKNOWN back to VALIDATING */
+ return;
+ }
+
res->ctx->env->msg_cache = unified_msg_cache;
res->ctx->env->rrset_cache = unified_rrset_cache;
res->ctx->env->key_cache = unified_key_cache;
@@ -1466,7 +1490,11 @@ check_resolver_done(struct uw_resolver *res, void *arg,
int rcode,
}
if (sec == SECURE) {
- checked_resolver->state = VALIDATING;
+ if (prev_state == UNKNOWN) {
+ checked_resolver->state = VALIDATING;
+ set_unified_cache(checked_resolver);
+ } else if (prev_state != VALIDATING)
+ new_resolver(checked_resolver->type, VALIDATING);
if (!(evtimer_pending(&trust_anchor_timer, NULL)))
evtimer_add(&trust_anchor_timer, &tv);
} else if (rcode == LDNS_RCODE_NOERROR &&
@@ -1479,7 +1507,10 @@ check_resolver_done(struct uw_resolver *res, void *arg,
int rcode,
log_warnx("%s: %s", uw_resolver_type_str[
checked_resolver->type], why_bogus);
}
- checked_resolver->state = RESOLVING;
+ if (prev_state == UNKNOWN)
+ checked_resolver->state = RESOLVING;
+ else if (prev_state != RESOLVING)
+ new_resolver(checked_resolver->type, RESOLVING);
} else
checked_resolver->state = DEAD; /* we know the root exists */
@@ -1547,6 +1578,7 @@ schedule_recheck_all_resolvers(void)
if (resolvers[i] == NULL)
continue;
tv.tv_usec = arc4random() % 1000000; /* modulo bias is ok */
+ resolvers[i]->state = UNKNOWN;
evtimer_add(&resolvers[i]->check_ev, &tv);
}
}
@@ -1667,7 +1699,8 @@ restart_ub_resolvers(void)
for (i = 0; i < UW_RES_NONE; i++)
if (i != UW_RES_ASR)
- new_resolver(i);
+ new_resolver(i, resolvers[i] != NULL ?
+ resolvers[i]->state : UNKNOWN);
}
void
@@ -1942,9 +1975,9 @@ replace_autoconf_forwarders(struct imsg_rdns_proposal
*rdns_proposal)
if (changed) {
replace_forwarders(&new_forwarder_list,
&autoconf_forwarder_list);
- new_resolver(UW_RES_ASR);
- new_resolver(UW_RES_DHCP);
- new_resolver(UW_RES_ODOT_DHCP);
+ new_resolver(UW_RES_ASR, UNKNOWN);
+ new_resolver(UW_RES_DHCP, UNKNOWN);
+ new_resolver(UW_RES_ODOT_DHCP, UNKNOWN);
} else {
while ((tmp = TAILQ_FIRST(&new_forwarder_list)) != NULL) {
TAILQ_REMOVE(&new_forwarder_list, tmp, entry);
--
I'm not entirely sure you are real.