]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
dnssec lame servers are used as last effort.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 23 Oct 2007 12:37:18 +0000 (12:37 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 23 Oct 2007 12:37:18 +0000 (12:37 +0000)
git-svn-id: file:///svn/unbound/trunk@716 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
iterator/iter_utils.c
iterator/iter_utils.h
iterator/iterator.c
services/cache/infra.c
services/cache/infra.h
testcode/unitmain.c
testdata/val_nokeyprime.rpl [new file with mode: 0644]

index eab2cc2017a7201758d5df4d4d1c4b63a70c4ed8..e2aae25458023fe18bab1eac40178a8e52efdd1d 100644 (file)
@@ -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
index 589da242f52504f97cf142df484bbd408a762ffb..56cbed1284ff90f4e1506560673031a00b7b97d5 100644 (file)
@@ -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)
index 4999df98b688a3b58b44b9c7d89c4cead1360912..e737f2564b66264b2120b28ca5f498e570c27bc4 100644 (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 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.
index 07ca5a69a8fc64bb47bdf27f5b9de86f744716b3..48baf653a35f57c4ee3b26de1a51aa1bcd1cab01 100644 (file)
@@ -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 
index 5b75e3d3bc565c5a72301900fc3da621c8833166..d95568bf097321b69583bb8600738e4edc69d8c8 100644 (file)
@@ -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;
index 1252c717ee82c276d0c58b6c620b485f86d385c1..9934b696f6dd797ecc6c50e245734f0e29df561b 100644 (file)
@@ -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.
index b4666528baf0425f5a2a4358ad35e1183cace9bc..0db87f85e6788a639521f722422fdc731da7a316 100644 (file)
@@ -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 (file)
index 0000000..4e4f759
--- /dev/null
@@ -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