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