mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-02-03 20:29:28 -05:00
cycle detection
git-svn-id: file:///svn/unbound/trunk@452 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
9bd8d5a929
commit
85bfa1bd35
8 changed files with 97 additions and 8 deletions
|
|
@ -712,6 +712,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
|||
worker->env.kill_sub = &mesh_state_delete;
|
||||
worker->env.query_done = &mesh_query_done;
|
||||
worker->env.walk_supers = &mesh_walk_supers;
|
||||
worker->env.detect_cycle = &mesh_detect_cycle;
|
||||
if(!worker->env.mesh) {
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
26 July 2007: Wouter
|
||||
- cycle detection, for query state dependencies. Will attempt to
|
||||
circumvent the cycle, but if no other targets available fails.
|
||||
|
||||
25 July 2007: Wouter
|
||||
- testbound read ADDRESS and check it.
|
||||
- test for version.bind and friends.
|
||||
|
|
|
|||
|
|
@ -354,3 +354,32 @@ iter_ns_probability(struct ub_randstate* rnd, int n, int m)
|
|||
sel = ub_random(rnd) % m;
|
||||
return (sel < n);
|
||||
}
|
||||
|
||||
/** detect dependency cycle for query and target */
|
||||
static int
|
||||
causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen,
|
||||
uint16_t t, uint16_t c)
|
||||
{
|
||||
struct query_info qinf;
|
||||
qinf.qname = name;
|
||||
qinf.qname_len = namelen;
|
||||
qinf.qtype = t;
|
||||
qinf.qclass = c;
|
||||
return (*qstate->env->detect_cycle)(qstate, &qinf);
|
||||
}
|
||||
|
||||
void
|
||||
iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
if(ns->resolved)
|
||||
continue;
|
||||
/* see if this ns as target causes dependency cycle */
|
||||
if(causes_cycle(qstate, ns->name, ns->namelen,
|
||||
LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass) ||
|
||||
causes_cycle(qstate, ns->name, ns->namelen,
|
||||
LDNS_RR_TYPE_A, qstate->qinfo.qclass))
|
||||
ns->resolved = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ struct msg_parse;
|
|||
struct ub_randstate;
|
||||
struct query_info;
|
||||
struct reply_info;
|
||||
struct module_qstate;
|
||||
|
||||
/**
|
||||
* Process config options and set iterator module state.
|
||||
|
|
@ -119,4 +120,12 @@ int iter_dns_store(struct module_env* env, struct query_info* qinf,
|
|||
*/
|
||||
int iter_ns_probability(struct ub_randstate* rnd, int n, int m);
|
||||
|
||||
/**
|
||||
* Mark targets that result in a dependency cycle as done, so they
|
||||
* will not get selected as targets.
|
||||
* @param qstate: query state.
|
||||
* @param dp: delegpt to mark ns in.
|
||||
*/
|
||||
void iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp);
|
||||
|
||||
#endif /* ITERATOR_ITER_UTILS_H */
|
||||
|
|
|
|||
|
|
@ -811,8 +811,11 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
{
|
||||
int query_count = 0;
|
||||
struct delegpt_ns* ns = iq->dp->nslist;
|
||||
int missing = (int)delegpt_count_missing_targets(iq->dp);
|
||||
int missing;
|
||||
int toget = 0;
|
||||
|
||||
iter_mark_cycle_targets(qstate, iq->dp);
|
||||
missing = (int)delegpt_count_missing_targets(iq->dp);
|
||||
log_assert(maxtargets != 0); /* that would not be useful */
|
||||
|
||||
/* Generate target requests. Basically, any missing targets
|
||||
|
|
@ -840,13 +843,6 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
missing --;
|
||||
continue;
|
||||
}
|
||||
if(iq->refetch_glue && dname_subdomain_c(ns->name,
|
||||
iq->dp->name)) {
|
||||
log_nametypeclass(VERB_DETAIL, "skip double glue "
|
||||
"refetch", ns->name, LDNS_RR_TYPE_A,
|
||||
iq->qchase.qclass);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ie->supports_ipv6) {
|
||||
/* Send the AAAA request. */
|
||||
|
|
|
|||
|
|
@ -588,3 +588,28 @@ mesh_get_mem(struct mesh_area* mesh)
|
|||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/** helper recursive rbtree find routine */
|
||||
static int
|
||||
find_in_subsub(struct mesh_state* m, struct mesh_state* tofind)
|
||||
{
|
||||
struct mesh_state_ref* r;
|
||||
RBTREE_FOR(r, struct mesh_state_ref*, &m->sub_set) {
|
||||
if(r->s == tofind || find_in_subsub(r->s, tofind))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo)
|
||||
{
|
||||
struct mesh_area* mesh = qstate->env->mesh;
|
||||
struct mesh_state* cyc_m = qstate->mesh_info;
|
||||
struct mesh_state* dep_m = mesh_area_find(mesh, qinfo, BIT_RD, 0);
|
||||
if(!dep_m)
|
||||
return 0;
|
||||
if(dep_m == cyc_m || find_in_subsub(dep_m, cyc_m))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -357,4 +357,15 @@ void mesh_stats(struct mesh_area* mesh, const char* str);
|
|||
*/
|
||||
size_t mesh_get_mem(struct mesh_area* mesh);
|
||||
|
||||
/**
|
||||
* Find cycle; see if the given mesh is in the targets sub, or sub-sub, ...
|
||||
* trees.
|
||||
* @param qstate: given mesh querystate.
|
||||
* @param qinfo: query info for dependency.
|
||||
* @return true if the name,type,class exists and the given qstate mesh exists
|
||||
* as a dependency of that name. Thus if qstate becomes dependent on
|
||||
* name,type,class then a cycle is created.
|
||||
*/
|
||||
int mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo);
|
||||
|
||||
#endif /* SERVICES_MESH_H */
|
||||
|
|
|
|||
|
|
@ -196,6 +196,20 @@ struct module_env {
|
|||
void (*walk_supers)(struct module_qstate* qstate, int id,
|
||||
void (*cb)(struct module_qstate*, int, struct module_qstate*));
|
||||
|
||||
/**
|
||||
* Detect if adding a dependency for qstate on name,type,class will
|
||||
* create a dependency cycle.
|
||||
* @param qstate: given mesh querystate.
|
||||
* @param qinfo: query info for dependency. Assumed RDflag and not
|
||||
* priming.
|
||||
* @return true if the name,type,class exists and the given
|
||||
* qstate mesh exists as a dependency of that name. Thus
|
||||
* if qstate becomes dependent on name,type,class then a
|
||||
* cycle is created.
|
||||
*/
|
||||
int (*detect_cycle)(struct module_qstate* qstate,
|
||||
struct query_info* qinfo);
|
||||
|
||||
/** region for temporary usage. May be cleared after operate() call. */
|
||||
struct region* scratch;
|
||||
/** internal data for daemon - worker thread. */
|
||||
|
|
|
|||
Loading…
Reference in a new issue