struct alloc_cache superalloc;
/** the message cache, content is struct msgreply_entry* */
struct slabhash* msg_cache;
- /** the rrset cache, content is struct struct ub_packed_rrset_key* */
+ /** the rrset cache, content is struct ub_packed_rrset_key* */
struct slabhash* rrset_cache;
};
query_info_clear(&w->qinfo);
}
+/** see if rrset needs to be updated in the cache */
+static int
+need_to_update_rrset(struct packed_rrset_data* newd,
+ struct packed_rrset_data* cached)
+{
+ if( newd->trust > cached->trust )
+ return 1;
+ if( newd->ttl > cached->ttl &&
+ rrsetdata_equal(newd, cached))
+ return 1;
+ return 0;
+}
+
/** store rrsets in the rrset cache. */
static void
worker_store_rrsets(struct worker* worker, struct reply_info* rep)
{
+ struct lruhash_entry* e;
size_t i;
+ /* see if rrset already exists in cache, if not insert it. */
+ /* if it does exist: */
+ /* o if current RRset is more trustworthy - insert it */
+ /* o see if TTL is better than TTL in cache. */
+ /* if so, see if rrset+rdata is (exactly!) the same */
+ /* if so, update TTL in cache. */
for(i=0; i<rep->rrset_count; i++) {
- /* TODO: check if update really needed */
+ rep->ref[i].key = rep->rrsets[i];
+ rep->ref[i].id = rep->rrsets[i]->id;
+ /* looks up item with a readlock - no editing! */
+ if((e=slabhash_lookup(worker->daemon->rrset_cache,
+ rep->rrsets[i]->entry.hash, rep->rrsets[i]->entry.key,
+ 0)) != 0) {
+ struct packed_rrset_data* data =
+ (struct packed_rrset_data*)e->data;
+ struct packed_rrset_data* rd =
+ (struct packed_rrset_data*)
+ rep->rrsets[i]->entry.data;
+ rep->ref[i].key = (struct ub_packed_rrset_key*)e->key;
+ rep->ref[i].id = rep->rrsets[i]->id;
+ /* found in cache, do checks above */
+ if(!need_to_update_rrset(rd, data)) {
+ lock_rw_unlock(&e->lock);
+ ub_packed_rrset_parsedelete(rep->rrsets[i],
+ &worker->alloc);
+ rep->rrsets[i] = rep->ref[i].key;
+ continue; /* use cached item instead */
+ }
+ if(rd->trust < data->trust)
+ rd->trust = data->trust;
+ lock_rw_unlock(&e->lock);
+ /* small gap here, where entry is not locked.
+ * possibly entry is updated with something else.
+ * this is just too bad, its cache anyway. */
+ /* use insert to update entry to manage lruhash
+ * cache size values nicely. */
+ }
slabhash_insert(worker->daemon->rrset_cache,
rep->rrsets[i]->entry.hash, &rep->rrsets[i]->entry,
rep->rrsets[i]->entry.data, &worker->alloc);
+ /* TODO store correct key and id */
}
}
}
reply_info_set_ttls(rep, time(0));
worker_store_rrsets(w->worker, rep);
- reply_info_fillref(rep);
+ reply_info_sortref(rep);
/* store msg in the cache */
if(!(e = query_info_entrysetup(&qinf, rep, w->query_hash))) {
query_info_clear(&qinf);
- config settings for rrset cache size and slabs.
- hashtable insert takes argument so that a thread can use its own
alloc cache to store released keys.
+ - alloc cache special_release() locks if necessary.
+ - rrset trustworthiness type added.
3 May 2007: Wouter
- fill refs. Use new parse and encode to answer queries.
start to send out compressed AXFRs then it becomes a problem.
We can cap AXFR packets on 256 or 1024 domain names, for example.
o speed up pkt domain name decompression loop detection using counter perhaps.
+o detect OS/400 pthreads implementation that allows upgrading to writelock
+ on pthreads rwlocks and use it to examine-rd before storing-wr rrset cache.
data->ttl = MAX_TTL;
data->count = pset->rr_count;
data->rrsig_count = pset->rrsig_count;
+ data->trust = rrset_trust_none;
/* layout: struct - rr_len - rr_data - rdata - rrsig */
data->rr_len = (size_t*)((uint8_t*)data +
sizeof(struct packed_rrset_data));
return 0;
}
+/** get trust value for rrset */
+static enum rrset_trust
+get_rrset_trust(struct reply_info* rep, size_t i)
+{
+ uint16_t AA = rep->flags & BIT_AA;
+ /* TODO: need scrubber that knows what zone the server serves, so that
+ * it can check if AA bit is warranted.
+ * it can check if rrset_trust_nonauth_ans_AA should be used */
+ if(i < rep->an_numrrsets) {
+ /* answer section */
+ if(AA) return rrset_trust_ans_AA;
+ else return rrset_trust_ans_noAA;
+
+ } else if(i < rep->an_numrrsets+rep->ns_numrrsets) {
+ /* authority section */
+ if(AA) return rrset_trust_auth_AA;
+ else return rrset_trust_auth_noAA;
+ } else {
+ /* addit section */
+ if(AA) return rrset_trust_add_AA;
+ else return rrset_trust_add_noAA;
+ }
+ return rrset_trust_none;
+}
+
/**
* Copy and decompress rrs
* @param pkt: the packet for compression pointer resolution.
rep->rrsets[i]->entry.data = (void*)data;
rep->rrsets[i]->entry.key = (void*)rep->rrsets[i];
rep->rrsets[i]->entry.hash = pset->hash;
+ data->trust = get_rrset_trust(rep, i);
if(data->ttl < rep->ttl)
rep->ttl = data->ttl;
/** helper compare function to sort in lock order */
static int
-reply_info_fillref_cmp(const void* a, const void* b)
+reply_info_sortref_cmp(const void* a, const void* b)
{
if(a < b) return -1;
if(a > b) return 1;
}
void
-reply_info_fillref(struct reply_info* rep)
+reply_info_sortref(struct reply_info* rep)
{
- size_t i;
- for(i=0; i<rep->rrset_count; i++) {
- rep->ref[i].key = rep->rrsets[i];
- rep->ref[i].id = rep->rrsets[i]->id;
- }
qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref),
- reply_info_fillref_cmp);
+ reply_info_sortref_cmp);
}
void
struct query_info* qinf, struct reply_info** rep);
/**
- * Fills in the ref array based on the rest of the structure, the rrsets.
+ * Sorts the ref array.
* @param rep: reply info. rrsets must be filled in.
*/
-void reply_info_fillref(struct reply_info* rep);
+void reply_info_sortref(struct reply_info* rep);
/**
* Set TTLs inside the replyinfo to absolute values.
struct packed_rrset_data* d = (struct packed_rrset_data*)data;
free(d);
}
+
+int
+rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2)
+{
+ size_t i;
+ size_t total;
+ if(d1->count != d2->count || d1->rrsig_count != d2->rrsig_count)
+ return 0;
+ total = d1->count + d1->rrsig_count;
+ for(i=0; i<total; i++) {
+ if(d1->rr_len[i] != d2->rr_len[i])
+ return 0;
+ if(memcmp(d1->rr_data[i], d2->rr_data[i], d1->rr_len[i]) != 0)
+ return 0;
+ }
+ return 1;
+}
struct packed_rrset_key rk;
};
+/**
+ * RRset trustworthiness. Bigger value is more trust. RFC 2181.
+ * The rrset_trust_add_noAA, rrset_trust_auth_noAA, rrset_trust_add_AA,
+ * are mentioned as the same trustworthiness in 2181, but split up here
+ * for ease of processing.
+ *
+ * rrset_trust_nonauth_ans_AA, rrset_trust_ans_noAA
+ * are also mentioned as the same trustworthiness in 2181, but split up here
+ * for ease of processing.
+ *
+ * Added trust_none for a sane initial value, smaller than anything else.
+ * Added validated and ultimate trust for keys and rrsig validated content.
+ */
+enum rrset_trust {
+ /** initial value for trust */
+ rrset_trust_none = 0,
+ /** Additional information from non-authoritative answers */
+ rrset_trust_add_noAA,
+ /** Data from the authority section of a non-authoritative answer */
+ rrset_trust_auth_noAA,
+ /** Additional information from an authoritative answer */
+ rrset_trust_add_AA,
+ /** non-authoritative data from the answer section of authoritative
+ * answers */
+ rrset_trust_nonauth_ans_AA,
+ /** Data from the answer section of a non-authoritative answer */
+ rrset_trust_ans_noAA,
+ /** Glue from a primary zone, or glue from a zone transfer */
+ rrset_trust_glue,
+ /** Data from the authority section of an authoritative answer */
+ rrset_trust_auth_AA,
+ /** The authoritative data included in the answer section of an
+ * authoritative reply */
+ rrset_trust_ans_AA,
+ /** Data from a zone transfer, other than glue */
+ rrset_trust_sec_noglue,
+ /** Data from a primary zone file, other than glue data */
+ rrset_trust_prim_noglue,
+ /** DNSSEC(rfc4034) validated with trusted keys */
+ rrset_trust_validated,
+ /** ultimately trusted, no more trust is possible;
+ * trusted keys from the unbound configuration setup. */
+ rrset_trust_ultimate
+};
+
/**
* RRset data.
*
size_t count;
/** number of rrsigs, if 0 no rrsigs */
size_t rrsig_count;
+ /** the trustworthiness of the rrset data */
+ enum rrset_trust trust;
/** length of every rr's rdata, rr_len[i] is size of rr_data[i]. */
size_t* rr_len;
/** ttl of every rr. rr_ttl[i] ttl of rr i. */
*/
int ub_rrset_compare(void* k1, void* k2);
+/**
+ * compare two rrset data structures.
+ * Compared rdata and rrsigdata, not the trust or ttl value.
+ * @param d1: data to compare.
+ * @param d2: data to compare.
+ * @return 1 if equal.
+ */
+int rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2);
+
/**
* Old key to be deleted. RRset keys are recycled via alloc.
* @param key: struct ub_packed_rrset_key*.