Пример #1
0
ldns_status
ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
{
	uint16_t i;
	uint16_t rdl_pos = 0;
	
	if (ldns_rr_owner(rr)) {
		(void) ldns_dname2buffer_wire(buffer, ldns_rr_owner(rr));
	}
	
	if (ldns_buffer_reserve(buffer, 4)) {
		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
	}

	if (section != LDNS_SECTION_QUESTION) {
		if (ldns_buffer_reserve(buffer, 6)) {
			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
			/* remember pos for later */
			rdl_pos = ldns_buffer_position(buffer);
			ldns_buffer_write_u16(buffer, 0);
		}	

		for (i = 0; i < ldns_rr_rd_count(rr); i++) {
			(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
		}
		
		if (rdl_pos != 0) {
			ldns_buffer_write_u16_at(buffer, rdl_pos,
			                         ldns_buffer_position(buffer)
		        	                   - rdl_pos - 2);
		}
	}
	return ldns_buffer_status(buffer);
}
Пример #2
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.
 */
static void
chaos_replystr(ldns_buffer* pkt, const char* str, struct edns_data* edns)
{
	size_t len = strlen(str);
	unsigned int rd = LDNS_RD_WIRE(ldns_buffer_begin(pkt));
	unsigned int cd = LDNS_CD_WIRE(ldns_buffer_begin(pkt));
	if(len>255) len=255; /* cap size of TXT record */
	ldns_buffer_clear(pkt);
	ldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */
	ldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA));
	if(rd) LDNS_RD_SET(ldns_buffer_begin(pkt));
	if(cd) LDNS_CD_SET(ldns_buffer_begin(pkt));
	ldns_buffer_write_u16(pkt, 1); /* qdcount */
	ldns_buffer_write_u16(pkt, 1); /* ancount */
	ldns_buffer_write_u16(pkt, 0); /* nscount */
	ldns_buffer_write_u16(pkt, 0); /* arcount */
	(void)query_dname_len(pkt); /* skip qname */
	ldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */
	ldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */
	ldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */
	ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT);
	ldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH);
	ldns_buffer_write_u32(pkt, 0); /* TTL */
	ldns_buffer_write_u16(pkt, sizeof(uint8_t) + len);
	ldns_buffer_write_u8(pkt, len);
	ldns_buffer_write(pkt, str, len);
	ldns_buffer_flip(pkt);
	edns->edns_version = EDNS_ADVERTISED_VERSION;
	edns->udp_size = EDNS_ADVERTISED_SIZE;
	edns->bits &= EDNS_DO;
	attach_edns_record(pkt, edns);
}
Пример #3
0
void 
qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo)
{
	uint16_t flags = 0; /* QUERY, NOERROR */
	ldns_buffer_clear(pkt);
	log_assert(ldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
	ldns_buffer_skip(pkt, 2); /* id done later */
	ldns_buffer_write_u16(pkt, flags);
	ldns_buffer_write_u16(pkt, 1); /* query count */
	ldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
	ldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len);
	ldns_buffer_write_u16(pkt, qinfo->qtype);
	ldns_buffer_write_u16(pkt, qinfo->qclass);
	ldns_buffer_flip(pkt);
}
Пример #4
0
/** compress a domain name */
static int
write_compressed_dname(ldns_buffer* pkt, uint8_t* dname, int labs,
	struct compress_tree_node* p)
{
	/* compress it */
	int labcopy = labs - p->labs;
	uint8_t lablen;
	uint16_t ptr;

	if(labs == 1) {
		/* write root label */
		if(ldns_buffer_remaining(pkt) < 1)
			return 0;
		ldns_buffer_write_u8(pkt, 0);
		return 1;
	}

	/* copy the first couple of labels */
	while(labcopy--) {
		lablen = *dname++;
		if(ldns_buffer_remaining(pkt) < (size_t)lablen+1)
			return 0;
		ldns_buffer_write_u8(pkt, lablen);
		ldns_buffer_write(pkt, dname, lablen);
		dname += lablen;
	}
	/* insert compression ptr */
	if(ldns_buffer_remaining(pkt) < 2)
		return 0;
	ptr = PTR_CREATE(p->offset);
	ldns_buffer_write_u16(pkt, ptr);
	return 1;
}
Пример #5
0
/** store query section in wireformat buffer, return RETVAL */
static int
insert_query(struct query_info* qinfo, struct compress_tree_node** tree, 
	ldns_buffer* buffer, struct regional* region)
{
	if(ldns_buffer_remaining(buffer) < 
		qinfo->qname_len+sizeof(uint16_t)*2)
		return RETVAL_TRUNC; /* buffer too small */
	/* the query is the first name inserted into the tree */
	if(!compress_tree_store(qinfo->qname, 
		dname_count_labels(qinfo->qname), 
		ldns_buffer_position(buffer), region, NULL, tree))
		return RETVAL_OUTMEM;
	if(ldns_buffer_current(buffer) == qinfo->qname)
		ldns_buffer_skip(buffer, (ssize_t)qinfo->qname_len);
	else	ldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len);
	ldns_buffer_write_u16(buffer, qinfo->qtype);
	ldns_buffer_write_u16(buffer, qinfo->qclass);
	return RETVAL_OK;
}
Пример #6
0
void
attach_edns_record(ldns_buffer* pkt, struct edns_data* edns)
{
	size_t len;
	if(!edns || !edns->edns_present)
		return;
	/* inc additional count */
	ldns_buffer_write_u16_at(pkt, 10,
		ldns_buffer_read_u16_at(pkt, 10) + 1);
	len = ldns_buffer_limit(pkt);
	ldns_buffer_clear(pkt);
	ldns_buffer_set_position(pkt, len);
	/* write EDNS record */
	ldns_buffer_write_u8(pkt, 0); /* '.' label */
	ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
	ldns_buffer_write_u16(pkt, edns->udp_size); /* class */
	ldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
	ldns_buffer_write_u8(pkt, edns->edns_version);
	ldns_buffer_write_u16(pkt, edns->bits);
	ldns_buffer_write_u16(pkt, 0); /* rdatalen */
	ldns_buffer_flip(pkt);
}
Пример #7
0
void 
error_encode(ldns_buffer* buf, int r, struct query_info* qinfo,
	uint16_t qid, uint16_t qflags, struct edns_data* edns)
{
	uint16_t flags;

	ldns_buffer_clear(buf);
	ldns_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 */
	ldns_buffer_write_u16(buf, flags);
	if(qinfo) flags = 1;
	else	flags = 0;
	ldns_buffer_write_u16(buf, flags);
	flags = 0;
	ldns_buffer_write(buf, &flags, sizeof(uint16_t));
	ldns_buffer_write(buf, &flags, sizeof(uint16_t));
	ldns_buffer_write(buf, &flags, sizeof(uint16_t));
	if(qinfo) {
		if(ldns_buffer_current(buf) == qinfo->qname)
			ldns_buffer_skip(buf, (ssize_t)qinfo->qname_len);
		else	ldns_buffer_write(buf, qinfo->qname, qinfo->qname_len);
		ldns_buffer_write_u16(buf, qinfo->qtype);
		ldns_buffer_write_u16(buf, qinfo->qclass);
	}
	ldns_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(ldns_buffer_limit(buf) + calc_edns_field_size(&es) >
			edns->udp_size)
			return;
		attach_edns_record(buf, &es);
	}
}
Пример #8
0
/*
 * Copies the packet header data to the buffer in wire format
 */
static ldns_status
ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
{
	uint8_t flags;
	uint16_t arcount;
	
	if (ldns_buffer_reserve(buffer, 12)) {
		ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
		
		flags = ldns_pkt_qr(packet) << 7
		        | ldns_pkt_get_opcode(packet) << 3
		        | ldns_pkt_aa(packet) << 2
		        | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet);
		ldns_buffer_write_u8(buffer, flags);
		
		flags = ldns_pkt_ra(packet) << 7
		        /*| ldns_pkt_z(packet) << 6*/
		        | ldns_pkt_ad(packet) << 5
		        | ldns_pkt_cd(packet) << 4 | ldns_pkt_get_rcode(packet);
		ldns_buffer_write_u8(buffer, flags);
		
		ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet));
		ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet));
		ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet));
		/* add EDNS0 and TSIG to additional if they are there */
		arcount = ldns_pkt_arcount(packet);
		if (ldns_pkt_tsig(packet)) {
			arcount++;
		}
		if (ldns_pkt_edns(packet)) {
			arcount++;
		}
		ldns_buffer_write_u16(buffer, arcount);
	}
	
	return ldns_buffer_status(buffer);
}
Пример #9
0
static ldns_status
ldns_tsig_mac_new(ldns_rdf **tsig_mac, uint8_t *pkt_wire, size_t pkt_wire_size,
		const char *key_data, ldns_rdf *key_name_rdf, ldns_rdf *fudge_rdf,
		ldns_rdf *algorithm_rdf, ldns_rdf *time_signed_rdf, ldns_rdf *error_rdf,
		ldns_rdf *other_data_rdf, ldns_rdf *orig_mac_rdf, int tsig_timers_only)
{
	ldns_status status;
	char *wireformat;
	int wiresize;
	unsigned char *mac_bytes = NULL;
	unsigned char *key_bytes = NULL;
	int key_size;
	const EVP_MD *digester;
	char *algorithm_name = NULL;
	unsigned int md_len = EVP_MAX_MD_SIZE;
	ldns_rdf *result = NULL;
	ldns_buffer *data_buffer = NULL;
	ldns_rdf *canonical_key_name_rdf = NULL;
	ldns_rdf *canonical_algorithm_rdf = NULL;
	
	if (key_name_rdf == NULL || algorithm_rdf == NULL) {
		return LDNS_STATUS_NULL;
	}
	canonical_key_name_rdf  = ldns_rdf_clone(key_name_rdf);
	if (canonical_key_name_rdf == NULL) {
		return LDNS_STATUS_MEM_ERR;
	}
	canonical_algorithm_rdf = ldns_rdf_clone(algorithm_rdf);
	if (canonical_algorithm_rdf == NULL) {
		ldns_rdf_deep_free(canonical_key_name_rdf);
		return LDNS_STATUS_MEM_ERR;
	}
	/*
	 * prepare the digestable information
	 */
	data_buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
	if (!data_buffer) {
		status = LDNS_STATUS_MEM_ERR;
		goto clean;
	}
	/* if orig_mac is not NULL, add it too */
	if (orig_mac_rdf) {
		(void) ldns_rdf2buffer_wire(data_buffer, orig_mac_rdf);
 	}
	ldns_buffer_write(data_buffer, pkt_wire, pkt_wire_size);
	if (!tsig_timers_only) {
		ldns_dname2canonical(canonical_key_name_rdf);
		(void)ldns_rdf2buffer_wire(data_buffer, 
				canonical_key_name_rdf);
		ldns_buffer_write_u16(data_buffer, LDNS_RR_CLASS_ANY);
		ldns_buffer_write_u32(data_buffer, 0);
		ldns_dname2canonical(canonical_algorithm_rdf);
		(void)ldns_rdf2buffer_wire(data_buffer, 
				canonical_algorithm_rdf);
	}
	(void)ldns_rdf2buffer_wire(data_buffer, time_signed_rdf);
	(void)ldns_rdf2buffer_wire(data_buffer, fudge_rdf);
	if (!tsig_timers_only) {
		(void)ldns_rdf2buffer_wire(data_buffer, error_rdf);
		(void)ldns_rdf2buffer_wire(data_buffer, other_data_rdf);
	}

	wireformat = (char *) data_buffer->_data;
	wiresize = (int) ldns_buffer_position(data_buffer);

	algorithm_name = ldns_rdf2str(algorithm_rdf);
	if(!algorithm_name) {
		status = LDNS_STATUS_MEM_ERR;
		goto clean;
	}

	/* prepare the key */
	key_bytes = LDNS_XMALLOC(unsigned char,
			ldns_b64_pton_calculate_size(strlen(key_data)));
	if(!key_bytes) {
		status = LDNS_STATUS_MEM_ERR;
		goto clean;
	}
	key_size = ldns_b64_pton(key_data, key_bytes,
	ldns_b64_pton_calculate_size(strlen(key_data)));
	if (key_size < 0) {
		status = LDNS_STATUS_INVALID_B64;
		goto clean;
	}
	/* hmac it */
	/* 2 spare bytes for the length */
	mac_bytes = LDNS_XMALLOC(unsigned char, md_len+2);
	if(!mac_bytes) {
		status = LDNS_STATUS_MEM_ERR;
		goto clean;
	}
	memset(mac_bytes, 0, md_len+2);

	digester = ldns_digest_function(algorithm_name);

	if (digester) {
		(void) HMAC(digester, key_bytes, key_size, (void *)wireformat,
		            (size_t) wiresize, mac_bytes + 2, &md_len);

		ldns_write_uint16(mac_bytes, md_len);
		result = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT16_DATA, md_len + 2,
				mac_bytes);
	} else {
		status = LDNS_STATUS_CRYPTO_UNKNOWN_ALGO;
		goto clean;
	}
	*tsig_mac = result;
	status = LDNS_STATUS_OK;
  clean:
	LDNS_FREE(mac_bytes);
	LDNS_FREE(key_bytes);
	LDNS_FREE(algorithm_name);
	ldns_buffer_free(data_buffer);
	ldns_rdf_deep_free(canonical_algorithm_rdf);
	ldns_rdf_deep_free(canonical_key_name_rdf);
	return status;
}
Пример #10
0
ldns_status
ldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
						const ldns_rr *rr,
						int section)
{
	uint16_t i;
	uint16_t rdl_pos = 0;
	bool pre_rfc3597 = false;
	switch (ldns_rr_get_type(rr)) {
	case LDNS_RR_TYPE_NS:
	case LDNS_RR_TYPE_MD:
	case LDNS_RR_TYPE_MF:
	case LDNS_RR_TYPE_CNAME:
	case LDNS_RR_TYPE_SOA:
	case LDNS_RR_TYPE_MB:
	case LDNS_RR_TYPE_MG:
	case LDNS_RR_TYPE_MR:
	case LDNS_RR_TYPE_PTR:
	case LDNS_RR_TYPE_HINFO:
	case LDNS_RR_TYPE_MINFO:
	case LDNS_RR_TYPE_MX:
	case LDNS_RR_TYPE_RP:
	case LDNS_RR_TYPE_AFSDB:
	case LDNS_RR_TYPE_RT:
	case LDNS_RR_TYPE_SIG:
	case LDNS_RR_TYPE_PX:
	case LDNS_RR_TYPE_NXT:
	case LDNS_RR_TYPE_NAPTR:
	case LDNS_RR_TYPE_KX:
	case LDNS_RR_TYPE_SRV:
	case LDNS_RR_TYPE_DNAME:
	case LDNS_RR_TYPE_A6:
		pre_rfc3597 = true;
		break;
	default:
		break;
	}
	
	if (ldns_rr_owner(rr)) {
		(void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr));
	}
	
	if (ldns_buffer_reserve(buffer, 4)) {
		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
	}

	if (section != LDNS_SECTION_QUESTION) {
		if (ldns_buffer_reserve(buffer, 6)) {
			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
			/* remember pos for later */
			rdl_pos = ldns_buffer_position(buffer);
			ldns_buffer_write_u16(buffer, 0);
		}	

		for (i = 0; i < ldns_rr_rd_count(rr); i++) {
			if (pre_rfc3597) {
				(void) ldns_rdf2buffer_wire_canonical(buffer,
											   ldns_rr_rdf(rr, i));
			} else {
				(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
			}
		}
		
		if (rdl_pos != 0) {
			ldns_buffer_write_u16_at(buffer, rdl_pos,
			                         ldns_buffer_position(buffer)
		        	                   - rdl_pos - 2);
		}
	}
	return ldns_buffer_status(buffer);
}
Пример #11
0
int 
reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 
	uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_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; 

	ldns_buffer_clear(buffer);
	if(udpsize < ldns_buffer_limit(buffer))
		ldns_buffer_set_limit(buffer, udpsize);
	if(ldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
		return 0;

	ldns_buffer_write(buffer, &id, sizeof(uint16_t));
	ldns_buffer_write_u16(buffer, flags);
	ldns_buffer_write_u16(buffer, rep->qdcount);
	/* set an, ns, ar counts to zero in case of small packets */
	ldns_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 */
				ldns_buffer_write_u16_at(buffer, 4, 0);
				LDNS_TC_SET(ldns_buffer_begin(buffer));
				ldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
	}
	/* roundrobin offset. using query id for random number */
	rr_offset = RRSET_ROUNDROBIN?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 */
			ldns_buffer_write_u16_at(buffer, 6, ancount);
			LDNS_TC_SET(ldns_buffer_begin(buffer));
			ldns_buffer_flip(buffer);
			return 1;
		}
		return 0;
	}
	ldns_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 */
				ldns_buffer_write_u16_at(buffer, 8, nscount);
				LDNS_TC_SET(ldns_buffer_begin(buffer));
				ldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		ldns_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 */
				ldns_buffer_write_u16_at(buffer, 10, arcount);
				ldns_buffer_flip(buffer);
				return 1;
			}
			return 0;
		}
		ldns_buffer_write_u16_at(buffer, 10, arcount);
	} else {
		ldns_buffer_write_u16_at(buffer, 8, nscount);
		ldns_buffer_write_u16_at(buffer, 10, arcount);
	}
	ldns_buffer_flip(buffer);
	return 1;
}
Пример #12
0
/** store rrset in buffer in wireformat, return RETVAL_* */
static int
packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, 
	uint16_t* num_rrs, uint32_t timenow, struct regional* region,
	int do_data, int do_sig, struct compress_tree_node** tree,
	ldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
{
	size_t i, j, owner_pos;
	int r, owner_labs;
	uint16_t owner_ptr = 0;
	struct packed_rrset_data* data = (struct packed_rrset_data*)
		key->entry.data;
	
	/* does this RR type belong in the answer? */
	if(!rrset_belongs_in_reply(s, ntohs(key->rk.type), qtype, dnssec))
		return RETVAL_OK;

	owner_labs = dname_count_labels(key->rk.dname);
	owner_pos = ldns_buffer_position(pkt);

	if(do_data) {
		const ldns_rr_descriptor* c = type_rdata_compressable(key);
		for(i=0; i<data->count; i++) {
			/* rrset roundrobin */
			j = (i + rr_offset) % data->count;
			if((r=compress_owner(key, pkt, region, tree, 
				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);
			if(data->rr_ttl[j] < timenow)
				ldns_buffer_write_u32(pkt, 0);
			else 	ldns_buffer_write_u32(pkt, 
					data->rr_ttl[j]-timenow);
			if(c) {
				if((r=compress_rdata(pkt, data->rr_data[j],
					data->rr_len[j], region, tree, c))
					!= RETVAL_OK)
					return r;
			} else {
				if(ldns_buffer_remaining(pkt) < data->rr_len[j])
					return RETVAL_TRUNC;
				ldns_buffer_write(pkt, data->rr_data[j],
					data->rr_len[j]);
			}
		}
	}
	/* insert rrsigs */
	if(do_sig && dnssec) {
		size_t total = data->count+data->rrsig_count;
		for(i=data->count; i<total; i++) {
			if(owner_ptr && owner_labs != 1) {
				if(ldns_buffer_remaining(pkt) <
					2+4+4+data->rr_len[i]) 
					return RETVAL_TRUNC;
				ldns_buffer_write(pkt, &owner_ptr, 2);
			} else {
				if((r=compress_any_dname(key->rk.dname, 
					pkt, owner_labs, region, tree))
					!= RETVAL_OK)
					return r;
				if(ldns_buffer_remaining(pkt) < 
					4+4+data->rr_len[i])
					return RETVAL_TRUNC;
			}
			ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
			ldns_buffer_write(pkt, &key->rk.rrset_class, 2);
			if(data->rr_ttl[i] < timenow)
				ldns_buffer_write_u32(pkt, 0);
			else 	ldns_buffer_write_u32(pkt, 
					data->rr_ttl[i]-timenow);
			/* rrsig rdata cannot be compressed, perform 100+ byte
			 * memcopy. */
			ldns_buffer_write(pkt, data->rr_data[i],
				data->rr_len[i]);
		}
	}
	/* change rrnum only after we are sure it fits */
	if(do_data)
		*num_rrs += data->count;
	if(do_sig && dnssec)
		*num_rrs += data->rrsig_count;

	return RETVAL_OK;
}
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),
	struct sockaddr_storage* addr, socklen_t addrlen, 
	comm_point_callback_t* callback, void* callback_arg, 
	ldns_buffer* ATTR_UNUSED(buff), int (*arg_compare)(void*,void*))
{
	struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
	struct fake_pending* pend = (struct fake_pending*)calloc(1,
		sizeof(struct fake_pending));
	ldns_status status;
	(void)arg_compare;
	log_assert(pend);
	log_nametypeclass(VERB_OPS, "pending serviced query", 
		qname, qtype, qclass);
	verbose(VERB_OPS, "pending serviced query flags%s%s%s%s", 
		(flags&BIT_RD)?" RD":"", (flags&BIT_CD)?" CD":"",
		(flags&~(BIT_RD|BIT_CD))?" MORE":"", (dnssec)?" DO":"");

	/* create packet with EDNS */
	pend->buffer = ldns_buffer_new(512);
	log_assert(pend->buffer);
	ldns_buffer_write_u16(pend->buffer, 0); /* id */
	ldns_buffer_write_u16(pend->buffer, flags);
	ldns_buffer_write_u16(pend->buffer, 1); /* qdcount */
	ldns_buffer_write_u16(pend->buffer, 0); /* ancount */
	ldns_buffer_write_u16(pend->buffer, 0); /* nscount */
	ldns_buffer_write_u16(pend->buffer, 0); /* arcount */
	ldns_buffer_write(pend->buffer, qname, qnamelen);
	ldns_buffer_write_u16(pend->buffer, qtype);
	ldns_buffer_write_u16(pend->buffer, qclass);
	ldns_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->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;
	status = ldns_buffer2pkt_wire(&pend->pkt, pend->buffer);
	if(status != LDNS_STATUS_OK) {
		log_err("ldns error parsing serviced output packet: %s",
			ldns_get_errorstr_by_id(status));
		fatal_exit("internal error");
	}
	/*log_pkt("pending serviced query: ", pend->pkt);*/

	/* 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->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;
}