diff options
Diffstat (limited to 'iterator')
| -rw-r--r-- | iterator/iter_scrub.c | 37 | ||||
| -rw-r--r-- | iterator/iter_utils.c | 123 | ||||
| -rw-r--r-- | iterator/iter_utils.h | 9 | ||||
| -rw-r--r-- | iterator/iterator.c | 80 | ||||
| -rw-r--r-- | iterator/iterator.h | 2 |
5 files changed, 177 insertions, 74 deletions
diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c index b354eaa285b0..3f1438a4ff3d 100644 --- a/iterator/iter_scrub.c +++ b/iterator/iter_scrub.c @@ -316,6 +316,18 @@ sub_of_pkt(sldns_buffer* pkt, uint8_t* zone, uint8_t* comprname) return dname_subdomain_c(zone, buf); } +/** Check if there are SOA records in the authority section (negative) */ +static int +soa_in_auth(struct msg_parse* msg) +{ + struct rrset_parse* rrset; + for(rrset = msg->rrset_first; rrset; rrset = rrset->rrset_all_next) + if(rrset->type == LDNS_RR_TYPE_SOA && + rrset->section == LDNS_SECTION_AUTHORITY) + return 1; + return 0; +} + /** * This routine normalizes a response. This includes removing "irrelevant" * records from the answer and additional sections and (re)synthesizing @@ -497,6 +509,19 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, "RRset:", pkt, msg, prev, &rrset); continue; } + /* we don't want NS sets for NXDOMAIN answers, + * because they could contain poisonous contents, + * from. eg. fragmentation attacks, inserted after + * long RRSIGs in the packet get to the packet + * border and such */ + /* also for NODATA answers */ + if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NXDOMAIN || + (FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR + && soa_in_auth(msg) && msg->an_rrsets == 0)) { + remove_rrset("normalize: removing irrelevant " + "RRset:", pkt, msg, prev, &rrset); + continue; + } if(nsset == NULL) { nsset = rrset; } else { @@ -595,18 +620,6 @@ store_rrset(sldns_buffer* pkt, struct msg_parse* msg, struct module_env* env, (void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, now); } -/** Check if there are SOA records in the authority section (negative) */ -static int -soa_in_auth(struct msg_parse* msg) -{ - struct rrset_parse* rrset; - for(rrset = msg->rrset_first; rrset; rrset = rrset->rrset_all_next) - if(rrset->type == LDNS_RR_TYPE_SOA && - rrset->section == LDNS_SECTION_AUTHORITY) - return 1; - return 0; -} - /** * Check if right hand name in NSEC is within zone * @param rrset: the NSEC rrset diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 90c8cf114e33..4ac8efd0d17a 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -282,10 +282,13 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env, static int iter_fill_rtt(struct iter_env* iter_env, struct module_env* env, uint8_t* name, size_t namelen, uint16_t qtype, time_t now, - struct delegpt* dp, int* best_rtt, struct sock_list* blacklist) + struct delegpt* dp, int* best_rtt, struct sock_list* blacklist, + size_t* num_suitable_results) { int got_it = 0; struct delegpt_addr* a; + *num_suitable_results = 0; + if(dp->bogus) return 0; /* NS bogus, all bogus, nothing found */ for(a=dp->result_list; a; a = a->next_result) { @@ -301,11 +304,58 @@ iter_fill_rtt(struct iter_env* iter_env, struct module_env* env, } else if(a->sel_rtt < *best_rtt) { *best_rtt = a->sel_rtt; } + (*num_suitable_results)++; } } return got_it; } +/** compare two rtts, return -1, 0 or 1 */ +static int +rtt_compare(const void* x, const void* y) +{ + if(*(int*)x == *(int*)y) + return 0; + if(*(int*)x > *(int*)y) + return 1; + return -1; +} + +/** get RTT for the Nth fastest server */ +static int +nth_rtt(struct delegpt_addr* result_list, size_t num_results, size_t n) +{ + int rtt_band; + size_t i; + int* rtt_list, *rtt_index; + + if(num_results < 1 || n >= num_results) { + return -1; + } + + rtt_list = calloc(num_results, sizeof(int)); + if(!rtt_list) { + log_err("malloc failure: allocating rtt_list"); + return -1; + } + rtt_index = rtt_list; + + for(i=0; i<num_results && result_list; i++) { + if(result_list->sel_rtt != -1) { + *rtt_index = result_list->sel_rtt; + rtt_index++; + } + result_list=result_list->next_result; + } + qsort(rtt_list, num_results, sizeof(*rtt_list), rtt_compare); + + log_assert(n > 0); + rtt_band = rtt_list[n-1]; + free(rtt_list); + + return rtt_band; +} + /** filter the address list, putting best targets at front, * returns number of best targets (or 0, no suitable targets) */ static int @@ -314,12 +364,13 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env, struct delegpt* dp, int* selected_rtt, int open_target, struct sock_list* blacklist, time_t prefetch) { - int got_num = 0, low_rtt = 0, swap_to_front, rtt_band = RTT_BAND; + int got_num = 0, low_rtt = 0, swap_to_front, rtt_band = RTT_BAND, nth; + size_t num_results; struct delegpt_addr* a, *n, *prev=NULL; /* fillup sel_rtt and find best rtt in the bunch */ got_num = iter_fill_rtt(iter_env, env, name, namelen, qtype, now, dp, - &low_rtt, blacklist); + &low_rtt, blacklist, &num_results); if(got_num == 0) return 0; if(low_rtt >= USEFUL_SERVER_TOP_TIMEOUT && @@ -329,14 +380,19 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env, return 0 to force the caller to fetch more */ } - if(env->cfg->low_rtt_permil != 0 && prefetch == 0 && - low_rtt < env->cfg->low_rtt && - ub_random_max(env->rnd, 1000) < env->cfg->low_rtt_permil) { + if(env->cfg->fast_server_permil != 0 && prefetch == 0 && + num_results > env->cfg->fast_server_num && + ub_random_max(env->rnd, 1000) < env->cfg->fast_server_permil) { /* the query is not prefetch, but for a downstream client, - * there is a low_rtt (fast) server. We choose that x% of the - * time */ - /* pick rtt numbers from 0..LOWBAND_RTT */ - rtt_band = env->cfg->low_rtt - low_rtt; + * there are more servers available then the fastest N we want + * to choose from. Limit our choice to the fastest servers. */ + nth = nth_rtt(dp->result_list, num_results, + env->cfg->fast_server_num); + if(nth > 0) { + rtt_band = nth - low_rtt; + if(rtt_band > RTT_BAND) + rtt_band = RTT_BAND; + } } got_num = 0; @@ -1210,3 +1266,50 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp) return 0; return 1; } + +int +iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf) +{ + struct iter_hints_stub *stub; + struct delegpt *dp; + + /* Check for stub. */ + stub = hints_lookup_stub(qstate->env->hints, qinf->qname, + qinf->qclass, NULL); + dp = forwards_lookup(qstate->env->fwds, qinf->qname, qinf->qclass); + + /* see if forward or stub is more pertinent */ + if(stub && stub->dp && dp) { + if(dname_strict_subdomain(dp->name, dp->namelabs, + stub->dp->name, stub->dp->namelabs)) { + stub = NULL; /* ignore stub, forward is lower */ + } else { + dp = NULL; /* ignore forward, stub is lower */ + } + } + + /* check stub */ + if (stub != NULL && stub->dp != NULL) { + if(stub->dp->no_cache) { + char qname[255+1]; + char dpname[255+1]; + dname_str(qinf->qname, qname); + dname_str(stub->dp->name, dpname); + verbose(VERB_ALGO, "stub for %s %s has no_cache", qname, dpname); + } + return (stub->dp->no_cache); + } + + /* Check for forward. */ + if (dp) { + if(dp->no_cache) { + char qname[255+1]; + char dpname[255+1]; + dname_str(qinf->qname, qname); + dname_str(dp->name, dpname); + verbose(VERB_ALGO, "forward for %s %s has no_cache", qname, dpname); + } + return (dp->no_cache); + } + return 0; +} diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index e971d930b164..ccfb280224b3 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -369,4 +369,13 @@ int iter_ds_toolow(struct dns_msg* msg, struct delegpt* dp); */ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp); +/** + * Lookup if no_cache is set in stub or fwd. + * @param qstate: query state with env with hints and fwds. + * @param qinf: query name to lookup for. + * @return true if no_cache is set in stub or fwd. + */ +int iter_stub_fwd_no_cache(struct module_qstate *qstate, + struct query_info *qinf); + #endif /* ITERATOR_ITER_UTILS_H */ diff --git a/iterator/iterator.c b/iterator/iterator.c index 2f26bd3349de..8312dfd53313 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -69,6 +69,9 @@ #include "sldns/parseutil.h" #include "sldns/sbuffer.h" +/* in msec */ +int UNKNOWN_SERVER_NICENESS = 376; + int iter_init(struct module_env* env, int id) { @@ -324,6 +327,29 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode) /* serving expired contents, but nothing is cached * at all, so the servfail cache entry is useful * (stops waste of time on this servfail NORR_TTL) */ + } else { + /* don't overwrite existing (non-expired) data in + * cache with a servfail */ + struct msgreply_entry* msg; + if((msg=msg_cache_lookup(qstate->env, + qstate->qinfo.qname, qstate->qinfo.qname_len, + qstate->qinfo.qtype, qstate->qinfo.qclass, + qstate->query_flags, *qstate->env->now, 0)) + != NULL) { + struct reply_info* rep = (struct reply_info*) + msg->entry.data; + if(FLAGS_GET_RCODE(rep->flags) == + LDNS_RCODE_NOERROR || + FLAGS_GET_RCODE(rep->flags) == + LDNS_RCODE_NXDOMAIN) { + /* we have a good entry, + * don't overwrite */ + lock_rw_unlock(&msg->entry.lock); + return error_response(qstate, id, rcode); + } + lock_rw_unlock(&msg->entry.lock); + } + } memset(&err, 0, sizeof(err)); err.flags = (uint16_t)(BIT_QR | BIT_RA); @@ -1144,53 +1170,6 @@ forward_request(struct module_qstate* qstate, struct iter_qstate* iq) return 1; } -static int -iter_stub_fwd_no_cache(struct module_qstate *qstate, struct iter_qstate *iq) -{ - struct iter_hints_stub *stub; - struct delegpt *dp; - - /* Check for stub. */ - stub = hints_lookup_stub(qstate->env->hints, iq->qchase.qname, - iq->qchase.qclass, iq->dp); - dp = forwards_lookup(qstate->env->fwds, iq->qchase.qname, iq->qchase.qclass); - - /* see if forward or stub is more pertinent */ - if(stub && stub->dp && dp) { - if(dname_strict_subdomain(dp->name, dp->namelabs, - stub->dp->name, stub->dp->namelabs)) { - stub = NULL; /* ignore stub, forward is lower */ - } else { - dp = NULL; /* ignore forward, stub is lower */ - } - } - - /* check stub */ - if (stub != NULL && stub->dp != NULL) { - if(stub->dp->no_cache) { - char qname[255+1]; - char dpname[255+1]; - dname_str(iq->qchase.qname, qname); - dname_str(stub->dp->name, dpname); - verbose(VERB_ALGO, "stub for %s %s has no_cache", qname, dpname); - } - return (stub->dp->no_cache); - } - - /* Check for forward. */ - if (dp) { - if(dp->no_cache) { - char qname[255+1]; - char dpname[255+1]; - dname_str(iq->qchase.qname, qname); - dname_str(dp->name, dpname); - verbose(VERB_ALGO, "forward for %s %s has no_cache", qname, dpname); - } - return (dp->no_cache); - } - return 0; -} - /** * Process the initial part of the request handling. This state roughly * corresponds to resolver algorithms steps 1 (find answer in cache) and 2 @@ -1268,7 +1247,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, /* This either results in a query restart (CNAME cache response), a * terminating response (ANSWER), or a cache miss (null). */ - if (iter_stub_fwd_no_cache(qstate, iq)) { + if (iter_stub_fwd_no_cache(qstate, &iq->qchase)) { /* Asked to not query cache. */ verbose(VERB_ALGO, "no-cache set, going to the network"); qstate->no_cache_lookup = 1; @@ -1903,7 +1882,6 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, struct delegpt* p = hints_lookup_root(qstate->env->hints, iq->qchase.qclass); if(p) { - struct delegpt_ns* ns; struct delegpt_addr* a; iq->chase_flags &= ~BIT_RD; /* go to authorities */ for(ns = p->nslist; ns; ns=ns->next) { @@ -2320,7 +2298,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, errinf(qstate, "auth zone lookup failed, fallback is off"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } - if(iq->dp && iq->dp->auth_dp) { + if(iq->dp->auth_dp) { /* we wanted to fallback, but had no delegpt, only the * auth zone generated delegpt, create an actual one */ iq->auth_zone_avoid = 1; @@ -3592,7 +3570,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, if(event == module_event_noreply || event == module_event_error) { if(event == module_event_noreply && iq->sent_count >= 3 && qstate->env->cfg->use_caps_bits_for_id && - !iq->caps_fallback) { + !iq->caps_fallback && !is_caps_whitelisted(ie, iq)) { /* start fallback */ iq->caps_fallback = 1; iq->caps_server = 0; diff --git a/iterator/iterator.h b/iterator/iterator.h index 57cb7c4c474e..a2f1b5705e70 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -83,7 +83,7 @@ struct rbtree_type; /** how nice is a server without further information, in msec * Equals rtt initial timeout value. */ -#define UNKNOWN_SERVER_NICENESS 376 +extern int UNKNOWN_SERVER_NICENESS; /** maximum timeout before a host is deemed unsuitable, in msec. * After host_ttl this will be timed out and the host will be tried again. * Equals RTT_MAX_TIMEOUT |
