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