]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
parent-child misconfigured data lookup.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 28 May 2010 14:15:29 +0000 (14:15 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 28 May 2010 14:15:29 +0000 (14:15 +0000)
git-svn-id: file:///svn/unbound/trunk@2119 be551aaa-1e26-0410-a405-d3ace91eadb9

23 files changed:
doc/Changelog
iterator/iter_delegpt.c
iterator/iter_delegpt.h
iterator/iter_fwd.c
iterator/iter_hints.c
iterator/iter_utils.c
iterator/iter_utils.h
iterator/iterator.c
iterator/iterator.h
services/cache/dns.c
testdata/autotrust_init_fail.rpl
testdata/autotrust_probefail.rpl
testdata/autotrust_valid_use.rpl
testdata/iter_lame_aaaa.rpl
testdata/iter_lamescrub.rpl
testdata/iter_primenoglue.rpl
testdata/iter_privaddr.rpl
testdata/val_dnametoolong.rpl
testdata/val_ds_cname.rpl
testdata/val_faildnskey.rpl
testdata/val_faildnskey_ok.rpl
util/data/packed_rrset.c
util/data/packed_rrset.h

index dd75d67669075a7b2604ee834ee49f39e5157215..1e1af754b67ba0d4c161ab1c56fdfb4ebbe47822 100644 (file)
@@ -1,5 +1,16 @@
 28 May 2010: Wouter
        - iana portlist updated.
+       - parent-child disagreement approach altered.  Older fixes are
+         removed in place of a more exhaustive search for misconfigured data
+         available via the parent of a delegation.
+         This is designed to be throttled by cache entries, with TTL from the
+         parent if possible.  Additionally the loop-counter is used.
+         It also tests for NS RRset differences between parent and child.
+         The fetch of misconfigured data should be more reliable and thorough.
+         It should work reliably even with no or only partial data in cache.
+         Data received from the child (as always) is deemed more
+         authoritative than information received from the delegation parent.
+         The search for misconfigured data is not performed normally.
 
 26 May 2010: Wouter
        - Contribution from Migiel de Vos (Surfnet): nagios patch for
index 20284cf9ebec358b692466ff52e7076b2af237d3..28dac7c76ddb0548029722e3b3e51a28e95e293f 100644 (file)
@@ -69,12 +69,15 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
        if(!delegpt_set_name(copy, region, dp->name))
                return NULL;
        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))
+               if(!delegpt_add_ns(copy, region, ns->name, (int)ns->lame))
                        return NULL;
                copy->nslist->resolved = ns->resolved;
                copy->nslist->got4 = ns->got4;
                copy->nslist->got6 = ns->got6;
+               copy->nslist->done_pside4 = ns->done_pside4;
+               copy->nslist->done_pside6 = ns->done_pside6;
        }
        for(a = dp->target_list; a; a = a->next_target) {
                if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen, 
@@ -93,7 +96,8 @@ 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)
+delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
+       int lame)
 {
        struct delegpt_ns* ns;
        size_t len;
@@ -113,6 +117,9 @@ 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->done_pside4 = 0;
+       ns->done_pside6 = 0;
        return 1;
 }
 
@@ -245,15 +252,19 @@ void delegpt_log(enum verbosity_value v, struct delegpt* dp)
        delegpt_count_ns(dp, &numns, &missing);
        delegpt_count_addr(dp, &numaddr, &numres, &numavail);
        log_info("DelegationPoint<%s>: %u names (%u missing), "
-               "%u addrs (%u result, %u avail)", 
+               "%u addrs (%u result, %u avail)%s", 
                buf, (unsigned)numns, (unsigned)missing, 
-               (unsigned)numaddr, (unsigned)numres, (unsigned)numavail);
+               (unsigned)numaddr, (unsigned)numres, (unsigned)numavail,
+               (dp->has_parent_side_NS?" parentNS":" cacheNS"));
        if(verbosity >= VERB_ALGO) {
                for(ns = dp->nslist; ns; ns = ns->next) {
                        dname_str(ns->name, buf);
-                       log_info("  %s %s%s%s%s", buf, (ns->resolved?"*":""),
+                       log_info("  %s %s%s%s%s%s%s%s", buf, 
+                       (ns->resolved?"*":""),
                        (ns->got4?" A":""), (ns->got6?" AAAA":""),
-                       (dp->bogus?" BOGUS":"") );
+                       (dp->bogus?" BOGUS":""), (ns->lame?" PARENTSIDE":""),
+                       (ns->done_pside4?" PSIDE_A":""),
+                       (ns->done_pside6?" PSIDE_AAAA":""));
                }
                for(a = dp->target_list; a; a = a->next_target) {
                        const char* str = "  ";
@@ -277,6 +288,16 @@ delegpt_add_unused_targets(struct delegpt* dp)
        }
 }
 
+size_t
+delegpt_count_targets(struct delegpt* dp)
+{
+       struct delegpt_addr* a;
+       size_t n = 0;
+       for(a = dp->target_list; a; a = a->next_target)
+               n++;
+       return n;
+}
+
 size_t 
 delegpt_count_missing_targets(struct delegpt* dp)
 {
@@ -325,9 +346,10 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
        dp = delegpt_create(region);
        if(!dp)
                return NULL;
+       dp->has_parent_side_NS = 1; /* created from message */
        if(!delegpt_set_name(dp, region, ns_rrset->rk.dname))
                return NULL;
-       if(!delegpt_rrset_add_ns(dp, region, ns_rrset))
+       if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0))
                return NULL;
 
        /* add glue, A and AAAA in answer and additional section */
@@ -351,7 +373,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)
+        struct ub_packed_rrset_key* ns_rrset, int lame)
 {
        struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
                ns_rrset->entry.data;
@@ -364,7 +386,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
                        (size_t)ldns_read_uint16(nsdata->rr_data[i]))
                        continue; /* bad format */
                /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
-               if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2))
+               if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame))
                        return 0;
        }
        return 1;
@@ -418,16 +440,16 @@ 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)
+        struct ub_packed_rrset_key* rrset, int lame)
 {
        if(!rrset)
                return 1;
        if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS)
-               return delegpt_rrset_add_ns(dp, region, rrset);
+               return delegpt_rrset_add_ns(dp, region, rrset, lame);
        else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A)
-               return delegpt_add_rrset_A(dp, region, rrset, 0, 1);
+               return delegpt_add_rrset_A(dp, region, rrset, lame, 1);
        else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA)
-               return delegpt_add_rrset_AAAA(dp, region, rrset, 0, 1);
+               return delegpt_add_rrset_AAAA(dp, region, rrset, lame, 1);
        log_warn("Unknown rrset type added to delegpt");
        return 1;
 }
index bdea325d2cff29e140b84ef540e45a75149af5ad..b779abc94eb450f40741971a2b83edbc6abd0f07 100644 (file)
@@ -74,6 +74,11 @@ struct delegpt {
 
        /** if true, the NS RRset was bogus. All info is bad. */
        int bogus;
+       /** if true, the parent-side NS record has been applied:
+        * its names have been added and their addresses can follow later.
+        * Also true if the delegationpoint was created from a delegation
+        * message and thus contains the parent-side-info already. */
+       uint8_t has_parent_side_NS;
 };
 
 /**
@@ -90,13 +95,26 @@ struct delegpt_ns {
         * If the name has been resolved. false if not queried for yet.
         * true if the A, AAAA queries have been generated.
         * marked true if those queries fail.
-        * and marked true is got4 and got6 are both true.
+        * and marked true if got4 and got6 are both true.
         */
        int resolved;
        /** if the ipv4 address is in the delegpt */
        uint8_t got4;
        /** if the ipv6 address is in the delegpt */
        uint8_t got6;
+       /**
+        * If the name is parent-side only and thus dispreferred.
+        * Its addresses become dispreferred as well
+        */
+       uint8_t lame;
+       /** if the parent-side ipv4 address has been looked up (last resort).
+        * Also enabled if a parent-side cache entry exists, or a parent-side
+        * negative-cache entry exists. */
+       uint8_t done_pside4;
+       /** if the parent-side ipv6 address has been looked up (last resort).
+        * Also enabled if a parent-side cache entry exists, or a parent-side
+        * negative-cache entry exists. */
+       uint8_t done_pside6;
 };
 
 /**
@@ -155,20 +173,22 @@ int delegpt_set_name(struct delegpt* dp, struct regional* regional,
  * @param dp: delegation point.
  * @param regional: where to allocate the info.
  * @param name: domain name in wire format.
+ * @param lame: name is lame, disprefer it.
  * @return false on error.
  */
 int delegpt_add_ns(struct delegpt* dp, struct regional* regional, 
-       uint8_t* name);
+       uint8_t* name, int lame);
 
 /**
  * Add NS rrset; calls add_ns repeatedly.
  * @param dp: delegation point.
  * @param regional: where to allocate the info.
  * @param ns_rrset: NS rrset.
+ * @param lame: rrset is lame, disprefer it.
  * return 0 on alloc error.
  */
 int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
-       struct ub_packed_rrset_key* ns_rrset);
+       struct ub_packed_rrset_key* ns_rrset, int lame);
 
 /**
  * Add target address to the delegation point.
@@ -219,10 +239,11 @@ int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional,
  * @param dp: delegation point.
  * @param regional: where to allocate the info.
  * @param rrset: RRset to add, NS, A, AAAA.
+ * @param lame: rrset is lame, disprefer it.
  * @return 0 on alloc error.
  */
 int delegpt_add_rrset(struct delegpt* dp, struct regional* regional, 
-       struct ub_packed_rrset_key* rrset);
+       struct ub_packed_rrset_key* rrset, int lame);
 
 /**
  * Add address to the delegation point. No servername is associated or checked.
@@ -286,6 +307,9 @@ void delegpt_add_unused_targets(struct delegpt* dp);
  */
 size_t delegpt_count_missing_targets(struct delegpt* dp);
 
+/** count total number of targets in dp */
+size_t delegpt_count_targets(struct delegpt* dp);
+
 /**
  * Create new delegation point from a dns message
  *
index f0fca1eddcb770d273551716ee3f48526c08d56c..1c476f05db8c6d0c6855510dec2c771fffab20b9 100644 (file)
@@ -190,7 +190,7 @@ read_fwds_host(struct iter_forwards* fwd, struct config_stub* s,
                                s->name, p->str);
                        return 0;
                }
-               if(!delegpt_add_ns(dp, fwd->region, ldns_rdf_data(rdf))) {
+               if(!delegpt_add_ns(dp, fwd->region, ldns_rdf_data(rdf), 0)) {
                        ldns_rdf_deep_free(rdf);
                        log_err("out of memory");
                        return 0;
@@ -235,6 +235,9 @@ read_forwards(struct iter_forwards* fwd, struct config_file* cfg)
                        log_err("out of memory");
                        return 0;
                }
+               /* set flag that parent side NS information is included.
+                * Asking an (higher up) server on the internet is not useful*/
+               dp->has_parent_side_NS = 1;
                if(!read_fwds_name(fwd, s, dp) ||
                        !read_fwds_host(fwd, s, dp) ||
                        !read_fwds_addr(fwd, s, dp))
index bf740684276a5204b4c98af93cb40117e58ead2c..da6fa8314223cb317b76a2685789d6934b156bca 100644 (file)
@@ -85,7 +85,7 @@ ah(struct delegpt* dp, struct regional* r, const char* sv, const char* ip)
                log_err("could not parse %s", sv);
                return 0;
        }
-       if(!delegpt_add_ns(dp, r, ldns_rdf_data(rdf)) ||
+       if(!delegpt_add_ns(dp, r, ldns_rdf_data(rdf), 0) ||
           !extstrtoaddr(ip, &addr, &addrlen) ||
           !delegpt_add_target(dp, r, ldns_rdf_data(rdf), ldns_rdf_size(rdf),
                &addr, addrlen, 0, 0, 1)) {
@@ -112,6 +112,7 @@ compile_time_root_prime(struct regional* r, int do_ip4, int do_ip6)
        struct delegpt* dp = delegpt_create(r);
        if(!dp)
                return NULL;
+       dp->has_parent_side_NS = 1;
        if(!delegpt_set_name(dp, r, (uint8_t*)"\000"))
                return NULL;
       if(do_ip4) {
@@ -202,7 +203,7 @@ read_stubs_host(struct iter_hints* hints, struct config_stub* s,
                                s->name, p->str);
                        return 0;
                }
-               if(!delegpt_add_ns(dp, hints->region, ldns_rdf_data(rdf))) {
+               if(!delegpt_add_ns(dp, hints->region, ldns_rdf_data(rdf), 0)) {
                        ldns_rdf_deep_free(rdf);
                        log_err("out of memory");
                        return 0;
@@ -247,6 +248,7 @@ read_stubs(struct iter_hints* hints, struct config_file* cfg)
                        log_err("out of memory");
                        return 0;
                }
+               dp->has_parent_side_NS = 1;
                if(!read_stubs_name(hints, s, dp) ||
                        !read_stubs_host(hints, s, dp) ||
                        !read_stubs_addr(hints, s, dp))
@@ -283,6 +285,7 @@ read_root_hints(struct iter_hints* hints, char* fname)
                return 0;
        }
        verbose(VERB_QUERY, "Reading root hints from %s", fname);
+       dp->has_parent_side_NS = 1;
        while(!feof(f)) {
                status = ldns_rr_new_frm_fp_l(&rr, f, 
                        &default_ttl, &origin, &prev_rr, &lineno);
@@ -297,7 +300,7 @@ read_root_hints(struct iter_hints* hints, char* fname)
                }
                if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS) {
                        if(!delegpt_add_ns(dp, hints->region,
-                               ldns_rdf_data(ldns_rr_rdf(rr, 0)))) {
+                               ldns_rdf_data(ldns_rr_rdf(rr, 0)), 0)) {
                                log_err("out of memory reading root hints");
                                goto stop_read;
                        }
index ee3e7e7714b44613b3345e8e66e22f801d7b8180..8d539a82af80a4d7dc4250a9360c35baf86ebabe 100644 (file)
@@ -430,54 +430,6 @@ iter_ns_probability(struct ub_randstate* rnd, int n, int m)
        return (sel < n);
 }
 
-int iter_suspect_exists(struct query_info* qinfo, struct delegpt* dp,
-        struct module_env* env)
-{
-       struct ub_packed_rrset_key* r;
-       if(qinfo->qtype != LDNS_RR_TYPE_A && qinfo->qtype != LDNS_RR_TYPE_AAAA)
-               return 0; /* not glue type */
-       if(!dname_subdomain_c(qinfo->qname, dp->name))
-               return 0; /* not in-zone */
-       if(!delegpt_find_ns(dp, qinfo->qname, qinfo->qname_len))
-               return 0; /* not glue */
-
-       /* do we suspect that it exists? lookup with time=0 */
-       r = rrset_cache_lookup(env->rrset_cache, qinfo->qname, 
-               qinfo->qname_len, qinfo->qtype, qinfo->qclass, 0, 0, 0);
-       if(r) {
-               struct packed_rrset_data* d = (struct packed_rrset_data*)
-                       r->entry.data;
-               /* if it is valid, no need for queries to parent zone */
-               if(*env->now <= d->ttl) {
-                       lock_rw_unlock(&r->entry.lock);
-                       return 0;
-               }
-               /* was it recently expired? */
-               if( (*env->now - d->ttl) <= SUSPICION_RECENT_EXPIRY) {
-                       verbose(VERB_ALGO, "suspect glue at parent: "
-                               "rrset recently expired");
-                       lock_rw_unlock(&r->entry.lock);
-                       return 1;
-               }
-               lock_rw_unlock(&r->entry.lock);
-       }
-
-       /* so, qinfo not there, does the other A/AAAA type exist in cache? */
-       r=rrset_cache_lookup(env->rrset_cache, qinfo->qname, qinfo->qname_len,
-         (qinfo->qtype==LDNS_RR_TYPE_A)?LDNS_RR_TYPE_AAAA:LDNS_RR_TYPE_A,
-         qinfo->qclass, 0, *env->now, 0);
-       if(r) {
-               /* it exists and explains why the glue is there */
-               lock_rw_unlock(&r->entry.lock);
-               return 0;
-       }
-
-       /* neither exist, so logically, one should exist for a nameserver */
-       verbose(VERB_ALGO, "suspect glue at parent: "
-               "neither A nor AAAA exist in cache");
-       return 1;
-}
-
 /** detect dependency cycle for query and target */
 static int
 causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen,
@@ -516,6 +468,27 @@ iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
        }
 }
 
+void 
+iter_mark_pside_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
+{
+       struct delegpt_ns* ns;
+       for(ns = dp->nslist; ns; ns = ns->next) {
+               if(ns->done_pside4 && ns->done_pside6)
+                       continue;
+               /* see if this ns as target causes dependency cycle */
+               if(causes_cycle(qstate, ns->name, ns->namelen, 
+                       LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass) ||
+                  causes_cycle(qstate, ns->name, ns->namelen, 
+                       LDNS_RR_TYPE_A, qstate->qinfo.qclass)) {
+                       log_nametypeclass(VERB_QUERY, "skipping target due "
+                               "to dependency cycle", ns->name,
+                               LDNS_RR_TYPE_A, qstate->qinfo.qclass);
+                       ns->done_pside4 = 1;
+                       ns->done_pside6 = 1;
+               }
+       }
+}
+
 int 
 iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags, 
        struct delegpt* dp)
@@ -735,56 +708,162 @@ reply_equal(struct reply_info* p, struct reply_info* q, ldns_buffer* scratch)
 }
 
 void 
-iter_store_inzone_glue(struct module_env* env, struct query_info* qinfo,
-       struct reply_info* rep)
+iter_store_parentside_rrset(struct module_env* env, 
+       struct ub_packed_rrset_key* rrset)
 {
        struct rrset_ref ref;
-       struct ub_packed_rrset_key* rrset;
-       if(qinfo->qtype != LDNS_RR_TYPE_A && qinfo->qtype != LDNS_RR_TYPE_AAAA)
-               return;
-       rrset = reply_find_rrset(rep, qinfo->qname, qinfo->qname_len,
-               qinfo->qtype, qinfo->qclass);
-       if(!rrset)
-               return;
-       /* got A or AAAA glue rrset. store it in case its handy */
        rrset = packed_rrset_copy_alloc(rrset, env->alloc, *env->now);
        if(!rrset) {
-               log_err("malloc failure in store_inzone_glue");
+               log_err("malloc failure in store_parentside_rrset");
                return;
        }
        rrset->rk.flags |= PACKED_RRSET_PARENT_SIDE;
        rrset->entry.hash = rrset_key_hash(&rrset->rk);
        ref.key = rrset;
        ref.id = rrset->id;
-       /* ignore ret: it was in the cache, ref updated */
+       /* ignore ret: if it was in the cache, ref updated */
        (void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, *env->now);
 }
 
+/** fetch NS record from reply, if any */
+static struct ub_packed_rrset_key*
+reply_get_NS_rrset(struct reply_info* rep)
+{
+       size_t i;
+       for(i=0; i<rep->rrset_count; i++) {
+               if(rep->rrsets[i]->rk.type == htons(LDNS_RR_TYPE_NS)) {
+                       return rep->rrsets[i];
+               }
+       }
+       return NULL;
+}
+
+void
+iter_store_parentside_NS(struct module_env* env, struct reply_info* rep)
+{
+       struct ub_packed_rrset_key* rrset = reply_get_NS_rrset(rep);
+       if(rrset) {
+               log_rrset_key(VERB_ALGO, "store parent-side NS", rrset);
+               iter_store_parentside_rrset(env, rrset);
+       }
+}
+
+void iter_store_parentside_neg(struct module_env* env, 
+        struct query_info* qinfo, struct reply_info* rep)
+{
+       /* TTL: NS from referral in iq->deleg_msg,
+        *      or first RR from iq->response,
+        *      or servfail5secs if !iq->response */ 
+       uint32_t ttl = NORR_TTL;
+       struct ub_packed_rrset_key* neg;
+       struct packed_rrset_data* newd;
+       if(rep) {
+               struct ub_packed_rrset_key* rrset = reply_get_NS_rrset(rep);
+               if(!rrset && rep->rrset_count != 0) rrset = rep->rrsets[0];
+               if(rrset) ttl = ub_packed_rrset_ttl(rrset);
+       }
+       /* create empty rrset to store */
+       neg = (struct ub_packed_rrset_key*)regional_alloc(env->scratch,
+                       sizeof(struct ub_packed_rrset_key));
+       if(!neg) {
+               log_err("out of memory in store_parentside_neg");
+               return;
+       }
+       memset(&neg->entry, 0, sizeof(neg->entry));
+       neg->entry.key = neg;
+       neg->rk.type = htons(qinfo->qtype);
+       neg->rk.rrset_class = htons(qinfo->qclass);
+       neg->rk.flags = 0;
+       neg->rk.dname = regional_alloc_init(env->scratch, qinfo->qname, 
+               qinfo->qname_len);
+       if(!neg->rk.dname) {
+               log_err("out of memory in store_parentside_neg");
+               return;
+       }
+       neg->rk.dname_len = qinfo->qname_len;
+       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));
+       if(!newd) {
+               log_err("out of memory in store_parentside_neg");
+               return;
+       }
+       neg->entry.data = newd;
+       newd->ttl = ttl;
+       /* entry must have one RR, otherwise not valid in cache.
+        * put in one RR with empty rdata: those are ignored as nameserver */
+       newd->count = 1;
+       newd->rrsig_count = 0;
+       newd->trust = rrset_trust_ans_noAA;
+       newd->rr_len = (size_t*)((uint8_t*)newd +
+               sizeof(struct packed_rrset_data));
+       newd->rr_len[0] = 0 /* zero len rdata */ + sizeof(uint16_t);
+       packed_rrset_ptr_fixup(newd);
+       newd->rr_ttl[0] = newd->ttl;
+       ldns_write_uint16(newd->rr_data[0], 0 /* zero len rdata */);
+       /* store it */
+       log_rrset_key(VERB_ALGO, "store parent-side negative", neg);
+       iter_store_parentside_rrset(env, neg);
+}
+
 int 
-iter_lookup_inzone_glue(struct module_env* env, struct delegpt* dp,
+iter_lookup_parent_NS_from_cache(struct module_env* env, struct delegpt* dp,
        struct regional* region, struct query_info* qinfo)
 {
        struct ub_packed_rrset_key* akey;
-       akey = rrset_cache_lookup(env->rrset_cache, qinfo->qname, 
-               qinfo->qname_len, qinfo->qtype, qinfo->qclass, 
+       akey = rrset_cache_lookup(env->rrset_cache, dp->name, 
+               dp->namelen, LDNS_RR_TYPE_NS, qinfo->qclass, 
                PACKED_RRSET_PARENT_SIDE, *env->now, 0);
        if(akey) {
-               if(qinfo->qtype == LDNS_RR_TYPE_A) {
-                       if(!delegpt_add_rrset_A(dp, region, akey, 1, 1)) {
-                               lock_rw_unlock(&akey->entry.lock);
-                               return 0;
-                       }
-               } else if(qinfo->qtype == LDNS_RR_TYPE_AAAA) {
-                       if(!delegpt_add_rrset_AAAA(dp, region, akey, 1, 1)) {
-                               lock_rw_unlock(&akey->entry.lock);
-                               return 0;
-                       }
+               log_rrset_key(VERB_ALGO, "found parent-side NS in cache", akey);
+               dp->has_parent_side_NS = 1;
+               /* and mark the new names as lame */
+               if(!delegpt_rrset_add_ns(dp, region, akey, 1)) {
+                       lock_rw_unlock(&akey->entry.lock);
+                       return 0;
                }
                lock_rw_unlock(&akey->entry.lock);
        }
        return 1;
 }
 
+int iter_lookup_parent_glue_from_cache(struct module_env* env,
+        struct delegpt* dp, struct regional* region, struct query_info* qinfo)
+{
+       struct ub_packed_rrset_key* akey;
+       struct delegpt_ns* ns;
+       size_t num = delegpt_count_targets(dp);
+       for(ns = dp->nslist; ns; ns = ns->next) {
+               /* get cached parentside A */
+               akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
+                       ns->namelen, LDNS_RR_TYPE_A, qinfo->qclass, 
+                       PACKED_RRSET_PARENT_SIDE, *env->now, 0);
+               if(akey) {
+                       log_rrset_key(VERB_ALGO, "found parent-side", akey);
+                       ns->done_pside4 = 1;
+                       /* a negative-cache-element has no addresses it adds */
+                       if(!delegpt_add_rrset_A(dp, region, akey, 1, 1))
+                               log_err("malloc failure in lookup_parent_glue");
+                       lock_rw_unlock(&akey->entry.lock);
+               }
+               /* get cached parentside AAAA */
+               akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
+                       ns->namelen, LDNS_RR_TYPE_AAAA, qinfo->qclass, 
+                       PACKED_RRSET_PARENT_SIDE, *env->now, 0);
+               if(akey) {
+                       log_rrset_key(VERB_ALGO, "found parent-side", akey);
+                       ns->done_pside6 = 1;
+                       /* a negative-cache-element has no addresses it adds */
+                       if(!delegpt_add_rrset_AAAA(dp, region, akey, 1, 1))
+                               log_err("malloc failure in lookup_parent_glue");
+                       lock_rw_unlock(&akey->entry.lock);
+               }
+       }
+       /* see if new (but lame) addresses have become available */
+       return delegpt_count_targets(dp) != num;
+}
+
 int 
 iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd, 
        uint16_t* c)
index d3870ecd33510da2e56bba168c5ed01ca66070c3..e8c5d04f24da5a35a9a26c6b99245e158e0885a8 100644 (file)
@@ -145,17 +145,13 @@ int iter_ns_probability(struct ub_randstate* rnd, int n, int m);
 void iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp);
 
 /**
- * See if query is in-zone glue and we suspect that it exists.
- * Suspicion that it exists, is if there is no A or AAAA in cache (since
- * one of them is expected for an NS record) or the qtype is in cache but
- * was recently expired (so we have seen this data recently).
- * @param qinfo: query info.
- * @param dp: delegation point we are at.
- * @param env: environment with rrset cache.
- * @return true if suspect that this glue exists.
+ * Mark targets that result in a dependency cycle as done, so they
+ * will not get selected as targets.  For the parent-side lookups.
+ * @param qstate: query state.
+ * @param dp: delegpt to mark ns in.
  */
-int iter_suspect_exists(struct query_info* qinfo, struct delegpt* dp,
-       struct module_env* env);
+void iter_mark_pside_cycle_targets(struct module_qstate* qstate,
+       struct delegpt* dp);
 
 /**
  * See if delegation is useful or offers immediately no targets for 
@@ -217,26 +213,63 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
 int reply_equal(struct reply_info* p, struct reply_info* q, ldns_buffer* buf);
 
 /**
- * Store in-zone glue in seperate rrset cache entries for later last-resort
- * lookups in case the child-side versions of this information fails.
+ * Store parent-side rrset in seperate rrset cache entries for later 
+ * last-resort * lookups in case the child-side versions of this information 
+ * fails.
  * @param env: environment with cache, time, ...
- * @param qinfo: query info. must match the information stored to avoid
- *     Kaminsky-style trouble.
- * @param rep: reply with possibly A or AAAA content to store.
+ * @param rrset: the rrset to store (copied).
+ * Failure to store is logged, but otherwise ignored.
  */
-void iter_store_inzone_glue(struct module_env* env, struct query_info* qinfo,
-       struct reply_info* rep);
+void iter_store_parentside_rrset(struct module_env* env, 
+       struct ub_packed_rrset_key* rrset);
 
 /**
- * Find in-zone glue from rrset cache again.
+ * Store parent-side NS records from a referral message
+ * @param env: environment with cache, time, ...
+ * @param rep: response with NS rrset.
+ * Failure to store is logged, but otherwise ignored.
+ */
+void iter_store_parentside_NS(struct module_env* env, struct reply_info* rep);
+
+/**
+ * Store parent-side negative element, the parentside rrset does not exist,
+ * creates an rrset with empty rdata in the rrset cache with PARENTSIDE flag.
+ * @param env: environment with cache, time, ...
+ * @param qinfo: the identity of the rrset that is missing.
+ * @param rep: delegation response or answer response, to glean TTL from.
+ * (malloc) failure is logged but otherwise ignored.
+ */
+void iter_store_parentside_neg(struct module_env* env, 
+       struct query_info* qinfo, struct reply_info* rep);
+
+/**
+ * Add parent NS record if that exists in the cache.  This is both new
+ * information and acts like a timeout throttle on retries.
  * @param env: query env with rrset cache and time.
- * @param dp: delegation point to store result in.
+ * @param dp: delegation point to store result in.  Also this dp is used to
+ *     see which NS name is needed.
  * @param region: region to alloc result in.
- * @param qinfo: query into that is pertinent.
+ * @param qinfo: pertinent information, the qclass.
  * @return false on malloc failure.
+ *     if true, the routine worked and if such cached information 
+ *     existed dp->has_parent_side_NS is set true.
+ */
+int iter_lookup_parent_NS_from_cache(struct module_env* env,
+       struct delegpt* dp, struct regional* region, struct query_info* qinfo);
+
+/**
+ * Add parent-side glue if that exists in the cache.  This is both new
+ * information and acts like a timeout throttle on retries to fetch them.
+ * @param env: query env with rrset cache and time.
+ * @param dp: delegation point to store result in.  Also this dp is used to
+ *     see which NS name is needed.
+ * @param region: region to alloc result in.
+ * @param qinfo: pertinent information, the qclass.
+ * @return: true, it worked, no malloc failures, and new addresses (lame)
+ *     have been added, giving extra options as query targets.
  */
-int iter_lookup_inzone_glue(struct module_env* env, struct delegpt* dp,
-       struct regional* region, struct query_info* qinfo);
+int iter_lookup_parent_glue_from_cache(struct module_env* env,
+       struct delegpt* dp, struct regional* region, struct query_info* qinfo);
 
 /**
  * Lookup next root-hint or root-forward entry.
index ce0e6419b5d14617b41581eeaac3864cf4955e9e..c9815fb56c1deebf9ea090365b59c956999799cf 100644 (file)
@@ -1211,8 +1211,9 @@ processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq,
 }
 
 /**
- * Given a basic query, generate a "target" query. These are subordinate
- * queries for missing delegation point target addresses.
+ * Given a basic query, generate a parent-side "target" query. 
+ * These are subordinate queries for missing delegation point target addresses,
+ * for which only the parent of the delegation provides correct IP addresses.
  *
  * @param qstate: query state.
  * @param iq: iterator query state.
@@ -1224,8 +1225,9 @@ processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq,
  * @return true on success, false on failure.
  */
 static int
-generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
-        int id, uint8_t* name, size_t namelen, uint16_t qtype, uint16_t qclass)
+generate_parentside_target_query(struct module_qstate* qstate, 
+       struct iter_qstate* iq, int id, uint8_t* name, size_t namelen, 
+       uint16_t qtype, uint16_t qclass)
 {
        struct module_qstate* subq;
        if(!generate_sub_request(name, namelen, qtype, qclass, qstate, 
@@ -1234,15 +1236,53 @@ generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
        if(subq) {
                struct iter_qstate* subiq = 
                        (struct iter_qstate*)subq->minfo[id];
+               /* blacklist the cache - we want to fetch parent stuff */
+               sock_list_insert(&subq->blacklist, NULL, 0, subq->region);
+               subiq->query_for_pside_glue = 1;
                if(dname_subdomain_c(name, iq->dp->name)) {
-                       verbose(VERB_ALGO, "refetch of target glue");
-                       subiq->refetch_glue = 1;
                        subiq->dp = delegpt_copy(iq->dp, subq->region);
                        subiq->dnssec_expected = iter_indicates_dnssec(
                                qstate->env, subiq->dp, NULL, 
                                subq->qinfo.qclass);
+                       subiq->refetch_glue = 1;
+               } else {
+                       subiq->dp = dns_cache_find_delegation(qstate->env, 
+                               name, namelen, qtype, qclass, subq->region,
+                               &subiq->deleg_msg, *qstate->env->now); 
+                       /* if no dp, then it's from root, refetch unneeded */
+                       if(subiq->dp) { 
+                               subiq->dnssec_expected = iter_indicates_dnssec(
+                                       qstate->env, subiq->dp, NULL, 
+                                       subq->qinfo.qclass);
+                               subiq->refetch_glue = 1;
+                       }
                }
        }
+       log_nametypeclass(VERB_QUERY, "new pside target", name, qtype, qclass);
+       return 1;
+}
+
+/**
+ * Given a basic query, generate a "target" query. These are subordinate
+ * queries for missing delegation point target addresses.
+ *
+ * @param qstate: query state.
+ * @param iq: iterator query state.
+ * @param id: module id.
+ * @param name: target qname.
+ * @param namelen: target qname length.
+ * @param qtype: target qtype (either A or AAAA).
+ * @param qclass: target qclass.
+ * @return true on success, false on failure.
+ */
+static int
+generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
+        int id, uint8_t* name, size_t namelen, uint16_t qtype, uint16_t qclass)
+{
+       struct module_qstate* subq;
+       if(!generate_sub_request(name, namelen, qtype, qclass, qstate, 
+               id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0))
+               return 0;
        log_nametypeclass(VERB_QUERY, "new target", name, qtype, qclass);
        return 1;
 }
@@ -1331,6 +1371,99 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
        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
+ * options are explored.  If there are no more options, the result is SERVFAIL
+ *
+ * @param qstate: query state.
+ * @param iq: iterator query state.
+ * @param ie: iterator shared global environment.
+ * @param id: module id.
+ * @return true if the event requires more request processing immediately,
+ *         false if not. 
+ */
+static int
+processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
+       struct iter_env* ie, int id)
+{
+       struct delegpt_ns* ns;
+       int query_count = 0;
+       verbose(VERB_ALGO, "No more query targets, attempting last resort");
+       log_assert(iq->dp);
+
+       if(!iq->dp->has_parent_side_NS) {
+               if(!iter_lookup_parent_NS_from_cache(qstate->env, iq->dp,
+                       qstate->region, &qstate->qinfo) 
+                       || !iq->dp->has_parent_side_NS) {
+                       /* if: malloc failure in lookup go up to try */
+                       /* if: no parent NS in cache - go up one level */
+                       verbose(VERB_ALGO, "try to grab parent NS");
+                       iq->store_parent_NS = 1;
+                       iq->deleg_msg = NULL;
+                       iq->refetch_glue = 1;
+                       iq->query_restart_count++;
+                       return next_state(iq, INIT_REQUEST_STATE);
+               }
+       }
+       /* try to fill out parent glue from cache */
+       if(iter_lookup_parent_glue_from_cache(qstate->env, iq->dp,
+               qstate->region, &qstate->qinfo)) {
+               /* got parent stuff from cache, see if we can continue */
+               verbose(VERB_ALGO, "try parent-side glue from cache");
+               return next_state(iq, QUERYTARGETS_STATE);
+       }
+       /* query for an extra name added by the parent-NS record */
+       if(delegpt_count_missing_targets(iq->dp) > 0) {
+               int qs = 0;
+               verbose(VERB_ALGO, "try parent-side target name");
+               if(!query_for_targets(qstate, iq, ie, id, 1, &qs)) {
+                       return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+               }
+               iq->num_target_queries += qs;
+               if(qs != 0)
+                       return 0; /* and wait for them */
+       }
+       /* mark cycle targets for parent-side lookups */
+       iter_mark_pside_cycle_targets(qstate, iq->dp);
+       /* see if we can issue queries to get nameserver addresses */
+       /* this lookup is not randomized, but sequential. */
+       for(ns = iq->dp->nslist; ns; ns = ns->next) {
+               /* query for parent-side A and AAAA for nameservers */
+               if(ie->supports_ipv6 && !ns->done_pside6) {
+                       /* Send the AAAA request. */
+                       if(!generate_parentside_target_query(qstate, iq, id, 
+                               ns->name, ns->namelen,
+                               LDNS_RR_TYPE_AAAA, iq->qchase.qclass))
+                               return error_response(qstate, id,
+                                       LDNS_RCODE_SERVFAIL);
+                       ns->done_pside6 = 1;
+                       query_count++;
+               }
+               if(!ns->done_pside4) {
+                       /* Send the A request. */
+                       if(!generate_parentside_target_query(qstate, iq, id, 
+                               ns->name, ns->namelen, 
+                               LDNS_RR_TYPE_A, iq->qchase.qclass))
+                               return error_response(qstate, id,
+                                       LDNS_RCODE_SERVFAIL);
+                       ns->done_pside4 = 1;
+                       query_count++;
+               }
+               if(query_count != 0) { /* suspend to await results */
+                       verbose(VERB_ALGO, "try parent-side glue lookup");
+                       iq->num_target_queries += query_count;
+                       qstate->ext_state[id] = module_wait_subquery;
+                       return 0;
+               }
+       }
+
+       verbose(VERB_QUERY, "out of query targets -- returning SERVFAIL");
+       /* fail -- no more targets, no more hope of targets, no hope 
+        * of a response. */
+       return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
+}
+
 /** 
  * This is the request event state where the request will be sent to one of
  * its current query targets. This state also handles issuing target lookup
@@ -1493,39 +1626,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                        /* Since a target query might have been made, we 
                         * need to check again. */
                        if(iq->num_target_queries == 0) {
-                               /* is it glue and we suspect that it exists?*/
-                               if(iter_suspect_exists(&iq->qchase, iq->dp, 
-                                       qstate->env)) {
-                                       /* try at parent */
-                                       iq->deleg_msg = NULL;
-                                       iq->refetch_glue = 1;
-                                       iq->query_restart_count++;
-                                       return next_state(iq, 
-                                               INIT_REQUEST_STATE);
-                               }
-                               /* is the current dp useless, like it would
-                                * be classified useless if picked from the
-                                * cache like this? If so, go back up */
-                               if(iter_dp_is_useless(&qstate->qinfo, 
-                                       qstate->query_flags, iq->dp) && 
-                                       !iq->dp->target_list) {
-                                       /* extra target list check because
-                                        * those become available again when
-                                        * lookup up from the cache */
-                                       verbose(VERB_QUERY, "delegation is "
-                                               "useless, try higher up");
-                                       iq->deleg_msg = NULL;
-                                       iq->query_restart_count++;
-                                       return next_state(iq, 
-                                               INIT_REQUEST_STATE);
-                               }
-
-                               verbose(VERB_QUERY, "out of query targets -- "
-                                       "returning SERVFAIL");
-                               /* fail -- no more targets, no more hope 
-                                * of targets, no hope of a response. */
-                               return error_response_cache(qstate, id,
-                                       LDNS_RCODE_SERVFAIL);
+                               return processLastResort(qstate, iq, ie, id);
                        }
                }
 
@@ -1709,15 +1810,24 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
                                iq->response->rep, 1, 0))
                                return error_response(qstate, id, 
                                        LDNS_RCODE_SERVFAIL);
+                       if(iq->store_parent_NS)
+                               iter_store_parentside_NS(qstate->env, 
+                                       iq->response->rep);
                        if(qstate->env->neg_cache)
                                val_neg_addreferral(qstate->env->neg_cache, 
                                        iq->response->rep, iq->dp->name);
                }
                /* store parent-side-in-zone-glue, if directly queried for */
-               if((qstate->qinfo.qtype == LDNS_RR_TYPE_A
-                       || qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA)) {
-                       iter_store_inzone_glue(qstate->env,
-                               &iq->response->qinfo, iq->response->rep);
+               if(iq->query_for_pside_glue && !iq->pside_glue) {
+                       iq->pside_glue = reply_find_rrset(iq->response->rep, 
+                               iq->qchase.qname, iq->qchase.qname_len, 
+                               iq->qchase.qtype, iq->qchase.qclass);
+                       if(iq->pside_glue) {
+                               log_rrset_key(VERB_ALGO, "found parent-side "
+                                       "glue", iq->pside_glue);
+                               iter_store_parentside_rrset(qstate->env,
+                                       iq->pside_glue);
+                       }
                }
 
                /* Reset the event state, setting the current delegation 
@@ -2007,10 +2117,17 @@ processTargetResponse(struct module_qstate* qstate, int id,
         * (regardless if it succeeded or not). */
        foriq->num_target_queries--;
 
-       /* perhaps we picked up interested cached addressed, like lame ones */
-       if(!iter_lookup_inzone_glue(forq->env, foriq->dp, forq->region, 
-               &iq->qchase))
-               log_err("out of memory adding lame glue");
+       /* if iq->query_for_pside_glue then add the pside_glue (marked lame) */
+       if(iq->pside_glue) {
+               /* if the pside_glue is NULL, then it could not be found,
+                * the done_pside is already set when created and a cache
+                * entry created in processFinished so nothing to do here */
+               log_rrset_key(VERB_ALGO, "add parentside glue to dp", 
+                       iq->pside_glue);
+               if(!delegpt_add_rrset(foriq->dp, forq->region, 
+                       iq->pside_glue, 1))
+                       log_err("out of memory adding pside glue");
+       }
 
        /* This response is relevant to the current query, so we 
         * add (attempt to add, anyway) this target(s) and reactivate 
@@ -2023,11 +2140,14 @@ processTargetResponse(struct module_qstate* qstate, int id,
                /* BTW. RFC 1918 says NS should not have got CNAMEs. Robust. */
                if(!delegpt_find_ns(foriq->dp, rrset->rk.dname, 
                        rrset->rk.dname_len)) {
+                       /* if dpns->lame then set newcname ns lame too */
                        if(!delegpt_add_ns(foriq->dp, forq->region, 
-                               rrset->rk.dname))
+                               rrset->rk.dname, (int)dpns->lame))
                                log_err("out of memory adding cnamed-ns");
                }
-               if(!delegpt_add_rrset(foriq->dp, forq->region, rrset))
+               /* if dpns->lame then set the address(es) lame too */
+               if(!delegpt_add_rrset(foriq->dp, forq->region, rrset, 
+                       (int)dpns->lame))
                        log_err("out of memory adding targets");
                verbose(VERB_ALGO, "added target response");
                delegpt_log(VERB_ALGO, foriq->dp);
@@ -2202,6 +2322,11 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
        log_query_info(VERB_QUERY, "finishing processing for", 
                &qstate->qinfo);
 
+       /* store negative cache element for parent side glue. */
+       if(iq->query_for_pside_glue && !iq->pside_glue)
+               iter_store_parentside_neg(qstate->env, &qstate->qinfo,
+                       iq->deleg_msg?iq->deleg_msg->rep:
+                       (iq->response?iq->response->rep:NULL));
        if(!iq->response) {
                verbose(VERB_ALGO, "No response is set, servfail");
                return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
index 350fb1d102caaa0fe0894fb1235b3cf578209850..407d6c5984be3e1eceac389aaf692e1eadd18a4b 100644 (file)
@@ -247,6 +247,24 @@ struct iter_qstate {
        /** the number of times this query as followed a referral. */
        int referral_count;
 
+       /**
+        * The query must store NS records from referrals as parentside RRs
+        * Enabled once it hits resolution problems, to throttle retries.
+        */
+       int store_parent_NS;
+
+       /**
+        * The query is for parent-side glue(A or AAAA) for a nameserver.
+        * If the item is seen as glue in a referral, and pside_glue is NULL,
+        * then it is stored in pside_glue for later.
+        * If it was never seen, at the end, then a negative caching element 
+        * must be created.  
+        * The (data or negative) RR cache element then throttles retries.
+        */
+       int query_for_pside_glue;
+       /** the parent-side-glue element (NULL if none, its first match) */
+       struct ub_packed_rrset_key* pside_glue;
+
        /** 
         * expected dnssec information for this iteration step. 
         * If dnssec rrsigs are expected and not given, the server is marked
index 057fa3e768524e6978b8936d1ed641a03084063a..709e37fc03816a69834641e7e43f9fbaa8ab9f2c 100644 (file)
@@ -213,27 +213,6 @@ find_add_addrs(struct module_env* env, uint16_t qclass,
                                lock_rw_unlock(&neg->entry.lock);
                        }
                }
-               /* see if we have parent-side-glue (dispreferred) */
-               akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
-                       ns->namelen, LDNS_RR_TYPE_A, qclass, 
-                       PACKED_RRSET_PARENT_SIDE, now, 0);
-               if(akey) {
-                       if(!delegpt_add_rrset_A(dp, region, akey, 1, 1)) {
-                               lock_rw_unlock(&akey->entry.lock);
-                               return 0;
-                       }
-                       lock_rw_unlock(&akey->entry.lock);
-               }
-               akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
-                       ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 
-                       PACKED_RRSET_PARENT_SIDE, now, 0);
-               if(akey) {
-                       if(!delegpt_add_rrset_AAAA(dp, region, akey, 1, 1)) {
-                               lock_rw_unlock(&akey->entry.lock);
-                               return 0;
-                       }
-                       lock_rw_unlock(&akey->entry.lock);
-               }
        }
        return 1;
 }
@@ -284,27 +263,6 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
                                lock_rw_unlock(&neg->entry.lock);
                        }
                }
-               /* see if we have parent-side-glue (dispreferred) */
-               akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
-                       ns->namelen, LDNS_RR_TYPE_A, qclass, 
-                       PACKED_RRSET_PARENT_SIDE, now, 0);
-               if(akey) {
-                       if(!delegpt_add_rrset_A(dp, region, akey, 1, 1)) {
-                               lock_rw_unlock(&akey->entry.lock);
-                               return 0;
-                       }
-                       lock_rw_unlock(&akey->entry.lock);
-               }
-               akey = rrset_cache_lookup(env->rrset_cache, ns->name, 
-                       ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 
-                       PACKED_RRSET_PARENT_SIDE, now, 0);
-               if(akey) {
-                       if(!delegpt_add_rrset_AAAA(dp, region, akey, 1, 1)) {
-                               lock_rw_unlock(&akey->entry.lock);
-                               return 0;
-                       }
-                       lock_rw_unlock(&akey->entry.lock);
-               }
        }
        return 1;
 }
@@ -420,7 +378,7 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
                        return NULL;
                }
        }
-       if(!delegpt_rrset_add_ns(dp, region, nskey))
+       if(!delegpt_rrset_add_ns(dp, region, nskey, 0))
                log_err("find_delegation: addns out of memory");
        lock_rw_unlock(&nskey->entry.lock); /* first unlock before next lookup*/
        /* find and add DS/NSEC (if any) */
index 7224704fe1b76642797f772d071debb2f2f4779d..3605fa13c198d2e1cee3a5007c3a19a301b4621a 100644 (file)
@@ -76,6 +76,21 @@ example.com. 3600    IN      RRSIG   NS 5 2 3600 20090924111500 20090821111500 30899 examp
 SECTION ADDITIONAL
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id
+REPLY QR AA
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.        3600    IN      A       1.2.3.4
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20090924111500 20090821111500 30899 example.com. JsXbS18oyc0zkVaOWGSFdIQuOsZKflT0GraT9afDPoWLCgH4ApF7jNgfJV7Pqy1sTBRajME5IUAhpANwGBuW4A== ;{id = 30899}
+SECTION AUTHORITY
+example.com.   3600    IN      NS      ns.example.com.
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20090924111500 20090821111500 30899 example.com. J5wxRq0jgwQL6yy530kvo9cHqNAUHV8IF4dvaYZL0bNraO2Oe6dVXqlJl4+cxNHI2TMsstwFPr2Zz8tv6Az2mQ== ;{id = 30899}
+SECTION ADDITIONAL
+ENTRY_END
+
 ENTRY_BEGIN
 MATCH opcode qname qtype
 ADJUST copy_id
index 0d9517098b1e974133b1ebfb9273db9a925e2979..f0fab861ef44f84af7e2deb077ffa36019f79abb 100644 (file)
@@ -77,6 +77,21 @@ ns.example.com. IN AAAA
 SECTION ANSWER
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id
+REPLY QR AA
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.        3600    IN      A       1.2.3.4
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20090924111500 20090821111500 30899 example.com. JsXbS18oyc0zkVaOWGSFdIQuOsZKflT0GraT9afDPoWLCgH4ApF7jNgfJV7Pqy1sTBRajME5IUAhpANwGBuW4A== ;{id = 30899}
+SECTION AUTHORITY
+example.com.   3600    IN      NS      ns.example.com.
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20090924111500 20090821111500 30899 example.com. J5wxRq0jgwQL6yy530kvo9cHqNAUHV8IF4dvaYZL0bNraO2Oe6dVXqlJl4+cxNHI2TMsstwFPr2Zz8tv6Az2mQ== ;{id = 30899}
+SECTION ADDITIONAL
+ENTRY_END
+
 ENTRY_BEGIN
 MATCH opcode qname qtype
 ADJUST copy_id
index ad7045355862d5748b7cc476e86cbf16b93062c3..5274848aceae77d146c23f9c7d397a1edddb3245 100644 (file)
@@ -141,6 +141,20 @@ RANGE_END
 ; ns.example.com.  KSK 55582 and 60946 (signatures updated)
 RANGE_BEGIN 41 50
        ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id
+REPLY QR AA
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.        3600    IN      A       1.2.3.4
+ns.example.com.        3600    IN      RRSIG   A 5 3 3600 20090924111500 20090821111500 30899 example.com. JsXbS18oyc0zkVaOWGSFdIQuOsZKflT0GraT9afDPoWLCgH4ApF7jNgfJV7Pqy1sTBRajME5IUAhpANwGBuW4A== ;{id = 30899}
+SECTION AUTHORITY
+example.com.   3600    IN      NS      ns.example.com.
+example.com.   3600    IN      RRSIG   NS 5 2 3600 20090924111500 20090821111500 30899 example.com. J5wxRq0jgwQL6yy530kvo9cHqNAUHV8IF4dvaYZL0bNraO2Oe6dVXqlJl4+cxNHI2TMsstwFPr2Zz8tv6Az2mQ== ;{id = 30899}
+SECTION ADDITIONAL
+ENTRY_END
 
 ENTRY_BEGIN
 MATCH opcode qname qtype
index f40e5967f6f5562edcc5f483d4cbb75a9429642b..8afef770ff6bd05dd3a54184994faa41900e4928 100644 (file)
@@ -78,6 +78,15 @@ ns.example.com. IN AAAA
 SECTION ANSWER
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ENTRY_END
+
 ENTRY_BEGIN
 MATCH opcode qtype qname
 ADJUST copy_id
index 1bdcf48aebc04d971783d71cd6023f9fcd411198..5fe6b8af3d1c8b1e69dea9d8db47ef6a7e7b59a8 100644 (file)
@@ -41,6 +41,16 @@ SECTION QUESTION
 a.gtld-servers.net. IN AAAA
 SECTION ANSWER
 ENTRY_END
+ENTRY_BEGIN
+
+MATCH opcode qtype qname
+ADJUST copy_id 
+REPLY QR NOERROR
+SECTION QUESTION
+a.gtld-servers.net. IN A
+SECTION ANSWER
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
 RANGE_END
 
 ; a.gtld-servers.net.
index 59110a5f178ecbcc2e25d6e59ae24b3d0edf2590..24de1e367f22b333b6747614fd8be13b24c86e47 100644 (file)
@@ -177,6 +177,29 @@ SECTION ADDITIONAL
 A.ROOT-SERVERS.NET.    IN      A       198.41.0.4
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+A.ROOT-SERVERS.NET.    IN      A
+SECTION ANSWER
+A.ROOT-SERVERS.NET.    IN      A       198.41.0.4
+SECTION AUTHORITY
+ROOT-SERVERS.NET.      IN      NS A.ROOT-SERVERS.NET.
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+A.ROOT-SERVERS.NET.    IN      AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+ROOT-SERVERS.NET.      IN      NS A.ROOT-SERVERS.NET.
+ENTRY_END
+
 ENTRY_BEGIN
 MATCH opcode qtype qname
 ADJUST copy_id
index 5687cf87ae9f27cf1846e5bad915aa498941ec17..06517756241453bd292d08831dcac113db3b14b3 100644 (file)
@@ -101,6 +101,18 @@ SECTION ADDITIONAL
 ns.example.com.                IN      A       1.2.3.4
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.                IN      A       1.2.3.4
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+ENTRY_END
+
 ENTRY_BEGIN
 MATCH opcode qtype qname
 ADJUST copy_id
index 8ff513d4787eda0e250b6cdb8e3ca50044982e2d..43b27f1868ea744a28395daf744875ccfca2b903 100644 (file)
@@ -121,6 +121,20 @@ ns.example.com.         IN      A       1.2.3.4
 ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+SECTION AUTHORITY
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+ENTRY_END
+
 ENTRY_BEGIN
 MATCH opcode qtype qname
 ADJUST copy_id
index e5e1c194aa4a83d6286b1349a30507a7eb0d50bf..1c9fb77513682b7ccfd1f560e9f8565d3249f02a 100644 (file)
@@ -80,6 +80,22 @@ RANGE_END
 ; ns.example.com.
 RANGE_BEGIN 0 100
        ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION ANSWER
+; not legal NOERROR/NODATA response, but leniently accepted (not validated)
+SECTION AUTHORITY
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
 ENTRY_BEGIN
 MATCH opcode qtype qname
 ADJUST copy_id
index 9b63081bb568750857889385d94c1be4ea4de4ac..1d154591fe05067f36fa44c6bcad8071c3a5996e 100644 (file)
@@ -86,6 +86,20 @@ ns.example.com.         IN      A       1.2.3.4
 ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+SECTION AUTHORITY
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+ENTRY_END
+
 ; response to DNSKEY priming query
 ENTRY_BEGIN
 MATCH opcode qtype qname
index 125aaf1a9f278ed8d99d04723fbafd03101c0c0a..5bd6db261d7632d4927d5c4b1902e873e3a775a0 100644 (file)
@@ -86,6 +86,21 @@ ns.example.com.         IN      A       1.2.3.4
 ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+SECTION AUTHORITY
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+ENTRY_END
+
+
 ; response to DNSKEY priming query
 ENTRY_BEGIN
 MATCH opcode qtype qname
index 77780d613683d0ab33ab6eba6f782a1ff2651bf7..fd5b23e668930396541ef41128bec7052fb3be7b 100644 (file)
@@ -258,6 +258,14 @@ sec_status_to_string(enum sec_status s)
        return "unknown_sec_status_value";
 }
 
+void log_rrset_key(enum verbosity_value v, const char* str, 
+       struct ub_packed_rrset_key* rrset)
+{
+       if(verbosity >= v)
+               log_nametypeclass(v, str, rrset->rk.dname,
+                       ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
+}
+
 uint32_t 
 ub_packed_rrset_ttl(struct ub_packed_rrset_key* key)
 {
index da06725bc7de6a738a7213191aa91aa00bd8553e..2171ecbb054e1fcbf0b70f6ac950dc98abc51e7c 100644 (file)
@@ -368,6 +368,15 @@ const char* rrset_trust_to_string(enum rrset_trust s);
  */
 const char* sec_status_to_string(enum sec_status s);
 
+/**
+ * Print string with neat domain name, type, class from rrset.
+ * @param v: at what verbosity level to print this.
+ * @param str: string of message.
+ * @param rrset: structure with name, type and class.
+ */
+void log_rrset_key(enum verbosity_value v, const char* str, 
+       struct ub_packed_rrset_key* rrset);
+
 /** 
  * Allocate rrset in region - no more locks needed 
  * @param key: a (just from rrset cache looked up) rrset key + valid,