dnssec lame servers are used as last effort.

git-svn-id: file:///svn/unbound/trunk@716 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-10-23 12:37:18 +00:00
parent f92d51b3fe
commit 861483ac82
8 changed files with 176 additions and 20 deletions

View file

@ -3,6 +3,11 @@
- fixup tests to do additional section processing for lame replies, - fixup tests to do additional section processing for lame replies,
since the detection needs that. since the detection needs that.
- no longer trust in query section in reply during dnssec lame detect. - 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 22 October 2007: Wouter
- added donotquerylocalhost config option. Can be turned off for - added donotquerylocalhost config option. Can be turned off for

View file

@ -134,6 +134,7 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
{ {
int rtt; int rtt;
int lame; int lame;
int dnsseclame;
if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) { if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) {
return -1; /* server is on the donotquery list */ return -1; /* server is on the donotquery list */
} }
@ -142,11 +143,13 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
} }
/* check lameness - need zone , class info */ /* check lameness - need zone , class info */
if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen, 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) if(lame)
return -1; /* server is lame */ return -1; /* server is lame */
else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT) else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT)
return -1; /* server is unresponsive */ return -1; /* server is unresponsive */
else if(dnsseclame)
return rtt+USEFUL_SERVER_TOP_TIMEOUT; /* nonpref */
else return rtt; else return rtt;
} }
/* no server information present */ /* no server information present */
@ -157,7 +160,8 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
* returns number of best targets (or 0, no suitable targets) */ * returns number of best targets (or 0, no suitable targets) */
static int static int
iter_filter_order(struct iter_env* iter_env, struct module_env* env, 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; int got_num = 0, got_rtt = 0, thisrtt, swap_to_front;
struct delegpt_addr* a, *n, *prev=NULL; struct delegpt_addr* a, *n, *prev=NULL;
@ -198,21 +202,26 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
a = a->next_result; a = a->next_result;
} }
} }
*best_rtt = got_rtt;
return got_num; return got_num;
} }
struct delegpt_addr* struct delegpt_addr*
iter_server_selection(struct iter_env* iter_env, iter_server_selection(struct iter_env* iter_env,
struct module_env* env, struct delegpt* dp, 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); time_t now = time(NULL);
int sel; int sel;
int selrtt;
struct delegpt_addr* a, *prev; 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) if(num == 0)
return NULL; return NULL;
if(selrtt >= USEFUL_SERVER_TOP_TIMEOUT)
*dnssec_expected = 0;
if(num == 1) { if(num == 1) {
a = dp->result_list; a = dp->result_list;
if(++a->attempts < OUTBOUND_MSG_RETRY) if(++a->attempts < OUTBOUND_MSG_RETRY)

View file

@ -74,12 +74,14 @@ int iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg);
* @param dp: delegation point with result list. * @param dp: delegation point with result list.
* @param name: zone name (for lameness check). * @param name: zone name (for lameness check).
* @param namelen: length of name. * @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. * @return best target or NULL if no target.
* if not null, that target is removed from the result list in the dp. * 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 delegpt_addr* iter_server_selection(struct iter_env* iter_env,
struct module_env* env, struct delegpt* dp, uint8_t* name, 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. * Allocate dns_msg from parsed msg, in regional.

View file

@ -1082,7 +1082,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
/* Select the next usable target, filtering out unsuitable targets. */ /* 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->dp->name, iq->dp->namelen, &iq->dnssec_expected);
/* If no usable target was selected... */ /* If no usable target was selected... */
if(!target) { if(!target) {
@ -1179,6 +1179,7 @@ static int
processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
int id) int id)
{ {
int dnsseclame = 0;
enum response_type type; enum response_type type;
iq->num_current_queries--; iq->num_current_queries--;
if(iq->response == NULL) { if(iq->response == NULL) {
@ -1203,8 +1204,10 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
* might mark the server,zone lame inappropriately */ * might mark the server,zone lame inappropriately */
if(!iter_msg_has_dnssec(iq->response) && if(!iter_msg_has_dnssec(iq->response) &&
iter_msg_from_zone(iq->response, iq->dp, type, iter_msg_from_zone(iq->response, iq->dp, type,
iq->qchase.qclass)) iq->qchase.qclass)) {
type = RESPONSE_TYPE_LAME; type = RESPONSE_TYPE_LAME;
dnsseclame = 1;
}
} }
/* handle each of the type cases */ /* handle each of the type cases */
@ -1307,15 +1310,18 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
return next_state(iq, INIT_REQUEST_STATE); return next_state(iq, INIT_REQUEST_STATE);
} else if(type == RESPONSE_TYPE_LAME) { } else if(type == RESPONSE_TYPE_LAME) {
/* Cache the LAMEness. */ /* Cache the LAMEness. */
verbose(VERB_DETAIL, "query response was LAME"); verbose(VERB_DETAIL, "query response was %sLAME",
dnsseclame?"DNSSEC ":"");
if(qstate->reply) { if(qstate->reply) {
/* need addr for lameness cache, but we may have /* need addr for lameness cache, but we may have
* gotten this from cache, so test to be sure */ * gotten this from cache, so test to be sure */
if(!infra_set_lame(qstate->env->infra_cache, if(!infra_set_lame(qstate->env->infra_cache,
&qstate->reply->addr, qstate->reply->addrlen, &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"); 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) { } else if(type == RESPONSE_TYPE_THROWAWAY) {
/* LAME and THROWAWAY responses are handled the same way. /* LAME and THROWAWAY responses are handled the same way.
* In this case, the event is just sent directly back to * In this case, the event is just sent directly back to

View file

@ -266,6 +266,7 @@ infra_lookup_lame(struct infra_host_data* host,
struct lruhash_entry* e; struct lruhash_entry* e;
struct infra_lame_key k; struct infra_lame_key k;
struct infra_lame_data *d; struct infra_lame_data *d;
int dl;
if(!host->lameness) if(!host->lameness)
return 0; return 0;
k.entry.hash = hash_lameness(name, namelen); k.entry.hash = hash_lameness(name, namelen);
@ -281,8 +282,9 @@ infra_lookup_lame(struct infra_host_data* host,
lock_rw_unlock(&e->lock); lock_rw_unlock(&e->lock);
return 0; return 0;
} }
dl = d->isdnsseclame;
lock_rw_unlock(&e->lock); lock_rw_unlock(&e->lock);
return 1; return dl?2:1;
} }
size_t size_t
@ -329,7 +331,7 @@ infra_lame_deldatafunc(void* d, void* ATTR_UNUSED(arg))
int int
infra_set_lame(struct infra_cache* infra, infra_set_lame(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen, 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 infra_host_data* data;
struct lruhash_entry* e; struct lruhash_entry* e;
@ -360,6 +362,7 @@ infra_set_lame(struct infra_cache* infra,
k->entry.key = (void*)k; k->entry.key = (void*)k;
k->entry.data = (void*)d; k->entry.data = (void*)d;
d->ttl = timenow + infra->lame_ttl; d->ttl = timenow + infra->lame_ttl;
d->isdnsseclame = dnsseclame;
k->namelen = namelen; k->namelen = namelen;
e = infra_lookup_host_nottl(infra, addr, addrlen, 1); e = infra_lookup_host_nottl(infra, addr, addrlen, 1);
if(!e) { if(!e) {
@ -476,22 +479,31 @@ infra_edns_update(struct infra_cache* infra,
int int
infra_get_lame_rtt(struct infra_cache* infra, infra_get_lame_rtt(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen, 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 infra_host_data* host;
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr, struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
addrlen, 0); addrlen, 0);
int lm;
if(!e) if(!e)
return 0; return 0;
host = (struct infra_host_data*)e->data; host = (struct infra_host_data*)e->data;
*rtt = rtt_unclamped(&host->rtt); *rtt = rtt_unclamped(&host->rtt);
/* check lameness first, if so, ttl on host does not matter anymore */ /* 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); lock_rw_unlock(&e->lock);
*lame = 1; if(lm == 1) {
*lame = 1;
*dnsseclame = 0;
} else {
*lame = 0;
*dnsseclame = 1;
}
return 1; return 1;
} }
*lame = 0; *lame = 0;
*dnsseclame = 0;
if(timenow > host->ttl) { if(timenow > host->ttl) {
lock_rw_unlock(&e->lock); lock_rw_unlock(&e->lock);
return 0; return 0;

View file

@ -91,6 +91,9 @@ struct infra_lame_key {
struct infra_lame_data { struct infra_lame_data {
/** TTL of this entry. absolute time. */ /** TTL of this entry. absolute time. */
time_t ttl; 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;
}; };
/** /**
@ -172,7 +175,7 @@ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
* @param name: domain name of zone apex. * @param name: domain name of zone apex.
* @param namelen: length of domain name. * @param namelen: length of domain name.
* @param timenow: what time it is now. * @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, int infra_lookup_lame(struct infra_host_data* host,
uint8_t* name, size_t namelen, time_t timenow); uint8_t* name, size_t namelen, time_t timenow);
@ -185,11 +188,13 @@ int infra_lookup_lame(struct infra_host_data* host,
* @param name: domain name of zone apex. * @param name: domain name of zone apex.
* @param namelen: length of domain name. * @param namelen: length of domain name.
* @param timenow: what time it is now. * @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. * @return: 0 on error.
*/ */
int infra_set_lame(struct infra_cache* infra, int infra_set_lame(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen, 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. * Update rtt information for the host.
@ -235,6 +240,8 @@ int infra_edns_update(struct infra_cache* infra,
* @param name: zone name. * @param name: zone name.
* @param namelen: zone name length. * @param namelen: zone name length.
* @param lame: if function returns true, this returns lameness of the zone. * @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. * @param rtt: if function returns true, this returns avg rtt of the server.
* The rtt value is unclamped and reflects recent timeouts. * The rtt value is unclamped and reflects recent timeouts.
* @param timenow: what time it is now. * @param timenow: what time it is now.
@ -242,7 +249,8 @@ int infra_edns_update(struct infra_cache* infra,
*/ */
int infra_get_lame_rtt(struct infra_cache* infra, int infra_get_lame_rtt(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen, 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. * Get memory used by the infra cache.

View file

@ -184,12 +184,12 @@ infra_test()
unit_assert( vs == 0 && to == init ); unit_assert( vs == 0 && to == init );
unit_assert( infra_set_lame(slab, (struct sockaddr_storage*)&one, 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, unit_assert( (d=infra_lookup_host(slab, (struct sockaddr_storage*)&one,
(socklen_t)sizeof(int), 0, now, &k)) ); (socklen_t)sizeof(int), 0, now, &k)) );
unit_assert( d->ttl == now+cfg->host_ttl ); unit_assert( d->ttl == now+cfg->host_ttl );
unit_assert( d->edns_version == 0 ); 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, unit_assert( !infra_lookup_lame(d, zone, zonelen,
now+cfg->lame_ttl+10) ); now+cfg->lame_ttl+10) );
unit_assert( !infra_lookup_lame(d, (uint8_t*)"\000", 1, now) ); unit_assert( !infra_lookup_lame(d, (uint8_t*)"\000", 1, now) );

114
testdata/val_nokeyprime.rpl vendored Normal file
View file

@ -0,0 +1,114 @@
; 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