summaryrefslogtreecommitdiff
path: root/iterator
diff options
context:
space:
mode:
Diffstat (limited to 'iterator')
-rw-r--r--iterator/iter_delegpt.c29
-rw-r--r--iterator/iter_delegpt.h30
-rw-r--r--iterator/iter_fwd.c14
-rw-r--r--iterator/iter_fwd.h10
-rw-r--r--iterator/iter_priv.c48
-rw-r--r--iterator/iter_priv.h2
-rw-r--r--iterator/iter_scrub.c16
-rw-r--r--iterator/iter_utils.c18
-rw-r--r--iterator/iter_utils.h2
-rw-r--r--iterator/iterator.c66
10 files changed, 176 insertions, 59 deletions
diff --git a/iterator/iter_delegpt.c b/iterator/iter_delegpt.c
index d2f5d73335dc..c204ddfec745 100644
--- a/iterator/iter_delegpt.c
+++ b/iterator/iter_delegpt.c
@@ -71,7 +71,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
copy->bogus = dp->bogus;
copy->has_parent_side_NS = dp->has_parent_side_NS;
for(ns = dp->nslist; ns; ns = ns->next) {
- if(!delegpt_add_ns(copy, region, ns->name, (int)ns->lame))
+ if(!delegpt_add_ns(copy, region, ns->name, ns->lame))
return NULL;
copy->nslist->resolved = ns->resolved;
copy->nslist->got4 = ns->got4;
@@ -98,7 +98,7 @@ delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name)
int
delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
- int lame)
+ uint8_t lame)
{
struct delegpt_ns* ns;
size_t len;
@@ -119,7 +119,7 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
ns->resolved = 0;
ns->got4 = 0;
ns->got6 = 0;
- ns->lame = (uint8_t)lame;
+ ns->lame = lame;
ns->done_pside4 = 0;
ns->done_pside6 = 0;
return ns->name != 0;
@@ -156,7 +156,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, int bogus, int lame)
+ socklen_t addrlen, uint8_t bogus, uint8_t lame)
{
struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen);
log_assert(!dp->dp_type_mlc);
@@ -176,8 +176,8 @@ delegpt_add_target(struct delegpt* dp, struct regional* region,
int
delegpt_add_addr(struct delegpt* dp, struct regional* region,
- struct sockaddr_storage* addr, socklen_t addrlen, int bogus,
- int lame)
+ struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus,
+ uint8_t lame)
{
struct delegpt_addr* a;
log_assert(!dp->dp_type_mlc);
@@ -204,6 +204,7 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region,
a->attempts = 0;
a->bogus = bogus;
a->lame = lame;
+ a->dnsseclame = 0;
return 1;
}
@@ -376,7 +377,7 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
int
delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
- struct ub_packed_rrset_key* ns_rrset, int lame)
+ struct ub_packed_rrset_key* ns_rrset, uint8_t lame)
{
struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
ns_rrset->entry.data;
@@ -398,7 +399,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, int lame)
+ struct ub_packed_rrset_key* ak, uint8_t lame)
{
struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
size_t i;
@@ -422,7 +423,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, int lame)
+ struct ub_packed_rrset_key* ak, uint8_t lame)
{
struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
size_t i;
@@ -446,7 +447,7 @@ 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, int lame)
+ struct ub_packed_rrset_key* rrset, uint8_t lame)
{
if(!rrset)
return 1;
@@ -548,7 +549,7 @@ int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name)
return (dp->name != NULL);
}
-int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, int lame)
+int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame)
{
struct delegpt_ns* ns;
size_t len;
@@ -579,7 +580,7 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, int lame)
}
int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
- socklen_t addrlen, int bogus, int lame)
+ socklen_t addrlen, uint8_t bogus, uint8_t lame)
{
struct delegpt_addr* a;
log_assert(dp->dp_type_mlc);
@@ -605,11 +606,13 @@ int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
a->attempts = 0;
a->bogus = bogus;
a->lame = lame;
+ a->dnsseclame = 0;
return 1;
}
int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen,
- struct sockaddr_storage* addr, socklen_t addrlen, int bogus, int lame)
+ struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus,
+ uint8_t lame)
{
struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen);
log_assert(dp->dp_type_mlc);
diff --git a/iterator/iter_delegpt.h b/iterator/iter_delegpt.h
index 7728031aa999..d7e0767d62eb 100644
--- a/iterator/iter_delegpt.h
+++ b/iterator/iter_delegpt.h
@@ -140,9 +140,13 @@ struct delegpt_addr {
int sel_rtt;
/** if true, the A or AAAA RR was bogus, so this address is bad.
* Also check the dp->bogus to see if everything is bogus. */
- int bogus;
+ uint8_t bogus;
/** if true, this address is dispreferred: it is a lame IP address */
- int lame;
+ uint8_t lame;
+ /** if the address is dnsseclame, but this cannot be cached, this
+ * option is useful to mark the address dnsseclame.
+ * This value is not copied in addr-copy and dp-copy. */
+ uint8_t dnsseclame;
};
/**
@@ -179,7 +183,7 @@ int delegpt_set_name(struct delegpt* dp, struct regional* regional,
* @return false on error.
*/
int delegpt_add_ns(struct delegpt* dp, struct regional* regional,
- uint8_t* name, int lame);
+ uint8_t* name, uint8_t lame);
/**
* Add NS rrset; calls add_ns repeatedly.
@@ -190,7 +194,7 @@ int delegpt_add_ns(struct delegpt* dp, struct regional* regional,
* @return 0 on alloc error.
*/
int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
- struct ub_packed_rrset_key* ns_rrset, int lame);
+ struct ub_packed_rrset_key* ns_rrset, uint8_t lame);
/**
* Add target address to the delegation point.
@@ -207,7 +211,7 @@ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
*/
int delegpt_add_target(struct delegpt* dp, struct regional* regional,
uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
- socklen_t addrlen, int bogus, int lame);
+ socklen_t addrlen, uint8_t bogus, uint8_t lame);
/**
* Add A RRset to delegpt.
@@ -218,7 +222,7 @@ int delegpt_add_target(struct delegpt* dp, struct regional* regional,
* @return 0 on alloc error.
*/
int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional,
- struct ub_packed_rrset_key* rrset, int lame);
+ struct ub_packed_rrset_key* rrset, uint8_t lame);
/**
* Add AAAA RRset to delegpt.
@@ -229,7 +233,7 @@ int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional,
* @return 0 on alloc error.
*/
int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional,
- struct ub_packed_rrset_key* rrset, int lame);
+ struct ub_packed_rrset_key* rrset, uint8_t lame);
/**
* Add any RRset to delegpt.
@@ -241,7 +245,7 @@ int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional,
* @return 0 on alloc error.
*/
int delegpt_add_rrset(struct delegpt* dp, struct regional* regional,
- struct ub_packed_rrset_key* rrset, int lame);
+ struct ub_packed_rrset_key* rrset, uint8_t lame);
/**
* Add address to the delegation point. No servername is associated or checked.
@@ -254,7 +258,8 @@ int delegpt_add_rrset(struct delegpt* dp, struct regional* regional,
* @return false on error.
*/
int delegpt_add_addr(struct delegpt* dp, struct regional* regional,
- struct sockaddr_storage* addr, socklen_t addrlen, int bogus, int lame);
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t bogus, uint8_t lame);
/**
* Find NS record in name list of delegation point.
@@ -376,7 +381,7 @@ int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name);
* @param lame: the name is lame, disprefer.
* @return false on error.
*/
-int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, int lame);
+int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame);
/**
* add an address to a malloced delegation point.
@@ -388,7 +393,7 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, int lame);
* @return false on error.
*/
int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
- socklen_t addrlen, int bogus, int lame);
+ socklen_t addrlen, uint8_t bogus, uint8_t lame);
/**
* Add target address to the delegation point.
@@ -403,7 +408,8 @@ int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
* @return false on error.
*/
int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen,
- struct sockaddr_storage* addr, socklen_t addrlen, int bogus, int lame);
+ struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus,
+ uint8_t lame);
/** get memory in use by dp */
size_t delegpt_get_mem(struct delegpt* dp);
diff --git a/iterator/iter_fwd.c b/iterator/iter_fwd.c
index 0b3b6525c26b..b84e5eff60d0 100644
--- a/iterator/iter_fwd.c
+++ b/iterator/iter_fwd.c
@@ -325,6 +325,20 @@ forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg)
}
struct delegpt*
+forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
+{
+ rbnode_t* res = NULL;
+ struct iter_forward_zone key;
+ key.node.key = &key;
+ key.dclass = qclass;
+ key.name = qname;
+ key.namelabs = dname_count_size_labels(qname, &key.namelen);
+ res = rbtree_search(fwd->tree, &key);
+ if(res) return ((struct iter_forward_zone*)res)->dp;
+ return NULL;
+}
+
+struct delegpt*
forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
{
/* lookup the forward zone in the tree */
diff --git a/iterator/iter_fwd.h b/iterator/iter_fwd.h
index dbb84f226126..62408ad52e2b 100644
--- a/iterator/iter_fwd.h
+++ b/iterator/iter_fwd.h
@@ -105,6 +105,16 @@ void forwards_delete(struct iter_forwards* fwd);
int forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg);
/**
+ * Find forward zone exactly by name
+ * @param fwd: forward storage.
+ * @param qname: The qname of the query.
+ * @param qclass: The qclass of the query.
+ * @return: A delegation point or null.
+ */
+struct delegpt* forwards_find(struct iter_forwards* fwd, uint8_t* qname,
+ uint16_t qclass);
+
+/**
* Find forward zone information
* For this qname/qclass find forward zone information, returns delegation
* point with server names and addresses, or NULL if no forwarding is needed.
diff --git a/iterator/iter_priv.c b/iterator/iter_priv.c
index db7dbe5faa65..572f701f350d 100644
--- a/iterator/iter_priv.c
+++ b/iterator/iter_priv.c
@@ -208,6 +208,28 @@ size_t priv_get_mem(struct iter_priv* priv)
return sizeof(*priv) + regional_get_mem(priv->region);
}
+/** remove RR from msgparse RRset, return true if rrset is entirely bad */
+static int
+remove_rr(const char* str, ldns_buffer* pkt, struct rrset_parse* rrset,
+ struct rr_parse* prev, struct rr_parse** rr, struct sockaddr_storage* addr, socklen_t addrlen)
+{
+ if(verbosity >= VERB_QUERY && rrset->dname_len <= LDNS_MAX_DOMAINLEN && str) {
+ uint8_t buf[LDNS_MAX_DOMAINLEN+1];
+ dname_pkt_copy(pkt, buf, rrset->dname);
+ log_name_addr(VERB_QUERY, str, buf, addr, addrlen);
+ }
+ if(prev)
+ prev->next = (*rr)->next;
+ else rrset->rr_first = (*rr)->next;
+ if(rrset->rr_last == *rr)
+ rrset->rr_last = prev;
+ rrset->rr_count --;
+ rrset->size -= (*rr)->size;
+ /* rr struct still exists, but is unlinked, so that in the for loop
+ * the rr->next works fine to continue. */
+ return rrset->rr_count == 0;
+}
+
int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt,
struct rrset_parse* rrset)
{
@@ -221,7 +243,7 @@ int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt,
} else {
/* so its a public name, check the address */
socklen_t len;
- struct rr_parse* rr;
+ struct rr_parse* rr, *prev = NULL;
if(rrset->type == LDNS_RR_TYPE_A) {
struct sockaddr_storage addr;
struct sockaddr_in sa;
@@ -232,13 +254,19 @@ int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt,
sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
for(rr = rrset->rr_first; rr; rr = rr->next) {
if(ldns_read_uint16(rr->ttl_data+4)
- != INET_SIZE)
+ != INET_SIZE) {
+ prev = rr;
continue;
+ }
memmove(&sa.sin_addr, rr->ttl_data+4+2,
INET_SIZE);
memmove(&addr, &sa, len);
- if(priv_lookup_addr(priv, &addr, len))
- return 1;
+ if(priv_lookup_addr(priv, &addr, len)) {
+ if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len))
+ return 1;
+ continue;
+ }
+ prev = rr;
}
} else if(rrset->type == LDNS_RR_TYPE_AAAA) {
struct sockaddr_storage addr;
@@ -249,13 +277,19 @@ int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt,
sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
for(rr = rrset->rr_first; rr; rr = rr->next) {
if(ldns_read_uint16(rr->ttl_data+4)
- != INET6_SIZE)
+ != INET6_SIZE) {
+ prev = rr;
continue;
+ }
memmove(&sa.sin6_addr, rr->ttl_data+4+2,
INET6_SIZE);
memmove(&addr, &sa, len);
- if(priv_lookup_addr(priv, &addr, len))
- return 1;
+ if(priv_lookup_addr(priv, &addr, len)) {
+ if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len))
+ return 1;
+ continue;
+ }
+ prev = rr;
}
}
}
diff --git a/iterator/iter_priv.h b/iterator/iter_priv.h
index f6264f8d0c9b..e6e51c159b09 100644
--- a/iterator/iter_priv.h
+++ b/iterator/iter_priv.h
@@ -92,6 +92,8 @@ int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg);
/**
* See if rrset is bad.
+ * Will remove individual RRs that are bad (if possible) to
+ * sanitize the RRset without removing it completely.
* @param priv: structure for private address storage.
* @param pkt: packet to decompress rrset name in.
* @param rrset: the rrset to examine, A or AAAA.
diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c
index 6147c96a9e37..a2407c27c840 100644
--- a/iterator/iter_scrub.c
+++ b/iterator/iter_scrub.c
@@ -62,7 +62,7 @@ static void
remove_rrset(const char* str, ldns_buffer* pkt, struct msg_parse* msg,
struct rrset_parse* prev, struct rrset_parse** rrset)
{
- if(verbosity >= VERB_QUERY
+ if(verbosity >= VERB_QUERY && str
&& (*rrset)->dname_len <= LDNS_MAX_DOMAINLEN) {
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
dname_pkt_copy(pkt, buf, (*rrset)->dname);
@@ -520,7 +520,7 @@ store_rrset(ldns_buffer* pkt, struct msg_parse* msg, struct module_env* env,
struct ub_packed_rrset_key* k;
struct packed_rrset_data* d;
struct rrset_ref ref;
- uint32_t now = *env->now;
+ time_t now = *env->now;
k = alloc_special_obtain(env->alloc);
if(!k)
@@ -646,14 +646,16 @@ scrub_sanitize(ldns_buffer* pkt, struct msg_parse* msg,
/* remove private addresses */
if( (rrset->type == LDNS_RR_TYPE_A ||
- rrset->type == LDNS_RR_TYPE_AAAA) &&
- priv_rrset_bad(ie->priv, pkt, rrset)) {
+ rrset->type == LDNS_RR_TYPE_AAAA)) {
/* do not set servfail since this leads to too
* many drops of other people using rfc1918 space */
- remove_rrset("sanitize: removing public name with "
- "private address", pkt, msg, prev, &rrset);
- continue;
+ /* also do not remove entire rrset, unless all records
+ * in it are bad */
+ if(priv_rrset_bad(ie->priv, pkt, rrset)) {
+ remove_rrset(NULL, pkt, msg, prev, &rrset);
+ continue;
+ }
}
/* skip DNAME records -- they will always be followed by a
diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c
index a500c75e786a..28f7dc2415c1 100644
--- a/iterator/iter_utils.c
+++ b/iterator/iter_utils.c
@@ -177,7 +177,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
*/
static int
iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
- uint8_t* name, size_t namelen, uint16_t qtype, uint32_t now,
+ uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
struct delegpt_addr* a)
{
int rtt, lame, reclame, dnsseclame;
@@ -217,14 +217,16 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
/* select remainder from worst to best */
else if(reclame)
return rtt+USEFUL_SERVER_TOP_TIMEOUT*3; /* nonpref */
- else if(dnsseclame )
+ else if(dnsseclame || a->dnsseclame)
return rtt+USEFUL_SERVER_TOP_TIMEOUT*2; /* nonpref */
else if(a->lame)
return rtt+USEFUL_SERVER_TOP_TIMEOUT+1; /* nonpref */
else return rtt;
}
/* no server information present */
- if(a->lame)
+ if(a->dnsseclame)
+ return UNKNOWN_SERVER_NICENESS+USEFUL_SERVER_TOP_TIMEOUT*2; /* nonpref */
+ else if(a->lame)
return USEFUL_SERVER_TOP_TIMEOUT+1+UNKNOWN_SERVER_NICENESS; /* nonpref */
return UNKNOWN_SERVER_NICENESS;
}
@@ -232,7 +234,7 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
/** lookup RTT information, and also store fastest rtt (if any) */
static int
iter_fill_rtt(struct iter_env* iter_env, struct module_env* env,
- uint8_t* name, size_t namelen, uint16_t qtype, uint32_t now,
+ uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
struct delegpt* dp, int* best_rtt, struct sock_list* blacklist)
{
int got_it = 0;
@@ -261,7 +263,7 @@ iter_fill_rtt(struct iter_env* iter_env, struct module_env* env,
* returns number of best targets (or 0, no suitable targets) */
static int
iter_filter_order(struct iter_env* iter_env, struct module_env* env,
- uint8_t* name, size_t namelen, uint16_t qtype, uint32_t now,
+ uint8_t* name, size_t namelen, uint16_t qtype, time_t now,
struct delegpt* dp, int* selected_rtt, int open_target,
struct sock_list* blacklist)
{
@@ -420,7 +422,7 @@ dns_copy_msg(struct dns_msg* from, struct regional* region)
void
iter_dns_store(struct module_env* env, struct query_info* msgqinf,
- struct reply_info* msgrep, int is_referral, uint32_t leeway, int pside,
+ struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
struct regional* region)
{
if(!dns_cache_store(env, msgqinf, msgrep, is_referral, leeway,
@@ -768,7 +770,7 @@ void iter_store_parentside_neg(struct module_env* env,
/* TTL: NS from referral in iq->deleg_msg,
* or first RR from iq->response,
* or servfail5secs if !iq->response */
- uint32_t ttl = NORR_TTL;
+ time_t ttl = NORR_TTL;
struct ub_packed_rrset_key* neg;
struct packed_rrset_data* newd;
if(rep) {
@@ -798,7 +800,7 @@ void iter_store_parentside_neg(struct module_env* env,
neg->entry.hash = rrset_key_hash(&neg->rk);
newd = (struct packed_rrset_data*)regional_alloc_zero(env->scratch,
sizeof(struct packed_rrset_data) + sizeof(size_t) +
- sizeof(uint8_t*) + sizeof(uint32_t) + sizeof(uint16_t));
+ sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t));
if(!newd) {
log_err("out of memory in store_parentside_neg");
return;
diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h
index 8f5a291af678..2070622d4758 100644
--- a/iterator/iter_utils.h
+++ b/iterator/iter_utils.h
@@ -131,7 +131,7 @@ struct dns_msg* dns_copy_msg(struct dns_msg* from, struct regional* regional);
* but the query resolution can continue without cache storage.
*/
void iter_dns_store(struct module_env* env, struct query_info* qinf,
- struct reply_info* rep, int is_referral, uint32_t leeway, int pside,
+ struct reply_info* rep, int is_referral, time_t leeway, int pside,
struct regional* region);
/**
diff --git a/iterator/iterator.c b/iterator/iterator.c
index e3f058fe5122..160489331703 100644
--- a/iterator/iterator.c
+++ b/iterator/iterator.c
@@ -1409,6 +1409,35 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
return 1;
}
+/** see if last resort is possible - does config allow queries to parent */
+static int
+can_have_last_resort(struct module_env* env, struct delegpt* dp,
+ struct iter_qstate* iq)
+{
+ struct delegpt* fwddp;
+ struct iter_hints_stub* stub;
+ /* do not process a last resort (the parent side) if a stub
+ * or forward is configured, because we do not want to go 'above'
+ * the configured servers */
+ if(!dname_is_root(dp->name) && (stub = (struct iter_hints_stub*)
+ name_tree_find(&env->hints->tree, dp->name, dp->namelen,
+ dp->namelabs, iq->qchase.qclass)) &&
+ /* has_parent side is turned off for stub_first, where we
+ * are allowed to go to the parent */
+ stub->dp->has_parent_side_NS) {
+ verbose(VERB_QUERY, "configured stub servers failed -- returning SERVFAIL");
+ return 0;
+ }
+ if((fwddp = forwards_find(env->fwds, dp->name, iq->qchase.qclass)) &&
+ /* has_parent_side is turned off for forward_first, where
+ * we are allowed to go to the parent */
+ fwddp->has_parent_side_NS) {
+ verbose(VERB_QUERY, "configured forward servers failed -- returning SERVFAIL");
+ return 0;
+ }
+ return 1;
+}
+
/**
* Called by processQueryTargets when it would like extra targets to query
* but it seems to be out of options. At last resort some less appealing
@@ -1430,6 +1459,11 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
verbose(VERB_ALGO, "No more query targets, attempting last resort");
log_assert(iq->dp);
+ if(!can_have_last_resort(qstate->env, iq->dp, iq)) {
+ /* fail -- no more targets, no more hope of targets, no hope
+ * of a response. */
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) {
struct delegpt* p = hints_lookup_root(qstate->env->hints,
iq->qchase.qclass);
@@ -1439,7 +1473,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
iq->chase_flags &= ~BIT_RD; /* go to authorities */
for(ns = p->nslist; ns; ns=ns->next) {
(void)delegpt_add_ns(iq->dp, qstate->region,
- ns->name, (int)ns->lame);
+ ns->name, ns->lame);
}
for(a = p->target_list; a; a=a->next_target) {
(void)delegpt_add_addr(iq->dp, qstate->region,
@@ -1880,12 +1914,23 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
&& type != RESPONSE_TYPE_UNTYPED) {
/* a possible answer, see if it is missing DNSSEC */
/* but not when forwarding, so we dont mark fwder lame */
- /* also make sure the answer is from the zone we expected,
- * otherwise, (due to parent,child on same server), we
- * might mark the server,zone lame inappropriately */
- if(!iter_msg_has_dnssec(iq->response) &&
- iter_msg_from_zone(iq->response, iq->dp, type,
- iq->qchase.qclass)) {
+ if(!iter_msg_has_dnssec(iq->response)) {
+ /* Mark this address as dnsseclame in this dp,
+ * because that will make serverselection disprefer
+ * it, but also, once it is the only final option,
+ * use dnssec-lame-bypass if it needs to query there.*/
+ if(qstate->reply) {
+ struct delegpt_addr* a = delegpt_find_addr(
+ iq->dp, &qstate->reply->addr,
+ qstate->reply->addrlen);
+ if(a) a->dnsseclame = 1;
+ }
+ /* test the answer is from the zone we expected,
+ * otherwise, (due to parent,child on same server), we
+ * might mark the server,zone lame inappropriately */
+ if(!iter_msg_from_zone(iq->response, iq->dp, type,
+ iq->qchase.qclass))
+ qstate->reply = NULL;
type = RESPONSE_TYPE_LAME;
dnsseclame = 1;
}
@@ -2117,8 +2162,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
*qstate->env->now, dnsseclame, 0,
iq->qchase.qtype))
log_err("mark host lame: out of memory");
- } else log_err("%slame response from cache",
- dnsseclame?"DNSSEC ":"");
+ }
} else if(type == RESPONSE_TYPE_REC_LAME) {
/* Cache the LAMEness. */
verbose(VERB_DETAIL, "query response REC_LAME: "
@@ -2326,12 +2370,12 @@ processTargetResponse(struct module_qstate* qstate, int id,
rrset->rk.dname_len)) {
/* if dpns->lame then set newcname ns lame too */
if(!delegpt_add_ns(foriq->dp, forq->region,
- rrset->rk.dname, (int)dpns->lame))
+ rrset->rk.dname, dpns->lame))
log_err("out of memory adding cnamed-ns");
}
/* if dpns->lame then set the address(es) lame too */
if(!delegpt_add_rrset(foriq->dp, forq->region, rrset,
- (int)dpns->lame))
+ dpns->lame))
log_err("out of memory adding targets");
verbose(VERB_ALGO, "added target response");
delegpt_log(VERB_ALGO, foriq->dp);