xref: /openbsd/usr.bin/dig/lib/dns/message.c (revision 097a140d)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: message.c,v 1.18 2020/11/01 07:12:14 florian Exp $ */
18 
19 /*! \file */
20 
21 /***
22  *** Imports
23  ***/
24 
25 #include <sys/socket.h>
26 #include <arpa/inet.h>
27 
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include <isc/buffer.h>
33 #include <isc/util.h>
34 
35 #include <dns/log.h>
36 #include <dns/masterdump.h>
37 #include <dns/message.h>
38 #include <dns/rdata.h>
39 #include <dns/rdatalist.h>
40 #include <dns/rdataset.h>
41 #include <dns/result.h>
42 #include <dns/tsig.h>
43 #include <dns/ttl.h>
44 
45 #define DNS_MESSAGE_OPCODE_MASK		0x7800U
46 #define DNS_MESSAGE_OPCODE_SHIFT	11
47 #define DNS_MESSAGE_RCODE_MASK		0x000fU
48 #define DNS_MESSAGE_FLAG_MASK		0x8ff0U
49 #define DNS_MESSAGE_EDNSRCODE_MASK	0xff000000U
50 
51 #define VALID_NAMED_SECTION(s)  (((s) > DNS_SECTION_ANY) \
52 				 && ((s) < DNS_SECTION_MAX))
53 #define VALID_SECTION(s)	(((s) >= DNS_SECTION_ANY) \
54 				 && ((s) < DNS_SECTION_MAX))
55 #define ADD_STRING(b, s)	{if (strlen(s) >= \
56 				   isc_buffer_availablelength(b)) \
57 				       return(ISC_R_NOSPACE); else \
58 				       isc_buffer_putstr(b, s);}
59 #define VALID_PSEUDOSECTION(s)	(((s) >= DNS_PSEUDOSECTION_ANY) \
60 				 && ((s) < DNS_PSEUDOSECTION_MAX))
61 
62 #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
63 
64 /*%
65  * This is the size of each individual scratchpad buffer, and the numbers
66  * of various block allocations used within the server.
67  * XXXMLG These should come from a config setting.
68  */
69 #define SCRATCHPAD_SIZE		512
70 #define OFFSET_COUNT		  4
71 #define RDATA_COUNT		  8
72 #define RDATALIST_COUNT		  8
73 
74 /*%
75  * Text representation of the different items, for message_totext
76  * functions.
77  */
78 static const char *sectiontext[] = {
79 	"QUESTION",
80 	"ANSWER",
81 	"AUTHORITY",
82 	"ADDITIONAL"
83 };
84 
85 static const char *updsectiontext[] = {
86 	"ZONE",
87 	"PREREQUISITE",
88 	"UPDATE",
89 	"ADDITIONAL"
90 };
91 
92 /*%
93  * "helper" type, which consists of a block of some type, and is linkable.
94  * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
95  * size, or the allocated elements will not be aligned correctly.
96  */
97 struct dns_msgblock {
98 	unsigned int			count;
99 	unsigned int			remaining;
100 	ISC_LINK(dns_msgblock_t)	link;
101 }; /* dynamically sized */
102 
103 static inline dns_msgblock_t *
104 msgblock_allocate(unsigned int, unsigned int);
105 
106 #define msgblock_get(block, type) \
107 	((type *)msgblock_internalget(block, sizeof(type)))
108 
109 static inline void *
110 msgblock_internalget(dns_msgblock_t *, unsigned int);
111 
112 static inline void
113 msgblock_reset(dns_msgblock_t *);
114 
115 /*
116  * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
117  * is free, return NULL.
118  */
119 static inline dns_msgblock_t *
120 msgblock_allocate(unsigned int sizeof_type,
121 		  unsigned int count)
122 {
123 	dns_msgblock_t *block;
124 	unsigned int length;
125 
126 	length = sizeof(dns_msgblock_t) + (sizeof_type * count);
127 
128 	block = malloc(length);
129 	if (block == NULL)
130 		return (NULL);
131 
132 	block->count = count;
133 	block->remaining = count;
134 
135 	ISC_LINK_INIT(block, link);
136 
137 	return (block);
138 }
139 
140 /*
141  * Return an element from the msgblock.  If no more are available, return
142  * NULL.
143  */
144 static inline void *
145 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
146 	void *ptr;
147 
148 	if (block == NULL || block->remaining == 0)
149 		return (NULL);
150 
151 	block->remaining--;
152 
153 	ptr = (((unsigned char *)block)
154 	       + sizeof(dns_msgblock_t)
155 	       + (sizeof_type * block->remaining));
156 
157 	return (ptr);
158 }
159 
160 static inline void
161 msgblock_reset(dns_msgblock_t *block) {
162 	block->remaining = block->count;
163 }
164 
165 /*
166  * Allocate a new dynamic buffer, and attach it to this message as the
167  * "current" buffer.  (which is always the last on the list, for our
168  * uses)
169  */
170 static inline isc_result_t
171 newbuffer(dns_message_t *msg, unsigned int size) {
172 	isc_result_t result;
173 	isc_buffer_t *dynbuf;
174 
175 	dynbuf = NULL;
176 	result = isc_buffer_allocate(&dynbuf, size);
177 	if (result != ISC_R_SUCCESS)
178 		return (ISC_R_NOMEMORY);
179 
180 	ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
181 	return (ISC_R_SUCCESS);
182 }
183 
184 static inline isc_buffer_t *
185 currentbuffer(dns_message_t *msg) {
186 	isc_buffer_t *dynbuf;
187 
188 	dynbuf = ISC_LIST_TAIL(msg->scratchpad);
189 	INSIST(dynbuf != NULL);
190 
191 	return (dynbuf);
192 }
193 
194 static inline void
195 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
196 	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
197 }
198 
199 static inline dns_rdata_t *
200 newrdata(dns_message_t *msg) {
201 	dns_msgblock_t *msgblock;
202 	dns_rdata_t *rdata;
203 
204 	rdata = ISC_LIST_HEAD(msg->freerdata);
205 	if (rdata != NULL) {
206 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
207 		return (rdata);
208 	}
209 
210 	msgblock = ISC_LIST_TAIL(msg->rdatas);
211 	rdata = msgblock_get(msgblock, dns_rdata_t);
212 	if (rdata == NULL) {
213 		msgblock = msgblock_allocate(sizeof(dns_rdata_t), RDATA_COUNT);
214 		if (msgblock == NULL)
215 			return (NULL);
216 
217 		ISC_LIST_APPEND(msg->rdatas, msgblock, link);
218 
219 		rdata = msgblock_get(msgblock, dns_rdata_t);
220 	}
221 
222 	dns_rdata_init(rdata);
223 	return (rdata);
224 }
225 
226 static inline void
227 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
228 	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
229 }
230 
231 static inline dns_rdatalist_t *
232 newrdatalist(dns_message_t *msg) {
233 	dns_msgblock_t *msgblock;
234 	dns_rdatalist_t *rdatalist;
235 
236 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
237 	if (rdatalist != NULL) {
238 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
239 		goto out;
240 	}
241 
242 	msgblock = ISC_LIST_TAIL(msg->rdatalists);
243 	rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
244 	if (rdatalist == NULL) {
245 		msgblock = msgblock_allocate(sizeof(dns_rdatalist_t),
246 					     RDATALIST_COUNT);
247 		if (msgblock == NULL)
248 			return (NULL);
249 
250 		ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
251 
252 		rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
253 	}
254  out:
255 	if (rdatalist != NULL)
256 		dns_rdatalist_init(rdatalist);
257 
258 	return (rdatalist);
259 }
260 
261 static inline dns_offsets_t *
262 newoffsets(dns_message_t *msg) {
263 	dns_msgblock_t *msgblock;
264 	dns_offsets_t *offsets;
265 
266 	msgblock = ISC_LIST_TAIL(msg->offsets);
267 	offsets = msgblock_get(msgblock, dns_offsets_t);
268 	if (offsets == NULL) {
269 		msgblock = msgblock_allocate(sizeof(dns_offsets_t),
270 					     OFFSET_COUNT);
271 		if (msgblock == NULL)
272 			return (NULL);
273 
274 		ISC_LIST_APPEND(msg->offsets, msgblock, link);
275 
276 		offsets = msgblock_get(msgblock, dns_offsets_t);
277 	}
278 
279 	return (offsets);
280 }
281 
282 static inline void
283 msginitheader(dns_message_t *m) {
284 	m->id = 0;
285 	m->flags = 0;
286 	m->rcode = 0;
287 	m->opcode = 0;
288 	m->rdclass = 0;
289 }
290 
291 static inline void
292 msginitprivate(dns_message_t *m) {
293 	unsigned int i;
294 
295 	for (i = 0; i < DNS_SECTION_MAX; i++) {
296 		m->cursors[i] = NULL;
297 		m->counts[i] = 0;
298 	}
299 	m->opt = NULL;
300 	m->sig0 = NULL;
301 	m->sig0name = NULL;
302 	m->tsig = NULL;
303 	m->tsigname = NULL;
304 	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
305 	m->opt_reserved = 0;
306 	m->sig_reserved = 0;
307 	m->reserved = 0;
308 	m->buffer = NULL;
309 }
310 
311 static inline void
312 msginittsig(dns_message_t *m) {
313 	m->tsigstatus = dns_rcode_noerror;
314 	m->querytsigstatus = dns_rcode_noerror;
315 	m->tsigkey = NULL;
316 	m->tsigctx = NULL;
317 	m->sigstart = -1;
318 	m->sig0status = dns_rcode_noerror;
319 	m->timeadjust = 0;
320 }
321 
322 /*
323  * Init elements to default state.  Used both when allocating a new element
324  * and when resetting one.
325  */
326 static inline void
327 msginit(dns_message_t *m) {
328 	msginitheader(m);
329 	msginitprivate(m);
330 	msginittsig(m);
331 	m->header_ok = 0;
332 	m->question_ok = 0;
333 	m->tcp_continuation = 0;
334 	m->verified_sig = 0;
335 	m->verify_attempted = 0;
336 	m->order = NULL;
337 	m->order_arg = NULL;
338 	m->query.base = NULL;
339 	m->query.length = 0;
340 	m->free_query = 0;
341 	m->saved.base = NULL;
342 	m->saved.length = 0;
343 	m->free_saved = 0;
344 	m->sitok = 0;
345 	m->sitbad = 0;
346 	m->tkey = 0;
347 	m->rdclass_set = 0;
348 	m->querytsig = NULL;
349 }
350 
351 static inline void
352 msgresetnames(dns_message_t *msg, unsigned int first_section) {
353 	unsigned int i;
354 	dns_name_t *name, *next_name;
355 	dns_rdataset_t *rds, *next_rds;
356 
357 	/*
358 	 * Clean up name lists by calling the rdataset disassociate function.
359 	 */
360 	for (i = first_section; i < DNS_SECTION_MAX; i++) {
361 		name = ISC_LIST_HEAD(msg->sections[i]);
362 		while (name != NULL) {
363 			next_name = ISC_LIST_NEXT(name, link);
364 			ISC_LIST_UNLINK(msg->sections[i], name, link);
365 
366 			rds = ISC_LIST_HEAD(name->list);
367 			while (rds != NULL) {
368 				next_rds = ISC_LIST_NEXT(rds, link);
369 				ISC_LIST_UNLINK(name->list, rds, link);
370 
371 				INSIST(dns_rdataset_isassociated(rds));
372 				dns_rdataset_disassociate(rds);
373 				free(rds);
374 				rds = next_rds;
375 			}
376 			if (dns_name_dynamic(name))
377 				dns_name_free(name);
378 			free(name);
379 			name = next_name;
380 		}
381 	}
382 }
383 
384 static void
385 msgresetopt(dns_message_t *msg)
386 {
387 	if (msg->opt != NULL) {
388 		if (msg->opt_reserved > 0) {
389 			dns_message_renderrelease(msg, msg->opt_reserved);
390 			msg->opt_reserved = 0;
391 		}
392 		INSIST(dns_rdataset_isassociated(msg->opt));
393 		dns_rdataset_disassociate(msg->opt);
394 		free(msg->opt);
395 		msg->opt = NULL;
396 		msg->sitok = 0;
397 		msg->sitbad = 0;
398 	}
399 }
400 
401 static void
402 msgresetsigs(dns_message_t *msg, int replying) {
403 	if (msg->sig_reserved > 0) {
404 		dns_message_renderrelease(msg, msg->sig_reserved);
405 		msg->sig_reserved = 0;
406 	}
407 	if (msg->tsig != NULL) {
408 		INSIST(dns_rdataset_isassociated(msg->tsig));
409 		if (replying) {
410 			INSIST(msg->querytsig == NULL);
411 			msg->querytsig = msg->tsig;
412 		} else {
413 			dns_rdataset_disassociate(msg->tsig);
414 			free(msg->tsig);
415 			if (msg->querytsig != NULL) {
416 				dns_rdataset_disassociate(msg->querytsig);
417 				free(msg->querytsig);
418 			}
419 		}
420 		if (dns_name_dynamic(msg->tsigname))
421 			dns_name_free(msg->tsigname);
422 		free(msg->tsigname);
423 		msg->tsig = NULL;
424 		msg->tsigname = NULL;
425 	} else if (msg->querytsig != NULL && !replying) {
426 		dns_rdataset_disassociate(msg->querytsig);
427 		free(msg->querytsig);
428 		msg->querytsig = NULL;
429 	}
430 	if (msg->sig0 != NULL) {
431 		INSIST(dns_rdataset_isassociated(msg->sig0));
432 		dns_rdataset_disassociate(msg->sig0);
433 		free(msg->sig0);
434 		if (msg->sig0name != NULL) {
435 			if (dns_name_dynamic(msg->sig0name))
436 				dns_name_free(msg->sig0name);
437 			free(msg->sig0name);
438 		}
439 		msg->sig0 = NULL;
440 		msg->sig0name = NULL;
441 	}
442 }
443 
444 /*
445  * Free all but one (or everything) for this message.  This is used by
446  * both dns_message_reset() and dns_message_destroy().
447  */
448 static void
449 msgreset(dns_message_t *msg, int everything) {
450 	dns_msgblock_t *msgblock, *next_msgblock;
451 	isc_buffer_t *dynbuf, *next_dynbuf;
452 	dns_rdata_t *rdata;
453 	dns_rdatalist_t *rdatalist;
454 
455 	msgresetnames(msg, 0);
456 	msgresetopt(msg);
457 	msgresetsigs(msg, 0);
458 
459 	/*
460 	 * Clean up linked lists.
461 	 */
462 
463 	/*
464 	 * Run through the free lists, and just unlink anything found there.
465 	 * The memory isn't lost since these are part of message blocks we
466 	 * have allocated.
467 	 */
468 	rdata = ISC_LIST_HEAD(msg->freerdata);
469 	while (rdata != NULL) {
470 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
471 		rdata = ISC_LIST_HEAD(msg->freerdata);
472 	}
473 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
474 	while (rdatalist != NULL) {
475 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
476 		rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
477 	}
478 
479 	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
480 	INSIST(dynbuf != NULL);
481 	if (!everything) {
482 		isc_buffer_clear(dynbuf);
483 		dynbuf = ISC_LIST_NEXT(dynbuf, link);
484 	}
485 	while (dynbuf != NULL) {
486 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
487 		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
488 		isc_buffer_free(&dynbuf);
489 		dynbuf = next_dynbuf;
490 	}
491 
492 	msgblock = ISC_LIST_HEAD(msg->rdatas);
493 	if (!everything && msgblock != NULL) {
494 		msgblock_reset(msgblock);
495 		msgblock = ISC_LIST_NEXT(msgblock, link);
496 	}
497 	while (msgblock != NULL) {
498 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
499 		ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
500 		free(msgblock);
501 		msgblock = next_msgblock;
502 	}
503 
504 	/*
505 	 * rdatalists could be empty.
506 	 */
507 
508 	msgblock = ISC_LIST_HEAD(msg->rdatalists);
509 	if (!everything && msgblock != NULL) {
510 		msgblock_reset(msgblock);
511 		msgblock = ISC_LIST_NEXT(msgblock, link);
512 	}
513 	while (msgblock != NULL) {
514 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
515 		ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
516 		free(msgblock);
517 		msgblock = next_msgblock;
518 	}
519 
520 	msgblock = ISC_LIST_HEAD(msg->offsets);
521 	if (!everything && msgblock != NULL) {
522 		msgblock_reset(msgblock);
523 		msgblock = ISC_LIST_NEXT(msgblock, link);
524 	}
525 	while (msgblock != NULL) {
526 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
527 		ISC_LIST_UNLINK(msg->offsets, msgblock, link);
528 		free(msgblock);
529 		msgblock = next_msgblock;
530 	}
531 
532 	if (msg->tsigkey != NULL) {
533 		dns_tsigkey_detach(&msg->tsigkey);
534 		msg->tsigkey = NULL;
535 	}
536 
537 	if (msg->tsigctx != NULL)
538 		dst_context_destroy(&msg->tsigctx);
539 
540 	if (msg->query.base != NULL) {
541 		if (msg->free_query != 0)
542 			free(msg->query.base);
543 		msg->query.base = NULL;
544 		msg->query.length = 0;
545 	}
546 
547 	if (msg->saved.base != NULL) {
548 		if (msg->free_saved != 0)
549 			free(msg->saved.base);
550 		msg->saved.base = NULL;
551 		msg->saved.length = 0;
552 	}
553 
554 	/*
555 	 * cleanup the buffer cleanup list
556 	 */
557 	dynbuf = ISC_LIST_HEAD(msg->cleanup);
558 	while (dynbuf != NULL) {
559 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
560 		ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
561 		isc_buffer_free(&dynbuf);
562 		dynbuf = next_dynbuf;
563 	}
564 
565 	/*
566 	 * Set other bits to normal default values.
567 	 */
568 	if (!everything)
569 		msginit(msg);
570 }
571 
572 static unsigned int
573 spacefortsig(dns_tsigkey_t *key, int otherlen) {
574 	isc_region_t r1, r2;
575 	unsigned int x;
576 	isc_result_t result;
577 
578 	/*
579 	 * The space required for an TSIG record is:
580 	 *
581 	 *	n1 bytes for the name
582 	 *	2 bytes for the type
583 	 *	2 bytes for the class
584 	 *	4 bytes for the ttl
585 	 *	2 bytes for the rdlength
586 	 *	n2 bytes for the algorithm name
587 	 *	6 bytes for the time signed
588 	 *	2 bytes for the fudge
589 	 *	2 bytes for the MAC size
590 	 *	x bytes for the MAC
591 	 *	2 bytes for the original id
592 	 *	2 bytes for the error
593 	 *	2 bytes for the other data length
594 	 *	y bytes for the other data (at most)
595 	 * ---------------------------------
596 	 *     26 + n1 + n2 + x + y bytes
597 	 */
598 
599 	dns_name_toregion(&key->name, &r1);
600 	dns_name_toregion(key->algorithm, &r2);
601 	if (key->key == NULL)
602 		x = 0;
603 	else {
604 		result = dst_key_sigsize(key->key, &x);
605 		if (result != ISC_R_SUCCESS)
606 			x = 0;
607 	}
608 	return (26 + r1.length + r2.length + x + otherlen);
609 }
610 
611 isc_result_t
612 dns_message_create(unsigned int intent, dns_message_t **msgp)
613 {
614 	dns_message_t *m;
615 	isc_result_t result;
616 	isc_buffer_t *dynbuf;
617 	unsigned int i;
618 
619 	REQUIRE(msgp != NULL);
620 	REQUIRE(*msgp == NULL);
621 	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
622 		|| intent == DNS_MESSAGE_INTENTRENDER);
623 
624 	m = malloc(sizeof(dns_message_t));
625 	if (m == NULL)
626 		return (ISC_R_NOMEMORY);
627 
628 	/*
629 	 * No allocations until further notice.  Just initialize all lists
630 	 * and other members that are freed in the cleanup phase here.
631 	 */
632 
633 	m->from_to_wire = intent;
634 	msginit(m);
635 
636 	for (i = 0; i < DNS_SECTION_MAX; i++)
637 		ISC_LIST_INIT(m->sections[i]);
638 
639 	ISC_LIST_INIT(m->scratchpad);
640 	ISC_LIST_INIT(m->cleanup);
641 	ISC_LIST_INIT(m->rdatas);
642 	ISC_LIST_INIT(m->rdatalists);
643 	ISC_LIST_INIT(m->offsets);
644 	ISC_LIST_INIT(m->freerdata);
645 	ISC_LIST_INIT(m->freerdatalist);
646 
647 	/*
648 	 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
649 	 */
650 
651 	dynbuf = NULL;
652 	result = isc_buffer_allocate(&dynbuf, SCRATCHPAD_SIZE);
653 	if (result != ISC_R_SUCCESS)
654 		goto cleanup;
655 	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
656 
657 	m->cctx = NULL;
658 
659 	*msgp = m;
660 	return (ISC_R_SUCCESS);
661 
662 	/*
663 	 * Cleanup for error returns.
664 	 */
665  cleanup:
666 	dynbuf = ISC_LIST_HEAD(m->scratchpad);
667 	if (dynbuf != NULL) {
668 		ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
669 		isc_buffer_free(&dynbuf);
670 	}
671 	free(m);
672 
673 	return (ISC_R_NOMEMORY);
674 }
675 
676 void
677 dns_message_destroy(dns_message_t **msgp) {
678 	dns_message_t *msg;
679 
680 	REQUIRE(msgp != NULL);
681 
682 	msg = *msgp;
683 	*msgp = NULL;
684 
685 	msgreset(msg, 1);
686 	free(msg);
687 }
688 
689 static isc_result_t
690 findname(dns_name_t **foundname, dns_name_t *target,
691 	 dns_namelist_t *section)
692 {
693 	dns_name_t *curr;
694 
695 	for (curr = ISC_LIST_TAIL(*section);
696 	     curr != NULL;
697 	     curr = ISC_LIST_PREV(curr, link)) {
698 		if (dns_name_equal(curr, target)) {
699 			if (foundname != NULL)
700 				*foundname = curr;
701 			return (ISC_R_SUCCESS);
702 		}
703 	}
704 
705 	return (ISC_R_NOTFOUND);
706 }
707 
708 isc_result_t
709 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
710 		 dns_rdatatype_t type, dns_rdatatype_t covers,
711 		 dns_rdataset_t **rdataset)
712 {
713 	dns_rdataset_t *curr;
714 
715 	REQUIRE(name != NULL);
716 	REQUIRE(rdataset == NULL || *rdataset == NULL);
717 
718 	for (curr = ISC_LIST_TAIL(name->list);
719 	     curr != NULL;
720 	     curr = ISC_LIST_PREV(curr, link)) {
721 		if (curr->rdclass == rdclass &&
722 		    curr->type == type && curr->covers == covers) {
723 			if (rdataset != NULL)
724 				*rdataset = curr;
725 			return (ISC_R_SUCCESS);
726 		}
727 	}
728 
729 	return (ISC_R_NOTFOUND);
730 }
731 
732 isc_result_t
733 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
734 		     dns_rdatatype_t covers, dns_rdataset_t **rdataset)
735 {
736 	dns_rdataset_t *curr;
737 
738 	REQUIRE(name != NULL);
739 	REQUIRE(rdataset == NULL || *rdataset == NULL);
740 
741 	for (curr = ISC_LIST_TAIL(name->list);
742 	     curr != NULL;
743 	     curr = ISC_LIST_PREV(curr, link)) {
744 		if (curr->type == type && curr->covers == covers) {
745 			if (rdataset != NULL)
746 				*rdataset = curr;
747 			return (ISC_R_SUCCESS);
748 		}
749 	}
750 
751 	return (ISC_R_NOTFOUND);
752 }
753 
754 /*
755  * Read a name from buffer "source".
756  */
757 static isc_result_t
758 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
759 	dns_decompress_t *dctx)
760 {
761 	isc_buffer_t *scratch;
762 	isc_result_t result;
763 	unsigned int tries;
764 
765 	scratch = currentbuffer(msg);
766 
767 	/*
768 	 * First try:  use current buffer.
769 	 * Second try:  allocate a new buffer and use that.
770 	 */
771 	tries = 0;
772 	while (tries < 2) {
773 		result = dns_name_fromwire(name, source, dctx, 0,
774 					   scratch);
775 
776 		if (result == ISC_R_NOSPACE) {
777 			tries++;
778 
779 			result = newbuffer(msg, SCRATCHPAD_SIZE);
780 			if (result != ISC_R_SUCCESS)
781 				return (result);
782 
783 			scratch = currentbuffer(msg);
784 			dns_name_reset(name);
785 		} else {
786 			return (result);
787 		}
788 	}
789 
790 	INSIST(0);  /* Cannot get here... */
791 	return (ISC_R_UNEXPECTED);
792 }
793 
794 static isc_result_t
795 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
796 	 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
797 	 unsigned int rdatalen, dns_rdata_t *rdata)
798 {
799 	isc_buffer_t *scratch;
800 	isc_result_t result;
801 	unsigned int tries;
802 	unsigned int trysize;
803 
804 	scratch = currentbuffer(msg);
805 
806 	isc_buffer_setactive(source, rdatalen);
807 
808 	/*
809 	 * First try:  use current buffer.
810 	 * Second try:  allocate a new buffer of size
811 	 *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
812 	 *     (the data will fit if it was not more than 50% compressed)
813 	 * Subsequent tries: double buffer size on each try.
814 	 */
815 	tries = 0;
816 	trysize = 0;
817 	/* XXX possibly change this to a while (tries < 2) loop */
818 	for (;;) {
819 		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
820 					    source, dctx, 0,
821 					    scratch);
822 
823 		if (result == ISC_R_NOSPACE) {
824 			if (tries == 0) {
825 				trysize = 2 * rdatalen;
826 				if (trysize < SCRATCHPAD_SIZE)
827 					trysize = SCRATCHPAD_SIZE;
828 			} else {
829 				INSIST(trysize != 0);
830 				if (trysize >= 65535)
831 					return (ISC_R_NOSPACE);
832 					/* XXX DNS_R_RRTOOLONG? */
833 				trysize *= 2;
834 			}
835 			tries++;
836 			result = newbuffer(msg, trysize);
837 			if (result != ISC_R_SUCCESS)
838 				return (result);
839 
840 			scratch = currentbuffer(msg);
841 		} else {
842 			return (result);
843 		}
844 	}
845 }
846 
847 #define DO_FORMERR					\
848 	do {						\
849 		if (best_effort)			\
850 			seen_problem = 1;	\
851 		else {					\
852 			result = DNS_R_FORMERR;		\
853 			goto cleanup;			\
854 		}					\
855 	} while (0)
856 
857 static isc_result_t
858 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
859 	     unsigned int options)
860 {
861 	isc_region_t r;
862 	unsigned int count;
863 	dns_name_t *name;
864 	dns_name_t *name2;
865 	dns_offsets_t *offsets;
866 	dns_rdataset_t *rdataset;
867 	dns_rdatalist_t *rdatalist;
868 	isc_result_t result;
869 	dns_rdatatype_t rdtype;
870 	dns_rdataclass_t rdclass;
871 	dns_namelist_t *section;
872 	int free_name;
873 	int best_effort;
874 	int seen_problem;
875 
876 	section = &msg->sections[DNS_SECTION_QUESTION];
877 
878 	best_effort = options & DNS_MESSAGEPARSE_BESTEFFORT;
879 	seen_problem = 0;
880 
881 	name = NULL;
882 	rdataset = NULL;
883 	rdatalist = NULL;
884 
885 	for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
886 		name = malloc(sizeof(dns_name_t));
887 		if (name == NULL)
888 			return (ISC_R_NOMEMORY);
889 		free_name = 1;
890 
891 		offsets = newoffsets(msg);
892 		if (offsets == NULL) {
893 			result = ISC_R_NOMEMORY;
894 			goto cleanup;
895 		}
896 		dns_name_init(name, *offsets);
897 
898 		/*
899 		 * Parse the name out of this packet.
900 		 */
901 		isc_buffer_remainingregion(source, &r);
902 		isc_buffer_setactive(source, r.length);
903 		result = getname(name, source, msg, dctx);
904 		if (result != ISC_R_SUCCESS)
905 			goto cleanup;
906 
907 		/*
908 		 * Run through the section, looking to see if this name
909 		 * is already there.  If it is found, put back the allocated
910 		 * name since we no longer need it, and set our name pointer
911 		 * to point to the name we found.
912 		 */
913 		result = findname(&name2, name, section);
914 
915 		/*
916 		 * If it is the first name in the section, accept it.
917 		 *
918 		 * If it is not, but is not the same as the name already
919 		 * in the question section, append to the section.  Note that
920 		 * here in the question section this is illegal, so return
921 		 * FORMERR.  In the future, check the opcode to see if
922 		 * this should be legal or not.  In either case we no longer
923 		 * need this name pointer.
924 		 */
925 		if (result != ISC_R_SUCCESS) {
926 			if (!ISC_LIST_EMPTY(*section))
927 				DO_FORMERR;
928 			ISC_LIST_APPEND(*section, name, link);
929 			free_name = 0;
930 		} else {
931 			free(name);
932 			name = name2;
933 			name2 = NULL;
934 			free_name = 0;
935 		}
936 
937 		/*
938 		 * Get type and class.
939 		 */
940 		isc_buffer_remainingregion(source, &r);
941 		if (r.length < 4) {
942 			result = ISC_R_UNEXPECTEDEND;
943 			goto cleanup;
944 		}
945 		rdtype = isc_buffer_getuint16(source);
946 		rdclass = isc_buffer_getuint16(source);
947 
948 		/*
949 		 * If this class is different than the one we already read,
950 		 * this is an error.
951 		 */
952 		if (msg->rdclass_set == 0) {
953 			msg->rdclass = rdclass;
954 			msg->rdclass_set = 1;
955 		} else if (msg->rdclass != rdclass)
956 			DO_FORMERR;
957 
958 		/*
959 		 * Is this a TKEY query?
960 		 */
961 		if (rdtype == dns_rdatatype_tkey)
962 			msg->tkey = 1;
963 
964 		/*
965 		 * Can't ask the same question twice.
966 		 */
967 		result = dns_message_find(name, rdclass, rdtype, 0, NULL);
968 		if (result == ISC_R_SUCCESS)
969 			DO_FORMERR;
970 
971 		/*
972 		 * Allocate a new rdatalist.
973 		 */
974 		rdatalist = newrdatalist(msg);
975 		if (rdatalist == NULL) {
976 			result = ISC_R_NOMEMORY;
977 			goto cleanup;
978 		}
979 		rdataset =  malloc(sizeof(dns_rdataset_t));
980 		if (rdataset == NULL) {
981 			result = ISC_R_NOMEMORY;
982 			goto cleanup;
983 		}
984 
985 		/*
986 		 * Convert rdatalist to rdataset, and attach the latter to
987 		 * the name.
988 		 */
989 		rdatalist->type = rdtype;
990 		rdatalist->covers = 0;
991 		rdatalist->rdclass = rdclass;
992 		rdatalist->ttl = 0;
993 		ISC_LIST_INIT(rdatalist->rdata);
994 
995 		dns_rdataset_init(rdataset);
996 		result = dns_rdatalist_tordataset(rdatalist, rdataset);
997 		if (result != ISC_R_SUCCESS)
998 			goto cleanup;
999 
1000 		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1001 
1002 		ISC_LIST_APPEND(name->list, rdataset, link);
1003 		rdataset = NULL;
1004 	}
1005 
1006 	if (seen_problem)
1007 		return (DNS_R_RECOVERABLE);
1008 	return (ISC_R_SUCCESS);
1009 
1010  cleanup:
1011 	if (rdataset != NULL) {
1012 		INSIST(!dns_rdataset_isassociated(rdataset));
1013 		free(rdataset);
1014 	}
1015 	if (free_name)
1016 		free(name);
1017 
1018 	return (result);
1019 }
1020 
1021 static int
1022 update(dns_section_t section, dns_rdataclass_t rdclass) {
1023 	if (section == DNS_SECTION_PREREQUISITE)
1024 		return (rdclass == dns_rdataclass_any ||
1025 			       rdclass == dns_rdataclass_none);
1026 	if (section == DNS_SECTION_UPDATE)
1027 		return (rdclass == dns_rdataclass_any);
1028 	return (0);
1029 }
1030 
1031 static isc_result_t
1032 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1033 	   dns_section_t sectionid, unsigned int options)
1034 {
1035 	isc_region_t r;
1036 	unsigned int count, rdatalen;
1037 	dns_name_t *name = NULL;
1038 	dns_offsets_t *offsets;
1039 	dns_rdataset_t *rdataset;
1040 	dns_rdatalist_t *rdatalist;
1041 	isc_result_t result;
1042 	dns_rdatatype_t rdtype, covers;
1043 	dns_rdataclass_t rdclass;
1044 	dns_rdata_t *rdata;
1045 	dns_ttl_t ttl;
1046 	dns_namelist_t *section;
1047 	int free_name = 0, free_rdataset = 0;
1048 	int best_effort, seen_problem;
1049 	int issigzero;
1050 
1051 	best_effort = options & DNS_MESSAGEPARSE_BESTEFFORT;
1052 	seen_problem = 0;
1053 
1054 	section = &msg->sections[sectionid];
1055 
1056 	for (count = 0; count < msg->counts[sectionid]; count++) {
1057 		int recstart = source->current;
1058 		free_rdataset = 0;
1059 
1060 		name = malloc(sizeof(dns_name_t));
1061 		if (name == NULL)
1062 			return (ISC_R_NOMEMORY);
1063 		free_name = 1;
1064 
1065 		offsets = newoffsets(msg);
1066 		if (offsets == NULL) {
1067 			result = ISC_R_NOMEMORY;
1068 			goto cleanup;
1069 		}
1070 		dns_name_init(name, *offsets);
1071 
1072 		/*
1073 		 * Parse the name out of this packet.
1074 		 */
1075 		isc_buffer_remainingregion(source, &r);
1076 		isc_buffer_setactive(source, r.length);
1077 		result = getname(name, source, msg, dctx);
1078 		if (result != ISC_R_SUCCESS)
1079 			goto cleanup;
1080 
1081 		/*
1082 		 * Get type, class, ttl, and rdatalen.  Verify that at least
1083 		 * rdatalen bytes remain.  (Some of this is deferred to
1084 		 * later.)
1085 		 */
1086 		isc_buffer_remainingregion(source, &r);
1087 		if (r.length < 2 + 2 + 4 + 2) {
1088 			result = ISC_R_UNEXPECTEDEND;
1089 			goto cleanup;
1090 		}
1091 		rdtype = isc_buffer_getuint16(source);
1092 		rdclass = isc_buffer_getuint16(source);
1093 
1094 		/*
1095 		 * If there was no question section, we may not yet have
1096 		 * established a class.  Do so now.
1097 		 */
1098 		if (msg->rdclass_set == 0 &&
1099 		    rdtype != dns_rdatatype_opt &&	/* class is UDP SIZE */
1100 		    rdtype != dns_rdatatype_tsig &&	/* class is ANY */
1101 		    rdtype != dns_rdatatype_tkey) {	/* class is undefined */
1102 			msg->rdclass = rdclass;
1103 			msg->rdclass_set = 1;
1104 		}
1105 
1106 		/*
1107 		 * If this class is different than the one in the question
1108 		 * section, bail.
1109 		 */
1110 		if (msg->opcode != dns_opcode_update
1111 		    && rdtype != dns_rdatatype_tsig
1112 		    && rdtype != dns_rdatatype_opt
1113 		    && rdtype != dns_rdatatype_key /* in a TKEY query */
1114 		    && rdtype != dns_rdatatype_sig /* SIG(0) */
1115 		    && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1116 		    && msg->rdclass != dns_rdataclass_any
1117 		    && msg->rdclass != rdclass)
1118 			DO_FORMERR;
1119 
1120 		/*
1121 		 * If this is not a TKEY query/response then the KEY
1122 		 * record's class needs to match.
1123 		 */
1124 		if (msg->opcode != dns_opcode_update && !msg->tkey &&
1125 		    rdtype == dns_rdatatype_key &&
1126 		    msg->rdclass != dns_rdataclass_any &&
1127 		    msg->rdclass != rdclass)
1128 			DO_FORMERR;
1129 
1130 		/*
1131 		 * Special type handling for TSIG, OPT, and TKEY.
1132 		 */
1133 		if (rdtype == dns_rdatatype_tsig) {
1134 			/*
1135 			 * If it is a tsig, verify that it is in the
1136 			 * additional data section.
1137 			 */
1138 			if (sectionid != DNS_SECTION_ADDITIONAL ||
1139 			    rdclass != dns_rdataclass_any ||
1140 			    count != msg->counts[sectionid]  - 1)
1141 				DO_FORMERR;
1142 			msg->sigstart = recstart;
1143 		} else if (rdtype == dns_rdatatype_opt) {
1144 			/*
1145 			 * The name of an OPT record must be ".", it
1146 			 * must be in the additional data section, and
1147 			 * it must be the first OPT we've seen.
1148 			 */
1149 			if (!dns_name_equal(dns_rootname, name) ||
1150 			    sectionid != DNS_SECTION_ADDITIONAL ||
1151 			    msg->opt != NULL)
1152 				DO_FORMERR;
1153 		} else if (rdtype == dns_rdatatype_tkey) {
1154 			/*
1155 			 * A TKEY must be in the additional section if this
1156 			 * is a query, and the answer section if this is a
1157 			 * response.  Unless it's a Win2000 client.
1158 			 *
1159 			 * Its class is ignored.
1160 			 */
1161 			dns_section_t tkeysection;
1162 
1163 			if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1164 				tkeysection = DNS_SECTION_ADDITIONAL;
1165 			else
1166 				tkeysection = DNS_SECTION_ANSWER;
1167 			if (sectionid != tkeysection &&
1168 			    sectionid != DNS_SECTION_ANSWER)
1169 				DO_FORMERR;
1170 		}
1171 
1172 		/*
1173 		 * ... now get ttl and rdatalen, and check buffer.
1174 		 */
1175 		ttl = isc_buffer_getuint32(source);
1176 		rdatalen = isc_buffer_getuint16(source);
1177 		r.length -= (2 + 2 + 4 + 2);
1178 		if (r.length < rdatalen) {
1179 			result = ISC_R_UNEXPECTEDEND;
1180 			goto cleanup;
1181 		}
1182 
1183 		/*
1184 		 * Read the rdata from the wire format.  Interpret the
1185 		 * rdata according to its actual class, even if it had a
1186 		 * DynDNS meta-class in the packet (unless this is a TSIG).
1187 		 * Then put the meta-class back into the finished rdata.
1188 		 */
1189 		rdata = newrdata(msg);
1190 		if (rdata == NULL) {
1191 			result = ISC_R_NOMEMORY;
1192 			goto cleanup;
1193 		}
1194 		if (msg->opcode == dns_opcode_update &&
1195 		    update(sectionid, rdclass)) {
1196 			if (rdatalen != 0) {
1197 				result = DNS_R_FORMERR;
1198 				goto cleanup;
1199 			}
1200 			/*
1201 			 * When the rdata is empty, the data pointer is
1202 			 * never dereferenced, but it must still be non-NULL.
1203 			 * Casting 1 rather than "" avoids warnings about
1204 			 * discarding the const attribute of a string,
1205 			 * for compilers that would warn about such things.
1206 			 */
1207 			rdata->data = (unsigned char *)1;
1208 			rdata->length = 0;
1209 			rdata->rdclass = rdclass;
1210 			rdata->type = rdtype;
1211 			rdata->flags = DNS_RDATA_UPDATE;
1212 			result = ISC_R_SUCCESS;
1213 		} else if (rdclass == dns_rdataclass_none &&
1214 			   msg->opcode == dns_opcode_update &&
1215 			   sectionid == DNS_SECTION_UPDATE) {
1216 			result = getrdata(source, msg, dctx, msg->rdclass,
1217 					  rdtype, rdatalen, rdata);
1218 		} else
1219 			result = getrdata(source, msg, dctx, rdclass,
1220 					  rdtype, rdatalen, rdata);
1221 		if (result != ISC_R_SUCCESS)
1222 			goto cleanup;
1223 		rdata->rdclass = rdclass;
1224 		issigzero = 0;
1225 		if (rdtype == dns_rdatatype_rrsig &&
1226 		    rdata->flags == 0) {
1227 			covers = dns_rdata_covers(rdata);
1228 			if (covers == 0)
1229 				DO_FORMERR;
1230 		} else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1231 			   rdata->flags == 0) {
1232 			covers = dns_rdata_covers(rdata);
1233 			if (covers == 0) {
1234 				if (sectionid != DNS_SECTION_ADDITIONAL ||
1235 				    count != msg->counts[sectionid]  - 1)
1236 					DO_FORMERR;
1237 				msg->sigstart = recstart;
1238 				issigzero = 1;
1239 			} else {
1240 				if (msg->rdclass != dns_rdataclass_any &&
1241 				    msg->rdclass != rdclass)
1242 					DO_FORMERR;
1243 			}
1244 		} else
1245 			covers = 0;
1246 
1247 		/*
1248 		 * Check the ownername of NSEC3 records
1249 		 */
1250 		if (rdtype == dns_rdatatype_nsec3 &&
1251 		    !dns_rdata_checkowner_nsec3(name, msg->rdclass, rdtype,
1252 					  0)) {
1253 			result = DNS_R_BADOWNERNAME;
1254 			goto cleanup;
1255 		}
1256 
1257 		if (rdtype != dns_rdatatype_opt &&
1258 		    rdtype != dns_rdatatype_tsig && !issigzero) {
1259 			ISC_LIST_APPEND(*section, name, link);
1260 			free_name = 0;
1261 		}
1262 
1263 		rdataset = malloc(sizeof(dns_rdataset_t));
1264 		if (rdataset == NULL) {
1265 			result = ISC_R_NOMEMORY;
1266 			goto cleanup;
1267 		}
1268 		free_rdataset = 1;
1269 
1270 		rdatalist = newrdatalist(msg);
1271 		if (rdatalist == NULL) {
1272 			result = ISC_R_NOMEMORY;
1273 			goto cleanup;
1274 		}
1275 
1276 		rdatalist->type = rdtype;
1277 		rdatalist->covers = covers;
1278 		rdatalist->rdclass = rdclass;
1279 		rdatalist->ttl = ttl;
1280 		ISC_LIST_INIT(rdatalist->rdata);
1281 
1282 		dns_rdataset_init(rdataset);
1283 		RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1284 							       rdataset)
1285 			      == ISC_R_SUCCESS);
1286 
1287 		if (rdtype != dns_rdatatype_opt &&
1288 		    rdtype != dns_rdatatype_tsig &&
1289 		    !issigzero)
1290 		{
1291 			ISC_LIST_APPEND(name->list, rdataset, link);
1292 			free_rdataset = 0;
1293 		}
1294 
1295 		/*
1296 		 * Minimize TTLs.
1297 		 *
1298 		 * Section 5.2 of RFC2181 says we should drop
1299 		 * nonauthoritative rrsets where the TTLs differ, but we
1300 		 * currently treat them the as if they were authoritative and
1301 		 * minimize them.
1302 		 */
1303 		if (ttl != rdataset->ttl) {
1304 			rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1305 			if (ttl < rdataset->ttl)
1306 				rdataset->ttl = ttl;
1307 		}
1308 
1309 		/* Append this rdata to the rdataset. */
1310 		dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1311 		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1312 
1313 		/*
1314 		 * If this is an OPT, SIG(0) or TSIG record, remember it.
1315 		 * Also, set the extended rcode for TSIG.
1316 		 *
1317 		 * Note msg->opt, msg->sig0 and msg->tsig will only be
1318 		 * already set if best-effort parsing is enabled otherwise
1319 		 * there will only be at most one of each.
1320 		 */
1321 		if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1322 			dns_rcode_t ercode;
1323 
1324 			msg->opt = rdataset;
1325 			rdataset = NULL;
1326 			free_rdataset = 0;
1327 			ercode = (dns_rcode_t)
1328 				((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1329 				 >> 20);
1330 			msg->rcode |= ercode;
1331 			free(name);
1332 			free_name = 0;
1333 		} else if (issigzero && msg->sig0 == NULL) {
1334 			msg->sig0 = rdataset;
1335 			msg->sig0name = name;
1336 			rdataset = NULL;
1337 			free_rdataset = 0;
1338 			free_name = 0;
1339 		} else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1340 			msg->tsig = rdataset;
1341 			msg->tsigname = name;
1342 			/* Windows doesn't like TSIG names to be compressed. */
1343 			msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1344 			rdataset = NULL;
1345 			free_rdataset = 0;
1346 			free_name = 0;
1347 		}
1348 
1349 		if (seen_problem) {
1350 			if (free_name)
1351 				free(name);
1352 			if (free_rdataset)
1353 				free(rdataset);
1354 			free_name = free_rdataset = 0;
1355 		}
1356 		INSIST(!free_name);
1357 		INSIST(!free_rdataset);
1358 	}
1359 
1360 	if (seen_problem)
1361 		return (DNS_R_RECOVERABLE);
1362 	return (ISC_R_SUCCESS);
1363 
1364  cleanup:
1365 	if (free_name)
1366 		free(name);
1367 	if (free_rdataset)
1368 		free(rdataset);
1369 
1370 	return (result);
1371 }
1372 
1373 isc_result_t
1374 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1375 		  unsigned int options)
1376 {
1377 	isc_region_t r;
1378 	dns_decompress_t dctx;
1379 	isc_result_t ret;
1380 	uint16_t tmpflags;
1381 	isc_buffer_t origsource;
1382 	int seen_problem;
1383 	int ignore_tc;
1384 
1385 	REQUIRE(source != NULL);
1386 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1387 
1388 	seen_problem = 0;
1389 	ignore_tc = options & DNS_MESSAGEPARSE_IGNORETRUNCATION;
1390 
1391 	origsource = *source;
1392 
1393 	msg->header_ok = 0;
1394 	msg->question_ok = 0;
1395 
1396 	isc_buffer_remainingregion(source, &r);
1397 	if (r.length < DNS_MESSAGE_HEADERLEN)
1398 		return (ISC_R_UNEXPECTEDEND);
1399 
1400 	msg->id = isc_buffer_getuint16(source);
1401 	tmpflags = isc_buffer_getuint16(source);
1402 	msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1403 		       >> DNS_MESSAGE_OPCODE_SHIFT);
1404 	msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1405 	msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1406 	msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1407 	msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1408 	msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1409 	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1410 
1411 	msg->header_ok = 1;
1412 	msg->state = DNS_SECTION_QUESTION;
1413 
1414 	/*
1415 	 * -1 means no EDNS.
1416 	 */
1417 	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1418 
1419 	dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1420 
1421 	ret = getquestions(source, msg, &dctx, options);
1422 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1423 		goto truncated;
1424 	if (ret == DNS_R_RECOVERABLE) {
1425 		seen_problem = 1;
1426 		ret = ISC_R_SUCCESS;
1427 	}
1428 	if (ret != ISC_R_SUCCESS)
1429 		return (ret);
1430 	msg->question_ok = 1;
1431 
1432 	ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1433 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1434 		goto truncated;
1435 	if (ret == DNS_R_RECOVERABLE) {
1436 		seen_problem = 1;
1437 		ret = ISC_R_SUCCESS;
1438 	}
1439 	if (ret != ISC_R_SUCCESS)
1440 		return (ret);
1441 
1442 	ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1443 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1444 		goto truncated;
1445 	if (ret == DNS_R_RECOVERABLE) {
1446 		seen_problem = 1;
1447 		ret = ISC_R_SUCCESS;
1448 	}
1449 	if (ret != ISC_R_SUCCESS)
1450 		return (ret);
1451 
1452 	ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1453 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1454 		goto truncated;
1455 	if (ret == DNS_R_RECOVERABLE) {
1456 		seen_problem = 1;
1457 		ret = ISC_R_SUCCESS;
1458 	}
1459 	if (ret != ISC_R_SUCCESS)
1460 		return (ret);
1461 
1462 	isc_buffer_remainingregion(source, &r);
1463 	if (r.length != 0) {
1464 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1465 			      DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1466 			      "message has %u byte(s) of trailing garbage",
1467 			      r.length);
1468 	}
1469 
1470  truncated:
1471 	isc_buffer_usedregion(&origsource, &msg->saved);
1472 
1473 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1474 		return (DNS_R_RECOVERABLE);
1475 	if (seen_problem)
1476 		return (DNS_R_RECOVERABLE);
1477 	return (ISC_R_SUCCESS);
1478 }
1479 
1480 isc_result_t
1481 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1482 			isc_buffer_t *buffer)
1483 {
1484 	isc_region_t r;
1485 
1486 	REQUIRE(buffer != NULL);
1487 	REQUIRE(msg->buffer == NULL);
1488 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1489 
1490 	msg->cctx = cctx;
1491 
1492 	/*
1493 	 * Erase the contents of this buffer.
1494 	 */
1495 	isc_buffer_clear(buffer);
1496 
1497 	/*
1498 	 * Make certain there is enough for at least the header in this
1499 	 * buffer.
1500 	 */
1501 	isc_buffer_availableregion(buffer, &r);
1502 	if (r.length < DNS_MESSAGE_HEADERLEN)
1503 		return (ISC_R_NOSPACE);
1504 
1505 	if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
1506 		return (ISC_R_NOSPACE);
1507 
1508 	/*
1509 	 * Reserve enough space for the header in this buffer.
1510 	 */
1511 	isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1512 
1513 	msg->buffer = buffer;
1514 
1515 	return (ISC_R_SUCCESS);
1516 }
1517 
1518 void
1519 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1520 	REQUIRE(space <= msg->reserved);
1521 
1522 	msg->reserved -= space;
1523 }
1524 
1525 isc_result_t
1526 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1527 	isc_region_t r;
1528 
1529 	if (msg->buffer != NULL) {
1530 		isc_buffer_availableregion(msg->buffer, &r);
1531 		if (r.length < (space + msg->reserved))
1532 			return (ISC_R_NOSPACE);
1533 	}
1534 
1535 	msg->reserved += space;
1536 
1537 	return (ISC_R_SUCCESS);
1538 }
1539 
1540 static inline int
1541 wrong_priority(dns_rdataset_t *rds, int pass) {
1542 	int pass_needed;
1543 
1544 	/*
1545 	 * If we are not rendering class IN, this ordering is bogus.
1546 	 */
1547 	if (rds->rdclass != dns_rdataclass_in)
1548 		return (0);
1549 
1550 	switch (rds->type) {
1551 	case dns_rdatatype_a:
1552 	case dns_rdatatype_aaaa:
1553 		pass_needed = 3;
1554 		break;
1555 	case dns_rdatatype_rrsig:
1556 	case dns_rdatatype_dnskey:
1557 		pass_needed = 2;
1558 		break;
1559 	default:
1560 		pass_needed = 1;
1561 	}
1562 
1563 	if (pass_needed >= pass)
1564 		return (0);
1565 
1566 	return (1);
1567 }
1568 
1569 static isc_result_t
1570 renderset(dns_rdataset_t *rdataset, dns_name_t *owner_name,
1571 	  dns_compress_t *cctx, isc_buffer_t *target,
1572 	  unsigned int reserved, unsigned int *countp)
1573 {
1574 	isc_result_t result;
1575 
1576 	/*
1577 	 * Shrink the space in the buffer by the reserved amount.
1578 	 */
1579 	if (target->length - target->used < reserved)
1580 		return (ISC_R_NOSPACE);
1581 
1582 	target->length -= reserved;
1583 	result = dns_rdataset_towire(rdataset, owner_name,
1584 				     cctx, target, countp);
1585 	target->length += reserved;
1586 
1587 	return (result);
1588 }
1589 
1590 static void
1591 maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) {
1592 	if (msg->counts[sectionid] == 0 &&
1593 	    (sectionid == DNS_SECTION_ANSWER ||
1594 	     (sectionid == DNS_SECTION_AUTHORITY &&
1595 	      msg->counts[DNS_SECTION_ANSWER] == 0)))
1596 		msg->flags &= ~DNS_MESSAGEFLAG_AD;
1597 }
1598 
1599 isc_result_t
1600 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid)
1601 {
1602 	dns_namelist_t *section;
1603 	dns_name_t *name, *next_name;
1604 	dns_rdataset_t *rdataset, *next_rdataset;
1605 	unsigned int count, total;
1606 	isc_result_t result;
1607 	isc_buffer_t st; /* for rollbacks */
1608 	int pass;
1609 
1610 	REQUIRE(msg->buffer != NULL);
1611 	REQUIRE(VALID_NAMED_SECTION(sectionid));
1612 
1613 	section = &msg->sections[sectionid];
1614 
1615 	if (sectionid == DNS_SECTION_ADDITIONAL)
1616 		pass = 3;
1617 	else
1618 		pass = 1;
1619 
1620 	/*
1621 	 * Shrink the space in the buffer by the reserved amount.
1622 	 */
1623 	if (msg->buffer->length - msg->buffer->used < msg->reserved)
1624 		return (ISC_R_NOSPACE);
1625 	msg->buffer->length -= msg->reserved;
1626 
1627 	total = 0;
1628 
1629 	do {
1630 		name = ISC_LIST_HEAD(*section);
1631 		if (name == NULL) {
1632 			msg->buffer->length += msg->reserved;
1633 			msg->counts[sectionid] += total;
1634 			return (ISC_R_SUCCESS);
1635 		}
1636 
1637 		while (name != NULL) {
1638 			next_name = ISC_LIST_NEXT(name, link);
1639 
1640 			rdataset = ISC_LIST_HEAD(name->list);
1641 			while (rdataset != NULL) {
1642 				next_rdataset = ISC_LIST_NEXT(rdataset, link);
1643 
1644 				if ((rdataset->attributes &
1645 				     DNS_RDATASETATTR_RENDERED) != 0)
1646 					goto next;
1647 
1648 				if ((sectionid == DNS_SECTION_ADDITIONAL)
1649 				    && wrong_priority(rdataset, pass))
1650 					goto next;
1651 
1652 				st = *(msg->buffer);
1653 
1654 				count = 0;
1655 				result = dns_rdataset_towiresorted(
1656 						  rdataset,
1657 						  name,
1658 						  msg->cctx,
1659 						  msg->buffer,
1660 						  msg->order,
1661 						  msg->order_arg,
1662 						  &count);
1663 
1664 				total += count;
1665 
1666 				/*
1667 				 * If out of space, record stats on what we
1668 				 * rendered so far, and return that status.
1669 				 *
1670 				 */
1671 				if (result != ISC_R_SUCCESS) {
1672 					INSIST(st.used < 65536);
1673 					dns_compress_rollback(msg->cctx,
1674 							(uint16_t)st.used);
1675 					*(msg->buffer) = st;  /* rollback */
1676 					msg->buffer->length += msg->reserved;
1677 					msg->counts[sectionid] += total;
1678 					maybe_clear_ad(msg, sectionid);
1679 					return (result);
1680 				}
1681 
1682 				/*
1683 				 * If we have rendered non-validated data,
1684 				 * ensure that the AD bit is not set.
1685 				 */
1686 				if (rdataset->trust != dns_trust_secure &&
1687 				    (sectionid == DNS_SECTION_ANSWER ||
1688 				     sectionid == DNS_SECTION_AUTHORITY))
1689 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
1690 				if (OPTOUT(rdataset))
1691 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
1692 
1693 				rdataset->attributes |=
1694 					DNS_RDATASETATTR_RENDERED;
1695 
1696 			next:
1697 				rdataset = next_rdataset;
1698 			}
1699 
1700 			name = next_name;
1701 		}
1702 	} while (--pass != 0);
1703 
1704 	msg->buffer->length += msg->reserved;
1705 	msg->counts[sectionid] += total;
1706 
1707 	return (ISC_R_SUCCESS);
1708 }
1709 
1710 void
1711 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
1712 	uint16_t tmp;
1713 	isc_region_t r;
1714 
1715 	REQUIRE(target != NULL);
1716 
1717 	isc_buffer_availableregion(target, &r);
1718 	REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
1719 
1720 	isc_buffer_putuint16(target, msg->id);
1721 
1722 	tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
1723 	       & DNS_MESSAGE_OPCODE_MASK);
1724 	tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
1725 	tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
1726 
1727 	INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
1728 	       msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
1729 	       msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
1730 	       msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
1731 
1732 	isc_buffer_putuint16(target, tmp);
1733 	isc_buffer_putuint16(target,
1734 			    (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
1735 	isc_buffer_putuint16(target,
1736 			    (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
1737 	isc_buffer_putuint16(target,
1738 			    (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
1739 	isc_buffer_putuint16(target,
1740 			    (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
1741 }
1742 
1743 isc_result_t
1744 dns_message_renderend(dns_message_t *msg) {
1745 	isc_buffer_t tmpbuf;
1746 	isc_region_t r;
1747 	int result;
1748 	unsigned int count;
1749 
1750 	REQUIRE(msg->buffer != NULL);
1751 
1752 	if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
1753 		/*
1754 		 * We have an extended rcode but are not using EDNS.
1755 		 */
1756 		return (DNS_R_FORMERR);
1757 	}
1758 
1759 	/*
1760 	 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
1761 	 * clear all rdatasets from the message except for the question
1762 	 * before adding the OPT, TSIG or SIG(0).  If the question doesn't
1763 	 * fit, don't include it.
1764 	 */
1765 	if ((msg->tsigkey != NULL || msg->opt) &&
1766 	    (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
1767 	{
1768 		isc_buffer_t *buf;
1769 
1770 		msgresetnames(msg, DNS_SECTION_ANSWER);
1771 		buf = msg->buffer;
1772 		dns_message_renderreset(msg);
1773 		msg->buffer = buf;
1774 		isc_buffer_clear(msg->buffer);
1775 		isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
1776 		dns_compress_rollback(msg->cctx, 0);
1777 		result = dns_message_rendersection(msg, DNS_SECTION_QUESTION);
1778 		if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
1779 			return (result);
1780 	}
1781 
1782 	/*
1783 	 * If we've got an OPT record, render it.
1784 	 */
1785 	if (msg->opt != NULL) {
1786 		dns_message_renderrelease(msg, msg->opt_reserved);
1787 		msg->opt_reserved = 0;
1788 		/*
1789 		 * Set the extended rcode.
1790 		 */
1791 		msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
1792 		msg->opt->ttl |= ((msg->rcode << 20) &
1793 				  DNS_MESSAGE_EDNSRCODE_MASK);
1794 		/*
1795 		 * Render.
1796 		 */
1797 		count = 0;
1798 		result = renderset(msg->opt, dns_rootname, msg->cctx,
1799 				   msg->buffer, msg->reserved, &count);
1800 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
1801 		if (result != ISC_R_SUCCESS)
1802 			return (result);
1803 	}
1804 
1805 	/*
1806 	 * If we're adding a TSIG record, generate and render it.
1807 	 */
1808 	if (msg->tsigkey != NULL) {
1809 		dns_message_renderrelease(msg, msg->sig_reserved);
1810 		msg->sig_reserved = 0;
1811 		result = dns_tsig_sign(msg);
1812 		if (result != ISC_R_SUCCESS)
1813 			return (result);
1814 		count = 0;
1815 		result = renderset(msg->tsig, msg->tsigname, msg->cctx,
1816 				   msg->buffer, msg->reserved, &count);
1817 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
1818 		if (result != ISC_R_SUCCESS)
1819 			return (result);
1820 	}
1821 
1822 	isc_buffer_usedregion(msg->buffer, &r);
1823 	isc_buffer_init(&tmpbuf, r.base, r.length);
1824 
1825 	dns_message_renderheader(msg, &tmpbuf);
1826 
1827 	msg->buffer = NULL;  /* forget about this buffer only on success XXX */
1828 
1829 	return (ISC_R_SUCCESS);
1830 }
1831 
1832 void
1833 dns_message_renderreset(dns_message_t *msg) {
1834 	unsigned int i;
1835 	dns_name_t *name;
1836 	dns_rdataset_t *rds;
1837 
1838 	/*
1839 	 * Reset the message so that it may be rendered again.
1840 	 */
1841 
1842 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1843 
1844 	msg->buffer = NULL;
1845 
1846 	for (i = 0; i < DNS_SECTION_MAX; i++) {
1847 		msg->cursors[i] = NULL;
1848 		msg->counts[i] = 0;
1849 		for (name = ISC_LIST_HEAD(msg->sections[i]);
1850 		     name != NULL;
1851 		     name = ISC_LIST_NEXT(name, link)) {
1852 			for (rds = ISC_LIST_HEAD(name->list);
1853 			     rds != NULL;
1854 			     rds = ISC_LIST_NEXT(rds, link)) {
1855 				rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
1856 			}
1857 		}
1858 	}
1859 	if (msg->tsigname != NULL)
1860 		dns_message_puttempname(msg, &msg->tsigname);
1861 	if (msg->tsig != NULL) {
1862 		dns_rdataset_disassociate(msg->tsig);
1863 		dns_message_puttemprdataset(msg, &msg->tsig);
1864 	}
1865 	if (msg->sig0 != NULL) {
1866 		dns_rdataset_disassociate(msg->sig0);
1867 		dns_message_puttemprdataset(msg, &msg->sig0);
1868 	}
1869 }
1870 
1871 isc_result_t
1872 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
1873 	REQUIRE(VALID_NAMED_SECTION(section));
1874 
1875 	msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
1876 
1877 	if (msg->cursors[section] == NULL)
1878 		return (ISC_R_NOMORE);
1879 
1880 	return (ISC_R_SUCCESS);
1881 }
1882 
1883 isc_result_t
1884 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
1885 	REQUIRE(VALID_NAMED_SECTION(section));
1886 	REQUIRE(msg->cursors[section] != NULL);
1887 
1888 	msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
1889 
1890 	if (msg->cursors[section] == NULL)
1891 		return (ISC_R_NOMORE);
1892 
1893 	return (ISC_R_SUCCESS);
1894 }
1895 
1896 void
1897 dns_message_currentname(dns_message_t *msg, dns_section_t section,
1898 			dns_name_t **name)
1899 {
1900 	REQUIRE(VALID_NAMED_SECTION(section));
1901 	REQUIRE(name != NULL && *name == NULL);
1902 	REQUIRE(msg->cursors[section] != NULL);
1903 
1904 	*name = msg->cursors[section];
1905 }
1906 
1907 isc_result_t
1908 dns_message_findname(dns_message_t *msg, dns_section_t section,
1909 		     dns_name_t *target, dns_rdatatype_t type,
1910 		     dns_rdatatype_t covers, dns_name_t **name,
1911 		     dns_rdataset_t **rdataset)
1912 {
1913 	dns_name_t *foundname;
1914 	isc_result_t result;
1915 
1916 	/*
1917 	 * XXX These requirements are probably too intensive, especially
1918 	 * where things can be NULL, but as they are they ensure that if
1919 	 * something is NON-NULL, indicating that the caller expects it
1920 	 * to be filled in, that we can in fact fill it in.
1921 	 */
1922 	REQUIRE(msg != NULL);
1923 	REQUIRE(VALID_SECTION(section));
1924 	REQUIRE(target != NULL);
1925 	REQUIRE(name == NULL || *name == NULL);
1926 
1927 	if (type == dns_rdatatype_any) {
1928 		REQUIRE(rdataset == NULL);
1929 	} else {
1930 		REQUIRE(rdataset == NULL || *rdataset == NULL);
1931 	}
1932 
1933 	result = findname(&foundname, target,
1934 			  &msg->sections[section]);
1935 
1936 	if (result == ISC_R_NOTFOUND)
1937 		return (DNS_R_NXDOMAIN);
1938 	else if (result != ISC_R_SUCCESS)
1939 		return (result);
1940 
1941 	if (name != NULL)
1942 		*name = foundname;
1943 
1944 	/*
1945 	 * And now look for the type.
1946 	 */
1947 	if (type == dns_rdatatype_any)
1948 		return (ISC_R_SUCCESS);
1949 
1950 	result = dns_message_findtype(foundname, type, covers, rdataset);
1951 	if (result == ISC_R_NOTFOUND)
1952 		return (DNS_R_NXRRSET);
1953 
1954 	return (result);
1955 }
1956 
1957 void
1958 dns_message_addname(dns_message_t *msg, dns_name_t *name,
1959 		    dns_section_t section)
1960 {
1961 	REQUIRE(msg != NULL);
1962 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1963 	REQUIRE(name != NULL);
1964 	REQUIRE(VALID_NAMED_SECTION(section));
1965 
1966 	ISC_LIST_APPEND(msg->sections[section], name, link);
1967 }
1968 
1969 isc_result_t
1970 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
1971 	REQUIRE(item != NULL && *item == NULL);
1972 
1973 	UNUSED(msg);
1974 
1975 	*item = malloc(sizeof(dns_name_t));
1976 	if (*item == NULL)
1977 		return (ISC_R_NOMEMORY);
1978 	dns_name_init(*item, NULL);
1979 
1980 	return (ISC_R_SUCCESS);
1981 }
1982 
1983 isc_result_t
1984 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
1985 	REQUIRE(item != NULL && *item == NULL);
1986 
1987 	*item = newrdata(msg);
1988 	if (*item == NULL)
1989 		return (ISC_R_NOMEMORY);
1990 
1991 	return (ISC_R_SUCCESS);
1992 }
1993 
1994 isc_result_t
1995 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
1996 	REQUIRE(item != NULL && *item == NULL);
1997 
1998 	UNUSED(msg);
1999 
2000 	*item = malloc(sizeof(dns_rdataset_t));
2001 	if (*item == NULL)
2002 		return (ISC_R_NOMEMORY);
2003 
2004 	dns_rdataset_init(*item);
2005 
2006 	return (ISC_R_SUCCESS);
2007 }
2008 
2009 isc_result_t
2010 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2011 	REQUIRE(item != NULL && *item == NULL);
2012 
2013 	*item = newrdatalist(msg);
2014 	if (*item == NULL)
2015 		return (ISC_R_NOMEMORY);
2016 
2017 	return (ISC_R_SUCCESS);
2018 }
2019 
2020 void
2021 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2022 	REQUIRE(item != NULL && *item != NULL);
2023 
2024 	UNUSED(msg);
2025 
2026 	if (dns_name_dynamic(*item))
2027 		dns_name_free(*item);
2028 	free(*item);
2029 	*item = NULL;
2030 }
2031 
2032 void
2033 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2034 	REQUIRE(item != NULL && *item != NULL);
2035 
2036 	releaserdata(msg, *item);
2037 	*item = NULL;
2038 }
2039 
2040 void
2041 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2042 	REQUIRE(item != NULL && *item != NULL);
2043 	REQUIRE(!dns_rdataset_isassociated(*item));
2044 
2045 	UNUSED(msg);
2046 
2047 	free(*item);
2048 	*item = NULL;
2049 }
2050 
2051 void
2052 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2053 	REQUIRE(item != NULL && *item != NULL);
2054 
2055 	releaserdatalist(msg, *item);
2056 	*item = NULL;
2057 }
2058 
2059 isc_result_t
2060 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2061 		       unsigned int *flagsp)
2062 {
2063 	isc_region_t r;
2064 	isc_buffer_t buffer;
2065 	dns_messageid_t id;
2066 	unsigned int flags;
2067 
2068 	REQUIRE(source != NULL);
2069 
2070 	buffer = *source;
2071 
2072 	isc_buffer_remainingregion(&buffer, &r);
2073 	if (r.length < DNS_MESSAGE_HEADERLEN)
2074 		return (ISC_R_UNEXPECTEDEND);
2075 
2076 	id = isc_buffer_getuint16(&buffer);
2077 	flags = isc_buffer_getuint16(&buffer);
2078 	flags &= DNS_MESSAGE_FLAG_MASK;
2079 
2080 	if (flagsp != NULL)
2081 		*flagsp = flags;
2082 	if (idp != NULL)
2083 		*idp = id;
2084 
2085 	return (ISC_R_SUCCESS);
2086 }
2087 
2088 dns_rdataset_t *
2089 dns_message_getopt(dns_message_t *msg) {
2090 
2091 	/*
2092 	 * Get the OPT record for 'msg'.
2093 	 */
2094 	return (msg->opt);
2095 }
2096 
2097 isc_result_t
2098 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2099 	isc_result_t result;
2100 	dns_rdata_t rdata = DNS_RDATA_INIT;
2101 
2102 	/*
2103 	 * Set the OPT record for 'msg'.
2104 	 */
2105 
2106 	/*
2107 	 * The space required for an OPT record is:
2108 	 *
2109 	 *	1 byte for the name
2110 	 *	2 bytes for the type
2111 	 *	2 bytes for the class
2112 	 *	4 bytes for the ttl
2113 	 *	2 bytes for the rdata length
2114 	 * ---------------------------------
2115 	 *     11 bytes
2116 	 *
2117 	 * plus the length of the rdata.
2118 	 */
2119 
2120 	REQUIRE(opt->type == dns_rdatatype_opt);
2121 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2122 	REQUIRE(msg->state == DNS_SECTION_ANY);
2123 
2124 	msgresetopt(msg);
2125 
2126 	result = dns_rdataset_first(opt);
2127 	if (result != ISC_R_SUCCESS)
2128 		goto cleanup;
2129 	dns_rdataset_current(opt, &rdata);
2130 	msg->opt_reserved = 11 + rdata.length;
2131 	result = dns_message_renderreserve(msg, msg->opt_reserved);
2132 	if (result != ISC_R_SUCCESS) {
2133 		msg->opt_reserved = 0;
2134 		goto cleanup;
2135 	}
2136 
2137 	msg->opt = opt;
2138 
2139 	return (ISC_R_SUCCESS);
2140 
2141  cleanup:
2142 	dns_rdataset_disassociate(opt);
2143 	dns_message_puttemprdataset(msg, &opt);
2144 	return (result);
2145 }
2146 
2147 dns_rdataset_t *
2148 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2149 
2150 	/*
2151 	 * Get the TSIG record and owner for 'msg'.
2152 	 */
2153 
2154 	REQUIRE(owner == NULL || *owner == NULL);
2155 
2156 	if (owner != NULL)
2157 		*owner = msg->tsigname;
2158 	return (msg->tsig);
2159 }
2160 
2161 isc_result_t
2162 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2163 	isc_result_t result;
2164 
2165 	/*
2166 	 * Set the TSIG key for 'msg'
2167 	 */
2168 
2169 	REQUIRE(msg->state == DNS_SECTION_ANY);
2170 
2171 	if (key == NULL && msg->tsigkey != NULL) {
2172 		if (msg->sig_reserved != 0) {
2173 			dns_message_renderrelease(msg, msg->sig_reserved);
2174 			msg->sig_reserved = 0;
2175 		}
2176 		dns_tsigkey_detach(&msg->tsigkey);
2177 	}
2178 	if (key != NULL) {
2179 		REQUIRE(msg->tsigkey == NULL);
2180 		dns_tsigkey_attach(key, &msg->tsigkey);
2181 		if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2182 			msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2183 			result = dns_message_renderreserve(msg,
2184 							   msg->sig_reserved);
2185 			if (result != ISC_R_SUCCESS) {
2186 				dns_tsigkey_detach(&msg->tsigkey);
2187 				msg->sig_reserved = 0;
2188 				return (result);
2189 			}
2190 		}
2191 	}
2192 	return (ISC_R_SUCCESS);
2193 }
2194 
2195 dns_tsigkey_t *
2196 dns_message_gettsigkey(dns_message_t *msg) {
2197 
2198 	/*
2199 	 * Get the TSIG key for 'msg'
2200 	 */
2201 	return (msg->tsigkey);
2202 }
2203 
2204 isc_result_t
2205 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2206 	dns_rdata_t *rdata = NULL;
2207 	dns_rdatalist_t *list = NULL;
2208 	dns_rdataset_t *set = NULL;
2209 	isc_buffer_t *buf = NULL;
2210 	isc_region_t r;
2211 	isc_result_t result;
2212 
2213 	REQUIRE(msg->querytsig == NULL);
2214 
2215 	if (querytsig == NULL)
2216 		return (ISC_R_SUCCESS);
2217 
2218 	result = dns_message_gettemprdata(msg, &rdata);
2219 	if (result != ISC_R_SUCCESS)
2220 		goto cleanup;
2221 
2222 	result = dns_message_gettemprdatalist(msg, &list);
2223 	if (result != ISC_R_SUCCESS)
2224 		goto cleanup;
2225 	result = dns_message_gettemprdataset(msg, &set);
2226 	if (result != ISC_R_SUCCESS)
2227 		goto cleanup;
2228 
2229 	isc_buffer_usedregion(querytsig, &r);
2230 	result = isc_buffer_allocate(&buf, r.length);
2231 	if (result != ISC_R_SUCCESS)
2232 		goto cleanup;
2233 	isc_buffer_putmem(buf, r.base, r.length);
2234 	isc_buffer_usedregion(buf, &r);
2235 	dns_rdata_init(rdata);
2236 	dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2237 	dns_message_takebuffer(msg, &buf);
2238 	ISC_LIST_APPEND(list->rdata, rdata, link);
2239 	result = dns_rdatalist_tordataset(list, set);
2240 	if (result != ISC_R_SUCCESS)
2241 		goto cleanup;
2242 
2243 	msg->querytsig = set;
2244 
2245 	return (result);
2246 
2247  cleanup:
2248 	if (rdata != NULL)
2249 		dns_message_puttemprdata(msg, &rdata);
2250 	if (list != NULL)
2251 		dns_message_puttemprdatalist(msg, &list);
2252 	if (set != NULL)
2253 		dns_message_puttemprdataset(msg, &set);
2254 	return (ISC_R_NOMEMORY);
2255 }
2256 
2257 isc_result_t
2258 dns_message_getquerytsig(dns_message_t *msg, isc_buffer_t **querytsig) {
2259 	isc_result_t result;
2260 	dns_rdata_t rdata = DNS_RDATA_INIT;
2261 	isc_region_t r;
2262 
2263 	REQUIRE(querytsig != NULL && *querytsig == NULL);
2264 
2265 	if (msg->tsig == NULL)
2266 		return (ISC_R_SUCCESS);
2267 
2268 	result = dns_rdataset_first(msg->tsig);
2269 	if (result != ISC_R_SUCCESS)
2270 		return (result);
2271 	dns_rdataset_current(msg->tsig, &rdata);
2272 	dns_rdata_toregion(&rdata, &r);
2273 
2274 	result = isc_buffer_allocate(querytsig, r.length);
2275 	if (result != ISC_R_SUCCESS)
2276 		return (result);
2277 	isc_buffer_putmem(*querytsig, r.base, r.length);
2278 	return (ISC_R_SUCCESS);
2279 }
2280 
2281 dns_rdataset_t *
2282 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2283 
2284 	/*
2285 	 * Get the SIG(0) record for 'msg'.
2286 	 */
2287 
2288 	REQUIRE(owner == NULL || *owner == NULL);
2289 
2290 	if (msg->sig0 != NULL && owner != NULL) {
2291 		/* If dns_message_getsig0 is called on a rendered message
2292 		 * after the SIG(0) has been applied, we need to return the
2293 		 * root name, not NULL.
2294 		 */
2295 		if (msg->sig0name == NULL)
2296 			*owner = dns_rootname;
2297 		else
2298 			*owner = msg->sig0name;
2299 	}
2300 	return (msg->sig0);
2301 }
2302 
2303 void
2304 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2305 	REQUIRE(buffer != NULL);
2306 
2307 	ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2308 	*buffer = NULL;
2309 }
2310 
2311 isc_result_t
2312 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
2313 			  const dns_master_style_t *style,
2314 			  dns_messagetextflag_t flags,
2315 			  isc_buffer_t *target) {
2316 	dns_name_t *name, empty_name;
2317 	dns_rdataset_t *rdataset;
2318 	isc_result_t result;
2319 	int seensoa = 0;
2320 
2321 	REQUIRE(target != NULL);
2322 	REQUIRE(VALID_SECTION(section));
2323 
2324 	if (ISC_LIST_EMPTY(msg->sections[section]))
2325 		return (ISC_R_SUCCESS);
2326 
2327 	if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
2328 		ADD_STRING(target, ";; ");
2329 		if (msg->opcode != dns_opcode_update) {
2330 			ADD_STRING(target, sectiontext[section]);
2331 		} else {
2332 			ADD_STRING(target, updsectiontext[section]);
2333 		}
2334 		ADD_STRING(target, " SECTION:\n");
2335 	}
2336 
2337 	dns_name_init(&empty_name, NULL);
2338 	result = dns_message_firstname(msg, section);
2339 	if (result != ISC_R_SUCCESS) {
2340 		return (result);
2341 	}
2342 	do {
2343 		name = NULL;
2344 		dns_message_currentname(msg, section, &name);
2345 		for (rdataset = ISC_LIST_HEAD(name->list);
2346 		     rdataset != NULL;
2347 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
2348 			if (section == DNS_SECTION_ANSWER &&
2349 			    rdataset->type == dns_rdatatype_soa) {
2350 				if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
2351 					continue;
2352 				if (seensoa &&
2353 				    (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
2354 					continue;
2355 				seensoa = 1;
2356 			}
2357 			if (section == DNS_SECTION_QUESTION) {
2358 				ADD_STRING(target, ";");
2359 				result = dns_master_questiontotext(name,
2360 								   rdataset,
2361 								   style,
2362 								   target);
2363 			} else {
2364 				result = dns_master_rdatasettotext(name,
2365 								   rdataset,
2366 								   style,
2367 								   target);
2368 			}
2369 			if (result != ISC_R_SUCCESS)
2370 				return (result);
2371 		}
2372 		result = dns_message_nextname(msg, section);
2373 	} while (result == ISC_R_SUCCESS);
2374 	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2375 	    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2376 		ADD_STRING(target, "\n");
2377 	if (result == ISC_R_NOMORE)
2378 		result = ISC_R_SUCCESS;
2379 	return (result);
2380 }
2381 
2382 static isc_result_t
2383 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
2384 	int i;
2385 	char addr[16], addr_text[64];
2386 	uint16_t family;
2387 	uint8_t addrlen, addrbytes, scopelen;
2388 
2389 	/*
2390 	 * Note: This routine needs to handle malformed ECS options.
2391 	 */
2392 
2393 	if (isc_buffer_remaininglength(ecsbuf) < 4)
2394 		return (DNS_R_OPTERR);
2395 	family = isc_buffer_getuint16(ecsbuf);
2396 	addrlen = isc_buffer_getuint8(ecsbuf);
2397 	scopelen = isc_buffer_getuint8(ecsbuf);
2398 
2399 	addrbytes = (addrlen + 7) / 8;
2400 	if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
2401 		return (DNS_R_OPTERR);
2402 
2403 	if (addrbytes > sizeof(addr))
2404 		return (DNS_R_OPTERR);
2405 
2406 	memset(addr, 0, sizeof(addr));
2407 	for (i = 0; i < addrbytes; i ++)
2408 		addr[i] = isc_buffer_getuint8(ecsbuf);
2409 
2410 	switch (family) {
2411 	case 0:
2412 		if (addrlen != 0U || scopelen != 0U)
2413 			return (DNS_R_OPTERR);
2414 		strlcpy(addr_text, "0", sizeof(addr_text));
2415 		break;
2416 	case 1:
2417 		if (addrlen > 32 || scopelen > 32)
2418 			return (DNS_R_OPTERR);
2419 		inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
2420 		break;
2421 	case 2:
2422 		if (addrlen > 128 || scopelen > 128)
2423 			return (DNS_R_OPTERR);
2424 		inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
2425 		break;
2426 	default:
2427 		return (DNS_R_OPTERR);
2428 	}
2429 
2430 	ADD_STRING(target, ": ");
2431 	ADD_STRING(target, addr_text);
2432 	snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
2433 	ADD_STRING(target, addr_text);
2434 	return (ISC_R_SUCCESS);
2435 }
2436 
2437 static const char *
2438 ede_info_code2str(uint16_t info_code)
2439 {
2440 	if (info_code > 49151)
2441 		return "Private Use";
2442 
2443 	switch (info_code) {
2444 	case 0:
2445 		return "Other Error";
2446 	case 1:
2447 		return "Unsupported DNSKEY Algorithm";
2448 	case 2:
2449 		return "Unsupported DS Digest Type";
2450 	case 3:
2451 		return "Stale Answer";
2452 	case 4:
2453 		return "Forged Answer";
2454 	case 5:
2455 		return "DNSSEC Indeterminate";
2456 	case 6:
2457 		return "DNSSEC Bogus";
2458 	case 7:
2459 		return "Signature Expired";
2460 	case 8:
2461 		return "Signature Not Yet Valid";
2462 	case 9:
2463 		return "DNSKEY Missing";
2464 	case 10:
2465 		return "RRSIGs Missing";
2466 	case 11:
2467 		return "No Zone Key Bit Set";
2468 	case 12:
2469 		return "NSEC Missing";
2470 	case 13:
2471 		return "Cached Error";
2472 	case 14:
2473 		return "Not Ready";
2474 	case 15:
2475 		return "Blocked";
2476 	case 16:
2477 		return "Censored";
2478 	case 17:
2479 		return "Filtered";
2480 	case 18:
2481 		return "Prohibited";
2482 	case 19:
2483 		return "Stale NXDomain Answer";
2484 	case 20:
2485 		return "Not Authoritative";
2486 	case 21:
2487 		return "Not Supported";
2488 	case 22:
2489 		return "No Reachable Authority";
2490 	case 23:
2491 		return "Network Error";
2492 	case 24:
2493 		return "Invalid Data";
2494 	default:
2495 		return "Unassigned";
2496 	}
2497 }
2498 
2499 isc_result_t
2500 dns_message_pseudosectiontotext(dns_message_t *msg,
2501 				dns_pseudosection_t section,
2502 				const dns_master_style_t *style,
2503 				dns_messagetextflag_t flags,
2504 				isc_buffer_t *target)
2505 {
2506 	dns_rdataset_t *ps = NULL;
2507 	dns_name_t *name = NULL;
2508 	isc_result_t result;
2509 	char buf[sizeof("1234567890")];
2510 	uint32_t mbz;
2511 	dns_rdata_t rdata;
2512 	isc_buffer_t optbuf;
2513 	uint16_t optcode, optlen;
2514 	unsigned char *optdata;
2515 
2516 	REQUIRE(target != NULL);
2517 	REQUIRE(VALID_PSEUDOSECTION(section));
2518 
2519 	switch (section) {
2520 	case DNS_PSEUDOSECTION_OPT:
2521 		ps = dns_message_getopt(msg);
2522 		if (ps == NULL)
2523 			return (ISC_R_SUCCESS);
2524 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2525 			ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
2526 		ADD_STRING(target, "; EDNS: version: ");
2527 		snprintf(buf, sizeof(buf), "%u",
2528 			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
2529 		ADD_STRING(target, buf);
2530 		ADD_STRING(target, ", flags:");
2531 		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
2532 			ADD_STRING(target, " do");
2533 		mbz = ps->ttl & 0xffff;
2534 		mbz &= ~DNS_MESSAGEEXTFLAG_DO;		/* Known Flags. */
2535 		if (mbz != 0) {
2536 			ADD_STRING(target, "; MBZ: ");
2537 			snprintf(buf, sizeof(buf), "0x%.4x", mbz);
2538 			ADD_STRING(target, buf);
2539 			ADD_STRING(target, ", udp: ");
2540 		} else
2541 			ADD_STRING(target, "; udp: ");
2542 		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
2543 		ADD_STRING(target, buf);
2544 
2545 		result = dns_rdataset_first(ps);
2546 		if (result != ISC_R_SUCCESS)
2547 			return (ISC_R_SUCCESS);
2548 
2549 		/*
2550 		 * Print EDNS info, if any.
2551 		 *
2552 		 * WARNING: The option contents may be malformed as
2553 		 * dig +ednsopt=value:<content> does not validity
2554 		 * checking.
2555 		 */
2556 		dns_rdata_init(&rdata);
2557 		dns_rdataset_current(ps, &rdata);
2558 
2559 		isc_buffer_init(&optbuf, rdata.data, rdata.length);
2560 		isc_buffer_add(&optbuf, rdata.length);
2561 		while (isc_buffer_remaininglength(&optbuf) != 0) {
2562 			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
2563 			optcode = isc_buffer_getuint16(&optbuf);
2564 			optlen = isc_buffer_getuint16(&optbuf);
2565 			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
2566 
2567 			if (optcode == DNS_OPT_NSID) {
2568 				ADD_STRING(target, "; NSID");
2569 			} else if (optcode == DNS_OPT_COOKIE) {
2570 				ADD_STRING(target, "; COOKIE");
2571 			} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
2572 				isc_buffer_t ecsbuf;
2573 
2574 				ADD_STRING(target, "; CLIENT-SUBNET");
2575 				isc_buffer_init(&ecsbuf,
2576 						isc_buffer_current(&optbuf),
2577 						optlen);
2578 				isc_buffer_add(&ecsbuf, optlen);
2579 				result = render_ecs(&ecsbuf, target);
2580 				if (result == ISC_R_NOSPACE)
2581 					return (result);
2582 				if (result == ISC_R_SUCCESS) {
2583 					isc_buffer_forward(&optbuf, optlen);
2584 					ADD_STRING(target, "\n");
2585 					continue;
2586 				}
2587 			} else if (optcode == DNS_OPT_EXPIRE) {
2588 				if (optlen == 4) {
2589 					uint32_t secs;
2590 					secs = isc_buffer_getuint32(&optbuf);
2591 					ADD_STRING(target, "; EXPIRE: ");
2592 					snprintf(buf, sizeof(buf), "%u", secs);
2593 					ADD_STRING(target, buf);
2594 					ADD_STRING(target, " (");
2595 					result = dns_ttl_totext(secs,
2596 								1,
2597 								target);
2598 					if (result != ISC_R_SUCCESS)
2599 						return (result);
2600 					ADD_STRING(target, ")\n");
2601 					continue;
2602 				}
2603 				ADD_STRING(target, "; EXPIRE");
2604 			} else if (optcode == DNS_OPT_PAD) {
2605 				ADD_STRING(target, "; PAD");
2606 			} else if (optcode == DNS_OPT_KEY_TAG) {
2607 				ADD_STRING(target, "; KEY-TAG");
2608 				if (optlen > 0U && (optlen % 2U) == 0U) {
2609 					const char *sep = ": ";
2610 					uint16_t id;
2611 					while (optlen > 0U) {
2612 					    id = isc_buffer_getuint16(&optbuf);
2613 					    snprintf(buf, sizeof(buf), "%s%u",
2614 						     sep, id);
2615 					    ADD_STRING(target, buf);
2616 					    sep = ", ";
2617 					    optlen -= 2;
2618 					}
2619 					ADD_STRING(target, "\n");
2620 					continue;
2621 				}
2622 			} else if (optcode == DNS_OPT_EDE) {
2623 				uint16_t info_code;
2624 				ADD_STRING(target, "; EDE");
2625 				if (optlen >= 2) {
2626 					info_code =
2627 					    isc_buffer_getuint16(&optbuf);
2628 					optlen -= 2;
2629 					snprintf(buf, sizeof(buf), ": %u (",
2630 					    info_code);
2631 					ADD_STRING(target, buf);
2632 					ADD_STRING(target,
2633 					    ede_info_code2str(info_code));
2634 					ADD_STRING(target, ")");
2635 				}
2636 			} else {
2637 				ADD_STRING(target, "; OPT=");
2638 				snprintf(buf, sizeof(buf), "%u", optcode);
2639 				ADD_STRING(target, buf);
2640 			}
2641 
2642 			if (optlen != 0) {
2643 				int i;
2644 				ADD_STRING(target, ": ");
2645 
2646 				optdata = isc_buffer_current(&optbuf);
2647 				for (i = 0; i < optlen; i++) {
2648 					const char *sep;
2649 					switch (optcode) {
2650 					case DNS_OPT_COOKIE:
2651 						sep = "";
2652 						break;
2653 					default:
2654 						sep = " ";
2655 						break;
2656 					}
2657 					snprintf(buf, sizeof(buf), "%02x%s",
2658 						 optdata[i], sep);
2659 					ADD_STRING(target, buf);
2660 				}
2661 
2662 				isc_buffer_forward(&optbuf, optlen);
2663 
2664 				if (optcode == DNS_OPT_COOKIE) {
2665 					if (msg->sitok)
2666 						ADD_STRING(target, " (good)");
2667 					if (msg->sitbad)
2668 						ADD_STRING(target, " (bad)");
2669 					ADD_STRING(target, "\n");
2670 					continue;
2671 				}
2672 
2673 				if (optcode == DNS_OPT_CLIENT_SUBNET) {
2674 					ADD_STRING(target, "\n");
2675 					continue;
2676 				}
2677 
2678 				/*
2679 				 * For non-SIT options, add a printable
2680 				 * version
2681 				 */
2682 				ADD_STRING(target, "(\"");
2683 				if (isc_buffer_availablelength(target) < optlen)
2684 					return (ISC_R_NOSPACE);
2685 				for (i = 0; i < optlen; i++) {
2686 					if (isprint(optdata[i]))
2687 						isc_buffer_putmem(target,
2688 								  &optdata[i],
2689 								  1);
2690 					else
2691 						isc_buffer_putstr(target, ".");
2692 				}
2693 				ADD_STRING(target, "\")");
2694 			}
2695 			ADD_STRING(target, "\n");
2696 		}
2697 		return (ISC_R_SUCCESS);
2698 	case DNS_PSEUDOSECTION_TSIG:
2699 		ps = dns_message_gettsig(msg, &name);
2700 		if (ps == NULL)
2701 			return (ISC_R_SUCCESS);
2702 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2703 			ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
2704 		result = dns_master_rdatasettotext(name, ps, style, target);
2705 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2706 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2707 			ADD_STRING(target, "\n");
2708 		return (result);
2709 	case DNS_PSEUDOSECTION_SIG0:
2710 		ps = dns_message_getsig0(msg, &name);
2711 		if (ps == NULL)
2712 			return (ISC_R_SUCCESS);
2713 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2714 			ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
2715 		result = dns_master_rdatasettotext(name, ps, style, target);
2716 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2717 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2718 			ADD_STRING(target, "\n");
2719 		return (result);
2720 	}
2721 	return (ISC_R_UNEXPECTED);
2722 }
2723 
2724 isc_result_t
2725 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
2726 		     unsigned int version, uint16_t udpsize,
2727 		     unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
2728 {
2729 	dns_rdataset_t *rdataset = NULL;
2730 	dns_rdatalist_t *rdatalist = NULL;
2731 	dns_rdata_t *rdata = NULL;
2732 	isc_result_t result;
2733 	unsigned int len = 0, i;
2734 
2735 	REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
2736 
2737 	result = dns_message_gettemprdatalist(message, &rdatalist);
2738 	if (result != ISC_R_SUCCESS)
2739 		return (result);
2740 	result = dns_message_gettemprdata(message, &rdata);
2741 	if (result != ISC_R_SUCCESS)
2742 		goto cleanup;
2743 	result = dns_message_gettemprdataset(message, &rdataset);
2744 	if (result != ISC_R_SUCCESS)
2745 		goto cleanup;
2746 
2747 	rdatalist->type = dns_rdatatype_opt;
2748 
2749 	/*
2750 	 * Set Maximum UDP buffer size.
2751 	 */
2752 	rdatalist->rdclass = udpsize;
2753 
2754 	/*
2755 	 * Set EXTENDED-RCODE and Z to 0.
2756 	 */
2757 	rdatalist->ttl = (version << 16);
2758 	rdatalist->ttl |= (flags & 0xffff);
2759 
2760 	/*
2761 	 * Set EDNS options if applicable
2762 	 */
2763 	if (count != 0U) {
2764 		isc_buffer_t *buf = NULL;
2765 		for (i = 0; i < count; i++)
2766 			len += ednsopts[i].length + 4;
2767 
2768 		if (len > 0xffffU) {
2769 			result = ISC_R_NOSPACE;
2770 			goto cleanup;
2771 		}
2772 
2773 		result = isc_buffer_allocate(&buf, len);
2774 		if (result != ISC_R_SUCCESS)
2775 			goto cleanup;
2776 
2777 		for (i = 0; i < count; i++)  {
2778 			isc_buffer_putuint16(buf, ednsopts[i].code);
2779 			isc_buffer_putuint16(buf, ednsopts[i].length);
2780 			if (ednsopts[i].length != 0) {
2781 				isc_buffer_putmem(buf, ednsopts[i].value,
2782 						  ednsopts[i].length);
2783 			}
2784 		}
2785 		rdata->data = isc_buffer_base(buf);
2786 		rdata->length = len;
2787 		dns_message_takebuffer(message, &buf);
2788 	} else {
2789 		rdata->data = NULL;
2790 		rdata->length = 0;
2791 	}
2792 
2793 	rdata->rdclass = rdatalist->rdclass;
2794 	rdata->type = rdatalist->type;
2795 	rdata->flags = 0;
2796 
2797 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
2798 	result = dns_rdatalist_tordataset(rdatalist, rdataset);
2799 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2800 
2801 	*rdatasetp = rdataset;
2802 	return (ISC_R_SUCCESS);
2803 
2804  cleanup:
2805 	if (rdata != NULL)
2806 		dns_message_puttemprdata(message, &rdata);
2807 	if (rdataset != NULL)
2808 		dns_message_puttemprdataset(message, &rdataset);
2809 	if (rdatalist != NULL)
2810 		dns_message_puttemprdatalist(message, &rdatalist);
2811 	return (result);
2812 }
2813