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