From: Wouter Wijngaards Date: Fri, 28 May 2010 14:15:29 +0000 (+0000) Subject: parent-child misconfigured data lookup. X-Git-Tag: release-1.4.5rc1~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6d77834955c2343a6d1a255fecd716aa2d17da86;p=thirdparty%2Funbound.git parent-child misconfigured data lookup. git-svn-id: file:///svn/unbound/trunk@2119 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index dd75d6766..1e1af754b 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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 diff --git a/iterator/iter_delegpt.c b/iterator/iter_delegpt.c index 20284cf9e..28dac7c76 100644 --- a/iterator/iter_delegpt.c +++ b/iterator/iter_delegpt.c @@ -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; } diff --git a/iterator/iter_delegpt.h b/iterator/iter_delegpt.h index bdea325d2..b779abc94 100644 --- a/iterator/iter_delegpt.h +++ b/iterator/iter_delegpt.h @@ -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 * diff --git a/iterator/iter_fwd.c b/iterator/iter_fwd.c index f0fca1edd..1c476f05d 100644 --- a/iterator/iter_fwd.c +++ b/iterator/iter_fwd.c @@ -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)) diff --git a/iterator/iter_hints.c b/iterator/iter_hints.c index bf7406842..da6fa8314 100644 --- a/iterator/iter_hints.c +++ b/iterator/iter_hints.c @@ -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; } diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index ee3e7e771..8d539a82a 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -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; irrset_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) diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index d3870ecd3..e8c5d04f2 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -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. diff --git a/iterator/iterator.c b/iterator/iterator.c index ce0e6419b..c9815fb56 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -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); diff --git a/iterator/iterator.h b/iterator/iterator.h index 350fb1d10..407d6c598 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -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 diff --git a/services/cache/dns.c b/services/cache/dns.c index 057fa3e76..709e37fc0 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -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) */ diff --git a/testdata/autotrust_init_fail.rpl b/testdata/autotrust_init_fail.rpl index 7224704fe..3605fa13c 100644 --- a/testdata/autotrust_init_fail.rpl +++ b/testdata/autotrust_init_fail.rpl @@ -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 diff --git a/testdata/autotrust_probefail.rpl b/testdata/autotrust_probefail.rpl index 0d9517098..f0fab861e 100644 --- a/testdata/autotrust_probefail.rpl +++ b/testdata/autotrust_probefail.rpl @@ -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 diff --git a/testdata/autotrust_valid_use.rpl b/testdata/autotrust_valid_use.rpl index ad7045355..5274848ac 100644 --- a/testdata/autotrust_valid_use.rpl +++ b/testdata/autotrust_valid_use.rpl @@ -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 diff --git a/testdata/iter_lame_aaaa.rpl b/testdata/iter_lame_aaaa.rpl index f40e5967f..8afef770f 100644 --- a/testdata/iter_lame_aaaa.rpl +++ b/testdata/iter_lame_aaaa.rpl @@ -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 diff --git a/testdata/iter_lamescrub.rpl b/testdata/iter_lamescrub.rpl index 1bdcf48ae..5fe6b8af3 100644 --- a/testdata/iter_lamescrub.rpl +++ b/testdata/iter_lamescrub.rpl @@ -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. diff --git a/testdata/iter_primenoglue.rpl b/testdata/iter_primenoglue.rpl index 59110a5f1..24de1e367 100644 --- a/testdata/iter_primenoglue.rpl +++ b/testdata/iter_primenoglue.rpl @@ -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 diff --git a/testdata/iter_privaddr.rpl b/testdata/iter_privaddr.rpl index 5687cf87a..065177562 100644 --- a/testdata/iter_privaddr.rpl +++ b/testdata/iter_privaddr.rpl @@ -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 diff --git a/testdata/val_dnametoolong.rpl b/testdata/val_dnametoolong.rpl index 8ff513d47..43b27f186 100644 --- a/testdata/val_dnametoolong.rpl +++ b/testdata/val_dnametoolong.rpl @@ -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 diff --git a/testdata/val_ds_cname.rpl b/testdata/val_ds_cname.rpl index e5e1c194a..1c9fb7751 100644 --- a/testdata/val_ds_cname.rpl +++ b/testdata/val_ds_cname.rpl @@ -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 diff --git a/testdata/val_faildnskey.rpl b/testdata/val_faildnskey.rpl index 9b63081bb..1d154591f 100644 --- a/testdata/val_faildnskey.rpl +++ b/testdata/val_faildnskey.rpl @@ -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 diff --git a/testdata/val_faildnskey_ok.rpl b/testdata/val_faildnskey_ok.rpl index 125aaf1a9..5bd6db261 100644 --- a/testdata/val_faildnskey_ok.rpl +++ b/testdata/val_faildnskey_ok.rpl @@ -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 diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c index 77780d613..fd5b23e66 100644 --- a/util/data/packed_rrset.c +++ b/util/data/packed_rrset.c @@ -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) { diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h index da06725bc..2171ecbb0 100644 --- a/util/data/packed_rrset.h +++ b/util/data/packed_rrset.h @@ -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,