Exemplo n.º 1
0
size_t
nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, 
	size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max)
{
	size_t i, hash_len;
	/* prepare buffer for first iteration */
	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, nm, nmlen);
	query_dname_tolower(sldns_buffer_begin(buf));
	sldns_buffer_write(buf, salt, saltlen);
	sldns_buffer_flip(buf);
	hash_len = nsec3_hash_algo_size_supported(algo);
	if(hash_len == 0) {
		log_err("nsec3 hash of unknown algo %d", algo);
		return 0;
	}
	if(hash_len > max)
		return 0;
	if(!secalgo_nsec3_hash(algo, (unsigned char*)sldns_buffer_begin(buf),
		sldns_buffer_limit(buf), (unsigned char*)res))
		return 0;
	for(i=0; i<iter; i++) {
		sldns_buffer_clear(buf);
		sldns_buffer_write(buf, res, hash_len);
		sldns_buffer_write(buf, salt, saltlen);
		sldns_buffer_flip(buf);
		if(!secalgo_nsec3_hash(algo,
			(unsigned char*)sldns_buffer_begin(buf),
			sldns_buffer_limit(buf), (unsigned char*)res))
			return 0;
	}
	return hash_len;
}
Exemplo n.º 2
0
/** setup looped dname and out-of-bounds dname ptr */
static void
dname_setup_bufs(sldns_buffer* loopbuf, sldns_buffer* boundbuf)
{
	sldns_buffer_write_u16(loopbuf, 0xd54d);  /* id */
	sldns_buffer_write_u16(loopbuf, 0x12);    /* flags  */
	sldns_buffer_write_u16(loopbuf, 1);       /* qdcount */
	sldns_buffer_write_u16(loopbuf, 0);       /* ancount */
	sldns_buffer_write_u16(loopbuf, 0);       /* nscount */
	sldns_buffer_write_u16(loopbuf, 0);       /* arcount */
	sldns_buffer_write_u8(loopbuf, 0xc0); /* PTR back at itself */
	sldns_buffer_write_u8(loopbuf, 0x0c);
	sldns_buffer_flip(loopbuf);

	sldns_buffer_write_u16(boundbuf, 0xd54d);  /* id */
	sldns_buffer_write_u16(boundbuf, 0x12);    /* flags  */
	sldns_buffer_write_u16(boundbuf, 1);       /* qdcount */
	sldns_buffer_write_u16(boundbuf, 0);       /* ancount */
	sldns_buffer_write_u16(boundbuf, 0);       /* nscount */
	sldns_buffer_write_u16(boundbuf, 0);       /* arcount */
	sldns_buffer_write_u8(boundbuf, 0x01); /* len=1 */
	sldns_buffer_write_u8(boundbuf, (uint8_t)'A'); /* A. label */
	sldns_buffer_write_u8(boundbuf, 0xc0); /* PTR out of bounds */
	sldns_buffer_write_u8(boundbuf, 0xcc);
	sldns_buffer_flip(boundbuf);
}
Exemplo n.º 3
0
size_t
nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, 
	size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max)
{
	size_t i, hash_len;
	/* prepare buffer for first iteration */
	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, nm, nmlen);
	query_dname_tolower(sldns_buffer_begin(buf));
	sldns_buffer_write(buf, salt, saltlen);
	sldns_buffer_flip(buf);
	switch(algo) {
#if defined(HAVE_EVP_SHA1) || defined(HAVE_NSS)
		case NSEC3_HASH_SHA1:
#ifdef HAVE_SSL
			hash_len = SHA_DIGEST_LENGTH;
#else
			hash_len = SHA1_LENGTH;
#endif
			if(hash_len > max)
				return 0;
#  ifdef HAVE_SSL
			(void)SHA1((unsigned char*)sldns_buffer_begin(buf),
				(unsigned long)sldns_buffer_limit(buf),
				(unsigned char*)res);
#  else
			(void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)res,
				(unsigned char*)sldns_buffer_begin(buf),
				(unsigned long)sldns_buffer_limit(buf));
#  endif
			for(i=0; i<iter; i++) {
				sldns_buffer_clear(buf);
				sldns_buffer_write(buf, res, hash_len);
				sldns_buffer_write(buf, salt, saltlen);
				sldns_buffer_flip(buf);
#  ifdef HAVE_SSL
				(void)SHA1(
					(unsigned char*)sldns_buffer_begin(buf),
					(unsigned long)sldns_buffer_limit(buf),
					(unsigned char*)res);
#  else
				(void)HASH_HashBuf(HASH_AlgSHA1,
					(unsigned char*)res,
					(unsigned char*)sldns_buffer_begin(buf),
					(unsigned long)sldns_buffer_limit(buf));
#  endif
			}
			break;
#endif /* HAVE_EVP_SHA1 or NSS */
		default:
			log_err("nsec3 hash of unknown algo %d", algo);
			return 0;
	}
	return hash_len;
}
Exemplo n.º 4
0
/**
 * Fill CH class answer into buffer. Keeps query.
 * @param pkt: buffer
 * @param str: string to put into text record (<255).
 * @param edns: edns reply information.
 * @param worker: worker with scratch region.
 */
static void
chaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns,
	struct worker* worker)
{
	size_t len = strlen(str);
	unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt));
	unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt));
	if(len>255) len=255; /* cap size of TXT record */
	sldns_buffer_clear(pkt);
	sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */
	sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA));
	if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt));
	if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt));
	sldns_buffer_write_u16(pkt, 1); /* qdcount */
	sldns_buffer_write_u16(pkt, 1); /* ancount */
	sldns_buffer_write_u16(pkt, 0); /* nscount */
	sldns_buffer_write_u16(pkt, 0); /* arcount */
	(void)query_dname_len(pkt); /* skip qname */
	sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */
	sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */
	sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */
	sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT);
	sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH);
	sldns_buffer_write_u32(pkt, 0); /* TTL */
	sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len);
	sldns_buffer_write_u8(pkt, len);
	sldns_buffer_write(pkt, str, len);
	sldns_buffer_flip(pkt);
	edns->edns_version = EDNS_ADVERTISED_VERSION;
	edns->udp_size = EDNS_ADVERTISED_SIZE;
	edns->bits &= EDNS_DO;
	if(!edns_opt_inplace_reply(edns, worker->scratchpad))
		edns->opt_list = NULL;
	attach_edns_record(pkt, edns);
}
Exemplo n.º 5
0
void dname_test(void)
{
	sldns_buffer* loopbuf = sldns_buffer_new(14);
	sldns_buffer* boundbuf = sldns_buffer_new(16);
	sldns_buffer* buff = sldns_buffer_new(65800);
	unit_assert(loopbuf && boundbuf && buff);
	sldns_buffer_flip(buff);
	dname_setup_bufs(loopbuf, boundbuf);
	dname_test_qdl(buff);
	dname_test_qdtl(buff);
	dname_test_pdtl(loopbuf, boundbuf);
	dname_test_query_dname_compare();
	dname_test_count_labels();
	dname_test_count_size_labels();
	dname_test_dname_lab_cmp();
	dname_test_pkt_dname_len(buff);
	dname_test_strict_subdomain();
	dname_test_subdomain();
	dname_test_isroot();
	dname_test_removelabel();
	dname_test_sigcount();
	dname_test_iswild();
	dname_test_canoncmp();
	dname_test_topdomain();
	dname_test_valid();
	sldns_buffer_free(buff);
	sldns_buffer_free(loopbuf);
	sldns_buffer_free(boundbuf);
}
Exemplo n.º 6
0
/**
 * Create a DS digest for a DNSKEY entry.
 *
 * @param env: module environment. Uses scratch space.
 * @param dnskey_rrset: DNSKEY rrset.
 * @param dnskey_idx: index of RR in rrset.
 * @param ds_rrset: DS rrset
 * @param ds_idx: index of RR in DS rrset.
 * @param digest: digest is returned in here (must be correctly sized).
 * @return false on error.
 */
static int
ds_create_dnskey_digest(struct module_env* env, 
	struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx,
	struct ub_packed_rrset_key* ds_rrset, size_t ds_idx,
	uint8_t* digest)
{
	sldns_buffer* b = env->scratch_buffer;
	uint8_t* dnskey_rdata;
	size_t dnskey_len;
	rrset_get_rdata(dnskey_rrset, dnskey_idx, &dnskey_rdata, &dnskey_len);

	/* create digest source material in buffer 
	 * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
	 *	DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */
	sldns_buffer_clear(b);
	sldns_buffer_write(b, dnskey_rrset->rk.dname, 
		dnskey_rrset->rk.dname_len);
	query_dname_tolower(sldns_buffer_begin(b));
	sldns_buffer_write(b, dnskey_rdata+2, dnskey_len-2); /* skip rdatalen*/
	sldns_buffer_flip(b);
	
	return secalgo_ds_digest(ds_get_digest_algo(ds_rrset, ds_idx),
		(unsigned char*)sldns_buffer_begin(b), sldns_buffer_limit(b),
		(unsigned char*)digest);
}
Exemplo n.º 7
0
void
attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
{
	size_t len;
	size_t rdatapos;
	struct edns_option* opt;
	if(!edns || !edns->edns_present)
		return;
	/* inc additional count */
	sldns_buffer_write_u16_at(pkt, 10,
		sldns_buffer_read_u16_at(pkt, 10) + 1);
	len = sldns_buffer_limit(pkt);
	sldns_buffer_clear(pkt);
	sldns_buffer_set_position(pkt, len);
	/* write EDNS record */
	sldns_buffer_write_u8(pkt, 0); /* '.' label */
	sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
	sldns_buffer_write_u16(pkt, edns->udp_size); /* class */
	sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
	sldns_buffer_write_u8(pkt, edns->edns_version);
	sldns_buffer_write_u16(pkt, edns->bits);
	rdatapos = sldns_buffer_position(pkt);
	sldns_buffer_write_u16(pkt, 0); /* rdatalen */
	/* write rdata */
	for(opt=edns->opt_list; opt; opt=opt->next) {
		sldns_buffer_write_u16(pkt, opt->opt_code);
		sldns_buffer_write_u16(pkt, opt->opt_len);
		if(opt->opt_len != 0)
			sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
	}
	if(edns->opt_list)
		sldns_buffer_write_u16_at(pkt, rdatapos, 
			sldns_buffer_position(pkt)-rdatapos-2);
	sldns_buffer_flip(pkt);
}
Exemplo n.º 8
0
static int
testframe_lookup(struct module_env* env, struct cachedb_env* cachedb_env,
	char* key, struct sldns_buffer* result_buffer)
{
	struct testframe_moddata* d = (struct testframe_moddata*)
		cachedb_env->backend_data;
	(void)env;
	verbose(VERB_ALGO, "testframe_lookup of %s", key);
	lock_basic_lock(&d->lock);
	if(d->stored_key && strcmp(d->stored_key, key) == 0) {
		if(d->stored_datalen > sldns_buffer_capacity(result_buffer)) {
			lock_basic_unlock(&d->lock);
			return 0; /* too large */
		}
		verbose(VERB_ALGO, "testframe_lookup found %d bytes",
			(int)d->stored_datalen);
		sldns_buffer_clear(result_buffer);
		sldns_buffer_write(result_buffer, d->stored_data,
			d->stored_datalen);
		sldns_buffer_flip(result_buffer);
		lock_basic_unlock(&d->lock);
		return 1;
	}
	lock_basic_unlock(&d->lock);
	return 0;
}
Exemplo n.º 9
0
/** 
 * answer in case where no exact match is found 
 * @param z: zone for query
 * @param qinfo: query
 * @param edns: edns from query
 * @param buf: buffer for answer.
 * @param temp: temp region for encoding
 * @param ld: local data, if NULL, no such name exists in localdata.
 * @param lz_type: type of the local zone
 * @return 1 if a reply is to be sent, 0 if not.
 */
static int
lz_zone_answer(struct local_zone* z, struct query_info* qinfo,
	struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
	struct local_data* ld, enum localzone_type lz_type)
{
	if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) {
		/** no reply at all, signal caller by clearing buffer. */
		sldns_buffer_clear(buf);
		sldns_buffer_flip(buf);
		return 1;
	} else if(lz_type == local_zone_refuse
		|| lz_type == local_zone_always_refuse) {
		error_encode(buf, (LDNS_RCODE_REFUSED|BIT_AA), qinfo,
			*(uint16_t*)sldns_buffer_begin(buf),
		       sldns_buffer_read_u16_at(buf, 2), edns);
		return 1;
	} else if(lz_type == local_zone_static ||
		lz_type == local_zone_redirect ||
		lz_type == local_zone_always_nxdomain) {
		/* for static, reply nodata or nxdomain
		 * for redirect, reply nodata */
		/* no additional section processing,
		 * cname, dname or wildcard processing,
		 * or using closest match for NSEC.
		 * or using closest match for returning delegation downwards
		 */
		int rcode = (ld || lz_type == local_zone_redirect)?
			LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
		if(z->soa)
			return local_encode(qinfo, edns, buf, temp, 
				z->soa, 0, rcode);
		error_encode(buf, (rcode|BIT_AA), qinfo, 
			*(uint16_t*)sldns_buffer_begin(buf), 
			sldns_buffer_read_u16_at(buf, 2), edns);
		return 1;
	} else if(lz_type == local_zone_typetransparent
		|| lz_type == local_zone_always_transparent) {
		/* no NODATA or NXDOMAINS for this zone type */
		return 0;
	}
	/* else lz_type == local_zone_transparent */

	/* if the zone is transparent and the name exists, but the type
	 * does not, then we should make this noerror/nodata */
	if(ld && ld->rrsets) {
		int rcode = LDNS_RCODE_NOERROR;
		if(z->soa)
			return local_encode(qinfo, edns, buf, temp, 
				z->soa, 0, rcode);
		error_encode(buf, (rcode|BIT_AA), qinfo, 
			*(uint16_t*)sldns_buffer_begin(buf), 
			sldns_buffer_read_u16_at(buf, 2), edns);
		return 1;
	}

	/* stop here, and resolve further on */
	return 0;
}
Exemplo n.º 10
0
void 
sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from)
{
	size_t tocopy = sldns_buffer_limit(from);

	if(tocopy > sldns_buffer_capacity(result))
		tocopy = sldns_buffer_capacity(result);
	sldns_buffer_clear(result);
	sldns_buffer_write(result, sldns_buffer_begin(from), tocopy);
	sldns_buffer_flip(result);
}
Exemplo n.º 11
0
/**
 * Create canonical form of rrset in the scratch buffer.
 * @param region: temporary region.
 * @param buf: the buffer to use.
 * @param k: the rrset to insert.
 * @param sig: RRSIG rdata to include.
 * @param siglen: RRSIG rdata len excluding signature field, but inclusive
 * 	signer name length.
 * @param sortree: if NULL is passed a new sorted rrset tree is built.
 * 	Otherwise it is reused.
 * @return false on alloc error.
 */
static int
rrset_canonical(struct regional* region, sldns_buffer* buf, 
	struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen,
	struct rbtree_t** sortree)
{
	struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
	uint8_t* can_owner = NULL;
	size_t can_owner_len = 0;
	struct canon_rr* walk;
	struct canon_rr* rrs;

	if(!*sortree) {
		*sortree = (struct rbtree_t*)regional_alloc(region, 
			sizeof(rbtree_t));
		if(!*sortree)
			return 0;
		if(d->count > RR_COUNT_MAX)
			return 0; /* integer overflow protection */
		rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count);
		if(!rrs) {
			*sortree = NULL;
			return 0;
		}
		rbtree_init(*sortree, &canonical_tree_compare);
		canonical_sort(k, d, *sortree, rrs);
	}

	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, sig, siglen);
	/* canonicalize signer name */
	query_dname_tolower(sldns_buffer_begin(buf)+18); 
	RBTREE_FOR(walk, struct canon_rr*, (*sortree)) {
		/* see if there is enough space left in the buffer */
		if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4
			+ d->rr_len[walk->rr_idx]) {
			log_err("verify: failed to canonicalize, "
				"rrset too big");
			return 0;
		}
		/* determine canonical owner name */
		if(can_owner)
			sldns_buffer_write(buf, can_owner, can_owner_len);
		else	insert_can_owner(buf, k, sig, &can_owner, 
				&can_owner_len);
		sldns_buffer_write(buf, &k->rk.type, 2);
		sldns_buffer_write(buf, &k->rk.rrset_class, 2);
		sldns_buffer_write(buf, sig+4, 4);
		sldns_buffer_write(buf, d->rr_data[walk->rr_idx], 
			d->rr_len[walk->rr_idx]);
		canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]);
	}
	sldns_buffer_flip(buf);
	return 1;
}
Exemplo n.º 12
0
/** entry to packet buffer with wireformat */
static void
entry_to_buf(struct entry* e, sldns_buffer* pkt)
{
	unit_assert(e->reply_list);
	if(e->reply_list->reply_from_hex) {
		sldns_buffer_copy(pkt, e->reply_list->reply_from_hex);
	} else {
		sldns_buffer_clear(pkt);
		sldns_buffer_write(pkt, e->reply_list->reply_pkt,
			e->reply_list->reply_len);
		sldns_buffer_flip(pkt);
	}
}
Exemplo n.º 13
0
void anchors_test(void)
{
	sldns_buffer* buff = sldns_buffer_new(65800);
	struct val_anchors* a;
	unit_show_feature("trust anchor store");
	unit_assert(a = anchors_create());
	sldns_buffer_flip(buff);
	test_anchor_empty(a);
	test_anchor_one(buff, a);
	test_anchors(buff, a);
	anchors_delete(a);
	sldns_buffer_free(buff);
}
Exemplo n.º 14
0
/** put dname into buffer */
static sldns_buffer*
dname_to_buf(sldns_buffer* b, const char* str)
{
	int e;
	size_t len = sldns_buffer_capacity(b);
	sldns_buffer_clear(b);
	e = sldns_str2wire_dname_buf(str, sldns_buffer_begin(b), &len);
	if(e != 0)
		fatal_exit("%s ldns: %s", __func__, 
			sldns_get_errorstr_parse(e));
	sldns_buffer_set_position(b, len);
	sldns_buffer_flip(b);
	return b;
}
Exemplo n.º 15
0
struct waiting_tcp* 
pending_tcp_query(struct outside_network* outnet, sldns_buffer* packet,
	struct sockaddr_storage* addr, socklen_t addrlen, int timeout,
	comm_point_callback_t* callback, void* callback_arg,
	int ATTR_UNUSED(ssl_upstream))
{
	struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
	struct fake_pending* pend = (struct fake_pending*)calloc(1,
		sizeof(struct fake_pending));
	log_assert(pend);
	pend->buffer = sldns_buffer_new(sldns_buffer_capacity(packet));
	log_assert(pend->buffer);
	sldns_buffer_write(pend->buffer, sldns_buffer_begin(packet),
		sldns_buffer_limit(packet));
	sldns_buffer_flip(pend->buffer);
	memcpy(&pend->addr, addr, addrlen);
	pend->addrlen = addrlen;
	pend->callback = callback;
	pend->cb_arg = callback_arg;
	pend->timeout = timeout;
	pend->transport = transport_tcp;
	pend->pkt = NULL;
	pend->zone = NULL;
	pend->runtime = runtime;
	pend->serviced = 0;
	pend->pkt_len = sldns_buffer_limit(packet);
	pend->pkt = memdup(sldns_buffer_begin(packet), pend->pkt_len);
	if(!pend->pkt) fatal_exit("out of memory");
	log_pkt("pending tcp pkt: ", pend->pkt, pend->pkt_len);

	/* see if it matches the current moment */
	if(runtime->now && runtime->now->evt_type == repevt_back_query &&
		(runtime->now->addrlen == 0 || sockaddr_cmp(
			&runtime->now->addr, runtime->now->addrlen,
			&pend->addr, pend->addrlen) == 0) &&
		find_match(runtime->now->match, pend->pkt, pend->pkt_len,
			pend->transport)) {
		log_info("testbound: matched pending to event. "
			"advance time between events.");
		log_info("testbound: do STEP %d %s", runtime->now->time_step,
			repevt_string(runtime->now->evt_type));
		advance_moment(runtime);
		/* still create the pending, because we need it to callback */
	} 
	log_info("testbound: created fake pending");
	/* add to list */
	pend->next = runtime->pending_list;
	runtime->pending_list = pend;
	return (struct waiting_tcp*)pend;
}
Exemplo n.º 16
0
/** perform hash of name */
static int
nsec3_calc_hash(struct regional* region, sldns_buffer* buf, 
	struct nsec3_cached_hash* c)
{
	int algo = nsec3_get_algo(c->nsec3, c->rr);
	size_t iter = nsec3_get_iter(c->nsec3, c->rr);
	uint8_t* salt;
	size_t saltlen, i;
	if(!nsec3_get_salt(c->nsec3, c->rr, &salt, &saltlen))
		return -1;
	/* prepare buffer for first iteration */
	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, c->dname, c->dname_len);
	query_dname_tolower(sldns_buffer_begin(buf));
	sldns_buffer_write(buf, salt, saltlen);
	sldns_buffer_flip(buf);
	c->hash_len = nsec3_hash_algo_size_supported(algo);
	if(c->hash_len == 0) {
		log_err("nsec3 hash of unknown algo %d", algo);
		return -1;
	}
	c->hash = (uint8_t*)regional_alloc(region, c->hash_len);
	if(!c->hash)
		return 0;
	(void)secalgo_nsec3_hash(algo, (unsigned char*)sldns_buffer_begin(buf),
		sldns_buffer_limit(buf), (unsigned char*)c->hash);
	for(i=0; i<iter; i++) {
		sldns_buffer_clear(buf);
		sldns_buffer_write(buf, c->hash, c->hash_len);
		sldns_buffer_write(buf, salt, saltlen);
		sldns_buffer_flip(buf);
		(void)secalgo_nsec3_hash(algo,
			(unsigned char*)sldns_buffer_begin(buf),
			sldns_buffer_limit(buf), (unsigned char*)c->hash);
	}
	return 1;
}
Exemplo n.º 17
0
void 
qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo)
{
	uint16_t flags = 0; /* QUERY, NOERROR */
	sldns_buffer_clear(pkt);
	log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
	sldns_buffer_skip(pkt, 2); /* id done later */
	sldns_buffer_write_u16(pkt, flags);
	sldns_buffer_write_u16(pkt, 1); /* query count */
	sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
	sldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len);
	sldns_buffer_write_u16(pkt, qinfo->qtype);
	sldns_buffer_write_u16(pkt, qinfo->qclass);
	sldns_buffer_flip(pkt);
}
Exemplo n.º 18
0
void 
error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
	uint16_t qid, uint16_t qflags, struct edns_data* edns)
{
	uint16_t flags;

	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, &qid, sizeof(uint16_t));
	flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/
	flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
	sldns_buffer_write_u16(buf, flags);
	if(qinfo) flags = 1;
	else	flags = 0;
	sldns_buffer_write_u16(buf, flags);
	flags = 0;
	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
	if(qinfo) {
		const uint8_t* qname = qinfo->local_alias ?
			qinfo->local_alias->rrset->rk.dname : qinfo->qname;
		size_t qname_len = qinfo->local_alias ?
			qinfo->local_alias->rrset->rk.dname_len :
			qinfo->qname_len;
		if(sldns_buffer_current(buf) == qname)
			sldns_buffer_skip(buf, (ssize_t)qname_len);
		else	sldns_buffer_write(buf, qname, qname_len);
		sldns_buffer_write_u16(buf, qinfo->qtype);
		sldns_buffer_write_u16(buf, qinfo->qclass);
	}
	sldns_buffer_flip(buf);
	if(edns) {
		struct edns_data es = *edns;
		es.edns_version = EDNS_ADVERTISED_VERSION;
		es.udp_size = EDNS_ADVERTISED_SIZE;
		es.ext_rcode = 0;
		es.bits &= EDNS_DO;
		if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
			edns->udp_size)
			return;
		attach_edns_record(buf, &es);
	}
}
Exemplo n.º 19
0
void 
qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo)
{
	uint16_t flags = 0; /* QUERY, NOERROR */
	const uint8_t* qname = qinfo->local_alias ?
		qinfo->local_alias->rrset->rk.dname : qinfo->qname;
	size_t qname_len = qinfo->local_alias ?
		qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len;
	sldns_buffer_clear(pkt);
	log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
	sldns_buffer_skip(pkt, 2); /* id done later */
	sldns_buffer_write_u16(pkt, flags);
	sldns_buffer_write_u16(pkt, 1); /* query count */
	sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
	sldns_buffer_write(pkt, qname, qname_len);
	sldns_buffer_write_u16(pkt, qinfo->qtype);
	sldns_buffer_write_u16(pkt, qinfo->qclass);
	sldns_buffer_flip(pkt);
}
Exemplo n.º 20
0
/* takes a hex string and puts into buffer */
void hex_to_buf(sldns_buffer* pkt, const char* hex)
{
	const char* p = hex;
	int val;
	sldns_buffer_clear(pkt);
	while(*p) {
		skip_whites(&p);
		if(sldns_buffer_position(pkt) == sldns_buffer_limit(pkt))
			fatal_exit("hex_to_buf: buffer too small");
		if(!isalnum((unsigned char)*p))
			break;
		val = sldns_hexdigit_to_int(*p++) << 4;
		skip_whites(&p);
		log_assert(*p && isalnum((unsigned char)*p));
		val |= sldns_hexdigit_to_int(*p++);
		sldns_buffer_write_u8(pkt, (uint8_t)val);
		skip_whites(&p);
	}
	sldns_buffer_flip(pkt);
}
Exemplo n.º 21
0
void
attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
{
	size_t len;
	if(!edns || !edns->edns_present)
		return;
	/* inc additional count */
	sldns_buffer_write_u16_at(pkt, 10,
		sldns_buffer_read_u16_at(pkt, 10) + 1);
	len = sldns_buffer_limit(pkt);
	sldns_buffer_clear(pkt);
	sldns_buffer_set_position(pkt, len);
	/* write EDNS record */
	sldns_buffer_write_u8(pkt, 0); /* '.' label */
	sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
	sldns_buffer_write_u16(pkt, edns->udp_size); /* class */
	sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
	sldns_buffer_write_u8(pkt, edns->edns_version);
	sldns_buffer_write_u16(pkt, edns->bits);
	sldns_buffer_write_u16(pkt, 0); /* rdatalen */
	sldns_buffer_flip(pkt);
}
Exemplo n.º 22
0
/**
 * Fill buffer with reply from the entry.
 */
static void
fill_buffer_with_reply(sldns_buffer* buffer, struct entry* entry, uint8_t* q,
	size_t qlen)
{
	uint8_t* c;
	size_t clen;
	log_assert(entry && entry->reply_list);
	sldns_buffer_clear(buffer);
	if(entry->reply_list->reply_from_hex) {
		c = sldns_buffer_begin(entry->reply_list->reply_from_hex);
		clen = sldns_buffer_limit(entry->reply_list->reply_from_hex);
		if(!c) fatal_exit("out of memory");
	} else {
		c = entry->reply_list->reply_pkt;
		clen = entry->reply_list->reply_len;
	}
	if(c) {
		if(q) adjust_packet(entry, &c, &clen, q, qlen);
		sldns_buffer_write(buffer, c, clen);
		if(q) free(c);
	}
	sldns_buffer_flip(buffer);
}
Exemplo n.º 23
0
int 
reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 
	uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow, 
	struct regional* region, uint16_t udpsize, int dnssec)
{
	uint16_t ancount=0, nscount=0, arcount=0;
	struct compress_tree_node* tree = 0;
	int r;
	size_t rr_offset; 

	sldns_buffer_clear(buffer);
	if(udpsize < sldns_buffer_limit(buffer))
		sldns_buffer_set_limit(buffer, udpsize);
	if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
		return 0;

	sldns_buffer_write(buffer, &id, sizeof(uint16_t));
	sldns_buffer_write_u16(buffer, flags);
	sldns_buffer_write_u16(buffer, rep->qdcount);
	/* set an, ns, ar counts to zero in case of small packets */
	sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6);

	/* insert query section */
	if(rep->qdcount) {
		if((r=insert_query(qinfo, &tree, buffer, region)) != 
			RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 4, 0);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
	}
	/* roundrobin offset. using query id for random number.  With ntohs
	 * for different roundrobins for sequential id client senders. */
	rr_offset = RRSET_ROUNDROBIN?ntohs(id):0;

	/* "prepend" any local alias records in the answer section if this
	 * response is supposed to be authoritative.  Currently it should
	 * be a single CNAME record (sanity-checked in worker_handle_request())
	 * but it can be extended if and when we support more variations of
	 * aliases. */
	if(qinfo->local_alias && (flags & BIT_AA)) {
		struct reply_info arep;
		time_t timezero = 0; /* to use the 'authoritative' TTL */
		memset(&arep, 0, sizeof(arep));
		arep.flags = rep->flags;
		arep.an_numrrsets = 1;
		arep.rrset_count = 1;
		arep.rrsets = &qinfo->local_alias->rrset;
		if((r=insert_section(&arep, 1, &ancount, buffer, 0,
			timezero, region, &tree, LDNS_SECTION_ANSWER,
			qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 6, ancount);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
	}

	/* insert answer section */
	if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 
		0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, 
		dnssec, rr_offset)) != RETVAL_OK) {
		if(r == RETVAL_TRUNC) {
			/* create truncated message */
			sldns_buffer_write_u16_at(buffer, 6, ancount);
			LDNS_TC_SET(sldns_buffer_begin(buffer));
			sldns_buffer_flip(buffer);
			return 1;
		}
		return 0;
	}
	sldns_buffer_write_u16_at(buffer, 6, ancount);

	/* if response is positive answer, auth/add sections are not required */
	if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) {
		/* insert auth section */
		if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, 
			rep->an_numrrsets, timenow, region, &tree,
			LDNS_SECTION_AUTHORITY, qinfo->qtype,
			dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 8, nscount);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		sldns_buffer_write_u16_at(buffer, 8, nscount);

		/* insert add section */
		if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, 
			rep->an_numrrsets + rep->ns_numrrsets, timenow, region, 
			&tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, 
			dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* no need to set TC bit, this is the additional */
				sldns_buffer_write_u16_at(buffer, 10, arcount);
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		sldns_buffer_write_u16_at(buffer, 10, arcount);
	}
	sldns_buffer_flip(buffer);
	return 1;
}
Exemplo n.º 24
0
/** process answer from bg worker */
static int
process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len,
	ub_callback_t* cb, void** cbarg, int* err,
	struct ub_result** res)
{
	struct ctx_query* q;
	if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) {
		log_err("error: bad data from bg worker %d",
			(int)context_serial_getcmd(msg, len));
		return 0;
	}

	lock_basic_lock(&ctx->cfglock);
	q = context_deserialize_answer(ctx, msg, len, err);
	if(!q) {
		lock_basic_unlock(&ctx->cfglock);
		/* probably simply the lookup that failed, i.e.
		 * response returned before cancel was sent out, so noerror */
		return 1;
	}
	log_assert(q->async);

	/* grab cb while locked */
	if(q->cancelled) {
		*cb = NULL;
		*cbarg = NULL;
	} else {
		*cb = q->cb;
		*cbarg = q->cb_arg;
	}
	if(*err) {
		*res = NULL;
		ub_resolve_free(q->res);
	} else {
		/* parse the message, extract rcode, fill result */
		sldns_buffer* buf = sldns_buffer_new(q->msg_len);
		struct regional* region = regional_create();
		*res = q->res;
		(*res)->rcode = LDNS_RCODE_SERVFAIL;
		if(region && buf) {
			sldns_buffer_clear(buf);
			sldns_buffer_write(buf, q->msg, q->msg_len);
			sldns_buffer_flip(buf);
			libworker_enter_result(*res, buf, region,
				q->msg_security);
		}
		(*res)->answer_packet = q->msg;
		(*res)->answer_len = (int)q->msg_len;
		q->msg = NULL;
		sldns_buffer_free(buf);
		regional_destroy(region);
	}
	q->res = NULL;
	/* delete the q from list */
	(void)rbtree_delete(&ctx->queries, q->node.key);
	ctx->num_async--;
	context_query_delete(q);
	lock_basic_unlock(&ctx->cfglock);

	if(*cb) return 2;
	ub_resolve_free(*res);
	return 1;
}
Exemplo n.º 25
0
/** perform hash of name */
static int
nsec3_calc_hash(struct regional* region, sldns_buffer* buf, 
	struct nsec3_cached_hash* c)
{
	int algo = nsec3_get_algo(c->nsec3, c->rr);
	size_t iter = nsec3_get_iter(c->nsec3, c->rr);
	uint8_t* salt;
	size_t saltlen, i;
	if(!nsec3_get_salt(c->nsec3, c->rr, &salt, &saltlen))
		return -1;
	/* prepare buffer for first iteration */
	sldns_buffer_clear(buf);
	sldns_buffer_write(buf, c->dname, c->dname_len);
	query_dname_tolower(sldns_buffer_begin(buf));
	sldns_buffer_write(buf, salt, saltlen);
	sldns_buffer_flip(buf);
	switch(algo) {
#if defined(HAVE_EVP_SHA1) || defined(HAVE_NSS)
		case NSEC3_HASH_SHA1:
#ifdef HAVE_SSL
			c->hash_len = SHA_DIGEST_LENGTH;
#else
			c->hash_len = SHA1_LENGTH;
#endif
			c->hash = (uint8_t*)regional_alloc(region, 
				c->hash_len);
			if(!c->hash)
				return 0;
#  ifdef HAVE_SSL
			(void)SHA1((unsigned char*)sldns_buffer_begin(buf),
				(unsigned long)sldns_buffer_limit(buf),
				(unsigned char*)c->hash);
#  else
			(void)HASH_HashBuf(HASH_AlgSHA1,
				(unsigned char*)c->hash,
				(unsigned char*)sldns_buffer_begin(buf),
				(unsigned long)sldns_buffer_limit(buf));
#  endif
			for(i=0; i<iter; i++) {
				sldns_buffer_clear(buf);
				sldns_buffer_write(buf, c->hash, c->hash_len);
				sldns_buffer_write(buf, salt, saltlen);
				sldns_buffer_flip(buf);
#  ifdef HAVE_SSL
				(void)SHA1(
					(unsigned char*)sldns_buffer_begin(buf),
					(unsigned long)sldns_buffer_limit(buf),
					(unsigned char*)c->hash);
#  else
				(void)HASH_HashBuf(HASH_AlgSHA1,
					(unsigned char*)c->hash,
					(unsigned char*)sldns_buffer_begin(buf),
					(unsigned long)sldns_buffer_limit(buf));
#  endif
			}
			break;
#endif /* HAVE_EVP_SHA1 or NSS */
		default:
			log_err("nsec3 hash of unknown algo %d", algo);
			return -1;
	}
	return 1;
}
Exemplo n.º 26
0
struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
	uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec),
	int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
	size_t zonelen, comm_point_callback_t* callback, void* callback_arg,
	sldns_buffer* ATTR_UNUSED(buff))
{
	struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
	struct fake_pending* pend = (struct fake_pending*)calloc(1,
		sizeof(struct fake_pending));
	char z[256];
	log_assert(pend);
	log_nametypeclass(VERB_OPS, "pending serviced query", 
		qname, qtype, qclass);
	dname_str(zone, z);
	verbose(VERB_OPS, "pending serviced query zone %s flags%s%s%s%s", 
		z, (flags&BIT_RD)?" RD":"", (flags&BIT_CD)?" CD":"",
		(flags&~(BIT_RD|BIT_CD))?" MORE":"", (dnssec)?" DO":"");

	/* create packet with EDNS */
	pend->buffer = sldns_buffer_new(512);
	log_assert(pend->buffer);
	sldns_buffer_write_u16(pend->buffer, 0); /* id */
	sldns_buffer_write_u16(pend->buffer, flags);
	sldns_buffer_write_u16(pend->buffer, 1); /* qdcount */
	sldns_buffer_write_u16(pend->buffer, 0); /* ancount */
	sldns_buffer_write_u16(pend->buffer, 0); /* nscount */
	sldns_buffer_write_u16(pend->buffer, 0); /* arcount */
	sldns_buffer_write(pend->buffer, qname, qnamelen);
	sldns_buffer_write_u16(pend->buffer, qtype);
	sldns_buffer_write_u16(pend->buffer, qclass);
	sldns_buffer_flip(pend->buffer);
	if(1) {
		/* add edns */
		struct edns_data edns;
		edns.edns_present = 1;
		edns.ext_rcode = 0;
		edns.edns_version = EDNS_ADVERTISED_VERSION;
		edns.udp_size = EDNS_ADVERTISED_SIZE;
		edns.bits = 0;
		if(dnssec)
			edns.bits = EDNS_DO;
		attach_edns_record(pend->buffer, &edns);
	}
	memcpy(&pend->addr, addr, addrlen);
	pend->addrlen = addrlen;
	pend->zone = memdup(zone, zonelen);
	pend->zonelen = zonelen;
	pend->qtype = (int)qtype;
	log_assert(pend->zone);
	pend->callback = callback;
	pend->cb_arg = callback_arg;
	pend->timeout = UDP_AUTH_QUERY_TIMEOUT;
	pend->transport = transport_udp; /* pretend UDP */
	pend->pkt = NULL;
	pend->runtime = runtime;
	pend->serviced = 1;
	pend->pkt_len = sldns_buffer_limit(pend->buffer);
	pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len);
	if(!pend->pkt) fatal_exit("out of memory");
	/*log_pkt("pending serviced query: ", pend->pkt, pend->pkt_len);*/

	/* see if it matches the current moment */
	if(runtime->now && runtime->now->evt_type == repevt_back_query &&
		(runtime->now->addrlen == 0 || sockaddr_cmp(
			&runtime->now->addr, runtime->now->addrlen,
			&pend->addr, pend->addrlen) == 0) &&
		find_match(runtime->now->match, pend->pkt, pend->pkt_len,
			pend->transport)) {
		log_info("testbound: matched pending to event. "
			"advance time between events.");
		log_info("testbound: do STEP %d %s", runtime->now->time_step,
			repevt_string(runtime->now->evt_type));
		advance_moment(runtime);
		/* still create the pending, because we need it to callback */
	} 
	log_info("testbound: created fake pending");
	/* add to list */
	pend->next = runtime->pending_list;
	runtime->pending_list = pend;
	return (struct serviced_query*)pend;
}
Exemplo n.º 27
0
/** test pkt_dname_len */
static void
dname_test_pkt_dname_len(sldns_buffer* buff)
{
	unit_show_func("util/data/dname.c", "pkt_dname_len");
	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, "\000", 1);
	sldns_buffer_flip(buff);
	unit_assert( pkt_dname_len(buff) == 1 );
	unit_assert( sldns_buffer_position(buff) == 1);

	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, "\003org\000", 5);
	sldns_buffer_flip(buff);
	unit_assert( pkt_dname_len(buff) == 5 );
	unit_assert( sldns_buffer_position(buff) == 5);

	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, "\002os\007example\003org\000", 16);
	sldns_buffer_flip(buff);
	unit_assert( pkt_dname_len(buff) == 16 );
	unit_assert( sldns_buffer_position(buff) == 16);

	/* invalid compression pointer: to self */
	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, "\300\000os\007example\003org\000", 17);
	sldns_buffer_flip(buff);
	unit_assert( pkt_dname_len(buff) == 0 );

	/* valid compression pointer */
	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, "\003com\000\040\300\000", 8);
	sldns_buffer_flip(buff);
	sldns_buffer_set_position(buff, 6);
	unit_assert( pkt_dname_len(buff) == 5 );
	unit_assert( sldns_buffer_position(buff) == 8);

	/* unknown label type */
	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, "\002os\107example\003org\000", 16);
	sldns_buffer_flip(buff);
	unit_assert( pkt_dname_len(buff) == 0 );

	/* label too long */
	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, "\002os\047example\003org\000", 16);
	sldns_buffer_flip(buff);
	unit_assert( pkt_dname_len(buff) == 0 );

	/* label exceeds packet */
	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, "\002os\007example\007org\004", 16);
	sldns_buffer_flip(buff);
	unit_assert( pkt_dname_len(buff) == 0 );

	/* name very long */
	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, 
		"\020a1cdef5555544444"
		"\020a2cdef5555544444"
		"\020a3cdef5555544444"
		"\020a4cdef5555544444"
		"\020a5cdef5555544444"
		"\020a6cdef5555544444"
		"\020a7cdef5555544444"
		"\020a8cdef5555544444"
		"\020a9cdef5555544444"
		"\020aAcdef5555544444"
		"\020aBcdef5555544444"
		"\020aCcdef5555544444"
		"\020aDcdef5555544444"
		"\020aEcdef5555544444"	/* 238 up to here */
		"\007aabbccd"		/* 246 up to here */
		"\007example\000"	/* 255 to here */
		, 255);
	sldns_buffer_flip(buff);
	unit_assert( pkt_dname_len(buff) == 255 );
	unit_assert( sldns_buffer_position(buff) == 255);

	/* name too long */
	sldns_buffer_clear(buff);
	sldns_buffer_write(buff, 
		"\020a1cdef5555544444"
		"\020a2cdef5555544444"
		"\020a3cdef5555544444"
		"\020a4cdef5555544444"
		"\020a5cdef5555544444"
		"\020a6cdef5555544444"
		"\020a7cdef5555544444"
		"\020a8cdef5555544444"
		"\020a9cdef5555544444"
		"\020aAcdef5555544444"
		"\020aBcdef5555544444"
		"\020aCcdef5555544444"
		"\020aXcdef5555544444"
		"\020aXcdef5555544444"
		"\020aXcdef5555544444"
		"\020aDcdef5555544444"
		"\020aEcdef5555544444"	/* 238 up to here */
		"\007aabbccd"		/* 246 up to here */
		"\007example\000"	/* 255 to here */
		, 255);
	sldns_buffer_flip(buff);
	unit_assert( pkt_dname_len(buff) == 0 );
}
Exemplo n.º 28
0
int 
reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 
	uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow, 
	struct regional* region, uint16_t udpsize, int dnssec)
{
	uint16_t ancount=0, nscount=0, arcount=0;
	struct compress_tree_node* tree = 0;
	int r;
	size_t rr_offset; 

	sldns_buffer_clear(buffer);
	if(udpsize < sldns_buffer_limit(buffer))
		sldns_buffer_set_limit(buffer, udpsize);
	if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
		return 0;

	sldns_buffer_write(buffer, &id, sizeof(uint16_t));
	sldns_buffer_write_u16(buffer, flags);
	sldns_buffer_write_u16(buffer, rep->qdcount);
	/* set an, ns, ar counts to zero in case of small packets */
	sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6);

	/* insert query section */
	if(rep->qdcount) {
		if((r=insert_query(qinfo, &tree, buffer, region)) != 
			RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 4, 0);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
	}
	/* roundrobin offset. using query id for random number.  With ntohs
	 * for different roundrobins for sequential id client senders. */
	rr_offset = RRSET_ROUNDROBIN?ntohs(id):0;

	/* insert answer section */
	if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 
		0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, 
		dnssec, rr_offset)) != RETVAL_OK) {
		if(r == RETVAL_TRUNC) {
			/* create truncated message */
			sldns_buffer_write_u16_at(buffer, 6, ancount);
			LDNS_TC_SET(sldns_buffer_begin(buffer));
			sldns_buffer_flip(buffer);
			return 1;
		}
		return 0;
	}
	sldns_buffer_write_u16_at(buffer, 6, ancount);

	/* if response is positive answer, auth/add sections are not required */
	if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) {
		/* insert auth section */
		if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, 
			rep->an_numrrsets, timenow, region, &tree,
			LDNS_SECTION_AUTHORITY, qinfo->qtype,
			dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* create truncated message */
				sldns_buffer_write_u16_at(buffer, 8, nscount);
				LDNS_TC_SET(sldns_buffer_begin(buffer));
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		sldns_buffer_write_u16_at(buffer, 8, nscount);

		/* insert add section */
		if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, 
			rep->an_numrrsets + rep->ns_numrrsets, timenow, region, 
			&tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, 
			dnssec, rr_offset)) != RETVAL_OK) {
			if(r == RETVAL_TRUNC) {
				/* no need to set TC bit, this is the additional */
				sldns_buffer_write_u16_at(buffer, 10, arcount);
				sldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		sldns_buffer_write_u16_at(buffer, 10, arcount);
	}
	sldns_buffer_flip(buffer);
	return 1;
}