diff options
Diffstat (limited to 'iterator/iterator.c')
| -rw-r--r-- | iterator/iterator.c | 55 |
1 files changed, 52 insertions, 3 deletions
diff --git a/iterator/iterator.c b/iterator/iterator.c index 99ce96f384ee..43b3d30c330b 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -373,6 +373,29 @@ iter_prepend(struct iter_qstate* iq, struct dns_msg* msg, } /** + * Find rrset in ANSWER prepend list. + * to avoid duplicate DNAMEs when a DNAME is traversed twice. + * @param iq: iterator query state. + * @param rrset: rrset to add. + * @return false if not found + */ +static int +iter_find_rrset_in_prepend_answer(struct iter_qstate* iq, + struct ub_packed_rrset_key* rrset) +{ + struct iter_prep_list* p = iq->an_prepend_list; + while(p) { + if(ub_rrset_compare(p->rrset, rrset) == 0 && + rrsetdata_equal((struct packed_rrset_data*)p->rrset + ->entry.data, (struct packed_rrset_data*)rrset + ->entry.data)) + return 1; + p = p->next; + } + return 0; +} + +/** * Add rrset to ANSWER prepend list * @param qstate: query state. * @param iq: iterator query state. @@ -454,14 +477,16 @@ handle_cname_response(struct module_qstate* qstate, struct iter_qstate* iq, * by this DNAME following, so we don't process the DNAME * directly. */ if(ntohs(r->rk.type) == LDNS_RR_TYPE_DNAME && - dname_strict_subdomain_c(*mname, r->rk.dname)) { + dname_strict_subdomain_c(*mname, r->rk.dname) && + !iter_find_rrset_in_prepend_answer(iq, r)) { if(!iter_add_prepend_answer(qstate, iq, r)) return 0; continue; } if(ntohs(r->rk.type) == LDNS_RR_TYPE_CNAME && - query_dname_compare(*mname, r->rk.dname) == 0) { + query_dname_compare(*mname, r->rk.dname) == 0 && + !iter_find_rrset_in_prepend_answer(iq, r)) { /* Add this relevant CNAME rrset to the prepend list.*/ if(!iter_add_prepend_answer(qstate, iq, r)) return 0; @@ -1326,7 +1351,7 @@ processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq, /* If the RD flag wasn't set, then we just finish with the * cached referral as the response. */ - if(!(qstate->query_flags & BIT_RD)) { + if(!(qstate->query_flags & BIT_RD) && iq->deleg_msg) { iq->response = iq->deleg_msg; if(verbosity >= VERB_ALGO && iq->response) log_dns_msg("no RD requested, using delegation msg", @@ -2169,6 +2194,10 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, int dnsseclame = 0; enum response_type type; iq->num_current_queries--; + + if(!inplace_cb_query_response_call(qstate->env, qstate, iq->response)) + log_err("unable to call query_response callback"); + if(iq->response == NULL) { /* Don't increment qname when QNAME minimisation is enabled */ if(qstate->env->cfg->qname_minimisation) @@ -2233,6 +2262,22 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, } else iter_scrub_ds(iq->response, ns, iq->dp->name); } else iter_scrub_ds(iq->response, NULL, NULL); + if(type == RESPONSE_TYPE_THROWAWAY && + FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) { + /* YXDOMAIN is a permanent error, no need to retry */ + type = RESPONSE_TYPE_ANSWER; + } + if(type == RESPONSE_TYPE_CNAME && iq->response->rep->an_numrrsets >= 1 + && ntohs(iq->response->rep->rrsets[0]->rk.type) == LDNS_RR_TYPE_DNAME) { + uint8_t* sname = NULL; + size_t snamelen = 0; + get_cname_target(iq->response->rep->rrsets[0], &sname, + &snamelen); + if(snamelen && dname_subdomain_c(sname, iq->response->rep->rrsets[0]->rk.dname)) { + /* DNAME to a subdomain loop; do not recurse */ + type = RESPONSE_TYPE_ANSWER; + } + } /* handle each of the type cases */ if(type == RESPONSE_TYPE_ANSWER) { @@ -3161,6 +3206,10 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, /* like packet got dropped */ goto handle_it; } + if(!inplace_cb_edns_back_parsed_call(qstate->env, qstate)) { + log_err("unable to call edns_back_parsed callback"); + goto handle_it; + } } /* remove CD-bit, we asked for in case we handle validation ourself */ |
