From: Wouter Wijngaards Date: Fri, 25 May 2007 12:02:37 +0000 (+0000) Subject: - Acknowledge use of unbound-java code in iterator. Nicer readme. X-Git-Tag: release-0.4~127 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c7a9776d913681b951316d4383145f86e93d56f9;p=thirdparty%2Funbound.git - Acknowledge use of unbound-java code in iterator. Nicer readme. - services/cache/dns.c DNS Cache. Hybrid cache uses msgcache and rrset cache from module environment. - packed rrset key has type and class as easily accessable struct members. They are still kept in network format for fast msg encode. - dns cache find_delegation routine. git-svn-id: file:///svn/unbound/trunk@339 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 3a089a518..d009617cb 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,11 @@ +25 May 2007: Wouter + - Acknowledge use of unbound-java code in iterator. Nicer readme. + - services/cache/dns.c DNS Cache. Hybrid cache uses msgcache and + rrset cache from module environment. + - packed rrset key has type and class as easily accessable struct + members. They are still kept in network format for fast msg encode. + - dns cache find_delegation routine. + 24 May 2007: Wouter - small changes to prepare for subqueries. - iterator forwarder feature separated out. diff --git a/doc/README b/doc/README index c1bb61b83..3fc47c6e6 100644 --- a/doc/README +++ b/doc/README @@ -4,19 +4,27 @@ http://unbound.net This software is under BSD license, see LICENSE for details. +* Download the latest version of this software from + http://unbound.net + or get a beta version from the svn repository at + http://unbound.net/svn/ + * Needs the following libraries * ldns http://www.nlnetlabs.nl/ldns/ (BSD license) * libevent http://www.monkey.org/~provos/libevent/ (BSD license) +* Create build environment + * run libtoolize -c if config.sub is missing. + * autoreconf (autoheader && autoconf), if ./configure is missing. + * Make and install: ./configure; make * --with-ldns=/path/to/ldns * --with-libevent=/path/to/libevent Can be set to either the system install or the build directory. - --with-libevent=no gives an alternative to libevent (based on select). - -* Create build environment - * run libtoolize -c if config.sub is missing. - * autoreconf (autoheader && autoconf), if ./configure is missing. + --with-libevent=no gives a builtin alternative implementation. + * --without-pthreads + This disables pthreads, and uses Solaris thr library or no threading. + Without this option the pthreads library is detected automatically. Known issues ------------ @@ -25,4 +33,11 @@ o If libevent is older (1.3 and before), unbound will exit instead of reload printed. Perform ./configure --with-libevent=no or update libevent, rerun configure and recompile unbound to make sighup work correctly. +Acknowledgements +---------------- +o Thanks to David Blacka and Matt Larson (Verisign) for the unbound-java + prototype. Design and code from that prototype has been used to create + this program. Such as the iterator state machine and the cache design. +o See Credits file for contributors. + * mailto:wouter@nlnetlabs.nl diff --git a/iterator/iterator.c b/iterator/iterator.c index 2e425761e..19f6f8fca 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -42,14 +42,13 @@ #include "config.h" #include "iterator/iterator.h" +#include "iterator/iter_utils.h" +#include "iterator/iter_hints.h" +#include "services/cache/dns.h" #include "util/module.h" #include "util/netevent.h" #include "util/net_help.h" -#include "util/storage/slabhash.h" #include "util/region-allocator.h" -#include "services/cache/rrset.h" -#include "iterator/iter_utils.h" -#include "iterator/iter_hints.h" /** iterator init */ static int @@ -83,45 +82,6 @@ iter_deinit(struct module_env* env, int id) free(iter_env); } -/** store rrsets in the rrset cache. */ -static void -store_rrsets(struct module_env* env, struct reply_info* rep, uint32_t now) -{ - size_t i; - /* see if rrset already exists in cache, if not insert it. */ - for(i=0; irrset_count; i++) { - rep->ref[i].key = rep->rrsets[i]; - rep->ref[i].id = rep->rrsets[i]->id; - if(rrset_cache_update(env->rrset_cache, &rep->ref[i], - env->alloc, now)) /* it was in the cache */ - rep->rrsets[i] = rep->ref[i].key; - } -} - - -/** store message in the cache */ -static void -store_msg(struct module_qstate* qstate, struct query_info* qinfo, - struct reply_info* rep) -{ - struct msgreply_entry* e; - uint32_t now = time(NULL); - reply_info_set_ttls(rep, now); - store_rrsets(qstate->env, rep, now); - if(rep->ttl == 0) { - log_info("TTL 0: dropped msg from cache"); - return; - } - reply_info_sortref(rep); - /* store msg in the cache */ - if(!(e = query_info_entrysetup(qinfo, rep, qstate->query_hash))) { - log_err("store_msg: malloc failed"); - return; - } - slabhash_insert(qstate->env->msg_cache, qstate->query_hash, - &e->entry, rep, &qstate->env->alloc); -} - /** new query for iterator */ static int iter_new(struct module_qstate* qstate, int id) @@ -175,7 +135,8 @@ iter_handlereply(struct module_qstate* qstate, int id, qstate->query_flags, qstate->buf, 0, 0, qstate->scratch, us, &qstate->edns)) return 0; - store_msg(qstate, &reply_qinfo, reply_msg); + dns_cache_store_msg(qstate->env, &reply_qinfo, qstate->query_hash, + reply_msg); qstate->ext_state[id] = module_finished; return 1; } diff --git a/services/cache/dns.c b/services/cache/dns.c new file mode 100644 index 000000000..bf10c3dcf --- /dev/null +++ b/services/cache/dns.c @@ -0,0 +1,231 @@ +/* + * services/cache/dns.c - Cache services for DNS using msg and rrset caches. + * + * Copyright (c) 2007, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains the DNS cache. + */ +#include "config.h" +#include "iterator/iter_delegpt.h" +#include "services/cache/dns.h" +#include "services/cache/rrset.h" +#include "util/data/msgreply.h" +#include "util/data/packed_rrset.h" +#include "util/module.h" +#include "util/net_help.h" + +/** store rrsets in the rrset cache. */ +static void +store_rrsets(struct module_env* env, struct reply_info* rep, uint32_t now) +{ + size_t i; + /* see if rrset already exists in cache, if not insert it. */ + for(i=0; irrset_count; i++) { + rep->ref[i].key = rep->rrsets[i]; + rep->ref[i].id = rep->rrsets[i]->id; + if(rrset_cache_update(env->rrset_cache, &rep->ref[i], + env->alloc, now)) /* it was in the cache */ + rep->rrsets[i] = rep->ref[i].key; + } +} + +void +dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, + hashvalue_t hash, struct reply_info* rep) +{ + struct msgreply_entry* e; + uint32_t now = time(NULL); + + /* store RRsets */ + reply_info_set_ttls(rep, now); + store_rrsets(env, rep, now); + if(rep->ttl == 0) { + /* we do not store the message, but we did store the RRs, + * which could be useful for delegation information */ + verbose(VERB_ALGO, "TTL 0: dropped msg from cache"); + return; + } + + /* store msg in the cache */ + reply_info_sortref(rep); + if(!(e = query_info_entrysetup(qinfo, rep, hash))) { + log_err("store_msg: malloc failed"); + return; + } + slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc); +} + +/** find closest NS and returns the rrset (locked) */ +static struct ub_packed_rrset_key* +find_deleg_ns(struct module_env* env, uint8_t* qname, size_t qnamelen, + uint16_t qclass, uint32_t now) +{ + struct ub_packed_rrset_key *rrset; + uint8_t lablen; + + /* snip off front part of qname until NS is found */ + while(qnamelen > 0) { + if((rrset = rrset_cache_lookup(env->rrset_cache, qname, + qnamelen, LDNS_RR_TYPE_NS, qclass, 0, now, 0))) + return rrset; + + /* snip off front label */ + lablen = *qname; + qname += lablen + 1; + qnamelen -= lablen + 1; + } + return NULL; +} + +/** add A records to delegation */ +static int +add_a(struct ub_packed_rrset_key* ak, struct delegpt* dp, + struct region* region) +{ + struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; + size_t i; + struct sockaddr_in sa; + socklen_t len = (socklen_t)sizeof(sa); + memset(&sa, 0, len); + sa.sin_family = AF_INET; + sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); + for(i=0; icount; i++) { + if(d->rr_len[i] != 2 + INET_SIZE) + continue; + memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE); + log_addr("adding A to deleg", (struct sockaddr_storage*)&sa, + len); + if(!delegpt_add_target(dp, region, ak->rk.dname, + ak->rk.dname_len, (struct sockaddr_storage*)&sa, + len)) + return 0; + } + return 1; +} + +/** add AAAA records to delegation */ +static int +add_aaaa(struct ub_packed_rrset_key* ak, struct delegpt* dp, + struct region* region) +{ + struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; + size_t i; + struct sockaddr_in6 sa; + socklen_t len = (socklen_t)sizeof(sa); + memset(&sa, 0, len); + sa.sin6_family = AF_INET6; + sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); + for(i=0; icount; i++) { + if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */ + continue; + memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE); + log_addr("adding AAAA to deleg", (struct sockaddr_storage*)&sa, + len); + if(!delegpt_add_target(dp, region, ak->rk.dname, + ak->rk.dname_len, (struct sockaddr_storage*)&sa, + len)) + return 0; + } + return 1; +} + +/** find and add A and AAAA records for nameservers in delegpt */ +static int +find_add_addrs(struct module_env* env, uint16_t qclass, struct region* region, + struct delegpt* dp, uint32_t now) +{ + struct delegpt_ns* ns; + struct ub_packed_rrset_key* akey; + for(ns = dp->nslist; ns; ns = ns->next) { + akey = rrset_cache_lookup(env->rrset_cache, ns->name, + ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); + if(akey) { + if(!add_a(akey, dp, region)) { + 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, 0, now, 0); + if(akey) { + if(!add_aaaa(akey, dp, region)) { + lock_rw_unlock(akey->entry.lock); + return 0; + } + lock_rw_unlock(akey->entry.lock); + } + } + return 1; +} + +struct delegpt* +dns_cache_find_delegation(struct module_env* env, uint8_t* qname, + size_t qnamelen, uint16_t qclass, struct region* region) +{ + /* try to find closest NS rrset */ + struct ub_packed_rrset_key* nskey; + struct packed_rrset_data* nsdata; + struct delegpt* dp; + size_t i; + uint32_t now = (uint32_t)time(NULL); + + nskey = find_deleg_ns(env, qname, qnamelen, qclass, now); + if(!nskey) /* hope the caller has hints to prime or something */ + return NULL; + nsdata = (struct packed_rrset_data*)nskey->entry.data; + /* got the NS key, create delegation point */ + dp = delegpt_create(region); + if(!dp || !delegpt_set_name(dp, region, nskey->rk.dname)) { + lock_rw_unlock(nskey->entry.lock); + log_err("find_delegation: out of memory"); + return NULL; + } + /* add NS entries */ + for(i=0; icount; i++) { + if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ + /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ + if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2)) + log_err("find_delegation: addns out of memory"); + } + /* find and add A entries */ + lock_rw_unlock(nskey->entry.lock); /* first unlock before next lookup*/ + if(!find_add_addrs(env, qclass, region, dp, now)) + log_err("find_delegation: addrs out of memory"); + log_info("dns_cache_find_delegation returns delegpt"); + delegpt_log(dp); + return dp; +} diff --git a/services/cache/dns.h b/services/cache/dns.h new file mode 100644 index 000000000..4da517071 --- /dev/null +++ b/services/cache/dns.h @@ -0,0 +1,82 @@ +/* + * services/cache/dns.h - Cache services for DNS using msg and rrset caches. + * + * Copyright (c) 2007, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains the DNS cache. + */ + +#ifndef SERVICES_CACHE_DNS_H +#define SERVICES_CACHE_DNS_H +#include "util/storage/lruhash.h" +struct module_env; +struct query_info; +struct reply_info; +struct region; +struct delegpt; + +/** + * Store message in the cache. Stores in message cache and rrset cache. + * Both qinfo and rep should be malloced and are put in the cache. + * They should not be used after this call, as they are then in shared cache. + * Does not return errors, they are logged and only lead to less cache. + * + * @param env: module environment with the DNS cache. + * @param qinfo: query info + * @param hash: hash over qinfo. + * @param rep: reply info, together with qinfo makes up the message. + * Adjusts the reply info TTLs to absolute time. + */ +void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, + hashvalue_t hash, struct reply_info* rep); + +/** + * Find a delegation from the cache. + * @param env: module environment with the DNS cache. + * @param qname: query name. + * @param qnamelen: length of qname. + * @param qclass: query class. + * @param region: where to allocate result delegation. + * @return new delegation or NULL on error or if not found in cache. + */ +struct delegpt* dns_cache_find_delegation(struct module_env* env, + uint8_t* qname, size_t qnamelen, uint16_t qclass, + struct region* region); + +/** Find cached message */ +/** Find covering DNAME */ + +#endif /* SERVICES_CACHE_DNS_H */ diff --git a/services/cache/rrset.c b/services/cache/rrset.c index a35e14d41..cf87bfe77 100644 --- a/services/cache/rrset.c +++ b/services/cache/rrset.c @@ -174,3 +174,35 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, return 1; return 0; } + +struct ub_packed_rrset_key* +rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen, + uint16_t qtype, uint16_t qclass, uint32_t flags, uint32_t timenow, + int wr) +{ + struct lruhash_entry* e; + struct ub_packed_rrset_key key; + + key.entry.key = &key; + key.entry.data = NULL; + key.rk.dname = qname; + key.rk.dname_len = qnamelen; + key.rk.type = htons(qtype); + key.rk.rrset_class = htons(qclass); + key.rk.flags = flags; + + key.entry.hash = rrset_key_hash(&key.rk); + + if((e = slabhash_lookup(&r->table, key.entry.hash, &key, wr))) { + /* check TTL */ + struct packed_rrset_data* data = + (struct packed_rrset_data*)e->data; + if(timenow > data->ttl) { + lock_rw_unlock(e->lock); + return NULL; + } + /* we're done */ + return (struct ub_packed_rrset_key*)e->key; + } + return NULL; +} diff --git a/services/cache/rrset.h b/services/cache/rrset.h index 313a69452..d4630b14f 100644 --- a/services/cache/rrset.h +++ b/services/cache/rrset.h @@ -128,4 +128,22 @@ void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key, int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, struct alloc_cache* alloc, uint32_t timenow); +/** + * Lookup rrset. You obtain read/write lock. You must unlock before lookup + * anything of else. + * @param r: the rrset cache. + * @param qname: name of rrset to lookup. + * @param qnamelen: length of name of rrset to lookup. + * @param qtype: type of rrset to lookup (host order). + * @param qclass: class of rrset to lookup (host order). + * @param flags: rrset flags, or 0. + * @param timenow: used to compare with TTL. + * @param wr: set true to get writelock. + * @return packed rrset key pointer. Remember to unlock the key.entry.lock. + * or NULL if could not be found or it was timed out. + */ +struct ub_packed_rrset_key* rrset_cache_lookup(struct rrset_cache* r, + uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, + uint32_t flags, uint32_t timenow, int wr); + #endif /* SERVICES_CACHE_RRSET_H */ diff --git a/services/outside_network.c b/services/outside_network.c index fdb097429..25b318385 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -58,10 +58,6 @@ /** number of times to retry making a random ID that is unique. */ #define MAX_ID_RETRY 1000 -/** byte size of ip4 address */ -#define INET_SIZE 4 -/** byte size of ip6 address */ -#define INET6_SIZE 16 /** number of retries on outgoing UDP queries */ #define OUTBOUND_UDP_RETRY 4 diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 01964477d..ebc88808a 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -160,9 +160,11 @@ static hashvalue_t pkt_hash_rrset(ldns_buffer* pkt, uint8_t* dname, uint16_t type, uint16_t dclass, uint32_t rrset_flags) { + /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ + /* this routine handles compressed names */ hashvalue_t h = 0xab; - h = hashlittle(&type, sizeof(type), h); - h = hashlittle(&dclass, sizeof(dclass), h); + h = hashlittle(&type, sizeof(type), h); /* host order */ + h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */ h = hashlittle(&rrset_flags, sizeof(uint32_t), h); h = dname_pkt_hash(pkt, dname, h); return h; diff --git a/util/data/msgreply.c b/util/data/msgreply.c index d4f3a82d0..abd9bda94 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -285,7 +285,6 @@ parse_copy_decompress(ldns_buffer* pkt, struct msg_parse* msg, { int ret; size_t i; - uint16_t t; struct rrset_parse *pset = msg->rrset_first; struct packed_rrset_data* data; log_assert(rep); @@ -296,18 +295,14 @@ parse_copy_decompress(ldns_buffer* pkt, struct msg_parse* msg, for(i=0; irrset_count; i++) { rep->rrsets[i]->rk.flags = pset->flags; rep->rrsets[i]->rk.dname_len = pset->dname_len; - rep->rrsets[i]->rk.dname = (uint8_t*)malloc( - pset->dname_len + 4 /* size of type and class */ ); + rep->rrsets[i]->rk.dname = (uint8_t*)malloc(pset->dname_len); if(!rep->rrsets[i]->rk.dname) return LDNS_RCODE_SERVFAIL; /** copy & decompress dname */ dname_pkt_copy(pkt, rep->rrsets[i]->rk.dname, pset->dname); /** copy over type and class */ - t = htons(pset->type); - memmove(&rep->rrsets[i]->rk.dname[pset->dname_len], - &t, sizeof(uint16_t)); - memmove(&rep->rrsets[i]->rk.dname[pset->dname_len+2], - &pset->rrset_class, sizeof(uint16_t)); + rep->rrsets[i]->rk.type = htons(pset->type); + rep->rrsets[i]->rk.rrset_class = pset->rrset_class; /** read data part. */ if((ret=parse_create_rrset(pkt, pset, &data)) != 0) return ret; @@ -771,14 +766,12 @@ compress_owner(struct ub_packed_rrset_key* key, ldns_buffer* pkt, /* check if typeclass+4 ttl + rdatalen is available */ if(ldns_buffer_remaining(pkt) < 4+4+2) return RETVAL_TRUNC; - ldns_buffer_write(pkt, &key->rk.dname[ - key->rk.dname_len], 4); } else { /* no compress */ if(ldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2) return RETVAL_TRUNC; ldns_buffer_write(pkt, key->rk.dname, - key->rk.dname_len+4); + key->rk.dname_len); if(owner_pos <= PTR_MAX_OFFSET) *owner_ptr = htons(PTR_CREATE(owner_pos)); } @@ -796,7 +789,6 @@ compress_owner(struct ub_packed_rrset_key* key, ldns_buffer* pkt, return RETVAL_TRUNC; ldns_buffer_write(pkt, owner_ptr, 2); } - ldns_buffer_write(pkt, &key->rk.dname[key->rk.dname_len], 4); } return RETVAL_OK; } @@ -824,9 +816,7 @@ compress_any_dname(uint8_t* dname, ldns_buffer* pkt, int labs, static const ldns_rr_descriptor* type_rdata_compressable(struct ub_packed_rrset_key* key) { - uint16_t t; - memmove(&t, &key->rk.dname[key->rk.dname_len], sizeof(t)); - t = ntohs(t); + uint16_t t = ntohs(key->rk.type); if(ldns_rr_descript(t) && ldns_rr_descript(t)->_compress == LDNS_RR_COMPRESS) return ldns_rr_descript(t); @@ -909,6 +899,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, owner_pos, &owner_ptr, owner_labs)) != RETVAL_OK) return r; + ldns_buffer_write(pkt, &key->rk.type, 2); + ldns_buffer_write(pkt, &key->rk.rrset_class, 2); ldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow); if(c) { if((r=compress_rdata(pkt, data->rr_data[i], @@ -942,8 +934,7 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, return RETVAL_TRUNC; } ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG); - ldns_buffer_write(pkt, &(key->rk.dname[ - key->rk.dname_len+2]), sizeof(uint16_t)); + ldns_buffer_write(pkt, &key->rk.rrset_class, 2); ldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow); /* rrsig rdata cannot be compressed, perform 100+ byte * memcopy. */ diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c index 23aa080a2..fb8a42284 100644 --- a/util/data/packed_rrset.c +++ b/util/data/packed_rrset.c @@ -41,6 +41,8 @@ #include "config.h" #include "util/data/packed_rrset.h" +#include "util/data/dname.h" +#include "util/storage/lookup3.h" #include "util/log.h" #include "util/alloc.h" @@ -85,6 +87,11 @@ ub_rrset_compare(void* k1, void* k2) int c; if(key1 == key2 || key1->id == key2->id) return 0; + if(key1->rk.type != key2->rk.type) { + if(key1->rk.type < key2->rk.type) + return -1; + return 1; + } if(key1->rk.dname_len != key2->rk.dname_len) { if(key1->rk.dname_len < key2->rk.dname_len) return -1; @@ -92,6 +99,11 @@ ub_rrset_compare(void* k1, void* k2) } if((c=memcmp(key1->rk.dname, key2->rk.dname, key1->rk.dname_len)) != 0) return c; + if(key1->rk.rrset_class != key2->rk.rrset_class) { + if(key1->rk.rrset_class < key2->rk.rrset_class) + return -1; + return 1; + } if(key1->rk.flags != key2->rk.flags) { if(key1->rk.flags < key2->rk.flags) return -1; @@ -137,3 +149,18 @@ rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2) } return 1; } + +hashvalue_t +rrset_key_hash(struct packed_rrset_key* key) +{ + /* type is hashed in host order */ + uint16_t t = ntohs(key->type); + /* Note this MUST be identical to pkt_hash_rrset in msgparse.c */ + /* this routine does not have a compressed name */ + hashvalue_t h = 0xab; + h = hashlittle(&t, sizeof(t), h); + h = hashlittle(&key->rrset_class, sizeof(uint16_t), h); + h = hashlittle(&key->flags, sizeof(uint32_t), h); + h = dname_query_hash(key->dname, h); + return h; +} diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h index 3570fafb3..02f883d38 100644 --- a/util/data/packed_rrset.h +++ b/util/data/packed_rrset.h @@ -61,14 +61,10 @@ struct packed_rrset_key { * The domain name. If not null (for id=0) it is allocated, and * contains the wireformat domain name. * This dname is not canonicalized. - * After the dname uint16_t type and uint16_t class is stored - * in wireformat. - * Use accessor functions to get type and class values. */ uint8_t* dname; /** * Length of the domain name, including last 0 root octet. - * The value+sizeof(uint16_t)*2 is actually allocated. */ size_t dname_len; /** @@ -77,6 +73,10 @@ struct packed_rrset_key { * o PACKED_RRSET_CD */ uint32_t flags; + /** the rrset type in network format */ + uint16_t type; + /** the rrset class in network format */ + uint16_t rrset_class; }; /** @@ -279,4 +279,11 @@ void ub_rrset_key_delete(void* key, void* userdata, int is_locked); */ void rrset_data_delete(void* data, void* userdata); +/** + * Calculate hash value for a packed rrset key. + * @param key: the rrset key with name, type, class, flags. + * @return hash value. + */ +hashvalue_t rrset_key_hash(struct packed_rrset_key* key); + #endif /* UTIL_DATA_PACKED_RRSET_H */ diff --git a/util/net_help.h b/util/net_help.h index a223fa4bf..85ac3b282 100644 --- a/util/net_help.h +++ b/util/net_help.h @@ -62,6 +62,10 @@ #define EDNS_ADVERTISED_SIZE 4096 /** bits for EDNS bitfield */ #define EDNS_DO 0x8000 /* Dnssec Ok */ +/** byte size of ip4 address */ +#define INET_SIZE 4 +/** byte size of ip6 address */ +#define INET6_SIZE 16 /** * See if string is ip4 or ip6.