xref: /freebsd/contrib/unbound/util/data/msgencode.c (revision 5a5c2279813012882e59aa7bb51d50c5baba3b1e)
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
compress_tree_search(struct compress_tree_node ** tree,uint8_t * dname,int labs,struct compress_tree_node ** match,int * matchlabels,struct compress_tree_node *** insertpt)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*
compress_tree_lookup(struct compress_tree_node ** tree,uint8_t * dname,int labs,struct compress_tree_node *** insertpt)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*
compress_tree_newnode(uint8_t * dname,int labs,size_t offset,struct regional * region)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
compress_tree_store(uint8_t * dname,int labs,size_t offset,struct regional * region,struct compress_tree_node * closest,struct compress_tree_node ** insertpt)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
write_compressed_dname(sldns_buffer * pkt,uint8_t * dname,int labs,struct compress_tree_node * p)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
compress_owner(struct ub_packed_rrset_key * key,sldns_buffer * pkt,struct regional * region,struct compress_tree_node ** tree,size_t owner_pos,uint16_t * owner_ptr,int owner_labs,size_t * compress_count)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
compress_any_dname(uint8_t * dname,sldns_buffer * pkt,int labs,struct regional * region,struct compress_tree_node ** tree,size_t * compress_count)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 		(*compress_count)++;
356 	} else {
357 		if(!dname_buffer_write(pkt, dname))
358 			return RETVAL_TRUNC;
359 	}
360 	if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
361 		!compress_tree_store(dname, labs, pos, region, p, insertpt))
362 		return RETVAL_OUTMEM;
363 	return RETVAL_OK;
364 }
365 
366 /** return true if type needs domain name compression in rdata */
367 static const sldns_rr_descriptor*
type_rdata_compressable(struct ub_packed_rrset_key * key)368 type_rdata_compressable(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
compress_rdata(sldns_buffer * pkt,uint8_t * rdata,size_t todolen,struct regional * region,struct compress_tree_node ** tree,const sldns_rr_descriptor * desc,size_t * compress_count)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
rrset_belongs_in_reply(sldns_pkt_section s,uint16_t rrtype,uint16_t qtype,int dnssec)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
packed_rrset_encode(struct ub_packed_rrset_key * key,sldns_buffer * pkt,uint16_t * num_rrs,time_t timenow,struct regional * region,int do_data,int do_sig,struct compress_tree_node ** tree,sldns_pkt_section s,uint16_t qtype,int dnssec,size_t rr_offset,size_t * compress_count)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_compressable(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(data->rr_ttl[j] < adjust)
500 				sldns_buffer_write_u32(pkt,
501 					SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0);
502 			else	sldns_buffer_write_u32(pkt, data->rr_ttl[j]-adjust);
503 			if(c) {
504 				if((r=compress_rdata(pkt, data->rr_data[j],
505 					data->rr_len[j], region, tree, c,
506 					compress_count)) != RETVAL_OK)
507 					return r;
508 			} else {
509 				if(sldns_buffer_remaining(pkt) < data->rr_len[j])
510 					return RETVAL_TRUNC;
511 				sldns_buffer_write(pkt, data->rr_data[j],
512 					data->rr_len[j]);
513 			}
514 		}
515 	}
516 	/* insert rrsigs */
517 	if(do_sig && dnssec) {
518 		size_t total = data->count+data->rrsig_count;
519 		for(i=data->count; i<total; i++) {
520 			if(owner_ptr && owner_labs != 1) {
521 				if(sldns_buffer_remaining(pkt) <
522 					2+4+4+data->rr_len[i])
523 					return RETVAL_TRUNC;
524 				sldns_buffer_write(pkt, &owner_ptr, 2);
525 			} else {
526 				if((r=compress_any_dname(key->rk.dname,
527 					pkt, owner_labs, region, tree,
528 					compress_count)) != RETVAL_OK)
529 					return r;
530 				if(sldns_buffer_remaining(pkt) <
531 					4+4+data->rr_len[i])
532 					return RETVAL_TRUNC;
533 			}
534 			sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
535 			sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
536 			if(data->rr_ttl[i] < adjust)
537 				sldns_buffer_write_u32(pkt,
538 					SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0);
539 			else	sldns_buffer_write_u32(pkt, data->rr_ttl[i]-adjust);
540 			/* rrsig rdata cannot be compressed, perform 100+ byte
541 			 * memcopy. */
542 			sldns_buffer_write(pkt, data->rr_data[i],
543 				data->rr_len[i]);
544 		}
545 	}
546 	/* change rrnum only after we are sure it fits */
547 	if(do_data)
548 		*num_rrs += data->count;
549 	if(do_sig && dnssec)
550 		*num_rrs += data->rrsig_count;
551 
552 	return RETVAL_OK;
553 }
554 
555 /** store msg section in wireformat buffer, return RETVAL_* */
556 static int
insert_section(struct reply_info * rep,size_t num_rrsets,uint16_t * num_rrs,sldns_buffer * pkt,size_t rrsets_before,time_t timenow,struct regional * region,struct compress_tree_node ** tree,sldns_pkt_section s,uint16_t qtype,int dnssec,size_t rr_offset,size_t * compress_count)557 insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
558 	sldns_buffer* pkt, size_t rrsets_before, time_t timenow,
559 	struct regional* region, struct compress_tree_node** tree,
560 	sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset,
561 	size_t* compress_count)
562 {
563 	int r;
564 	size_t i, setstart;
565 	/* we now allow this function to be called multiple times for the
566 	 * same section, incrementally updating num_rrs.  The caller is
567 	 * responsible for initializing it (which is the case in the current
568 	 * implementation). */
569 
570 	if(s != LDNS_SECTION_ADDITIONAL) {
571 		if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY)
572 			dnssec = 1; /* include all types in ANY answer */
573 	  	for(i=0; i<num_rrsets; i++) {
574 			setstart = sldns_buffer_position(pkt);
575 			if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
576 				pkt, num_rrs, timenow, region, 1, 1, tree,
577 				s, qtype, dnssec, rr_offset, compress_count))
578 				!= RETVAL_OK) {
579 				/* Bad, but if due to size must set TC bit */
580 				/* trim off the rrset neatly. */
581 				sldns_buffer_set_position(pkt, setstart);
582 				return r;
583 			}
584 		}
585 	} else {
586 	  	for(i=0; i<num_rrsets; i++) {
587 			setstart = sldns_buffer_position(pkt);
588 			if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
589 				pkt, num_rrs, timenow, region, 1, 0, tree,
590 				s, qtype, dnssec, rr_offset, compress_count))
591 				!= RETVAL_OK) {
592 				sldns_buffer_set_position(pkt, setstart);
593 				return r;
594 			}
595 		}
596 		if(dnssec)
597 	  	  for(i=0; i<num_rrsets; i++) {
598 			setstart = sldns_buffer_position(pkt);
599 			if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
600 				pkt, num_rrs, timenow, region, 0, 1, tree,
601 				s, qtype, dnssec, rr_offset, compress_count))
602 				!= RETVAL_OK) {
603 				sldns_buffer_set_position(pkt, setstart);
604 				return r;
605 			}
606 		  }
607 	}
608 	return RETVAL_OK;
609 }
610 
611 /** store query section in wireformat buffer, return RETVAL */
612 static int
insert_query(struct query_info * qinfo,struct compress_tree_node ** tree,sldns_buffer * buffer,struct regional * region)613 insert_query(struct query_info* qinfo, struct compress_tree_node** tree,
614 	sldns_buffer* buffer, struct regional* region)
615 {
616 	uint8_t* qname = qinfo->local_alias ?
617 		qinfo->local_alias->rrset->rk.dname : qinfo->qname;
618 	size_t qname_len = qinfo->local_alias ?
619 		qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len;
620 	if(sldns_buffer_remaining(buffer) <
621 		qinfo->qname_len+sizeof(uint16_t)*2)
622 		return RETVAL_TRUNC; /* buffer too small */
623 	/* the query is the first name inserted into the tree */
624 	if(!compress_tree_store(qname, dname_count_labels(qname),
625 		sldns_buffer_position(buffer), region, NULL, tree))
626 		return RETVAL_OUTMEM;
627 	if(sldns_buffer_current(buffer) == qname)
628 		sldns_buffer_skip(buffer, (ssize_t)qname_len);
629 	else	sldns_buffer_write(buffer, qname, qname_len);
630 	sldns_buffer_write_u16(buffer, qinfo->qtype);
631 	sldns_buffer_write_u16(buffer, qinfo->qclass);
632 	return RETVAL_OK;
633 }
634 
635 static int
positive_answer(struct reply_info * rep,uint16_t qtype)636 positive_answer(struct reply_info* rep, uint16_t qtype) {
637 	size_t i;
638 	if (FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR)
639 		return 0;
640 
641 	for(i=0;i<rep->an_numrrsets; i++) {
642 		if(ntohs(rep->rrsets[i]->rk.type) == qtype) {
643 			/* for priming queries, type NS, include addresses */
644 			if(qtype == LDNS_RR_TYPE_NS)
645 				return 0;
646 			/* in case it is a wildcard with DNSSEC, there will
647 			 * be NSEC/NSEC3 records in the authority section
648 			 * that we cannot remove */
649 			for(i=rep->an_numrrsets; i<rep->an_numrrsets+
650 				rep->ns_numrrsets; i++) {
651 				if(ntohs(rep->rrsets[i]->rk.type) ==
652 					LDNS_RR_TYPE_NSEC ||
653 				   ntohs(rep->rrsets[i]->rk.type) ==
654 				   	LDNS_RR_TYPE_NSEC3)
655 					return 0;
656 			}
657 			return 1;
658 		}
659 	}
660 	return 0;
661 }
662 
663 static int
negative_answer(struct reply_info * rep)664 negative_answer(struct reply_info* rep) {
665 	size_t i;
666 	int ns_seen = 0;
667 	if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)
668 		return 1;
669 	if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR &&
670 		rep->an_numrrsets != 0)
671 		return 0; /* positive */
672 	if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR &&
673 		FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN)
674 		return 0;
675 	for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++){
676 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_SOA)
677 			return 1;
678 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
679 			ns_seen = 1;
680 	}
681 	if(ns_seen) return 0; /* could be referral, NS, but no SOA */
682 	return 1;
683 }
684 
685 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,int minimise)686 reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
687 	uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow,
688 	struct regional* region, uint16_t udpsize, int dnssec, int minimise)
689 {
690 	uint16_t ancount=0, nscount=0, arcount=0;
691 	struct compress_tree_node* tree = 0;
692 	int r;
693 	size_t rr_offset;
694 	size_t compress_count=0;
695 
696 	sldns_buffer_clear(buffer);
697 	if(udpsize < sldns_buffer_limit(buffer))
698 		sldns_buffer_set_limit(buffer, udpsize);
699 	if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
700 		return 0;
701 
702 	sldns_buffer_write(buffer, &id, sizeof(uint16_t));
703 	sldns_buffer_write_u16(buffer, flags);
704 	sldns_buffer_write_u16(buffer, rep->qdcount);
705 	/* set an, ns, ar counts to zero in case of small packets */
706 	sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6);
707 
708 	/* insert query section */
709 	if(rep->qdcount) {
710 		if((r=insert_query(qinfo, &tree, buffer, region)) !=
711 			RETVAL_OK) {
712 			if(r == RETVAL_TRUNC) {
713 				/* create truncated message */
714 				sldns_buffer_write_u16_at(buffer, 4, 0);
715 				LDNS_TC_SET(sldns_buffer_begin(buffer));
716 				sldns_buffer_flip(buffer);
717 				return 1;
718 			}
719 			return 0;
720 		}
721 	}
722 	/* roundrobin offset. using query id for random number.  With ntohs
723 	 * for different roundrobins for sequential id client senders. */
724 	rr_offset = RRSET_ROUNDROBIN?ntohs(id)+(timenow?timenow:time(NULL)):0;
725 
726 	/* "prepend" any local alias records in the answer section if this
727 	 * response is supposed to be authoritative.  Currently it should
728 	 * be a single CNAME record (sanity-checked in worker_handle_request())
729 	 * but it can be extended if and when we support more variations of
730 	 * aliases. */
731 	if(qinfo->local_alias && (flags & BIT_AA)) {
732 		struct reply_info arep;
733 		time_t timezero = 0; /* to use the 'authoritative' TTL */
734 		memset(&arep, 0, sizeof(arep));
735 		arep.flags = rep->flags;
736 		arep.an_numrrsets = 1;
737 		arep.rrset_count = 1;
738 		arep.rrsets = &qinfo->local_alias->rrset;
739 		if((r=insert_section(&arep, 1, &ancount, buffer, 0,
740 			timezero, region, &tree, LDNS_SECTION_ANSWER,
741 			qinfo->qtype, dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
742 			if(r == RETVAL_TRUNC) {
743 				/* create truncated message */
744 				sldns_buffer_write_u16_at(buffer, 6, ancount);
745 				LDNS_TC_SET(sldns_buffer_begin(buffer));
746 				sldns_buffer_flip(buffer);
747 				return 1;
748 			}
749 			return 0;
750 		}
751 	}
752 
753 	/* insert answer section */
754 	if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer,
755 		0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype,
756 		dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
757 		if(r == RETVAL_TRUNC) {
758 			/* create truncated message */
759 			sldns_buffer_write_u16_at(buffer, 6, ancount);
760 			LDNS_TC_SET(sldns_buffer_begin(buffer));
761 			sldns_buffer_flip(buffer);
762 			return 1;
763 		}
764 		return 0;
765 	}
766 	sldns_buffer_write_u16_at(buffer, 6, ancount);
767 
768 	/* if response is positive answer, auth/add sections are not required */
769 	if( ! (minimise && positive_answer(rep, qinfo->qtype)) ) {
770 		/* insert auth section */
771 		if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer,
772 			rep->an_numrrsets, timenow, region, &tree,
773 			LDNS_SECTION_AUTHORITY, qinfo->qtype,
774 			dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
775 			if(r == RETVAL_TRUNC) {
776 				/* create truncated message */
777 				sldns_buffer_write_u16_at(buffer, 8, nscount);
778 				LDNS_TC_SET(sldns_buffer_begin(buffer));
779 				sldns_buffer_flip(buffer);
780 				return 1;
781 			}
782 			return 0;
783 		}
784 		sldns_buffer_write_u16_at(buffer, 8, nscount);
785 
786 		if(! (minimise && negative_answer(rep))) {
787 			/* insert add section */
788 			if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer,
789 				rep->an_numrrsets + rep->ns_numrrsets, timenow, region,
790 				&tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype,
791 				dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
792 				if(r == RETVAL_TRUNC) {
793 					/* no need to set TC bit, this is the additional */
794 					sldns_buffer_write_u16_at(buffer, 10, arcount);
795 					sldns_buffer_flip(buffer);
796 					return 1;
797 				}
798 				return 0;
799 			}
800 			sldns_buffer_write_u16_at(buffer, 10, arcount);
801 		}
802 	}
803 	sldns_buffer_flip(buffer);
804 	return 1;
805 }
806 
807 uint16_t
calc_edns_field_size(struct edns_data * edns)808 calc_edns_field_size(struct edns_data* edns)
809 {
810 	size_t rdatalen = 0;
811 	struct edns_option* opt;
812 	if(!edns || !edns->edns_present)
813 		return 0;
814 	for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
815 		rdatalen += 4 + opt->opt_len;
816 	}
817 	for(opt = edns->opt_list_out; opt; opt = opt->next) {
818 		rdatalen += 4 + opt->opt_len;
819 	}
820 	/* domain root '.' + type + class + ttl + rdatalen */
821 	return 1 + 2 + 2 + 4 + 2 + rdatalen;
822 }
823 
824 uint16_t
calc_edns_option_size(struct edns_data * edns,uint16_t code)825 calc_edns_option_size(struct edns_data* edns, uint16_t code)
826 {
827 	size_t rdatalen = 0;
828 	struct edns_option* opt;
829 	if(!edns || !edns->edns_present)
830 		return 0;
831 	for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
832 		if(opt->opt_code == code)
833 			rdatalen += 4 + opt->opt_len;
834 	}
835 	for(opt = edns->opt_list_out; opt; opt = opt->next) {
836 		if(opt->opt_code == code)
837 			rdatalen += 4 + opt->opt_len;
838 	}
839 	return rdatalen;
840 }
841 
842 uint16_t
calc_ede_option_size(struct edns_data * edns,uint16_t * txt_size)843 calc_ede_option_size(struct edns_data* edns, uint16_t* txt_size)
844 {
845 	size_t rdatalen = 0;
846 	struct edns_option* opt;
847 	*txt_size = 0;
848 	if(!edns || !edns->edns_present)
849 		return 0;
850 	for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) {
851 		if(opt->opt_code == LDNS_EDNS_EDE) {
852 			rdatalen += 4 + opt->opt_len;
853 			if(opt->opt_len > 2) *txt_size += opt->opt_len - 2;
854 			if(opt->opt_len >= 2 && sldns_read_uint16(
855 				opt->opt_data) == LDNS_EDE_OTHER) {
856 				*txt_size += 4 + 2;
857 			}
858 		}
859 	}
860 	for(opt = edns->opt_list_out; opt; opt = opt->next) {
861 		if(opt->opt_code == LDNS_EDNS_EDE) {
862 			rdatalen += 4 + opt->opt_len;
863 			if(opt->opt_len > 2) *txt_size += opt->opt_len - 2;
864 			if(opt->opt_len >= 2 && sldns_read_uint16(
865 				opt->opt_data) == LDNS_EDE_OTHER) {
866 				*txt_size += 4 + 2;
867 			}
868 		}
869 	}
870 	return rdatalen;
871 }
872 
873 /* Trims the EDE OPTION-DATA to not include any EXTRA-TEXT data.
874  * Also removes any LDNS_EDE_OTHER options from the list since they are useless
875  * without the extra text. */
876 static void
ede_trim_text(struct edns_option ** list)877 ede_trim_text(struct edns_option** list)
878 {
879 	struct edns_option* curr, *prev = NULL;
880 	if(!list || !(*list)) return;
881 	/* Unlink and repoint if LDNS_EDE_OTHER are first in list */
882 	while(list && *list && (*list)->opt_code == LDNS_EDNS_EDE
883 		&& (*list)->opt_len >= 2
884 		&& sldns_read_uint16((*list)->opt_data) == LDNS_EDE_OTHER ) {
885 		*list = (*list)->next;
886 	}
887 	if(!list || !(*list)) return;
888 	curr = *list;
889 	while(curr) {
890 		if(curr->opt_code == LDNS_EDNS_EDE) {
891 			if(curr->opt_len >= 2 && sldns_read_uint16(
892 				curr->opt_data) == LDNS_EDE_OTHER) {
893 				/* LDNS_EDE_OTHER cannot be the first option in
894 				 * this while, so prev is always initialized at
895 				 * this point from the other branches;
896 				 * cut this option off */
897 				prev->next = curr->next;
898 				curr = curr->next;
899 			} else if(curr->opt_len > 2) {
900 				/* trim this option's EXTRA-TEXT */
901 				curr->opt_len = 2;
902 				prev = curr;
903 				curr = curr->next;
904 			} else {
905 				prev = curr;
906 				curr = curr->next;
907 			}
908 		} else {
909 			/* continue */
910 			prev = curr;
911 			curr = curr->next;
912 		}
913 	}
914 }
915 
916 static void
attach_edns_record_max_msg_sz(sldns_buffer * pkt,struct edns_data * edns,uint16_t max_msg_sz)917 attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns,
918 	uint16_t max_msg_sz)
919 {
920 	size_t len;
921 	size_t rdatapos;
922 	struct edns_option* opt;
923 	struct edns_option* padding_option = NULL;
924 	/* inc additional count */
925 	sldns_buffer_write_u16_at(pkt, 10,
926 		sldns_buffer_read_u16_at(pkt, 10) + 1);
927 	len = sldns_buffer_limit(pkt);
928 	sldns_buffer_clear(pkt);
929 	sldns_buffer_set_position(pkt, len);
930 	/* write EDNS record */
931 	sldns_buffer_write_u8(pkt, 0); /* '.' label */
932 	sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
933 	sldns_buffer_write_u16(pkt, edns->udp_size); /* class */
934 	sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
935 	sldns_buffer_write_u8(pkt, edns->edns_version);
936 	sldns_buffer_write_u16(pkt, edns->bits);
937 	rdatapos = sldns_buffer_position(pkt);
938 	sldns_buffer_write_u16(pkt, 0); /* rdatalen */
939 	/* write rdata */
940 	for(opt=edns->opt_list_inplace_cb_out; opt; opt=opt->next) {
941 		if (opt->opt_code == LDNS_EDNS_PADDING) {
942 			padding_option = opt;
943 			continue;
944 		}
945 		sldns_buffer_write_u16(pkt, opt->opt_code);
946 		sldns_buffer_write_u16(pkt, opt->opt_len);
947 		if(opt->opt_len != 0)
948 			sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
949 	}
950 	for(opt=edns->opt_list_out; opt; opt=opt->next) {
951 		if (opt->opt_code == LDNS_EDNS_PADDING) {
952 			padding_option = opt;
953 			continue;
954 		}
955 		sldns_buffer_write_u16(pkt, opt->opt_code);
956 		sldns_buffer_write_u16(pkt, opt->opt_len);
957 		if(opt->opt_len != 0)
958 			sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
959 	}
960 	if (padding_option && edns->padding_block_size ) {
961 		size_t pad_pos = sldns_buffer_position(pkt);
962 		size_t msg_sz = ((pad_pos + 3) / edns->padding_block_size + 1)
963 		                               * edns->padding_block_size;
964 		size_t pad_sz;
965 
966 		if (msg_sz > max_msg_sz)
967 			msg_sz = max_msg_sz;
968 
969 		/* By use of calc_edns_field_size, calling functions should
970 		 * have made sure that there is enough space for at least a
971 		 * zero sized padding option.
972 		 */
973 		log_assert(pad_pos + 4 <= msg_sz);
974 
975 		pad_sz = msg_sz - pad_pos - 4;
976 		sldns_buffer_write_u16(pkt, LDNS_EDNS_PADDING);
977 		sldns_buffer_write_u16(pkt, pad_sz);
978 		if (pad_sz) {
979 			memset(sldns_buffer_current(pkt), 0, pad_sz);
980 			sldns_buffer_skip(pkt, pad_sz);
981 		}
982 	}
983 	sldns_buffer_write_u16_at(pkt, rdatapos,
984 			sldns_buffer_position(pkt)-rdatapos-2);
985 	sldns_buffer_flip(pkt);
986 }
987 
988 void
attach_edns_record(sldns_buffer * pkt,struct edns_data * edns)989 attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
990 {
991 	if(!edns || !edns->edns_present)
992 		return;
993 	attach_edns_record_max_msg_sz(pkt, edns, edns->udp_size);
994 }
995 
996 int
reply_info_answer_encode(struct query_info * qinf,struct reply_info * rep,uint16_t id,uint16_t qflags,sldns_buffer * pkt,time_t timenow,int cached,struct regional * region,uint16_t udpsize,struct edns_data * edns,int dnssec,int secure)997 reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
998 	uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow,
999 	int cached, struct regional* region, uint16_t udpsize,
1000 	struct edns_data* edns, int dnssec, int secure)
1001 {
1002 	uint16_t flags;
1003 	unsigned int attach_edns = 0;
1004 	uint16_t edns_field_size, ede_size, ede_txt_size;
1005 
1006 	if(!cached || rep->authoritative) {
1007 		/* original flags, copy RD and CD bits from query. */
1008 		flags = rep->flags | (qflags & (BIT_RD|BIT_CD));
1009 	} else {
1010 		/* remove AA bit, copy RD and CD bits from query. */
1011 		flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD));
1012 	}
1013 	if(secure && (dnssec || (qflags&BIT_AD)))
1014 		flags |= BIT_AD;
1015 	/* restore AA bit if we have a local alias and the response can be
1016 	 * authoritative.  Also clear AD bit if set as the local data is the
1017 	 * primary answer. */
1018 	if(qinf->local_alias &&
1019 		(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR ||
1020 		FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)) {
1021 		flags |= BIT_AA;
1022 		flags &= ~BIT_AD;
1023 	}
1024 	log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
1025 	if(udpsize < LDNS_HEADER_SIZE)
1026 		return 0;
1027 	/* currently edns does not change during calculations;
1028 	 * calculate sizes once here */
1029 	edns_field_size = calc_edns_field_size(edns);
1030 	ede_size = calc_ede_option_size(edns, &ede_txt_size);
1031 	if(sldns_buffer_capacity(pkt) < udpsize)
1032 		udpsize = sldns_buffer_capacity(pkt);
1033 	if(!edns || !edns->edns_present) {
1034 		attach_edns = 0;
1035 	/* EDEs are optional, try to fit anything else before them */
1036 	} else if(udpsize < LDNS_HEADER_SIZE + edns_field_size - ede_size) {
1037 		/* packet too small to contain edns, omit it. */
1038 		attach_edns = 0;
1039 	} else {
1040 		/* reserve space for edns record */
1041 		attach_edns = (unsigned int)edns_field_size - ede_size;
1042 	}
1043 
1044 	if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
1045 		udpsize - attach_edns, dnssec, MINIMAL_RESPONSES)) {
1046 		log_err("reply encode: out of memory");
1047 		return 0;
1048 	}
1049 	if(attach_edns) {
1050 		if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size)
1051 			attach_edns_record_max_msg_sz(pkt, edns, udpsize);
1052 		else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_txt_size) {
1053 			ede_trim_text(&edns->opt_list_inplace_cb_out);
1054 			ede_trim_text(&edns->opt_list_out);
1055 			attach_edns_record_max_msg_sz(pkt, edns, udpsize);
1056 		} else if(udpsize >= sldns_buffer_limit(pkt) + edns_field_size - ede_size) {
1057 			edns_opt_list_remove(&edns->opt_list_inplace_cb_out, LDNS_EDNS_EDE);
1058 			edns_opt_list_remove(&edns->opt_list_out, LDNS_EDNS_EDE);
1059 			attach_edns_record_max_msg_sz(pkt, edns, udpsize);
1060 		}
1061 	}
1062 	return 1;
1063 }
1064 
1065 void
qinfo_query_encode(sldns_buffer * pkt,struct query_info * qinfo)1066 qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo)
1067 {
1068 	uint16_t flags = 0; /* QUERY, NOERROR */
1069 	const uint8_t* qname = qinfo->local_alias ?
1070 		qinfo->local_alias->rrset->rk.dname : qinfo->qname;
1071 	size_t qname_len = qinfo->local_alias ?
1072 		qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len;
1073 	sldns_buffer_clear(pkt);
1074 	log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
1075 	sldns_buffer_skip(pkt, 2); /* id done later */
1076 	sldns_buffer_write_u16(pkt, flags);
1077 	sldns_buffer_write_u16(pkt, 1); /* query count */
1078 	sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
1079 	sldns_buffer_write(pkt, qname, qname_len);
1080 	sldns_buffer_write_u16(pkt, qinfo->qtype);
1081 	sldns_buffer_write_u16(pkt, qinfo->qclass);
1082 	sldns_buffer_flip(pkt);
1083 }
1084 
1085 void
extended_error_encode(sldns_buffer * buf,uint16_t rcode,struct query_info * qinfo,uint16_t qid,uint16_t qflags,uint16_t xflags,struct edns_data * edns)1086 extended_error_encode(sldns_buffer* buf, uint16_t rcode,
1087 	struct query_info* qinfo, uint16_t qid, uint16_t qflags,
1088 	uint16_t xflags, struct edns_data* edns)
1089 {
1090 	uint16_t flags;
1091 
1092 	sldns_buffer_clear(buf);
1093 	sldns_buffer_write(buf, &qid, sizeof(uint16_t));
1094 	flags = (uint16_t)(BIT_QR | BIT_RA | (rcode & 0xF)); /* QR and retcode*/
1095 	flags |= xflags;
1096 	flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
1097 	sldns_buffer_write_u16(buf, flags);
1098 	if(qinfo) flags = 1;
1099 	else	flags = 0;
1100 	sldns_buffer_write_u16(buf, flags);
1101 	flags = 0;
1102 	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
1103 	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
1104 	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
1105 	if(qinfo) {
1106 		const uint8_t* qname = qinfo->local_alias ?
1107 			qinfo->local_alias->rrset->rk.dname : qinfo->qname;
1108 		size_t qname_len = qinfo->local_alias ?
1109 			qinfo->local_alias->rrset->rk.dname_len :
1110 			qinfo->qname_len;
1111 		if(sldns_buffer_current(buf) == qname)
1112 			sldns_buffer_skip(buf, (ssize_t)qname_len);
1113 		else	sldns_buffer_write(buf, qname, qname_len);
1114 		sldns_buffer_write_u16(buf, qinfo->qtype);
1115 		sldns_buffer_write_u16(buf, qinfo->qclass);
1116 	}
1117 	sldns_buffer_flip(buf);
1118 	if(edns) {
1119 		struct edns_data es = *edns;
1120 		es.edns_version = EDNS_ADVERTISED_VERSION;
1121 		es.udp_size = EDNS_ADVERTISED_SIZE;
1122 		es.ext_rcode = (uint8_t)(rcode >> 4);
1123 		es.bits &= EDNS_DO;
1124 		if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
1125 			edns->udp_size) {
1126 			edns_opt_list_remove(&es.opt_list_inplace_cb_out, LDNS_EDNS_EDE);
1127 			edns_opt_list_remove(&es.opt_list_out, LDNS_EDNS_EDE);
1128 			if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
1129 				edns->udp_size) {
1130 				return;
1131 			}
1132 		}
1133 		attach_edns_record(buf, &es);
1134 	}
1135 }
1136 
1137 void
error_encode(sldns_buffer * buf,int r,struct query_info * qinfo,uint16_t qid,uint16_t qflags,struct edns_data * edns)1138 error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
1139 	uint16_t qid, uint16_t qflags, struct edns_data* edns)
1140 {
1141 	extended_error_encode(buf, (r & 0x000F), qinfo, qid, qflags,
1142 		(r & 0xFFF0), edns);
1143 }
1144