- fixup tests to do additional section processing for lame replies,
since the detection needs that.
- no longer trust in query section in reply during dnssec lame detect.
+ - dnssec lameness does not make the server never ever queried, but
+ non-preferred. If no other servers exist or answer, the dnssec lame
+ server is used; the fastest dnssec lame server is chosen.
+ - added test then when trust anchor cannot be primed (nodata), the
+ insecure mode from unbound works.
22 October 2007: Wouter
- added donotquerylocalhost config option. Can be turned off for
{
int rtt;
int lame;
+ int dnsseclame;
if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) {
return -1; /* server is on the donotquery list */
}
}
/* check lameness - need zone , class info */
if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
- name, namelen, &lame, &rtt, now)) {
+ name, namelen, &lame, &dnsseclame, &rtt, now)) {
if(lame)
return -1; /* server is lame */
else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT)
return -1; /* server is unresponsive */
+ else if(dnsseclame)
+ return rtt+USEFUL_SERVER_TOP_TIMEOUT; /* nonpref */
else return rtt;
}
/* no server information present */
* 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, time_t now, struct delegpt* dp)
+ uint8_t* name, size_t namelen, time_t now, struct delegpt* dp,
+ int* best_rtt)
{
int got_num = 0, got_rtt = 0, thisrtt, swap_to_front;
struct delegpt_addr* a, *n, *prev=NULL;
a = a->next_result;
}
}
+ *best_rtt = got_rtt;
return got_num;
}
struct delegpt_addr*
iter_server_selection(struct iter_env* iter_env,
struct module_env* env, struct delegpt* dp,
- uint8_t* name, size_t namelen)
+ uint8_t* name, size_t namelen, int* dnssec_expected)
{
time_t now = time(NULL);
int sel;
+ int selrtt;
struct delegpt_addr* a, *prev;
- int num = iter_filter_order(iter_env, env, name, namelen, now, dp);
+ int num = iter_filter_order(iter_env, env, name, namelen, now, dp,
+ &selrtt);
if(num == 0)
return NULL;
+ if(selrtt >= USEFUL_SERVER_TOP_TIMEOUT)
+ *dnssec_expected = 0;
if(num == 1) {
a = dp->result_list;
if(++a->attempts < OUTBOUND_MSG_RETRY)
* @param dp: delegation point with result list.
* @param name: zone name (for lameness check).
* @param namelen: length of name.
+ * @param dnssec_expected: set to 0, if a known dnssec-lame server is selected
+ * these are not preferred, but are used as a last resort.
* @return best target or NULL if no target.
* if not null, that target is removed from the result list in the dp.
*/
struct delegpt_addr* iter_server_selection(struct iter_env* iter_env,
struct module_env* env, struct delegpt* dp, uint8_t* name,
- size_t namelen);
+ size_t namelen, int* dnssec_expected);
/**
* Allocate dns_msg from parsed msg, in regional.
/* Select the next usable target, filtering out unsuitable targets. */
target = iter_server_selection(ie, qstate->env, iq->dp,
- iq->dp->name, iq->dp->namelen);
+ iq->dp->name, iq->dp->namelen, &iq->dnssec_expected);
/* If no usable target was selected... */
if(!target) {
processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
int id)
{
+ int dnsseclame = 0;
enum response_type type;
iq->num_current_queries--;
if(iq->response == NULL) {
* 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))
+ iq->qchase.qclass)) {
type = RESPONSE_TYPE_LAME;
+ dnsseclame = 1;
+ }
}
/* handle each of the type cases */
return next_state(iq, INIT_REQUEST_STATE);
} else if(type == RESPONSE_TYPE_LAME) {
/* Cache the LAMEness. */
- verbose(VERB_DETAIL, "query response was LAME");
+ verbose(VERB_DETAIL, "query response was %sLAME",
+ dnsseclame?"DNSSEC ":"");
if(qstate->reply) {
/* need addr for lameness cache, but we may have
* gotten this from cache, so test to be sure */
if(!infra_set_lame(qstate->env->infra_cache,
&qstate->reply->addr, qstate->reply->addrlen,
- iq->dp->name, iq->dp->namelen, time(NULL)))
+ iq->dp->name, iq->dp->namelen, time(NULL),
+ dnsseclame))
log_err("mark host lame: out of memory");
- } else log_err("lame response from cache");
+ } else log_err("%slame response from cache",
+ dnsseclame?"DNSSEC ":"");
} else if(type == RESPONSE_TYPE_THROWAWAY) {
/* LAME and THROWAWAY responses are handled the same way.
* In this case, the event is just sent directly back to
struct lruhash_entry* e;
struct infra_lame_key k;
struct infra_lame_data *d;
+ int dl;
if(!host->lameness)
return 0;
k.entry.hash = hash_lameness(name, namelen);
lock_rw_unlock(&e->lock);
return 0;
}
+ dl = d->isdnsseclame;
lock_rw_unlock(&e->lock);
- return 1;
+ return dl?2:1;
}
size_t
int
infra_set_lame(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
- uint8_t* name, size_t namelen, time_t timenow)
+ uint8_t* name, size_t namelen, time_t timenow, int dnsseclame)
{
struct infra_host_data* data;
struct lruhash_entry* e;
k->entry.key = (void*)k;
k->entry.data = (void*)d;
d->ttl = timenow + infra->lame_ttl;
+ d->isdnsseclame = dnsseclame;
k->namelen = namelen;
e = infra_lookup_host_nottl(infra, addr, addrlen, 1);
if(!e) {
int
infra_get_lame_rtt(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
- uint8_t* name, size_t namelen, int* lame, int* rtt, time_t timenow)
+ uint8_t* name, size_t namelen, int* lame, int* dnsseclame,
+ int* rtt, time_t timenow)
{
struct infra_host_data* host;
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
addrlen, 0);
+ int lm;
if(!e)
return 0;
host = (struct infra_host_data*)e->data;
*rtt = rtt_unclamped(&host->rtt);
/* check lameness first, if so, ttl on host does not matter anymore */
- if(infra_lookup_lame(host, name, namelen, timenow)) {
+ if((lm=infra_lookup_lame(host, name, namelen, timenow))) {
lock_rw_unlock(&e->lock);
- *lame = 1;
+ if(lm == 1) {
+ *lame = 1;
+ *dnsseclame = 0;
+ } else {
+ *lame = 0;
+ *dnsseclame = 1;
+ }
return 1;
}
*lame = 0;
+ *dnsseclame = 0;
if(timenow > host->ttl) {
lock_rw_unlock(&e->lock);
return 0;
struct infra_lame_data {
/** TTL of this entry. absolute time. */
time_t ttl;
+ /** is the host lame (does not serve the zone authoritatively),
+ * or is the host dnssec lame (does not serve DNSSEC data) */
+ int isdnsseclame;
};
/**
* @param name: domain name of zone apex.
* @param namelen: length of domain name.
* @param timenow: what time it is now.
- * @return: 0 if not lame or unknown or timed out, true if lame.
+ * @return: 0 if not lame or unknown or timed out, 1 if lame, 2 if dnsseclame.
*/
int infra_lookup_lame(struct infra_host_data* host,
uint8_t* name, size_t namelen, time_t timenow);
* @param name: domain name of zone apex.
* @param namelen: length of domain name.
* @param timenow: what time it is now.
+ * @param dnsseclame: if true the host is set dnssec lame.
+ * if false, the host is marked lame (not serving the zone).
* @return: 0 on error.
*/
int infra_set_lame(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
- uint8_t* name, size_t namelen, time_t timenow);
+ uint8_t* name, size_t namelen, time_t timenow, int dnsseclame);
/**
* Update rtt information for the host.
* @param name: zone name.
* @param namelen: zone name length.
* @param lame: if function returns true, this returns lameness of the zone.
+ * @param dnsseclame: if function returns true, this returns if the zone
+ * is dnssec-lame.
* @param rtt: if function returns true, this returns avg rtt of the server.
* The rtt value is unclamped and reflects recent timeouts.
* @param timenow: what time it is now.
*/
int infra_get_lame_rtt(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
- uint8_t* name, size_t namelen, int* lame, int* rtt, time_t timenow);
+ uint8_t* name, size_t namelen, int* lame, int* dnsseclame,
+ int* rtt, time_t timenow);
/**
* Get memory used by the infra cache.
unit_assert( vs == 0 && to == init );
unit_assert( infra_set_lame(slab, (struct sockaddr_storage*)&one,
- (socklen_t)sizeof(int), zone, zonelen, now) );
+ (socklen_t)sizeof(int), zone, zonelen, now, 0) );
unit_assert( (d=infra_lookup_host(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), 0, now, &k)) );
unit_assert( d->ttl == now+cfg->host_ttl );
unit_assert( d->edns_version == 0 );
- unit_assert( infra_lookup_lame(d, zone, zonelen, now) );
+ unit_assert( infra_lookup_lame(d, zone, zonelen, now)==1 );
unit_assert( !infra_lookup_lame(d, zone, zonelen,
now+cfg->lame_ttl+10) );
unit_assert( !infra_lookup_lame(d, (uint8_t*)"\000", 1, now) );
--- /dev/null
+; config options
+; The island of trust is at example.com
+server:
+ trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+ val-override-date: "20070916134226"
+
+stub-zone:
+ name: "."
+ stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with failed key prime, no keys.
+
+; 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 qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.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
+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
+www.example.com. IN A
+SECTION AUTHORITY
+example.com. IN NS ns.example.com.
+SECTION ADDITIONAL
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+ ADDRESS 1.2.3.4
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+SECTION AUTHORITY
+example.com. IN SOA ns.example.com. hostmaster.example.com. 2007101500 28800 7200 604800 18000
+SECTION ADDITIONAL
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+SECTION AUTHORITY
+example.com. IN NS ns.example.com.
+SECTION ADDITIONAL
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here.
+; Should return insecure as answer.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A 10.20.30.40
+SECTION AUTHORITY
+example.com. IN NS ns.example.com.
+SECTION ADDITIONAL
+ns.example.com. IN A 1.2.3.4
+ENTRY_END
+
+SCENARIO_END