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