From: Wouter Wijngaards Date: Thu, 19 Jul 2007 09:25:55 +0000 (+0000) Subject: shuffle NS selection randomly for getting addresses. X-Git-Tag: release-0.4~30 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=55630293b986129b56bcd0da8c49ef5bff807d1d;p=thirdparty%2Funbound.git shuffle NS selection randomly for getting addresses. git-svn-id: file:///svn/unbound/trunk@436 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 555795af4..7e7fb9433 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +19 July 2007: Wouter + - shuffle NS selection when getting nameserver target addresses. + 18 July 2007: Wouter - do not query addresses, 127.0.0.1, and ::1 by default. diff --git a/iterator/iter_delegpt.c b/iterator/iter_delegpt.c index e27328d4b..f0038b288 100644 --- a/iterator/iter_delegpt.c +++ b/iterator/iter_delegpt.c @@ -99,6 +99,17 @@ delegpt_add_ns(struct delegpt* dp, struct region* region, uint8_t* name) (void)dname_count_size_labels(name, &ns->namelen); ns->name = region_alloc_init(region, name, ns->namelen); ns->resolved = 0; + + /* Sanity check: if the target name is at or *below* the + * delegation point itself, then this will be (potentially) + * unresolvable. This is the one case where glue *must* + * have been present. + * FIXME: at this point, this *may* be resolvable, so + * perhaps we should issue the query anyway and let it fail.*/ + if(dname_subdomain_c(ns->name, dp->name)) { + ns->resolved = 1; + } + return 1; } @@ -374,4 +385,3 @@ delegpt_add_rrset(struct delegpt* dp, struct region* region, log_warn("Unknown rrset type added to delegpt"); return 1; } - diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 300c22e91..53f3c3343 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -341,3 +341,15 @@ iter_dns_store(struct module_env* env, struct dns_msg* msg, int is_referral) } return 1; } + +int +iter_ns_probability(struct ub_randstate* rnd, int n, int m) +{ + int sel; + if(n == m) /* 100% chance */ + return 1; + /* we do not need secure random numbers here, but + * we do need it to be threadsafe, so we use this */ + sel = ub_random(rnd) % m; + return (sel < n); +} diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 89f6f1608..dacd95478 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -49,6 +49,7 @@ struct delegpt_addr; struct delegpt; struct region; struct msg_parse; +struct ub_randstate; /** * Process config options and set iterator module state. @@ -105,4 +106,14 @@ struct dns_msg* dns_copy_msg(struct dns_msg* from, struct region* region); int iter_dns_store(struct module_env* env, struct dns_msg* msg, int is_referral); +/** + * Select randomly with n/m probability. + * For shuffle NS records for address fetching. + * @param rnd: random table + * @param n: probability. + * @param m: divisor for probability. + * @return true with n/m probability. + */ +int iter_ns_probability(struct ub_randstate* rnd, int n, int m); + #endif /* ITERATOR_ITER_UTILS_H */ diff --git a/iterator/iterator.c b/iterator/iterator.c index f4bbee8ab..5f339ed86 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -803,29 +803,34 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, struct iter_env* ie, int id, int maxtargets, int* num) { int query_count = 0; - int target_count = 0; struct delegpt_ns* ns = iq->dp->nslist; + int missing = (int)delegpt_count_missing_targets(iq->dp); + int toget = 0; log_assert(maxtargets != 0); /* that would not be useful */ /* Generate target requests. Basically, any missing targets * are queried for here, regardless if it is necessary to do * so to continue processing. */ + if(maxtargets < 0 || maxtargets > missing) + toget = missing; + else toget = maxtargets; + if(toget == 0) { + *num = 0; + return 1; + } + /* select 'toget' items from the total of 'missing' items */ + log_assert(toget <= missing); /* loop over missing targets */ for(ns = iq->dp->nslist; ns; ns = ns->next) { if(ns->resolved) continue; - /* Sanity check: if the target name is at or *below* the - * delegation point itself, then this will be (potentially) - * unresolvable. This is the one case where glue *must* - * have been present. - * FIXME: at this point, this *may* be resolvable, so - * perhaps we should issue the query anyway and let it fail.*/ - if(dname_subdomain_c(ns->name, iq->dp->name)) { - log_nametypeclass(VERB_DETAIL, "skipping target name " - "because it should have been glue", ns->name, - LDNS_RR_TYPE_NS, iq->qchase.qclass); + /* randomly select this item with probability toget/missing */ + if(!iter_ns_probability(qstate->env->rnd, toget, missing)) { + /* do not select this one, next; select toget number + * of items from a list one less in size */ + missing --; continue; } @@ -846,10 +851,9 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, /* mark this target as in progress. */ ns->resolved = 1; - - /* if maxtargets is negative, there is no maximum, - * otherwise only query for ntarget names. */ - if(maxtargets >= 0 && ++target_count >= maxtargets) + missing--; + toget--; + if(toget == 0) break; } *num = query_count; @@ -1286,6 +1290,7 @@ processTargetResponse(struct module_qstate* qstate, int id, rrset = reply_find_answer_rrset(&iq->qchase, iq->response->rep); if(rrset) { /* if CNAMEs have been followed - add new NS to delegpt. */ + /* BTW. RFC 1918 says NS should not have got CNAMEs. Robust. */ if(!delegpt_find_ns(foriq->dp, rrset->rk.dname, rrset->rk.dname_len)) { if(!delegpt_add_ns(foriq->dp, forq->region, @@ -1295,8 +1300,6 @@ processTargetResponse(struct module_qstate* qstate, int id, if(!delegpt_add_rrset(foriq->dp, forq->region, rrset)) log_err("out of memory adding targets"); } else dpns->resolved = 1; /* fail the target */ - - log_assert(dpns->resolved); /* one way or another it is now done */ } /**