Example #1
0
/*  Invalidate the message associated with query_info stored in message cache */
void invalidateQueryInCache(struct module_qstate* qstate, struct query_info* qinfo)
{ 
    hashvalue_t h;
    struct lruhash_entry* e;
    struct reply_info *r;
    size_t i, j;

    h = query_info_hash(qinfo, qstate->query_flags);
    if ((e=slabhash_lookup(qstate->env->msg_cache, h, qinfo, 0))) 
    {
	r = (struct reply_info*)(e->data);
	if (r) 
	{
	   r->ttl = 0;
	   if(rrset_array_lock(r->ref, r->rrset_count, *qstate->env->now)) {
		   for(i=0; i< r->rrset_count; i++) 
		   {
		       struct packed_rrset_data* data = 
		       	(struct packed_rrset_data*) r->ref[i].key->entry.data;
		       if(i>0 && r->ref[i].key == r->ref[i-1].key)
			   continue;
	      
		       data->ttl = r->ttl;
		       for(j=0; j<data->count + data->rrsig_count; j++)
			   data->rr_ttl[j] = r->ttl;
		   }
		   rrset_array_unlock(r->ref, r->rrset_count);
	   }
	}
	lock_rw_unlock(&e->lock);
    } else {
	log_info("invalidateQueryInCache: qinfo is not in cache");
    }
}
Example #2
0
/** find data item in array, for write access, caller unlocks */
static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra,
	uint8_t* name, size_t namelen, int wr)
{
	struct rate_key key;
	hashvalue_t h = dname_query_hash(name, 0xab);
	memset(&key, 0, sizeof(key));
	key.name = name;
	key.namelen = namelen;
	key.entry.hash = h;
	return slabhash_lookup(infra->domain_rates, h, &key, wr);
}
Example #3
0
/** test hashtable using short sequence */
static void
test_short_table(struct slabhash* table) 
{
	testkey_type* k = newkey(12);
	testkey_type* k2 = newkey(14);
	testdata_type* d = newdata(128);
	testdata_type* d2 = newdata(129);
	
	k->entry.data = d;
	k2->entry.data = d2;

	slabhash_insert(table, myhash(12), &k->entry, d, NULL);
	slabhash_insert(table, myhash(14), &k2->entry, d2, NULL);
	
	unit_assert( slabhash_lookup(table, myhash(12), k, 0) == &k->entry);
	lock_rw_unlock( &k->entry.lock );
	unit_assert( slabhash_lookup(table, myhash(14), k2, 0) == &k2->entry);
	lock_rw_unlock( &k2->entry.lock );
	slabhash_remove(table, myhash(12), k);
	slabhash_remove(table, myhash(14), k2);
}
Example #4
0
/** lookup version that does not check host ttl (you check it) */
struct lruhash_entry* 
infra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr,
	socklen_t addrlen, uint8_t* name, size_t namelen, int wr)
{
	struct infra_key k;
	k.addrlen = addrlen;
	memcpy(&k.addr, addr, addrlen);
	k.namelen = namelen;
	k.zonename = name;
	k.entry.hash = hash_infra(addr, addrlen, name);
	k.entry.key = (void*)&k;
	k.entry.data = NULL;
	return slabhash_lookup(infra->hosts, k.entry.hash, &k, wr);
}
Example #5
0
/**
 * Lookup exactly in the key cache. Returns pointer to locked entry.
 * Caller must unlock it after use.
 * @param kcache: the key cache.
 * @param name: for what name to look; uncompressed wireformat
 * @param namelen: length of the name.
 * @param key_class: class of the key.
 * @param wr: set true to get a writelock.
 * @return key entry, locked, or NULL if not found. No TTL checking is
 * 	performed.
 */
static struct key_entry_key*
key_cache_search(struct key_cache* kcache, uint8_t* name, size_t namelen, 
	uint16_t key_class, int wr)
{
	struct lruhash_entry* e;
	struct key_entry_key lookfor;
	lookfor.entry.key = &lookfor;
	lookfor.name = name;
	lookfor.namelen = namelen;
	lookfor.key_class = key_class;
	key_entry_hash(&lookfor);
	e = slabhash_lookup(kcache->slab, lookfor.entry.hash, &lookfor, wr);
	if(!e) 
		return NULL;
	return (struct key_entry_key*)e->key;
}
Example #6
0
/** test adding a random element */
static void
testlookup(struct slabhash* table, testdata_type* ref[])
{
	int num = random() % HASHTESTMAX;
	testkey_type* key = newkey(num);
	struct lruhash_entry* en = slabhash_lookup(table, myhash(num), key, 0);
	testdata_type* data = en? (testdata_type*)en->data : NULL;
	if(en) {
		unit_assert(en->key);
		unit_assert(en->data);
	}
	if(0) log_info("lookup %d got %d, expect %d", num, en? data->data :-1,
		ref[num]? ref[num]->data : -1);
	unit_assert( data == ref[num] );
	if(en) { lock_rw_unlock(&en->lock); }
	delkey(key);
}
Example #7
0
/** test adding a random element (unlimited range) */
static void
testlookup_unlim(struct slabhash* table, testdata_type** ref)
{
	int num = random() % (HASHTESTMAX*10);
	testkey_type* key = newkey(num);
	struct lruhash_entry* en = slabhash_lookup(table, myhash(num), key, 0);
	testdata_type* data = en? (testdata_type*)en->data : NULL;
	if(en) {
		unit_assert(en->key);
		unit_assert(en->data);
	}
	if(0 && ref) log_info("lookup unlim %d got %d, expect %d", num, en ? 
		data->data :-1, ref[num] ? ref[num]->data : -1);
	if(data && ref) {
		/* its okay for !data, it fell off the lru */
		unit_assert( data == ref[num] );
	}
	if(en) { lock_rw_unlock(&en->lock); }
	delkey(key);
}
Example #8
0
File: dns.c Project: coyizumi/cs111
/** lookup message in message cache */
static struct msgreply_entry*
msg_cache_lookup(struct module_env* env, uint8_t* qname, size_t qnamelen,
                 uint16_t qtype, uint16_t qclass, uint16_t flags, time_t now, int wr)
{
    struct lruhash_entry* e;
    struct query_info k;
    hashvalue_t h;

    k.qname = qname;
    k.qname_len = qnamelen;
    k.qtype = qtype;
    k.qclass = qclass;
    h = query_info_hash(&k, flags);
    e = slabhash_lookup(env->msg_cache, h, &k, wr);

    if(!e) return NULL;
    if( now > ((struct reply_info*)e->data)->ttl ) {
        lock_rw_unlock(&e->lock);
        return NULL;
    }
    return (struct msgreply_entry*)e->key;
}
Example #9
0
struct dns_msg* 
dns_cache_lookup(struct module_env* env,
	uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
	uint16_t flags, struct regional* region, struct regional* scratch,
	int no_partial)
{
	struct lruhash_entry* e;
	struct query_info k;
	hashvalue_type h;
	time_t now = *env->now;
	struct ub_packed_rrset_key* rrset;

	/* lookup first, this has both NXdomains and ANSWER responses */
	k.qname = qname;
	k.qname_len = qnamelen;
	k.qtype = qtype;
	k.qclass = qclass;
	k.local_alias = NULL;
	h = query_info_hash(&k, flags);
	e = slabhash_lookup(env->msg_cache, h, &k, 0);
	if(e) {
		struct msgreply_entry* key = (struct msgreply_entry*)e->key;
		struct reply_info* data = (struct reply_info*)e->data;
		struct dns_msg* msg = tomsg(env, &key->key, data, region, now, 
			scratch);
		if(msg) {
			lock_rw_unlock(&e->lock);
			return msg;
		}
		/* could be msg==NULL; due to TTL or not all rrsets available */
		lock_rw_unlock(&e->lock);
	}

	/* see if a DNAME exists. Checked for first, to enforce that DNAMEs
	 * are more important, the CNAME is resynthesized and thus 
	 * consistent with the DNAME */
	if(!no_partial &&
		(rrset=find_closest_of_type(env, qname, qnamelen, qclass, now,
		LDNS_RR_TYPE_DNAME, 1))) {
		/* synthesize a DNAME+CNAME message based on this */
		enum sec_status sec_status = sec_status_unchecked;
		struct dns_msg* msg = synth_dname_msg(rrset, region, now, &k,
			&sec_status);
		if(msg) {
			struct ub_packed_rrset_key* cname_rrset;
			lock_rw_unlock(&rrset->entry.lock);
			/* now, after unlocking the DNAME rrset lock,
			 * check the sec_status, and see if we need to look
			 * up the CNAME record associated before it can
			 * be used */
			/* normally, only secure DNAMEs allowed from cache*/
			if(sec_status == sec_status_secure)
				return msg;
			/* but if we have a CNAME cached with this name, then we
			 * have previously already allowed this name to pass.
			 * the next cache lookup is going to fetch that CNAME itself,
			 * but it is better to have the (unsigned)DNAME + CNAME in
			 * that case */
			cname_rrset = rrset_cache_lookup(
				env->rrset_cache, qname, qnamelen,
				LDNS_RR_TYPE_CNAME, qclass, 0, now, 0);
			if(cname_rrset) {
				/* CNAME already synthesized by
				 * synth_dname_msg routine, so we can
				 * straight up return the msg */
				lock_rw_unlock(&cname_rrset->entry.lock);
				return msg;
			}
		} else {
			lock_rw_unlock(&rrset->entry.lock);
		}
	}

	/* see if we have CNAME for this domain,
	 * but not for DS records (which are part of the parent) */
	if(!no_partial && qtype != LDNS_RR_TYPE_DS &&
	   (rrset=rrset_cache_lookup(env->rrset_cache, qname, qnamelen, 
		LDNS_RR_TYPE_CNAME, qclass, 0, now, 0))) {
		uint8_t* wc = NULL;
		size_t wl;
		/* if the rrset is not a wildcard expansion, with wcname */
		/* because, if we return that CNAME rrset on its own, it is
		 * missing the NSEC or NSEC3 proof */
		if(!(val_rrset_wildcard(rrset, &wc, &wl) && wc != NULL)) {
			struct dns_msg* msg = rrset_msg(rrset, region, now, &k);
			if(msg) {
				lock_rw_unlock(&rrset->entry.lock);
				return msg;
			}
		}
		lock_rw_unlock(&rrset->entry.lock);
	}

	/* construct DS, DNSKEY, DLV messages from rrset cache. */
	if((qtype == LDNS_RR_TYPE_DS || qtype == LDNS_RR_TYPE_DNSKEY ||
		qtype == LDNS_RR_TYPE_DLV) &&
		(rrset=rrset_cache_lookup(env->rrset_cache, qname, qnamelen, 
		qtype, qclass, 0, now, 0))) {
		/* if the rrset is from the additional section, and the
		 * signatures have fallen off, then do not synthesize a msg
		 * instead, allow a full query for signed results to happen.
		 * Forego all rrset data from additional section, because
		 * some signatures may not be present and cause validation
		 * failure.
		 */
		struct packed_rrset_data *d = (struct packed_rrset_data*)
			rrset->entry.data;
		if(d->trust != rrset_trust_add_noAA && 
			d->trust != rrset_trust_add_AA && 
			(qtype == LDNS_RR_TYPE_DS || 
				(d->trust != rrset_trust_auth_noAA 
				&& d->trust != rrset_trust_auth_AA) )) {
			struct dns_msg* msg = rrset_msg(rrset, region, now, &k);
			if(msg) {
				lock_rw_unlock(&rrset->entry.lock);
				return msg;
			}
		}
		lock_rw_unlock(&rrset->entry.lock);
	}

	/* stop downwards cache search on NXDOMAIN.
	 * Empty nonterminals are NOERROR, so an NXDOMAIN for foo
	 * means bla.foo also does not exist.  The DNSSEC proofs are
	 * the same.  We search upwards for NXDOMAINs. */
	if(env->cfg->harden_below_nxdomain)
	    while(!dname_is_root(k.qname)) {
		dname_remove_label(&k.qname, &k.qname_len);
		h = query_info_hash(&k, flags);
		e = slabhash_lookup(env->msg_cache, h, &k, 0);
		if(!e && k.qtype != LDNS_RR_TYPE_A &&
			env->cfg->qname_minimisation) {
			k.qtype = LDNS_RR_TYPE_A;
			h = query_info_hash(&k, flags);
			e = slabhash_lookup(env->msg_cache, h, &k, 0);
		}
		if(e) {
			struct reply_info* data = (struct reply_info*)e->data;
			struct dns_msg* msg;
			if(FLAGS_GET_RCODE(data->flags) == LDNS_RCODE_NXDOMAIN
			  && data->security == sec_status_secure
			  && (msg=tomsg(env, &k, data, region, now, scratch))){
				lock_rw_unlock(&e->lock);
				msg->qinfo.qname=qname;
				msg->qinfo.qname_len=qnamelen;
				/* check that DNSSEC really works out */
				msg->rep->security = sec_status_unchecked;
				return msg;
			}
			lock_rw_unlock(&e->lock);
		}
		k.qtype = qtype;
	    }

	/* fill common RR types for ANY response to avoid requery */
	if(qtype == LDNS_RR_TYPE_ANY) {
		return fill_any(env, qname, qnamelen, qtype, qclass, region);
	}

	return NULL;
}
Example #10
0
File: dns.c Project: coyizumi/cs111
struct dns_msg*
dns_cache_lookup(struct module_env* env,
                 uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
                 uint16_t flags, struct regional* region, struct regional* scratch)
{
    struct lruhash_entry* e;
    struct query_info k;
    hashvalue_t h;
    time_t now = *env->now;
    struct ub_packed_rrset_key* rrset;

    /* lookup first, this has both NXdomains and ANSWER responses */
    k.qname = qname;
    k.qname_len = qnamelen;
    k.qtype = qtype;
    k.qclass = qclass;
    h = query_info_hash(&k, flags);
    e = slabhash_lookup(env->msg_cache, h, &k, 0);
    if(e) {
        struct msgreply_entry* key = (struct msgreply_entry*)e->key;
        struct reply_info* data = (struct reply_info*)e->data;
        struct dns_msg* msg = tomsg(env, &key->key, data, region, now,
                                    scratch);
        if(msg) {
            lock_rw_unlock(&e->lock);
            return msg;
        }
        /* could be msg==NULL; due to TTL or not all rrsets available */
        lock_rw_unlock(&e->lock);
    }

    /* see if a DNAME exists. Checked for first, to enforce that DNAMEs
     * are more important, the CNAME is resynthesized and thus
     * consistent with the DNAME */
    if( (rrset=find_closest_of_type(env, qname, qnamelen, qclass, now,
                                    LDNS_RR_TYPE_DNAME, 1))) {
        /* synthesize a DNAME+CNAME message based on this */
        struct dns_msg* msg = synth_dname_msg(rrset, region, now, &k);
        if(msg) {
            lock_rw_unlock(&rrset->entry.lock);
            return msg;
        }
        lock_rw_unlock(&rrset->entry.lock);
    }

    /* see if we have CNAME for this domain,
     * but not for DS records (which are part of the parent) */
    if( qtype != LDNS_RR_TYPE_DS &&
            (rrset=rrset_cache_lookup(env->rrset_cache, qname, qnamelen,
                                      LDNS_RR_TYPE_CNAME, qclass, 0, now, 0))) {
        struct dns_msg* msg = rrset_msg(rrset, region, now, &k);
        if(msg) {
            lock_rw_unlock(&rrset->entry.lock);
            return msg;
        }
        lock_rw_unlock(&rrset->entry.lock);
    }

    /* construct DS, DNSKEY, DLV messages from rrset cache. */
    if((qtype == LDNS_RR_TYPE_DS || qtype == LDNS_RR_TYPE_DNSKEY ||
            qtype == LDNS_RR_TYPE_DLV) &&
            (rrset=rrset_cache_lookup(env->rrset_cache, qname, qnamelen,
                                      qtype, qclass, 0, now, 0))) {
        /* if the rrset is from the additional section, and the
         * signatures have fallen off, then do not synthesize a msg
         * instead, allow a full query for signed results to happen.
         * Forego all rrset data from additional section, because
         * some signatures may not be present and cause validation
         * failure.
         */
        struct packed_rrset_data *d = (struct packed_rrset_data*)
                                      rrset->entry.data;
        if(d->trust != rrset_trust_add_noAA &&
                d->trust != rrset_trust_add_AA &&
                (qtype == LDNS_RR_TYPE_DS ||
                 (d->trust != rrset_trust_auth_noAA
                  && d->trust != rrset_trust_auth_AA) )) {
            struct dns_msg* msg = rrset_msg(rrset, region, now, &k);
            if(msg) {
                lock_rw_unlock(&rrset->entry.lock);
                return msg;
            }
        }
        lock_rw_unlock(&rrset->entry.lock);
    }

    /* stop downwards cache search on NXDOMAIN.
     * Empty nonterminals are NOERROR, so an NXDOMAIN for foo
     * means bla.foo also does not exist.  The DNSSEC proofs are
     * the same.  We search upwards for NXDOMAINs. */
    if(env->cfg->harden_below_nxdomain)
        while(!dname_is_root(k.qname)) {
            dname_remove_label(&k.qname, &k.qname_len);
            h = query_info_hash(&k, flags);
            e = slabhash_lookup(env->msg_cache, h, &k, 0);
            if(e) {
                struct reply_info* data = (struct reply_info*)e->data;
                struct dns_msg* msg;
                if(FLAGS_GET_RCODE(data->flags) == LDNS_RCODE_NXDOMAIN
                        && data->security == sec_status_secure
                        && (msg=tomsg(env, &k, data, region, now, scratch))) {
                    lock_rw_unlock(&e->lock);
                    msg->qinfo.qname=qname;
                    msg->qinfo.qname_len=qnamelen;
                    /* check that DNSSEC really works out */
                    msg->rep->security = sec_status_unchecked;
                    return msg;
                }
                lock_rw_unlock(&e->lock);
            }
        }

    return NULL;
}