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