示例#1
0
/**
 * Handle a cachedb module event with a query
 * @param qstate: query state (from the mesh), passed between modules.
 * 	contains qstate->env module environment with global caches and so on.
 * @param iq: query state specific for this module.  per-query.
 * @param ie: environment specific for this module.  global.
 * @param id: module id.
 */
static void
cachedb_handle_query(struct module_qstate* qstate,
	struct cachedb_qstate* ATTR_UNUSED(iq),
	struct cachedb_env* ie, int id)
{
	/* check if we are enabled, and skip if so */
	if(!ie->enabled) {
		/* pass request to next module */
		qstate->ext_state[id] = module_wait_module;
		return;
	}

	if(qstate->blacklist || qstate->no_cache_lookup) {
		/* cache is blacklisted or we are instructed from edns to not look */
		/* pass request to next module */
		qstate->ext_state[id] = module_wait_module;
		return;
	}

	/* lookup inside unbound's internal cache */
	if(cachedb_intcache_lookup(qstate)) {
		if(verbosity >= VERB_ALGO) {
			if(qstate->return_msg->rep)
				log_dns_msg("cachedb internal cache lookup",
					&qstate->return_msg->qinfo,
					qstate->return_msg->rep);
			else log_info("cachedb internal cache lookup: rcode %s",
				sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)?
				sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)->name:"??");
		}
		/* we are done with the query */
		qstate->ext_state[id] = module_finished;
		return;
	}

	/* ask backend cache to see if we have data */
	if(cachedb_extcache_lookup(qstate, ie)) {
		if(verbosity >= VERB_ALGO)
			log_dns_msg(ie->backend->name,
				&qstate->return_msg->qinfo,
				qstate->return_msg->rep);
		/* store this result in internal cache */
		cachedb_intcache_store(qstate);
		/* we are done with the query */
		qstate->ext_state[id] = module_finished;
		return;
	}

	/* no cache fetches */
	/* pass request to next module */
	qstate->ext_state[id] = module_wait_module;
}
示例#2
0
/* Create response according to the ldns packet content */
int createResponse(struct module_qstate* qstate, sldns_buffer* pkt)
{
    struct msg_parse* prs;
    struct edns_data edns;
    
    /* parse message */
    prs = (struct msg_parse*) regional_alloc(qstate->env->scratch, sizeof(struct msg_parse));
    if (!prs) {
	log_err("storeResponse: out of memory on incoming message");
	return 0;
    }

    memset(prs, 0, sizeof(*prs));
    memset(&edns, 0, sizeof(edns));

    sldns_buffer_set_position(pkt, 0);
    if (parse_packet(pkt, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) {
	verbose(VERB_ALGO, "storeResponse: parse error on reply packet");
	return 0;
    }
    /* edns is not examined, but removed from message to help cache */
    if(parse_extract_edns(prs, &edns) != LDNS_RCODE_NOERROR)
	return 0;

    /* remove CD-bit, we asked for in case we handle validation ourself */
    prs->flags &= ~BIT_CD;

    /* allocate response dns_msg in region */
    qstate->return_msg = (struct dns_msg*)regional_alloc(qstate->region, sizeof(struct dns_msg));
    if (!qstate->return_msg)
       return 0;

    memset(qstate->return_msg, 0, sizeof(*qstate->return_msg));
    if(!parse_create_msg(pkt, prs, NULL, &(qstate->return_msg)->qinfo, &(qstate->return_msg)->rep, qstate->region)) {
	log_err("storeResponse: malloc failure: allocating incoming dns_msg");
	return 0;
    }
    
    /* Make sure that the RA flag is set (since the presence of 
     * this module means that recursion is available) */
    /* qstate->return_msg->rep->flags |= BIT_RA; */

    /* Clear the AA flag */
    /* FIXME: does this action go here or in some other module? */
    /*qstate->return_msg->rep->flags &= ~BIT_AA; */

    /* make sure QR flag is on */
    /*qstate->return_msg->rep->flags |= BIT_QR; */

    if(verbosity >= VERB_ALGO)
	log_dns_msg("storeResponse: packet:", &qstate->return_msg->qinfo, qstate->return_msg->rep);

    return 1;
}
示例#3
0
/** convert data from return_msg into the data buffer */
static int
prep_data(struct module_qstate* qstate, struct sldns_buffer* buf)
{
	uint64_t timestamp, expiry;
	size_t oldlim;
	struct edns_data edns;
	memset(&edns, 0, sizeof(edns));
	edns.edns_present = 1;
	edns.bits = EDNS_DO;
	edns.ext_rcode = 0;
	edns.edns_version = EDNS_ADVERTISED_VERSION;
	edns.udp_size = EDNS_ADVERTISED_SIZE;

	if(!qstate->return_msg || !qstate->return_msg->rep)
		return 0;
	/* We don't store the reply if its TTL is 0 unless serve-expired is
	 * enabled.  Such a reply won't be reusable and simply be a waste for
	 * the backend.  It's also compatible with the default behavior of
	 * dns_cache_store_msg(). */
	if(qstate->return_msg->rep->ttl == 0 &&
		!qstate->env->cfg->serve_expired)
		return 0;
	if(verbosity >= VERB_ALGO)
		log_dns_msg("cachedb encoding", &qstate->return_msg->qinfo,
	                qstate->return_msg->rep);
	if(!reply_info_answer_encode(&qstate->return_msg->qinfo,
		qstate->return_msg->rep, 0, qstate->query_flags,
		buf, 0, 1, qstate->env->scratch, 65535, &edns, 1, 0))
		return 0;

	/* TTLs in the return_msg are relative to time(0) so we have to
	 * store that, we also store the smallest ttl in the packet+time(0)
	 * as the packet expiry time */
	/* qstate->return_msg->rep->ttl contains that relative shortest ttl */
	timestamp = (uint64_t)*qstate->env->now;
	expiry = timestamp + (uint64_t)qstate->return_msg->rep->ttl;
	timestamp = htobe64(timestamp);
	expiry = htobe64(expiry);
	oldlim = sldns_buffer_limit(buf);
	if(oldlim + sizeof(timestamp)+sizeof(expiry) >=
		sldns_buffer_capacity(buf))
		return 0; /* doesn't fit. */
	sldns_buffer_set_limit(buf, oldlim + sizeof(timestamp)+sizeof(expiry));
	sldns_buffer_write_at(buf, oldlim, &timestamp, sizeof(timestamp));
	sldns_buffer_write_at(buf, oldlim+sizeof(timestamp), &expiry,
		sizeof(expiry));

	return 1;
}
示例#4
0
/** check RRSIGs in packet */
static void
check_the_rrsigs(struct query_info* qinfo, struct reply_info* rep)
{
	/* every RRSIG must be matched to an RRset */
	size_t i;
	for(i=0; i<rep->rrset_count; i++) {
		struct ub_packed_rrset_key* s = rep->rrsets[i];
		if(ntohs(s->rk.type) == LDNS_RR_TYPE_RRSIG) {
			/* see if really a problem, i.e. is there a data
			 * element. */
			if(no_data_for_rrsig(rep, rep->rrsets[i]))
				continue;
			log_dns_msg("rrsig failed for packet", qinfo, rep);
			print_packet_rrsets(qinfo, rep);
			printf("failed rrset is nr %d\n", (int)i);
			unit_assert(0);
		}
	}
}
示例#5
0
enum val_classification 
val_classify_response(uint16_t query_flags, struct query_info* origqinf,
	struct query_info* qinf, struct reply_info* rep, size_t skip)
{
	int rcode = (int)FLAGS_GET_RCODE(rep->flags);
	size_t i;

	/* Normal Name Error's are easy to detect -- but don't mistake a CNAME
	 * chain ending in NXDOMAIN. */
	if(rcode == LDNS_RCODE_NXDOMAIN && rep->an_numrrsets == 0)
		return VAL_CLASS_NAMEERROR;

	/* check for referral: nonRD query and it looks like a nodata */
	if(!(query_flags&BIT_RD) && rep->an_numrrsets == 0 &&
		rcode == LDNS_RCODE_NOERROR) {
		/* SOA record in auth indicates it is NODATA instead.
		 * All validation requiring NODATA messages have SOA in 
		 * authority section. */
		/* uses fact that answer section is empty */
		int saw_ns = 0;
		for(i=0; i<rep->ns_numrrsets; i++) {
			if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_SOA)
				return VAL_CLASS_NODATA;
			if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_DS)
				return VAL_CLASS_REFERRAL;
			if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
				saw_ns = 1;
		}
		return saw_ns?VAL_CLASS_REFERRAL:VAL_CLASS_NODATA;
	}
	/* root referral where NS set is in the answer section */
	if(!(query_flags&BIT_RD) && rep->ns_numrrsets == 0 &&
		rep->an_numrrsets == 1 && rcode == LDNS_RCODE_NOERROR &&
		ntohs(rep->rrsets[0]->rk.type) == LDNS_RR_TYPE_NS &&
		query_dname_compare(rep->rrsets[0]->rk.dname, 
			origqinf->qname) != 0)
		return VAL_CLASS_REFERRAL;

	/* dump bad messages */
	if(rcode != LDNS_RCODE_NOERROR)
		return VAL_CLASS_UNKNOWN;
	log_assert(rcode == LDNS_RCODE_NOERROR);
	/* next check if the skip into the answer section shows no answer */
	if(skip>0 && rep->an_numrrsets <= skip)
		return VAL_CLASS_CNAMENOANSWER;

	/* Next is NODATA */
	if(rep->an_numrrsets == 0)
		return VAL_CLASS_NODATA;
	
	/* We distinguish between CNAME response and other positive/negative
	 * responses because CNAME answers require extra processing. */

	/* We distinguish between ANY and CNAME or POSITIVE because 
	 * ANY responses are validated differently. */
	if(qinf->qtype == LDNS_RR_TYPE_ANY)
		return VAL_CLASS_ANY;
	
	/* Note that DNAMEs will be ignored here, unless qtype=DNAME. Unless
	 * qtype=CNAME, this will yield a CNAME response. */
	for(i=skip; i<rep->an_numrrsets; i++) {
		if(ntohs(rep->rrsets[i]->rk.type) == qinf->qtype)
			return VAL_CLASS_POSITIVE;
		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME)
			return VAL_CLASS_CNAME;
	}
	log_dns_msg("validator: error. failed to classify response message: ",
		qinf, rep);
	return VAL_CLASS_UNKNOWN;
}