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