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