Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP2
unbound.24859
unbound-1.6.8-amplifying-an-incoming-query.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File unbound-1.6.8-amplifying-an-incoming-query.patch of Package unbound.24859
diff --git a/iterator/iter_delegpt.c b/iterator/iter_delegpt.c index ecf88b2..1ababa1 100644 --- a/iterator/iter_delegpt.c +++ b/iterator/iter_delegpt.c @@ -84,7 +84,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region) } for(a = dp->target_list; a; a = a->next_target) { if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen, - a->bogus, a->lame)) + a->bogus, a->lame, NULL)) return NULL; } return copy; @@ -161,7 +161,7 @@ delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr, int delegpt_add_target(struct delegpt* dp, struct regional* region, uint8_t* name, size_t namelen, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t bogus, uint8_t lame) + socklen_t addrlen, uint8_t bogus, uint8_t lame, int* additions) { struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); log_assert(!dp->dp_type_mlc); @@ -176,13 +176,13 @@ delegpt_add_target(struct delegpt* dp, struct regional* region, if(ns->got4 && ns->got6) ns->resolved = 1; } - return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame); + return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame, additions); } int delegpt_add_addr(struct delegpt* dp, struct regional* region, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, - uint8_t lame) + uint8_t lame, int* additions) { struct delegpt_addr* a; log_assert(!dp->dp_type_mlc); @@ -195,6 +195,9 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region, return 1; } + if(additions) + *additions = 1; + a = (struct delegpt_addr*)regional_alloc(region, sizeof(struct delegpt_addr)); if(!a) @@ -370,10 +373,10 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region) continue; if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { - if(!delegpt_add_rrset_A(dp, region, s, 0)) + if(!delegpt_add_rrset_A(dp, region, s, 0, NULL)) return NULL; } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { - if(!delegpt_add_rrset_AAAA(dp, region, s, 0)) + if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL)) return NULL; } } @@ -404,7 +407,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, int delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ak, uint8_t lame) + struct ub_packed_rrset_key* ak, uint8_t lame, int* additions) { struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; size_t i; @@ -420,7 +423,7 @@ delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE); if(!delegpt_add_target(dp, region, ak->rk.dname, ak->rk.dname_len, (struct sockaddr_storage*)&sa, - len, (d->security==sec_status_bogus), lame)) + len, (d->security==sec_status_bogus), lame, additions)) return 0; } return 1; @@ -428,7 +431,7 @@ delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ak, uint8_t lame) + struct ub_packed_rrset_key* ak, uint8_t lame, int* additions) { struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; size_t i; @@ -444,7 +447,7 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE); if(!delegpt_add_target(dp, region, ak->rk.dname, ak->rk.dname_len, (struct sockaddr_storage*)&sa, - len, (d->security==sec_status_bogus), lame)) + len, (d->security==sec_status_bogus), lame, additions)) return 0; } return 1; @@ -452,20 +455,32 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, int delegpt_add_rrset(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* rrset, uint8_t lame) + struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions) { if(!rrset) return 1; if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) return delegpt_rrset_add_ns(dp, region, rrset, lame); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) - return delegpt_add_rrset_A(dp, region, rrset, lame); + return delegpt_add_rrset_A(dp, region, rrset, lame, additions); else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) - return delegpt_add_rrset_AAAA(dp, region, rrset, lame); + return delegpt_add_rrset_AAAA(dp, region, rrset, lame, additions); log_warn("Unknown rrset type added to delegpt"); return 1; } +void delegpt_mark_neg(struct delegpt_ns* ns, uint16_t qtype) +{ + if(ns) { + if(qtype == LDNS_RR_TYPE_A) + ns->got4 = 2; + else if(qtype == LDNS_RR_TYPE_AAAA) + ns->got6 = 2; + if(ns->got4 && ns->got6) + ns->resolved = 1; + } +} + void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg) { struct reply_info* rep = (struct reply_info*)msg->entry.data; @@ -475,14 +490,7 @@ void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg) if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) { struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname, msg->key.qname_len); - if(ns) { - if(msg->key.qtype == LDNS_RR_TYPE_A) - ns->got4 = 1; - else if(msg->key.qtype == LDNS_RR_TYPE_AAAA) - ns->got6 = 1; - if(ns->got4 && ns->got6) - ns->resolved = 1; - } + delegpt_mark_neg(ns, msg->key.qtype); } } diff --git a/iterator/iter_delegpt.h b/iterator/iter_delegpt.h index 4bd79c8..e640fc6 100644 --- a/iterator/iter_delegpt.h +++ b/iterator/iter_delegpt.h @@ -102,9 +102,10 @@ struct delegpt_ns { * and marked true if got4 and got6 are both true. */ int resolved; - /** if the ipv4 address is in the delegpt */ + /** if the ipv4 address is in the delegpt, 0=not, 1=yes 2=negative, + * * negative means it was done, but no content. */ uint8_t got4; - /** if the ipv6 address is in the delegpt */ + /** if the ipv6 address is in the delegpt, 0=not, 1=yes 2=negative */ uint8_t got6; /** * If the name is parent-side only and thus dispreferred. @@ -209,11 +210,12 @@ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional, * @param addrlen: the length of addr. * @param bogus: security status for the address, pass true if bogus. * @param lame: address is lame. + * @param additions: will be set to 1 if a new address is added * @return false on error. */ int delegpt_add_target(struct delegpt* dp, struct regional* regional, uint8_t* name, size_t namelen, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t bogus, uint8_t lame); + socklen_t addrlen, uint8_t bogus, uint8_t lame, int* additions); /** * Add A RRset to delegpt. @@ -221,21 +223,23 @@ int delegpt_add_target(struct delegpt* dp, struct regional* regional, * @param regional: where to allocate the info. * @param rrset: RRset A to add. * @param lame: rrset is lame, disprefer it. + * @param additions: will be set to 1 if a new address is added * @return 0 on alloc error. */ int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* rrset, uint8_t lame); + struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions); /** * Add AAAA RRset to delegpt. * @param dp: delegation point. * @param regional: where to allocate the info. * @param rrset: RRset AAAA to add. + * @param additions: will be set to 1 if a new address is added * @param lame: rrset is lame, disprefer it. * @return 0 on alloc error. */ int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* rrset, uint8_t lame); + struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions); /** * Add any RRset to delegpt. @@ -244,10 +248,11 @@ int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional, * @param regional: where to allocate the info. * @param rrset: RRset to add, NS, A, AAAA. * @param lame: rrset is lame, disprefer it. + * @param additions: will be set to 1 if a new address is added * @return 0 on alloc error. */ int delegpt_add_rrset(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* rrset, uint8_t lame); + struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions); /** * Add address to the delegation point. No servername is associated or checked. @@ -257,11 +262,13 @@ int delegpt_add_rrset(struct delegpt* dp, struct regional* regional, * @param addrlen: the length of addr. * @param bogus: if address is bogus. * @param lame: if address is lame. + * @param additions: will be set to 1 if a new address is added + * @return 0 on alloc error. * @return false on error. */ int delegpt_add_addr(struct delegpt* dp, struct regional* regional, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t bogus, uint8_t lame); + uint8_t bogus, uint8_t lame, int* additions); /** * Find NS record in name list of delegation point. @@ -334,6 +341,14 @@ size_t delegpt_count_targets(struct delegpt* dp); struct delegpt* delegpt_from_message(struct dns_msg* msg, struct regional* regional); +/** +* Mark negative return in delegation point for specific nameserver. +* sets the got4 or got6 to negative, updates the ns->resolved. +* @param ns: the nameserver in the delegpt. +* @param qtype: A or AAAA (host order). +*/ +void delegpt_mark_neg(struct delegpt_ns* ns, uint16_t qtype); + /** * Add negative message to delegation point. * @param dp: delegation point. diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c index 6bdfe41..36ff766 100644 --- a/iterator/iter_scrub.c +++ b/iterator/iter_scrub.c @@ -185,8 +185,9 @@ mark_additional_rrset(sldns_buffer* pkt, struct msg_parse* msg, /** Get target name of a CNAME */ static int parse_get_cname_target(struct rrset_parse* rrset, uint8_t** sname, - size_t* snamelen) + size_t* snamelen, sldns_buffer* pkt) { + size_t oldpos, dlen; if(rrset->rr_count != 1) { struct rr_parse* sig; verbose(VERB_ALGO, "Found CNAME rrset with " @@ -204,6 +205,19 @@ parse_get_cname_target(struct rrset_parse* rrset, uint8_t** sname, *sname = rrset->rr_first->ttl_data + sizeof(uint32_t) + sizeof(uint16_t); /* skip ttl, rdatalen */ *snamelen = rrset->rr_first->size - sizeof(uint16_t); + + if(rrset->rr_first->outside_packet) { + if(!dname_valid(*sname, *snamelen)) + return 0; + return 1; + } + oldpos = sldns_buffer_position(pkt); + sldns_buffer_set_position(pkt, (size_t)(*sname - sldns_buffer_begin(pkt))); + dlen = pkt_dname_len(pkt); + sldns_buffer_set_position(pkt, oldpos); + if(dlen == 0) + return 0; /* parse fail on the rdata name */ + *snamelen = dlen; return 1; } @@ -215,7 +229,7 @@ synth_cname(uint8_t* qname, size_t qnamelen, struct rrset_parse* dname_rrset, /* we already know that sname is a strict subdomain of DNAME owner */ uint8_t* dtarg = NULL; size_t dtarglen; - if(!parse_get_cname_target(dname_rrset, &dtarg, &dtarglen)) + if(!parse_get_cname_target(dname_rrset, &dtarg, &dtarglen, pkt)) return 0; log_assert(qnamelen > dname_rrset->dname_len); /* DNAME from com. to net. with qname example.com. -> example.net. */ @@ -372,7 +386,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, /* check next cname */ uint8_t* t = NULL; size_t tlen = 0; - if(!parse_get_cname_target(nx, &t, &tlen)) + if(!parse_get_cname_target(nx, &t, &tlen, pkt)) return 0; if(dname_pkt_compare(pkt, alias, t) == 0) { /* it's OK and better capitalized */ @@ -423,7 +437,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, size_t tlen = 0; if(synth_cname(sname, snamelen, nx, alias, &aliaslen, pkt) && - parse_get_cname_target(rrset, &t, &tlen) && + parse_get_cname_target(rrset, &t, &tlen, pkt) && dname_pkt_compare(pkt, alias, t) == 0) { /* the synthesized CNAME equals the * current CNAME. This CNAME is the @@ -441,7 +455,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, } /* move to next name in CNAME chain */ - if(!parse_get_cname_target(rrset, &sname, &snamelen)) + if(!parse_get_cname_target(rrset, &sname, &snamelen, pkt)) return 0; prev = rrset; rrset = rrset->rrset_all_next; diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 70cab40..fc7d625 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -997,7 +997,7 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env, log_rrset_key(VERB_ALGO, "found parent-side", akey); ns->done_pside4 = 1; /* a negative-cache-element has no addresses it adds */ - if(!delegpt_add_rrset_A(dp, region, akey, 1)) + if(!delegpt_add_rrset_A(dp, region, akey, 1, NULL)) log_err("malloc failure in lookup_parent_glue"); lock_rw_unlock(&akey->entry.lock); } @@ -1009,7 +1009,7 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env, log_rrset_key(VERB_ALGO, "found parent-side", akey); ns->done_pside6 = 1; /* a negative-cache-element has no addresses it adds */ - if(!delegpt_add_rrset_AAAA(dp, region, akey, 1)) + if(!delegpt_add_rrset_AAAA(dp, region, akey, 1, NULL)) log_err("malloc failure in lookup_parent_glue"); lock_rw_unlock(&akey->entry.lock); } diff --git a/iterator/iterator.c b/iterator/iterator.c index 01ac883..7fd4d32 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -68,6 +68,8 @@ #include "sldns/parseutil.h" #include "sldns/sbuffer.h" +static void target_count_increase_nx(struct iter_qstate* iq, int num); + int iter_init(struct module_env* env, int id) { @@ -146,6 +148,7 @@ iter_new(struct module_qstate* qstate, int id) iq->sent_count = 0; iq->ratelimit_ok = 0; iq->target_count = NULL; + iq->dp_target_count = 0; iq->wait_priming_stub = 0; iq->refetch_glue = 0; iq->dnssec_expected = 0; @@ -217,6 +220,7 @@ final_state(struct iter_qstate* iq) static void error_supers(struct module_qstate* qstate, int id, struct module_qstate* super) { + struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id]; struct iter_qstate* super_iq = (struct iter_qstate*)super->minfo[id]; if(qstate->qinfo.qtype == LDNS_RR_TYPE_A || @@ -241,7 +245,11 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super) super->region, super_iq->dp)) log_err("out of memory adding missing"); } + delegpt_mark_neg(dpns, qstate->qinfo.qtype); dpns->resolved = 1; /* mark as failed */ + if((dpns->got4 == 2 || !ie->supports_ipv4) && + (dpns->got6 == 2 || !ie->supports_ipv6)) + target_count_increase_nx(super_iq, 1); } if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) { /* prime failed to get delegation */ @@ -574,7 +582,7 @@ static void target_count_create(struct iter_qstate* iq) { if(!iq->target_count) { - iq->target_count = (int*)calloc(2, sizeof(int)); + iq->target_count = (int*)calloc(3, sizeof(int)); /* if calloc fails we simply do not track this number */ if(iq->target_count) iq->target_count[0] = 1; @@ -587,6 +595,15 @@ target_count_increase(struct iter_qstate* iq, int num) target_count_create(iq); if(iq->target_count) iq->target_count[1] += num; + iq->dp_target_count++; +} + +static void +target_count_increase_nx(struct iter_qstate* iq, int num) +{ + target_count_create(iq); + if(iq->target_count) + iq->target_count[2] += num; } /** @@ -609,13 +626,15 @@ target_count_increase(struct iter_qstate* iq, int num) * @param subq_ret: if newly allocated, the subquerystate, or NULL if it does * not need initialisation. * @param v: if true, validation is done on the subquery. + * @param detached: true if this qstate should not attach to the subquery * @return false on error (malloc). */ static int generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, struct module_qstate* qstate, int id, struct iter_qstate* iq, enum iter_state initial_state, - enum iter_state finalstate, struct module_qstate** subq_ret, int v) + enum iter_state finalstate, struct module_qstate** subq_ret, int v, + int detached) { struct module_qstate* subq = NULL; struct iter_qstate* subiq = NULL; @@ -642,12 +661,24 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype, valrec = 1; } - /* attach subquery, lookup existing or make a new one */ - fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); - if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, valrec, - &subq)) { - return 0; - } + if(detached) { + struct mesh_state* sub = NULL; + fptr_ok(fptr_whitelist_modenv_add_sub( + qstate->env->add_sub)); + if(!(*qstate->env->add_sub)(qstate, &qinf, + qflags, prime, valrec, &subq, &sub)){ + return 0; + } + } + else { + /* attach subquery, lookup existing or make a new one */ + fptr_ok(fptr_whitelist_modenv_attach_sub( + qstate->env->attach_sub)); + if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, + valrec, &subq)) { + return 0; + } + } *subq_ret = subq; if(subq) { /* initialise the new subquery */ @@ -669,6 +700,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype, subiq->target_count = iq->target_count; if(iq->target_count) iq->target_count[0] ++; /* extra reference */ + subiq->dp_target_count = 0; subiq->num_current_queries = 0; subiq->depth = iq->depth+1; outbound_list_init(&subiq->outlist); @@ -712,7 +744,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id, * the normal INIT state logic (which would cause an infloop). */ if(!generate_sub_request((uint8_t*)"\000", 1, LDNS_RR_TYPE_NS, qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE, - &subq, 0)) { + &subq, 0, 0)) { verbose(VERB_ALGO, "could not prime root"); return 0; } @@ -797,7 +829,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, * redundant INIT state processing. */ if(!generate_sub_request(stub_dp->name, stub_dp->namelen, LDNS_RR_TYPE_NS, qclass, qstate, id, iq, - QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0)) { + QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0, 0)) { verbose(VERB_ALGO, "could not prime stub"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); return 1; /* return 1 to make module stop, with error */ @@ -878,7 +910,7 @@ generate_a_aaaa_check(struct module_qstate* qstate, struct iter_qstate* iq, if(!generate_sub_request(s->rk.dname, s->rk.dname_len, ntohs(s->rk.type), ntohs(s->rk.rrset_class), qstate, id, iq, - INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) { + INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1, 0)) { verbose(VERB_ALGO, "could not generate addr check"); return; } @@ -919,7 +951,7 @@ generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id) iq->dp->name, LDNS_RR_TYPE_NS, iq->qchase.qclass); if(!generate_sub_request(iq->dp->name, iq->dp->namelen, LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq, - INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) { + INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1, 0)) { verbose(VERB_ALGO, "could not generate ns check"); return; } @@ -976,7 +1008,7 @@ generate_dnskey_prefetch(struct module_qstate* qstate, iq->dp->name, LDNS_RR_TYPE_DNSKEY, iq->qchase.qclass); if(!generate_sub_request(iq->dp->name, iq->dp->namelen, LDNS_RR_TYPE_DNSKEY, iq->qchase.qclass, qstate, id, iq, - INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) { + INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0)) { /* we'll be slower, but it'll work */ verbose(VERB_ALGO, "could not generate dnskey prefetch"); return; @@ -1150,6 +1182,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, iq->refetch_glue = 0; iq->query_restart_count++; iq->sent_count = 0; + iq->dp_target_count = 0; sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region); if(qstate->env->cfg->qname_minimisation) iq->minimisation_state = INIT_MINIMISE_STATE; @@ -1468,7 +1501,7 @@ generate_parentside_target_query(struct module_qstate* qstate, { struct module_qstate* subq; if(!generate_sub_request(name, namelen, qtype, qclass, qstate, - id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) + id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0)) return 0; if(subq) { struct iter_qstate* subiq = @@ -1519,7 +1552,7 @@ generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq, { struct module_qstate* subq; if(!generate_sub_request(name, namelen, qtype, qclass, qstate, - id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) + id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0)) return 0; log_nametypeclass(VERB_QUERY, "new target", name, qtype, qclass); return 1; @@ -1558,6 +1591,14 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, "number of glue fetches %d", s, iq->target_count[1]); return 0; } + if(iq->dp_target_count > MAX_DP_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 to a single delegation point", + s, iq->dp_target_count); + return 0; + } iter_mark_cycle_targets(qstate, iq->dp); missing = (int)delegpt_count_missing_targets(iq->dp); @@ -1670,7 +1711,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, for(a = p->target_list; a; a=a->next_target) { (void)delegpt_add_addr(iq->dp, qstate->region, &a->addr, a->addrlen, a->bogus, - a->lame); + a->lame, NULL); } } iq->dp->has_parent_side_NS = 1; @@ -1687,6 +1728,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, iq->refetch_glue = 1; iq->query_restart_count++; iq->sent_count = 0; + iq->dp_target_count = 0; if(qstate->env->cfg->qname_minimisation) iq->minimisation_state = INIT_MINIMISE_STATE; return next_state(iq, INIT_REQUEST_STATE); @@ -1841,7 +1883,7 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id) iq->dsns_point, LDNS_RR_TYPE_NS, iq->qchase.qclass); if(!generate_sub_request(iq->dsns_point, iq->dsns_point_len, LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq, - INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) { + INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0)) { return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } @@ -1893,6 +1935,15 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, "number of sends with %d", iq->sent_count); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } + + if(iq->target_count && iq->target_count[2] > MAX_TARGET_NX) { + verbose(VERB_QUERY, "request has exceeded the maximum " + " number of nxdomain nameserver lookups with %d", + iq->target_count[2]); + errinf(qstate, "exceeded the maximum nameserver nxdomains"); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + /* Make sure we have a delegation point, otherwise priming failed * or another failure occurred */ @@ -2160,12 +2211,41 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, iq->qinfo_out.qtype, iq->qinfo_out.qclass, qstate->query_flags, qstate->region, qstate->env->scratch); - if(msg && msg->rep->an_numrrsets == 0 - && FLAGS_GET_RCODE(msg->rep->flags) == + if(msg && FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NOERROR) /* no need to send query if it is already - * cached as NOERROR/NODATA */ + * cached as NOERROR */ return 1; + if(msg && FLAGS_GET_RCODE(msg->rep->flags) == + LDNS_RCODE_NXDOMAIN && + qstate->env->need_to_validate && + qstate->env->cfg->harden_below_nxdomain) { + if(msg->rep->security == sec_status_secure) { + iq->response = msg; + return final_state(iq); + } + if(msg->rep->security == sec_status_unchecked) { + struct module_qstate* subq = NULL; + if(!generate_sub_request( + iq->qinfo_out.qname, + iq->qinfo_out.qname_len, + iq->qinfo_out.qtype, + iq->qinfo_out.qclass, + qstate, id, iq, + INIT_REQUEST_STATE, + FINISHED_STATE, &subq, 1, 1)) + verbose(VERB_ALGO, + "could not validate NXDOMAIN " + "response"); + } + } + if(msg && FLAGS_GET_RCODE(msg->rep->flags) == + LDNS_RCODE_NXDOMAIN) { + /* return and add a label in the next + * minimisation iteration. + */ + return 1; + } } } if(iq->minimisation_state == SKIP_MINIMISE_STATE) { @@ -2216,6 +2296,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, outbound_list_insert(&iq->outlist, outq); iq->num_current_queries++; iq->sent_count++; + iq->dp_target_count = 0; qstate->ext_state[id] = module_wait_reply; return 0; @@ -2404,7 +2485,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, /* Make subrequest to validate intermediate * NXDOMAIN if harden-below-nxdomain is * enabled. */ - if(qstate->env->cfg->harden_below_nxdomain) { + if(qstate->env->cfg->harden_below_nxdomain && + qstate->env->need_to_validate) { struct module_qstate* subq = NULL; log_query_info(VERB_QUERY, "schedule NXDOMAIN validation:", @@ -2416,7 +2498,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, iq->response->qinfo.qclass, qstate, id, iq, INIT_REQUEST_STATE, - FINISHED_STATE, &subq, 1)) + FINISHED_STATE, &subq, 1, 1)) verbose(VERB_ALGO, "could not validate NXDOMAIN " "response"); @@ -2499,6 +2581,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, /* Count this as a referral. */ iq->referral_count++; iq->sent_count = 0; + iq->dp_target_count = 0; /* see if the next dp is a trust anchor, or a DS was sent * along, indicating dnssec is expected for next zone */ iq->dnssec_expected = iter_indicates_dnssec(qstate->env, @@ -2739,7 +2822,7 @@ processPrimeResponse(struct module_qstate* qstate, int id) if(!generate_sub_request(qstate->qinfo.qname, qstate->qinfo.qname_len, qstate->qinfo.qtype, qstate->qinfo.qclass, qstate, id, iq, - INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) { + INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1, 0)) { verbose(VERB_ALGO, "could not generate prime check"); } generate_a_aaaa_check(qstate, iq, id); @@ -2767,6 +2850,7 @@ static void processTargetResponse(struct module_qstate* qstate, int id, struct module_qstate* forq) { + struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id]; struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id]; struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id]; struct ub_packed_rrset_key* rrset; @@ -2804,7 +2888,7 @@ processTargetResponse(struct module_qstate* qstate, int id, log_rrset_key(VERB_ALGO, "add parentside glue to dp", iq->pside_glue); if(!delegpt_add_rrset(foriq->dp, forq->region, - iq->pside_glue, 1)) + iq->pside_glue, 1, NULL)) log_err("out of memory adding pside glue"); } @@ -2815,6 +2899,7 @@ processTargetResponse(struct module_qstate* qstate, int id, * response type was ANSWER. */ rrset = reply_find_answer_rrset(&iq->qchase, qstate->return_msg->rep); if(rrset) { + int additions = 0; /* 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, @@ -2826,13 +2911,23 @@ processTargetResponse(struct module_qstate* qstate, int id, } /* if dpns->lame then set the address(es) lame too */ if(!delegpt_add_rrset(foriq->dp, forq->region, rrset, - dpns->lame)) + dpns->lame, &additions)) log_err("out of memory adding targets"); + if(!additions) { + /* no new addresses, increase the nxns counter, like + * this could be a list of wildcards with no new + * addresses */ + target_count_increase_nx(foriq, 1); + } verbose(VERB_ALGO, "added target response"); delegpt_log(VERB_ALGO, foriq->dp); } else { verbose(VERB_ALGO, "iterator TargetResponse failed"); + delegpt_mark_neg(dpns, qstate->qinfo.qtype); dpns->resolved = 1; /* fail the target */ + if((dpns->got4 == 2 || !ie->supports_ipv4) && + (dpns->got6 == 2 || !ie->supports_ipv6)) + target_count_increase_nx(foriq, 1); } } @@ -3003,7 +3098,7 @@ processCollectClass(struct module_qstate* qstate, int id) qstate->qinfo.qname_len, qstate->qinfo.qtype, c, qstate, id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, - (int)!(qstate->query_flags&BIT_CD))) { + (int)!(qstate->query_flags&BIT_CD), 0)) { return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } diff --git a/iterator/iterator.h b/iterator/iterator.h index 75aafee..3534b5c 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -55,6 +55,11 @@ struct rbtree_type; /** max number of targets spawned for a query and its subqueries */ #define MAX_TARGET_COUNT 64 +/** max number of target lookups per qstate, per delegation point */ +#define MAX_DP_TARGET_COUNT 16 +/** max number of nxdomains allowed for target lookups for a query and + * its subqueries */ +#define MAX_TARGET_NX 5 /** 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 */ @@ -305,9 +310,14 @@ struct iter_qstate { int sent_count; /** number of target queries spawned in [1], for this query and its - * subqueries, the malloced-array is shared, [0] refcount. */ + * subqueries, the malloced-array is shared, [0] refcount. + * in [2] the number of nxdomains is counted. */ int* target_count; + /** number of target lookups per delegation point. Reset to 0 after + * receiving referral answer. Not shared with subqueries. */ + int dp_target_count; + /** if true, already tested for ratelimiting and passed the test */ int ratelimit_ok; diff --git a/services/cache/dns.c b/services/cache/dns.c index da43c50..ce138f1 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -223,7 +223,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); if(akey) { - if(!delegpt_add_rrset_A(dp, region, akey, 0)) { + if(!delegpt_add_rrset_A(dp, region, akey, 0, NULL)) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -243,7 +243,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0); if(akey) { - if(!delegpt_add_rrset_AAAA(dp, region, akey, 0)) { + if(!delegpt_add_rrset_AAAA(dp, region, akey, 0, NULL)) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -277,7 +277,8 @@ cache_fill_missing(struct module_env* env, uint16_t qclass, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); if(akey) { - if(!delegpt_add_rrset_A(dp, region, akey, ns->lame)) { + if(!delegpt_add_rrset_A(dp, region, akey, ns->lame, + NULL)) { lock_rw_unlock(&akey->entry.lock); return 0; } @@ -297,7 +298,8 @@ cache_fill_missing(struct module_env* env, uint16_t qclass, akey = rrset_cache_lookup(env->rrset_cache, ns->name, ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0); if(akey) { - if(!delegpt_add_rrset_AAAA(dp, region, akey, ns->lame)) { + if(!delegpt_add_rrset_AAAA(dp, region, akey, ns->lame, + NULL)) { lock_rw_unlock(&akey->entry.lock); return 0; } diff --git a/util/data/dname.c b/util/data/dname.c index 517af28..a80a4e2 100644 --- a/util/data/dname.c +++ b/util/data/dname.c @@ -231,17 +231,28 @@ int dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2) { uint8_t len1, len2; + int count1 = 0, count2 = 0; log_assert(pkt && d1 && d2); len1 = *d1++; len2 = *d2++; while( len1 != 0 || len2 != 0 ) { /* resolve ptrs */ if(LABEL_IS_PTR(len1)) { + if((size_t)PTR_OFFSET(len1, *d1) + >= sldns_buffer_limit(pkt)) + return -1; + if(count1++ > MAX_COMPRESS_PTRS) + return -1; d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1)); len1 = *d1++; continue; } if(LABEL_IS_PTR(len2)) { + if((size_t)PTR_OFFSET(len2, *d2) + >= sldns_buffer_limit(pkt)) + return 1; + if(count2++ > MAX_COMPRESS_PTRS) + return 1; d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2)); len2 = *d2++; continue; @@ -276,6 +287,7 @@ dname_query_hash(uint8_t* dname, hashvalue_type h) uint8_t labuf[LDNS_MAX_LABELLEN+1]; uint8_t lablen; int i; + int count = 0; /* preserve case of query, make hash label by label */ lablen = *dname++; @@ -333,6 +345,9 @@ void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname) while(lablen) { if(LABEL_IS_PTR(lablen)) { /* follow pointer */ + if((size_t)PTR_OFFSET(lablen, *dname) + >= sldns_buffer_limit(pkt)) + return; dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); lablen = *dname++; continue; @@ -357,6 +372,7 @@ void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname) void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname) { uint8_t lablen; + int count = 0; if(!out) out = stdout; if(!dname) return; @@ -370,6 +386,15 @@ void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname) fputs("??compressionptr??", out); return; } + if((size_t)PTR_OFFSET(lablen, *dname) + >= sldns_buffer_limit(pkt)) { + fputs("??compressionptr??", out); + return; + } + if(count++ > MAX_COMPRESS_PTRS) { + fputs("??compressionptr??", out); + return; + } dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); lablen = *dname++; continue; diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 2887200..783f3a7 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -55,7 +55,11 @@ smart_compare(sldns_buffer* pkt, uint8_t* dnow, { if(LABEL_IS_PTR(*dnow)) { /* ptr points to a previous dname */ - uint8_t* p = sldns_buffer_at(pkt, PTR_OFFSET(dnow[0], dnow[1])); + uint8_t* p; + if((size_t)PTR_OFFSET(dnow[0], dnow[1]) + >= sldns_buffer_limit(pkt)) + return -1; + p = sldns_buffer_at(pkt, PTR_OFFSET(dnow[0], dnow[1])); if( p == dprfirst || p == dprlast ) return 0; /* prev dname is also a ptr, both ptrs are the same. */
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor