mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 06:37:08 +00:00
- Allow fallback to the parent side when MAX_TARGET_NX is reached.
This will also allow MAX_TARGET_NX more NXDOMAINs.
This commit is contained in:
parent
58b21e4fca
commit
923eb7d474
@ -7,6 +7,8 @@
|
||||
sent; introduces 'num.query.udpout' to the 'unbound-control stats'
|
||||
command.
|
||||
- Fix to not count cached NXDOMAIN for MAX_TARGET_NX.
|
||||
- Allow fallback to the parent side when MAX_TARGET_NX is reached.
|
||||
This will also allow MAX_TARGET_NX more NXDOMAINs.
|
||||
|
||||
28 June 2022: George
|
||||
- Show the output of the exact .rpl run that failed with 'make test'.
|
||||
|
@ -185,6 +185,10 @@ delegpt_add_target(struct delegpt* dp, struct regional* region,
|
||||
else ns->got4 = 1;
|
||||
if(ns->got4 && ns->got6)
|
||||
ns->resolved = 1;
|
||||
} else {
|
||||
if(addr_is_ip6(addr, addrlen))
|
||||
ns->done_pside6 = 1;
|
||||
else ns->done_pside4 = 1;
|
||||
}
|
||||
log_assert(ns->port>0);
|
||||
return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame,
|
||||
@ -338,13 +342,16 @@ delegpt_count_targets(struct delegpt* dp)
|
||||
}
|
||||
|
||||
size_t
|
||||
delegpt_count_missing_targets(struct delegpt* dp)
|
||||
delegpt_count_missing_targets(struct delegpt* dp, int* alllame)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
size_t n = 0;
|
||||
for(ns = dp->nslist; ns; ns = ns->next)
|
||||
if(!ns->resolved)
|
||||
n++;
|
||||
size_t n = 0, nlame = 0;
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
if(ns->resolved) continue;
|
||||
n++;
|
||||
if(ns->lame) nlame++;
|
||||
}
|
||||
if(alllame && n == nlame) *alllame = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -694,6 +701,10 @@ int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen,
|
||||
else ns->got4 = 1;
|
||||
if(ns->got4 && ns->got6)
|
||||
ns->resolved = 1;
|
||||
} else {
|
||||
if(addr_is_ip6(addr, addrlen))
|
||||
ns->done_pside6 = 1;
|
||||
else ns->done_pside4 = 1;
|
||||
}
|
||||
log_assert(ns->port>0);
|
||||
return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame,
|
||||
|
@ -330,9 +330,10 @@ void delegpt_add_unused_targets(struct delegpt* dp);
|
||||
/**
|
||||
* Count number of missing targets. These are ns names with no resolved flag.
|
||||
* @param dp: delegation point.
|
||||
* @param alllame: if set, check if all the missing targets are lame.
|
||||
* @return number of missing targets (or 0).
|
||||
*/
|
||||
size_t delegpt_count_missing_targets(struct delegpt* dp);
|
||||
size_t delegpt_count_missing_targets(struct delegpt* dp, int* alllame);
|
||||
|
||||
/** count total number of targets in dp */
|
||||
size_t delegpt_count_targets(struct delegpt* dp);
|
||||
|
@ -367,6 +367,7 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
|
||||
struct sock_list* blacklist, time_t prefetch)
|
||||
{
|
||||
int got_num = 0, low_rtt = 0, swap_to_front, rtt_band = RTT_BAND, nth;
|
||||
int alllame = 0;
|
||||
size_t num_results;
|
||||
struct delegpt_addr* a, *n, *prev=NULL;
|
||||
|
||||
@ -376,7 +377,10 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
|
||||
if(got_num == 0)
|
||||
return 0;
|
||||
if(low_rtt >= USEFUL_SERVER_TOP_TIMEOUT &&
|
||||
(delegpt_count_missing_targets(dp) > 0 || open_target > 0)) {
|
||||
/* If all missing (or not fully resolved) targets are lame,
|
||||
* then use the remaining lame address. */
|
||||
((delegpt_count_missing_targets(dp, &alllame) > 0 && !alllame) ||
|
||||
open_target > 0)) {
|
||||
verbose(VERB_ALGO, "Bad choices, trying to get more choice");
|
||||
return 0; /* we want more choice. The best choice is a bad one.
|
||||
return 0 to force the caller to fetch more */
|
||||
|
@ -253,8 +253,9 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
|
||||
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))
|
||||
(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 */
|
||||
@ -678,15 +679,20 @@ is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
|
||||
iq->qchase.qclass) != NULL;
|
||||
}
|
||||
|
||||
/** create target count structure for this query */
|
||||
/**
|
||||
* Create target count structure for this query. This is always explicitly
|
||||
* created for the parent query.
|
||||
*/
|
||||
static void
|
||||
target_count_create(struct iter_qstate* iq)
|
||||
{
|
||||
if(!iq->target_count) {
|
||||
iq->target_count = (int*)calloc(3, sizeof(int));
|
||||
iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int));
|
||||
/* if calloc fails we simply do not track this number */
|
||||
if(iq->target_count)
|
||||
iq->target_count[0] = 1;
|
||||
if(iq->target_count) {
|
||||
iq->target_count[TARGET_COUNT_REF] = 1;
|
||||
iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -695,7 +701,7 @@ target_count_increase(struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[1] += num;
|
||||
iq->target_count[TARGET_COUNT_QUERIES] += num;
|
||||
iq->dp_target_count++;
|
||||
}
|
||||
|
||||
@ -704,7 +710,7 @@ target_count_increase_nx(struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[2] += num;
|
||||
iq->target_count[TARGET_COUNT_NX] += num;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -799,8 +805,10 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
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 */
|
||||
if(iq->target_count) {
|
||||
iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */
|
||||
subiq->nxns_dp = iq->nxns_dp;
|
||||
}
|
||||
subiq->dp_target_count = 0;
|
||||
subiq->num_current_queries = 0;
|
||||
subiq->depth = iq->depth+1;
|
||||
@ -1832,7 +1840,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
int toget = 0;
|
||||
|
||||
iter_mark_cycle_targets(qstate, iq->dp);
|
||||
missing = (int)delegpt_count_missing_targets(iq->dp);
|
||||
missing = (int)delegpt_count_missing_targets(iq->dp, NULL);
|
||||
log_assert(maxtargets != 0); /* that would not be useful */
|
||||
|
||||
/* Generate target requests. Basically, any missing targets
|
||||
@ -1851,11 +1859,12 @@ 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) {
|
||||
iq->target_count[TARGET_COUNT_QUERIES] > 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]);
|
||||
"number of glue fetches %d", s,
|
||||
iq->target_count[TARGET_COUNT_QUERIES]);
|
||||
return 0;
|
||||
}
|
||||
if(iq->dp_target_count > MAX_DP_TARGET_COUNT) {
|
||||
@ -1883,7 +1892,9 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ie->supports_ipv6 && !ns->got6) {
|
||||
if(ie->supports_ipv6 &&
|
||||
((ns->lame && !ns->done_pside6) ||
|
||||
(!ns->lame && !ns->got6))) {
|
||||
/* Send the AAAA request. */
|
||||
if(!generate_target_query(qstate, iq, id,
|
||||
ns->name, ns->namelen,
|
||||
@ -1896,7 +1907,9 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
query_count++;
|
||||
}
|
||||
/* Send the A request. */
|
||||
if(ie->supports_ipv4 && !ns->got4) {
|
||||
if(ie->supports_ipv4 &&
|
||||
((ns->lame && !ns->done_pside4) ||
|
||||
(!ns->lame && !ns->got4))) {
|
||||
if(!generate_target_query(qstate, iq, id,
|
||||
ns->name, ns->namelen,
|
||||
LDNS_RR_TYPE_A, iq->qchase.qclass)) {
|
||||
@ -2006,7 +2019,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return next_state(iq, QUERYTARGETS_STATE);
|
||||
}
|
||||
/* query for an extra name added by the parent-NS record */
|
||||
if(delegpt_count_missing_targets(iq->dp) > 0) {
|
||||
if(delegpt_count_missing_targets(iq->dp, NULL) > 0) {
|
||||
int qs = 0;
|
||||
verbose(VERB_ALGO, "try parent-side target name");
|
||||
if(!query_for_targets(qstate, iq, ie, id, 1, &qs)) {
|
||||
@ -2027,11 +2040,12 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
if(iq->depth > 0 && iq->target_count &&
|
||||
iq->target_count[1] > MAX_TARGET_COUNT) {
|
||||
iq->target_count[TARGET_COUNT_QUERIES] > 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]);
|
||||
"number of glue fetches %d", s,
|
||||
iq->target_count[TARGET_COUNT_QUERIES]);
|
||||
errinf(qstate, "exceeded the maximum number of glue fetches");
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
@ -2211,12 +2225,112 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
errinf(qstate, "exceeded the maximum number of sends");
|
||||
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);
|
||||
/* Check if we reached MAX_TARGET_NX limit without a fallback activation. */
|
||||
if(iq->target_count && !*iq->nxns_dp &&
|
||||
iq->target_count[TARGET_COUNT_NX] > MAX_TARGET_NX) {
|
||||
struct delegpt_ns* ns;
|
||||
/* If we can wait for resolution, do so. */
|
||||
if(iq->num_target_queries>0 || iq->num_current_queries>0) {
|
||||
if(iq->num_target_queries>0 && iq->num_current_queries>0) {
|
||||
verbose(VERB_ALGO, "waiting for %d targets to "
|
||||
"resolve or %d outstanding queries to "
|
||||
"respond", iq->num_target_queries,
|
||||
iq->num_current_queries);
|
||||
qstate->ext_state[id] = module_wait_reply;
|
||||
} else if(iq->num_target_queries>0) {
|
||||
verbose(VERB_ALGO, "waiting for %d targets to "
|
||||
"resolve", iq->num_target_queries);
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
} else {
|
||||
verbose(VERB_ALGO, "waiting for %d "
|
||||
"outstanding queries to respond",
|
||||
iq->num_current_queries);
|
||||
qstate->ext_state[id] = module_wait_reply;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_ALGO, "request has exceeded the maximum "
|
||||
"number of nxdomain nameserver lookups (%d) with %d",
|
||||
MAX_TARGET_NX, iq->target_count[TARGET_COUNT_NX]);
|
||||
/* Check for dp because we require one below */
|
||||
if(!iq->dp) {
|
||||
verbose(VERB_QUERY, "Failed to get a delegation, "
|
||||
"giving up");
|
||||
errinf(qstate, "failed to get a delegation (eg. prime "
|
||||
"failure)");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
/* We reached the limit but we already have parent side
|
||||
* information; stop resolution */
|
||||
if(iq->dp->has_parent_side_NS) {
|
||||
errinf(qstate, "exceeded the maximum nameserver nxdomains");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
/* Mark all the current NSes as resolved to allow for parent
|
||||
* fallback */
|
||||
for(ns=iq->dp->nslist; ns; ns=ns->next) {
|
||||
ns->resolved = 1;
|
||||
}
|
||||
/* Note the delegation point that triggered the NXNS fallback;
|
||||
* no reason for shared queries to keep trying there.
|
||||
* This also marks the fallback activation. */
|
||||
*iq->nxns_dp = malloc(iq->dp->namelen);
|
||||
if(!*iq->nxns_dp) {
|
||||
errinf(qstate, "exceeded the maximum nameserver nxdomains");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
memcpy(*iq->nxns_dp, iq->dp->name, iq->dp->namelen);
|
||||
} else if(iq->target_count && *iq->nxns_dp) {
|
||||
/* Handle the NXNS fallback case. */
|
||||
/* If we can wait for resolution, do so. */
|
||||
if(iq->num_target_queries>0 || iq->num_current_queries>0) {
|
||||
if(iq->num_target_queries>0 && iq->num_current_queries>0) {
|
||||
verbose(VERB_ALGO, "waiting for %d targets to "
|
||||
"resolve or %d outstanding queries to "
|
||||
"respond", iq->num_target_queries,
|
||||
iq->num_current_queries);
|
||||
qstate->ext_state[id] = module_wait_reply;
|
||||
} else if(iq->num_target_queries>0) {
|
||||
verbose(VERB_ALGO, "waiting for %d targets to "
|
||||
"resolve", iq->num_target_queries);
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
} else {
|
||||
verbose(VERB_ALGO, "waiting for %d "
|
||||
"outstanding queries to respond",
|
||||
iq->num_current_queries);
|
||||
qstate->ext_state[id] = module_wait_reply;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* Check for dp because we require one below */
|
||||
if(!iq->dp) {
|
||||
verbose(VERB_QUERY, "Failed to get a delegation, "
|
||||
"giving up");
|
||||
errinf(qstate, "failed to get a delegation (eg. prime "
|
||||
"failure)");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
|
||||
if(iq->target_count[TARGET_COUNT_NX] > MAX_TARGET_NX_FALLBACK) {
|
||||
verbose(VERB_ALGO, "request has exceeded the maximum "
|
||||
"number of fallback nxdomain nameserver "
|
||||
"lookups (%d) with %d", MAX_TARGET_NX_FALLBACK,
|
||||
iq->target_count[TARGET_COUNT_NX]);
|
||||
errinf(qstate, "exceeded the maximum nameserver nxdomains");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
|
||||
if(!iq->dp->has_parent_side_NS) {
|
||||
struct delegpt_ns* ns;
|
||||
if(!dname_canonical_compare(*iq->nxns_dp, iq->dp->name)) {
|
||||
verbose(VERB_ALGO, "this delegation point "
|
||||
"initiated the fallback, marking the "
|
||||
"nslist as resolved");
|
||||
for(ns=iq->dp->nslist; ns; ns=ns->next) {
|
||||
ns->resolved = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure we have a delegation point, otherwise priming failed
|
||||
@ -2434,7 +2548,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* 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->target_count || iq->target_count[TARGET_COUNT_NX]==0)
|
||||
&& iq->sent_count < TARGET_FETCH_STOP) {
|
||||
tf_policy = ie->target_fetch_policy[iq->depth];
|
||||
}
|
||||
@ -2523,9 +2637,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
|
||||
/* Select the next usable target, filtering out unsuitable targets. */
|
||||
target = iter_server_selection(ie, qstate->env, iq->dp,
|
||||
target = iter_server_selection(ie, qstate->env, iq->dp,
|
||||
iq->dp->name, iq->dp->namelen, iq->qchase.qtype,
|
||||
&iq->dnssec_lame_query, &iq->chase_to_rd,
|
||||
&iq->dnssec_lame_query, &iq->chase_to_rd,
|
||||
iq->num_target_queries, qstate->blacklist,
|
||||
qstate->prefetch_leeway);
|
||||
|
||||
@ -2544,7 +2658,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* If there is nothing to wait for, then we need
|
||||
* to distinguish between generating (a) new target
|
||||
* query, or failing. */
|
||||
if(delegpt_count_missing_targets(iq->dp) > 0) {
|
||||
if(delegpt_count_missing_targets(iq->dp, NULL) > 0) {
|
||||
int qs = 0;
|
||||
verbose(VERB_ALGO, "querying for next "
|
||||
"missing target");
|
||||
@ -2556,7 +2670,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
if(qs == 0 &&
|
||||
delegpt_count_missing_targets(iq->dp) == 0){
|
||||
delegpt_count_missing_targets(iq->dp, NULL) == 0){
|
||||
/* it looked like there were missing
|
||||
* targets, but they did not turn up.
|
||||
* Try the bad choices again (if any),
|
||||
@ -4005,8 +4119,11 @@ 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)
|
||||
if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) {
|
||||
free(iq->target_count);
|
||||
if(*iq->nxns_dp) free(*iq->nxns_dp);
|
||||
free(iq->nxns_dp);
|
||||
}
|
||||
iq->num_current_queries = 0;
|
||||
}
|
||||
qstate->minfo[id] = NULL;
|
||||
|
@ -60,6 +60,9 @@ struct rbtree_type;
|
||||
/** max number of nxdomains allowed for target lookups for a query and
|
||||
* its subqueries */
|
||||
#define MAX_TARGET_NX 5
|
||||
/** max number of nxdomains allowed for target lookups for a query and
|
||||
* its subqueries when fallback has kicked in */
|
||||
#define MAX_TARGET_NX_FALLBACK (MAX_TARGET_NX*2)
|
||||
/** max number of query restarts. Determines max number of CNAME chain. */
|
||||
#define MAX_RESTART_COUNT 11
|
||||
/** max number of referrals. Makes sure resolver does not run away */
|
||||
@ -217,6 +220,21 @@ enum iter_state {
|
||||
FINISHED_STATE
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared counters for queries.
|
||||
*/
|
||||
enum target_count_variables {
|
||||
/** Reference count for the shared iter_qstate->target_count. */
|
||||
TARGET_COUNT_REF = 0,
|
||||
/** Number of target queries spawned for the query and subqueries. */
|
||||
TARGET_COUNT_QUERIES,
|
||||
/** Number of nxdomain responses encountered. */
|
||||
TARGET_COUNT_NX,
|
||||
|
||||
/** This should stay last here, it is used for the allocation */
|
||||
TARGET_COUNT_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* Per query state for the iterator module.
|
||||
*/
|
||||
@ -310,15 +328,20 @@ 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.
|
||||
* in [2] the number of nxdomains is counted. */
|
||||
/** malloced-array shared with this query and its subqueries. It keeps
|
||||
* track of the defined enum target_count_variables counters. */
|
||||
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;
|
||||
|
||||
/** Delegation point that triggered the NXNS fallback; shared with
|
||||
* this query and its subqueries, count-referenced by the reference
|
||||
* counter in target_count.
|
||||
* This also marks the fallback activation. */
|
||||
uint8_t** nxns_dp;
|
||||
|
||||
/** if true, already tested for ratelimiting and passed the test */
|
||||
int ratelimit_ok;
|
||||
|
||||
|
380
testdata/iter_nxns_fallback.rpl
vendored
Normal file
380
testdata/iter_nxns_fallback.rpl
vendored
Normal file
@ -0,0 +1,380 @@
|
||||
; Check if fallback to the parent side works when MAX_TARGET_NX is reached.
|
||||
|
||||
server:
|
||||
module-config: "iterator"
|
||||
trust-anchor-signaling: no
|
||||
target-fetch-policy: "0 0 0 0 0"
|
||||
verbosity: 3
|
||||
access-control: 127.0.0.1 allow_snoop
|
||||
qname-minimisation: no
|
||||
minimal-responses: no
|
||||
rrset-roundrobin: no
|
||||
|
||||
stub-zone:
|
||||
name: "."
|
||||
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test the NXNS fallback
|
||||
|
||||
; K.ROOT-SERVERS.NET.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 193.0.14.129
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
. IN NS
|
||||
SECTION ANSWER
|
||||
. IN NS K.ROOT-SERVERS.NET.
|
||||
SECTION ADDITIONAL
|
||||
K.ROOT-SERVERS.NET. IN A 193.0.14.129
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype subdomain
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode subdomain
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
nonexistant.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; a.gtld-servers.net.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 192.5.6.30
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
com. IN NS
|
||||
SECTION ANSWER
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype subdomain
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 10 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode subdomain
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
nonexistant.com. IN A
|
||||
SECTION AUTHORITY
|
||||
nonexistant.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 10 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
example.com. IN NS ns9.nonexistant.com.
|
||||
example.com. IN NS ns10.nonexistant.com.
|
||||
example.com. IN NS ns11.nonexistant.com.
|
||||
example.com. IN NS ns12.nonexistant.com.
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
ns.example.com. IN A
|
||||
SECTION ANSWER
|
||||
ns.example.com. 10 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
ns.example.com. IN AAAA
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode subdomain
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NXDOMAIN
|
||||
SECTION QUESTION
|
||||
nonexistant.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
a.example.com. IN A
|
||||
SECTION ANSWER
|
||||
a.example.com. IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
example.com. IN NS ns9.nonexistant.com.
|
||||
example.com. IN NS ns10.nonexistant.com.
|
||||
example.com. IN NS ns11.nonexistant.com.
|
||||
example.com. IN NS ns12.nonexistant.com.
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
b.example.com. IN A
|
||||
SECTION ANSWER
|
||||
b.example.com. IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
example.com. IN NS ns9.nonexistant.com.
|
||||
example.com. IN NS ns10.nonexistant.com.
|
||||
example.com. IN NS ns11.nonexistant.com.
|
||||
example.com. IN NS ns12.nonexistant.com.
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
c.example.com. IN A
|
||||
SECTION ANSWER
|
||||
c.example.com. IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
example.com. IN NS ns9.nonexistant.com.
|
||||
example.com. IN NS ns10.nonexistant.com.
|
||||
example.com. IN NS ns11.nonexistant.com.
|
||||
example.com. IN NS ns12.nonexistant.com.
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
d.example.com. IN A
|
||||
SECTION ANSWER
|
||||
d.example.com. IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
example.com. IN NS ns9.nonexistant.com.
|
||||
example.com. IN NS ns10.nonexistant.com.
|
||||
example.com. IN NS ns11.nonexistant.com.
|
||||
example.com. IN NS ns12.nonexistant.com.
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
a.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; This was resolved by asking the parent side nameservers
|
||||
STEP 2 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
a.example.com. IN A
|
||||
SECTION ANSWER
|
||||
a.example.com. IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
example.com. IN NS ns9.nonexistant.com.
|
||||
example.com. IN NS ns10.nonexistant.com.
|
||||
example.com. IN NS ns11.nonexistant.com.
|
||||
example.com. IN NS ns12.nonexistant.com.
|
||||
ENTRY_END
|
||||
|
||||
; The child side nameservers are now known to Unbound
|
||||
|
||||
; Query again, the child server nameservers will be asked now
|
||||
STEP 3 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
b.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; This was resolved by falling back to the parent side nameservers
|
||||
STEP 4 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
b.example.com. IN A
|
||||
SECTION ANSWER
|
||||
b.example.com. IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
example.com. IN NS ns9.nonexistant.com.
|
||||
example.com. IN NS ns10.nonexistant.com.
|
||||
example.com. IN NS ns11.nonexistant.com.
|
||||
example.com. IN NS ns12.nonexistant.com.
|
||||
ENTRY_END
|
||||
|
||||
; Query a third time, this will get the cached NXDOMAINs (no NX counter for
|
||||
; those) and will go to the parent as a last resort. This query will test that
|
||||
; we will not have resolution for the lame(parent side) addresses that could
|
||||
; raise the NX counter because of no address addition to the delegation point
|
||||
; (the same addresses are already there).
|
||||
STEP 5 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
c.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; This was resolved by going back to the parent side nameservers (child side
|
||||
; was exhausted from cache and queries < MAX_TARGET_NX).
|
||||
STEP 6 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
c.example.com. IN A
|
||||
SECTION ANSWER
|
||||
c.example.com. IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
example.com. IN NS ns9.nonexistant.com.
|
||||
example.com. IN NS ns10.nonexistant.com.
|
||||
example.com. IN NS ns11.nonexistant.com.
|
||||
example.com. IN NS ns12.nonexistant.com.
|
||||
ENTRY_END
|
||||
|
||||
; Allow for the nameserver glue to expire
|
||||
STEP 10 TIME_PASSES ELAPSE 11
|
||||
|
||||
; Query again for the parent side fallback
|
||||
STEP 11 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
d.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; This was resolved by falling back to the parent side nameservers
|
||||
STEP 12 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
d.example.com. IN A
|
||||
SECTION ANSWER
|
||||
d.example.com. IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
example.com. IN NS ns9.nonexistant.com.
|
||||
example.com. IN NS ns10.nonexistant.com.
|
||||
example.com. IN NS ns11.nonexistant.com.
|
||||
example.com. IN NS ns12.nonexistant.com.
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
118
testdata/iter_nxns_parentside.rpl
vendored
Normal file
118
testdata/iter_nxns_parentside.rpl
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
; Check if the NXNS fallback to the parent side does not mess with normal
|
||||
; parent side resolution. Parent side resolution should SERVFAIL when reaching
|
||||
; the MAX_TARGET_NX limit.
|
||||
|
||||
server:
|
||||
module-config: "iterator"
|
||||
trust-anchor-signaling: no
|
||||
target-fetch-policy: "0 0 0 0 0"
|
||||
verbosity: 3
|
||||
access-control: 127.0.0.1 allow_snoop
|
||||
qname-minimisation: no
|
||||
minimal-responses: no
|
||||
rrset-roundrobin: no
|
||||
|
||||
stub-zone:
|
||||
name: "."
|
||||
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test that the NXNS fallback does not mess with parent side resolution
|
||||
|
||||
; K.ROOT-SERVERS.NET.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 193.0.14.129
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
. IN NS
|
||||
SECTION ANSWER
|
||||
. IN NS K.ROOT-SERVERS.NET.
|
||||
SECTION ADDITIONAL
|
||||
K.ROOT-SERVERS.NET. IN A 193.0.14.129
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype subdomain
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode subdomain
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
nonexistant.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; a.gtld-servers.net.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 192.5.6.30
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
com. IN NS
|
||||
SECTION ANSWER
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype subdomain
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns1.nonexistant.com.
|
||||
example.com. IN NS ns2.nonexistant.com.
|
||||
example.com. IN NS ns3.nonexistant.com.
|
||||
example.com. IN NS ns4.nonexistant.com.
|
||||
example.com. IN NS ns5.nonexistant.com.
|
||||
example.com. IN NS ns6.nonexistant.com.
|
||||
example.com. IN NS ns7.nonexistant.com.
|
||||
example.com. IN NS ns8.nonexistant.com.
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode subdomain
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NXDOMAIN
|
||||
SECTION QUESTION
|
||||
nonexistant.com. IN A
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
a.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
STEP 2 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA SERVFAIL
|
||||
SECTION QUESTION
|
||||
a.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
Loading…
Reference in New Issue
Block a user