diff options
author | Riccardo Spagni <ric@spagni.net> | 2015-04-02 11:16:18 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2015-04-02 11:16:18 +0200 |
commit | 1f49833d4fc449d54c95c3235b5c18523e6f8d69 (patch) | |
tree | ae027273609339b9b89e3e546552af7a7afb23e7 /external/unbound/iterator | |
parent | Merge pull request #248 (diff) | |
download | monero-1f49833d4fc449d54c95c3235b5c18523e6f8d69.tar.xz |
update unbound from upstream
Diffstat (limited to 'external/unbound/iterator')
-rw-r--r-- | external/unbound/iterator/iter_delegpt.c | 4 | ||||
-rw-r--r-- | external/unbound/iterator/iter_fwd.c | 4 | ||||
-rw-r--r-- | external/unbound/iterator/iter_hints.c | 6 | ||||
-rw-r--r-- | external/unbound/iterator/iter_priv.c | 4 | ||||
-rw-r--r-- | external/unbound/iterator/iter_resptype.c | 4 | ||||
-rw-r--r-- | external/unbound/iterator/iter_scrub.c | 6 | ||||
-rw-r--r-- | external/unbound/iterator/iter_utils.c | 44 | ||||
-rw-r--r-- | external/unbound/iterator/iter_utils.h | 17 | ||||
-rw-r--r-- | external/unbound/iterator/iterator.c | 120 | ||||
-rw-r--r-- | external/unbound/iterator/iterator.h | 7 |
10 files changed, 196 insertions, 20 deletions
diff --git a/external/unbound/iterator/iter_delegpt.c b/external/unbound/iterator/iter_delegpt.c index b212ec077..0e251ff58 100644 --- a/external/unbound/iterator/iter_delegpt.c +++ b/external/unbound/iterator/iter_delegpt.c @@ -47,8 +47,8 @@ #include "util/data/packed_rrset.h" #include "util/data/msgreply.h" #include "util/net_help.h" -#include "ldns/rrdef.h" -#include "ldns/sbuffer.h" +#include "sldns/rrdef.h" +#include "sldns/sbuffer.h" struct delegpt* delegpt_create(struct regional* region) diff --git a/external/unbound/iterator/iter_fwd.c b/external/unbound/iterator/iter_fwd.c index 012121241..0feee032c 100644 --- a/external/unbound/iterator/iter_fwd.c +++ b/external/unbound/iterator/iter_fwd.c @@ -46,8 +46,8 @@ #include "util/config_file.h" #include "util/net_help.h" #include "util/data/dname.h" -#include "ldns/rrdef.h" -#include "ldns/str2wire.h" +#include "sldns/rrdef.h" +#include "sldns/str2wire.h" int fwd_cmp(const void* k1, const void* k2) diff --git a/external/unbound/iterator/iter_hints.c b/external/unbound/iterator/iter_hints.c index 57b57c2e0..25cae0723 100644 --- a/external/unbound/iterator/iter_hints.c +++ b/external/unbound/iterator/iter_hints.c @@ -46,9 +46,9 @@ #include "util/config_file.h" #include "util/net_help.h" #include "util/data/dname.h" -#include "ldns/rrdef.h" -#include "ldns/str2wire.h" -#include "ldns/wire2str.h" +#include "sldns/rrdef.h" +#include "sldns/str2wire.h" +#include "sldns/wire2str.h" struct iter_hints* hints_create(void) diff --git a/external/unbound/iterator/iter_priv.c b/external/unbound/iterator/iter_priv.c index 9e09a84bd..90bea1746 100644 --- a/external/unbound/iterator/iter_priv.c +++ b/external/unbound/iterator/iter_priv.c @@ -49,8 +49,8 @@ #include "util/data/msgparse.h" #include "util/net_help.h" #include "util/storage/dnstree.h" -#include "ldns/str2wire.h" -#include "ldns/sbuffer.h" +#include "sldns/str2wire.h" +#include "sldns/sbuffer.h" struct iter_priv* priv_create(void) { diff --git a/external/unbound/iterator/iter_resptype.c b/external/unbound/iterator/iter_resptype.c index 45f919387..f146a2b6b 100644 --- a/external/unbound/iterator/iter_resptype.c +++ b/external/unbound/iterator/iter_resptype.c @@ -45,8 +45,8 @@ #include "services/cache/dns.h" #include "util/net_help.h" #include "util/data/dname.h" -#include "ldns/rrdef.h" -#include "ldns/pkthdr.h" +#include "sldns/rrdef.h" +#include "sldns/pkthdr.h" enum response_type response_type_from_cache(struct dns_msg* msg, diff --git a/external/unbound/iterator/iter_scrub.c b/external/unbound/iterator/iter_scrub.c index b2248bc0c..e9db19482 100644 --- a/external/unbound/iterator/iter_scrub.c +++ b/external/unbound/iterator/iter_scrub.c @@ -53,7 +53,7 @@ #include "util/data/dname.h" #include "util/data/msgreply.h" #include "util/alloc.h" -#include "ldns/sbuffer.h" +#include "sldns/sbuffer.h" /** RRset flag used during scrubbing. The RRset is OK. */ #define RRSET_SCRUB_OK 0x80 @@ -680,7 +680,9 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg, * (we dont want its glue that was approved * during the normalize action) */ del_addi = 1; - } else if(!env->cfg->harden_glue) { + } else if(!env->cfg->harden_glue && ( + rrset->type == LDNS_RR_TYPE_A || + rrset->type == LDNS_RR_TYPE_AAAA)) { /* store in cache! Since it is relevant * (from normalize) it will be picked up * from the cache to be used later */ diff --git a/external/unbound/iterator/iter_utils.c b/external/unbound/iterator/iter_utils.c index 9d0aa698f..5ec5752bf 100644 --- a/external/unbound/iterator/iter_utils.c +++ b/external/unbound/iterator/iter_utils.c @@ -64,7 +64,7 @@ #include "validator/val_kentry.h" #include "validator/val_utils.h" #include "validator/val_sigcrypt.h" -#include "ldns/sbuffer.h" +#include "sldns/sbuffer.h" /** time when nameserver glue is said to be 'recent' */ #define SUSPICION_RECENT_EXPIRY 86400 @@ -715,6 +715,48 @@ reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region) } void +caps_strip_reply(struct reply_info* rep) +{ + size_t i; + if(!rep) return; + /* see if message is a referral, in which case the additional and + * NS record cannot be removed */ + /* referrals have the AA flag unset (strict check, not elsewhere in + * unbound, but for 0x20 this is very convenient). */ + if(!(rep->flags&BIT_AA)) + return; + /* remove the additional section from the reply */ + if(rep->ar_numrrsets != 0) { + verbose(VERB_ALGO, "caps fallback: removing additional section"); + rep->rrset_count -= rep->ar_numrrsets; + rep->ar_numrrsets = 0; + } + /* is there an NS set in the authority section to remove? */ + /* the failure case (Cisco firewalls) only has one rrset in authsec */ + for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) { + struct ub_packed_rrset_key* s = rep->rrsets[i]; + if(ntohs(s->rk.type) == LDNS_RR_TYPE_NS) { + /* remove NS rrset and break from loop (loop limits + * have changed) */ + /* move last rrset into this position (there is no + * additional section any more) */ + verbose(VERB_ALGO, "caps fallback: removing NS rrset"); + if(i < rep->rrset_count-1) + rep->rrsets[i]=rep->rrsets[rep->rrset_count-1]; + rep->rrset_count --; + rep->ns_numrrsets --; + break; + } + } +} + +int caps_failed_rcode(struct reply_info* rep) +{ + return !(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR || + FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN); +} + +void iter_store_parentside_rrset(struct module_env* env, struct ub_packed_rrset_key* rrset) { diff --git a/external/unbound/iterator/iter_utils.h b/external/unbound/iterator/iter_utils.h index d7c2b68af..3a4df3e45 100644 --- a/external/unbound/iterator/iter_utils.h +++ b/external/unbound/iterator/iter_utils.h @@ -223,6 +223,23 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp, int reply_equal(struct reply_info* p, struct reply_info* q, struct regional* region); /** + * Remove unused bits from the reply if possible. + * So that caps-for-id (0x20) fallback is more likely to be successful. + * This removes like, the additional section, and NS record in the authority + * section if those records are gratuitous (not for a referral). + * @param rep: the reply to strip stuff out of. + */ +void caps_strip_reply(struct reply_info* rep); + +/** + * see if reply has a 'useful' rcode for capsforid comparison, so + * not SERVFAIL or REFUSED, and thus NOERROR or NXDOMAIN. + * @param rep: reply to check. + * @return true if the rcode is a bad type of message. + */ +int caps_failed_rcode(struct reply_info* rep); + +/** * Store parent-side rrset in seperate rrset cache entries for later * last-resort * lookups in case the child-side versions of this information * fails. diff --git a/external/unbound/iterator/iterator.c b/external/unbound/iterator/iterator.c index 843948a2e..02de86e12 100644 --- a/external/unbound/iterator/iterator.c +++ b/external/unbound/iterator/iterator.c @@ -61,10 +61,10 @@ #include "util/data/msgencode.h" #include "util/fptr_wlist.h" #include "util/config_file.h" -#include "ldns/rrdef.h" -#include "ldns/wire2str.h" -#include "ldns/parseutil.h" -#include "ldns/sbuffer.h" +#include "sldns/rrdef.h" +#include "sldns/wire2str.h" +#include "sldns/parseutil.h" +#include "sldns/sbuffer.h" int iter_init(struct module_env* env, int id) @@ -120,6 +120,7 @@ iter_new(struct module_qstate* qstate, int id) iq->query_restart_count = 0; iq->referral_count = 0; iq->sent_count = 0; + iq->target_count = NULL; iq->wait_priming_stub = 0; iq->refetch_glue = 0; iq->dnssec_expected = 0; @@ -307,6 +308,8 @@ iter_prepend(struct iter_qstate* iq, struct dns_msg* msg, if(num_an + num_ns == 0) return 1; verbose(VERB_ALGO, "prepending %d rrsets", (int)num_an + (int)num_ns); + if(num_an > RR_COUNT_MAX || num_ns > RR_COUNT_MAX || + msg->rep->rrset_count > RR_COUNT_MAX) return 0; /* overflow */ sets = regional_alloc(region, (num_an+num_ns+msg->rep->rrset_count) * sizeof(struct ub_packed_rrset_key*)); if(!sets) @@ -454,6 +457,26 @@ handle_cname_response(struct module_qstate* qstate, struct iter_qstate* iq, return 1; } +/** create target count structure for this query */ +static void +target_count_create(struct iter_qstate* iq) +{ + if(!iq->target_count) { + iq->target_count = (int*)calloc(2, sizeof(int)); + /* if calloc fails we simply do not track this number */ + if(iq->target_count) + iq->target_count[0] = 1; + } +} + +static void +target_count_increase(struct iter_qstate* iq, int num) +{ + target_count_create(iq); + if(iq->target_count) + iq->target_count[1] += num; +} + /** * Generate a subrequest. * Generate a local request event. Local events are tied to this module, and @@ -529,6 +552,10 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype, subiq = (struct iter_qstate*)subq->minfo[id]; memset(subiq, 0, sizeof(*subiq)); subiq->num_target_queries = 0; + target_count_create(iq); + subiq->target_count = iq->target_count; + if(iq->target_count) + iq->target_count[0] ++; /* extra reference */ subiq->num_current_queries = 0; subiq->depth = iq->depth+1; outbound_list_init(&subiq->outlist); @@ -1356,6 +1383,14 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, if(iq->depth == ie->max_dependency_depth) return 0; + if(iq->depth > 0 && iq->target_count && + iq->target_count[1] > MAX_TARGET_COUNT) { + char s[LDNS_MAX_DOMAINLEN+1]; + dname_str(qstate->qinfo.qname, s); + verbose(VERB_QUERY, "request %s has exceeded the maximum " + "number of glue fetches %d", s, iq->target_count[1]); + return 0; + } iter_mark_cycle_targets(qstate, iq->dp); missing = (int)delegpt_count_missing_targets(iq->dp); @@ -1538,6 +1573,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += qs; + target_count_increase(iq, qs); if(qs != 0) { qstate->ext_state[id] = module_wait_subquery; return 0; /* and wait for them */ @@ -1547,6 +1583,14 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, verbose(VERB_QUERY, "maxdepth and need more nameservers, fail"); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } + if(iq->depth > 0 && iq->target_count && + iq->target_count[1] > MAX_TARGET_COUNT) { + char s[LDNS_MAX_DOMAINLEN+1]; + dname_str(qstate->qinfo.qname, s); + verbose(VERB_QUERY, "request %s has exceeded the maximum " + "number of glue fetches %d", s, iq->target_count[1]); + return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); + } /* mark cycle targets for parent-side lookups */ iter_mark_pside_cycle_targets(qstate, iq->dp); /* see if we can issue queries to get nameserver addresses */ @@ -1576,6 +1620,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, if(query_count != 0) { /* suspend to await results */ verbose(VERB_ALGO, "try parent-side glue lookup"); iq->num_target_queries += query_count; + target_count_increase(iq, query_count); qstate->ext_state[id] = module_wait_subquery; return 0; } @@ -1731,6 +1776,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } iq->num_target_queries += extra; + target_count_increase(iq, extra); if(iq->num_target_queries > 0) { /* wait to get all targets, we want to try em */ verbose(VERB_ALGO, "wait for all targets for fallback"); @@ -1743,11 +1789,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, * the original query is one that matched too, so we have * caps_server+1 number of matching queries now */ if(iq->caps_server+1 >= naddr*3 || - iq->caps_server+1 >= MAX_SENT_COUNT) { + iq->caps_server*2+2 >= MAX_SENT_COUNT) { + /* *2 on sentcount check because ipv6 may fail */ /* we're done, process the response */ verbose(VERB_ALGO, "0x20 fallback had %d responses " "match for %d wanted, done.", (int)iq->caps_server+1, (int)naddr*3); + iq->response = iq->caps_response; iq->caps_fallback = 0; iter_dec_attempts(iq->dp, 3); /* space for fallback */ iq->num_current_queries++; /* RespState decrements it*/ @@ -1771,6 +1819,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, /* errors ignored, these targets are not strictly necessary for * this result, we do not have to reply with SERVFAIL */ iq->num_target_queries += extra; + target_count_increase(iq, extra); } /* Add the current set of unused targets to our queue. */ @@ -1816,10 +1865,29 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, return 1; } iq->num_target_queries += qs; + target_count_increase(iq, qs); } /* Since a target query might have been made, we * need to check again. */ if(iq->num_target_queries == 0) { + /* if in capsforid fallback, instead of last + * resort, we agree with the current reply + * we have (if any) (our count of addrs bad)*/ + if(iq->caps_fallback && iq->caps_reply) { + /* we're done, process the response */ + verbose(VERB_ALGO, "0x20 fallback had %d responses, " + "but no more servers except " + "last resort, done.", + (int)iq->caps_server+1); + iq->response = iq->caps_response; + iq->caps_fallback = 0; + iter_dec_attempts(iq->dp, 3); /* space for fallback */ + iq->num_current_queries++; /* RespState decrements it*/ + iq->referral_count++; /* make sure we don't loop */ + iq->sent_count = 0; + iq->state = QUERY_RESP_STATE; + return 1; + } return processLastResort(qstate, iq, ie, id); } } @@ -2483,6 +2551,12 @@ processClassResponse(struct module_qstate* qstate, int id, /* copy appropriate rcode */ to->rep->flags = from->rep->flags; /* copy rrsets */ + if(from->rep->rrset_count > RR_COUNT_MAX || + to->rep->rrset_count > RR_COUNT_MAX) { + log_err("malloc failed (too many rrsets) in collect ANY"); + foriq->state = FINISHED_STATE; + return; /* integer overflow protection */ + } dest = regional_alloc(forq->region, sizeof(dest[0])*n); if(!dest) { log_err("malloc failed in collect ANY"); @@ -2779,6 +2853,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, iq->caps_fallback = 1; iq->caps_server = 0; iq->caps_reply = NULL; + iq->caps_response = NULL; iq->state = QUERYTARGETS_STATE; iq->num_current_queries--; /* need fresh attempts for the 0x20 fallback, if @@ -2821,8 +2896,19 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, /* normalize and sanitize: easy to delete items from linked lists */ if(!scrub_message(pkt, prs, &iq->qchase, iq->dp->name, - qstate->env->scratch, qstate->env, ie)) + qstate->env->scratch, qstate->env, ie)) { + /* if 0x20 enabled, start fallback, but we have no message */ + if(event == module_event_capsfail && !iq->caps_fallback) { + iq->caps_fallback = 1; + iq->caps_server = 0; + iq->caps_reply = NULL; + iq->caps_response = NULL; + iq->state = QUERYTARGETS_STATE; + iq->num_current_queries--; + verbose(VERB_DETAIL, "Capsforid: scrub failed, starting fallback with no response"); + } goto handle_it; + } /* allocate response dns_msg in region */ iq->response = dns_alloc_msg(pkt, prs, qstate->region); @@ -2836,11 +2922,15 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, iq->response->rep); if(event == module_event_capsfail || iq->caps_fallback) { + /* for fallback we care about main answer, not additionals */ + /* removing that makes comparison more likely to succeed */ + caps_strip_reply(iq->response->rep); if(!iq->caps_fallback) { /* start fallback */ iq->caps_fallback = 1; iq->caps_server = 0; iq->caps_reply = iq->response->rep; + iq->caps_response = iq->response; iq->state = QUERYTARGETS_STATE; iq->num_current_queries--; verbose(VERB_DETAIL, "Capsforid: starting fallback"); @@ -2849,8 +2939,24 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, /* check if reply is the same, otherwise, fail */ if(!iq->caps_reply) { iq->caps_reply = iq->response->rep; + iq->caps_response = iq->response; iq->caps_server = -1; /*become zero at ++, so that we start the full set of trials */ + } else if(caps_failed_rcode(iq->caps_reply) && + !caps_failed_rcode(iq->response->rep)) { + /* prefer to upgrade to non-SERVFAIL */ + iq->caps_reply = iq->response->rep; + iq->caps_response = iq->response; + } else if(!caps_failed_rcode(iq->caps_reply) && + caps_failed_rcode(iq->response->rep)) { + /* if we have non-SERVFAIL as answer then + * we can ignore SERVFAILs for the equality + * comparison */ + /* no instructions here, skip other else */ + } else if(caps_failed_rcode(iq->caps_reply) && + caps_failed_rcode(iq->response->rep)) { + /* failure is same as other failure in fallbk*/ + /* no instructions here, skip other else */ } else if(!reply_equal(iq->response->rep, iq->caps_reply, qstate->env->scratch)) { verbose(VERB_DETAIL, "Capsforid fallback: " @@ -2928,6 +3034,8 @@ iter_clear(struct module_qstate* qstate, int id) iq = (struct iter_qstate*)qstate->minfo[id]; if(iq) { outbound_list_clear(&iq->outlist); + if(iq->target_count && --iq->target_count[0] == 0) + free(iq->target_count); iq->num_current_queries = 0; } qstate->minfo[id] = NULL; diff --git a/external/unbound/iterator/iterator.h b/external/unbound/iterator/iterator.h index 0b91760d4..cb8043fd5 100644 --- a/external/unbound/iterator/iterator.h +++ b/external/unbound/iterator/iterator.h @@ -52,6 +52,8 @@ struct iter_donotq; struct iter_prep_list; struct iter_priv; +/** max number of targets spawned for a query and its subqueries */ +#define MAX_TARGET_COUNT 32 /** max number of query restarts. Determines max number of CNAME chain. */ #define MAX_RESTART_COUNT 8 /** max number of referrals. Makes sure resolver does not run away */ @@ -233,6 +235,7 @@ struct iter_qstate { /** state for capsfail: stored query for comparisons. Can be NULL if * no response had been seen prior to starting the fallback. */ struct reply_info* caps_reply; + struct dns_msg* caps_response; /** Current delegation message - returned for non-RD queries */ struct dns_msg* deleg_msg; @@ -251,6 +254,10 @@ struct iter_qstate { /** number of queries fired off */ int sent_count; + + /** number of target queries spawned in [1], for this query and its + * subqueries, the malloced-array is shared, [0] refcount. */ + int* target_count; /** * The query must store NS records from referrals as parentside RRs |