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