From: Wouter Wijngaards Date: Thu, 26 Jul 2007 09:29:21 +0000 (+0000) Subject: cycle detection X-Git-Tag: release-0.4~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=85bfa1bd355411653ff736071ac4fdabd7e8039c;p=thirdparty%2Funbound.git cycle detection git-svn-id: file:///svn/unbound/trunk@452 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/worker.c b/daemon/worker.c index 4043c4ff8..994a7d0c2 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -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; diff --git a/doc/Changelog b/doc/Changelog index f1713c8bb..e4967167b 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 656b58f5c..bedf78a40 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -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; + } +} diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 2531ad37f..7e3a5ccab 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -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 */ diff --git a/iterator/iterator.c b/iterator/iterator.c index 0809535bc..f2cff2b47 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -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. */ diff --git a/services/mesh.c b/services/mesh.c index 0061c1e1d..3d8c48ea9 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -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; +} diff --git a/services/mesh.h b/services/mesh.h index 75afdcb70..dc260a615 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -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 */ diff --git a/util/module.h b/util/module.h index 5d2481b60..687aea63e 100644 --- a/util/module.h +++ b/util/module.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. */