And then rebuild and install unbound and unwind:
cd /usr/src/usr.sbin/unbound
make -f Makefile.bsd-wrapper obj
make -f Makefile.bsd-wrapper clean
make -f Makefile.bsd-wrapper
make -f Makefile.bsd-wrapper install
cd /usr/src/sbin/unwind
make obj
make clean
make
make install
Index: sbin/unwind/libunbound/iterator/iter_delegpt.h
===================================================================
RCS file: /home/cvs/src/sbin/unwind/libunbound/iterator/iter_delegpt.h,v
retrieving revision 1.1
diff -u -p -r1.1 iter_delegpt.h
--- sbin/unwind/libunbound/iterator/iter_delegpt.h 23 Jan 2019 13:05:27 -0000 1.1
+++ sbin/unwind/libunbound/iterator/iter_delegpt.h 19 May 2020 16:50:57 -0000
@@ -106,9 +106,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.
@@ -215,11 +216,12 @@ int delegpt_rrset_add_ns(struct delegpt*
* @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.
@@ -227,10 +229,11 @@ int delegpt_add_target(struct delegpt* d
* @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.
@@ -238,10 +241,11 @@ int delegpt_add_rrset_A(struct delegpt*
* @param regional: where to allocate the info.
* @param rrset: RRset AAAA 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_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.
@@ -250,10 +254,11 @@ int delegpt_add_rrset_AAAA(struct delegp
* @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.
@@ -264,11 +269,12 @@ int delegpt_add_rrset(struct delegpt* dp
* @param bogus: if address is bogus.
* @param lame: if address is lame.
* @param tls_auth_name: TLS authentication name (or NULL).
+ * @param additions: will be set to 1 if a new address is added
* @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, char* tls_auth_name);
+ uint8_t bogus, uint8_t lame, char* tls_auth_name, int* additions);
/**
* Find NS record in name list of delegation point.
@@ -340,6 +346,14 @@ size_t delegpt_count_targets(struct dele
*/
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);
if(qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
@@ -246,7 +250,11 @@ error_supers(struct module_qstate* qstat
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 */
@@ -621,7 +629,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;
@@ -634,6 +642,15 @@ target_count_increase(struct iter_qstate
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;
}
/**
@@ -656,13 +673,15 @@ target_count_increase(struct iter_qstate
* @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;
@@ -689,11 +708,23 @@ generate_sub_request(uint8_t* qname, siz
valrec = 1;
}
/* Make sure we have a delegation point, otherwise priming failed
* or another failure occurred */
@@ -2240,12 +2289,41 @@ processQueryTargets(struct module_qstate
iq->qinfo_out.qtype, iq->qinfo_out.qclass,
qstate->query_flags, qstate->region,
qstate->env->scratch, 0);
- 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) {
@@ -2321,6 +2399,8 @@ processQueryTargets(struct module_qstate
* generated query will immediately be discarded due to depth and
* that servfail is cached, which is not good as opportunism goes. */
if(iq->depth < ie->max_dependency_depth
+ && iq->num_target_queries == 0
+ && (!iq->target_count || iq->target_count[2]==0)
&& iq->sent_count < TARGET_FETCH_STOP) {
tf_policy = ie->target_fetch_policy[iq->depth];
}
@@ -2366,6 +2446,7 @@ processQueryTargets(struct module_qstate
iq->num_current_queries++; /* RespState decrements it*/
iq->referral_count++; /* make sure we don't loop */
iq->sent_count = 0;
+ iq->dp_target_count = 0;
iq->state = QUERY_RESP_STATE;
return 1;
}
@@ -2453,6 +2534,7 @@ processQueryTargets(struct module_qstate
iq->num_current_queries++; /* RespState decrements it*/
iq->referral_count++; /* make sure we don't loop */
iq->sent_count = 0;
+ iq->dp_target_count = 0;
iq->state = QUERY_RESP_STATE;
return 1;
}
@@ -2747,7 +2829,8 @@ processQueryResponse(struct module_qstat
/* 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:",
@@ -2759,16 +2842,10 @@ processQueryResponse(struct module_qstat
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");
- outbound_list_clear(&iq->outlist);
- iq->num_current_queries = 0;
- fptr_ok(fptr_whitelist_modenv_detach_subs(
- qstate->env->detach_subs));
- (*qstate->env->detach_subs)(qstate);
- iq->num_target_queries = 0;
}
}
return next_state(iq, QUERYTARGETS_STATE);
@@ -2852,6 +2929,7 @@ processQueryResponse(struct module_qstat
/* 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,
@@ -2928,6 +3006,7 @@ processQueryResponse(struct module_qstat
iq->dsns_point = NULL;
iq->auth_zone_response = 0;
iq->sent_count = 0;
+ iq->dp_target_count = 0;
if(iq->minimisation_state != MINIMISE_STATE)
/* Only count as query restart when it is not an extra
* query as result of qname minimisation. */
@@ -3120,7 +3199,7 @@ processPrimeResponse(struct module_qstat
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);
@@ -3148,6 +3227,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;
@@ -3185,7 +3265,7 @@ processTargetResponse(struct module_qsta
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");
}
@@ -3196,6 +3276,7 @@ processTargetResponse(struct module_qsta
* 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,
@@ -3207,13 +3288,23 @@ processTargetResponse(struct module_qsta
}
/* 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);
}
}
/** 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,8 +310,13 @@ 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;
Index: usr.sbin/unbound/iterator/iter_delegpt.h
===================================================================
RCS file: /home/cvs/src/usr.sbin/unbound/iterator/iter_delegpt.h,v
retrieving revision 1.5
diff -u -p -r1.5 iter_delegpt.h
--- usr.sbin/unbound/iterator/iter_delegpt.h 20 Sep 2018 23:15:39 -0000 1.5
+++ usr.sbin/unbound/iterator/iter_delegpt.h 19 May 2020 16:49:57 -0000
@@ -106,9 +106,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.
@@ -215,11 +216,12 @@ int delegpt_rrset_add_ns(struct delegpt*
* @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.
@@ -227,10 +229,11 @@ int delegpt_add_target(struct delegpt* d
* @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.
@@ -238,10 +241,11 @@ int delegpt_add_rrset_A(struct delegpt*
* @param regional: where to allocate the info.
* @param rrset: RRset AAAA 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_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.
@@ -250,10 +254,11 @@ int delegpt_add_rrset_AAAA(struct delegp
* @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.
@@ -264,11 +269,12 @@ int delegpt_add_rrset(struct delegpt* dp
* @param bogus: if address is bogus.
* @param lame: if address is lame.
* @param tls_auth_name: TLS authentication name (or NULL).
+ * @param additions: will be set to 1 if a new address is added
* @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, char* tls_auth_name);
+ uint8_t bogus, uint8_t lame, char* tls_auth_name, int* additions);
/**
* Find NS record in name list of delegation point.
@@ -340,6 +346,14 @@ size_t delegpt_count_targets(struct dele
*/
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);
if(qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
@@ -246,7 +250,11 @@ error_supers(struct module_qstate* qstat
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 */
@@ -621,7 +629,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;
@@ -634,6 +642,15 @@ target_count_increase(struct iter_qstate
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;
}
/**
@@ -656,13 +673,15 @@ target_count_increase(struct iter_qstate
* @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;
@@ -689,11 +708,23 @@ generate_sub_request(uint8_t* qname, siz
valrec = 1;
}
/* Make sure we have a delegation point, otherwise priming failed
* or another failure occurred */
@@ -2240,12 +2289,41 @@ processQueryTargets(struct module_qstate
iq->qinfo_out.qtype, iq->qinfo_out.qclass,
qstate->query_flags, qstate->region,
qstate->env->scratch, 0);
- 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) {
@@ -2321,6 +2399,8 @@ processQueryTargets(struct module_qstate
* generated query will immediately be discarded due to depth and
* that servfail is cached, which is not good as opportunism goes. */
if(iq->depth < ie->max_dependency_depth
+ && iq->num_target_queries == 0
+ && (!iq->target_count || iq->target_count[2]==0)
&& iq->sent_count < TARGET_FETCH_STOP) {
tf_policy = ie->target_fetch_policy[iq->depth];
}
@@ -2366,6 +2446,7 @@ processQueryTargets(struct module_qstate
iq->num_current_queries++; /* RespState decrements it*/
iq->referral_count++; /* make sure we don't loop */
iq->sent_count = 0;
+ iq->dp_target_count = 0;
iq->state = QUERY_RESP_STATE;
return 1;
}
@@ -2453,6 +2534,7 @@ processQueryTargets(struct module_qstate
iq->num_current_queries++; /* RespState decrements it*/
iq->referral_count++; /* make sure we don't loop */
iq->sent_count = 0;
+ iq->dp_target_count = 0;
iq->state = QUERY_RESP_STATE;
return 1;
}
@@ -2747,7 +2829,8 @@ processQueryResponse(struct module_qstat
/* 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:",
@@ -2759,16 +2842,10 @@ processQueryResponse(struct module_qstat
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");
- outbound_list_clear(&iq->outlist);
- iq->num_current_queries = 0;
- fptr_ok(fptr_whitelist_modenv_detach_subs(
- qstate->env->detach_subs));
- (*qstate->env->detach_subs)(qstate);
- iq->num_target_queries = 0;
}
}
return next_state(iq, QUERYTARGETS_STATE);
@@ -2852,6 +2929,7 @@ processQueryResponse(struct module_qstat
/* 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,
@@ -2928,6 +3006,7 @@ processQueryResponse(struct module_qstat
iq->dsns_point = NULL;
iq->auth_zone_response = 0;
iq->sent_count = 0;
+ iq->dp_target_count = 0;
if(iq->minimisation_state != MINIMISE_STATE)
/* Only count as query restart when it is not an extra
* query as result of qname minimisation. */
@@ -3120,7 +3199,7 @@ processPrimeResponse(struct module_qstat
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);
@@ -3148,6 +3227,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;
@@ -3185,7 +3265,7 @@ processTargetResponse(struct module_qsta
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");
}
@@ -3196,6 +3276,7 @@ processTargetResponse(struct module_qsta
* 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,
@@ -3207,13 +3288,23 @@ processTargetResponse(struct module_qsta
}
/* 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);
}
}
/** 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,8 +310,13 @@ 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;