xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/dns/message.c (revision 32d1c65c71fbdb65a012e8392a62a757dd6853e9)
1 /*	$NetBSD: message.c,v 1.1 2024/02/18 20:57:32 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 /***
19  *** Imports
20  ***/
21 
22 #include <ctype.h>
23 #include <inttypes.h>
24 #include <stdbool.h>
25 
26 #include <isc/buffer.h>
27 #include <isc/hash.h>
28 #include <isc/ht.h>
29 #include <isc/mem.h>
30 #include <isc/print.h>
31 #include <isc/string.h> /* Required for HP/UX (and others?) */
32 #include <isc/utf8.h>
33 #include <isc/util.h>
34 
35 #include <dns/dnssec.h>
36 #include <dns/keyvalues.h>
37 #include <dns/log.h>
38 #include <dns/masterdump.h>
39 #include <dns/message.h>
40 #include <dns/opcode.h>
41 #include <dns/rcode.h>
42 #include <dns/rdata.h>
43 #include <dns/rdatalist.h>
44 #include <dns/rdataset.h>
45 #include <dns/rdatastruct.h>
46 #include <dns/result.h>
47 #include <dns/tsig.h>
48 #include <dns/ttl.h>
49 #include <dns/view.h>
50 
51 #ifdef SKAN_MSG_DEBUG
52 static void
53 hexdump(const char *msg, const char *msg2, void *base, size_t len) {
54 	unsigned char *p;
55 	unsigned int cnt;
56 
57 	p = base;
58 	cnt = 0;
59 
60 	printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, (unsigned)len, base);
61 
62 	while (cnt < len) {
63 		if (cnt % 16 == 0) {
64 			printf("%p: ", p);
65 		} else if (cnt % 8 == 0) {
66 			printf(" |");
67 		}
68 		printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
69 		p++;
70 		cnt++;
71 
72 		if (cnt % 16 == 0) {
73 			printf("\n");
74 		}
75 	}
76 
77 	if (cnt % 16 != 0) {
78 		printf("\n");
79 	}
80 }
81 #endif /* ifdef SKAN_MSG_DEBUG */
82 
83 #define DNS_MESSAGE_OPCODE_MASK	      0x7800U
84 #define DNS_MESSAGE_OPCODE_SHIFT      11
85 #define DNS_MESSAGE_RCODE_MASK	      0x000fU
86 #define DNS_MESSAGE_FLAG_MASK	      0x8ff0U
87 #define DNS_MESSAGE_EDNSRCODE_MASK    0xff000000U
88 #define DNS_MESSAGE_EDNSRCODE_SHIFT   24
89 #define DNS_MESSAGE_EDNSVERSION_MASK  0x00ff0000U
90 #define DNS_MESSAGE_EDNSVERSION_SHIFT 16
91 
92 #define VALID_NAMED_SECTION(s) \
93 	(((s) > DNS_SECTION_ANY) && ((s) < DNS_SECTION_MAX))
94 #define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) && ((s) < DNS_SECTION_MAX))
95 #define ADD_STRING(b, s)                                          \
96 	{                                                         \
97 		if (strlen(s) >= isc_buffer_availablelength(b)) { \
98 			result = ISC_R_NOSPACE;                   \
99 			goto cleanup;                             \
100 		} else                                            \
101 			isc_buffer_putstr(b, s);                  \
102 	}
103 #define VALID_PSEUDOSECTION(s) \
104 	(((s) >= DNS_PSEUDOSECTION_ANY) && ((s) < DNS_PSEUDOSECTION_MAX))
105 
106 #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
107 
108 /*%
109  * This is the size of each individual scratchpad buffer, and the numbers
110  * of various block allocations used within the server.
111  * XXXMLG These should come from a config setting.
112  */
113 #define SCRATCHPAD_SIZE	   1232
114 #define NAME_FILLCOUNT	   4
115 #define NAME_FREEMAX	   8 * NAME_FILLCOUNT
116 #define OFFSET_COUNT	   4
117 #define RDATA_COUNT	   8
118 #define RDATALIST_COUNT	   8
119 #define RDATASET_FILLCOUNT 4
120 #define RDATASET_FREEMAX   8 * RDATASET_FILLCOUNT
121 
122 /*%
123  * Text representation of the different items, for message_totext
124  * functions.
125  */
126 static const char *sectiontext[] = { "QUESTION", "ANSWER", "AUTHORITY",
127 				     "ADDITIONAL" };
128 
129 static const char *updsectiontext[] = { "ZONE", "PREREQUISITE", "UPDATE",
130 					"ADDITIONAL" };
131 
132 static const char *opcodetext[] = { "QUERY",	  "IQUERY",	"STATUS",
133 				    "RESERVED3",  "NOTIFY",	"UPDATE",
134 				    "RESERVED6",  "RESERVED7",	"RESERVED8",
135 				    "RESERVED9",  "RESERVED10", "RESERVED11",
136 				    "RESERVED12", "RESERVED13", "RESERVED14",
137 				    "RESERVED15" };
138 
139 static const char *edetext[] = { "Other",
140 				 "Unsupported DNSKEY Algorithm",
141 				 "Unsupported DS Digest Type",
142 				 "Stale Answer",
143 				 "Forged Answer",
144 				 "DNSSEC Indeterminate",
145 				 "DNSSEC Bogus",
146 				 "Signature Expired",
147 				 "Signature Not Yet Valid",
148 				 "DNSKEY Missing",
149 				 "RRSIGs Missing",
150 				 "No Zone Key Bit Set",
151 				 "NSEC Missing",
152 				 "Cached Error",
153 				 "Not Ready",
154 				 "Blocked",
155 				 "Censored",
156 				 "Filtered",
157 				 "Prohibited",
158 				 "Stale NXDOMAIN Answer",
159 				 "Not Authoritative",
160 				 "Not Supported",
161 				 "No Reachable Authority",
162 				 "Network Error",
163 				 "Invalid Data" };
164 
165 /*%
166  * "helper" type, which consists of a block of some type, and is linkable.
167  * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
168  * size, or the allocated elements will not be aligned correctly.
169  */
170 struct dns_msgblock {
171 	unsigned int count;
172 	unsigned int remaining;
173 	ISC_LINK(dns_msgblock_t) link;
174 }; /* dynamically sized */
175 
176 static dns_msgblock_t *
177 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
178 
179 #define msgblock_get(block, type) \
180 	((type *)msgblock_internalget(block, sizeof(type)))
181 
182 static void *
183 msgblock_internalget(dns_msgblock_t *, unsigned int);
184 
185 static void
186 msgblock_reset(dns_msgblock_t *);
187 
188 static void
189 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
190 
191 static void
192 logfmtpacket(dns_message_t *message, const char *description,
193 	     const isc_sockaddr_t *address, isc_logcategory_t *category,
194 	     isc_logmodule_t *module, const dns_master_style_t *style,
195 	     int level, isc_mem_t *mctx);
196 
197 /*
198  * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
199  * is free, return NULL.
200  */
201 static dns_msgblock_t *
202 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
203 		  unsigned int count) {
204 	dns_msgblock_t *block;
205 	unsigned int length;
206 
207 	length = sizeof(dns_msgblock_t) + (sizeof_type * count);
208 
209 	block = isc_mem_get(mctx, length);
210 
211 	block->count = count;
212 	block->remaining = count;
213 
214 	ISC_LINK_INIT(block, link);
215 
216 	return (block);
217 }
218 
219 /*
220  * Return an element from the msgblock.  If no more are available, return
221  * NULL.
222  */
223 static void *
224 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
225 	void *ptr;
226 
227 	if (block == NULL || block->remaining == 0) {
228 		return (NULL);
229 	}
230 
231 	block->remaining--;
232 
233 	ptr = (((unsigned char *)block) + sizeof(dns_msgblock_t) +
234 	       (sizeof_type * block->remaining));
235 
236 	return (ptr);
237 }
238 
239 static void
240 msgblock_reset(dns_msgblock_t *block) {
241 	block->remaining = block->count;
242 }
243 
244 /*
245  * Release memory associated with a message block.
246  */
247 static void
248 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block,
249 	      unsigned int sizeof_type) {
250 	unsigned int length;
251 
252 	length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
253 
254 	isc_mem_put(mctx, block, length);
255 }
256 
257 /*
258  * Allocate a new dynamic buffer, and attach it to this message as the
259  * "current" buffer.  (which is always the last on the list, for our
260  * uses)
261  */
262 static isc_result_t
263 newbuffer(dns_message_t *msg, unsigned int size) {
264 	isc_buffer_t *dynbuf;
265 
266 	dynbuf = NULL;
267 	isc_buffer_allocate(msg->mctx, &dynbuf, size);
268 
269 	ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
270 	return (ISC_R_SUCCESS);
271 }
272 
273 static isc_buffer_t *
274 currentbuffer(dns_message_t *msg) {
275 	isc_buffer_t *dynbuf;
276 
277 	dynbuf = ISC_LIST_TAIL(msg->scratchpad);
278 	INSIST(dynbuf != NULL);
279 
280 	return (dynbuf);
281 }
282 
283 static void
284 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
285 	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
286 }
287 
288 static dns_rdata_t *
289 newrdata(dns_message_t *msg) {
290 	dns_msgblock_t *msgblock;
291 	dns_rdata_t *rdata;
292 
293 	rdata = ISC_LIST_HEAD(msg->freerdata);
294 	if (rdata != NULL) {
295 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
296 		return (rdata);
297 	}
298 
299 	msgblock = ISC_LIST_TAIL(msg->rdatas);
300 	rdata = msgblock_get(msgblock, dns_rdata_t);
301 	if (rdata == NULL) {
302 		msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
303 					     RDATA_COUNT);
304 		if (msgblock == NULL) {
305 			return (NULL);
306 		}
307 
308 		ISC_LIST_APPEND(msg->rdatas, msgblock, link);
309 
310 		rdata = msgblock_get(msgblock, dns_rdata_t);
311 	}
312 
313 	dns_rdata_init(rdata);
314 	return (rdata);
315 }
316 
317 static void
318 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
319 	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
320 }
321 
322 static dns_rdatalist_t *
323 newrdatalist(dns_message_t *msg) {
324 	dns_msgblock_t *msgblock;
325 	dns_rdatalist_t *rdatalist;
326 
327 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
328 	if (rdatalist != NULL) {
329 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
330 		goto out;
331 	}
332 
333 	msgblock = ISC_LIST_TAIL(msg->rdatalists);
334 	rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
335 	if (rdatalist == NULL) {
336 		msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdatalist_t),
337 					     RDATALIST_COUNT);
338 		if (msgblock == NULL) {
339 			return (NULL);
340 		}
341 
342 		ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
343 
344 		rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
345 	}
346 out:
347 	if (rdatalist != NULL) {
348 		dns_rdatalist_init(rdatalist);
349 	}
350 
351 	return (rdatalist);
352 }
353 
354 static dns_offsets_t *
355 newoffsets(dns_message_t *msg) {
356 	dns_msgblock_t *msgblock;
357 	dns_offsets_t *offsets;
358 
359 	msgblock = ISC_LIST_TAIL(msg->offsets);
360 	offsets = msgblock_get(msgblock, dns_offsets_t);
361 	if (offsets == NULL) {
362 		msgblock = msgblock_allocate(msg->mctx, sizeof(dns_offsets_t),
363 					     OFFSET_COUNT);
364 		if (msgblock == NULL) {
365 			return (NULL);
366 		}
367 
368 		ISC_LIST_APPEND(msg->offsets, msgblock, link);
369 
370 		offsets = msgblock_get(msgblock, dns_offsets_t);
371 	}
372 
373 	return (offsets);
374 }
375 
376 static void
377 msginitheader(dns_message_t *m) {
378 	m->id = 0;
379 	m->flags = 0;
380 	m->rcode = 0;
381 	m->opcode = 0;
382 	m->rdclass = 0;
383 }
384 
385 static void
386 msginitprivate(dns_message_t *m) {
387 	unsigned int i;
388 
389 	for (i = 0; i < DNS_SECTION_MAX; i++) {
390 		m->cursors[i] = NULL;
391 		m->counts[i] = 0;
392 	}
393 	m->opt = NULL;
394 	m->sig0 = NULL;
395 	m->sig0name = NULL;
396 	m->tsig = NULL;
397 	m->tsigname = NULL;
398 	m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
399 	m->opt_reserved = 0;
400 	m->sig_reserved = 0;
401 	m->reserved = 0;
402 	m->padding = 0;
403 	m->padding_off = 0;
404 	m->buffer = NULL;
405 }
406 
407 static void
408 msginittsig(dns_message_t *m) {
409 	m->tsigstatus = dns_rcode_noerror;
410 	m->querytsigstatus = dns_rcode_noerror;
411 	m->tsigkey = NULL;
412 	m->tsigctx = NULL;
413 	m->sigstart = -1;
414 	m->sig0key = NULL;
415 	m->sig0status = dns_rcode_noerror;
416 	m->timeadjust = 0;
417 }
418 
419 /*
420  * Init elements to default state.  Used both when allocating a new element
421  * and when resetting one.
422  */
423 static void
424 msginit(dns_message_t *m) {
425 	msginitheader(m);
426 	msginitprivate(m);
427 	msginittsig(m);
428 	m->header_ok = 0;
429 	m->question_ok = 0;
430 	m->tcp_continuation = 0;
431 	m->verified_sig = 0;
432 	m->verify_attempted = 0;
433 	m->order = NULL;
434 	m->order_arg.env = NULL;
435 	m->order_arg.acl = NULL;
436 	m->order_arg.element = NULL;
437 	m->query.base = NULL;
438 	m->query.length = 0;
439 	m->free_query = 0;
440 	m->saved.base = NULL;
441 	m->saved.length = 0;
442 	m->free_saved = 0;
443 	m->cc_ok = 0;
444 	m->cc_bad = 0;
445 	m->tkey = 0;
446 	m->rdclass_set = 0;
447 	m->querytsig = NULL;
448 	m->indent.string = "\t";
449 	m->indent.count = 0;
450 }
451 
452 static void
453 msgresetnames(dns_message_t *msg, unsigned int first_section) {
454 	unsigned int i;
455 	dns_name_t *name, *next_name;
456 	dns_rdataset_t *rds, *next_rds;
457 
458 	/*
459 	 * Clean up name lists by calling the rdataset disassociate function.
460 	 */
461 	for (i = first_section; i < DNS_SECTION_MAX; i++) {
462 		name = ISC_LIST_HEAD(msg->sections[i]);
463 		while (name != NULL) {
464 			next_name = ISC_LIST_NEXT(name, link);
465 			ISC_LIST_UNLINK(msg->sections[i], name, link);
466 
467 			rds = ISC_LIST_HEAD(name->list);
468 			while (rds != NULL) {
469 				next_rds = ISC_LIST_NEXT(rds, link);
470 				ISC_LIST_UNLINK(name->list, rds, link);
471 
472 				INSIST(dns_rdataset_isassociated(rds));
473 				dns_rdataset_disassociate(rds);
474 				isc_mempool_put(msg->rdspool, rds);
475 				rds = next_rds;
476 			}
477 			dns_message_puttempname(msg, &name);
478 			name = next_name;
479 		}
480 	}
481 }
482 
483 static void
484 msgresetopt(dns_message_t *msg) {
485 	if (msg->opt != NULL) {
486 		if (msg->opt_reserved > 0) {
487 			dns_message_renderrelease(msg, msg->opt_reserved);
488 			msg->opt_reserved = 0;
489 		}
490 		INSIST(dns_rdataset_isassociated(msg->opt));
491 		dns_rdataset_disassociate(msg->opt);
492 		isc_mempool_put(msg->rdspool, msg->opt);
493 		msg->opt = NULL;
494 		msg->cc_ok = 0;
495 		msg->cc_bad = 0;
496 	}
497 }
498 
499 static void
500 msgresetsigs(dns_message_t *msg, bool replying) {
501 	if (msg->sig_reserved > 0) {
502 		dns_message_renderrelease(msg, msg->sig_reserved);
503 		msg->sig_reserved = 0;
504 	}
505 	if (msg->tsig != NULL) {
506 		INSIST(dns_rdataset_isassociated(msg->tsig));
507 		INSIST(msg->namepool != NULL);
508 		if (replying) {
509 			INSIST(msg->querytsig == NULL);
510 			msg->querytsig = msg->tsig;
511 		} else {
512 			dns_rdataset_disassociate(msg->tsig);
513 			isc_mempool_put(msg->rdspool, msg->tsig);
514 			msg->tsig = NULL;
515 			if (msg->querytsig != NULL) {
516 				dns_rdataset_disassociate(msg->querytsig);
517 				isc_mempool_put(msg->rdspool, msg->querytsig);
518 				msg->querytsig = NULL;
519 			}
520 		}
521 		dns_message_puttempname(msg, &msg->tsigname);
522 		msg->tsig = NULL;
523 	} else if (msg->querytsig != NULL && !replying) {
524 		dns_rdataset_disassociate(msg->querytsig);
525 		isc_mempool_put(msg->rdspool, msg->querytsig);
526 		msg->querytsig = NULL;
527 	}
528 	if (msg->sig0 != NULL) {
529 		INSIST(dns_rdataset_isassociated(msg->sig0));
530 		dns_rdataset_disassociate(msg->sig0);
531 		isc_mempool_put(msg->rdspool, msg->sig0);
532 		if (msg->sig0name != NULL) {
533 			dns_message_puttempname(msg, &msg->sig0name);
534 		}
535 		msg->sig0 = NULL;
536 		msg->sig0name = NULL;
537 	}
538 }
539 
540 /*
541  * Free all but one (or everything) for this message.  This is used by
542  * both dns_message_reset() and dns__message_destroy().
543  */
544 static void
545 msgreset(dns_message_t *msg, bool everything) {
546 	dns_msgblock_t *msgblock, *next_msgblock;
547 	isc_buffer_t *dynbuf, *next_dynbuf;
548 	dns_rdata_t *rdata;
549 	dns_rdatalist_t *rdatalist;
550 
551 	msgresetnames(msg, 0);
552 	msgresetopt(msg);
553 	msgresetsigs(msg, false);
554 
555 	/*
556 	 * Clean up linked lists.
557 	 */
558 
559 	/*
560 	 * Run through the free lists, and just unlink anything found there.
561 	 * The memory isn't lost since these are part of message blocks we
562 	 * have allocated.
563 	 */
564 	rdata = ISC_LIST_HEAD(msg->freerdata);
565 	while (rdata != NULL) {
566 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
567 		rdata = ISC_LIST_HEAD(msg->freerdata);
568 	}
569 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
570 	while (rdatalist != NULL) {
571 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
572 		rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
573 	}
574 
575 	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
576 	INSIST(dynbuf != NULL);
577 	if (!everything) {
578 		isc_buffer_clear(dynbuf);
579 		dynbuf = ISC_LIST_NEXT(dynbuf, link);
580 	}
581 	while (dynbuf != NULL) {
582 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
583 		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
584 		isc_buffer_free(&dynbuf);
585 		dynbuf = next_dynbuf;
586 	}
587 
588 	msgblock = ISC_LIST_HEAD(msg->rdatas);
589 	if (!everything && msgblock != NULL) {
590 		msgblock_reset(msgblock);
591 		msgblock = ISC_LIST_NEXT(msgblock, link);
592 	}
593 	while (msgblock != NULL) {
594 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
595 		ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
596 		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
597 		msgblock = next_msgblock;
598 	}
599 
600 	/*
601 	 * rdatalists could be empty.
602 	 */
603 
604 	msgblock = ISC_LIST_HEAD(msg->rdatalists);
605 	if (!everything && msgblock != NULL) {
606 		msgblock_reset(msgblock);
607 		msgblock = ISC_LIST_NEXT(msgblock, link);
608 	}
609 	while (msgblock != NULL) {
610 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
611 		ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
612 		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
613 		msgblock = next_msgblock;
614 	}
615 
616 	msgblock = ISC_LIST_HEAD(msg->offsets);
617 	if (!everything && msgblock != NULL) {
618 		msgblock_reset(msgblock);
619 		msgblock = ISC_LIST_NEXT(msgblock, link);
620 	}
621 	while (msgblock != NULL) {
622 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
623 		ISC_LIST_UNLINK(msg->offsets, msgblock, link);
624 		msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
625 		msgblock = next_msgblock;
626 	}
627 
628 	if (msg->tsigkey != NULL) {
629 		dns_tsigkey_detach(&msg->tsigkey);
630 		msg->tsigkey = NULL;
631 	}
632 
633 	if (msg->tsigctx != NULL) {
634 		dst_context_destroy(&msg->tsigctx);
635 	}
636 
637 	if (msg->query.base != NULL) {
638 		if (msg->free_query != 0) {
639 			isc_mem_put(msg->mctx, msg->query.base,
640 				    msg->query.length);
641 		}
642 		msg->query.base = NULL;
643 		msg->query.length = 0;
644 	}
645 
646 	if (msg->saved.base != NULL) {
647 		if (msg->free_saved != 0) {
648 			isc_mem_put(msg->mctx, msg->saved.base,
649 				    msg->saved.length);
650 		}
651 		msg->saved.base = NULL;
652 		msg->saved.length = 0;
653 	}
654 
655 	/*
656 	 * cleanup the buffer cleanup list
657 	 */
658 	dynbuf = ISC_LIST_HEAD(msg->cleanup);
659 	while (dynbuf != NULL) {
660 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
661 		ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
662 		isc_buffer_free(&dynbuf);
663 		dynbuf = next_dynbuf;
664 	}
665 
666 	/*
667 	 * Set other bits to normal default values.
668 	 */
669 	if (!everything) {
670 		msginit(msg);
671 	}
672 
673 	ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
674 	ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
675 }
676 
677 static unsigned int
678 spacefortsig(dns_tsigkey_t *key, int otherlen) {
679 	isc_region_t r1, r2;
680 	unsigned int x;
681 	isc_result_t result;
682 
683 	/*
684 	 * The space required for an TSIG record is:
685 	 *
686 	 *	n1 bytes for the name
687 	 *	2 bytes for the type
688 	 *	2 bytes for the class
689 	 *	4 bytes for the ttl
690 	 *	2 bytes for the rdlength
691 	 *	n2 bytes for the algorithm name
692 	 *	6 bytes for the time signed
693 	 *	2 bytes for the fudge
694 	 *	2 bytes for the MAC size
695 	 *	x bytes for the MAC
696 	 *	2 bytes for the original id
697 	 *	2 bytes for the error
698 	 *	2 bytes for the other data length
699 	 *	y bytes for the other data (at most)
700 	 * ---------------------------------
701 	 *     26 + n1 + n2 + x + y bytes
702 	 */
703 
704 	dns_name_toregion(&key->name, &r1);
705 	dns_name_toregion(key->algorithm, &r2);
706 	if (key->key == NULL) {
707 		x = 0;
708 	} else {
709 		result = dst_key_sigsize(key->key, &x);
710 		if (result != ISC_R_SUCCESS) {
711 			x = 0;
712 		}
713 	}
714 	return (26 + r1.length + r2.length + x + otherlen);
715 }
716 
717 void
718 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp) {
719 	dns_message_t *m = NULL;
720 	isc_buffer_t *dynbuf = NULL;
721 	unsigned int i;
722 
723 	REQUIRE(mctx != NULL);
724 	REQUIRE(msgp != NULL);
725 	REQUIRE(*msgp == NULL);
726 	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE ||
727 		intent == DNS_MESSAGE_INTENTRENDER);
728 
729 	m = isc_mem_get(mctx, sizeof(dns_message_t));
730 	*m = (dns_message_t){ .from_to_wire = intent };
731 	isc_mem_attach(mctx, &m->mctx);
732 	msginit(m);
733 
734 	for (i = 0; i < DNS_SECTION_MAX; i++) {
735 		ISC_LIST_INIT(m->sections[i]);
736 	}
737 
738 	ISC_LIST_INIT(m->scratchpad);
739 	ISC_LIST_INIT(m->cleanup);
740 	ISC_LIST_INIT(m->rdatas);
741 	ISC_LIST_INIT(m->rdatalists);
742 	ISC_LIST_INIT(m->offsets);
743 	ISC_LIST_INIT(m->freerdata);
744 	ISC_LIST_INIT(m->freerdatalist);
745 
746 	isc_mempool_create(m->mctx, sizeof(dns_fixedname_t), &m->namepool);
747 	isc_mempool_setfillcount(m->namepool, NAME_FILLCOUNT);
748 	isc_mempool_setfreemax(m->namepool, NAME_FREEMAX);
749 	isc_mempool_setname(m->namepool, "msg:names");
750 
751 	isc_mempool_create(m->mctx, sizeof(dns_rdataset_t), &m->rdspool);
752 	isc_mempool_setfillcount(m->rdspool, RDATASET_FILLCOUNT);
753 	isc_mempool_setfreemax(m->rdspool, RDATASET_FREEMAX);
754 	isc_mempool_setname(m->rdspool, "msg:rdataset");
755 
756 	isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
757 	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
758 
759 	isc_refcount_init(&m->refcount, 1);
760 	m->magic = DNS_MESSAGE_MAGIC;
761 
762 	*msgp = m;
763 }
764 
765 void
766 dns_message_reset(dns_message_t *msg, unsigned int intent) {
767 	REQUIRE(DNS_MESSAGE_VALID(msg));
768 	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE ||
769 		intent == DNS_MESSAGE_INTENTRENDER);
770 
771 	msgreset(msg, false);
772 	msg->from_to_wire = intent;
773 }
774 
775 static void
776 dns__message_destroy(dns_message_t *msg) {
777 	REQUIRE(msg != NULL);
778 	REQUIRE(DNS_MESSAGE_VALID(msg));
779 
780 	msgreset(msg, true);
781 	isc_mempool_destroy(&msg->namepool);
782 	isc_mempool_destroy(&msg->rdspool);
783 	isc_refcount_destroy(&msg->refcount);
784 	msg->magic = 0;
785 	isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
786 }
787 
788 void
789 dns_message_attach(dns_message_t *source, dns_message_t **target) {
790 	REQUIRE(DNS_MESSAGE_VALID(source));
791 
792 	isc_refcount_increment(&source->refcount);
793 	*target = source;
794 }
795 
796 void
797 dns_message_detach(dns_message_t **messagep) {
798 	REQUIRE(messagep != NULL && DNS_MESSAGE_VALID(*messagep));
799 	dns_message_t *msg = *messagep;
800 	*messagep = NULL;
801 
802 	if (isc_refcount_decrement(&msg->refcount) == 1) {
803 		dns__message_destroy(msg);
804 	}
805 }
806 
807 static isc_result_t
808 name_hash_add(isc_ht_t *ht, dns_name_t *name, dns_name_t **foundp) {
809 	isc_result_t result = isc_ht_find(ht, name->ndata, name->length,
810 					  (void **)foundp);
811 	if (result == ISC_R_SUCCESS) {
812 		return (ISC_R_EXISTS);
813 	}
814 	result = isc_ht_add(ht, name->ndata, name->length, (void *)name);
815 	INSIST(result == ISC_R_SUCCESS);
816 	return (ISC_R_SUCCESS);
817 }
818 
819 static isc_result_t
820 findname(dns_name_t **foundname, const dns_name_t *target,
821 	 dns_namelist_t *section) {
822 	dns_name_t *curr;
823 
824 	for (curr = ISC_LIST_TAIL(*section); curr != NULL;
825 	     curr = ISC_LIST_PREV(curr, link))
826 	{
827 		if (dns_name_equal(curr, target)) {
828 			if (foundname != NULL) {
829 				*foundname = curr;
830 			}
831 			return (ISC_R_SUCCESS);
832 		}
833 	}
834 
835 	return (ISC_R_NOTFOUND);
836 }
837 
838 typedef struct __attribute__((__packed__)) rds_key {
839 	dns_rdataclass_t rdclass;
840 	dns_rdatatype_t type;
841 	dns_rdatatype_t covers;
842 } rds_key_t;
843 
844 static isc_result_t
845 rds_hash_add(isc_ht_t *ht, dns_rdataset_t *rds, dns_rdataset_t **foundp) {
846 	rds_key_t key = { .rdclass = rds->rdclass,
847 			  .type = rds->type,
848 			  .covers = rds->covers };
849 	isc_result_t result = isc_ht_find(ht, (const unsigned char *)&key,
850 					  sizeof(key), (void **)foundp);
851 	if (result == ISC_R_SUCCESS) {
852 		return (ISC_R_EXISTS);
853 	}
854 	result = isc_ht_add(ht, (const unsigned char *)&key, sizeof(key),
855 			    (void *)rds);
856 	INSIST(result == ISC_R_SUCCESS);
857 	return (ISC_R_SUCCESS);
858 }
859 
860 isc_result_t
861 dns_message_findtype(const dns_name_t *name, dns_rdatatype_t type,
862 		     dns_rdatatype_t covers, dns_rdataset_t **rdataset) {
863 	dns_rdataset_t *curr;
864 
865 	REQUIRE(name != NULL);
866 	REQUIRE(rdataset == NULL || *rdataset == NULL);
867 
868 	for (curr = ISC_LIST_TAIL(name->list); curr != NULL;
869 	     curr = ISC_LIST_PREV(curr, link))
870 	{
871 		if (curr->type == type && curr->covers == covers) {
872 			if (ISC_UNLIKELY(rdataset != NULL)) {
873 				*rdataset = curr;
874 			}
875 			return (ISC_R_SUCCESS);
876 		}
877 	}
878 
879 	return (ISC_R_NOTFOUND);
880 }
881 
882 /*
883  * Read a name from buffer "source".
884  */
885 static isc_result_t
886 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
887 	dns_decompress_t *dctx) {
888 	isc_buffer_t *scratch;
889 	isc_result_t result;
890 	unsigned int tries;
891 
892 	scratch = currentbuffer(msg);
893 
894 	/*
895 	 * First try:  use current buffer.
896 	 * Second try:  allocate a new buffer and use that.
897 	 */
898 	tries = 0;
899 	while (tries < 2) {
900 		result = dns_name_fromwire(name, source, dctx, 0, scratch);
901 
902 		if (result == ISC_R_NOSPACE) {
903 			tries++;
904 
905 			result = newbuffer(msg, SCRATCHPAD_SIZE);
906 			if (result != ISC_R_SUCCESS) {
907 				return (result);
908 			}
909 
910 			scratch = currentbuffer(msg);
911 			dns_name_reset(name);
912 		} else {
913 			return (result);
914 		}
915 	}
916 
917 	UNREACHABLE();
918 }
919 
920 static isc_result_t
921 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
922 	 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
923 	 unsigned int rdatalen, dns_rdata_t *rdata) {
924 	isc_buffer_t *scratch;
925 	isc_result_t result;
926 	unsigned int tries;
927 	unsigned int trysize;
928 
929 	scratch = currentbuffer(msg);
930 
931 	isc_buffer_setactive(source, rdatalen);
932 
933 	/*
934 	 * First try:  use current buffer.
935 	 * Second try:  allocate a new buffer of size
936 	 *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
937 	 *     (the data will fit if it was not more than 50% compressed)
938 	 * Subsequent tries: double buffer size on each try.
939 	 */
940 	tries = 0;
941 	trysize = 0;
942 	/* XXX possibly change this to a while (tries < 2) loop */
943 	for (;;) {
944 		result = dns_rdata_fromwire(rdata, rdclass, rdtype, source,
945 					    dctx, 0, scratch);
946 
947 		if (result == ISC_R_NOSPACE) {
948 			if (tries == 0) {
949 				trysize = 2 * rdatalen;
950 				if (trysize < SCRATCHPAD_SIZE) {
951 					trysize = SCRATCHPAD_SIZE;
952 				}
953 			} else {
954 				INSIST(trysize != 0);
955 				if (trysize >= 65535) {
956 					return (ISC_R_NOSPACE);
957 				}
958 				/* XXX DNS_R_RRTOOLONG? */
959 				trysize *= 2;
960 			}
961 			tries++;
962 			result = newbuffer(msg, trysize);
963 			if (result != ISC_R_SUCCESS) {
964 				return (result);
965 			}
966 
967 			scratch = currentbuffer(msg);
968 		} else {
969 			return (result);
970 		}
971 	}
972 }
973 
974 #define DO_ERROR(r)                          \
975 	do {                                 \
976 		if (best_effort) {           \
977 			seen_problem = true; \
978 		} else {                     \
979 			result = r;          \
980 			goto cleanup;        \
981 		}                            \
982 	} while (0)
983 
984 static void
985 cleanup_name_hashmaps(dns_namelist_t *section) {
986 	dns_name_t *name = NULL;
987 	for (name = ISC_LIST_HEAD(*section); name != NULL;
988 	     name = ISC_LIST_NEXT(name, link))
989 	{
990 		if (name->ht != NULL) {
991 			isc_ht_destroy(&name->ht);
992 		}
993 	}
994 }
995 
996 static isc_result_t
997 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
998 	     unsigned int options) {
999 	isc_region_t r;
1000 	unsigned int count;
1001 	dns_name_t *name = NULL;
1002 	dns_name_t *name2 = NULL;
1003 	dns_rdataset_t *rdataset = NULL;
1004 	dns_rdatalist_t *rdatalist = NULL;
1005 	isc_result_t result = ISC_R_SUCCESS;
1006 	dns_rdatatype_t rdtype;
1007 	dns_rdataclass_t rdclass;
1008 	dns_namelist_t *section = &msg->sections[DNS_SECTION_QUESTION];
1009 	bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
1010 	bool seen_problem = false;
1011 	bool free_name = false;
1012 	bool free_ht = false;
1013 	isc_ht_t *name_map = NULL;
1014 
1015 	if (msg->counts[DNS_SECTION_QUESTION] > 1) {
1016 		isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE);
1017 	}
1018 
1019 	for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1020 		name = NULL;
1021 		result = dns_message_gettempname(msg, &name);
1022 		if (result != ISC_R_SUCCESS) {
1023 			goto cleanup;
1024 		}
1025 		name->offsets = (unsigned char *)newoffsets(msg);
1026 		free_name = true;
1027 
1028 		/*
1029 		 * Parse the name out of this packet.
1030 		 */
1031 		isc_buffer_remainingregion(source, &r);
1032 		isc_buffer_setactive(source, r.length);
1033 		result = getname(name, source, msg, dctx);
1034 		if (result != ISC_R_SUCCESS) {
1035 			goto cleanup;
1036 		}
1037 
1038 		/* If there is only one QNAME, skip the duplicity checks */
1039 		if (name_map == NULL) {
1040 			result = ISC_R_SUCCESS;
1041 			goto skip_name_check;
1042 		}
1043 
1044 		/*
1045 		 * Run through the section, looking to see if this name
1046 		 * is already there.  If it is found, put back the allocated
1047 		 * name since we no longer need it, and set our name pointer
1048 		 * to point to the name we found.
1049 		 */
1050 		result = name_hash_add(name_map, name, &name2);
1051 
1052 		/*
1053 		 * If it is the first name in the section, accept it.
1054 		 *
1055 		 * If it is not, but is not the same as the name already
1056 		 * in the question section, append to the section.  Note that
1057 		 * here in the question section this is illegal, so return
1058 		 * FORMERR.  In the future, check the opcode to see if
1059 		 * this should be legal or not.  In either case we no longer
1060 		 * need this name pointer.
1061 		 */
1062 	skip_name_check:
1063 		switch (result) {
1064 		case ISC_R_SUCCESS:
1065 			if (!ISC_LIST_EMPTY(*section)) {
1066 				DO_ERROR(DNS_R_FORMERR);
1067 			}
1068 			ISC_LIST_APPEND(*section, name, link);
1069 			break;
1070 		case ISC_R_EXISTS:
1071 			dns_message_puttempname(msg, &name);
1072 			name = name2;
1073 			name2 = NULL;
1074 			break;
1075 		default:
1076 			UNREACHABLE();
1077 		}
1078 
1079 		free_name = false;
1080 
1081 		/*
1082 		 * Get type and class.
1083 		 */
1084 		isc_buffer_remainingregion(source, &r);
1085 		if (r.length < 4) {
1086 			result = ISC_R_UNEXPECTEDEND;
1087 			goto cleanup;
1088 		}
1089 		rdtype = isc_buffer_getuint16(source);
1090 		rdclass = isc_buffer_getuint16(source);
1091 
1092 		/*
1093 		 * If this class is different than the one we already read,
1094 		 * this is an error.
1095 		 */
1096 		if (msg->rdclass_set == 0) {
1097 			msg->rdclass = rdclass;
1098 			msg->rdclass_set = 1;
1099 		} else if (msg->rdclass != rdclass) {
1100 			DO_ERROR(DNS_R_FORMERR);
1101 		}
1102 
1103 		/*
1104 		 * Is this a TKEY query?
1105 		 */
1106 		if (rdtype == dns_rdatatype_tkey) {
1107 			msg->tkey = 1;
1108 		}
1109 
1110 		/*
1111 		 * Allocate a new rdatalist.
1112 		 */
1113 		rdatalist = newrdatalist(msg);
1114 		if (rdatalist == NULL) {
1115 			result = ISC_R_NOMEMORY;
1116 			goto cleanup;
1117 		}
1118 		rdataset = isc_mempool_get(msg->rdspool);
1119 		if (rdataset == NULL) {
1120 			result = ISC_R_NOMEMORY;
1121 			goto cleanup;
1122 		}
1123 		dns_rdataset_init(rdataset);
1124 
1125 		/*
1126 		 * Convert rdatalist to rdataset, and attach the latter to
1127 		 * the name.
1128 		 */
1129 		rdatalist->type = rdtype;
1130 		rdatalist->rdclass = rdclass;
1131 
1132 		result = dns_rdatalist_tordataset(rdatalist, rdataset);
1133 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1134 
1135 		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1136 
1137 		/*
1138 		 * Skip the duplicity check for first rdataset
1139 		 */
1140 		if (ISC_LIST_EMPTY(name->list)) {
1141 			result = ISC_R_SUCCESS;
1142 			goto skip_rds_check;
1143 		}
1144 
1145 		/*
1146 		 * Can't ask the same question twice.
1147 		 */
1148 		if (name->ht == NULL) {
1149 			isc_ht_init(&name->ht, msg->mctx, 1,
1150 				    ISC_HT_CASE_SENSITIVE);
1151 			free_ht = true;
1152 
1153 			INSIST(ISC_LIST_HEAD(name->list) ==
1154 			       ISC_LIST_TAIL(name->list));
1155 
1156 			dns_rdataset_t *old_rdataset =
1157 				ISC_LIST_HEAD(name->list);
1158 
1159 			result = rds_hash_add(name->ht, old_rdataset, NULL);
1160 
1161 			INSIST(result == ISC_R_SUCCESS);
1162 		}
1163 		result = rds_hash_add(name->ht, rdataset, NULL);
1164 		if (result == ISC_R_EXISTS) {
1165 			DO_ERROR(DNS_R_FORMERR);
1166 		}
1167 
1168 	skip_rds_check:
1169 		ISC_LIST_APPEND(name->list, rdataset, link);
1170 
1171 		rdataset = NULL;
1172 	}
1173 
1174 	if (seen_problem) {
1175 		result = DNS_R_RECOVERABLE;
1176 	}
1177 
1178 cleanup:
1179 	if (rdataset != NULL) {
1180 		if (dns_rdataset_isassociated(rdataset)) {
1181 			dns_rdataset_disassociate(rdataset);
1182 		}
1183 		isc_mempool_put(msg->rdspool, rdataset);
1184 	}
1185 	if (free_name) {
1186 		dns_message_puttempname(msg, &name);
1187 	}
1188 
1189 	if (free_ht) {
1190 		cleanup_name_hashmaps(section);
1191 	}
1192 
1193 	if (name_map != NULL) {
1194 		isc_ht_destroy(&name_map);
1195 	}
1196 
1197 	return (result);
1198 }
1199 
1200 static bool
1201 update(dns_section_t section, dns_rdataclass_t rdclass) {
1202 	if (section == DNS_SECTION_PREREQUISITE) {
1203 		return (rdclass == dns_rdataclass_any ||
1204 			rdclass == dns_rdataclass_none);
1205 	}
1206 	if (section == DNS_SECTION_UPDATE) {
1207 		return (rdclass == dns_rdataclass_any);
1208 	}
1209 	return (false);
1210 }
1211 
1212 /*
1213  * Check to confirm that all DNSSEC records (DS, NSEC, NSEC3) have
1214  * covering RRSIGs.
1215  */
1216 static bool
1217 auth_signed(dns_namelist_t *section) {
1218 	dns_name_t *name;
1219 
1220 	for (name = ISC_LIST_HEAD(*section); name != NULL;
1221 	     name = ISC_LIST_NEXT(name, link))
1222 	{
1223 		int auth_dnssec = 0, auth_rrsig = 0;
1224 		dns_rdataset_t *rds;
1225 
1226 		for (rds = ISC_LIST_HEAD(name->list); rds != NULL;
1227 		     rds = ISC_LIST_NEXT(rds, link))
1228 		{
1229 			switch (rds->type) {
1230 			case dns_rdatatype_ds:
1231 				auth_dnssec |= 0x1;
1232 				break;
1233 			case dns_rdatatype_nsec:
1234 				auth_dnssec |= 0x2;
1235 				break;
1236 			case dns_rdatatype_nsec3:
1237 				auth_dnssec |= 0x4;
1238 				break;
1239 			case dns_rdatatype_rrsig:
1240 				break;
1241 			default:
1242 				continue;
1243 			}
1244 
1245 			switch (rds->covers) {
1246 			case dns_rdatatype_ds:
1247 				auth_rrsig |= 0x1;
1248 				break;
1249 			case dns_rdatatype_nsec:
1250 				auth_rrsig |= 0x2;
1251 				break;
1252 			case dns_rdatatype_nsec3:
1253 				auth_rrsig |= 0x4;
1254 				break;
1255 			default:
1256 				break;
1257 			}
1258 		}
1259 
1260 		if (auth_dnssec != auth_rrsig) {
1261 			return (false);
1262 		}
1263 	}
1264 
1265 	return (true);
1266 }
1267 
1268 static isc_result_t
1269 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1270 	   dns_section_t sectionid, unsigned int options) {
1271 	isc_region_t r;
1272 	unsigned int count, rdatalen;
1273 	dns_name_t *name = NULL;
1274 	dns_name_t *name2 = NULL;
1275 	dns_rdataset_t *rdataset = NULL;
1276 	dns_rdataset_t *found_rdataset = NULL;
1277 	dns_rdatalist_t *rdatalist = NULL;
1278 	isc_result_t result = ISC_R_SUCCESS;
1279 	dns_rdatatype_t rdtype, covers;
1280 	dns_rdataclass_t rdclass;
1281 	dns_rdata_t *rdata = NULL;
1282 	dns_ttl_t ttl;
1283 	dns_namelist_t *section = &msg->sections[sectionid];
1284 	bool free_name = false, seen_problem = false;
1285 	bool free_ht = false;
1286 	bool preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0);
1287 	bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
1288 	bool isedns, issigzero, istsig;
1289 	isc_ht_t *name_map = NULL;
1290 
1291 	if (msg->counts[sectionid] > 1) {
1292 		isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE);
1293 	}
1294 
1295 	for (count = 0; count < msg->counts[sectionid]; count++) {
1296 		int recstart = source->current;
1297 		bool skip_name_search, skip_type_search;
1298 
1299 		skip_name_search = false;
1300 		skip_type_search = false;
1301 		isedns = false;
1302 		issigzero = false;
1303 		istsig = false;
1304 		found_rdataset = NULL;
1305 
1306 		name = NULL;
1307 		result = dns_message_gettempname(msg, &name);
1308 		if (result != ISC_R_SUCCESS) {
1309 			goto cleanup;
1310 		}
1311 		name->offsets = (unsigned char *)newoffsets(msg);
1312 		free_name = true;
1313 
1314 		/*
1315 		 * Parse the name out of this packet.
1316 		 */
1317 		isc_buffer_remainingregion(source, &r);
1318 		isc_buffer_setactive(source, r.length);
1319 		result = getname(name, source, msg, dctx);
1320 		if (result != ISC_R_SUCCESS) {
1321 			goto cleanup;
1322 		}
1323 
1324 		/*
1325 		 * Get type, class, ttl, and rdatalen.  Verify that at least
1326 		 * rdatalen bytes remain.  (Some of this is deferred to
1327 		 * later.)
1328 		 */
1329 		isc_buffer_remainingregion(source, &r);
1330 		if (r.length < 2 + 2 + 4 + 2) {
1331 			result = ISC_R_UNEXPECTEDEND;
1332 			goto cleanup;
1333 		}
1334 		rdtype = isc_buffer_getuint16(source);
1335 		rdclass = isc_buffer_getuint16(source);
1336 
1337 		/*
1338 		 * If there was no question section, we may not yet have
1339 		 * established a class.  Do so now.
1340 		 */
1341 		if (msg->rdclass_set == 0 &&
1342 		    rdtype != dns_rdatatype_opt &&  /* class is UDP SIZE */
1343 		    rdtype != dns_rdatatype_tsig && /* class is ANY */
1344 		    rdtype != dns_rdatatype_tkey)   /* class is undefined */
1345 		{
1346 			msg->rdclass = rdclass;
1347 			msg->rdclass_set = 1;
1348 		}
1349 
1350 		/*
1351 		 * If this class is different than the one in the question
1352 		 * section, bail.
1353 		 */
1354 		if (msg->opcode != dns_opcode_update &&
1355 		    rdtype != dns_rdatatype_tsig &&
1356 		    rdtype != dns_rdatatype_opt &&
1357 		    rdtype != dns_rdatatype_key &&  /* in a TKEY query */
1358 		    rdtype != dns_rdatatype_sig &&  /* SIG(0) */
1359 		    rdtype != dns_rdatatype_tkey && /* Win2000 TKEY */
1360 		    msg->rdclass != dns_rdataclass_any &&
1361 		    msg->rdclass != rdclass)
1362 		{
1363 			DO_ERROR(DNS_R_FORMERR);
1364 		}
1365 
1366 		/*
1367 		 * If this is not a TKEY query/response then the KEY
1368 		 * record's class needs to match.
1369 		 */
1370 		if (msg->opcode != dns_opcode_update && !msg->tkey &&
1371 		    rdtype == dns_rdatatype_key &&
1372 		    msg->rdclass != dns_rdataclass_any &&
1373 		    msg->rdclass != rdclass)
1374 		{
1375 			DO_ERROR(DNS_R_FORMERR);
1376 		}
1377 
1378 		/*
1379 		 * Special type handling for TSIG, OPT, and TKEY.
1380 		 */
1381 		if (rdtype == dns_rdatatype_tsig) {
1382 			/*
1383 			 * If it is a tsig, verify that it is in the
1384 			 * additional data section.
1385 			 */
1386 			if (sectionid != DNS_SECTION_ADDITIONAL ||
1387 			    rdclass != dns_rdataclass_any ||
1388 			    count != msg->counts[sectionid] - 1)
1389 			{
1390 				DO_ERROR(DNS_R_BADTSIG);
1391 			} else {
1392 				skip_name_search = true;
1393 				skip_type_search = true;
1394 				istsig = true;
1395 			}
1396 		} else if (rdtype == dns_rdatatype_opt) {
1397 			/*
1398 			 * The name of an OPT record must be ".", it
1399 			 * must be in the additional data section, and
1400 			 * it must be the first OPT we've seen.
1401 			 */
1402 			if (!dns_name_equal(dns_rootname, name) ||
1403 			    sectionid != DNS_SECTION_ADDITIONAL ||
1404 			    msg->opt != NULL)
1405 			{
1406 				DO_ERROR(DNS_R_FORMERR);
1407 			} else {
1408 				skip_name_search = true;
1409 				skip_type_search = true;
1410 				isedns = true;
1411 			}
1412 		} else if (rdtype == dns_rdatatype_tkey) {
1413 			/*
1414 			 * A TKEY must be in the additional section if this
1415 			 * is a query, and the answer section if this is a
1416 			 * response.  Unless it's a Win2000 client.
1417 			 *
1418 			 * Its class is ignored.
1419 			 */
1420 			dns_section_t tkeysection;
1421 
1422 			if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0) {
1423 				tkeysection = DNS_SECTION_ADDITIONAL;
1424 			} else {
1425 				tkeysection = DNS_SECTION_ANSWER;
1426 			}
1427 			if (sectionid != tkeysection &&
1428 			    sectionid != DNS_SECTION_ANSWER)
1429 			{
1430 				DO_ERROR(DNS_R_FORMERR);
1431 			}
1432 		}
1433 
1434 		/*
1435 		 * ... now get ttl and rdatalen, and check buffer.
1436 		 */
1437 		ttl = isc_buffer_getuint32(source);
1438 		rdatalen = isc_buffer_getuint16(source);
1439 		r.length -= (2 + 2 + 4 + 2);
1440 		if (r.length < rdatalen) {
1441 			result = ISC_R_UNEXPECTEDEND;
1442 			goto cleanup;
1443 		}
1444 
1445 		/*
1446 		 * Read the rdata from the wire format.  Interpret the
1447 		 * rdata according to its actual class, even if it had a
1448 		 * DynDNS meta-class in the packet (unless this is a TSIG).
1449 		 * Then put the meta-class back into the finished rdata.
1450 		 */
1451 		rdata = newrdata(msg);
1452 		if (msg->opcode == dns_opcode_update &&
1453 		    update(sectionid, rdclass))
1454 		{
1455 			if (rdatalen != 0) {
1456 				result = DNS_R_FORMERR;
1457 				goto cleanup;
1458 			}
1459 			/*
1460 			 * When the rdata is empty, the data pointer is
1461 			 * never dereferenced, but it must still be non-NULL.
1462 			 * Casting 1 rather than "" avoids warnings about
1463 			 * discarding the const attribute of a string,
1464 			 * for compilers that would warn about such things.
1465 			 */
1466 			rdata->data = (unsigned char *)1;
1467 			rdata->length = 0;
1468 			rdata->rdclass = rdclass;
1469 			rdata->type = rdtype;
1470 			rdata->flags = DNS_RDATA_UPDATE;
1471 			result = ISC_R_SUCCESS;
1472 		} else if (rdclass == dns_rdataclass_none &&
1473 			   msg->opcode == dns_opcode_update &&
1474 			   sectionid == DNS_SECTION_UPDATE)
1475 		{
1476 			result = getrdata(source, msg, dctx, msg->rdclass,
1477 					  rdtype, rdatalen, rdata);
1478 		} else {
1479 			result = getrdata(source, msg, dctx, rdclass, rdtype,
1480 					  rdatalen, rdata);
1481 		}
1482 		if (result != ISC_R_SUCCESS) {
1483 			goto cleanup;
1484 		}
1485 		rdata->rdclass = rdclass;
1486 		if (rdtype == dns_rdatatype_rrsig && rdata->flags == 0) {
1487 			covers = dns_rdata_covers(rdata);
1488 			if (covers == 0) {
1489 				DO_ERROR(DNS_R_FORMERR);
1490 			}
1491 		} else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1492 			   rdata->flags == 0)
1493 		{
1494 			covers = dns_rdata_covers(rdata);
1495 			if (covers == 0) {
1496 				if (sectionid != DNS_SECTION_ADDITIONAL ||
1497 				    count != msg->counts[sectionid] - 1)
1498 				{
1499 					DO_ERROR(DNS_R_BADSIG0);
1500 				} else {
1501 					skip_name_search = true;
1502 					skip_type_search = true;
1503 					issigzero = true;
1504 				}
1505 			} else {
1506 				if (msg->rdclass != dns_rdataclass_any &&
1507 				    msg->rdclass != rdclass)
1508 				{
1509 					DO_ERROR(DNS_R_FORMERR);
1510 				}
1511 			}
1512 		} else {
1513 			covers = 0;
1514 		}
1515 
1516 		/*
1517 		 * Check the ownername of NSEC3 records
1518 		 */
1519 		if (rdtype == dns_rdatatype_nsec3 &&
1520 		    !dns_rdata_checkowner(name, msg->rdclass, rdtype, false))
1521 		{
1522 			result = DNS_R_BADOWNERNAME;
1523 			goto cleanup;
1524 		}
1525 
1526 		/*
1527 		 * If we are doing a dynamic update or this is a meta-type,
1528 		 * don't bother searching for a name, just append this one
1529 		 * to the end of the message.
1530 		 */
1531 		if (preserve_order || msg->opcode == dns_opcode_update ||
1532 		    skip_name_search)
1533 		{
1534 			if (!isedns && !istsig && !issigzero) {
1535 				ISC_LIST_APPEND(*section, name, link);
1536 				free_name = false;
1537 			}
1538 		} else {
1539 			if (name_map == NULL) {
1540 				result = ISC_R_SUCCESS;
1541 				goto skip_name_check;
1542 			}
1543 
1544 			/*
1545 			 * Run through the section, looking to see if this name
1546 			 * is already there.  If it is found, put back the
1547 			 * allocated name since we no longer need it, and set
1548 			 * our name pointer to point to the name we found.
1549 			 */
1550 			result = name_hash_add(name_map, name, &name2);
1551 
1552 			/*
1553 			 * If it is a new name, append to the section.
1554 			 */
1555 		skip_name_check:
1556 			switch (result) {
1557 			case ISC_R_SUCCESS:
1558 				ISC_LIST_APPEND(*section, name, link);
1559 				break;
1560 			case ISC_R_EXISTS:
1561 				dns_message_puttempname(msg, &name);
1562 				name = name2;
1563 				name2 = NULL;
1564 				break;
1565 			default:
1566 				UNREACHABLE();
1567 			}
1568 			free_name = false;
1569 		}
1570 
1571 		rdatalist = newrdatalist(msg);
1572 		if (rdatalist == NULL) {
1573 			result = ISC_R_NOMEMORY;
1574 			goto cleanup;
1575 		}
1576 		dns_message_gettemprdataset(msg, &rdataset);
1577 		if (rdataset == NULL) {
1578 			result = ISC_R_NOMEMORY;
1579 			goto cleanup;
1580 		}
1581 
1582 		rdatalist->type = rdtype;
1583 		rdatalist->covers = covers;
1584 		rdatalist->rdclass = rdclass;
1585 		rdatalist->ttl = ttl;
1586 
1587 		RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1588 			      ISC_R_SUCCESS);
1589 		dns_rdataset_setownercase(rdataset, name);
1590 		rdatalist = NULL;
1591 
1592 		/*
1593 		 * Search name for the particular type and class.
1594 		 * Skip this stage if in update mode or this is a meta-type.
1595 		 */
1596 		if (isedns || istsig || issigzero) {
1597 			/* Skip adding the rdataset to the tables */
1598 		} else if (preserve_order || msg->opcode == dns_opcode_update ||
1599 			   skip_type_search)
1600 		{
1601 			result = ISC_R_SUCCESS;
1602 
1603 			ISC_LIST_APPEND(name->list, rdataset, link);
1604 		} else {
1605 			/*
1606 			 * If this is a type that can only occur in
1607 			 * the question section, fail.
1608 			 */
1609 			if (dns_rdatatype_questiononly(rdtype)) {
1610 				DO_ERROR(DNS_R_FORMERR);
1611 			}
1612 
1613 			if (ISC_LIST_EMPTY(name->list)) {
1614 				result = ISC_R_SUCCESS;
1615 				goto skip_rds_check;
1616 			}
1617 
1618 			if (name->ht == NULL) {
1619 				isc_ht_init(&name->ht, msg->mctx, 1,
1620 					    ISC_HT_CASE_SENSITIVE);
1621 				free_ht = true;
1622 
1623 				INSIST(ISC_LIST_HEAD(name->list) ==
1624 				       ISC_LIST_TAIL(name->list));
1625 
1626 				dns_rdataset_t *old_rdataset =
1627 					ISC_LIST_HEAD(name->list);
1628 
1629 				result = rds_hash_add(name->ht, old_rdataset,
1630 						      NULL);
1631 
1632 				INSIST(result == ISC_R_SUCCESS);
1633 			}
1634 			found_rdataset = NULL;
1635 			result = rds_hash_add(name->ht, rdataset,
1636 					      &found_rdataset);
1637 
1638 			/*
1639 			 * If we found an rdataset that matches, we need to
1640 			 * append this rdata to that set.  If we did not, we
1641 			 * need to create a new rdatalist, store the important
1642 			 * bits there, convert it to an rdataset, and link the
1643 			 * latter to the name. Yuck.  When appending, make
1644 			 * certain that the type isn't a singleton type, such as
1645 			 * SOA or CNAME.
1646 			 *
1647 			 * Note that this check will be bypassed when preserving
1648 			 * order, the opcode is an update, or the type search is
1649 			 * skipped.
1650 			 */
1651 		skip_rds_check:
1652 			switch (result) {
1653 			case ISC_R_EXISTS:
1654 				/* Free the rdataset we used as the key */
1655 				dns_rdataset_disassociate(rdataset);
1656 				isc_mempool_put(msg->rdspool, rdataset);
1657 				result = ISC_R_SUCCESS;
1658 				rdataset = found_rdataset;
1659 
1660 				if (!dns_rdatatype_issingleton(rdtype)) {
1661 					break;
1662 				}
1663 
1664 				dns_rdatalist_fromrdataset(rdataset,
1665 							   &rdatalist);
1666 				dns_rdata_t *first =
1667 					ISC_LIST_HEAD(rdatalist->rdata);
1668 				INSIST(first != NULL);
1669 				if (dns_rdata_compare(rdata, first) != 0) {
1670 					DO_ERROR(DNS_R_FORMERR);
1671 				}
1672 				break;
1673 			case ISC_R_SUCCESS:
1674 				ISC_LIST_APPEND(name->list, rdataset, link);
1675 				break;
1676 			default:
1677 				UNREACHABLE();
1678 			}
1679 		}
1680 
1681 		/*
1682 		 * Minimize TTLs.
1683 		 *
1684 		 * Section 5.2 of RFC2181 says we should drop
1685 		 * nonauthoritative rrsets where the TTLs differ, but we
1686 		 * currently treat them the as if they were authoritative and
1687 		 * minimize them.
1688 		 */
1689 		if (ttl != rdataset->ttl) {
1690 			rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1691 			if (ttl < rdataset->ttl) {
1692 				rdataset->ttl = ttl;
1693 			}
1694 		}
1695 
1696 		/* Append this rdata to the rdataset. */
1697 		dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1698 		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1699 
1700 		/*
1701 		 * If this is an OPT, SIG(0) or TSIG record, remember it.
1702 		 * Also, set the extended rcode for TSIG.
1703 		 *
1704 		 * Note msg->opt, msg->sig0 and msg->tsig will only be
1705 		 * already set if best-effort parsing is enabled otherwise
1706 		 * there will only be at most one of each.
1707 		 */
1708 		if (isedns) {
1709 			dns_rcode_t ercode;
1710 
1711 			msg->opt = rdataset;
1712 			ercode = (dns_rcode_t)((msg->opt->ttl &
1713 						DNS_MESSAGE_EDNSRCODE_MASK) >>
1714 					       20);
1715 			msg->rcode |= ercode;
1716 			dns_message_puttempname(msg, &name);
1717 			free_name = false;
1718 		} else if (issigzero) {
1719 			msg->sig0 = rdataset;
1720 			msg->sig0name = name;
1721 			msg->sigstart = recstart;
1722 			free_name = false;
1723 		} else if (istsig) {
1724 			msg->tsig = rdataset;
1725 			msg->tsigname = name;
1726 			msg->sigstart = recstart;
1727 			/*
1728 			 * Windows doesn't like TSIG names to be compressed.
1729 			 */
1730 			msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1731 			free_name = false;
1732 		}
1733 		rdataset = NULL;
1734 
1735 		if (seen_problem) {
1736 			if (free_name) {
1737 				dns_message_puttempname(msg, &name);
1738 			}
1739 			free_name = false;
1740 		}
1741 		INSIST(!free_name);
1742 	}
1743 
1744 	/*
1745 	 * If any of DS, NSEC or NSEC3 appeared in the
1746 	 * authority section of a query response without
1747 	 * a covering RRSIG, FORMERR
1748 	 */
1749 	if (sectionid == DNS_SECTION_AUTHORITY &&
1750 	    msg->opcode == dns_opcode_query &&
1751 	    ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) &&
1752 	    ((msg->flags & DNS_MESSAGEFLAG_TC) == 0) && !preserve_order &&
1753 	    !auth_signed(section))
1754 	{
1755 		DO_ERROR(DNS_R_FORMERR);
1756 	}
1757 
1758 	if (seen_problem) {
1759 		result = DNS_R_RECOVERABLE;
1760 	}
1761 
1762 cleanup:
1763 	if (rdataset != NULL && rdataset != found_rdataset) {
1764 		dns_rdataset_disassociate(rdataset);
1765 		isc_mempool_put(msg->rdspool, rdataset);
1766 	}
1767 	if (free_name) {
1768 		dns_message_puttempname(msg, &name);
1769 	}
1770 
1771 	if (free_ht) {
1772 		cleanup_name_hashmaps(section);
1773 	}
1774 
1775 	if (name_map != NULL) {
1776 		isc_ht_destroy(&name_map);
1777 	}
1778 
1779 	return (result);
1780 }
1781 
1782 isc_result_t
1783 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1784 		  unsigned int options) {
1785 	isc_region_t r;
1786 	dns_decompress_t dctx;
1787 	isc_result_t ret;
1788 	uint16_t tmpflags;
1789 	isc_buffer_t origsource;
1790 	bool seen_problem;
1791 	bool ignore_tc;
1792 
1793 	REQUIRE(DNS_MESSAGE_VALID(msg));
1794 	REQUIRE(source != NULL);
1795 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1796 
1797 	seen_problem = false;
1798 	ignore_tc = ((options & DNS_MESSAGEPARSE_IGNORETRUNCATION) != 0);
1799 
1800 	origsource = *source;
1801 
1802 	msg->header_ok = 0;
1803 	msg->question_ok = 0;
1804 
1805 	if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0) {
1806 		isc_buffer_usedregion(&origsource, &msg->saved);
1807 	} else {
1808 		msg->saved.length = isc_buffer_usedlength(&origsource);
1809 		msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1810 		memmove(msg->saved.base, isc_buffer_base(&origsource),
1811 			msg->saved.length);
1812 		msg->free_saved = 1;
1813 	}
1814 
1815 	isc_buffer_remainingregion(source, &r);
1816 	if (r.length < DNS_MESSAGE_HEADERLEN) {
1817 		return (ISC_R_UNEXPECTEDEND);
1818 	}
1819 
1820 	msg->id = isc_buffer_getuint16(source);
1821 	tmpflags = isc_buffer_getuint16(source);
1822 	msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK) >>
1823 		       DNS_MESSAGE_OPCODE_SHIFT);
1824 	msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1825 	msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1826 	msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1827 	msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1828 	msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1829 	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1830 
1831 	msg->header_ok = 1;
1832 	msg->state = DNS_SECTION_QUESTION;
1833 
1834 	/*
1835 	 * -1 means no EDNS.
1836 	 */
1837 	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1838 
1839 	dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1840 
1841 	ret = getquestions(source, msg, &dctx, options);
1842 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) {
1843 		goto truncated;
1844 	}
1845 	if (ret == DNS_R_RECOVERABLE) {
1846 		seen_problem = true;
1847 		ret = ISC_R_SUCCESS;
1848 	}
1849 	if (ret != ISC_R_SUCCESS) {
1850 		return (ret);
1851 	}
1852 	msg->question_ok = 1;
1853 
1854 	ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1855 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) {
1856 		goto truncated;
1857 	}
1858 	if (ret == DNS_R_RECOVERABLE) {
1859 		seen_problem = true;
1860 		ret = ISC_R_SUCCESS;
1861 	}
1862 	if (ret != ISC_R_SUCCESS) {
1863 		return (ret);
1864 	}
1865 
1866 	ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1867 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) {
1868 		goto truncated;
1869 	}
1870 	if (ret == DNS_R_RECOVERABLE) {
1871 		seen_problem = true;
1872 		ret = ISC_R_SUCCESS;
1873 	}
1874 	if (ret != ISC_R_SUCCESS) {
1875 		return (ret);
1876 	}
1877 
1878 	ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1879 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) {
1880 		goto truncated;
1881 	}
1882 	if (ret == DNS_R_RECOVERABLE) {
1883 		seen_problem = true;
1884 		ret = ISC_R_SUCCESS;
1885 	}
1886 	if (ret != ISC_R_SUCCESS) {
1887 		return (ret);
1888 	}
1889 
1890 	isc_buffer_remainingregion(source, &r);
1891 	if (r.length != 0) {
1892 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1893 			      DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1894 			      "message has %u byte(s) of trailing garbage",
1895 			      r.length);
1896 	}
1897 
1898 truncated:
1899 
1900 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) {
1901 		return (DNS_R_RECOVERABLE);
1902 	}
1903 	if (seen_problem) {
1904 		return (DNS_R_RECOVERABLE);
1905 	}
1906 	return (ISC_R_SUCCESS);
1907 }
1908 
1909 isc_result_t
1910 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1911 			isc_buffer_t *buffer) {
1912 	isc_region_t r;
1913 
1914 	REQUIRE(DNS_MESSAGE_VALID(msg));
1915 	REQUIRE(buffer != NULL);
1916 	REQUIRE(msg->buffer == NULL);
1917 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1918 
1919 	msg->cctx = cctx;
1920 
1921 	/*
1922 	 * Erase the contents of this buffer.
1923 	 */
1924 	isc_buffer_clear(buffer);
1925 
1926 	/*
1927 	 * Make certain there is enough for at least the header in this
1928 	 * buffer.
1929 	 */
1930 	isc_buffer_availableregion(buffer, &r);
1931 	if (r.length < DNS_MESSAGE_HEADERLEN) {
1932 		return (ISC_R_NOSPACE);
1933 	}
1934 
1935 	if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved) {
1936 		return (ISC_R_NOSPACE);
1937 	}
1938 
1939 	/*
1940 	 * Reserve enough space for the header in this buffer.
1941 	 */
1942 	isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1943 
1944 	msg->buffer = buffer;
1945 
1946 	return (ISC_R_SUCCESS);
1947 }
1948 
1949 isc_result_t
1950 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1951 	isc_region_t r, rn;
1952 
1953 	REQUIRE(DNS_MESSAGE_VALID(msg));
1954 	REQUIRE(buffer != NULL);
1955 	REQUIRE(msg->buffer != NULL);
1956 
1957 	/*
1958 	 * Ensure that the new buffer is empty, and has enough space to
1959 	 * hold the current contents.
1960 	 */
1961 	isc_buffer_clear(buffer);
1962 
1963 	isc_buffer_availableregion(buffer, &rn);
1964 	isc_buffer_usedregion(msg->buffer, &r);
1965 	REQUIRE(rn.length > r.length);
1966 
1967 	/*
1968 	 * Copy the contents from the old to the new buffer.
1969 	 */
1970 	isc_buffer_add(buffer, r.length);
1971 	memmove(rn.base, r.base, r.length);
1972 
1973 	msg->buffer = buffer;
1974 
1975 	return (ISC_R_SUCCESS);
1976 }
1977 
1978 void
1979 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1980 	REQUIRE(DNS_MESSAGE_VALID(msg));
1981 	REQUIRE(space <= msg->reserved);
1982 
1983 	msg->reserved -= space;
1984 }
1985 
1986 isc_result_t
1987 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1988 	isc_region_t r;
1989 
1990 	REQUIRE(DNS_MESSAGE_VALID(msg));
1991 
1992 	if (msg->buffer != NULL) {
1993 		isc_buffer_availableregion(msg->buffer, &r);
1994 		if (r.length < (space + msg->reserved)) {
1995 			return (ISC_R_NOSPACE);
1996 		}
1997 	}
1998 
1999 	msg->reserved += space;
2000 
2001 	return (ISC_R_SUCCESS);
2002 }
2003 
2004 static bool
2005 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
2006 	int pass_needed;
2007 
2008 	/*
2009 	 * If we are not rendering class IN, this ordering is bogus.
2010 	 */
2011 	if (rds->rdclass != dns_rdataclass_in) {
2012 		return (false);
2013 	}
2014 
2015 	switch (rds->type) {
2016 	case dns_rdatatype_a:
2017 	case dns_rdatatype_aaaa:
2018 		if (preferred_glue == rds->type) {
2019 			pass_needed = 4;
2020 		} else {
2021 			pass_needed = 3;
2022 		}
2023 		break;
2024 	case dns_rdatatype_rrsig:
2025 	case dns_rdatatype_dnskey:
2026 		pass_needed = 2;
2027 		break;
2028 	default:
2029 		pass_needed = 1;
2030 	}
2031 
2032 	if (pass_needed >= pass) {
2033 		return (false);
2034 	}
2035 
2036 	return (true);
2037 }
2038 
2039 static isc_result_t
2040 renderset(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
2041 	  dns_compress_t *cctx, isc_buffer_t *target, unsigned int reserved,
2042 	  unsigned int options, unsigned int *countp) {
2043 	isc_result_t result;
2044 
2045 	/*
2046 	 * Shrink the space in the buffer by the reserved amount.
2047 	 */
2048 	if (target->length - target->used < reserved) {
2049 		return (ISC_R_NOSPACE);
2050 	}
2051 
2052 	target->length -= reserved;
2053 	result = dns_rdataset_towire(rdataset, owner_name, cctx, target,
2054 				     options, countp);
2055 	target->length += reserved;
2056 
2057 	return (result);
2058 }
2059 
2060 static void
2061 maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) {
2062 	if (msg->counts[sectionid] == 0 &&
2063 	    (sectionid == DNS_SECTION_ANSWER ||
2064 	     (sectionid == DNS_SECTION_AUTHORITY &&
2065 	      msg->counts[DNS_SECTION_ANSWER] == 0)))
2066 	{
2067 		msg->flags &= ~DNS_MESSAGEFLAG_AD;
2068 	}
2069 }
2070 
2071 isc_result_t
2072 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
2073 			  unsigned int options) {
2074 	dns_namelist_t *section;
2075 	dns_name_t *name, *next_name;
2076 	dns_rdataset_t *rdataset, *next_rdataset;
2077 	unsigned int count, total;
2078 	isc_result_t result;
2079 	isc_buffer_t st; /* for rollbacks */
2080 	int pass;
2081 	bool partial = false;
2082 	unsigned int rd_options;
2083 	dns_rdatatype_t preferred_glue = 0;
2084 
2085 	REQUIRE(DNS_MESSAGE_VALID(msg));
2086 	REQUIRE(msg->buffer != NULL);
2087 	REQUIRE(VALID_NAMED_SECTION(sectionid));
2088 
2089 	section = &msg->sections[sectionid];
2090 
2091 	if ((sectionid == DNS_SECTION_ADDITIONAL) &&
2092 	    (options & DNS_MESSAGERENDER_ORDERED) == 0)
2093 	{
2094 		if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
2095 			preferred_glue = dns_rdatatype_a;
2096 			pass = 4;
2097 		} else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
2098 			preferred_glue = dns_rdatatype_aaaa;
2099 			pass = 4;
2100 		} else {
2101 			pass = 3;
2102 		}
2103 	} else {
2104 		pass = 1;
2105 	}
2106 
2107 	if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0) {
2108 		rd_options = 0;
2109 	} else {
2110 		rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
2111 	}
2112 
2113 	/*
2114 	 * Shrink the space in the buffer by the reserved amount.
2115 	 */
2116 	if (msg->buffer->length - msg->buffer->used < msg->reserved) {
2117 		return (ISC_R_NOSPACE);
2118 	}
2119 	msg->buffer->length -= msg->reserved;
2120 
2121 	total = 0;
2122 	if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0) {
2123 		partial = true;
2124 	}
2125 
2126 	/*
2127 	 * Render required glue first.  Set TC if it won't fit.
2128 	 */
2129 	name = ISC_LIST_HEAD(*section);
2130 	if (name != NULL) {
2131 		rdataset = ISC_LIST_HEAD(name->list);
2132 		if (rdataset != NULL &&
2133 		    (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) !=
2134 			    0 &&
2135 		    (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0)
2136 		{
2137 			const void *order_arg = &msg->order_arg;
2138 			st = *(msg->buffer);
2139 			count = 0;
2140 			if (partial) {
2141 				result = dns_rdataset_towirepartial(
2142 					rdataset, name, msg->cctx, msg->buffer,
2143 					msg->order, order_arg, rd_options,
2144 					&count, NULL);
2145 			} else {
2146 				result = dns_rdataset_towiresorted(
2147 					rdataset, name, msg->cctx, msg->buffer,
2148 					msg->order, order_arg, rd_options,
2149 					&count);
2150 			}
2151 			total += count;
2152 			if (partial && result == ISC_R_NOSPACE) {
2153 				msg->flags |= DNS_MESSAGEFLAG_TC;
2154 				msg->buffer->length += msg->reserved;
2155 				msg->counts[sectionid] += total;
2156 				return (result);
2157 			}
2158 			if (result == ISC_R_NOSPACE) {
2159 				msg->flags |= DNS_MESSAGEFLAG_TC;
2160 			}
2161 			if (result != ISC_R_SUCCESS) {
2162 				INSIST(st.used < 65536);
2163 				dns_compress_rollback(msg->cctx,
2164 						      (uint16_t)st.used);
2165 				*(msg->buffer) = st; /* rollback */
2166 				msg->buffer->length += msg->reserved;
2167 				msg->counts[sectionid] += total;
2168 				return (result);
2169 			}
2170 			rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
2171 		}
2172 	}
2173 
2174 	do {
2175 		name = ISC_LIST_HEAD(*section);
2176 		if (name == NULL) {
2177 			msg->buffer->length += msg->reserved;
2178 			msg->counts[sectionid] += total;
2179 			return (ISC_R_SUCCESS);
2180 		}
2181 
2182 		while (name != NULL) {
2183 			next_name = ISC_LIST_NEXT(name, link);
2184 
2185 			rdataset = ISC_LIST_HEAD(name->list);
2186 			while (rdataset != NULL) {
2187 				next_rdataset = ISC_LIST_NEXT(rdataset, link);
2188 
2189 				if ((rdataset->attributes &
2190 				     DNS_RDATASETATTR_RENDERED) != 0)
2191 				{
2192 					goto next;
2193 				}
2194 
2195 				if (((options & DNS_MESSAGERENDER_ORDERED) ==
2196 				     0) &&
2197 				    (sectionid == DNS_SECTION_ADDITIONAL) &&
2198 				    wrong_priority(rdataset, pass,
2199 						   preferred_glue))
2200 				{
2201 					goto next;
2202 				}
2203 
2204 				st = *(msg->buffer);
2205 
2206 				count = 0;
2207 				if (partial) {
2208 					result = dns_rdataset_towirepartial(
2209 						rdataset, name, msg->cctx,
2210 						msg->buffer, msg->order,
2211 						&msg->order_arg, rd_options,
2212 						&count, NULL);
2213 				} else {
2214 					result = dns_rdataset_towiresorted(
2215 						rdataset, name, msg->cctx,
2216 						msg->buffer, msg->order,
2217 						&msg->order_arg, rd_options,
2218 						&count);
2219 				}
2220 
2221 				total += count;
2222 
2223 				/*
2224 				 * If out of space, record stats on what we
2225 				 * rendered so far, and return that status.
2226 				 *
2227 				 * XXXMLG Need to change this when
2228 				 * dns_rdataset_towire() can render partial
2229 				 * sets starting at some arbitrary point in the
2230 				 * set.  This will include setting a bit in the
2231 				 * rdataset to indicate that a partial
2232 				 * rendering was done, and some state saved
2233 				 * somewhere (probably in the message struct)
2234 				 * to indicate where to continue from.
2235 				 */
2236 				if (partial && result == ISC_R_NOSPACE) {
2237 					msg->buffer->length += msg->reserved;
2238 					msg->counts[sectionid] += total;
2239 					return (result);
2240 				}
2241 				if (result != ISC_R_SUCCESS) {
2242 					INSIST(st.used < 65536);
2243 					dns_compress_rollback(
2244 						msg->cctx, (uint16_t)st.used);
2245 					*(msg->buffer) = st; /* rollback */
2246 					msg->buffer->length += msg->reserved;
2247 					msg->counts[sectionid] += total;
2248 					maybe_clear_ad(msg, sectionid);
2249 					return (result);
2250 				}
2251 
2252 				/*
2253 				 * If we have rendered non-validated data,
2254 				 * ensure that the AD bit is not set.
2255 				 */
2256 				if (rdataset->trust != dns_trust_secure &&
2257 				    (sectionid == DNS_SECTION_ANSWER ||
2258 				     sectionid == DNS_SECTION_AUTHORITY))
2259 				{
2260 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
2261 				}
2262 				if (OPTOUT(rdataset)) {
2263 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
2264 				}
2265 
2266 				rdataset->attributes |=
2267 					DNS_RDATASETATTR_RENDERED;
2268 
2269 			next:
2270 				rdataset = next_rdataset;
2271 			}
2272 
2273 			name = next_name;
2274 		}
2275 	} while (--pass != 0);
2276 
2277 	msg->buffer->length += msg->reserved;
2278 	msg->counts[sectionid] += total;
2279 
2280 	return (ISC_R_SUCCESS);
2281 }
2282 
2283 void
2284 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2285 	uint16_t tmp;
2286 	isc_region_t r;
2287 
2288 	REQUIRE(DNS_MESSAGE_VALID(msg));
2289 	REQUIRE(target != NULL);
2290 
2291 	isc_buffer_availableregion(target, &r);
2292 	REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2293 
2294 	isc_buffer_putuint16(target, msg->id);
2295 
2296 	tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT) &
2297 	       DNS_MESSAGE_OPCODE_MASK);
2298 	tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2299 	tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2300 
2301 	INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
2302 	       msg->counts[DNS_SECTION_ANSWER] < 65536 &&
2303 	       msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2304 	       msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2305 
2306 	isc_buffer_putuint16(target, tmp);
2307 	isc_buffer_putuint16(target,
2308 			     (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2309 	isc_buffer_putuint16(target, (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2310 	isc_buffer_putuint16(target,
2311 			     (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2312 	isc_buffer_putuint16(target,
2313 			     (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2314 }
2315 
2316 isc_result_t
2317 dns_message_renderend(dns_message_t *msg) {
2318 	isc_buffer_t tmpbuf;
2319 	isc_region_t r;
2320 	int result;
2321 	unsigned int count;
2322 
2323 	REQUIRE(DNS_MESSAGE_VALID(msg));
2324 	REQUIRE(msg->buffer != NULL);
2325 
2326 	if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2327 		/*
2328 		 * We have an extended rcode but are not using EDNS.
2329 		 */
2330 		return (DNS_R_FORMERR);
2331 	}
2332 
2333 	/*
2334 	 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
2335 	 * clear all rdatasets from the message except for the question
2336 	 * before adding the OPT, TSIG or SIG(0).  If the question doesn't
2337 	 * fit, don't include it.
2338 	 */
2339 	if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
2340 	    (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2341 	{
2342 		isc_buffer_t *buf;
2343 
2344 		msgresetnames(msg, DNS_SECTION_ANSWER);
2345 		buf = msg->buffer;
2346 		dns_message_renderreset(msg);
2347 		msg->buffer = buf;
2348 		isc_buffer_clear(msg->buffer);
2349 		isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2350 		dns_compress_rollback(msg->cctx, 0);
2351 		result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2352 						   0);
2353 		if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) {
2354 			return (result);
2355 		}
2356 	}
2357 
2358 	/*
2359 	 * If we've got an OPT record, render it.
2360 	 */
2361 	if (msg->opt != NULL) {
2362 		dns_message_renderrelease(msg, msg->opt_reserved);
2363 		msg->opt_reserved = 0;
2364 		/*
2365 		 * Set the extended rcode.  Cast msg->rcode to dns_ttl_t
2366 		 * so that we do a unsigned shift.
2367 		 */
2368 		msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2369 		msg->opt->ttl |= (((dns_ttl_t)(msg->rcode) << 20) &
2370 				  DNS_MESSAGE_EDNSRCODE_MASK);
2371 		/*
2372 		 * Render.
2373 		 */
2374 		count = 0;
2375 		result = renderset(msg->opt, dns_rootname, msg->cctx,
2376 				   msg->buffer, msg->reserved, 0, &count);
2377 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2378 		if (result != ISC_R_SUCCESS) {
2379 			return (result);
2380 		}
2381 	}
2382 
2383 	/*
2384 	 * Deal with EDNS padding.
2385 	 *
2386 	 * padding_off is the length of the OPT with the 0-length PAD
2387 	 * at the end.
2388 	 */
2389 	if (msg->padding_off > 0) {
2390 		unsigned char *cp = isc_buffer_used(msg->buffer);
2391 		unsigned int used, remaining;
2392 		uint16_t len, padsize = 0;
2393 
2394 		/* Check PAD */
2395 		if ((cp[-4] != 0) || (cp[-3] != DNS_OPT_PAD) || (cp[-2] != 0) ||
2396 		    (cp[-1] != 0))
2397 		{
2398 			return (ISC_R_UNEXPECTED);
2399 		}
2400 
2401 		/*
2402 		 * Zero-fill the PAD to the computed size;
2403 		 * patch PAD length and OPT rdlength
2404 		 */
2405 
2406 		/* Aligned used length + reserved to padding block */
2407 		used = isc_buffer_usedlength(msg->buffer);
2408 		if (msg->padding != 0) {
2409 			padsize = ((uint16_t)used + msg->reserved) %
2410 				  msg->padding;
2411 		}
2412 		if (padsize != 0) {
2413 			padsize = msg->padding - padsize;
2414 		}
2415 		/* Stay below the available length */
2416 		remaining = isc_buffer_availablelength(msg->buffer);
2417 		if (padsize > remaining) {
2418 			padsize = remaining;
2419 		}
2420 
2421 		isc_buffer_add(msg->buffer, padsize);
2422 		memset(cp, 0, padsize);
2423 		cp[-2] = (unsigned char)((padsize & 0xff00U) >> 8);
2424 		cp[-1] = (unsigned char)(padsize & 0x00ffU);
2425 		cp -= msg->padding_off;
2426 		len = ((uint16_t)(cp[-2])) << 8;
2427 		len |= ((uint16_t)(cp[-1]));
2428 		len += padsize;
2429 		cp[-2] = (unsigned char)((len & 0xff00U) >> 8);
2430 		cp[-1] = (unsigned char)(len & 0x00ffU);
2431 	}
2432 
2433 	/*
2434 	 * If we're adding a TSIG record, generate and render it.
2435 	 */
2436 	if (msg->tsigkey != NULL) {
2437 		dns_message_renderrelease(msg, msg->sig_reserved);
2438 		msg->sig_reserved = 0;
2439 		result = dns_tsig_sign(msg);
2440 		if (result != ISC_R_SUCCESS) {
2441 			return (result);
2442 		}
2443 		count = 0;
2444 		result = renderset(msg->tsig, msg->tsigname, msg->cctx,
2445 				   msg->buffer, msg->reserved, 0, &count);
2446 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2447 		if (result != ISC_R_SUCCESS) {
2448 			return (result);
2449 		}
2450 	}
2451 
2452 	/*
2453 	 * If we're adding a SIG(0) record, generate and render it.
2454 	 */
2455 	if (msg->sig0key != NULL) {
2456 		dns_message_renderrelease(msg, msg->sig_reserved);
2457 		msg->sig_reserved = 0;
2458 		result = dns_dnssec_signmessage(msg, msg->sig0key);
2459 		if (result != ISC_R_SUCCESS) {
2460 			return (result);
2461 		}
2462 		count = 0;
2463 		/*
2464 		 * Note: dns_rootname is used here, not msg->sig0name, since
2465 		 * the owner name of a SIG(0) is irrelevant, and will not
2466 		 * be set in a message being rendered.
2467 		 */
2468 		result = renderset(msg->sig0, dns_rootname, msg->cctx,
2469 				   msg->buffer, msg->reserved, 0, &count);
2470 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2471 		if (result != ISC_R_SUCCESS) {
2472 			return (result);
2473 		}
2474 	}
2475 
2476 	isc_buffer_usedregion(msg->buffer, &r);
2477 	isc_buffer_init(&tmpbuf, r.base, r.length);
2478 
2479 	dns_message_renderheader(msg, &tmpbuf);
2480 
2481 	msg->buffer = NULL; /* forget about this buffer only on success XXX */
2482 
2483 	return (ISC_R_SUCCESS);
2484 }
2485 
2486 void
2487 dns_message_renderreset(dns_message_t *msg) {
2488 	unsigned int i;
2489 	dns_name_t *name;
2490 	dns_rdataset_t *rds;
2491 
2492 	/*
2493 	 * Reset the message so that it may be rendered again.
2494 	 */
2495 
2496 	REQUIRE(DNS_MESSAGE_VALID(msg));
2497 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2498 
2499 	msg->buffer = NULL;
2500 
2501 	for (i = 0; i < DNS_SECTION_MAX; i++) {
2502 		msg->cursors[i] = NULL;
2503 		msg->counts[i] = 0;
2504 		for (name = ISC_LIST_HEAD(msg->sections[i]); name != NULL;
2505 		     name = ISC_LIST_NEXT(name, link))
2506 		{
2507 			for (rds = ISC_LIST_HEAD(name->list); rds != NULL;
2508 			     rds = ISC_LIST_NEXT(rds, link))
2509 			{
2510 				rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2511 			}
2512 		}
2513 	}
2514 	if (msg->tsigname != NULL) {
2515 		dns_message_puttempname(msg, &msg->tsigname);
2516 	}
2517 	if (msg->tsig != NULL) {
2518 		dns_rdataset_disassociate(msg->tsig);
2519 		dns_message_puttemprdataset(msg, &msg->tsig);
2520 	}
2521 	if (msg->sig0 != NULL) {
2522 		dns_rdataset_disassociate(msg->sig0);
2523 		dns_message_puttemprdataset(msg, &msg->sig0);
2524 	}
2525 }
2526 
2527 isc_result_t
2528 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2529 	REQUIRE(DNS_MESSAGE_VALID(msg));
2530 	REQUIRE(VALID_NAMED_SECTION(section));
2531 
2532 	msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2533 
2534 	if (msg->cursors[section] == NULL) {
2535 		return (ISC_R_NOMORE);
2536 	}
2537 
2538 	return (ISC_R_SUCCESS);
2539 }
2540 
2541 isc_result_t
2542 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2543 	REQUIRE(DNS_MESSAGE_VALID(msg));
2544 	REQUIRE(VALID_NAMED_SECTION(section));
2545 	REQUIRE(msg->cursors[section] != NULL);
2546 
2547 	msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2548 
2549 	if (msg->cursors[section] == NULL) {
2550 		return (ISC_R_NOMORE);
2551 	}
2552 
2553 	return (ISC_R_SUCCESS);
2554 }
2555 
2556 void
2557 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2558 			dns_name_t **name) {
2559 	REQUIRE(DNS_MESSAGE_VALID(msg));
2560 	REQUIRE(VALID_NAMED_SECTION(section));
2561 	REQUIRE(name != NULL && *name == NULL);
2562 	REQUIRE(msg->cursors[section] != NULL);
2563 
2564 	*name = msg->cursors[section];
2565 }
2566 
2567 isc_result_t
2568 dns_message_findname(dns_message_t *msg, dns_section_t section,
2569 		     const dns_name_t *target, dns_rdatatype_t type,
2570 		     dns_rdatatype_t covers, dns_name_t **name,
2571 		     dns_rdataset_t **rdataset) {
2572 	dns_name_t *foundname = NULL;
2573 	isc_result_t result;
2574 
2575 	/*
2576 	 * XXX These requirements are probably too intensive, especially
2577 	 * where things can be NULL, but as they are they ensure that if
2578 	 * something is NON-NULL, indicating that the caller expects it
2579 	 * to be filled in, that we can in fact fill it in.
2580 	 */
2581 	REQUIRE(msg != NULL);
2582 	REQUIRE(VALID_SECTION(section));
2583 	REQUIRE(target != NULL);
2584 	REQUIRE(name == NULL || *name == NULL);
2585 
2586 	if (type == dns_rdatatype_any) {
2587 		REQUIRE(rdataset == NULL);
2588 	} else {
2589 		REQUIRE(rdataset == NULL || *rdataset == NULL);
2590 	}
2591 
2592 	result = findname(&foundname, target, &msg->sections[section]);
2593 
2594 	if (result == ISC_R_NOTFOUND) {
2595 		return (DNS_R_NXDOMAIN);
2596 	} else if (result != ISC_R_SUCCESS) {
2597 		return (result);
2598 	}
2599 
2600 	if (name != NULL) {
2601 		*name = foundname;
2602 	}
2603 
2604 	/*
2605 	 * And now look for the type.
2606 	 */
2607 	if (ISC_UNLIKELY(type == dns_rdatatype_any)) {
2608 		return (ISC_R_SUCCESS);
2609 	}
2610 
2611 	result = dns_message_findtype(foundname, type, covers, rdataset);
2612 	if (result == ISC_R_NOTFOUND) {
2613 		return (DNS_R_NXRRSET);
2614 	}
2615 
2616 	return (result);
2617 }
2618 
2619 void
2620 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2621 		    dns_section_t section) {
2622 	REQUIRE(msg != NULL);
2623 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2624 	REQUIRE(name != NULL);
2625 	REQUIRE(VALID_NAMED_SECTION(section));
2626 
2627 	ISC_LIST_APPEND(msg->sections[section], name, link);
2628 }
2629 
2630 void
2631 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2632 		       dns_section_t section) {
2633 	REQUIRE(msg != NULL);
2634 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2635 	REQUIRE(name != NULL);
2636 	REQUIRE(VALID_NAMED_SECTION(section));
2637 
2638 	ISC_LIST_UNLINK(msg->sections[section], name, link);
2639 }
2640 
2641 isc_result_t
2642 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2643 	dns_fixedname_t *fn = NULL;
2644 
2645 	REQUIRE(DNS_MESSAGE_VALID(msg));
2646 	REQUIRE(item != NULL && *item == NULL);
2647 
2648 	fn = isc_mempool_get(msg->namepool);
2649 	if (fn == NULL) {
2650 		return (ISC_R_NOMEMORY);
2651 	}
2652 	*item = dns_fixedname_initname(fn);
2653 
2654 	return (ISC_R_SUCCESS);
2655 }
2656 
2657 isc_result_t
2658 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2659 	REQUIRE(DNS_MESSAGE_VALID(msg));
2660 	REQUIRE(item != NULL && *item == NULL);
2661 
2662 	*item = newrdata(msg);
2663 	if (*item == NULL) {
2664 		return (ISC_R_NOMEMORY);
2665 	}
2666 
2667 	return (ISC_R_SUCCESS);
2668 }
2669 
2670 isc_result_t
2671 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2672 	REQUIRE(DNS_MESSAGE_VALID(msg));
2673 	REQUIRE(item != NULL && *item == NULL);
2674 
2675 	*item = isc_mempool_get(msg->rdspool);
2676 	if (*item == NULL) {
2677 		return (ISC_R_NOMEMORY);
2678 	}
2679 
2680 	dns_rdataset_init(*item);
2681 	return (ISC_R_SUCCESS);
2682 }
2683 
2684 isc_result_t
2685 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2686 	REQUIRE(DNS_MESSAGE_VALID(msg));
2687 	REQUIRE(item != NULL && *item == NULL);
2688 
2689 	*item = newrdatalist(msg);
2690 	if (*item == NULL) {
2691 		return (ISC_R_NOMEMORY);
2692 	}
2693 
2694 	return (ISC_R_SUCCESS);
2695 }
2696 
2697 void
2698 dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) {
2699 	dns_name_t *item = NULL;
2700 
2701 	REQUIRE(DNS_MESSAGE_VALID(msg));
2702 	REQUIRE(itemp != NULL && *itemp != NULL);
2703 
2704 	item = *itemp;
2705 	*itemp = NULL;
2706 
2707 	REQUIRE(!ISC_LINK_LINKED(item, link));
2708 	REQUIRE(ISC_LIST_HEAD(item->list) == NULL);
2709 
2710 	if (item->ht != NULL) {
2711 		isc_ht_destroy(&item->ht);
2712 	}
2713 
2714 	/*
2715 	 * we need to check this in case dns_name_dup() was used.
2716 	 */
2717 	if (dns_name_dynamic(item)) {
2718 		dns_name_free(item, msg->mctx);
2719 	}
2720 
2721 	/*
2722 	 * 'name' is the first field in dns_fixedname_t, so putting
2723 	 * back the address of name is the same as putting back
2724 	 * the fixedname.
2725 	 */
2726 	isc_mempool_put(msg->namepool, item);
2727 }
2728 
2729 void
2730 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2731 	REQUIRE(DNS_MESSAGE_VALID(msg));
2732 	REQUIRE(item != NULL && *item != NULL);
2733 
2734 	releaserdata(msg, *item);
2735 	*item = NULL;
2736 }
2737 
2738 void
2739 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2740 	REQUIRE(DNS_MESSAGE_VALID(msg));
2741 	REQUIRE(item != NULL && *item != NULL);
2742 
2743 	REQUIRE(!dns_rdataset_isassociated(*item));
2744 	isc_mempool_put(msg->rdspool, *item);
2745 	*item = NULL;
2746 }
2747 
2748 void
2749 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2750 	REQUIRE(DNS_MESSAGE_VALID(msg));
2751 	REQUIRE(item != NULL && *item != NULL);
2752 
2753 	releaserdatalist(msg, *item);
2754 	*item = NULL;
2755 }
2756 
2757 isc_result_t
2758 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2759 		       unsigned int *flagsp) {
2760 	isc_region_t r;
2761 	isc_buffer_t buffer;
2762 	dns_messageid_t id;
2763 	unsigned int flags;
2764 
2765 	REQUIRE(source != NULL);
2766 
2767 	buffer = *source;
2768 
2769 	isc_buffer_remainingregion(&buffer, &r);
2770 	if (r.length < DNS_MESSAGE_HEADERLEN) {
2771 		return (ISC_R_UNEXPECTEDEND);
2772 	}
2773 
2774 	id = isc_buffer_getuint16(&buffer);
2775 	flags = isc_buffer_getuint16(&buffer);
2776 	flags &= DNS_MESSAGE_FLAG_MASK;
2777 
2778 	if (flagsp != NULL) {
2779 		*flagsp = flags;
2780 	}
2781 	if (idp != NULL) {
2782 		*idp = id;
2783 	}
2784 
2785 	return (ISC_R_SUCCESS);
2786 }
2787 
2788 isc_result_t
2789 dns_message_reply(dns_message_t *msg, bool want_question_section) {
2790 	unsigned int clear_from;
2791 	isc_result_t result;
2792 
2793 	REQUIRE(DNS_MESSAGE_VALID(msg));
2794 	REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2795 
2796 	if (!msg->header_ok) {
2797 		return (DNS_R_FORMERR);
2798 	}
2799 	if (msg->opcode != dns_opcode_query && msg->opcode != dns_opcode_notify)
2800 	{
2801 		want_question_section = false;
2802 	}
2803 	if (msg->opcode == dns_opcode_update) {
2804 		clear_from = DNS_SECTION_PREREQUISITE;
2805 	} else if (want_question_section) {
2806 		if (!msg->question_ok) {
2807 			return (DNS_R_FORMERR);
2808 		}
2809 		clear_from = DNS_SECTION_ANSWER;
2810 	} else {
2811 		clear_from = DNS_SECTION_QUESTION;
2812 	}
2813 	msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2814 	msgresetnames(msg, clear_from);
2815 	msgresetopt(msg);
2816 	msgresetsigs(msg, true);
2817 	msginitprivate(msg);
2818 	/*
2819 	 * We now clear most flags and then set QR, ensuring that the
2820 	 * reply's flags will be in a reasonable state.
2821 	 */
2822 	if (msg->opcode == dns_opcode_query) {
2823 		msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2824 	} else {
2825 		msg->flags = 0;
2826 	}
2827 	msg->flags |= DNS_MESSAGEFLAG_QR;
2828 
2829 	/*
2830 	 * This saves the query TSIG status, if the query was signed, and
2831 	 * reserves space in the reply for the TSIG.
2832 	 */
2833 	if (msg->tsigkey != NULL) {
2834 		unsigned int otherlen = 0;
2835 		msg->querytsigstatus = msg->tsigstatus;
2836 		msg->tsigstatus = dns_rcode_noerror;
2837 		if (msg->querytsigstatus == dns_tsigerror_badtime) {
2838 			otherlen = 6;
2839 		}
2840 		msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2841 		result = dns_message_renderreserve(msg, msg->sig_reserved);
2842 		if (result != ISC_R_SUCCESS) {
2843 			msg->sig_reserved = 0;
2844 			return (result);
2845 		}
2846 	}
2847 	if (msg->saved.base != NULL) {
2848 		msg->query.base = msg->saved.base;
2849 		msg->query.length = msg->saved.length;
2850 		msg->free_query = msg->free_saved;
2851 		msg->saved.base = NULL;
2852 		msg->saved.length = 0;
2853 		msg->free_saved = 0;
2854 	}
2855 
2856 	return (ISC_R_SUCCESS);
2857 }
2858 
2859 dns_rdataset_t *
2860 dns_message_getopt(dns_message_t *msg) {
2861 	/*
2862 	 * Get the OPT record for 'msg'.
2863 	 */
2864 
2865 	REQUIRE(DNS_MESSAGE_VALID(msg));
2866 
2867 	return (msg->opt);
2868 }
2869 
2870 isc_result_t
2871 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2872 	isc_result_t result;
2873 	dns_rdata_t rdata = DNS_RDATA_INIT;
2874 
2875 	/*
2876 	 * Set the OPT record for 'msg'.
2877 	 */
2878 
2879 	/*
2880 	 * The space required for an OPT record is:
2881 	 *
2882 	 *	1 byte for the name
2883 	 *	2 bytes for the type
2884 	 *	2 bytes for the class
2885 	 *	4 bytes for the ttl
2886 	 *	2 bytes for the rdata length
2887 	 * ---------------------------------
2888 	 *     11 bytes
2889 	 *
2890 	 * plus the length of the rdata.
2891 	 */
2892 
2893 	REQUIRE(DNS_MESSAGE_VALID(msg));
2894 	REQUIRE(opt->type == dns_rdatatype_opt);
2895 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2896 	REQUIRE(msg->state == DNS_SECTION_ANY);
2897 
2898 	msgresetopt(msg);
2899 
2900 	result = dns_rdataset_first(opt);
2901 	if (result != ISC_R_SUCCESS) {
2902 		goto cleanup;
2903 	}
2904 	dns_rdataset_current(opt, &rdata);
2905 	msg->opt_reserved = 11 + rdata.length;
2906 	result = dns_message_renderreserve(msg, msg->opt_reserved);
2907 	if (result != ISC_R_SUCCESS) {
2908 		msg->opt_reserved = 0;
2909 		goto cleanup;
2910 	}
2911 
2912 	msg->opt = opt;
2913 
2914 	return (ISC_R_SUCCESS);
2915 
2916 cleanup:
2917 	dns_rdataset_disassociate(opt);
2918 	dns_message_puttemprdataset(msg, &opt);
2919 	return (result);
2920 }
2921 
2922 dns_rdataset_t *
2923 dns_message_gettsig(dns_message_t *msg, const dns_name_t **owner) {
2924 	/*
2925 	 * Get the TSIG record and owner for 'msg'.
2926 	 */
2927 
2928 	REQUIRE(DNS_MESSAGE_VALID(msg));
2929 	REQUIRE(owner == NULL || *owner == NULL);
2930 
2931 	if (owner != NULL) {
2932 		*owner = msg->tsigname;
2933 	}
2934 	return (msg->tsig);
2935 }
2936 
2937 isc_result_t
2938 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2939 	isc_result_t result;
2940 
2941 	/*
2942 	 * Set the TSIG key for 'msg'
2943 	 */
2944 
2945 	REQUIRE(DNS_MESSAGE_VALID(msg));
2946 
2947 	if (key == NULL && msg->tsigkey != NULL) {
2948 		if (msg->sig_reserved != 0) {
2949 			dns_message_renderrelease(msg, msg->sig_reserved);
2950 			msg->sig_reserved = 0;
2951 		}
2952 		dns_tsigkey_detach(&msg->tsigkey);
2953 	}
2954 	if (key != NULL) {
2955 		REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2956 		dns_tsigkey_attach(key, &msg->tsigkey);
2957 		if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2958 			msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2959 			result = dns_message_renderreserve(msg,
2960 							   msg->sig_reserved);
2961 			if (result != ISC_R_SUCCESS) {
2962 				dns_tsigkey_detach(&msg->tsigkey);
2963 				msg->sig_reserved = 0;
2964 				return (result);
2965 			}
2966 		}
2967 	}
2968 	return (ISC_R_SUCCESS);
2969 }
2970 
2971 dns_tsigkey_t *
2972 dns_message_gettsigkey(dns_message_t *msg) {
2973 	/*
2974 	 * Get the TSIG key for 'msg'
2975 	 */
2976 
2977 	REQUIRE(DNS_MESSAGE_VALID(msg));
2978 
2979 	return (msg->tsigkey);
2980 }
2981 
2982 isc_result_t
2983 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2984 	dns_rdata_t *rdata = NULL;
2985 	dns_rdatalist_t *list = NULL;
2986 	dns_rdataset_t *set = NULL;
2987 	isc_buffer_t *buf = NULL;
2988 	isc_region_t r;
2989 	isc_result_t result;
2990 
2991 	REQUIRE(DNS_MESSAGE_VALID(msg));
2992 	REQUIRE(msg->querytsig == NULL);
2993 
2994 	if (querytsig == NULL) {
2995 		return (ISC_R_SUCCESS);
2996 	}
2997 
2998 	result = dns_message_gettemprdata(msg, &rdata);
2999 	if (result != ISC_R_SUCCESS) {
3000 		goto cleanup;
3001 	}
3002 
3003 	result = dns_message_gettemprdatalist(msg, &list);
3004 	if (result != ISC_R_SUCCESS) {
3005 		goto cleanup;
3006 	}
3007 	result = dns_message_gettemprdataset(msg, &set);
3008 	if (result != ISC_R_SUCCESS) {
3009 		goto cleanup;
3010 	}
3011 
3012 	isc_buffer_usedregion(querytsig, &r);
3013 	isc_buffer_allocate(msg->mctx, &buf, r.length);
3014 	isc_buffer_putmem(buf, r.base, r.length);
3015 	isc_buffer_usedregion(buf, &r);
3016 	dns_rdata_init(rdata);
3017 	dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
3018 	dns_message_takebuffer(msg, &buf);
3019 	ISC_LIST_APPEND(list->rdata, rdata, link);
3020 	result = dns_rdatalist_tordataset(list, set);
3021 	if (result != ISC_R_SUCCESS) {
3022 		goto cleanup;
3023 	}
3024 
3025 	msg->querytsig = set;
3026 
3027 	return (result);
3028 
3029 cleanup:
3030 	if (rdata != NULL) {
3031 		dns_message_puttemprdata(msg, &rdata);
3032 	}
3033 	if (list != NULL) {
3034 		dns_message_puttemprdatalist(msg, &list);
3035 	}
3036 	if (set != NULL) {
3037 		dns_message_puttemprdataset(msg, &set);
3038 	}
3039 	return (ISC_R_NOMEMORY);
3040 }
3041 
3042 isc_result_t
3043 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
3044 			 isc_buffer_t **querytsig) {
3045 	isc_result_t result;
3046 	dns_rdata_t rdata = DNS_RDATA_INIT;
3047 	isc_region_t r;
3048 
3049 	REQUIRE(DNS_MESSAGE_VALID(msg));
3050 	REQUIRE(mctx != NULL);
3051 	REQUIRE(querytsig != NULL && *querytsig == NULL);
3052 
3053 	if (msg->tsig == NULL) {
3054 		return (ISC_R_SUCCESS);
3055 	}
3056 
3057 	result = dns_rdataset_first(msg->tsig);
3058 	if (result != ISC_R_SUCCESS) {
3059 		return (result);
3060 	}
3061 	dns_rdataset_current(msg->tsig, &rdata);
3062 	dns_rdata_toregion(&rdata, &r);
3063 
3064 	isc_buffer_allocate(mctx, querytsig, r.length);
3065 	isc_buffer_putmem(*querytsig, r.base, r.length);
3066 	return (ISC_R_SUCCESS);
3067 }
3068 
3069 dns_rdataset_t *
3070 dns_message_getsig0(dns_message_t *msg, const dns_name_t **owner) {
3071 	/*
3072 	 * Get the SIG(0) record for 'msg'.
3073 	 */
3074 
3075 	REQUIRE(DNS_MESSAGE_VALID(msg));
3076 	REQUIRE(owner == NULL || *owner == NULL);
3077 
3078 	if (msg->sig0 != NULL && owner != NULL) {
3079 		/* If dns_message_getsig0 is called on a rendered message
3080 		 * after the SIG(0) has been applied, we need to return the
3081 		 * root name, not NULL.
3082 		 */
3083 		if (msg->sig0name == NULL) {
3084 			*owner = dns_rootname;
3085 		} else {
3086 			*owner = msg->sig0name;
3087 		}
3088 	}
3089 	return (msg->sig0);
3090 }
3091 
3092 isc_result_t
3093 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
3094 	isc_region_t r;
3095 	unsigned int x;
3096 	isc_result_t result;
3097 
3098 	/*
3099 	 * Set the SIG(0) key for 'msg'
3100 	 */
3101 
3102 	/*
3103 	 * The space required for an SIG(0) record is:
3104 	 *
3105 	 *	1 byte for the name
3106 	 *	2 bytes for the type
3107 	 *	2 bytes for the class
3108 	 *	4 bytes for the ttl
3109 	 *	2 bytes for the type covered
3110 	 *	1 byte for the algorithm
3111 	 *	1 bytes for the labels
3112 	 *	4 bytes for the original ttl
3113 	 *	4 bytes for the signature expiration
3114 	 *	4 bytes for the signature inception
3115 	 *	2 bytes for the key tag
3116 	 *	n bytes for the signer's name
3117 	 *	x bytes for the signature
3118 	 * ---------------------------------
3119 	 *     27 + n + x bytes
3120 	 */
3121 	REQUIRE(DNS_MESSAGE_VALID(msg));
3122 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
3123 	REQUIRE(msg->state == DNS_SECTION_ANY);
3124 
3125 	if (key != NULL) {
3126 		REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
3127 		dns_name_toregion(dst_key_name(key), &r);
3128 		result = dst_key_sigsize(key, &x);
3129 		if (result != ISC_R_SUCCESS) {
3130 			msg->sig_reserved = 0;
3131 			return (result);
3132 		}
3133 		msg->sig_reserved = 27 + r.length + x;
3134 		result = dns_message_renderreserve(msg, msg->sig_reserved);
3135 		if (result != ISC_R_SUCCESS) {
3136 			msg->sig_reserved = 0;
3137 			return (result);
3138 		}
3139 		msg->sig0key = key;
3140 	}
3141 	return (ISC_R_SUCCESS);
3142 }
3143 
3144 dst_key_t *
3145 dns_message_getsig0key(dns_message_t *msg) {
3146 	/*
3147 	 * Get the SIG(0) key for 'msg'
3148 	 */
3149 
3150 	REQUIRE(DNS_MESSAGE_VALID(msg));
3151 
3152 	return (msg->sig0key);
3153 }
3154 
3155 void
3156 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
3157 	REQUIRE(DNS_MESSAGE_VALID(msg));
3158 	REQUIRE(buffer != NULL);
3159 	REQUIRE(ISC_BUFFER_VALID(*buffer));
3160 
3161 	ISC_LIST_APPEND(msg->cleanup, *buffer, link);
3162 	*buffer = NULL;
3163 }
3164 
3165 isc_result_t
3166 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
3167 	isc_result_t result = ISC_R_SUCCESS;
3168 	dns_rdata_t rdata = DNS_RDATA_INIT;
3169 
3170 	REQUIRE(DNS_MESSAGE_VALID(msg));
3171 	REQUIRE(signer != NULL);
3172 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
3173 
3174 	if (msg->tsig == NULL && msg->sig0 == NULL) {
3175 		return (ISC_R_NOTFOUND);
3176 	}
3177 
3178 	if (msg->verify_attempted == 0) {
3179 		return (DNS_R_NOTVERIFIEDYET);
3180 	}
3181 
3182 	if (!dns_name_hasbuffer(signer)) {
3183 		isc_buffer_t *dynbuf = NULL;
3184 		isc_buffer_allocate(msg->mctx, &dynbuf, 512);
3185 		dns_name_setbuffer(signer, dynbuf);
3186 		dns_message_takebuffer(msg, &dynbuf);
3187 	}
3188 
3189 	if (msg->sig0 != NULL) {
3190 		dns_rdata_sig_t sig;
3191 
3192 		result = dns_rdataset_first(msg->sig0);
3193 		INSIST(result == ISC_R_SUCCESS);
3194 		dns_rdataset_current(msg->sig0, &rdata);
3195 
3196 		result = dns_rdata_tostruct(&rdata, &sig, NULL);
3197 		if (result != ISC_R_SUCCESS) {
3198 			return (result);
3199 		}
3200 
3201 		if (msg->verified_sig && msg->sig0status == dns_rcode_noerror) {
3202 			result = ISC_R_SUCCESS;
3203 		} else {
3204 			result = DNS_R_SIGINVALID;
3205 		}
3206 		dns_name_clone(&sig.signer, signer);
3207 		dns_rdata_freestruct(&sig);
3208 	} else {
3209 		const dns_name_t *identity;
3210 		dns_rdata_any_tsig_t tsig;
3211 
3212 		result = dns_rdataset_first(msg->tsig);
3213 		INSIST(result == ISC_R_SUCCESS);
3214 		dns_rdataset_current(msg->tsig, &rdata);
3215 
3216 		result = dns_rdata_tostruct(&rdata, &tsig, NULL);
3217 		INSIST(result == ISC_R_SUCCESS);
3218 		if (msg->verified_sig && msg->tsigstatus == dns_rcode_noerror &&
3219 		    tsig.error == dns_rcode_noerror)
3220 		{
3221 			result = ISC_R_SUCCESS;
3222 		} else if ((!msg->verified_sig) ||
3223 			   (msg->tsigstatus != dns_rcode_noerror))
3224 		{
3225 			result = DNS_R_TSIGVERIFYFAILURE;
3226 		} else {
3227 			INSIST(tsig.error != dns_rcode_noerror);
3228 			result = DNS_R_TSIGERRORSET;
3229 		}
3230 		dns_rdata_freestruct(&tsig);
3231 
3232 		if (msg->tsigkey == NULL) {
3233 			/*
3234 			 * If msg->tsigstatus & tsig.error are both
3235 			 * dns_rcode_noerror, the message must have been
3236 			 * verified, which means msg->tsigkey will be
3237 			 * non-NULL.
3238 			 */
3239 			INSIST(result != ISC_R_SUCCESS);
3240 		} else {
3241 			identity = dns_tsigkey_identity(msg->tsigkey);
3242 			if (identity == NULL) {
3243 				if (result == ISC_R_SUCCESS) {
3244 					result = DNS_R_NOIDENTITY;
3245 				}
3246 				identity = &msg->tsigkey->name;
3247 			}
3248 			dns_name_clone(identity, signer);
3249 		}
3250 	}
3251 
3252 	return (result);
3253 }
3254 
3255 void
3256 dns_message_resetsig(dns_message_t *msg) {
3257 	REQUIRE(DNS_MESSAGE_VALID(msg));
3258 	msg->verified_sig = 0;
3259 	msg->verify_attempted = 0;
3260 	msg->tsigstatus = dns_rcode_noerror;
3261 	msg->sig0status = dns_rcode_noerror;
3262 	msg->timeadjust = 0;
3263 	if (msg->tsigkey != NULL) {
3264 		dns_tsigkey_detach(&msg->tsigkey);
3265 		msg->tsigkey = NULL;
3266 	}
3267 }
3268 
3269 isc_result_t
3270 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
3271 	dns_message_resetsig(msg);
3272 	return (dns_message_checksig(msg, view));
3273 }
3274 
3275 #ifdef SKAN_MSG_DEBUG
3276 void
3277 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
3278 	dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
3279 	dns_rdata_any_tsig_t querytsig;
3280 	isc_result_t result;
3281 
3282 	if (msg->tsig != NULL) {
3283 		result = dns_rdataset_first(msg->tsig);
3284 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3285 		dns_rdataset_current(msg->tsig, &querytsigrdata);
3286 		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3287 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3288 		hexdump(txt1, "TSIG", querytsig.signature, querytsig.siglen);
3289 	}
3290 
3291 	if (msg->querytsig != NULL) {
3292 		result = dns_rdataset_first(msg->querytsig);
3293 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3294 		dns_rdataset_current(msg->querytsig, &querytsigrdata);
3295 		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3296 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3297 		hexdump(txt1, "QUERYTSIG", querytsig.signature,
3298 			querytsig.siglen);
3299 	}
3300 }
3301 #endif /* ifdef SKAN_MSG_DEBUG */
3302 
3303 isc_result_t
3304 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3305 	isc_buffer_t b, msgb;
3306 
3307 	REQUIRE(DNS_MESSAGE_VALID(msg));
3308 
3309 	if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL) {
3310 		return (ISC_R_SUCCESS);
3311 	}
3312 
3313 	INSIST(msg->saved.base != NULL);
3314 	isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3315 	isc_buffer_add(&msgb, msg->saved.length);
3316 	if (msg->tsigkey != NULL || msg->tsig != NULL) {
3317 #ifdef SKAN_MSG_DEBUG
3318 		dns_message_dumpsig(msg, "dns_message_checksig#1");
3319 #endif /* ifdef SKAN_MSG_DEBUG */
3320 		if (view != NULL) {
3321 			return (dns_view_checksig(view, &msgb, msg));
3322 		} else {
3323 			return (dns_tsig_verify(&msgb, msg, NULL, NULL));
3324 		}
3325 	} else {
3326 		dns_rdata_t rdata = DNS_RDATA_INIT;
3327 		dns_rdata_sig_t sig;
3328 		dns_rdataset_t keyset;
3329 		isc_result_t result;
3330 
3331 		result = dns_rdataset_first(msg->sig0);
3332 		INSIST(result == ISC_R_SUCCESS);
3333 		dns_rdataset_current(msg->sig0, &rdata);
3334 
3335 		/*
3336 		 * This can occur when the message is a dynamic update, since
3337 		 * the rdata length checking is relaxed.  This should not
3338 		 * happen in a well-formed message, since the SIG(0) is only
3339 		 * looked for in the additional section, and the dynamic update
3340 		 * meta-records are in the prerequisite and update sections.
3341 		 */
3342 		if (rdata.length == 0) {
3343 			return (ISC_R_UNEXPECTEDEND);
3344 		}
3345 
3346 		result = dns_rdata_tostruct(&rdata, &sig, NULL);
3347 		if (result != ISC_R_SUCCESS) {
3348 			return (result);
3349 		}
3350 
3351 		dns_rdataset_init(&keyset);
3352 		if (view == NULL) {
3353 			result = DNS_R_KEYUNAUTHORIZED;
3354 			goto freesig;
3355 		}
3356 		result = dns_view_simplefind(view, &sig.signer,
3357 					     dns_rdatatype_key /* SIG(0) */, 0,
3358 					     0, false, &keyset, NULL);
3359 
3360 		if (result != ISC_R_SUCCESS) {
3361 			/* XXXBEW Should possibly create a fetch here */
3362 			result = DNS_R_KEYUNAUTHORIZED;
3363 			goto freesig;
3364 		} else if (keyset.trust < dns_trust_secure) {
3365 			/* XXXBEW Should call a validator here */
3366 			result = DNS_R_KEYUNAUTHORIZED;
3367 			goto freesig;
3368 		}
3369 		result = dns_rdataset_first(&keyset);
3370 		INSIST(result == ISC_R_SUCCESS);
3371 		for (; result == ISC_R_SUCCESS;
3372 		     result = dns_rdataset_next(&keyset))
3373 		{
3374 			dst_key_t *key = NULL;
3375 
3376 			dns_rdata_reset(&rdata);
3377 			dns_rdataset_current(&keyset, &rdata);
3378 			isc_buffer_init(&b, rdata.data, rdata.length);
3379 			isc_buffer_add(&b, rdata.length);
3380 
3381 			result = dst_key_fromdns(&sig.signer, rdata.rdclass, &b,
3382 						 view->mctx, &key);
3383 			if (result != ISC_R_SUCCESS) {
3384 				continue;
3385 			}
3386 			if (dst_key_alg(key) != sig.algorithm ||
3387 			    dst_key_id(key) != sig.keyid ||
3388 			    !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3389 			      dst_key_proto(key) == DNS_KEYPROTO_ANY))
3390 			{
3391 				dst_key_free(&key);
3392 				continue;
3393 			}
3394 			result = dns_dnssec_verifymessage(&msgb, msg, key);
3395 			dst_key_free(&key);
3396 			if (result == ISC_R_SUCCESS) {
3397 				break;
3398 			}
3399 		}
3400 		if (result == ISC_R_NOMORE) {
3401 			result = DNS_R_KEYUNAUTHORIZED;
3402 		}
3403 
3404 	freesig:
3405 		if (dns_rdataset_isassociated(&keyset)) {
3406 			dns_rdataset_disassociate(&keyset);
3407 		}
3408 		dns_rdata_freestruct(&sig);
3409 		return (result);
3410 	}
3411 }
3412 
3413 #define INDENT(sp)                                                           \
3414 	do {                                                                 \
3415 		unsigned int __i;                                            \
3416 		dns_masterstyle_flags_t __flags = dns_master_styleflags(sp); \
3417 		if ((__flags & DNS_STYLEFLAG_INDENT) == 0ULL &&              \
3418 		    (__flags & DNS_STYLEFLAG_YAML) == 0ULL)                  \
3419 			break;                                               \
3420 		for (__i = 0; __i < msg->indent.count; __i++) {              \
3421 			ADD_STRING(target, msg->indent.string);              \
3422 		}                                                            \
3423 	} while (0)
3424 
3425 isc_result_t
3426 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3427 			  const dns_master_style_t *style,
3428 			  dns_messagetextflag_t flags, isc_buffer_t *target) {
3429 	dns_name_t *name, empty_name;
3430 	dns_rdataset_t *rdataset;
3431 	isc_result_t result = ISC_R_SUCCESS;
3432 	bool seensoa = false;
3433 	size_t saved_count;
3434 	dns_masterstyle_flags_t sflags;
3435 
3436 	REQUIRE(DNS_MESSAGE_VALID(msg));
3437 	REQUIRE(target != NULL);
3438 	REQUIRE(VALID_SECTION(section));
3439 
3440 	saved_count = msg->indent.count;
3441 
3442 	if (ISC_LIST_EMPTY(msg->sections[section])) {
3443 		goto cleanup;
3444 	}
3445 
3446 	sflags = dns_master_styleflags(style);
3447 
3448 	INDENT(style);
3449 	if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3450 		if (msg->opcode != dns_opcode_update) {
3451 			ADD_STRING(target, sectiontext[section]);
3452 		} else {
3453 			ADD_STRING(target, updsectiontext[section]);
3454 		}
3455 		ADD_STRING(target, "_SECTION:\n");
3456 	} else if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3457 		ADD_STRING(target, ";; ");
3458 		if (msg->opcode != dns_opcode_update) {
3459 			ADD_STRING(target, sectiontext[section]);
3460 		} else {
3461 			ADD_STRING(target, updsectiontext[section]);
3462 		}
3463 		ADD_STRING(target, " SECTION:\n");
3464 	}
3465 
3466 	dns_name_init(&empty_name, NULL);
3467 	result = dns_message_firstname(msg, section);
3468 	if (result != ISC_R_SUCCESS) {
3469 		goto cleanup;
3470 	}
3471 	if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3472 		msg->indent.count++;
3473 	}
3474 	do {
3475 		name = NULL;
3476 		dns_message_currentname(msg, section, &name);
3477 		for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
3478 		     rdataset = ISC_LIST_NEXT(rdataset, link))
3479 		{
3480 			if (section == DNS_SECTION_ANSWER &&
3481 			    rdataset->type == dns_rdatatype_soa)
3482 			{
3483 				if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3484 				{
3485 					continue;
3486 				}
3487 				if (seensoa &&
3488 				    (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3489 				{
3490 					continue;
3491 				}
3492 				seensoa = true;
3493 			}
3494 			if (section == DNS_SECTION_QUESTION) {
3495 				INDENT(style);
3496 				if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3497 					ADD_STRING(target, "- ");
3498 				} else {
3499 					ADD_STRING(target, ";");
3500 				}
3501 				result = dns_master_questiontotext(
3502 					name, rdataset, style, target);
3503 			} else {
3504 				result = dns_master_rdatasettotext(
3505 					name, rdataset, style, &msg->indent,
3506 					target);
3507 			}
3508 			if (result != ISC_R_SUCCESS) {
3509 				goto cleanup;
3510 			}
3511 		}
3512 		result = dns_message_nextname(msg, section);
3513 	} while (result == ISC_R_SUCCESS);
3514 	if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3515 		msg->indent.count--;
3516 	}
3517 	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3518 	    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0 &&
3519 	    (sflags & DNS_STYLEFLAG_YAML) == 0)
3520 	{
3521 		INDENT(style);
3522 		ADD_STRING(target, "\n");
3523 	}
3524 	if (result == ISC_R_NOMORE) {
3525 		result = ISC_R_SUCCESS;
3526 	}
3527 
3528 cleanup:
3529 	msg->indent.count = saved_count;
3530 	return (result);
3531 }
3532 
3533 static isc_result_t
3534 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
3535 	int i;
3536 	char addr[16], addr_text[64];
3537 	uint16_t family;
3538 	uint8_t addrlen, addrbytes, scopelen;
3539 	isc_result_t result;
3540 
3541 	/*
3542 	 * Note: This routine needs to handle malformed ECS options.
3543 	 */
3544 
3545 	if (isc_buffer_remaininglength(ecsbuf) < 4) {
3546 		return (DNS_R_OPTERR);
3547 	}
3548 	family = isc_buffer_getuint16(ecsbuf);
3549 	addrlen = isc_buffer_getuint8(ecsbuf);
3550 	scopelen = isc_buffer_getuint8(ecsbuf);
3551 
3552 	addrbytes = (addrlen + 7) / 8;
3553 	if (isc_buffer_remaininglength(ecsbuf) < addrbytes) {
3554 		return (DNS_R_OPTERR);
3555 	}
3556 
3557 	if (addrbytes > sizeof(addr)) {
3558 		return (DNS_R_OPTERR);
3559 	}
3560 
3561 	memset(addr, 0, sizeof(addr));
3562 	for (i = 0; i < addrbytes; i++) {
3563 		addr[i] = isc_buffer_getuint8(ecsbuf);
3564 	}
3565 
3566 	switch (family) {
3567 	case 0:
3568 		if (addrlen != 0U || scopelen != 0U) {
3569 			return (DNS_R_OPTERR);
3570 		}
3571 		strlcpy(addr_text, "0", sizeof(addr_text));
3572 		break;
3573 	case 1:
3574 		if (addrlen > 32 || scopelen > 32) {
3575 			return (DNS_R_OPTERR);
3576 		}
3577 		inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
3578 		break;
3579 	case 2:
3580 		if (addrlen > 128 || scopelen > 128) {
3581 			return (DNS_R_OPTERR);
3582 		}
3583 		inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
3584 		break;
3585 	default:
3586 		return (DNS_R_OPTERR);
3587 	}
3588 
3589 	ADD_STRING(target, " ");
3590 	ADD_STRING(target, addr_text);
3591 	snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
3592 	ADD_STRING(target, addr_text);
3593 
3594 	result = ISC_R_SUCCESS;
3595 
3596 cleanup:
3597 	return (result);
3598 }
3599 
3600 static isc_result_t
3601 render_llq(isc_buffer_t *optbuf, isc_buffer_t *target) {
3602 	char buf[sizeof("18446744073709551615")]; /* 2^64-1 */
3603 	isc_result_t result = ISC_R_SUCCESS;
3604 	uint32_t u;
3605 	uint64_t q;
3606 
3607 	u = isc_buffer_getuint16(optbuf);
3608 	ADD_STRING(target, " Version: ");
3609 	snprintf(buf, sizeof(buf), "%u", u);
3610 	ADD_STRING(target, buf);
3611 
3612 	u = isc_buffer_getuint16(optbuf);
3613 	ADD_STRING(target, ", Opcode: ");
3614 	snprintf(buf, sizeof(buf), "%u", u);
3615 	ADD_STRING(target, buf);
3616 
3617 	u = isc_buffer_getuint16(optbuf);
3618 	ADD_STRING(target, ", Error: ");
3619 	snprintf(buf, sizeof(buf), "%u", u);
3620 	ADD_STRING(target, buf);
3621 
3622 	q = isc_buffer_getuint32(optbuf);
3623 	q <<= 32;
3624 	q |= isc_buffer_getuint32(optbuf);
3625 	ADD_STRING(target, ", Identifier: ");
3626 	snprintf(buf, sizeof(buf), "%" PRIu64, q);
3627 	ADD_STRING(target, buf);
3628 
3629 	u = isc_buffer_getuint32(optbuf);
3630 	ADD_STRING(target, ", Lifetime: ");
3631 	snprintf(buf, sizeof(buf), "%u", u);
3632 	ADD_STRING(target, buf);
3633 cleanup:
3634 	return (result);
3635 }
3636 
3637 static isc_result_t
3638 dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section,
3639 				const dns_master_style_t *style,
3640 				dns_messagetextflag_t flags,
3641 				isc_buffer_t *target) {
3642 	dns_rdataset_t *ps = NULL;
3643 	const dns_name_t *name = NULL;
3644 	isc_result_t result = ISC_R_SUCCESS;
3645 	char buf[sizeof("1234567890")];
3646 	uint32_t mbz;
3647 	dns_rdata_t rdata;
3648 	isc_buffer_t optbuf;
3649 	uint16_t optcode, optlen;
3650 	size_t saved_count;
3651 	unsigned char *optdata;
3652 	unsigned int indent;
3653 
3654 	REQUIRE(DNS_MESSAGE_VALID(msg));
3655 	REQUIRE(target != NULL);
3656 	REQUIRE(VALID_PSEUDOSECTION(section));
3657 
3658 	saved_count = msg->indent.count;
3659 
3660 	switch (section) {
3661 	case DNS_PSEUDOSECTION_OPT:
3662 		ps = dns_message_getopt(msg);
3663 		if (ps == NULL) {
3664 			goto cleanup;
3665 		}
3666 
3667 		INDENT(style);
3668 		ADD_STRING(target, "OPT_PSEUDOSECTION:\n");
3669 		msg->indent.count++;
3670 
3671 		INDENT(style);
3672 		ADD_STRING(target, "EDNS:\n");
3673 		indent = ++msg->indent.count;
3674 
3675 		INDENT(style);
3676 		ADD_STRING(target, "version: ");
3677 		snprintf(buf, sizeof(buf), "%u",
3678 			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3679 		ADD_STRING(target, buf);
3680 		ADD_STRING(target, "\n");
3681 		INDENT(style);
3682 		ADD_STRING(target, "flags:");
3683 		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) {
3684 			ADD_STRING(target, " do");
3685 		}
3686 		ADD_STRING(target, "\n");
3687 		mbz = ps->ttl & 0xffff;
3688 		mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */
3689 		if (mbz != 0) {
3690 			INDENT(style);
3691 			ADD_STRING(target, "MBZ: ");
3692 			snprintf(buf, sizeof(buf), "0x%.4x", mbz);
3693 			ADD_STRING(target, buf);
3694 			ADD_STRING(target, "\n");
3695 		}
3696 		INDENT(style);
3697 		ADD_STRING(target, "udp: ");
3698 		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3699 		ADD_STRING(target, buf);
3700 		result = dns_rdataset_first(ps);
3701 		if (result != ISC_R_SUCCESS) {
3702 			result = ISC_R_SUCCESS;
3703 			goto cleanup;
3704 		}
3705 
3706 		/*
3707 		 * Print EDNS info, if any.
3708 		 *
3709 		 * WARNING: The option contents may be malformed as
3710 		 * dig +ednsopt=value:<content> does not perform validity
3711 		 * checking.
3712 		 */
3713 		dns_rdata_init(&rdata);
3714 		dns_rdataset_current(ps, &rdata);
3715 
3716 		isc_buffer_init(&optbuf, rdata.data, rdata.length);
3717 		isc_buffer_add(&optbuf, rdata.length);
3718 		while (isc_buffer_remaininglength(&optbuf) != 0) {
3719 			bool extra_text = false;
3720 			msg->indent.count = indent;
3721 			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3722 			optcode = isc_buffer_getuint16(&optbuf);
3723 			optlen = isc_buffer_getuint16(&optbuf);
3724 			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3725 
3726 			if (optcode == DNS_OPT_LLQ) {
3727 				INDENT(style);
3728 				ADD_STRING(target, "LLQ:");
3729 				if (optlen == 18U) {
3730 					result = render_llq(&optbuf, target);
3731 					if (result != ISC_R_SUCCESS) {
3732 						goto cleanup;
3733 					}
3734 					ADD_STRING(target, "\n");
3735 					continue;
3736 				}
3737 			} else if (optcode == DNS_OPT_NSID) {
3738 				INDENT(style);
3739 				ADD_STRING(target, "NSID:");
3740 			} else if (optcode == DNS_OPT_COOKIE) {
3741 				INDENT(style);
3742 				ADD_STRING(target, "COOKIE:");
3743 			} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
3744 				isc_buffer_t ecsbuf;
3745 				INDENT(style);
3746 				ADD_STRING(target, "CLIENT-SUBNET:");
3747 				isc_buffer_init(&ecsbuf,
3748 						isc_buffer_current(&optbuf),
3749 						optlen);
3750 				isc_buffer_add(&ecsbuf, optlen);
3751 				result = render_ecs(&ecsbuf, target);
3752 				if (result == ISC_R_NOSPACE) {
3753 					goto cleanup;
3754 				}
3755 				if (result == ISC_R_SUCCESS) {
3756 					isc_buffer_forward(&optbuf, optlen);
3757 					ADD_STRING(target, "\n");
3758 					continue;
3759 				}
3760 				ADD_STRING(target, "\n");
3761 			} else if (optcode == DNS_OPT_EXPIRE) {
3762 				INDENT(style);
3763 				ADD_STRING(target, "EXPIRE:");
3764 				if (optlen == 4) {
3765 					uint32_t secs;
3766 					secs = isc_buffer_getuint32(&optbuf);
3767 					snprintf(buf, sizeof(buf), " %u", secs);
3768 					ADD_STRING(target, buf);
3769 					ADD_STRING(target, " (");
3770 					result = dns_ttl_totext(secs, true,
3771 								true, target);
3772 					if (result != ISC_R_SUCCESS) {
3773 						goto cleanup;
3774 					}
3775 					ADD_STRING(target, ")\n");
3776 					continue;
3777 				}
3778 			} else if (optcode == DNS_OPT_TCP_KEEPALIVE) {
3779 				if (optlen == 2) {
3780 					unsigned int dsecs;
3781 					dsecs = isc_buffer_getuint16(&optbuf);
3782 					INDENT(style);
3783 					ADD_STRING(target, "TCP-KEEPALIVE: ");
3784 					snprintf(buf, sizeof(buf), "%u.%u",
3785 						 dsecs / 10U, dsecs % 10U);
3786 					ADD_STRING(target, buf);
3787 					ADD_STRING(target, " secs\n");
3788 					continue;
3789 				}
3790 				INDENT(style);
3791 				ADD_STRING(target, "TCP-KEEPALIVE:");
3792 			} else if (optcode == DNS_OPT_PAD) {
3793 				INDENT(style);
3794 				ADD_STRING(target, "PAD:");
3795 			} else if (optcode == DNS_OPT_KEY_TAG) {
3796 				INDENT(style);
3797 				ADD_STRING(target, "KEY-TAG:");
3798 				if (optlen > 0U && (optlen % 2U) == 0U) {
3799 					const char *sep = "";
3800 					uint16_t id;
3801 					while (optlen > 0U) {
3802 						id = isc_buffer_getuint16(
3803 							&optbuf);
3804 						snprintf(buf, sizeof(buf),
3805 							 "%s %u", sep, id);
3806 						ADD_STRING(target, buf);
3807 						sep = ",";
3808 						optlen -= 2;
3809 					}
3810 					ADD_STRING(target, "\n");
3811 					continue;
3812 				}
3813 			} else if (optcode == DNS_OPT_EDE) {
3814 				INDENT(style);
3815 				ADD_STRING(target, "EDE:");
3816 				if (optlen >= 2U) {
3817 					uint16_t ede;
3818 					ADD_STRING(target, "\n");
3819 					msg->indent.count++;
3820 					INDENT(style);
3821 					ADD_STRING(target, "INFO-CODE:");
3822 					ede = isc_buffer_getuint16(&optbuf);
3823 					snprintf(buf, sizeof(buf), " %u", ede);
3824 					ADD_STRING(target, buf);
3825 					if (ede < ARRAY_SIZE(edetext)) {
3826 						ADD_STRING(target, " (");
3827 						ADD_STRING(target,
3828 							   edetext[ede]);
3829 						ADD_STRING(target, ")");
3830 					}
3831 					ADD_STRING(target, "\n");
3832 					optlen -= 2;
3833 					if (optlen != 0) {
3834 						INDENT(style);
3835 						ADD_STRING(target,
3836 							   "EXTRA-TEXT:");
3837 						extra_text = true;
3838 					}
3839 				}
3840 			} else if (optcode == DNS_OPT_CLIENT_TAG) {
3841 				uint16_t id;
3842 				INDENT(style);
3843 				ADD_STRING(target, "CLIENT-TAG:");
3844 				if (optlen == 2U) {
3845 					id = isc_buffer_getuint16(&optbuf);
3846 					snprintf(buf, sizeof(buf), " %u\n", id);
3847 					ADD_STRING(target, buf);
3848 					optlen -= 2;
3849 					POST(optlen);
3850 					continue;
3851 				}
3852 			} else if (optcode == DNS_OPT_SERVER_TAG) {
3853 				uint16_t id;
3854 				INDENT(style);
3855 				ADD_STRING(target, "SERVER-TAG:");
3856 				if (optlen == 2U) {
3857 					id = isc_buffer_getuint16(&optbuf);
3858 					snprintf(buf, sizeof(buf), " %u\n", id);
3859 					ADD_STRING(target, buf);
3860 					optlen -= 2;
3861 					POST(optlen);
3862 					continue;
3863 				}
3864 			} else {
3865 				INDENT(style);
3866 				ADD_STRING(target, "OPT=");
3867 				snprintf(buf, sizeof(buf), "%u:", optcode);
3868 				ADD_STRING(target, buf);
3869 			}
3870 
3871 			if (optlen != 0) {
3872 				int i;
3873 				bool utf8ok = false;
3874 
3875 				ADD_STRING(target, " ");
3876 
3877 				optdata = isc_buffer_current(&optbuf);
3878 				if (extra_text) {
3879 					utf8ok = isc_utf8_valid(optdata,
3880 								optlen);
3881 				}
3882 				if (!utf8ok) {
3883 					for (i = 0; i < optlen; i++) {
3884 						const char *sep;
3885 						switch (optcode) {
3886 						case DNS_OPT_COOKIE:
3887 							sep = "";
3888 							break;
3889 						default:
3890 							sep = " ";
3891 							break;
3892 						}
3893 						snprintf(buf, sizeof(buf),
3894 							 "%02x%s", optdata[i],
3895 							 sep);
3896 						ADD_STRING(target, buf);
3897 					}
3898 				}
3899 
3900 				isc_buffer_forward(&optbuf, optlen);
3901 
3902 				if (optcode == DNS_OPT_COOKIE) {
3903 					/*
3904 					 * Valid server cookie?
3905 					 */
3906 					if (msg->cc_ok && optlen >= 16) {
3907 						ADD_STRING(target, " (good)");
3908 					}
3909 					/*
3910 					 * Server cookie is not valid but
3911 					 * we had our cookie echoed back.
3912 					 */
3913 					if (msg->cc_ok && optlen < 16) {
3914 						ADD_STRING(target, " (echoed)");
3915 					}
3916 					/*
3917 					 * We didn't get our cookie echoed
3918 					 * back.
3919 					 */
3920 					if (msg->cc_bad) {
3921 						ADD_STRING(target, " (bad)");
3922 					}
3923 					ADD_STRING(target, "\n");
3924 					continue;
3925 				}
3926 
3927 				if (optcode == DNS_OPT_CLIENT_SUBNET) {
3928 					ADD_STRING(target, "\n");
3929 					continue;
3930 				}
3931 
3932 				/*
3933 				 * For non-COOKIE options, add a printable
3934 				 * version
3935 				 */
3936 				if (!extra_text) {
3937 					ADD_STRING(target, "(\"");
3938 				} else {
3939 					ADD_STRING(target, "\"");
3940 				}
3941 				if (isc_buffer_availablelength(target) < optlen)
3942 				{
3943 					result = ISC_R_NOSPACE;
3944 					goto cleanup;
3945 				}
3946 				for (i = 0; i < optlen; i++) {
3947 					if (isprint(optdata[i]) ||
3948 					    (utf8ok && optdata[i] > 127))
3949 					{
3950 						isc_buffer_putmem(
3951 							target, &optdata[i], 1);
3952 					} else {
3953 						isc_buffer_putstr(target, ".");
3954 					}
3955 				}
3956 				if (!extra_text) {
3957 					ADD_STRING(target, "\")");
3958 				} else {
3959 					ADD_STRING(target, "\"");
3960 				}
3961 			}
3962 			ADD_STRING(target, "\n");
3963 		}
3964 		msg->indent.count = indent;
3965 		result = ISC_R_SUCCESS;
3966 		goto cleanup;
3967 	case DNS_PSEUDOSECTION_TSIG:
3968 		ps = dns_message_gettsig(msg, &name);
3969 		if (ps == NULL) {
3970 			result = ISC_R_SUCCESS;
3971 			goto cleanup;
3972 		}
3973 		INDENT(style);
3974 		ADD_STRING(target, "TSIG_PSEUDOSECTION:\n");
3975 		result = dns_master_rdatasettotext(name, ps, style,
3976 						   &msg->indent, target);
3977 		ADD_STRING(target, "\n");
3978 		goto cleanup;
3979 	case DNS_PSEUDOSECTION_SIG0:
3980 		ps = dns_message_getsig0(msg, &name);
3981 		if (ps == NULL) {
3982 			result = ISC_R_SUCCESS;
3983 			goto cleanup;
3984 		}
3985 		INDENT(style);
3986 		ADD_STRING(target, "SIG0_PSEUDOSECTION:\n");
3987 		result = dns_master_rdatasettotext(name, ps, style,
3988 						   &msg->indent, target);
3989 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3990 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3991 		{
3992 			ADD_STRING(target, "\n");
3993 		}
3994 		goto cleanup;
3995 	}
3996 
3997 	result = ISC_R_UNEXPECTED;
3998 
3999 cleanup:
4000 	msg->indent.count = saved_count;
4001 	return (result);
4002 }
4003 
4004 isc_result_t
4005 dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section,
4006 				const dns_master_style_t *style,
4007 				dns_messagetextflag_t flags,
4008 				isc_buffer_t *target) {
4009 	dns_rdataset_t *ps = NULL;
4010 	const dns_name_t *name = NULL;
4011 	isc_result_t result;
4012 	char buf[sizeof(" (65000 bytes)")];
4013 	uint32_t mbz;
4014 	dns_rdata_t rdata;
4015 	isc_buffer_t optbuf;
4016 	uint16_t optcode, optlen;
4017 	unsigned char *optdata;
4018 
4019 	REQUIRE(DNS_MESSAGE_VALID(msg));
4020 	REQUIRE(target != NULL);
4021 	REQUIRE(VALID_PSEUDOSECTION(section));
4022 
4023 	if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0) {
4024 		return (dns_message_pseudosectiontoyaml(msg, section, style,
4025 							flags, target));
4026 	}
4027 
4028 	switch (section) {
4029 	case DNS_PSEUDOSECTION_OPT:
4030 		ps = dns_message_getopt(msg);
4031 		if (ps == NULL) {
4032 			return (ISC_R_SUCCESS);
4033 		}
4034 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
4035 			INDENT(style);
4036 			ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
4037 		}
4038 
4039 		INDENT(style);
4040 		ADD_STRING(target, "; EDNS: version: ");
4041 		snprintf(buf, sizeof(buf), "%u",
4042 			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
4043 		ADD_STRING(target, buf);
4044 		ADD_STRING(target, ", flags:");
4045 		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) {
4046 			ADD_STRING(target, " do");
4047 		}
4048 		mbz = ps->ttl & 0xffff;
4049 		mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */
4050 		if (mbz != 0) {
4051 			ADD_STRING(target, "; MBZ: ");
4052 			snprintf(buf, sizeof(buf), "0x%.4x", mbz);
4053 			ADD_STRING(target, buf);
4054 			ADD_STRING(target, ", udp: ");
4055 		} else {
4056 			ADD_STRING(target, "; udp: ");
4057 		}
4058 		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
4059 		ADD_STRING(target, buf);
4060 
4061 		result = dns_rdataset_first(ps);
4062 		if (result != ISC_R_SUCCESS) {
4063 			return (ISC_R_SUCCESS);
4064 		}
4065 
4066 		/*
4067 		 * Print EDNS info, if any.
4068 		 *
4069 		 * WARNING: The option contents may be malformed as
4070 		 * dig +ednsopt=value:<content> does no validity
4071 		 * checking.
4072 		 */
4073 		dns_rdata_init(&rdata);
4074 		dns_rdataset_current(ps, &rdata);
4075 
4076 		isc_buffer_init(&optbuf, rdata.data, rdata.length);
4077 		isc_buffer_add(&optbuf, rdata.length);
4078 		while (isc_buffer_remaininglength(&optbuf) != 0) {
4079 			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
4080 			optcode = isc_buffer_getuint16(&optbuf);
4081 			optlen = isc_buffer_getuint16(&optbuf);
4082 
4083 			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
4084 
4085 			INDENT(style);
4086 
4087 			if (optcode == DNS_OPT_LLQ) {
4088 				ADD_STRING(target, "; LLQ:");
4089 				if (optlen == 18U) {
4090 					result = render_llq(&optbuf, target);
4091 					if (result != ISC_R_SUCCESS) {
4092 						return (result);
4093 					}
4094 					ADD_STRING(target, "\n");
4095 					continue;
4096 				}
4097 			} else if (optcode == DNS_OPT_NSID) {
4098 				ADD_STRING(target, "; NSID:");
4099 			} else if (optcode == DNS_OPT_COOKIE) {
4100 				ADD_STRING(target, "; COOKIE:");
4101 			} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
4102 				isc_buffer_t ecsbuf;
4103 
4104 				ADD_STRING(target, "; CLIENT-SUBNET:");
4105 				isc_buffer_init(&ecsbuf,
4106 						isc_buffer_current(&optbuf),
4107 						optlen);
4108 				isc_buffer_add(&ecsbuf, optlen);
4109 				result = render_ecs(&ecsbuf, target);
4110 				if (result == ISC_R_NOSPACE) {
4111 					return (result);
4112 				}
4113 				if (result == ISC_R_SUCCESS) {
4114 					isc_buffer_forward(&optbuf, optlen);
4115 					ADD_STRING(target, "\n");
4116 					continue;
4117 				}
4118 			} else if (optcode == DNS_OPT_EXPIRE) {
4119 				ADD_STRING(target, "; EXPIRE:");
4120 				if (optlen == 4) {
4121 					uint32_t secs;
4122 					secs = isc_buffer_getuint32(&optbuf);
4123 					snprintf(buf, sizeof(buf), " %u", secs);
4124 					ADD_STRING(target, buf);
4125 					ADD_STRING(target, " (");
4126 					result = dns_ttl_totext(secs, true,
4127 								true, target);
4128 					if (result != ISC_R_SUCCESS) {
4129 						return (result);
4130 					}
4131 					ADD_STRING(target, ")\n");
4132 					continue;
4133 				}
4134 			} else if (optcode == DNS_OPT_TCP_KEEPALIVE) {
4135 				ADD_STRING(target, "; TCP KEEPALIVE:");
4136 				if (optlen == 2) {
4137 					unsigned int dsecs;
4138 					dsecs = isc_buffer_getuint16(&optbuf);
4139 					snprintf(buf, sizeof(buf), " %u.%u",
4140 						 dsecs / 10U, dsecs % 10U);
4141 					ADD_STRING(target, buf);
4142 					ADD_STRING(target, " secs\n");
4143 					continue;
4144 				}
4145 			} else if (optcode == DNS_OPT_PAD) {
4146 				ADD_STRING(target, "; PAD:");
4147 				if (optlen > 0U) {
4148 					snprintf(buf, sizeof(buf),
4149 						 " (%u bytes)", optlen);
4150 					ADD_STRING(target, buf);
4151 					isc_buffer_forward(&optbuf, optlen);
4152 				}
4153 				ADD_STRING(target, "\n");
4154 				continue;
4155 			} else if (optcode == DNS_OPT_KEY_TAG) {
4156 				ADD_STRING(target, "; KEY-TAG:");
4157 				if (optlen > 0U && (optlen % 2U) == 0U) {
4158 					const char *sep = "";
4159 					uint16_t id;
4160 					while (optlen > 0U) {
4161 						id = isc_buffer_getuint16(
4162 							&optbuf);
4163 						snprintf(buf, sizeof(buf),
4164 							 "%s %u", sep, id);
4165 						ADD_STRING(target, buf);
4166 						sep = ",";
4167 						optlen -= 2;
4168 					}
4169 					ADD_STRING(target, "\n");
4170 					continue;
4171 				}
4172 			} else if (optcode == DNS_OPT_EDE) {
4173 				ADD_STRING(target, "; EDE:");
4174 				if (optlen >= 2U) {
4175 					uint16_t ede;
4176 					ede = isc_buffer_getuint16(&optbuf);
4177 					snprintf(buf, sizeof(buf), " %u", ede);
4178 					ADD_STRING(target, buf);
4179 					if (ede < ARRAY_SIZE(edetext)) {
4180 						ADD_STRING(target, " (");
4181 						ADD_STRING(target,
4182 							   edetext[ede]);
4183 						ADD_STRING(target, ")");
4184 					}
4185 					optlen -= 2;
4186 					if (optlen != 0) {
4187 						ADD_STRING(target, ":");
4188 					}
4189 				} else if (optlen == 1U) {
4190 					/* Malformed */
4191 					optdata = isc_buffer_current(&optbuf);
4192 					snprintf(buf, sizeof(buf),
4193 						 " %02x (\"%c\")\n", optdata[0],
4194 						 isprint(optdata[0])
4195 							 ? optdata[0]
4196 							 : '.');
4197 					isc_buffer_forward(&optbuf, optlen);
4198 					ADD_STRING(target, buf);
4199 					continue;
4200 				}
4201 			} else if (optcode == DNS_OPT_CLIENT_TAG) {
4202 				uint16_t id;
4203 				ADD_STRING(target, "; CLIENT-TAG:");
4204 				if (optlen == 2U) {
4205 					id = isc_buffer_getuint16(&optbuf);
4206 					snprintf(buf, sizeof(buf), " %u\n", id);
4207 					ADD_STRING(target, buf);
4208 					optlen -= 2;
4209 					POST(optlen);
4210 					continue;
4211 				}
4212 			} else if (optcode == DNS_OPT_SERVER_TAG) {
4213 				uint16_t id;
4214 				ADD_STRING(target, "; SERVER-TAG:");
4215 				if (optlen == 2U) {
4216 					id = isc_buffer_getuint16(&optbuf);
4217 					snprintf(buf, sizeof(buf), " %u\n", id);
4218 					ADD_STRING(target, buf);
4219 					optlen -= 2;
4220 					POST(optlen);
4221 					continue;
4222 				}
4223 			} else {
4224 				ADD_STRING(target, "; OPT=");
4225 				snprintf(buf, sizeof(buf), "%u:", optcode);
4226 				ADD_STRING(target, buf);
4227 			}
4228 
4229 			if (optlen != 0) {
4230 				int i;
4231 				bool utf8ok = false;
4232 
4233 				ADD_STRING(target, " ");
4234 
4235 				optdata = isc_buffer_current(&optbuf);
4236 				if (optcode == DNS_OPT_EDE) {
4237 					utf8ok = isc_utf8_valid(optdata,
4238 								optlen);
4239 				}
4240 				if (!utf8ok) {
4241 					for (i = 0; i < optlen; i++) {
4242 						const char *sep;
4243 						switch (optcode) {
4244 						case DNS_OPT_COOKIE:
4245 							sep = "";
4246 							break;
4247 						default:
4248 							sep = " ";
4249 							break;
4250 						}
4251 						snprintf(buf, sizeof(buf),
4252 							 "%02x%s", optdata[i],
4253 							 sep);
4254 						ADD_STRING(target, buf);
4255 					}
4256 				}
4257 
4258 				isc_buffer_forward(&optbuf, optlen);
4259 
4260 				if (optcode == DNS_OPT_COOKIE) {
4261 					/*
4262 					 * Valid server cookie?
4263 					 */
4264 					if (msg->cc_ok && optlen >= 16) {
4265 						ADD_STRING(target, " (good)");
4266 					}
4267 					/*
4268 					 * Server cookie is not valid but
4269 					 * we had our cookie echoed back.
4270 					 */
4271 					if (msg->cc_ok && optlen < 16) {
4272 						ADD_STRING(target, " (echoed)");
4273 					}
4274 					/*
4275 					 * We didn't get our cookie echoed
4276 					 * back.
4277 					 */
4278 					if (msg->cc_bad) {
4279 						ADD_STRING(target, " (bad)");
4280 					}
4281 					ADD_STRING(target, "\n");
4282 					continue;
4283 				}
4284 
4285 				if (optcode == DNS_OPT_CLIENT_SUBNET) {
4286 					ADD_STRING(target, "\n");
4287 					continue;
4288 				}
4289 
4290 				/*
4291 				 * For non-COOKIE options, add a printable
4292 				 * version.
4293 				 */
4294 				if (optcode != DNS_OPT_EDE) {
4295 					ADD_STRING(target, "(\"");
4296 				} else {
4297 					ADD_STRING(target, "(");
4298 				}
4299 				if (isc_buffer_availablelength(target) < optlen)
4300 				{
4301 					return (ISC_R_NOSPACE);
4302 				}
4303 				for (i = 0; i < optlen; i++) {
4304 					if (isprint(optdata[i]) ||
4305 					    (utf8ok && optdata[i] > 127))
4306 					{
4307 						isc_buffer_putmem(
4308 							target, &optdata[i], 1);
4309 					} else {
4310 						isc_buffer_putstr(target, ".");
4311 					}
4312 				}
4313 				if (optcode != DNS_OPT_EDE) {
4314 					ADD_STRING(target, "\")");
4315 				} else {
4316 					ADD_STRING(target, ")");
4317 				}
4318 			}
4319 			ADD_STRING(target, "\n");
4320 		}
4321 		return (ISC_R_SUCCESS);
4322 	case DNS_PSEUDOSECTION_TSIG:
4323 		ps = dns_message_gettsig(msg, &name);
4324 		if (ps == NULL) {
4325 			return (ISC_R_SUCCESS);
4326 		}
4327 		INDENT(style);
4328 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
4329 			ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
4330 		}
4331 		result = dns_master_rdatasettotext(name, ps, style,
4332 						   &msg->indent, target);
4333 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
4334 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4335 		{
4336 			ADD_STRING(target, "\n");
4337 		}
4338 		return (result);
4339 	case DNS_PSEUDOSECTION_SIG0:
4340 		ps = dns_message_getsig0(msg, &name);
4341 		if (ps == NULL) {
4342 			return (ISC_R_SUCCESS);
4343 		}
4344 		INDENT(style);
4345 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
4346 			ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
4347 		}
4348 		result = dns_master_rdatasettotext(name, ps, style,
4349 						   &msg->indent, target);
4350 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
4351 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4352 		{
4353 			ADD_STRING(target, "\n");
4354 		}
4355 		return (result);
4356 	}
4357 	result = ISC_R_UNEXPECTED;
4358 cleanup:
4359 	return (result);
4360 }
4361 
4362 isc_result_t
4363 dns_message_headertotext(dns_message_t *msg, const dns_master_style_t *style,
4364 			 dns_messagetextflag_t flags, isc_buffer_t *target) {
4365 	char buf[sizeof("1234567890")];
4366 	isc_result_t result;
4367 
4368 	REQUIRE(DNS_MESSAGE_VALID(msg));
4369 	REQUIRE(target != NULL);
4370 
4371 	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) != 0) {
4372 		return (ISC_R_SUCCESS);
4373 	}
4374 
4375 	if (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) {
4376 		INDENT(style);
4377 		ADD_STRING(target, "opcode: ");
4378 		ADD_STRING(target, opcodetext[msg->opcode]);
4379 		ADD_STRING(target, "\n");
4380 		INDENT(style);
4381 		ADD_STRING(target, "status: ");
4382 		result = dns_rcode_totext(msg->rcode, target);
4383 		if (result != ISC_R_SUCCESS) {
4384 			return (result);
4385 		}
4386 		ADD_STRING(target, "\n");
4387 		INDENT(style);
4388 		ADD_STRING(target, "id: ");
4389 		snprintf(buf, sizeof(buf), "%u", msg->id);
4390 		ADD_STRING(target, buf);
4391 		ADD_STRING(target, "\n");
4392 		INDENT(style);
4393 		ADD_STRING(target, "flags:");
4394 		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
4395 			ADD_STRING(target, " qr");
4396 		}
4397 		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
4398 			ADD_STRING(target, " aa");
4399 		}
4400 		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
4401 			ADD_STRING(target, " tc");
4402 		}
4403 		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
4404 			ADD_STRING(target, " rd");
4405 		}
4406 		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
4407 			ADD_STRING(target, " ra");
4408 		}
4409 		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
4410 			ADD_STRING(target, " ad");
4411 		}
4412 		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
4413 			ADD_STRING(target, " cd");
4414 		}
4415 		ADD_STRING(target, "\n");
4416 		/*
4417 		 * The final unnamed flag must be zero.
4418 		 */
4419 		if ((msg->flags & 0x0040U) != 0) {
4420 			INDENT(style);
4421 			ADD_STRING(target, "MBZ: 0x4");
4422 			ADD_STRING(target, "\n");
4423 		}
4424 		if (msg->opcode != dns_opcode_update) {
4425 			INDENT(style);
4426 			ADD_STRING(target, "QUESTION: ");
4427 		} else {
4428 			INDENT(style);
4429 			ADD_STRING(target, "ZONE: ");
4430 		}
4431 		snprintf(buf, sizeof(buf), "%1u",
4432 			 msg->counts[DNS_SECTION_QUESTION]);
4433 		ADD_STRING(target, buf);
4434 		ADD_STRING(target, "\n");
4435 		if (msg->opcode != dns_opcode_update) {
4436 			INDENT(style);
4437 			ADD_STRING(target, "ANSWER: ");
4438 		} else {
4439 			INDENT(style);
4440 			ADD_STRING(target, "PREREQ: ");
4441 		}
4442 		snprintf(buf, sizeof(buf), "%1u",
4443 			 msg->counts[DNS_SECTION_ANSWER]);
4444 		ADD_STRING(target, buf);
4445 		ADD_STRING(target, "\n");
4446 		if (msg->opcode != dns_opcode_update) {
4447 			INDENT(style);
4448 			ADD_STRING(target, "AUTHORITY: ");
4449 		} else {
4450 			INDENT(style);
4451 			ADD_STRING(target, "UPDATE: ");
4452 		}
4453 		snprintf(buf, sizeof(buf), "%1u",
4454 			 msg->counts[DNS_SECTION_AUTHORITY]);
4455 		ADD_STRING(target, buf);
4456 		ADD_STRING(target, "\n");
4457 		INDENT(style);
4458 		ADD_STRING(target, "ADDITIONAL: ");
4459 		snprintf(buf, sizeof(buf), "%1u",
4460 			 msg->counts[DNS_SECTION_ADDITIONAL]);
4461 		ADD_STRING(target, buf);
4462 		ADD_STRING(target, "\n");
4463 	} else {
4464 		INDENT(style);
4465 		ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
4466 		ADD_STRING(target, opcodetext[msg->opcode]);
4467 		ADD_STRING(target, ", status: ");
4468 		result = dns_rcode_totext(msg->rcode, target);
4469 		if (result != ISC_R_SUCCESS) {
4470 			return (result);
4471 		}
4472 		ADD_STRING(target, ", id: ");
4473 		snprintf(buf, sizeof(buf), "%6u", msg->id);
4474 		ADD_STRING(target, buf);
4475 		ADD_STRING(target, "\n");
4476 		INDENT(style);
4477 		ADD_STRING(target, ";; flags:");
4478 		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
4479 			ADD_STRING(target, " qr");
4480 		}
4481 		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
4482 			ADD_STRING(target, " aa");
4483 		}
4484 		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
4485 			ADD_STRING(target, " tc");
4486 		}
4487 		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
4488 			ADD_STRING(target, " rd");
4489 		}
4490 		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
4491 			ADD_STRING(target, " ra");
4492 		}
4493 		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
4494 			ADD_STRING(target, " ad");
4495 		}
4496 		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
4497 			ADD_STRING(target, " cd");
4498 		}
4499 		/*
4500 		 * The final unnamed flag must be zero.
4501 		 */
4502 		if ((msg->flags & 0x0040U) != 0) {
4503 			INDENT(style);
4504 			ADD_STRING(target, "; MBZ: 0x4");
4505 		}
4506 		if (msg->opcode != dns_opcode_update) {
4507 			INDENT(style);
4508 			ADD_STRING(target, "; QUESTION: ");
4509 		} else {
4510 			INDENT(style);
4511 			ADD_STRING(target, "; ZONE: ");
4512 		}
4513 		snprintf(buf, sizeof(buf), "%1u",
4514 			 msg->counts[DNS_SECTION_QUESTION]);
4515 		ADD_STRING(target, buf);
4516 		if (msg->opcode != dns_opcode_update) {
4517 			ADD_STRING(target, ", ANSWER: ");
4518 		} else {
4519 			ADD_STRING(target, ", PREREQ: ");
4520 		}
4521 		snprintf(buf, sizeof(buf), "%1u",
4522 			 msg->counts[DNS_SECTION_ANSWER]);
4523 		ADD_STRING(target, buf);
4524 		if (msg->opcode != dns_opcode_update) {
4525 			ADD_STRING(target, ", AUTHORITY: ");
4526 		} else {
4527 			ADD_STRING(target, ", UPDATE: ");
4528 		}
4529 		snprintf(buf, sizeof(buf), "%1u",
4530 			 msg->counts[DNS_SECTION_AUTHORITY]);
4531 		ADD_STRING(target, buf);
4532 		ADD_STRING(target, ", ADDITIONAL: ");
4533 		snprintf(buf, sizeof(buf), "%1u",
4534 			 msg->counts[DNS_SECTION_ADDITIONAL]);
4535 		ADD_STRING(target, buf);
4536 		ADD_STRING(target, "\n");
4537 	}
4538 
4539 cleanup:
4540 	return (result);
4541 }
4542 
4543 isc_result_t
4544 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
4545 		   dns_messagetextflag_t flags, isc_buffer_t *target) {
4546 	isc_result_t result;
4547 
4548 	REQUIRE(DNS_MESSAGE_VALID(msg));
4549 	REQUIRE(target != NULL);
4550 
4551 	result = dns_message_headertotext(msg, style, flags, target);
4552 	if (result != ISC_R_SUCCESS) {
4553 		return (result);
4554 	}
4555 
4556 	result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_OPT,
4557 						 style, flags, target);
4558 	if (result != ISC_R_SUCCESS) {
4559 		return (result);
4560 	}
4561 
4562 	result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION, style,
4563 					   flags, target);
4564 	if (result != ISC_R_SUCCESS) {
4565 		return (result);
4566 	}
4567 
4568 	result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER, style,
4569 					   flags, target);
4570 	if (result != ISC_R_SUCCESS) {
4571 		return (result);
4572 	}
4573 
4574 	result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY, style,
4575 					   flags, target);
4576 	if (result != ISC_R_SUCCESS) {
4577 		return (result);
4578 	}
4579 
4580 	result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL, style,
4581 					   flags, target);
4582 	if (result != ISC_R_SUCCESS) {
4583 		return (result);
4584 	}
4585 
4586 	result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_TSIG,
4587 						 style, flags, target);
4588 	if (result != ISC_R_SUCCESS) {
4589 		return (result);
4590 	}
4591 
4592 	result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_SIG0,
4593 						 style, flags, target);
4594 	return (result);
4595 }
4596 
4597 isc_region_t *
4598 dns_message_getrawmessage(dns_message_t *msg) {
4599 	REQUIRE(DNS_MESSAGE_VALID(msg));
4600 	return (&msg->saved);
4601 }
4602 
4603 void
4604 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
4605 			 dns_aclenv_t *env, const dns_acl_t *acl,
4606 			 const dns_aclelement_t *elem) {
4607 	REQUIRE(DNS_MESSAGE_VALID(msg));
4608 	REQUIRE((order == NULL) == (env == NULL));
4609 	REQUIRE(env == NULL || (acl != NULL || elem != NULL));
4610 
4611 	msg->order = order;
4612 	msg->order_arg.env = env;
4613 	msg->order_arg.acl = acl;
4614 	msg->order_arg.element = elem;
4615 }
4616 
4617 void
4618 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
4619 	REQUIRE(DNS_MESSAGE_VALID(msg));
4620 	msg->timeadjust = timeadjust;
4621 }
4622 
4623 int
4624 dns_message_gettimeadjust(dns_message_t *msg) {
4625 	REQUIRE(DNS_MESSAGE_VALID(msg));
4626 	return (msg->timeadjust);
4627 }
4628 
4629 isc_result_t
4630 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
4631 	REQUIRE(opcode < 16);
4632 
4633 	if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode])) {
4634 		return (ISC_R_NOSPACE);
4635 	}
4636 	isc_buffer_putstr(target, opcodetext[opcode]);
4637 	return (ISC_R_SUCCESS);
4638 }
4639 
4640 void
4641 dns_message_logpacket(dns_message_t *message, const char *description,
4642 		      const isc_sockaddr_t *address,
4643 		      isc_logcategory_t *category, isc_logmodule_t *module,
4644 		      int level, isc_mem_t *mctx) {
4645 	REQUIRE(address != NULL);
4646 
4647 	logfmtpacket(message, description, address, category, module,
4648 		     &dns_master_style_debug, level, mctx);
4649 }
4650 
4651 void
4652 dns_message_logfmtpacket(dns_message_t *message, const char *description,
4653 			 const isc_sockaddr_t *address,
4654 			 isc_logcategory_t *category, isc_logmodule_t *module,
4655 			 const dns_master_style_t *style, int level,
4656 			 isc_mem_t *mctx) {
4657 	REQUIRE(address != NULL);
4658 
4659 	logfmtpacket(message, description, address, category, module, style,
4660 		     level, mctx);
4661 }
4662 
4663 static void
4664 logfmtpacket(dns_message_t *message, const char *description,
4665 	     const isc_sockaddr_t *address, isc_logcategory_t *category,
4666 	     isc_logmodule_t *module, const dns_master_style_t *style,
4667 	     int level, isc_mem_t *mctx) {
4668 	char addrbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
4669 	const char *newline = "\n";
4670 	const char *space = " ";
4671 	isc_buffer_t buffer;
4672 	char *buf = NULL;
4673 	int len = 1024;
4674 	isc_result_t result;
4675 
4676 	if (!isc_log_wouldlog(dns_lctx, level)) {
4677 		return;
4678 	}
4679 
4680 	/*
4681 	 * Note that these are multiline debug messages.  We want a newline
4682 	 * to appear in the log after each message.
4683 	 */
4684 
4685 	if (address != NULL) {
4686 		isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
4687 	} else {
4688 		newline = space = "";
4689 	}
4690 
4691 	do {
4692 		buf = isc_mem_get(mctx, len);
4693 		isc_buffer_init(&buffer, buf, len);
4694 		result = dns_message_totext(message, style, 0, &buffer);
4695 		if (result == ISC_R_NOSPACE) {
4696 			isc_mem_put(mctx, buf, len);
4697 			len += 1024;
4698 		} else if (result == ISC_R_SUCCESS) {
4699 			isc_log_write(dns_lctx, category, module, level,
4700 				      "%s%s%s%s%.*s", description, space,
4701 				      addrbuf, newline,
4702 				      (int)isc_buffer_usedlength(&buffer), buf);
4703 		}
4704 	} while (result == ISC_R_NOSPACE);
4705 
4706 	if (buf != NULL) {
4707 		isc_mem_put(mctx, buf, len);
4708 	}
4709 }
4710 
4711 isc_result_t
4712 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
4713 		     unsigned int version, uint16_t udpsize, unsigned int flags,
4714 		     dns_ednsopt_t *ednsopts, size_t count) {
4715 	dns_rdataset_t *rdataset = NULL;
4716 	dns_rdatalist_t *rdatalist = NULL;
4717 	dns_rdata_t *rdata = NULL;
4718 	isc_result_t result;
4719 	unsigned int len = 0, i;
4720 
4721 	REQUIRE(DNS_MESSAGE_VALID(message));
4722 	REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
4723 
4724 	result = dns_message_gettemprdatalist(message, &rdatalist);
4725 	if (result != ISC_R_SUCCESS) {
4726 		return (result);
4727 	}
4728 	result = dns_message_gettemprdata(message, &rdata);
4729 	if (result != ISC_R_SUCCESS) {
4730 		goto cleanup;
4731 	}
4732 	result = dns_message_gettemprdataset(message, &rdataset);
4733 	if (result != ISC_R_SUCCESS) {
4734 		goto cleanup;
4735 	}
4736 
4737 	rdatalist->type = dns_rdatatype_opt;
4738 
4739 	/*
4740 	 * Set Maximum UDP buffer size.
4741 	 */
4742 	rdatalist->rdclass = udpsize;
4743 
4744 	/*
4745 	 * Set EXTENDED-RCODE and Z to 0.
4746 	 */
4747 	rdatalist->ttl = (version << 16);
4748 	rdatalist->ttl |= (flags & 0xffff);
4749 
4750 	/*
4751 	 * Set EDNS options if applicable
4752 	 */
4753 	if (count != 0U) {
4754 		isc_buffer_t *buf = NULL;
4755 		bool seenpad = false;
4756 		for (i = 0; i < count; i++) {
4757 			len += ednsopts[i].length + 4;
4758 		}
4759 
4760 		if (len > 0xffffU) {
4761 			result = ISC_R_NOSPACE;
4762 			goto cleanup;
4763 		}
4764 
4765 		isc_buffer_allocate(message->mctx, &buf, len);
4766 
4767 		for (i = 0; i < count; i++) {
4768 			if (ednsopts[i].code == DNS_OPT_PAD &&
4769 			    ednsopts[i].length == 0U && !seenpad)
4770 			{
4771 				seenpad = true;
4772 				continue;
4773 			}
4774 			isc_buffer_putuint16(buf, ednsopts[i].code);
4775 			isc_buffer_putuint16(buf, ednsopts[i].length);
4776 			if (ednsopts[i].length != 0) {
4777 				isc_buffer_putmem(buf, ednsopts[i].value,
4778 						  ednsopts[i].length);
4779 			}
4780 		}
4781 
4782 		/* Padding must be the final option */
4783 		if (seenpad) {
4784 			isc_buffer_putuint16(buf, DNS_OPT_PAD);
4785 			isc_buffer_putuint16(buf, 0);
4786 		}
4787 		rdata->data = isc_buffer_base(buf);
4788 		rdata->length = len;
4789 		dns_message_takebuffer(message, &buf);
4790 		if (seenpad) {
4791 			message->padding_off = len;
4792 		}
4793 	} else {
4794 		rdata->data = NULL;
4795 		rdata->length = 0;
4796 	}
4797 
4798 	rdata->rdclass = rdatalist->rdclass;
4799 	rdata->type = rdatalist->type;
4800 	rdata->flags = 0;
4801 
4802 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
4803 	result = dns_rdatalist_tordataset(rdatalist, rdataset);
4804 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
4805 
4806 	*rdatasetp = rdataset;
4807 	return (ISC_R_SUCCESS);
4808 
4809 cleanup:
4810 	if (rdata != NULL) {
4811 		dns_message_puttemprdata(message, &rdata);
4812 	}
4813 	if (rdataset != NULL) {
4814 		dns_message_puttemprdataset(message, &rdataset);
4815 	}
4816 	if (rdatalist != NULL) {
4817 		dns_message_puttemprdatalist(message, &rdatalist);
4818 	}
4819 	return (result);
4820 }
4821 
4822 void
4823 dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
4824 	REQUIRE(DNS_MESSAGE_VALID(msg));
4825 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
4826 	REQUIRE(msg->state == DNS_SECTION_ANY);
4827 	REQUIRE(msg->rdclass_set == 0);
4828 
4829 	msg->rdclass = rdclass;
4830 	msg->rdclass_set = 1;
4831 }
4832 
4833 void
4834 dns_message_setpadding(dns_message_t *msg, uint16_t padding) {
4835 	REQUIRE(DNS_MESSAGE_VALID(msg));
4836 
4837 	/* Avoid silly large padding */
4838 	if (padding > 512) {
4839 		padding = 512;
4840 	}
4841 	msg->padding = padding;
4842 }
4843 
4844 void
4845 dns_message_clonebuffer(dns_message_t *msg) {
4846 	REQUIRE(DNS_MESSAGE_VALID(msg));
4847 
4848 	if (msg->free_saved == 0 && msg->saved.base != NULL) {
4849 		msg->saved.base =
4850 			memmove(isc_mem_get(msg->mctx, msg->saved.length),
4851 				msg->saved.base, msg->saved.length);
4852 		msg->free_saved = 1;
4853 	}
4854 	if (msg->free_query == 0 && msg->query.base != NULL) {
4855 		msg->query.base =
4856 			memmove(isc_mem_get(msg->mctx, msg->query.length),
4857 				msg->query.base, msg->query.length);
4858 		msg->free_query = 1;
4859 	}
4860 }
4861