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