From 44ef71ff6cc771880f01e75142d757778f0eeacb Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Fri, 4 May 2007 10:10:52 +0000 Subject: [PATCH] working on trust of rrsets. git-svn-id: file:///svn/unbound/trunk@281 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/daemon.h | 2 +- daemon/worker.c | 54 ++++++++++++++++++++++++++++++++++++-- doc/Changelog | 2 ++ doc/TODO | 2 ++ util/data/msgreply.c | 38 +++++++++++++++++++++------ util/data/msgreply.h | 4 +-- util/data/packed_rrset.c | 17 ++++++++++++ util/data/packed_rrset.h | 56 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 162 insertions(+), 13 deletions(-) diff --git a/daemon/daemon.h b/daemon/daemon.h index 8eee819b5..2979f65f8 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -74,7 +74,7 @@ struct daemon { 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; }; diff --git a/daemon/worker.c b/daemon/worker.c index 8c770be97..a5cde258a 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -129,16 +129,66 @@ replyerror(int r, struct work_query* w) 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; irrset_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 */ } } @@ -192,7 +242,7 @@ worker_handle_reply(struct comm_point* c, void* arg, int error, } 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); diff --git a/doc/Changelog b/doc/Changelog index a54c1c303..faa53bebb 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -3,6 +3,8 @@ - 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. diff --git a/doc/TODO b/doc/TODO index 8f639e1c4..40d013547 100644 --- a/doc/TODO +++ b/doc/TODO @@ -16,3 +16,5 @@ o use rbtree to compress domain names in messages, sorted AXFRs of 16Kb 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. diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 4d39058b7..8dc0687cd 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -199,6 +199,7 @@ parse_rr_copy(ldns_buffer* pkt, struct rrset_parse* pset, 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)); @@ -246,6 +247,31 @@ parse_create_rrset(ldns_buffer* pkt, struct rrset_parse* pset, 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. @@ -288,6 +314,7 @@ parse_copy_decompress(ldns_buffer* pkt, struct msg_parse* msg, 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; @@ -358,7 +385,7 @@ int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc, /** 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; @@ -366,15 +393,10 @@ reply_info_fillref_cmp(const void* a, const void* b) } void -reply_info_fillref(struct reply_info* rep) +reply_info_sortref(struct reply_info* rep) { - size_t i; - for(i=0; irrset_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 diff --git a/util/data/msgreply.h b/util/data/msgreply.h index a3e6b0d90..e356d0d1f 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -192,10 +192,10 @@ int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc, 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. diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c index 7c7a8c12f..0308157c9 100644 --- a/util/data/packed_rrset.c +++ b/util/data/packed_rrset.c @@ -117,3 +117,20 @@ rrset_data_delete(void* data, void* ATTR_UNUSED(userdata)) 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; irr_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; +} diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h index ce0ba8689..068ccf7aa 100644 --- a/util/data/packed_rrset.h +++ b/util/data/packed_rrset.h @@ -107,6 +107,51 @@ struct ub_packed_rrset_key { 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. * @@ -143,6 +188,8 @@ struct packed_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. */ @@ -194,6 +241,15 @@ size_t ub_rrset_sizefunc(void* key, void* data); */ 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*. -- 2.47.2