aboutsummaryrefslogtreecommitdiff
path: root/iterator/iterator.c
diff options
context:
space:
mode:
Diffstat (limited to 'iterator/iterator.c')
-rw-r--r--iterator/iterator.c55
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 */