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
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,
}
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;
ns->resolved = 0;
ns->got4 = 0;
ns->got6 = 0;
+ ns->lame = (uint8_t)lame;
+ ns->done_pside4 = 0;
+ ns->done_pside6 = 0;
return 1;
}
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 = " ";
}
}
+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)
{
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 */
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;
(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;
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;
}
/** 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;
};
/**
* 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;
};
/**
* @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.
* @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.
*/
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
*
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;
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))
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)) {
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) {
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;
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))
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);
}
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;
}
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,
}
}
+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)
}
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)
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
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.
}
/**
- * 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.
* @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,
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;
}
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
/* 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);
}
}
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
* (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
/* 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);
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);
/** 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
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;
}
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;
}
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) */
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
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
; 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
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
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.
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
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
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
; 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
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
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
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)
{
*/
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,