Home | History | Annotate | Line # | Download | only in data
      1 /*
      2  * util/data/msgencode.c - Encode DNS messages, queries and replies.
      3  *
      4  * Copyright (c) 2007, NLnet Labs. All rights reserved.
      5  *
      6  * This software is open source.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * Redistributions of source code must retain the above copyright notice,
     13  * this list of conditions and the following disclaimer.
     14  *
     15  * Redistributions in binary form must reproduce the above copyright notice,
     16  * this list of conditions and the following disclaimer in the documentation
     17  * and/or other materials provided with the distribution.
     18  *
     19  * Neither the name of the NLNET LABS nor the names of its contributors may
     20  * be used to endorse or promote products derived from this software without
     21  * specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
     29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 
     36 /**
     37  * \file
     38  *
     39  * This file contains a routines to encode DNS messages.
     40  */
     41 
     42 #include "config.h"
     43 #include "util/data/msgencode.h"
     44 #include "util/data/msgreply.h"
     45 #include "util/data/msgparse.h"
     46 #include "util/data/dname.h"
     47 #include "util/log.h"
     48 #include "util/regional.h"
     49 #include "util/net_help.h"
     50 #include "sldns/sbuffer.h"
     51 #include "services/localzone.h"
     52 
     53 #ifdef HAVE_TIME_H
     54 #include <time.h>
     55 #endif
     56 #include <sys/time.h>
     57 
     58 /** return code that means the function ran out of memory. negative so it does
     59  * not conflict with DNS rcodes. */
     60 #define RETVAL_OUTMEM	-2
     61 /** return code that means the data did not fit (completely) in the packet */
     62 #define RETVAL_TRUNC	-4
     63 /** return code that means all is peachy keen. Equal to DNS rcode NOERROR */
     64 #define RETVAL_OK	0
     65 /** Max compressions we are willing to perform; more than that will result
     66  *  in semi-compressed messages, or truncated even on TCP for huge messages, to
     67  *  avoid locking the CPU for long */
     68 #define MAX_COMPRESSION_PER_MESSAGE 120
     69 
     70 /**
     71  * Data structure to help domain name compression in outgoing messages.
     72  * A tree of dnames and their offsets in the packet is kept.
     73  * It is kept sorted, not canonical, but by label at least, so that after
     74  * a lookup of a name you know its closest match, and the parent from that
     75  * closest match. These are possible compression targets.
     76  *
     77  * It is a binary tree, not a rbtree or balanced tree, as the effort
     78  * of keeping it balanced probably outweighs usefulness (given typical
     79  * DNS packet size).
     80  */
     81 struct compress_tree_node {
     82 	/** left node in tree, all smaller to this */
     83 	struct compress_tree_node* left;
     84 	/** right node in tree, all larger than this */
     85 	struct compress_tree_node* right;
     86 
     87 	/** the parent node - not for tree, but zone parent. One less label */
     88 	struct compress_tree_node* parent;
     89 	/** the domain name for this node. Pointer to uncompressed memory. */
     90 	uint8_t* dname;
     91 	/** number of labels in domain name, kept to help compare func. */
     92 	int labs;
     93 	/** offset in packet that points to this dname */
     94 	size_t offset;
     95 };
     96 
     97 /**
     98  * Find domain name in tree, returns exact and closest match.
     99  * @param tree: root of tree.
    100  * @param dname: pointer to uncompressed dname.
    101  * @param labs: number of labels in domain name.
    102  * @param match: closest or exact match.
    103  *	guaranteed to be smaller or equal to the sought dname.
    104  *	can be null if the tree is empty.
    105  * @param matchlabels: number of labels that match with closest match.
    106  *	can be zero is there is no match.
    107  * @param insertpt: insert location for dname, if not found.
    108  * @return: 0 if no exact match.
    109  */
    110 static int
    111 compress_tree_search(struct compress_tree_node** tree, uint8_t* dname,
    112 	int labs, struct compress_tree_node** match, int* matchlabels,
    113 	struct compress_tree_node*** insertpt)
    114 {
    115 	int c, n, closen=0;
    116 	struct compress_tree_node* p = *tree;
    117 	struct compress_tree_node* close = 0;
    118 	struct compress_tree_node** prev = tree;
    119 	while(p) {
    120 		if((c = dname_lab_cmp(dname, labs, p->dname, p->labs, &n))
    121 			== 0) {
    122 			*matchlabels = n;
    123 			*match = p;
    124 			return 1;
    125 		}
    126 		if(c<0) {
    127 			prev = &p->left;
    128 			p = p->left;
    129 		} else	{
    130 			closen = n;
    131 			close = p; /* p->dname is smaller than dname */
    132 			prev = &p->right;
    133 			p = p->right;
    134 		}
    135 	}
    136 	*insertpt = prev;
    137 	*matchlabels = closen;
    138 	*match = close;
    139 	return 0;
    140 }
    141 
    142 /**
    143  * Lookup a domain name in compression tree.
    144  * @param tree: root of tree (not the node with '.').
    145  * @param dname: pointer to uncompressed dname.
    146  * @param labs: number of labels in domain name.
    147  * @param insertpt: insert location for dname, if not found.
    148  * @return: 0 if not found or compress treenode with best compression.
    149  */
    150 static struct compress_tree_node*
    151 compress_tree_lookup(struct compress_tree_node** tree, uint8_t* dname,
    152 	int labs, struct compress_tree_node*** insertpt)
    153 {
    154 	struct compress_tree_node* p;
    155 	int m;
    156 	if(labs <= 1)
    157 		return 0; /* do not compress root node */
    158 	if(compress_tree_search(tree, dname, labs, &p, &m, insertpt)) {
    159 		/* exact match */
    160 		return p;
    161 	}
    162 	/* return some ancestor of p that compresses well. */
    163 	if(m>1) {
    164 		/* www.example.com. (labs=4) matched foo.example.com.(labs=4)
    165 		 * then matchcount = 3. need to go up. */
    166 		while(p && p->labs > m)
    167 			p = p->parent;
    168 		return p;
    169 	}
    170 	return 0;
    171 }
    172 
    173 /**
    174  * Create node for domain name compression tree.
    175  * @param dname: pointer to uncompressed dname (stored in tree).
    176  * @param labs: number of labels in dname.
    177  * @param offset: offset into packet for dname.
    178  * @param region: how to allocate memory for new node.
    179  * @return new node or 0 on malloc failure.
    180  */
    181 static struct compress_tree_node*
    182 compress_tree_newnode(uint8_t* dname, int labs, size_t offset,
    183 	struct regional* region)
    184 {
    185 	struct compress_tree_node* n = (struct compress_tree_node*)
    186 		regional_alloc(region, sizeof(struct compress_tree_node));
    187 	if(!n) return 0;
    188 	n->left = 0;
    189 	n->right = 0;
    190 	n->parent = 0;
    191 	n->dname = dname;
    192 	n->labs = labs;
    193 	n->offset = offset;
    194 	return n;
    195 }
    196 
    197 /**
    198  * Store domain name and ancestors into compression tree.
    199  * @param dname: pointer to uncompressed dname (stored in tree).
    200  * @param labs: number of labels in dname.
    201  * @param offset: offset into packet for dname.
    202  * @param region: how to allocate memory for new node.
    203  * @param closest: match from previous lookup, used to compress dname.
    204  *	may be NULL if no previous match.
    205  *	if the tree has an ancestor of dname already, this must be it.
    206  * @param insertpt: where to insert the dname in tree.
    207  * @return: 0 on memory error.
    208  */
    209 static int
    210 compress_tree_store(uint8_t* dname, int labs, size_t offset,
    211 	struct regional* region, struct compress_tree_node* closest,
    212 	struct compress_tree_node** insertpt)
    213 {
    214 	uint8_t lablen;
    215 	struct compress_tree_node* newnode;
    216 	struct compress_tree_node* prevnode = NULL;
    217 	int uplabs = labs-1; /* does not store root in tree */
    218 	if(closest) uplabs = labs - closest->labs;
    219 	log_assert(uplabs >= 0);
    220 	/* algorithms builds up a vine of dname-labels to hang into tree */
    221 	while(uplabs--) {
    222 		if(offset > PTR_MAX_OFFSET) {
    223 			/* insertion failed, drop vine */
    224 			return 1; /* compression pointer no longer useful */
    225 		}
    226 		if(!(newnode = compress_tree_newnode(dname, labs, offset,
    227 			region))) {
    228 			/* insertion failed, drop vine */
    229 			return 0;
    230 		}
    231 
    232 		if(prevnode) {
    233 			/* chain nodes together, last one has one label more,
    234 			 * so is larger than newnode, thus goes right. */
    235 			newnode->right = prevnode;
    236 			prevnode->parent = newnode;
    237 		}
    238 
    239 		/* next label */
    240 		lablen = *dname++;
    241 		dname += lablen;
    242 		offset += lablen+1;
    243 		prevnode = newnode;
    244 		labs--;
    245 	}
    246 	/* if we have a vine, hang the vine into the tree */
    247 	if(prevnode) {
    248 		*insertpt = prevnode;
    249 		prevnode->parent = closest;
    250 	}
    251 	return 1;
    252 }
    253 
    254 /** compress a domain name */
    255 static int
    256 write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs,
    257 	struct compress_tree_node* p)
    258 {
    259 	/* compress it */
    260 	int labcopy = labs - p->labs;
    261 	uint8_t lablen;
    262 	uint16_t ptr;
    263 
    264 	if(labs == 1) {
    265 		/* write root label */
    266 		if(sldns_buffer_remaining(pkt) < 1)
    267 			return 0;
    268 		sldns_buffer_write_u8(pkt, 0);
    269 		return 1;
    270 	}
    271 
    272 	/* copy the first couple of labels */
    273 	while(labcopy--) {
    274 		lablen = *dname++;
    275 		if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
    276 			return 0;
    277 		sldns_buffer_write_u8(pkt, lablen);
    278 		sldns_buffer_write(pkt, dname, lablen);
    279 		dname += lablen;
    280 	}
    281 	/* insert compression ptr */
    282 	if(sldns_buffer_remaining(pkt) < 2)
    283 		return 0;
    284 	ptr = PTR_CREATE(p->offset);
    285 	sldns_buffer_write_u16(pkt, ptr);
    286 	return 1;
    287 }
    288 
    289 /** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */
    290 static int
    291 compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
    292 	struct regional* region, struct compress_tree_node** tree,
    293 	size_t owner_pos, uint16_t* owner_ptr, int owner_labs,
    294 	size_t* compress_count)
    295 {
    296 	struct compress_tree_node* p;
    297 	struct compress_tree_node** insertpt = NULL;
    298 	if(!*owner_ptr) {
    299 		/* compress first time dname */
    300 		if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
    301 			(p = compress_tree_lookup(tree, key->rk.dname,
    302 			owner_labs, &insertpt))) {
    303 			if(p->labs == owner_labs)
    304 				/* avoid ptr chains, since some software is
    305 				 * not capable of decoding ptr after a ptr. */
    306 				*owner_ptr = htons(PTR_CREATE(p->offset));
    307 			if(!write_compressed_dname(pkt, key->rk.dname,
    308 				owner_labs, p))
    309 				return RETVAL_TRUNC;
    310 			(*compress_count)++;
    311 			/* check if typeclass+4 ttl + rdatalen is available */
    312 			if(sldns_buffer_remaining(pkt) < 4+4+2)
    313 				return RETVAL_TRUNC;
    314 		} else {
    315 			/* no compress */
    316 			if(sldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2)
    317 				return RETVAL_TRUNC;
    318 			sldns_buffer_write(pkt, key->rk.dname,
    319 				key->rk.dname_len);
    320 			if(owner_pos <= PTR_MAX_OFFSET)
    321 				*owner_ptr = htons(PTR_CREATE(owner_pos));
    322 		}
    323 		if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
    324 			!compress_tree_store(key->rk.dname, owner_labs,
    325 			owner_pos, region, p, insertpt))
    326 			return RETVAL_OUTMEM;
    327 	} else {
    328 		/* always compress 2nd-further RRs in RRset */
    329 		if(owner_labs == 1) {
    330 			if(sldns_buffer_remaining(pkt) < 1+4+4+2)
    331 				return RETVAL_TRUNC;
    332 			sldns_buffer_write_u8(pkt, 0);
    333 		} else {
    334 			if(sldns_buffer_remaining(pkt) < 2+4+4+2)
    335 				return RETVAL_TRUNC;
    336 			sldns_buffer_write(pkt, owner_ptr, 2);
    337 		}
    338 	}
    339 	return RETVAL_OK;
    340 }
    341 
    342 /** compress any domain name to the packet, return RETVAL_* */
    343 static int
    344 compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
    345 	struct regional* region, struct compress_tree_node** tree,
    346 	size_t* compress_count)
    347 {
    348 	struct compress_tree_node* p;
    349 	struct compress_tree_node** insertpt = NULL;
    350 	size_t pos = sldns_buffer_position(pkt);
    351 	if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
    352 		(p = compress_tree_lookup(tree, dname, labs, &insertpt))) {
    353 		if(!write_compressed_dname(pkt, dname, labs, p))
    354 			return RETVAL_TRUNC;
    355 	} else {
    356 		if(!dname_buffer_write(pkt, dname))
    357 			return RETVAL_TRUNC;
    358 	}
    359 	if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
    360 		!compress_tree_store(dname, labs, pos, region, p, insertpt))
    361 		return RETVAL_OUTMEM;
    362 	(*compress_count)++;
    363 	return RETVAL_OK;
    364 }
    365 
    366 /** return true if type needs domain name compression in rdata */
    367 static const sldns_rr_descriptor*
    368 type_rdata_compressible(struct ub_packed_rrset_key* key)
    369 {
    370 	uint16_t t = ntohs(key->rk.type);
    371 	if(sldns_rr_descript(t) &&
    372 		sldns_rr_descript(t)->_compress == LDNS_RR_COMPRESS)
    373 		return sldns_rr_descript(t);
    374 	return 0;
    375 }
    376 
    377 /** compress domain names in rdata, return RETVAL_* */
    378 static int
    379 compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
    380 	struct regional* region, struct compress_tree_node** tree,
    381 	const sldns_rr_descriptor* desc, size_t* compress_count)
    382 {
    383 	int labs, r, rdf = 0;
    384 	size_t dname_len, len, pos = sldns_buffer_position(pkt);
    385 	uint8_t count = desc->_dname_count;
    386 
    387 	sldns_buffer_skip(pkt, 2); /* rdata len fill in later */
    388 	/* space for rdatalen checked for already */
    389 	rdata += 2;
    390 	todolen -= 2;
    391 	while(todolen > 0 && count) {
    392 		switch(desc->_wireformat[rdf]) {
    393 		case LDNS_RDF_TYPE_DNAME:
    394 			labs = dname_count_size_labels(rdata, &dname_len);
    395 			if((r=compress_any_dname(rdata, pkt, labs, region,
    396 				tree, compress_count)) != RETVAL_OK)
    397 				return r;
    398 			rdata += dname_len;
    399 			todolen -= dname_len;
    400 			count--;
    401 			len = 0;
    402 			break;
    403 		case LDNS_RDF_TYPE_STR:
    404 			len = *rdata + 1;
    405 			break;
    406 		default:
    407 			len = get_rdf_size(desc->_wireformat[rdf]);
    408 		}
    409 		if(len) {
    410 			/* copy over */
    411 			if(sldns_buffer_remaining(pkt) < len)
    412 				return RETVAL_TRUNC;
    413 			sldns_buffer_write(pkt, rdata, len);
    414 			todolen -= len;
    415 			rdata += len;
    416 		}
    417 		rdf++;
    418 	}
    419 	/* copy remainder */
    420 	if(todolen > 0) {
    421 		if(sldns_buffer_remaining(pkt) < todolen)
    422 			return RETVAL_TRUNC;
    423 		sldns_buffer_write(pkt, rdata, todolen);
    424 	}
    425 
    426 	/* set rdata len */
    427 	sldns_buffer_write_u16_at(pkt, pos, sldns_buffer_position(pkt)-pos-2);
    428 	return RETVAL_OK;
    429 }
    430 
    431 /** Returns true if RR type should be included */
    432 static int
    433 rrset_belongs_in_reply(sldns_pkt_section s, uint16_t rrtype, uint16_t qtype,
    434 	int dnssec)
    435 {
    436 	if(dnssec)
    437 		return 1;
    438 	/* skip non DNSSEC types, except if directly queried for */
    439 	if(s == LDNS_SECTION_ANSWER) {
    440 		if(qtype == LDNS_RR_TYPE_ANY || qtype == rrtype)
    441 			return 1;
    442 	}
    443 	/* check DNSSEC-ness */
    444 	switch(rrtype) {
    445 		case LDNS_RR_TYPE_SIG:
    446 		case LDNS_RR_TYPE_KEY:
    447 		case LDNS_RR_TYPE_NXT:
    448 		case LDNS_RR_TYPE_DS:
    449 		case LDNS_RR_TYPE_RRSIG:
    450 		case LDNS_RR_TYPE_NSEC:
    451 		case LDNS_RR_TYPE_DNSKEY:
    452 		case LDNS_RR_TYPE_NSEC3:
    453 		case LDNS_RR_TYPE_NSEC3PARAMS:
    454 			return 0;
    455 	}
    456 	return 1;
    457 }
    458 
    459 /** store rrset in buffer in wireformat, return RETVAL_* */
    460 static int
    461 packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
    462 	uint16_t* num_rrs, time_t timenow, struct regional* region,
    463 	int do_data, int do_sig, struct compress_tree_node** tree,
    464 	sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset,
    465 	size_t* compress_count)
    466 {
    467 	size_t i, j, owner_pos;
    468 	int r, owner_labs;
    469 	uint16_t owner_ptr = 0;
    470 	time_t adjust = 0;
    471 	struct packed_rrset_data* data = (struct packed_rrset_data*)
    472 		key->entry.data;
    473 
    474 	/* does this RR type belong in the answer? */
    475 	if(!rrset_belongs_in_reply(s, ntohs(key->rk.type), qtype, dnssec))
    476 		return RETVAL_OK;
    477 
    478 	owner_labs = dname_count_labels(key->rk.dname);
    479 	owner_pos = sldns_buffer_position(pkt);
    480 
    481 	/** Determine relative time adjustment for TTL values.
    482 	 * For an rrset with a fixed TTL, use the rrset's TTL as given. */
    483 	if((key->rk.flags & PACKED_RRSET_FIXEDTTL) != 0)
    484 		adjust = 0;
    485 	else
    486 		adjust = SERVE_ORIGINAL_TTL ? data->ttl_add : timenow;
    487 
    488 	if(do_data) {
    489 		const sldns_rr_descriptor* c = type_rdata_compressible(key);
    490 		for(i=0; i<data->count; i++) {
    491 			/* rrset roundrobin */
    492 			j = (i + rr_offset) % data->count;
    493 			if((r=compress_owner(key, pkt, region, tree,
    494 				owner_pos, &owner_ptr, owner_labs,
    495 				compress_count)) != RETVAL_OK)
    496 				return r;
    497 			sldns_buffer_write(pkt, &key->rk.type, 2);
    498 			sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
    499 			if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) {
    500 				sldns_buffer_write_u32(pkt, 0);
    501 			} else if(adjust == 0) {
    502 				sldns_buffer_write_u32(pkt, data->rr_ttl[j]);
    503 			} else if(TTL_IS_EXPIRED(data->rr_ttl[j], adjust)) {
    504 				sldns_buffer_write_u32(pkt,
    505 					EXPIRED_REPLY_TTL_CALC(
    506 					    data->rr_ttl[j], data->ttl_add));
    507 			} else {
    508 				sldns_buffer_write_u32(pkt,
    509 					data->rr_ttl[j] - adjust);
    510 			}
    511 			if(c) {
    512 				if((r=compress_rdata(pkt, data->rr_data[j],
    513 					data->rr_len[j], region, tree, c,
    514 					compress_count)) != RETVAL_OK)
    515 					return r;
    516 			} else {
    517 				if(sldns_buffer_remaining(pkt) < data->rr_len[j])
    518 					return RETVAL_TRUNC;
    519 				sldns_buffer_write(pkt, data->rr_data[j],
    520 					data->rr_len[j]);
    521 			}
    522 		}
    523 	}
    524 	/* insert rrsigs */
    525 	if(do_sig && dnssec) {
    526 		size_t total = data->count+data->rrsig_count;
    527 		for(i=data->count; i<total; i++) {
    528 			if(owner_ptr && owner_labs != 1) {
    529 				if(sldns_buffer_remaining(pkt) <
    530 					2+4+4+data->rr_len[i])
    531 					return RETVAL_TRUNC;
    532 				sldns_buffer_write(pkt, &owner_ptr, 2);
    533 			} else {
    534 				if((r=compress_any_dname(key->rk.dname,
    535 					pkt, owner_labs, region, tree,
    536 					compress_count)) != RETVAL_OK)
    537 					return r;
    538 				if(sldns_buffer_remaining(pkt) <
    539 					4+4+data->rr_len[i])
    540 					return RETVAL_TRUNC;
    541 			}
    542 			sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
    543 			sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
    544 			if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) {
    545 				sldns_buffer_write_u32(pkt, 0);
    546 			} else if(adjust == 0) {
    547 				sldns_buffer_write_u32(pkt, data->rr_ttl[i]);
    548 			} else if(TTL_IS_EXPIRED(data->rr_ttl[i], adjust)) {
    549 				sldns_buffer_write_u32(pkt,
    550 					EXPIRED_REPLY_TTL_CALC(
    551 					    data->rr_ttl[i], data->ttl_add));
    552 			} else {
    553 				sldns_buffer_write_u32(pkt,
    554 					data->rr_ttl[i] - adjust);
    555 			}
    556 			/* rrsig rdata cannot be compressed, perform 100+ byte
    557 			 * memcopy. */
    558 			sldns_buffer_write(pkt, data->rr_data[i],
    559 				data->rr_len[i]);
    560 		}
    561 	}
    562 	/* change rrnum only after we are sure it fits */
    563 	if(do_data)
    564 		*num_rrs += data->count;
    565 	if(do_sig && dnssec)
    566 		*num_rrs += data->rrsig_count;
    567 
    568 	return RETVAL_OK;
    569 }
    570 
    571 /** store msg section in wireformat buffer, return RETVAL_* */
    572 static int
    573 insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
    574 	sldns_buffer* pkt, size_t rrsets_before, time_t timenow,
    575 	struct regional* region, struct compress_tree_node** tree,
    576 	sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset,
    577 	size_t* compress_count)
    578 {
    579 	int r;
    580 	size_t i, setstart;
    581 	/* we now allow this function to be called multiple times for the
    582 	 * same section, incrementally updating num_rrs.  The caller is
    583 	 * responsible for initializing it (which is the case in the current
    584 	 * implementation). */
    585 
    586 	if(s != LDNS_SECTION_ADDITIONAL) {
    587 		if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY)
    588 			dnssec = 1; /* include all types in ANY answer */
    589 	  	for(i=0; i<num_rrsets; i++) {
    590 			setstart = sldns_buffer_position(pkt);
    591 			if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
    592 				pkt, num_rrs, timenow, region, 1, 1, tree,
    593 				s, qtype, dnssec, rr_offset, compress_count))
    594 				!= RETVAL_OK) {
    595 				/* Bad, but if due to size must set TC bit */
    596 				/* trim off the rrset neatly. */
    597 				sldns_buffer_set_position(pkt, setstart);
    598 				return r;
    599 			}
    600 		}
    601 	} else {
    602 	  	for(i=0; i<num_rrsets; i++) {
    603 			setstart = sldns_buffer_position(pkt);
    604 			if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
    605 				pkt, num_rrs, timenow, region, 1, 0, tree,
    606 				s, qtype, dnssec, rr_offset, compress_count))
    607 				!= RETVAL_OK) {
    608 				sldns_buffer_set_position(pkt, setstart);
    609 				return r;
    610 			}
    611 		}
    612 		if(dnssec)
    613 	  	  for(i=0; i<num_rrsets; i++) {
    614 			setstart = sldns_buffer_position(pkt);
    615 			if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
    616 				pkt, num_rrs, timenow, region, 0, 1, tree,
    617 				s, qtype, dnssec, rr_offset, compress_count))
    618 				!= RETVAL_OK) {
    619 				sldns_buffer_set_position(pkt, setstart);
    620 				return r;
    621 			}
    622 		  }
    623 	}
    624 	return RETVAL_OK;
    625 }
    626 
    627 /** store query section in wireformat buffer, return RETVAL */
    628 static int
    629 insert_query(struct query_info* qinfo, struct compress_tree_node** tree,
    630 	sldns_buffer* buffer, struct regional* region)
    631 {
    632 	uint8_t* qname = qinfo->local_alias ?
    633 		qinfo->local_alias->rrset->rk.dname : qinfo->qname;
    634 	size_t qname_len = qinfo->local_alias ?
    635 		qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len;
    636 	if(sldns_buffer_remaining(buffer) <
    637 		qinfo->qname_len+sizeof(uint16_t)*2)
    638 		return RETVAL_TRUNC; /* buffer too small */
    639 	/* the query is the first name inserted into the tree */
    640 	if(!compress_tree_store(qname, dname_count_labels(qname),
    641 		sldns_buffer_position(buffer), region, NULL, tree))
    642 		return RETVAL_OUTMEM;
    643 	if(sldns_buffer_current(buffer) == qname)
    644 		sldns_buffer_skip(buffer, (ssize_t)qname_len);
    645 	else	sldns_buffer_write(buffer, qname, qname_len);
    646 	sldns_buffer_write_u16(buffer, qinfo->qtype);
    647 	sldns_buffer_write_u16(buffer, qinfo->qclass);
    648 	return RETVAL_OK;
    649 }
    650 
    651 static int
    652 positive_answer(struct reply_info* rep, uint16_t qtype) {
    653 	size_t i;
    654 	if (FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR)
    655 		return 0;
    656 
    657 	for(i=0;i<rep->an_numrrsets; i++) {
    658 		if(ntohs(rep->rrsets[i]->rk.type) == qtype) {
    659 			/* for priming queries, type NS, include addresses */
    660 			if(qtype == LDNS_RR_TYPE_NS)
    661 				return 0;
    662 			/* in case it is a wildcard with DNSSEC, there will
    663 			 * be NSEC/NSEC3 records in the authority section
    664 			 * that we cannot remove */
    665 			for(i=rep->an_numrrsets; i<rep->an_numrrsets+
    666 				rep->ns_numrrsets; i++) {
    667 				if(ntohs(rep->rrsets[i]->rk.type) ==
    668 					LDNS_RR_TYPE_NSEC ||
    669 				   ntohs(rep->rrsets[i]->rk.type) ==
    670 				   	LDNS_RR_TYPE_NSEC3)
    671 					return 0;
    672 			}
    673 			return 1;
    674 		}
    675 	}
    676 	return 0;
    677 }
    678 
    679 static int
    680 negative_answer(struct reply_info* rep) {
    681 	size_t i;
    682 	int ns_seen = 0;
    683 	if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)
    684 		return 1;
    685 	if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR &&
    686 		rep->an_numrrsets != 0)
    687 		return 0; /* positive */
    688 	if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR &&
    689 		FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN)
    690 		return 0;
    691 	for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++){
    692 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_SOA)
    693 			return 1;
    694 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
    695 			ns_seen = 1;
    696 	}
    697 	if(ns_seen) return 0; /* could be referral, NS, but no SOA */
    698 	return 1;
    699 }
    700 
    701 int
    702 reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
    703 	uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow,
    704 	struct regional* region, uint16_t udpsize, int dnssec, int minimise)
    705 {
    706 	uint16_t ancount=0, nscount=0, arcount=0;
    707 	struct compress_tree_node* tree = 0;
    708 	int r;
    709 	size_t rr_offset;
    710 	size_t compress_count=0;
    711 
    712 	sldns_buffer_clear(buffer);
    713 	if(udpsize < sldns_buffer_limit(buffer))
    714 		sldns_buffer_set_limit(buffer, udpsize);
    715 	if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
    716 		return 0;
    717 
    718 	sldns_buffer_write(buffer, &id, sizeof(uint16_t));
    719 	sldns_buffer_write_u16(buffer, flags);
    720 	sldns_buffer_write_u16(buffer, rep->qdcount);
    721 	/* set an, ns, ar counts to zero in case of small packets */
    722 	sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6);
    723 
    724 	/* insert query section */
    725 	if(rep->qdcount) {
    726 		if((r=insert_query(qinfo, &tree, buffer, region)) !=
    727 			RETVAL_OK) {
    728 			if(r == RETVAL_TRUNC) {
    729 				/* create truncated message */
    730 				sldns_buffer_write_u16_at(buffer, 4, 0);
    731 				LDNS_TC_SET(sldns_buffer_begin(buffer));
    732 				sldns_buffer_flip(buffer);
    733 				return 1;
    734 			}
    735 			return 0;
    736 		}
    737 	}
    738 	/* roundrobin offset. using query id for random number.  With ntohs
    739 	 * for different roundrobins for sequential id client senders. */
    740 	rr_offset = RRSET_ROUNDROBIN?ntohs(id)+(timenow?timenow:time(NULL)):0;
    741 
    742 	/* "prepend" any local alias records in the answer section if this
    743 	 * response is supposed to be authoritative.  Currently it should
    744 	 * be a single CNAME record (sanity-checked in worker_handle_request())
    745 	 * but it can be extended if and when we support more variations of
    746 	 * aliases. */
    747 	if(qinfo->local_alias && (flags & BIT_AA)) {
    748 		struct reply_info arep;
    749 		time_t timezero = 0; /* to use the 'authoritative' TTL */
    750 		memset(&arep, 0, sizeof(arep));
    751 		arep.flags = rep->flags;
    752 		arep.an_numrrsets = 1;
    753 		arep.rrset_count = 1;
    754 		arep.rrsets = &qinfo->local_alias->rrset;
    755 		if((r=insert_section(&arep, 1, &ancount, buffer, 0,
    756 			timezero, region, &tree, LDNS_SECTION_ANSWER,
    757 			qinfo->qtype, dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
    758 			if(r == RETVAL_TRUNC) {
    759 				/* create truncated message */
    760 				sldns_buffer_write_u16_at(buffer, 6, ancount);
    761 				LDNS_TC_SET(sldns_buffer_begin(buffer));
    762 				sldns_buffer_flip(buffer);
    763 				return 1;
    764 			}
    765 			return 0;
    766 		}
    767 	}
    768 
    769 	/* insert answer section */
    770 	if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer,
    771 		0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype,
    772 		dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
    773 		if(r == RETVAL_TRUNC) {
    774 			/* create truncated message */
    775 			sldns_buffer_write_u16_at(buffer, 6, ancount);
    776 			LDNS_TC_SET(sldns_buffer_begin(buffer));
    777 			sldns_buffer_flip(buffer);
    778 			return 1;
    779 		}
    780 		return 0;
    781 	}
    782 	sldns_buffer_write_u16_at(buffer, 6, ancount);
    783 
    784 	/* if response is positive answer, auth/add sections are not required */
    785 	if( ! (minimise && positive_answer(rep, qinfo->qtype)) ) {
    786 		/* insert auth section */
    787 		if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer,
    788 			rep->an_numrrsets, timenow, region, &tree,
    789 			LDNS_SECTION_AUTHORITY, qinfo->qtype,
    790 			dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
    791 			if(r == RETVAL_TRUNC) {
    792 				/* create truncated message */
    793 				sldns_buffer_write_u16_at(buffer, 8, nscount);
    794 				LDNS_TC_SET(sldns_buffer_begin(buffer));
    795 				sldns_buffer_flip(buffer);
    796 				return 1;
    797 			}
    798 			return 0;
    799 		}
    800 		sldns_buffer_write_u16_at(buffer, 8, nscount);
    801 
    802 		if(! (minimise && negative_answer(rep))) {
    803 			/* insert add section */
    804 			if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer,
    805 				rep->an_numrrsets + rep->ns_numrrsets, timenow, region,
    806 				&tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype,
    807 				dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
    808 				if(r == RETVAL_TRUNC) {
    809 					/* no need to set TC bit, this is the additional */
    810 					sldns_buffer_write_u16_at(buffer, 10, arcount);
    811 					sldns_buffer_flip(buffer);
    812 					return 1;
    813 				}
    814 				return 0;
    815 			}
    816 			sldns_buffer_write_u16_at(buffer, 10, arcount);
    817 		}
    818 	}
    819 	sldns_buffer_flip(buffer);
    820 	return 1;
    821 }
    822 
    823 size_t
    824 calc_edns_field_size(struct edns_data* edns)
    825 {
    826 	size_t rdatalen = 0;
    827 	struct edns_option* opt;
    828 	if(!edns || !edns->edns_present)
    829 		return 0;
    830 	for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
    831 		rdatalen += 4 + opt->opt_len;
    832 	}
    833 	for(opt = edns->opt_list_out; opt; opt = opt->next) {
    834 		rdatalen += 4 + opt->opt_len;
    835 	}
    836 	/* domain root '.' + type + class + ttl + rdatalen */
    837 	return 1 + 2 + 2 + 4 + 2 + rdatalen;
    838 }
    839 
    840 uint16_t
    841 calc_edns_option_size(struct edns_data* edns, uint16_t code)
    842 {
    843 	size_t rdatalen = 0;
    844 	struct edns_option* opt;
    845 	if(!edns || !edns->edns_present)
    846 		return 0;
    847 	for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
    848 		if(opt->opt_code == code)
    849 			rdatalen += 4 + opt->opt_len;
    850 	}
    851 	for(opt = edns->opt_list_out; opt; opt = opt->next) {
    852 		if(opt->opt_code == code)
    853 			rdatalen += 4 + opt->opt_len;
    854 	}
    855 	return rdatalen;
    856 }
    857 
    858 uint16_t
    859 calc_ede_option_size(struct edns_data* edns, size_t* txt_size)
    860 {
    861 	size_t rdatalen = 0;
    862 	struct edns_option* opt;
    863 	*txt_size = 0;
    864 	if(!edns || !edns->edns_present)
    865 		return 0;
    866 	for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
    867 		if(opt->opt_code == LDNS_EDNS_EDE) {
    868 			rdatalen += 4 + opt->opt_len;
    869 			if(opt->opt_len > 2) *txt_size += opt->opt_len - 2;
    870 			if(opt->opt_len >= 2 && sldns_read_uint16(
    871 				opt->opt_data) == LDNS_EDE_OTHER) {
    872 				*txt_size += 4 + 2;
    873 			}
    874 		}
    875 	}
    876 	for(opt = edns->opt_list_out; opt; opt = opt->next) {
    877 		if(opt->opt_code == LDNS_EDNS_EDE) {
    878 			rdatalen += 4 + opt->opt_len;
    879 			if(opt->opt_len > 2) *txt_size += opt->opt_len - 2;
    880 			if(opt->opt_len >= 2 && sldns_read_uint16(
    881 				opt->opt_data) == LDNS_EDE_OTHER) {
    882 				*txt_size += 4 + 2;
    883 			}
    884 		}
    885 	}
    886 	return rdatalen;
    887 }
    888 
    889 /* Trims the EDE OPTION-DATA to not include any EXTRA-TEXT data.
    890  * Also removes any LDNS_EDE_OTHER options from the list since they are useless
    891  * without the extra text. */
    892 static void
    893 ede_trim_text(struct edns_option** list)
    894 {
    895 	struct edns_option* curr, *prev = NULL;
    896 	if(!list || !(*list)) return;
    897 	/* Unlink and repoint if LDNS_EDE_OTHER are first in list */
    898 	while(list && *list && (*list)->opt_code == LDNS_EDNS_EDE
    899 		&& (*list)->opt_len >= 2
    900 		&& sldns_read_uint16((*list)->opt_data) == LDNS_EDE_OTHER ) {
    901 		*list = (*list)->next;
    902 	}
    903 	if(!list || !(*list)) return;
    904 	curr = *list;
    905 	while(curr) {
    906 		if(curr->opt_code == LDNS_EDNS_EDE) {
    907 			if(curr->opt_len >= 2 && sldns_read_uint16(
    908 				curr->opt_data) == LDNS_EDE_OTHER) {
    909 				/* LDNS_EDE_OTHER cannot be the first option in
    910 				 * this while, so prev is always initialized at
    911 				 * this point from the other branches;
    912 				 * cut this option off */
    913 				prev->next = curr->next;
    914 				curr = curr->next;
    915 			} else if(curr->opt_len > 2) {
    916 				/* trim this option's EXTRA-TEXT */
    917 				curr->opt_len = 2;
    918 				prev = curr;
    919 				curr = curr->next;
    920 			} else {
    921 				prev = curr;
    922 				curr = curr->next;
    923 			}
    924 		} else {
    925 			/* continue */
    926 			prev = curr;
    927 			curr = curr->next;
    928 		}
    929 	}
    930 }
    931 
    932 static void
    933 attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns,
    934 	uint16_t max_msg_sz)
    935 {
    936 	size_t len;
    937 	size_t rdatapos;
    938 	struct edns_option* opt;
    939 	struct edns_option* padding_option = NULL;
    940 	/* inc additional count */
    941 	sldns_buffer_write_u16_at(pkt, 10,
    942 		sldns_buffer_read_u16_at(pkt, 10) + 1);
    943 	len = sldns_buffer_limit(pkt);
    944 	sldns_buffer_clear(pkt);
    945 	sldns_buffer_set_position(pkt, len);
    946 	/* write EDNS record */
    947 	sldns_buffer_write_u8(pkt, 0); /* '.' label */
    948 	sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
    949 	sldns_buffer_write_u16(pkt, edns->udp_size); /* class */
    950 	sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
    951 	sldns_buffer_write_u8(pkt, edns->edns_version);
    952 	sldns_buffer_write_u16(pkt, edns->bits);
    953 	rdatapos = sldns_buffer_position(pkt);
    954 	sldns_buffer_write_u16(pkt, 0); /* rdatalen */
    955 	/* write rdata */
    956 	for(opt=edns->opt_list_inplace_cb_out; opt; opt=opt->next) {
    957 		if (opt->opt_code == LDNS_EDNS_PADDING) {
    958 			padding_option = opt;
    959 			continue;
    960 		}
    961 		if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz)
    962 			break; /* no space for it */
    963 		if(!sldns_buffer_available(pkt, 4 + opt->opt_len))
    964 			break;
    965 		sldns_buffer_write_u16(pkt, opt->opt_code);
    966 		sldns_buffer_write_u16(pkt, opt->opt_len);
    967 		if(opt->opt_len != 0)
    968 			sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
    969 	}
    970 	for(opt=edns->opt_list_out; opt; opt=opt->next) {
    971 		if (opt->opt_code == LDNS_EDNS_PADDING) {
    972 			padding_option = opt;
    973 			continue;
    974 		}
    975 		if(sldns_buffer_position(pkt) + opt->opt_len + 4 > max_msg_sz)
    976 			break; /* no space for it */
    977 		if(!sldns_buffer_available(pkt, 4 + opt->opt_len))
    978 			break;
    979 		sldns_buffer_write_u16(pkt, opt->opt_code);
    980 		sldns_buffer_write_u16(pkt, opt->opt_len);
    981 		if(opt->opt_len != 0)
    982 			sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
    983 	}
    984 	if (padding_option && edns->padding_block_size &&
    985 		sldns_buffer_position(pkt)+4 <= max_msg_sz &&
    986 		sldns_buffer_available(pkt, 4) /* if there is space for it */) {
    987 		size_t pad_pos = sldns_buffer_position(pkt);
    988 		size_t msg_sz = ((pad_pos + 3) / edns->padding_block_size + 1)
    989 		                               * edns->padding_block_size;
    990 		size_t pad_sz;
    991 
    992 		if (msg_sz > max_msg_sz)
    993 			msg_sz = max_msg_sz;
    994 
    995 		/* By use of calc_edns_field_size, calling functions should
    996 		 * have made sure that there is enough space for at least a
    997 		 * zero sized padding option.
    998 		 */
    999 		log_assert(pad_pos + 4 <= msg_sz);
   1000 
   1001 		pad_sz = msg_sz - pad_pos - 4;
   1002 		sldns_buffer_write_u16(pkt, LDNS_EDNS_PADDING);
   1003 		sldns_buffer_write_u16(pkt, pad_sz);
   1004 		if (pad_sz) {
   1005 			memset(sldns_buffer_current(pkt), 0, pad_sz);
   1006 			sldns_buffer_skip(pkt, pad_sz);
   1007 		}
   1008 	}
   1009 	sldns_buffer_write_u16_at(pkt, rdatapos,
   1010 			sldns_buffer_position(pkt)-rdatapos-2);
   1011 	sldns_buffer_flip(pkt);
   1012 }
   1013 
   1014 void
   1015 attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
   1016 {
   1017 	if(!edns || !edns->edns_present)
   1018 		return;
   1019 	attach_edns_record_max_msg_sz(pkt, edns, edns->udp_size);
   1020 }
   1021 
   1022 int
   1023 reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
   1024 	uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow,
   1025 	int cached, struct regional* region, uint16_t udpsize,
   1026 	struct edns_data* edns, int dnssec, int secure)
   1027 {
   1028 	uint16_t flags;
   1029 	unsigned int attach_edns = 0;
   1030 	size_t edns_field_size, ede_size, ede_txt_size;
   1031 
   1032 	if(!cached || rep->authoritative) {
   1033 		/* original flags, copy RD and CD bits from query. */
   1034 		flags = rep->flags | (qflags & (BIT_RD|BIT_CD));
   1035 	} else {
   1036 		/* remove AA bit, copy RD and CD bits from query. */
   1037 		flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD));
   1038 	}
   1039 	if(secure && (dnssec || (qflags&BIT_AD)))
   1040 		flags |= BIT_AD;
   1041 	/* restore AA bit if we have a local alias and the response can be
   1042 	 * authoritative.  Also clear AD bit if set as the local data is the
   1043 	 * primary answer. */
   1044 	if(qinf->local_alias &&
   1045 		(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR ||
   1046 		FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)) {
   1047 		flags |= BIT_AA;
   1048 		flags &= ~BIT_AD;
   1049 	}
   1050 	log_assert((flags & BIT_QR)); /* QR bit must be on in our replies */
   1051 	if(udpsize < LDNS_HEADER_SIZE)
   1052 		return 0;
   1053 	/* currently edns does not change during calculations;
   1054 	 * calculate sizes once here */
   1055 	edns_field_size = calc_edns_field_size(edns);
   1056 	ede_size = calc_ede_option_size(edns, &ede_txt_size);
   1057 	if(sldns_buffer_capacity(pkt) < (size_t)udpsize)
   1058 		udpsize = sldns_buffer_capacity(pkt);
   1059 	if(!edns || !edns->edns_present) {
   1060 		attach_edns = 0;
   1061 	/* EDEs are optional, try to fit anything else before them */
   1062 	} else if((size_t)udpsize < (size_t)LDNS_HEADER_SIZE + edns_field_size - ede_size) {
   1063 		/* packet too small to contain edns, omit it. */
   1064 		attach_edns = 0;
   1065 	} else {
   1066 		/* reserve space for edns record */
   1067 		attach_edns = (unsigned int)edns_field_size - ede_size;
   1068 	}
   1069 
   1070 	if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
   1071 		udpsize - attach_edns, dnssec, MINIMAL_RESPONSES)) {
   1072 		log_err("reply encode: out of memory");
   1073 		return 0;
   1074 	}
   1075 	if(attach_edns) {
   1076 		if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size)
   1077 			attach_edns_record_max_msg_sz(pkt, edns, udpsize);
   1078 		else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) {
   1079 			ede_trim_text(&edns->opt_list_inplace_cb_out);
   1080 			ede_trim_text(&edns->opt_list_out);
   1081 			attach_edns_record_max_msg_sz(pkt, edns, udpsize);
   1082 		} else if((size_t)udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) {
   1083 			edns_opt_list_remove(&edns->opt_list_inplace_cb_out, LDNS_EDNS_EDE);
   1084 			edns_opt_list_remove(&edns->opt_list_out, LDNS_EDNS_EDE);
   1085 			attach_edns_record_max_msg_sz(pkt, edns, udpsize);
   1086 		}
   1087 	}
   1088 	return 1;
   1089 }
   1090 
   1091 void
   1092 qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo)
   1093 {
   1094 	uint16_t flags = 0; /* QUERY, NOERROR */
   1095 	const uint8_t* qname = qinfo->local_alias ?
   1096 		qinfo->local_alias->rrset->rk.dname : qinfo->qname;
   1097 	size_t qname_len = qinfo->local_alias ?
   1098 		qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len;
   1099 	sldns_buffer_clear(pkt);
   1100 	log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
   1101 	sldns_buffer_skip(pkt, 2); /* id done later */
   1102 	sldns_buffer_write_u16(pkt, flags);
   1103 	sldns_buffer_write_u16(pkt, 1); /* query count */
   1104 	sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
   1105 	sldns_buffer_write(pkt, qname, qname_len);
   1106 	sldns_buffer_write_u16(pkt, qinfo->qtype);
   1107 	sldns_buffer_write_u16(pkt, qinfo->qclass);
   1108 	sldns_buffer_flip(pkt);
   1109 }
   1110 
   1111 void
   1112 extended_error_encode(sldns_buffer* buf, uint16_t rcode,
   1113 	struct query_info* qinfo, uint16_t qid, uint16_t qflags,
   1114 	uint16_t xflags, struct edns_data* edns)
   1115 {
   1116 	uint16_t flags;
   1117 
   1118 	sldns_buffer_clear(buf);
   1119 	sldns_buffer_write(buf, &qid, sizeof(uint16_t));
   1120 	flags = (uint16_t)(BIT_QR | BIT_RA | (rcode & 0xF)); /* QR and retcode*/
   1121 	flags |= xflags;
   1122 	flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
   1123 	sldns_buffer_write_u16(buf, flags);
   1124 	if(qinfo) flags = 1;
   1125 	else	flags = 0;
   1126 	sldns_buffer_write_u16(buf, flags);
   1127 	flags = 0;
   1128 	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
   1129 	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
   1130 	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
   1131 	if(qinfo) {
   1132 		const uint8_t* qname = qinfo->local_alias ?
   1133 			qinfo->local_alias->rrset->rk.dname : qinfo->qname;
   1134 		size_t qname_len = qinfo->local_alias ?
   1135 			qinfo->local_alias->rrset->rk.dname_len :
   1136 			qinfo->qname_len;
   1137 		if(sldns_buffer_current(buf) == qname)
   1138 			sldns_buffer_skip(buf, (ssize_t)qname_len);
   1139 		else	sldns_buffer_write(buf, qname, qname_len);
   1140 		sldns_buffer_write_u16(buf, qinfo->qtype);
   1141 		sldns_buffer_write_u16(buf, qinfo->qclass);
   1142 	}
   1143 	sldns_buffer_flip(buf);
   1144 	if(edns && edns->edns_present) {
   1145 		size_t edns_field_size, ede_size, ede_txt_size;
   1146 		struct edns_data es = *edns;
   1147 		es.edns_version = EDNS_ADVERTISED_VERSION;
   1148 		es.udp_size = EDNS_ADVERTISED_SIZE;
   1149 		es.ext_rcode = (uint8_t)(rcode >> 4);
   1150 		es.bits &= EDNS_DO;
   1151 		/* EDEs are optional. If space is a concern try in order:
   1152 		 * - removing any EXTRA-TEXT fields from explicit EDEs, or
   1153 		 * - removing all EDEs,
   1154 		 * to see if EDNS can fit. */
   1155 		edns_field_size = calc_edns_field_size(&es);
   1156 		ede_size = calc_ede_option_size(&es, &ede_txt_size);
   1157 		if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size)
   1158 			attach_edns_record_max_msg_sz(buf, &es, edns->udp_size);
   1159 		else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_txt_size) {
   1160 			ede_trim_text(&es.opt_list_inplace_cb_out);
   1161 			ede_trim_text(&es.opt_list_out);
   1162 			attach_edns_record_max_msg_sz(buf, &es, edns->udp_size);
   1163 		} else if((size_t)edns->udp_size >= sldns_buffer_limit(buf) + edns_field_size - ede_size) {
   1164 			edns_opt_list_remove(&es.opt_list_inplace_cb_out, LDNS_EDNS_EDE);
   1165 			edns_opt_list_remove(&es.opt_list_out, LDNS_EDNS_EDE);
   1166 			attach_edns_record_max_msg_sz(buf, &es, edns->udp_size);
   1167 		}
   1168 	}
   1169 }
   1170 
   1171 void
   1172 error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
   1173 	uint16_t qid, uint16_t qflags, struct edns_data* edns)
   1174 {
   1175 	extended_error_encode(buf, (r & 0x000F), qinfo, qid, qflags,
   1176 		(r & 0xFFF0), edns);
   1177 }
   1178