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