diff --git a/doc/Changelog b/doc/Changelog index eab2cc201..e2aae2545 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -3,6 +3,11 @@ - 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 diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 589da242f..56cbed128 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -134,6 +134,7 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env, { int rtt; int lame; + int dnsseclame; if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) { 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 */ 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 */ @@ -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) */ 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; @@ -198,21 +202,26 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env, 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) diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 4999df98b..e737f2564 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -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 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. diff --git a/iterator/iterator.c b/iterator/iterator.c index 07ca5a69a..48baf653a 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1082,7 +1082,7 @@ 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, - iq->dp->name, iq->dp->namelen); + iq->dp->name, iq->dp->namelen, &iq->dnssec_expected); /* If no usable target was selected... */ if(!target) { @@ -1179,6 +1179,7 @@ static int 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) { @@ -1203,8 +1204,10 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, * 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 */ @@ -1307,15 +1310,18 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, 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 diff --git a/services/cache/infra.c b/services/cache/infra.c index 5b75e3d3b..d95568bf0 100644 --- a/services/cache/infra.c +++ b/services/cache/infra.c @@ -266,6 +266,7 @@ infra_lookup_lame(struct infra_host_data* host, 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); @@ -281,8 +282,9 @@ infra_lookup_lame(struct infra_host_data* host, lock_rw_unlock(&e->lock); return 0; } + dl = d->isdnsseclame; lock_rw_unlock(&e->lock); - return 1; + return dl?2:1; } size_t @@ -329,7 +331,7 @@ infra_lame_deldatafunc(void* d, void* ATTR_UNUSED(arg)) 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; @@ -360,6 +362,7 @@ infra_set_lame(struct infra_cache* infra, 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) { @@ -476,22 +479,31 @@ infra_edns_update(struct infra_cache* infra, 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; diff --git a/services/cache/infra.h b/services/cache/infra.h index 1252c717e..9934b696f 100644 --- a/services/cache/infra.h +++ b/services/cache/infra.h @@ -91,6 +91,9 @@ struct infra_lame_key { 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; }; /** @@ -172,7 +175,7 @@ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, * @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); @@ -185,11 +188,13 @@ int infra_lookup_lame(struct infra_host_data* host, * @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. @@ -235,6 +240,8 @@ int infra_edns_update(struct infra_cache* infra, * @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. @@ -242,7 +249,8 @@ int infra_edns_update(struct infra_cache* infra, */ 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. diff --git a/testcode/unitmain.c b/testcode/unitmain.c index b4666528b..0db87f85e 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -184,12 +184,12 @@ infra_test() 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) ); diff --git a/testdata/val_nokeyprime.rpl b/testdata/val_nokeyprime.rpl new file mode 100644 index 000000000..4e4f75950 --- /dev/null +++ b/testdata/val_nokeyprime.rpl @@ -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