Home | History | Annotate | Line # | Download | only in dns
message.c revision 1.4
      1 /*	$NetBSD: message.c,v 1.4 2019/02/24 20:01:30 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, false,
    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 issigzero;
   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 
   1259 		name = isc_mempool_get(msg->namepool);
   1260 		if (name == NULL)
   1261 			return (ISC_R_NOMEMORY);
   1262 		free_name = true;
   1263 
   1264 		offsets = newoffsets(msg);
   1265 		if (offsets == NULL) {
   1266 			result = ISC_R_NOMEMORY;
   1267 			goto cleanup;
   1268 		}
   1269 		dns_name_init(name, *offsets);
   1270 
   1271 		/*
   1272 		 * Parse the name out of this packet.
   1273 		 */
   1274 		isc_buffer_remainingregion(source, &r);
   1275 		isc_buffer_setactive(source, r.length);
   1276 		result = getname(name, source, msg, dctx);
   1277 		if (result != ISC_R_SUCCESS)
   1278 			goto cleanup;
   1279 
   1280 		/*
   1281 		 * Get type, class, ttl, and rdatalen.  Verify that at least
   1282 		 * rdatalen bytes remain.  (Some of this is deferred to
   1283 		 * later.)
   1284 		 */
   1285 		isc_buffer_remainingregion(source, &r);
   1286 		if (r.length < 2 + 2 + 4 + 2) {
   1287 			result = ISC_R_UNEXPECTEDEND;
   1288 			goto cleanup;
   1289 		}
   1290 		rdtype = isc_buffer_getuint16(source);
   1291 		rdclass = isc_buffer_getuint16(source);
   1292 
   1293 		/*
   1294 		 * If there was no question section, we may not yet have
   1295 		 * established a class.  Do so now.
   1296 		 */
   1297 		if (msg->rdclass_set == 0 &&
   1298 		    rdtype != dns_rdatatype_opt &&	/* class is UDP SIZE */
   1299 		    rdtype != dns_rdatatype_tsig &&	/* class is ANY */
   1300 		    rdtype != dns_rdatatype_tkey) {	/* class is undefined */
   1301 			msg->rdclass = rdclass;
   1302 			msg->rdclass_set = 1;
   1303 		}
   1304 
   1305 		/*
   1306 		 * If this class is different than the one in the question
   1307 		 * section, bail.
   1308 		 */
   1309 		if (msg->opcode != dns_opcode_update
   1310 		    && rdtype != dns_rdatatype_tsig
   1311 		    && rdtype != dns_rdatatype_opt
   1312 		    && rdtype != dns_rdatatype_key /* in a TKEY query */
   1313 		    && rdtype != dns_rdatatype_sig /* SIG(0) */
   1314 		    && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
   1315 		    && msg->rdclass != dns_rdataclass_any
   1316 		    && msg->rdclass != rdclass)
   1317 			DO_ERROR(DNS_R_FORMERR);
   1318 
   1319 		/*
   1320 		 * If this is not a TKEY query/response then the KEY
   1321 		 * record's class needs to match.
   1322 		 */
   1323 		if (msg->opcode != dns_opcode_update && !msg->tkey &&
   1324 		    rdtype == dns_rdatatype_key &&
   1325 		    msg->rdclass != dns_rdataclass_any &&
   1326 		    msg->rdclass != rdclass)
   1327 			DO_ERROR(DNS_R_FORMERR);
   1328 
   1329 		/*
   1330 		 * Special type handling for TSIG, OPT, and TKEY.
   1331 		 */
   1332 		if (rdtype == dns_rdatatype_tsig) {
   1333 			/*
   1334 			 * If it is a tsig, verify that it is in the
   1335 			 * additional data section.
   1336 			 */
   1337 			if (sectionid != DNS_SECTION_ADDITIONAL ||
   1338 			    rdclass != dns_rdataclass_any ||
   1339 			    count != msg->counts[sectionid]  - 1)
   1340 				DO_ERROR(DNS_R_BADTSIG);
   1341 			msg->sigstart = recstart;
   1342 			skip_name_search = true;
   1343 			skip_type_search = true;
   1344 		} else if (rdtype == dns_rdatatype_opt) {
   1345 			/*
   1346 			 * The name of an OPT record must be ".", it
   1347 			 * must be in the additional data section, and
   1348 			 * it must be the first OPT we've seen.
   1349 			 */
   1350 			if (!dns_name_equal(dns_rootname, name) ||
   1351 			    sectionid != DNS_SECTION_ADDITIONAL ||
   1352 			    msg->opt != NULL)
   1353 				DO_ERROR(DNS_R_FORMERR);
   1354 			skip_name_search = true;
   1355 			skip_type_search = true;
   1356 		} else if (rdtype == dns_rdatatype_tkey) {
   1357 			/*
   1358 			 * A TKEY must be in the additional section if this
   1359 			 * is a query, and the answer section if this is a
   1360 			 * response.  Unless it's a Win2000 client.
   1361 			 *
   1362 			 * Its class is ignored.
   1363 			 */
   1364 			dns_section_t tkeysection;
   1365 
   1366 			if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
   1367 				tkeysection = DNS_SECTION_ADDITIONAL;
   1368 			else
   1369 				tkeysection = DNS_SECTION_ANSWER;
   1370 			if (sectionid != tkeysection &&
   1371 			    sectionid != DNS_SECTION_ANSWER)
   1372 				DO_ERROR(DNS_R_FORMERR);
   1373 		}
   1374 
   1375 		/*
   1376 		 * ... now get ttl and rdatalen, and check buffer.
   1377 		 */
   1378 		ttl = isc_buffer_getuint32(source);
   1379 		rdatalen = isc_buffer_getuint16(source);
   1380 		r.length -= (2 + 2 + 4 + 2);
   1381 		if (r.length < rdatalen) {
   1382 			result = ISC_R_UNEXPECTEDEND;
   1383 			goto cleanup;
   1384 		}
   1385 
   1386 		/*
   1387 		 * Read the rdata from the wire format.  Interpret the
   1388 		 * rdata according to its actual class, even if it had a
   1389 		 * DynDNS meta-class in the packet (unless this is a TSIG).
   1390 		 * Then put the meta-class back into the finished rdata.
   1391 		 */
   1392 		rdata = newrdata(msg);
   1393 		if (rdata == NULL) {
   1394 			result = ISC_R_NOMEMORY;
   1395 			goto cleanup;
   1396 		}
   1397 		if (msg->opcode == dns_opcode_update &&
   1398 		    update(sectionid, rdclass)) {
   1399 			if (rdatalen != 0) {
   1400 				result = DNS_R_FORMERR;
   1401 				goto cleanup;
   1402 			}
   1403 			/*
   1404 			 * When the rdata is empty, the data pointer is
   1405 			 * never dereferenced, but it must still be non-NULL.
   1406 			 * Casting 1 rather than "" avoids warnings about
   1407 			 * discarding the const attribute of a string,
   1408 			 * for compilers that would warn about such things.
   1409 			 */
   1410 			rdata->data = (unsigned char *)1;
   1411 			rdata->length = 0;
   1412 			rdata->rdclass = rdclass;
   1413 			rdata->type = rdtype;
   1414 			rdata->flags = DNS_RDATA_UPDATE;
   1415 			result = ISC_R_SUCCESS;
   1416 		} else if (rdclass == dns_rdataclass_none &&
   1417 			   msg->opcode == dns_opcode_update &&
   1418 			   sectionid == DNS_SECTION_UPDATE) {
   1419 			result = getrdata(source, msg, dctx, msg->rdclass,
   1420 					  rdtype, rdatalen, rdata);
   1421 		} else
   1422 			result = getrdata(source, msg, dctx, rdclass,
   1423 					  rdtype, rdatalen, rdata);
   1424 		if (result != ISC_R_SUCCESS)
   1425 			goto cleanup;
   1426 		rdata->rdclass = rdclass;
   1427 		issigzero = false;
   1428 		if (rdtype == dns_rdatatype_rrsig &&
   1429 		    rdata->flags == 0) {
   1430 			covers = dns_rdata_covers(rdata);
   1431 			if (covers == 0)
   1432 				DO_ERROR(DNS_R_FORMERR);
   1433 		} else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
   1434 			   rdata->flags == 0) {
   1435 			covers = dns_rdata_covers(rdata);
   1436 			if (covers == 0) {
   1437 				if (sectionid != DNS_SECTION_ADDITIONAL ||
   1438 				    count != msg->counts[sectionid]  - 1)
   1439 					DO_ERROR(DNS_R_BADSIG0);
   1440 				msg->sigstart = recstart;
   1441 				skip_name_search = true;
   1442 				skip_type_search = true;
   1443 				issigzero = true;
   1444 			} else {
   1445 				if (msg->rdclass != dns_rdataclass_any &&
   1446 				    msg->rdclass != rdclass)
   1447 					DO_ERROR(DNS_R_FORMERR);
   1448 			}
   1449 		} else
   1450 			covers = 0;
   1451 
   1452 		/*
   1453 		 * Check the ownername of NSEC3 records
   1454 		 */
   1455 		if (rdtype == dns_rdatatype_nsec3 &&
   1456 		    !dns_rdata_checkowner(name, msg->rdclass, rdtype,
   1457 					  false)) {
   1458 			result = DNS_R_BADOWNERNAME;
   1459 			goto cleanup;
   1460 		}
   1461 
   1462 		/*
   1463 		 * If we are doing a dynamic update or this is a meta-type,
   1464 		 * don't bother searching for a name, just append this one
   1465 		 * to the end of the message.
   1466 		 */
   1467 		if (preserve_order || msg->opcode == dns_opcode_update ||
   1468 		    skip_name_search) {
   1469 			if (rdtype != dns_rdatatype_opt &&
   1470 			    rdtype != dns_rdatatype_tsig &&
   1471 			    !issigzero)
   1472 			{
   1473 				ISC_LIST_APPEND(*section, name, link);
   1474 				free_name = false;
   1475 			}
   1476 		} else {
   1477 			/*
   1478 			 * Run through the section, looking to see if this name
   1479 			 * is already there.  If it is found, put back the
   1480 			 * allocated name since we no longer need it, and set
   1481 			 * our name pointer to point to the name we found.
   1482 			 */
   1483 			result = findname(&name2, name, section);
   1484 
   1485 			/*
   1486 			 * If it is a new name, append to the section.
   1487 			 */
   1488 			if (result == ISC_R_SUCCESS) {
   1489 				isc_mempool_put(msg->namepool, name);
   1490 				name = name2;
   1491 			} else {
   1492 				ISC_LIST_APPEND(*section, name, link);
   1493 			}
   1494 			free_name = false;
   1495 		}
   1496 
   1497 		/*
   1498 		 * Search name for the particular type and class.
   1499 		 * Skip this stage if in update mode or this is a meta-type.
   1500 		 */
   1501 		if (preserve_order || msg->opcode == dns_opcode_update ||
   1502 		    skip_type_search)
   1503 			result = ISC_R_NOTFOUND;
   1504 		else {
   1505 			/*
   1506 			 * If this is a type that can only occur in
   1507 			 * the question section, fail.
   1508 			 */
   1509 			if (dns_rdatatype_questiononly(rdtype))
   1510 				DO_ERROR(DNS_R_FORMERR);
   1511 
   1512 			rdataset = NULL;
   1513 			result = dns_message_find(name, rdclass, rdtype,
   1514 						   covers, &rdataset);
   1515 		}
   1516 
   1517 		/*
   1518 		 * If we found an rdataset that matches, we need to
   1519 		 * append this rdata to that set.  If we did not, we need
   1520 		 * to create a new rdatalist, store the important bits there,
   1521 		 * convert it to an rdataset, and link the latter to the name.
   1522 		 * Yuck.  When appending, make certain that the type isn't
   1523 		 * a singleton type, such as SOA or CNAME.
   1524 		 *
   1525 		 * Note that this check will be bypassed when preserving order,
   1526 		 * the opcode is an update, or the type search is skipped.
   1527 		 */
   1528 		if (result == ISC_R_SUCCESS) {
   1529 			if (dns_rdatatype_issingleton(rdtype)) {
   1530 				dns_rdata_t *first;
   1531 				dns_rdatalist_fromrdataset(rdataset,
   1532 							   &rdatalist);
   1533 				first = ISC_LIST_HEAD(rdatalist->rdata);
   1534 				INSIST(first != NULL);
   1535 				if (dns_rdata_compare(rdata, first) != 0)
   1536 					DO_ERROR(DNS_R_FORMERR);
   1537 			}
   1538 		}
   1539 
   1540 		if (result == ISC_R_NOTFOUND) {
   1541 			rdataset = isc_mempool_get(msg->rdspool);
   1542 			if (rdataset == NULL) {
   1543 				result = ISC_R_NOMEMORY;
   1544 				goto cleanup;
   1545 			}
   1546 			free_rdataset = true;
   1547 
   1548 			rdatalist = newrdatalist(msg);
   1549 			if (rdatalist == NULL) {
   1550 				result = ISC_R_NOMEMORY;
   1551 				goto cleanup;
   1552 			}
   1553 
   1554 			rdatalist->type = rdtype;
   1555 			rdatalist->covers = covers;
   1556 			rdatalist->rdclass = rdclass;
   1557 			rdatalist->ttl = ttl;
   1558 
   1559 			dns_rdataset_init(rdataset);
   1560 			RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
   1561 							       rdataset)
   1562 				      == ISC_R_SUCCESS);
   1563 			dns_rdataset_setownercase(rdataset, name);
   1564 
   1565 			if (rdtype != dns_rdatatype_opt &&
   1566 			    rdtype != dns_rdatatype_tsig &&
   1567 			    !issigzero)
   1568 			{
   1569 				ISC_LIST_APPEND(name->list, rdataset, link);
   1570 				free_rdataset = false;
   1571 			}
   1572 		}
   1573 
   1574 		/*
   1575 		 * Minimize TTLs.
   1576 		 *
   1577 		 * Section 5.2 of RFC2181 says we should drop
   1578 		 * nonauthoritative rrsets where the TTLs differ, but we
   1579 		 * currently treat them the as if they were authoritative and
   1580 		 * minimize them.
   1581 		 */
   1582 		if (ttl != rdataset->ttl) {
   1583 			rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
   1584 			if (ttl < rdataset->ttl)
   1585 				rdataset->ttl = ttl;
   1586 		}
   1587 
   1588 		/* Append this rdata to the rdataset. */
   1589 		dns_rdatalist_fromrdataset(rdataset, &rdatalist);
   1590 		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
   1591 
   1592 		/*
   1593 		 * If this is an OPT, SIG(0) or TSIG record, remember it.
   1594 		 * Also, set the extended rcode for TSIG.
   1595 		 *
   1596 		 * Note msg->opt, msg->sig0 and msg->tsig will only be
   1597 		 * already set if best-effort parsing is enabled otherwise
   1598 		 * there will only be at most one of each.
   1599 		 */
   1600 		if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
   1601 			dns_rcode_t ercode;
   1602 
   1603 			msg->opt = rdataset;
   1604 			rdataset = NULL;
   1605 			free_rdataset = false;
   1606 			ercode = (dns_rcode_t)
   1607 				((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
   1608 				 >> 20);
   1609 			msg->rcode |= ercode;
   1610 			isc_mempool_put(msg->namepool, name);
   1611 			free_name = false;
   1612 		} else if (issigzero && msg->sig0 == NULL) {
   1613 			msg->sig0 = rdataset;
   1614 			msg->sig0name = name;
   1615 			rdataset = NULL;
   1616 			free_rdataset = false;
   1617 			free_name = false;
   1618 		} else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
   1619 			msg->tsig = rdataset;
   1620 			msg->tsigname = name;
   1621 			/* Windows doesn't like TSIG names to be compressed. */
   1622 			msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
   1623 			rdataset = NULL;
   1624 			free_rdataset = false;
   1625 			free_name = false;
   1626 		}
   1627 
   1628 		if (seen_problem) {
   1629 			if (free_name)
   1630 				isc_mempool_put(msg->namepool, name);
   1631 			if (free_rdataset)
   1632 				isc_mempool_put(msg->rdspool, rdataset);
   1633 			free_name = free_rdataset = false;
   1634 		}
   1635 		INSIST(free_name == false);
   1636 		INSIST(free_rdataset == false);
   1637 	}
   1638 
   1639 	/*
   1640 	 * If any of DS, NSEC or NSEC3 appeared in the
   1641 	 * authority section of a query response without
   1642 	 * a covering RRSIG, FORMERR
   1643 	 */
   1644 	if (sectionid == DNS_SECTION_AUTHORITY &&
   1645 	    msg->opcode == dns_opcode_query &&
   1646 	    ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) &&
   1647 	    ((msg->flags & DNS_MESSAGEFLAG_TC) == 0) &&
   1648 	    !preserve_order &&
   1649 	    !auth_signed(section))
   1650 		DO_ERROR(DNS_R_FORMERR);
   1651 
   1652 	if (seen_problem)
   1653 		return (DNS_R_RECOVERABLE);
   1654 	return (ISC_R_SUCCESS);
   1655 
   1656  cleanup:
   1657 	if (free_name)
   1658 		isc_mempool_put(msg->namepool, name);
   1659 	if (free_rdataset)
   1660 		isc_mempool_put(msg->rdspool, rdataset);
   1661 
   1662 	return (result);
   1663 }
   1664 
   1665 isc_result_t
   1666 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
   1667 		  unsigned int options)
   1668 {
   1669 	isc_region_t r;
   1670 	dns_decompress_t dctx;
   1671 	isc_result_t ret;
   1672 	uint16_t tmpflags;
   1673 	isc_buffer_t origsource;
   1674 	bool seen_problem;
   1675 	bool ignore_tc;
   1676 
   1677 	REQUIRE(DNS_MESSAGE_VALID(msg));
   1678 	REQUIRE(source != NULL);
   1679 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
   1680 
   1681 	seen_problem = false;
   1682 	ignore_tc = ((options & DNS_MESSAGEPARSE_IGNORETRUNCATION) != 0);
   1683 
   1684 	origsource = *source;
   1685 
   1686 	msg->header_ok = 0;
   1687 	msg->question_ok = 0;
   1688 
   1689 	isc_buffer_remainingregion(source, &r);
   1690 	if (r.length < DNS_MESSAGE_HEADERLEN)
   1691 		return (ISC_R_UNEXPECTEDEND);
   1692 
   1693 	msg->id = isc_buffer_getuint16(source);
   1694 	tmpflags = isc_buffer_getuint16(source);
   1695 	msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
   1696 		       >> DNS_MESSAGE_OPCODE_SHIFT);
   1697 	msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
   1698 	msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
   1699 	msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
   1700 	msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
   1701 	msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
   1702 	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
   1703 
   1704 	msg->header_ok = 1;
   1705 	msg->state = DNS_SECTION_QUESTION;
   1706 
   1707 	/*
   1708 	 * -1 means no EDNS.
   1709 	 */
   1710 	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
   1711 
   1712 	dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
   1713 
   1714 	ret = getquestions(source, msg, &dctx, options);
   1715 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
   1716 		goto truncated;
   1717 	if (ret == DNS_R_RECOVERABLE) {
   1718 		seen_problem = true;
   1719 		ret = ISC_R_SUCCESS;
   1720 	}
   1721 	if (ret != ISC_R_SUCCESS)
   1722 		return (ret);
   1723 	msg->question_ok = 1;
   1724 
   1725 	ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
   1726 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
   1727 		goto truncated;
   1728 	if (ret == DNS_R_RECOVERABLE) {
   1729 		seen_problem = true;
   1730 		ret = ISC_R_SUCCESS;
   1731 	}
   1732 	if (ret != ISC_R_SUCCESS)
   1733 		return (ret);
   1734 
   1735 	ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
   1736 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
   1737 		goto truncated;
   1738 	if (ret == DNS_R_RECOVERABLE) {
   1739 		seen_problem = true;
   1740 		ret = ISC_R_SUCCESS;
   1741 	}
   1742 	if (ret != ISC_R_SUCCESS)
   1743 		return (ret);
   1744 
   1745 	ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
   1746 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
   1747 		goto truncated;
   1748 	if (ret == DNS_R_RECOVERABLE) {
   1749 		seen_problem = true;
   1750 		ret = ISC_R_SUCCESS;
   1751 	}
   1752 	if (ret != ISC_R_SUCCESS)
   1753 		return (ret);
   1754 
   1755 	isc_buffer_remainingregion(source, &r);
   1756 	if (r.length != 0) {
   1757 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
   1758 			      DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
   1759 			      "message has %u byte(s) of trailing garbage",
   1760 			      r.length);
   1761 	}
   1762 
   1763  truncated:
   1764 	if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
   1765 		isc_buffer_usedregion(&origsource, &msg->saved);
   1766 	else {
   1767 		msg->saved.length = isc_buffer_usedlength(&origsource);
   1768 		msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
   1769 		if (msg->saved.base == NULL)
   1770 			return (ISC_R_NOMEMORY);
   1771 		memmove(msg->saved.base, isc_buffer_base(&origsource),
   1772 			msg->saved.length);
   1773 		msg->free_saved = 1;
   1774 	}
   1775 
   1776 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
   1777 		return (DNS_R_RECOVERABLE);
   1778 	if (seen_problem == true)
   1779 		return (DNS_R_RECOVERABLE);
   1780 	return (ISC_R_SUCCESS);
   1781 }
   1782 
   1783 isc_result_t
   1784 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
   1785 			isc_buffer_t *buffer)
   1786 {
   1787 	isc_region_t r;
   1788 
   1789 	REQUIRE(DNS_MESSAGE_VALID(msg));
   1790 	REQUIRE(buffer != NULL);
   1791 	REQUIRE(msg->buffer == NULL);
   1792 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
   1793 
   1794 	msg->cctx = cctx;
   1795 
   1796 	/*
   1797 	 * Erase the contents of this buffer.
   1798 	 */
   1799 	isc_buffer_clear(buffer);
   1800 
   1801 	/*
   1802 	 * Make certain there is enough for at least the header in this
   1803 	 * buffer.
   1804 	 */
   1805 	isc_buffer_availableregion(buffer, &r);
   1806 	if (r.length < DNS_MESSAGE_HEADERLEN)
   1807 		return (ISC_R_NOSPACE);
   1808 
   1809 	if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
   1810 		return (ISC_R_NOSPACE);
   1811 
   1812 	/*
   1813 	 * Reserve enough space for the header in this buffer.
   1814 	 */
   1815 	isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
   1816 
   1817 	msg->buffer = buffer;
   1818 
   1819 	return (ISC_R_SUCCESS);
   1820 }
   1821 
   1822 isc_result_t
   1823 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
   1824 	isc_region_t r, rn;
   1825 
   1826 	REQUIRE(DNS_MESSAGE_VALID(msg));
   1827 	REQUIRE(buffer != NULL);
   1828 	REQUIRE(msg->buffer != NULL);
   1829 
   1830 	/*
   1831 	 * Ensure that the new buffer is empty, and has enough space to
   1832 	 * hold the current contents.
   1833 	 */
   1834 	isc_buffer_clear(buffer);
   1835 
   1836 	isc_buffer_availableregion(buffer, &rn);
   1837 	isc_buffer_usedregion(msg->buffer, &r);
   1838 	REQUIRE(rn.length > r.length);
   1839 
   1840 	/*
   1841 	 * Copy the contents from the old to the new buffer.
   1842 	 */
   1843 	isc_buffer_add(buffer, r.length);
   1844 	memmove(rn.base, r.base, r.length);
   1845 
   1846 	msg->buffer = buffer;
   1847 
   1848 	return (ISC_R_SUCCESS);
   1849 }
   1850 
   1851 void
   1852 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
   1853 	REQUIRE(DNS_MESSAGE_VALID(msg));
   1854 	REQUIRE(space <= msg->reserved);
   1855 
   1856 	msg->reserved -= space;
   1857 }
   1858 
   1859 isc_result_t
   1860 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
   1861 	isc_region_t r;
   1862 
   1863 	REQUIRE(DNS_MESSAGE_VALID(msg));
   1864 
   1865 	if (msg->buffer != NULL) {
   1866 		isc_buffer_availableregion(msg->buffer, &r);
   1867 		if (r.length < (space + msg->reserved))
   1868 			return (ISC_R_NOSPACE);
   1869 	}
   1870 
   1871 	msg->reserved += space;
   1872 
   1873 	return (ISC_R_SUCCESS);
   1874 }
   1875 
   1876 static inline bool
   1877 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
   1878 	int pass_needed;
   1879 
   1880 	/*
   1881 	 * If we are not rendering class IN, this ordering is bogus.
   1882 	 */
   1883 	if (rds->rdclass != dns_rdataclass_in)
   1884 		return (false);
   1885 
   1886 	switch (rds->type) {
   1887 	case dns_rdatatype_a:
   1888 	case dns_rdatatype_aaaa:
   1889 		if (preferred_glue == rds->type)
   1890 			pass_needed = 4;
   1891 		else
   1892 			pass_needed = 3;
   1893 		break;
   1894 	case dns_rdatatype_rrsig:
   1895 	case dns_rdatatype_dnskey:
   1896 		pass_needed = 2;
   1897 		break;
   1898 	default:
   1899 		pass_needed = 1;
   1900 	}
   1901 
   1902 	if (pass_needed >= pass)
   1903 		return (false);
   1904 
   1905 	return (true);
   1906 }
   1907 
   1908 static isc_result_t
   1909 renderset(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
   1910 	  dns_compress_t *cctx, isc_buffer_t *target,
   1911 	  unsigned int reserved, unsigned int options, unsigned int *countp)
   1912 {
   1913 	isc_result_t result;
   1914 
   1915 	/*
   1916 	 * Shrink the space in the buffer by the reserved amount.
   1917 	 */
   1918 	if (target->length - target->used < reserved)
   1919 		return (ISC_R_NOSPACE);
   1920 
   1921 	target->length -= reserved;
   1922 	result = dns_rdataset_towire(rdataset, owner_name,
   1923 				     cctx, target, options, countp);
   1924 	target->length += reserved;
   1925 
   1926 	return (result);
   1927 }
   1928 
   1929 static void
   1930 maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) {
   1931 	if (msg->counts[sectionid] == 0 &&
   1932 	    (sectionid == DNS_SECTION_ANSWER ||
   1933 	     (sectionid == DNS_SECTION_AUTHORITY &&
   1934 	      msg->counts[DNS_SECTION_ANSWER] == 0)))
   1935 		msg->flags &= ~DNS_MESSAGEFLAG_AD;
   1936 }
   1937 
   1938 isc_result_t
   1939 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
   1940 			  unsigned int options)
   1941 {
   1942 	dns_namelist_t *section;
   1943 	dns_name_t *name, *next_name;
   1944 	dns_rdataset_t *rdataset, *next_rdataset;
   1945 	unsigned int count, total;
   1946 	isc_result_t result;
   1947 	isc_buffer_t st; /* for rollbacks */
   1948 	int pass;
   1949 	bool partial = false;
   1950 	unsigned int rd_options;
   1951 	dns_rdatatype_t preferred_glue = 0;
   1952 
   1953 	REQUIRE(DNS_MESSAGE_VALID(msg));
   1954 	REQUIRE(msg->buffer != NULL);
   1955 	REQUIRE(VALID_NAMED_SECTION(sectionid));
   1956 
   1957 	section = &msg->sections[sectionid];
   1958 
   1959 	if ((sectionid == DNS_SECTION_ADDITIONAL)
   1960 	    && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
   1961 		if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
   1962 			preferred_glue = dns_rdatatype_a;
   1963 			pass = 4;
   1964 		} else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
   1965 			preferred_glue = dns_rdatatype_aaaa;
   1966 			pass = 4;
   1967 		} else
   1968 			pass = 3;
   1969 	} else
   1970 		pass = 1;
   1971 
   1972 	if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
   1973 		rd_options = 0;
   1974 	else
   1975 		rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
   1976 
   1977 	/*
   1978 	 * Shrink the space in the buffer by the reserved amount.
   1979 	 */
   1980 	if (msg->buffer->length - msg->buffer->used < msg->reserved)
   1981 		return (ISC_R_NOSPACE);
   1982 	msg->buffer->length -= msg->reserved;
   1983 
   1984 	total = 0;
   1985 	if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
   1986 		partial = true;
   1987 
   1988 	/*
   1989 	 * Render required glue first.  Set TC if it won't fit.
   1990 	 */
   1991 	name = ISC_LIST_HEAD(*section);
   1992 	if (name != NULL) {
   1993 		rdataset = ISC_LIST_HEAD(name->list);
   1994 		if (rdataset != NULL &&
   1995 		    (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
   1996 		    (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
   1997 			const void *order_arg = &msg->order_arg;
   1998 			st = *(msg->buffer);
   1999 			count = 0;
   2000 			if (partial)
   2001 				result = dns_rdataset_towirepartial(rdataset,
   2002 								    name,
   2003 								    msg->cctx,
   2004 								    msg->buffer,
   2005 								    msg->order,
   2006 								    order_arg,
   2007 								    rd_options,
   2008 								    &count,
   2009 								    NULL);
   2010 			else
   2011 				result = dns_rdataset_towiresorted(rdataset,
   2012 								   name,
   2013 								   msg->cctx,
   2014 								   msg->buffer,
   2015 								   msg->order,
   2016 								   order_arg,
   2017 								   rd_options,
   2018 								   &count);
   2019 			total += count;
   2020 			if (partial && result == ISC_R_NOSPACE) {
   2021 				msg->flags |= DNS_MESSAGEFLAG_TC;
   2022 				msg->buffer->length += msg->reserved;
   2023 				msg->counts[sectionid] += total;
   2024 				return (result);
   2025 			}
   2026 			if (result == ISC_R_NOSPACE)
   2027 				msg->flags |= DNS_MESSAGEFLAG_TC;
   2028 			if (result != ISC_R_SUCCESS) {
   2029 				INSIST(st.used < 65536);
   2030 				dns_compress_rollback(msg->cctx,
   2031 						      (uint16_t)st.used);
   2032 				*(msg->buffer) = st;  /* rollback */
   2033 				msg->buffer->length += msg->reserved;
   2034 				msg->counts[sectionid] += total;
   2035 				return (result);
   2036 			}
   2037 			rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
   2038 		}
   2039 	}
   2040 
   2041 	do {
   2042 		name = ISC_LIST_HEAD(*section);
   2043 		if (name == NULL) {
   2044 			msg->buffer->length += msg->reserved;
   2045 			msg->counts[sectionid] += total;
   2046 			return (ISC_R_SUCCESS);
   2047 		}
   2048 
   2049 		while (name != NULL) {
   2050 			next_name = ISC_LIST_NEXT(name, link);
   2051 
   2052 			rdataset = ISC_LIST_HEAD(name->list);
   2053 			while (rdataset != NULL) {
   2054 				next_rdataset = ISC_LIST_NEXT(rdataset, link);
   2055 
   2056 				if ((rdataset->attributes &
   2057 				     DNS_RDATASETATTR_RENDERED) != 0)
   2058 					goto next;
   2059 
   2060 				if (((options & DNS_MESSAGERENDER_ORDERED)
   2061 				     == 0)
   2062 				    && (sectionid == DNS_SECTION_ADDITIONAL)
   2063 				    && wrong_priority(rdataset, pass,
   2064 						      preferred_glue))
   2065 					goto next;
   2066 
   2067 				st = *(msg->buffer);
   2068 
   2069 				count = 0;
   2070 				if (partial)
   2071 					result = dns_rdataset_towirepartial(
   2072 							  rdataset,
   2073 							  name,
   2074 							  msg->cctx,
   2075 							  msg->buffer,
   2076 							  msg->order,
   2077 							  &msg->order_arg,
   2078 							  rd_options,
   2079 							  &count,
   2080 							  NULL);
   2081 				else
   2082 					result = dns_rdataset_towiresorted(
   2083 							  rdataset,
   2084 							  name,
   2085 							  msg->cctx,
   2086 							  msg->buffer,
   2087 							  msg->order,
   2088 							  &msg->order_arg,
   2089 							  rd_options,
   2090 							  &count);
   2091 
   2092 				total += count;
   2093 
   2094 				/*
   2095 				 * If out of space, record stats on what we
   2096 				 * rendered so far, and return that status.
   2097 				 *
   2098 				 * XXXMLG Need to change this when
   2099 				 * dns_rdataset_towire() can render partial
   2100 				 * sets starting at some arbitrary point in the
   2101 				 * set.  This will include setting a bit in the
   2102 				 * rdataset to indicate that a partial
   2103 				 * rendering was done, and some state saved
   2104 				 * somewhere (probably in the message struct)
   2105 				 * to indicate where to continue from.
   2106 				 */
   2107 				if (partial && result == ISC_R_NOSPACE) {
   2108 					msg->buffer->length += msg->reserved;
   2109 					msg->counts[sectionid] += total;
   2110 					return (result);
   2111 				}
   2112 				if (result != ISC_R_SUCCESS) {
   2113 					INSIST(st.used < 65536);
   2114 					dns_compress_rollback(msg->cctx,
   2115 							(uint16_t)st.used);
   2116 					*(msg->buffer) = st;  /* rollback */
   2117 					msg->buffer->length += msg->reserved;
   2118 					msg->counts[sectionid] += total;
   2119 					maybe_clear_ad(msg, sectionid);
   2120 					return (result);
   2121 				}
   2122 
   2123 				/*
   2124 				 * If we have rendered non-validated data,
   2125 				 * ensure that the AD bit is not set.
   2126 				 */
   2127 				if (rdataset->trust != dns_trust_secure &&
   2128 				    (sectionid == DNS_SECTION_ANSWER ||
   2129 				     sectionid == DNS_SECTION_AUTHORITY))
   2130 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
   2131 				if (OPTOUT(rdataset))
   2132 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
   2133 
   2134 				rdataset->attributes |=
   2135 					DNS_RDATASETATTR_RENDERED;
   2136 
   2137 			next:
   2138 				rdataset = next_rdataset;
   2139 			}
   2140 
   2141 			name = next_name;
   2142 		}
   2143 	} while (--pass != 0);
   2144 
   2145 	msg->buffer->length += msg->reserved;
   2146 	msg->counts[sectionid] += total;
   2147 
   2148 	return (ISC_R_SUCCESS);
   2149 }
   2150 
   2151 void
   2152 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
   2153 	uint16_t tmp;
   2154 	isc_region_t r;
   2155 
   2156 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2157 	REQUIRE(target != NULL);
   2158 
   2159 	isc_buffer_availableregion(target, &r);
   2160 	REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
   2161 
   2162 	isc_buffer_putuint16(target, msg->id);
   2163 
   2164 	tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
   2165 	       & DNS_MESSAGE_OPCODE_MASK);
   2166 	tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
   2167 	tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
   2168 
   2169 	INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
   2170 	       msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
   2171 	       msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
   2172 	       msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
   2173 
   2174 	isc_buffer_putuint16(target, tmp);
   2175 	isc_buffer_putuint16(target,
   2176 			    (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
   2177 	isc_buffer_putuint16(target,
   2178 			    (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
   2179 	isc_buffer_putuint16(target,
   2180 			    (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
   2181 	isc_buffer_putuint16(target,
   2182 			    (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
   2183 }
   2184 
   2185 isc_result_t
   2186 dns_message_renderend(dns_message_t *msg) {
   2187 	isc_buffer_t tmpbuf;
   2188 	isc_region_t r;
   2189 	int result;
   2190 	unsigned int count;
   2191 
   2192 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2193 	REQUIRE(msg->buffer != NULL);
   2194 
   2195 	if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
   2196 		/*
   2197 		 * We have an extended rcode but are not using EDNS.
   2198 		 */
   2199 		return (DNS_R_FORMERR);
   2200 	}
   2201 
   2202 	/*
   2203 	 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
   2204 	 * clear all rdatasets from the message except for the question
   2205 	 * before adding the OPT, TSIG or SIG(0).  If the question doesn't
   2206 	 * fit, don't include it.
   2207 	 */
   2208 	if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
   2209 	    (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
   2210 	{
   2211 		isc_buffer_t *buf;
   2212 
   2213 		msgresetnames(msg, DNS_SECTION_ANSWER);
   2214 		buf = msg->buffer;
   2215 		dns_message_renderreset(msg);
   2216 		msg->buffer = buf;
   2217 		isc_buffer_clear(msg->buffer);
   2218 		isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
   2219 		dns_compress_rollback(msg->cctx, 0);
   2220 		result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
   2221 						   0);
   2222 		if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
   2223 			return (result);
   2224 	}
   2225 
   2226 	/*
   2227 	 * If we've got an OPT record, render it.
   2228 	 */
   2229 	if (msg->opt != NULL) {
   2230 		dns_message_renderrelease(msg, msg->opt_reserved);
   2231 		msg->opt_reserved = 0;
   2232 		/*
   2233 		 * Set the extended rcode.
   2234 		 */
   2235 		msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
   2236 		msg->opt->ttl |= ((msg->rcode << 20) &
   2237 				  DNS_MESSAGE_EDNSRCODE_MASK);
   2238 		/*
   2239 		 * Render.
   2240 		 */
   2241 		count = 0;
   2242 		result = renderset(msg->opt, dns_rootname, msg->cctx,
   2243 				   msg->buffer, msg->reserved, 0, &count);
   2244 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
   2245 		if (result != ISC_R_SUCCESS)
   2246 			return (result);
   2247 	}
   2248 
   2249 	/*
   2250 	 * Deal with EDNS padding.
   2251 	 *
   2252 	 * padding_off is the length of the OPT with the 0-length PAD
   2253 	 * at the end.
   2254 	 */
   2255 	if (msg->padding_off > 0) {
   2256 		unsigned char *cp = isc_buffer_used(msg->buffer);
   2257 		unsigned int used, remaining;
   2258 		uint16_t len, padsize = 0;
   2259 
   2260 		/* Check PAD */
   2261 		if ((cp[-4] != 0) ||
   2262 		    (cp[-3] != DNS_OPT_PAD) ||
   2263 		    (cp[-2] != 0) ||
   2264 		    (cp[-1] != 0))
   2265 			return (ISC_R_UNEXPECTED);
   2266 
   2267 		/*
   2268 		 * Zero-fill the PAD to the computed size;
   2269 		 * patch PAD length and OPT rdlength
   2270 		 */
   2271 
   2272 		/* Aligned used length + reserved to padding block */
   2273 		used = isc_buffer_usedlength(msg->buffer);
   2274 		if (msg->padding != 0) {
   2275 			padsize = ((uint16_t)used + msg->reserved)
   2276 				% msg->padding;
   2277 		}
   2278 		if (padsize != 0) {
   2279 			padsize = msg->padding - padsize;
   2280 		}
   2281 		/* Stay below the available length */
   2282 		remaining = isc_buffer_availablelength(msg->buffer);
   2283 		if (padsize > remaining)
   2284 			padsize = remaining;
   2285 
   2286 		isc_buffer_add(msg->buffer, padsize);
   2287 		memset(cp, 0, padsize);
   2288 		cp[-2] = (unsigned char)((padsize & 0xff00U) >> 8);
   2289 		cp[-1] = (unsigned char)(padsize & 0x00ffU);
   2290 		cp -= msg->padding_off;
   2291 		len = ((uint16_t)(cp[-2])) << 8;
   2292 		len |= ((uint16_t)(cp[-1]));
   2293 		len += padsize;
   2294 		cp[-2] = (unsigned char)((len & 0xff00U) >> 8);
   2295 		cp[-1] = (unsigned char)(len & 0x00ffU);
   2296 	}
   2297 
   2298 	/*
   2299 	 * If we're adding a TSIG record, generate and render it.
   2300 	 */
   2301 	if (msg->tsigkey != NULL) {
   2302 		dns_message_renderrelease(msg, msg->sig_reserved);
   2303 		msg->sig_reserved = 0;
   2304 		result = dns_tsig_sign(msg);
   2305 		if (result != ISC_R_SUCCESS)
   2306 			return (result);
   2307 		count = 0;
   2308 		result = renderset(msg->tsig, msg->tsigname, msg->cctx,
   2309 				   msg->buffer, msg->reserved, 0, &count);
   2310 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
   2311 		if (result != ISC_R_SUCCESS)
   2312 			return (result);
   2313 	}
   2314 
   2315 	/*
   2316 	 * If we're adding a SIG(0) record, generate and render it.
   2317 	 */
   2318 	if (msg->sig0key != NULL) {
   2319 		dns_message_renderrelease(msg, msg->sig_reserved);
   2320 		msg->sig_reserved = 0;
   2321 		result = dns_dnssec_signmessage(msg, msg->sig0key);
   2322 		if (result != ISC_R_SUCCESS)
   2323 			return (result);
   2324 		count = 0;
   2325 		/*
   2326 		 * Note: dns_rootname is used here, not msg->sig0name, since
   2327 		 * the owner name of a SIG(0) is irrelevant, and will not
   2328 		 * be set in a message being rendered.
   2329 		 */
   2330 		result = renderset(msg->sig0, dns_rootname, msg->cctx,
   2331 				   msg->buffer, msg->reserved, 0, &count);
   2332 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
   2333 		if (result != ISC_R_SUCCESS)
   2334 			return (result);
   2335 	}
   2336 
   2337 	isc_buffer_usedregion(msg->buffer, &r);
   2338 	isc_buffer_init(&tmpbuf, r.base, r.length);
   2339 
   2340 	dns_message_renderheader(msg, &tmpbuf);
   2341 
   2342 	msg->buffer = NULL;  /* forget about this buffer only on success XXX */
   2343 
   2344 	return (ISC_R_SUCCESS);
   2345 }
   2346 
   2347 void
   2348 dns_message_renderreset(dns_message_t *msg) {
   2349 	unsigned int i;
   2350 	dns_name_t *name;
   2351 	dns_rdataset_t *rds;
   2352 
   2353 	/*
   2354 	 * Reset the message so that it may be rendered again.
   2355 	 */
   2356 
   2357 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2358 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
   2359 
   2360 	msg->buffer = NULL;
   2361 
   2362 	for (i = 0; i < DNS_SECTION_MAX; i++) {
   2363 		msg->cursors[i] = NULL;
   2364 		msg->counts[i] = 0;
   2365 		for (name = ISC_LIST_HEAD(msg->sections[i]);
   2366 		     name != NULL;
   2367 		     name = ISC_LIST_NEXT(name, link)) {
   2368 			for (rds = ISC_LIST_HEAD(name->list);
   2369 			     rds != NULL;
   2370 			     rds = ISC_LIST_NEXT(rds, link)) {
   2371 				rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
   2372 			}
   2373 		}
   2374 	}
   2375 	if (msg->tsigname != NULL)
   2376 		dns_message_puttempname(msg, &msg->tsigname);
   2377 	if (msg->tsig != NULL) {
   2378 		dns_rdataset_disassociate(msg->tsig);
   2379 		dns_message_puttemprdataset(msg, &msg->tsig);
   2380 	}
   2381 	if (msg->sig0 != NULL) {
   2382 		dns_rdataset_disassociate(msg->sig0);
   2383 		dns_message_puttemprdataset(msg, &msg->sig0);
   2384 	}
   2385 }
   2386 
   2387 isc_result_t
   2388 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
   2389 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2390 	REQUIRE(VALID_NAMED_SECTION(section));
   2391 
   2392 	msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
   2393 
   2394 	if (msg->cursors[section] == NULL)
   2395 		return (ISC_R_NOMORE);
   2396 
   2397 	return (ISC_R_SUCCESS);
   2398 }
   2399 
   2400 isc_result_t
   2401 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
   2402 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2403 	REQUIRE(VALID_NAMED_SECTION(section));
   2404 	REQUIRE(msg->cursors[section] != NULL);
   2405 
   2406 	msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
   2407 
   2408 	if (msg->cursors[section] == NULL)
   2409 		return (ISC_R_NOMORE);
   2410 
   2411 	return (ISC_R_SUCCESS);
   2412 }
   2413 
   2414 void
   2415 dns_message_currentname(dns_message_t *msg, dns_section_t section,
   2416 			dns_name_t **name)
   2417 {
   2418 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2419 	REQUIRE(VALID_NAMED_SECTION(section));
   2420 	REQUIRE(name != NULL && *name == NULL);
   2421 	REQUIRE(msg->cursors[section] != NULL);
   2422 
   2423 	*name = msg->cursors[section];
   2424 }
   2425 
   2426 isc_result_t
   2427 dns_message_findname(dns_message_t *msg, dns_section_t section,
   2428 		     const dns_name_t *target, dns_rdatatype_t type,
   2429 		     dns_rdatatype_t covers, dns_name_t **name,
   2430 		     dns_rdataset_t **rdataset)
   2431 {
   2432 	dns_name_t *foundname;
   2433 	isc_result_t result;
   2434 
   2435 	/*
   2436 	 * XXX These requirements are probably too intensive, especially
   2437 	 * where things can be NULL, but as they are they ensure that if
   2438 	 * something is NON-NULL, indicating that the caller expects it
   2439 	 * to be filled in, that we can in fact fill it in.
   2440 	 */
   2441 	REQUIRE(msg != NULL);
   2442 	REQUIRE(VALID_SECTION(section));
   2443 	REQUIRE(target != NULL);
   2444 	REQUIRE(name == NULL || *name == NULL);
   2445 
   2446 	if (type == dns_rdatatype_any) {
   2447 		REQUIRE(rdataset == NULL);
   2448 	} else {
   2449 		REQUIRE(rdataset == NULL || *rdataset == NULL);
   2450 	}
   2451 
   2452 	result = findname(&foundname, target,
   2453 			  &msg->sections[section]);
   2454 
   2455 	if (result == ISC_R_NOTFOUND)
   2456 		return (DNS_R_NXDOMAIN);
   2457 	else if (result != ISC_R_SUCCESS)
   2458 		return (result);
   2459 
   2460 	if (name != NULL)
   2461 		*name = foundname;
   2462 
   2463 	/*
   2464 	 * And now look for the type.
   2465 	 */
   2466 	if (ISC_UNLIKELY(type == dns_rdatatype_any))
   2467 		return (ISC_R_SUCCESS);
   2468 
   2469 	result = dns_message_findtype(foundname, type, covers, rdataset);
   2470 	if (result == ISC_R_NOTFOUND)
   2471 		return (DNS_R_NXRRSET);
   2472 
   2473 	return (result);
   2474 }
   2475 
   2476 void
   2477 dns_message_movename(dns_message_t *msg, dns_name_t *name,
   2478 		     dns_section_t fromsection,
   2479 		     dns_section_t tosection)
   2480 {
   2481 	REQUIRE(msg != NULL);
   2482 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
   2483 	REQUIRE(name != NULL);
   2484 	REQUIRE(VALID_NAMED_SECTION(fromsection));
   2485 	REQUIRE(VALID_NAMED_SECTION(tosection));
   2486 
   2487 	/*
   2488 	 * Unlink the name from the old section
   2489 	 */
   2490 	ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
   2491 	ISC_LIST_APPEND(msg->sections[tosection], name, link);
   2492 }
   2493 
   2494 void
   2495 dns_message_addname(dns_message_t *msg, dns_name_t *name,
   2496 		    dns_section_t section)
   2497 {
   2498 	REQUIRE(msg != NULL);
   2499 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
   2500 	REQUIRE(name != NULL);
   2501 	REQUIRE(VALID_NAMED_SECTION(section));
   2502 
   2503 	ISC_LIST_APPEND(msg->sections[section], name, link);
   2504 }
   2505 
   2506 void
   2507 dns_message_removename(dns_message_t *msg, dns_name_t *name,
   2508 		       dns_section_t section)
   2509 {
   2510 	REQUIRE(msg != NULL);
   2511 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
   2512 	REQUIRE(name != NULL);
   2513 	REQUIRE(VALID_NAMED_SECTION(section));
   2514 
   2515 	ISC_LIST_UNLINK(msg->sections[section], name, link);
   2516 }
   2517 
   2518 isc_result_t
   2519 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
   2520 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2521 	REQUIRE(item != NULL && *item == NULL);
   2522 
   2523 	*item = isc_mempool_get(msg->namepool);
   2524 	if (*item == NULL)
   2525 		return (ISC_R_NOMEMORY);
   2526 	dns_name_init(*item, NULL);
   2527 
   2528 	return (ISC_R_SUCCESS);
   2529 }
   2530 
   2531 isc_result_t
   2532 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
   2533 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2534 	REQUIRE(item != NULL && *item == NULL);
   2535 
   2536 	*item = newoffsets(msg);
   2537 	if (*item == NULL)
   2538 		return (ISC_R_NOMEMORY);
   2539 
   2540 	return (ISC_R_SUCCESS);
   2541 }
   2542 
   2543 isc_result_t
   2544 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
   2545 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2546 	REQUIRE(item != NULL && *item == NULL);
   2547 
   2548 	*item = newrdata(msg);
   2549 	if (*item == NULL)
   2550 		return (ISC_R_NOMEMORY);
   2551 
   2552 	return (ISC_R_SUCCESS);
   2553 }
   2554 
   2555 isc_result_t
   2556 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
   2557 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2558 	REQUIRE(item != NULL && *item == NULL);
   2559 
   2560 	*item = isc_mempool_get(msg->rdspool);
   2561 	if (*item == NULL)
   2562 		return (ISC_R_NOMEMORY);
   2563 
   2564 	dns_rdataset_init(*item);
   2565 
   2566 	return (ISC_R_SUCCESS);
   2567 }
   2568 
   2569 isc_result_t
   2570 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
   2571 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2572 	REQUIRE(item != NULL && *item == NULL);
   2573 
   2574 	*item = newrdatalist(msg);
   2575 	if (*item == NULL)
   2576 		return (ISC_R_NOMEMORY);
   2577 
   2578 	return (ISC_R_SUCCESS);
   2579 }
   2580 
   2581 void
   2582 dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) {
   2583 	dns_name_t *item;
   2584 
   2585 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2586 	REQUIRE(itemp != NULL && *itemp != NULL);
   2587 	item = *itemp;
   2588 	REQUIRE(!ISC_LINK_LINKED(item, link));
   2589 	REQUIRE(ISC_LIST_HEAD(item->list) == NULL);
   2590 
   2591 	*itemp = NULL;
   2592 	if (dns_name_dynamic(item))
   2593 		dns_name_free(item, msg->mctx);
   2594 	isc_mempool_put(msg->namepool, item);
   2595 }
   2596 
   2597 void
   2598 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
   2599 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2600 	REQUIRE(item != NULL && *item != NULL);
   2601 
   2602 	releaserdata(msg, *item);
   2603 	*item = NULL;
   2604 }
   2605 
   2606 void
   2607 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
   2608 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2609 	REQUIRE(item != NULL && *item != NULL);
   2610 
   2611 	REQUIRE(!dns_rdataset_isassociated(*item));
   2612 	isc_mempool_put(msg->rdspool, *item);
   2613 	*item = NULL;
   2614 }
   2615 
   2616 void
   2617 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
   2618 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2619 	REQUIRE(item != NULL && *item != NULL);
   2620 
   2621 	releaserdatalist(msg, *item);
   2622 	*item = NULL;
   2623 }
   2624 
   2625 isc_result_t
   2626 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
   2627 		       unsigned int *flagsp)
   2628 {
   2629 	isc_region_t r;
   2630 	isc_buffer_t buffer;
   2631 	dns_messageid_t id;
   2632 	unsigned int flags;
   2633 
   2634 	REQUIRE(source != NULL);
   2635 
   2636 	buffer = *source;
   2637 
   2638 	isc_buffer_remainingregion(&buffer, &r);
   2639 	if (r.length < DNS_MESSAGE_HEADERLEN)
   2640 		return (ISC_R_UNEXPECTEDEND);
   2641 
   2642 	id = isc_buffer_getuint16(&buffer);
   2643 	flags = isc_buffer_getuint16(&buffer);
   2644 	flags &= DNS_MESSAGE_FLAG_MASK;
   2645 
   2646 	if (flagsp != NULL)
   2647 		*flagsp = flags;
   2648 	if (idp != NULL)
   2649 		*idp = id;
   2650 
   2651 	return (ISC_R_SUCCESS);
   2652 }
   2653 
   2654 isc_result_t
   2655 dns_message_reply(dns_message_t *msg, bool want_question_section) {
   2656 	unsigned int clear_from;
   2657 	isc_result_t result;
   2658 
   2659 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2660 	REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
   2661 
   2662 	if (!msg->header_ok)
   2663 		return (DNS_R_FORMERR);
   2664 	if (msg->opcode != dns_opcode_query &&
   2665 	    msg->opcode != dns_opcode_notify)
   2666 		want_question_section = false;
   2667 	if (msg->opcode == dns_opcode_update)
   2668 		clear_from = DNS_SECTION_PREREQUISITE;
   2669 	else if (want_question_section) {
   2670 		if (!msg->question_ok)
   2671 			return (DNS_R_FORMERR);
   2672 		clear_from = DNS_SECTION_ANSWER;
   2673 	} else
   2674 		clear_from = DNS_SECTION_QUESTION;
   2675 	msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
   2676 	msgresetnames(msg, clear_from);
   2677 	msgresetopt(msg);
   2678 	msgresetsigs(msg, true);
   2679 	msginitprivate(msg);
   2680 	/*
   2681 	 * We now clear most flags and then set QR, ensuring that the
   2682 	 * reply's flags will be in a reasonable state.
   2683 	 */
   2684 	if (msg->opcode == dns_opcode_query)
   2685 		msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
   2686 	else
   2687 		msg->flags = 0;
   2688 	msg->flags |= DNS_MESSAGEFLAG_QR;
   2689 
   2690 	/*
   2691 	 * This saves the query TSIG status, if the query was signed, and
   2692 	 * reserves space in the reply for the TSIG.
   2693 	 */
   2694 	if (msg->tsigkey != NULL) {
   2695 		unsigned int otherlen = 0;
   2696 		msg->querytsigstatus = msg->tsigstatus;
   2697 		msg->tsigstatus = dns_rcode_noerror;
   2698 		if (msg->querytsigstatus == dns_tsigerror_badtime)
   2699 			otherlen = 6;
   2700 		msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
   2701 		result = dns_message_renderreserve(msg, msg->sig_reserved);
   2702 		if (result != ISC_R_SUCCESS) {
   2703 			msg->sig_reserved = 0;
   2704 			return (result);
   2705 		}
   2706 	}
   2707 	if (msg->saved.base != NULL) {
   2708 		msg->query.base = msg->saved.base;
   2709 		msg->query.length = msg->saved.length;
   2710 		msg->free_query = msg->free_saved;
   2711 		msg->saved.base = NULL;
   2712 		msg->saved.length = 0;
   2713 		msg->free_saved = 0;
   2714 	}
   2715 
   2716 	return (ISC_R_SUCCESS);
   2717 }
   2718 
   2719 dns_rdataset_t *
   2720 dns_message_getopt(dns_message_t *msg) {
   2721 
   2722 	/*
   2723 	 * Get the OPT record for 'msg'.
   2724 	 */
   2725 
   2726 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2727 
   2728 	return (msg->opt);
   2729 }
   2730 
   2731 isc_result_t
   2732 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
   2733 	isc_result_t result;
   2734 	dns_rdata_t rdata = DNS_RDATA_INIT;
   2735 
   2736 	/*
   2737 	 * Set the OPT record for 'msg'.
   2738 	 */
   2739 
   2740 	/*
   2741 	 * The space required for an OPT record is:
   2742 	 *
   2743 	 *	1 byte for the name
   2744 	 *	2 bytes for the type
   2745 	 *	2 bytes for the class
   2746 	 *	4 bytes for the ttl
   2747 	 *	2 bytes for the rdata length
   2748 	 * ---------------------------------
   2749 	 *     11 bytes
   2750 	 *
   2751 	 * plus the length of the rdata.
   2752 	 */
   2753 
   2754 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2755 	REQUIRE(opt->type == dns_rdatatype_opt);
   2756 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
   2757 	REQUIRE(msg->state == DNS_SECTION_ANY);
   2758 
   2759 	msgresetopt(msg);
   2760 
   2761 	result = dns_rdataset_first(opt);
   2762 	if (result != ISC_R_SUCCESS)
   2763 		goto cleanup;
   2764 	dns_rdataset_current(opt, &rdata);
   2765 	msg->opt_reserved = 11 + rdata.length;
   2766 	result = dns_message_renderreserve(msg, msg->opt_reserved);
   2767 	if (result != ISC_R_SUCCESS) {
   2768 		msg->opt_reserved = 0;
   2769 		goto cleanup;
   2770 	}
   2771 
   2772 	msg->opt = opt;
   2773 
   2774 	return (ISC_R_SUCCESS);
   2775 
   2776  cleanup:
   2777 	dns_rdataset_disassociate(opt);
   2778 	dns_message_puttemprdataset(msg, &opt);
   2779 	return (result);
   2780 }
   2781 
   2782 dns_rdataset_t *
   2783 dns_message_gettsig(dns_message_t *msg, const dns_name_t **owner) {
   2784 
   2785 	/*
   2786 	 * Get the TSIG record and owner for 'msg'.
   2787 	 */
   2788 
   2789 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2790 	REQUIRE(owner == NULL || *owner == NULL);
   2791 
   2792 	if (owner != NULL)
   2793 		*owner = msg->tsigname;
   2794 	return (msg->tsig);
   2795 }
   2796 
   2797 isc_result_t
   2798 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
   2799 	isc_result_t result;
   2800 
   2801 	/*
   2802 	 * Set the TSIG key for 'msg'
   2803 	 */
   2804 
   2805 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2806 
   2807 	if (key == NULL && msg->tsigkey != NULL) {
   2808 		if (msg->sig_reserved != 0) {
   2809 			dns_message_renderrelease(msg, msg->sig_reserved);
   2810 			msg->sig_reserved = 0;
   2811 		}
   2812 		dns_tsigkey_detach(&msg->tsigkey);
   2813 	}
   2814 	if (key != NULL) {
   2815 		REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
   2816 		dns_tsigkey_attach(key, &msg->tsigkey);
   2817 		if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
   2818 			msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
   2819 			result = dns_message_renderreserve(msg,
   2820 							   msg->sig_reserved);
   2821 			if (result != ISC_R_SUCCESS) {
   2822 				dns_tsigkey_detach(&msg->tsigkey);
   2823 				msg->sig_reserved = 0;
   2824 				return (result);
   2825 			}
   2826 		}
   2827 	}
   2828 	return (ISC_R_SUCCESS);
   2829 }
   2830 
   2831 dns_tsigkey_t *
   2832 dns_message_gettsigkey(dns_message_t *msg) {
   2833 
   2834 	/*
   2835 	 * Get the TSIG key for 'msg'
   2836 	 */
   2837 
   2838 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2839 
   2840 	return (msg->tsigkey);
   2841 }
   2842 
   2843 isc_result_t
   2844 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
   2845 	dns_rdata_t *rdata = NULL;
   2846 	dns_rdatalist_t *list = NULL;
   2847 	dns_rdataset_t *set = NULL;
   2848 	isc_buffer_t *buf = NULL;
   2849 	isc_region_t r;
   2850 	isc_result_t result;
   2851 
   2852 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2853 	REQUIRE(msg->querytsig == NULL);
   2854 
   2855 	if (querytsig == NULL)
   2856 		return (ISC_R_SUCCESS);
   2857 
   2858 	result = dns_message_gettemprdata(msg, &rdata);
   2859 	if (result != ISC_R_SUCCESS)
   2860 		goto cleanup;
   2861 
   2862 	result = dns_message_gettemprdatalist(msg, &list);
   2863 	if (result != ISC_R_SUCCESS)
   2864 		goto cleanup;
   2865 	result = dns_message_gettemprdataset(msg, &set);
   2866 	if (result != ISC_R_SUCCESS)
   2867 		goto cleanup;
   2868 
   2869 	isc_buffer_usedregion(querytsig, &r);
   2870 	result = isc_buffer_allocate(msg->mctx, &buf, r.length);
   2871 	if (result != ISC_R_SUCCESS)
   2872 		goto cleanup;
   2873 	isc_buffer_putmem(buf, r.base, r.length);
   2874 	isc_buffer_usedregion(buf, &r);
   2875 	dns_rdata_init(rdata);
   2876 	dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
   2877 	dns_message_takebuffer(msg, &buf);
   2878 	ISC_LIST_APPEND(list->rdata, rdata, link);
   2879 	result = dns_rdatalist_tordataset(list, set);
   2880 	if (result != ISC_R_SUCCESS)
   2881 		goto cleanup;
   2882 
   2883 	msg->querytsig = set;
   2884 
   2885 	return (result);
   2886 
   2887  cleanup:
   2888 	if (rdata != NULL)
   2889 		dns_message_puttemprdata(msg, &rdata);
   2890 	if (list != NULL)
   2891 		dns_message_puttemprdatalist(msg, &list);
   2892 	if (set != NULL)
   2893 		dns_message_puttemprdataset(msg, &set);
   2894 	return (ISC_R_NOMEMORY);
   2895 }
   2896 
   2897 isc_result_t
   2898 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
   2899 			 isc_buffer_t **querytsig) {
   2900 	isc_result_t result;
   2901 	dns_rdata_t rdata = DNS_RDATA_INIT;
   2902 	isc_region_t r;
   2903 
   2904 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2905 	REQUIRE(mctx != NULL);
   2906 	REQUIRE(querytsig != NULL && *querytsig == NULL);
   2907 
   2908 	if (msg->tsig == NULL)
   2909 		return (ISC_R_SUCCESS);
   2910 
   2911 	result = dns_rdataset_first(msg->tsig);
   2912 	if (result != ISC_R_SUCCESS)
   2913 		return (result);
   2914 	dns_rdataset_current(msg->tsig, &rdata);
   2915 	dns_rdata_toregion(&rdata, &r);
   2916 
   2917 	result = isc_buffer_allocate(mctx, querytsig, r.length);
   2918 	if (result != ISC_R_SUCCESS)
   2919 		return (result);
   2920 	isc_buffer_putmem(*querytsig, r.base, r.length);
   2921 	return (ISC_R_SUCCESS);
   2922 }
   2923 
   2924 dns_rdataset_t *
   2925 dns_message_getsig0(dns_message_t *msg, const dns_name_t **owner) {
   2926 
   2927 	/*
   2928 	 * Get the SIG(0) record for 'msg'.
   2929 	 */
   2930 
   2931 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2932 	REQUIRE(owner == NULL || *owner == NULL);
   2933 
   2934 	if (msg->sig0 != NULL && owner != NULL) {
   2935 		/* If dns_message_getsig0 is called on a rendered message
   2936 		 * after the SIG(0) has been applied, we need to return the
   2937 		 * root name, not NULL.
   2938 		 */
   2939 		if (msg->sig0name == NULL)
   2940 			*owner = dns_rootname;
   2941 		else
   2942 			*owner = msg->sig0name;
   2943 	}
   2944 	return (msg->sig0);
   2945 }
   2946 
   2947 isc_result_t
   2948 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
   2949 	isc_region_t r;
   2950 	unsigned int x;
   2951 	isc_result_t result;
   2952 
   2953 	/*
   2954 	 * Set the SIG(0) key for 'msg'
   2955 	 */
   2956 
   2957 	/*
   2958 	 * The space required for an SIG(0) record is:
   2959 	 *
   2960 	 *	1 byte for the name
   2961 	 *	2 bytes for the type
   2962 	 *	2 bytes for the class
   2963 	 *	4 bytes for the ttl
   2964 	 *	2 bytes for the type covered
   2965 	 *	1 byte for the algorithm
   2966 	 *	1 bytes for the labels
   2967 	 *	4 bytes for the original ttl
   2968 	 *	4 bytes for the signature expiration
   2969 	 *	4 bytes for the signature inception
   2970 	 *	2 bytes for the key tag
   2971 	 *	n bytes for the signer's name
   2972 	 *	x bytes for the signature
   2973 	 * ---------------------------------
   2974 	 *     27 + n + x bytes
   2975 	 */
   2976 	REQUIRE(DNS_MESSAGE_VALID(msg));
   2977 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
   2978 	REQUIRE(msg->state == DNS_SECTION_ANY);
   2979 
   2980 	if (key != NULL) {
   2981 		REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
   2982 		dns_name_toregion(dst_key_name(key), &r);
   2983 		result = dst_key_sigsize(key, &x);
   2984 		if (result != ISC_R_SUCCESS) {
   2985 			msg->sig_reserved = 0;
   2986 			return (result);
   2987 		}
   2988 		msg->sig_reserved = 27 + r.length + x;
   2989 		result = dns_message_renderreserve(msg, msg->sig_reserved);
   2990 		if (result != ISC_R_SUCCESS) {
   2991 			msg->sig_reserved = 0;
   2992 			return (result);
   2993 		}
   2994 		msg->sig0key = key;
   2995 	}
   2996 	return (ISC_R_SUCCESS);
   2997 }
   2998 
   2999 dst_key_t *
   3000 dns_message_getsig0key(dns_message_t *msg) {
   3001 
   3002 	/*
   3003 	 * Get the SIG(0) key for 'msg'
   3004 	 */
   3005 
   3006 	REQUIRE(DNS_MESSAGE_VALID(msg));
   3007 
   3008 	return (msg->sig0key);
   3009 }
   3010 
   3011 void
   3012 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
   3013 	REQUIRE(DNS_MESSAGE_VALID(msg));
   3014 	REQUIRE(buffer != NULL);
   3015 	REQUIRE(ISC_BUFFER_VALID(*buffer));
   3016 
   3017 	ISC_LIST_APPEND(msg->cleanup, *buffer, link);
   3018 	*buffer = NULL;
   3019 }
   3020 
   3021 isc_result_t
   3022 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
   3023 	isc_result_t result = ISC_R_SUCCESS;
   3024 	dns_rdata_t rdata = DNS_RDATA_INIT;
   3025 
   3026 	REQUIRE(DNS_MESSAGE_VALID(msg));
   3027 	REQUIRE(signer != NULL);
   3028 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
   3029 
   3030 	if (msg->tsig == NULL && msg->sig0 == NULL)
   3031 		return (ISC_R_NOTFOUND);
   3032 
   3033 	if (msg->verify_attempted == 0)
   3034 		return (DNS_R_NOTVERIFIEDYET);
   3035 
   3036 	if (!dns_name_hasbuffer(signer)) {
   3037 		isc_buffer_t *dynbuf = NULL;
   3038 		result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
   3039 		if (result != ISC_R_SUCCESS)
   3040 			return (result);
   3041 		dns_name_setbuffer(signer, dynbuf);
   3042 		dns_message_takebuffer(msg, &dynbuf);
   3043 	}
   3044 
   3045 	if (msg->sig0 != NULL) {
   3046 		dns_rdata_sig_t sig;
   3047 
   3048 		result = dns_rdataset_first(msg->sig0);
   3049 		INSIST(result == ISC_R_SUCCESS);
   3050 		dns_rdataset_current(msg->sig0, &rdata);
   3051 
   3052 		result = dns_rdata_tostruct(&rdata, &sig, NULL);
   3053 		if (result != ISC_R_SUCCESS)
   3054 			return (result);
   3055 
   3056 		if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
   3057 			result = ISC_R_SUCCESS;
   3058 		else
   3059 			result = DNS_R_SIGINVALID;
   3060 		dns_name_clone(&sig.signer, signer);
   3061 		dns_rdata_freestruct(&sig);
   3062 	} else {
   3063 		dns_name_t *identity;
   3064 		dns_rdata_any_tsig_t tsig;
   3065 
   3066 		result = dns_rdataset_first(msg->tsig);
   3067 		INSIST(result == ISC_R_SUCCESS);
   3068 		dns_rdataset_current(msg->tsig, &rdata);
   3069 
   3070 		result = dns_rdata_tostruct(&rdata, &tsig, NULL);
   3071 		INSIST(result == ISC_R_SUCCESS);
   3072 		if (msg->verified_sig &&
   3073 		    msg->tsigstatus == dns_rcode_noerror &&
   3074 		    tsig.error == dns_rcode_noerror)
   3075 		{
   3076 			result = ISC_R_SUCCESS;
   3077 		} else if ((!msg->verified_sig) ||
   3078 			   (msg->tsigstatus != dns_rcode_noerror))
   3079 		{
   3080 			result = DNS_R_TSIGVERIFYFAILURE;
   3081 		} else {
   3082 			INSIST(tsig.error != dns_rcode_noerror);
   3083 			result = DNS_R_TSIGERRORSET;
   3084 		}
   3085 		dns_rdata_freestruct(&tsig);
   3086 
   3087 		if (msg->tsigkey == NULL) {
   3088 			/*
   3089 			 * If msg->tsigstatus & tsig.error are both
   3090 			 * dns_rcode_noerror, the message must have been
   3091 			 * verified, which means msg->tsigkey will be
   3092 			 * non-NULL.
   3093 			 */
   3094 			INSIST(result != ISC_R_SUCCESS);
   3095 		} else {
   3096 			identity = dns_tsigkey_identity(msg->tsigkey);
   3097 			if (identity == NULL) {
   3098 				if (result == ISC_R_SUCCESS)
   3099 					result = DNS_R_NOIDENTITY;
   3100 				identity = &msg->tsigkey->name;
   3101 			}
   3102 			dns_name_clone(identity, signer);
   3103 		}
   3104 	}
   3105 
   3106 	return (result);
   3107 }
   3108 
   3109 void
   3110 dns_message_resetsig(dns_message_t *msg) {
   3111 	REQUIRE(DNS_MESSAGE_VALID(msg));
   3112 	msg->verified_sig = 0;
   3113 	msg->verify_attempted = 0;
   3114 	msg->tsigstatus = dns_rcode_noerror;
   3115 	msg->sig0status = dns_rcode_noerror;
   3116 	msg->timeadjust = 0;
   3117 	if (msg->tsigkey != NULL) {
   3118 		dns_tsigkey_detach(&msg->tsigkey);
   3119 		msg->tsigkey = NULL;
   3120 	}
   3121 }
   3122 
   3123 isc_result_t
   3124 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
   3125 	dns_message_resetsig(msg);
   3126 	return (dns_message_checksig(msg, view));
   3127 }
   3128 
   3129 #ifdef SKAN_MSG_DEBUG
   3130 void
   3131 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
   3132 	dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
   3133 	dns_rdata_any_tsig_t querytsig;
   3134 	isc_result_t result;
   3135 
   3136 	if (msg->tsig != NULL) {
   3137 		result = dns_rdataset_first(msg->tsig);
   3138 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   3139 		dns_rdataset_current(msg->tsig, &querytsigrdata);
   3140 		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
   3141 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   3142 		hexdump(txt1, "TSIG", querytsig.signature,
   3143 			querytsig.siglen);
   3144 	}
   3145 
   3146 	if (msg->querytsig != NULL) {
   3147 		result = dns_rdataset_first(msg->querytsig);
   3148 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   3149 		dns_rdataset_current(msg->querytsig, &querytsigrdata);
   3150 		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
   3151 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   3152 		hexdump(txt1, "QUERYTSIG", querytsig.signature,
   3153 			querytsig.siglen);
   3154 	}
   3155 }
   3156 #endif
   3157 
   3158 isc_result_t
   3159 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
   3160 	isc_buffer_t b, msgb;
   3161 
   3162 	REQUIRE(DNS_MESSAGE_VALID(msg));
   3163 
   3164 	if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
   3165 		return (ISC_R_SUCCESS);
   3166 
   3167 	INSIST(msg->saved.base != NULL);
   3168 	isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
   3169 	isc_buffer_add(&msgb, msg->saved.length);
   3170 	if (msg->tsigkey != NULL || msg->tsig != NULL) {
   3171 #ifdef SKAN_MSG_DEBUG
   3172 		dns_message_dumpsig(msg, "dns_message_checksig#1");
   3173 #endif
   3174 		if (view != NULL)
   3175 			return (dns_view_checksig(view, &msgb, msg));
   3176 		else
   3177 			return (dns_tsig_verify(&msgb, msg, NULL, NULL));
   3178 	} else {
   3179 		dns_rdata_t rdata = DNS_RDATA_INIT;
   3180 		dns_rdata_sig_t sig;
   3181 		dns_rdataset_t keyset;
   3182 		isc_result_t result;
   3183 
   3184 		result = dns_rdataset_first(msg->sig0);
   3185 		INSIST(result == ISC_R_SUCCESS);
   3186 		dns_rdataset_current(msg->sig0, &rdata);
   3187 
   3188 		/*
   3189 		 * This can occur when the message is a dynamic update, since
   3190 		 * the rdata length checking is relaxed.  This should not
   3191 		 * happen in a well-formed message, since the SIG(0) is only
   3192 		 * looked for in the additional section, and the dynamic update
   3193 		 * meta-records are in the prerequisite and update sections.
   3194 		 */
   3195 		if (rdata.length == 0)
   3196 			return (ISC_R_UNEXPECTEDEND);
   3197 
   3198 		result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
   3199 		if (result != ISC_R_SUCCESS)
   3200 			return (result);
   3201 
   3202 		dns_rdataset_init(&keyset);
   3203 		if (view == NULL)
   3204 			return (DNS_R_KEYUNAUTHORIZED);
   3205 		result = dns_view_simplefind(view, &sig.signer,
   3206 					     dns_rdatatype_key /* SIG(0) */,
   3207 					     0, 0, false, &keyset, NULL);
   3208 
   3209 		if (result != ISC_R_SUCCESS) {
   3210 			/* XXXBEW Should possibly create a fetch here */
   3211 			result = DNS_R_KEYUNAUTHORIZED;
   3212 			goto freesig;
   3213 		} else if (keyset.trust < dns_trust_secure) {
   3214 			/* XXXBEW Should call a validator here */
   3215 			result = DNS_R_KEYUNAUTHORIZED;
   3216 			goto freesig;
   3217 		}
   3218 		result = dns_rdataset_first(&keyset);
   3219 		INSIST(result == ISC_R_SUCCESS);
   3220 		for (;
   3221 		     result == ISC_R_SUCCESS;
   3222 		     result = dns_rdataset_next(&keyset))
   3223 		{
   3224 			dst_key_t *key = NULL;
   3225 
   3226 			dns_rdata_reset(&rdata);
   3227 			dns_rdataset_current(&keyset, &rdata);
   3228 			isc_buffer_init(&b, rdata.data, rdata.length);
   3229 			isc_buffer_add(&b, rdata.length);
   3230 
   3231 			result = dst_key_fromdns(&sig.signer, rdata.rdclass,
   3232 						 &b, view->mctx, &key);
   3233 			if (result != ISC_R_SUCCESS)
   3234 				continue;
   3235 			if (dst_key_alg(key) != sig.algorithm ||
   3236 			    dst_key_id(key) != sig.keyid ||
   3237 			    !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
   3238 			      dst_key_proto(key) == DNS_KEYPROTO_ANY))
   3239 			{
   3240 				dst_key_free(&key);
   3241 				continue;
   3242 			}
   3243 			result = dns_dnssec_verifymessage(&msgb, msg, key);
   3244 			dst_key_free(&key);
   3245 			if (result == ISC_R_SUCCESS)
   3246 				break;
   3247 		}
   3248 		if (result == ISC_R_NOMORE)
   3249 			result = DNS_R_KEYUNAUTHORIZED;
   3250 
   3251  freesig:
   3252 		if (dns_rdataset_isassociated(&keyset))
   3253 			dns_rdataset_disassociate(&keyset);
   3254 		dns_rdata_freestruct(&sig);
   3255 		return (result);
   3256 	}
   3257 }
   3258 
   3259 #define INDENT(sp) \
   3260 	do { \
   3261 		unsigned int __i; \
   3262 		dns_masterstyle_flags_t  __flags = dns_master_styleflags(sp); \
   3263 		if ((__flags & DNS_STYLEFLAG_INDENT) == 0ULL && \
   3264 		    (__flags & DNS_STYLEFLAG_YAML) == 0ULL) \
   3265 			break; \
   3266 		for (__i = 0; __i < dns_master_indent; __i++) { \
   3267 			ADD_STRING(target, dns_master_indentstr); \
   3268 		} \
   3269 	} while (0)
   3270 
   3271 isc_result_t
   3272 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
   3273 			  const dns_master_style_t *style,
   3274 			  dns_messagetextflag_t flags,
   3275 			  isc_buffer_t *target) {
   3276 	dns_name_t *name, empty_name;
   3277 	dns_rdataset_t *rdataset;
   3278 	isc_result_t result = ISC_R_SUCCESS;
   3279 	bool seensoa = false;
   3280 	unsigned int saveindent;
   3281 	dns_masterstyle_flags_t sflags;
   3282 
   3283 	REQUIRE(DNS_MESSAGE_VALID(msg));
   3284 	REQUIRE(target != NULL);
   3285 	REQUIRE(VALID_SECTION(section));
   3286 
   3287 	saveindent = dns_master_indent;
   3288 	sflags = dns_master_styleflags(style);
   3289 	if (ISC_LIST_EMPTY(msg->sections[section]))
   3290 		goto cleanup;
   3291 
   3292 
   3293 	INDENT(style);
   3294 	if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
   3295 		if (msg->opcode != dns_opcode_update) {
   3296 			ADD_STRING(target, sectiontext[section]);
   3297 		} else {
   3298 			ADD_STRING(target, updsectiontext[section]);
   3299 		}
   3300 		ADD_STRING(target, "_SECTION:\n");
   3301 	} else if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
   3302 		ADD_STRING(target, ";; ");
   3303 		if (msg->opcode != dns_opcode_update) {
   3304 			ADD_STRING(target, sectiontext[section]);
   3305 		} else {
   3306 			ADD_STRING(target, updsectiontext[section]);
   3307 		}
   3308 		ADD_STRING(target, " SECTION:\n");
   3309 	}
   3310 
   3311 	dns_name_init(&empty_name, NULL);
   3312 	result = dns_message_firstname(msg, section);
   3313 	if (result != ISC_R_SUCCESS) {
   3314 		goto cleanup;
   3315 	}
   3316 	if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
   3317 		dns_master_indent++;
   3318 	}
   3319 	do {
   3320 		name = NULL;
   3321 		dns_message_currentname(msg, section, &name);
   3322 		for (rdataset = ISC_LIST_HEAD(name->list);
   3323 		     rdataset != NULL;
   3324 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
   3325 			if (section == DNS_SECTION_ANSWER &&
   3326 			    rdataset->type == dns_rdatatype_soa) {
   3327 				if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
   3328 					continue;
   3329 				if (seensoa &&
   3330 				    (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
   3331 					continue;
   3332 				seensoa = true;
   3333 			}
   3334 			if (section == DNS_SECTION_QUESTION) {
   3335 				INDENT(style);
   3336 				if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
   3337 					ADD_STRING(target, "- ");
   3338 				} else {
   3339 					ADD_STRING(target, ";");
   3340 				}
   3341 				result = dns_master_questiontotext(name,
   3342 								   rdataset,
   3343 								   style,
   3344 								   target);
   3345 			} else {
   3346 				result = dns_master_rdatasettotext(name,
   3347 								   rdataset,
   3348 								   style,
   3349 								   target);
   3350 			}
   3351 			if (result != ISC_R_SUCCESS)
   3352 				goto cleanup;
   3353 		}
   3354 		result = dns_message_nextname(msg, section);
   3355 	} while (result == ISC_R_SUCCESS);
   3356 	if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
   3357 		dns_master_indent--;
   3358 	}
   3359 	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
   3360 	    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0 &&
   3361 	    (sflags & DNS_STYLEFLAG_YAML) == 0)
   3362 	{
   3363 		INDENT(style);
   3364 		ADD_STRING(target, "\n");
   3365 	}
   3366 	if (result == ISC_R_NOMORE)
   3367 		result = ISC_R_SUCCESS;
   3368 
   3369  cleanup:
   3370 	dns_master_indent = saveindent;
   3371 	return (result);
   3372 }
   3373 
   3374 static isc_result_t
   3375 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
   3376 	int i;
   3377 	char addr[16], addr_text[64];
   3378 	uint16_t family;
   3379 	uint8_t addrlen, addrbytes, scopelen;
   3380 	isc_result_t result;
   3381 
   3382 	/*
   3383 	 * Note: This routine needs to handle malformed ECS options.
   3384 	 */
   3385 
   3386 	if (isc_buffer_remaininglength(ecsbuf) < 4)
   3387 		return (DNS_R_OPTERR);
   3388 	family = isc_buffer_getuint16(ecsbuf);
   3389 	addrlen = isc_buffer_getuint8(ecsbuf);
   3390 	scopelen = isc_buffer_getuint8(ecsbuf);
   3391 
   3392 	addrbytes = (addrlen + 7) / 8;
   3393 	if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
   3394 		return (DNS_R_OPTERR);
   3395 
   3396 	if (addrbytes > sizeof(addr))
   3397 		return (DNS_R_OPTERR);
   3398 
   3399 	memset(addr, 0, sizeof(addr));
   3400 	for (i = 0; i < addrbytes; i ++)
   3401 		addr[i] = isc_buffer_getuint8(ecsbuf);
   3402 
   3403 	switch (family) {
   3404 	case 0:
   3405 		if (addrlen != 0U || scopelen != 0U)
   3406 			return (DNS_R_OPTERR);
   3407 		strlcpy(addr_text, "0", sizeof(addr_text));
   3408 		break;
   3409 	case 1:
   3410 		if (addrlen > 32 || scopelen > 32)
   3411 			return (DNS_R_OPTERR);
   3412 		inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
   3413 		break;
   3414 	case 2:
   3415 		if (addrlen > 128 || scopelen > 128)
   3416 			return (DNS_R_OPTERR);
   3417 		inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
   3418 		break;
   3419 	default:
   3420 		return (DNS_R_OPTERR);
   3421 	}
   3422 
   3423 	ADD_STRING(target, ": ");
   3424 	ADD_STRING(target, addr_text);
   3425 	snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
   3426 	ADD_STRING(target, addr_text);
   3427 
   3428 	result = ISC_R_SUCCESS;
   3429 
   3430  cleanup:
   3431 	return (result);
   3432 }
   3433 
   3434 
   3435 static isc_result_t
   3436 dns_message_pseudosectiontoyaml(dns_message_t *msg,
   3437 				dns_pseudosection_t section,
   3438 				const dns_master_style_t *style,
   3439 				dns_messagetextflag_t flags,
   3440 				isc_buffer_t *target)
   3441 {
   3442 	dns_rdataset_t *ps = NULL;
   3443 	const dns_name_t *name = NULL;
   3444 	isc_result_t result = ISC_R_SUCCESS;
   3445 	char buf[sizeof("1234567890")];
   3446 	uint32_t mbz;
   3447 	dns_rdata_t rdata;
   3448 	isc_buffer_t optbuf;
   3449 	uint16_t optcode, optlen;
   3450 	unsigned char *optdata;
   3451 	unsigned int saveindent = dns_master_indent;
   3452 
   3453 	REQUIRE(DNS_MESSAGE_VALID(msg));
   3454 	REQUIRE(target != NULL);
   3455 	REQUIRE(VALID_PSEUDOSECTION(section));
   3456 
   3457 	switch (section) {
   3458 	case DNS_PSEUDOSECTION_OPT:
   3459 		ps = dns_message_getopt(msg);
   3460 		if (ps == NULL) {
   3461 			goto cleanup;
   3462 		}
   3463 
   3464 		INDENT(style);
   3465 		ADD_STRING(target, "OPT_PSEUDOSECTION:\n");
   3466 		dns_master_indent++;
   3467 
   3468 		INDENT(style);
   3469 		ADD_STRING(target, "EDNS:\n");
   3470 		dns_master_indent++;
   3471 
   3472 		INDENT(style);
   3473 		ADD_STRING(target, "version: ");
   3474 		snprintf(buf, sizeof(buf), "%u",
   3475 			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
   3476 		ADD_STRING(target, buf);
   3477 		ADD_STRING(target, "\n");
   3478 		INDENT(style);
   3479 		ADD_STRING(target, "flags:");
   3480 		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
   3481 			ADD_STRING(target, " do");
   3482 		ADD_STRING(target, "\n");
   3483 		mbz = ps->ttl & 0xffff;
   3484 		mbz &= ~DNS_MESSAGEEXTFLAG_DO;		/* Known Flags. */
   3485 		if (mbz != 0) {
   3486 			INDENT(style);
   3487 			ADD_STRING(target, "MBZ: ");
   3488 			snprintf(buf, sizeof(buf), "0x%.4x", mbz);
   3489 			ADD_STRING(target, buf);
   3490 			ADD_STRING(target, "\n");
   3491 		}
   3492 		INDENT(style);
   3493 		ADD_STRING(target, "udp: ");
   3494 		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
   3495 		ADD_STRING(target, buf);
   3496 		result = dns_rdataset_first(ps);
   3497 		if (result != ISC_R_SUCCESS) {
   3498 			result = ISC_R_SUCCESS;
   3499 			goto cleanup;
   3500 		}
   3501 
   3502 		/*
   3503 		 * Print EDNS info, if any.
   3504 		 *
   3505 		 * WARNING: The option contents may be malformed as
   3506 		 * dig +ednsopt=value:<content> does not validity
   3507 		 * checking.
   3508 		 */
   3509 		dns_rdata_init(&rdata);
   3510 		dns_rdataset_current(ps, &rdata);
   3511 
   3512 		isc_buffer_init(&optbuf, rdata.data, rdata.length);
   3513 		isc_buffer_add(&optbuf, rdata.length);
   3514 		while (isc_buffer_remaininglength(&optbuf) != 0) {
   3515 			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
   3516 			optcode = isc_buffer_getuint16(&optbuf);
   3517 			optlen = isc_buffer_getuint16(&optbuf);
   3518 			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
   3519 
   3520 			if (optcode == DNS_OPT_NSID) {
   3521 				INDENT(style);
   3522 				ADD_STRING(target, "NSID");
   3523 			} else if (optcode == DNS_OPT_COOKIE) {
   3524 				INDENT(style);
   3525 				ADD_STRING(target, "COOKIE");
   3526 			} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
   3527 				isc_buffer_t ecsbuf;
   3528 				INDENT(style);
   3529 				ADD_STRING(target, "CLIENT-SUBNET");
   3530 				isc_buffer_init(&ecsbuf,
   3531 						isc_buffer_current(&optbuf),
   3532 						optlen);
   3533 				isc_buffer_add(&ecsbuf, optlen);
   3534 				result = render_ecs(&ecsbuf, target);
   3535 				if (result == ISC_R_NOSPACE)
   3536 					goto cleanup;
   3537 				if (result == ISC_R_SUCCESS) {
   3538 					isc_buffer_forward(&optbuf, optlen);
   3539 					ADD_STRING(target, "\n");
   3540 					continue;
   3541 				}
   3542 				ADD_STRING(target, "\n");
   3543 			} else if (optcode == DNS_OPT_EXPIRE) {
   3544 				if (optlen == 4) {
   3545 					uint32_t secs;
   3546 					secs = isc_buffer_getuint32(&optbuf);
   3547 					INDENT(style);
   3548 					ADD_STRING(target, "EXPIRE: ");
   3549 					snprintf(buf, sizeof(buf), "%u", secs);
   3550 					ADD_STRING(target, buf);
   3551 					ADD_STRING(target, " (");
   3552 					result = dns_ttl_totext(secs,
   3553 								true,
   3554 								true,
   3555 								target);
   3556 					if (result != ISC_R_SUCCESS)
   3557 						goto cleanup;
   3558 					ADD_STRING(target, ")\n");
   3559 					continue;
   3560 				}
   3561 				INDENT(style);
   3562 				ADD_STRING(target, "EXPIRE");
   3563 			} else if (optcode == DNS_OPT_PAD) {
   3564 				INDENT(style);
   3565 				ADD_STRING(target, "PAD");
   3566 			} else if (optcode == DNS_OPT_KEY_TAG) {
   3567 				INDENT(style);
   3568 				ADD_STRING(target, "KEY-TAG");
   3569 				if (optlen > 0U && (optlen % 2U) == 0U) {
   3570 					const char *sep = ": ";
   3571 					uint16_t id;
   3572 					while (optlen > 0U) {
   3573 					    id = isc_buffer_getuint16(&optbuf);
   3574 					    snprintf(buf, sizeof(buf), "%s%u",
   3575 						     sep, id);
   3576 					    ADD_STRING(target, buf);
   3577 					    sep = ", ";
   3578 					    optlen -= 2;
   3579 					}
   3580 					ADD_STRING(target, "\n");
   3581 					continue;
   3582 				}
   3583 			} else {
   3584 				INDENT(style);
   3585 				ADD_STRING(target, "OPT: ");
   3586 				snprintf(buf, sizeof(buf), "%u", optcode);
   3587 				ADD_STRING(target, buf);
   3588 				ADD_STRING(target, "\n");
   3589 			}
   3590 
   3591 			if (optlen != 0) {
   3592 				int i;
   3593 				ADD_STRING(target, ": ");
   3594 
   3595 				optdata = isc_buffer_current(&optbuf);
   3596 				for (i = 0; i < optlen; i++) {
   3597 					const char *sep;
   3598 					switch (optcode) {
   3599 					case DNS_OPT_COOKIE:
   3600 						sep = "";
   3601 						break;
   3602 					default:
   3603 						sep = " ";
   3604 						break;
   3605 					}
   3606 					snprintf(buf, sizeof(buf), "%02x%s",
   3607 						 optdata[i], sep);
   3608 					ADD_STRING(target, buf);
   3609 				}
   3610 
   3611 				isc_buffer_forward(&optbuf, optlen);
   3612 
   3613 				if (optcode == DNS_OPT_COOKIE) {
   3614 					/*
   3615 					 * Valid server cookie?
   3616 					 */
   3617 					if (msg->cc_ok && optlen >= 16)
   3618 						ADD_STRING(target, " (good)");
   3619 					/*
   3620 					 * Server cookie is not valid but
   3621 					 * we had our cookie echoed back.
   3622 					 */
   3623 					if (msg->cc_ok && optlen < 16)
   3624 						ADD_STRING(target, " (echoed)");
   3625 					/*
   3626 					 * We didn't get our cookie echoed
   3627 					 * back.
   3628 					 */
   3629 					if (msg->cc_bad)
   3630 						ADD_STRING(target, " (bad)");
   3631 					ADD_STRING(target, "\n");
   3632 					continue;
   3633 				}
   3634 
   3635 				if (optcode == DNS_OPT_CLIENT_SUBNET) {
   3636 					ADD_STRING(target, "\n");
   3637 					continue;
   3638 				}
   3639 
   3640 				/*
   3641 				 * For non-COOKIE options, add a printable
   3642 				 * version
   3643 				 */
   3644 				ADD_STRING(target, "(\"");
   3645 				if (isc_buffer_availablelength(target) < optlen)
   3646 				{
   3647 					result = ISC_R_NOSPACE;
   3648 					goto cleanup;
   3649 				}
   3650 				for (i = 0; i < optlen; i++) {
   3651 					if (isprint(optdata[i]))
   3652 						isc_buffer_putmem(target,
   3653 								  &optdata[i],
   3654 								  1);
   3655 					else
   3656 						isc_buffer_putstr(target, ".");
   3657 				}
   3658 				ADD_STRING(target, "\")");
   3659 			}
   3660 			ADD_STRING(target, "\n");
   3661 		}
   3662 		result = ISC_R_SUCCESS;
   3663 		goto cleanup;
   3664 	case DNS_PSEUDOSECTION_TSIG:
   3665 		ps = dns_message_gettsig(msg, &name);
   3666 		if (ps == NULL) {
   3667 			result = ISC_R_SUCCESS;
   3668 			goto cleanup;
   3669 		}
   3670 		INDENT(style);
   3671 		ADD_STRING(target, "TSIG_PSEUDOSECTION:\n");
   3672 		result = dns_master_rdatasettotext(name, ps, style, target);
   3673 		ADD_STRING(target, "\n");
   3674 		goto cleanup;
   3675 	case DNS_PSEUDOSECTION_SIG0:
   3676 		ps = dns_message_getsig0(msg, &name);
   3677 		if (ps == NULL) {
   3678 			result = ISC_R_SUCCESS;
   3679 			goto cleanup;
   3680 		}
   3681 		INDENT(style);
   3682 		ADD_STRING(target, "SIG0_PSEUDOSECTION:\n");
   3683 		result = dns_master_rdatasettotext(name, ps, style, target);
   3684 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
   3685 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
   3686 			ADD_STRING(target, "\n");
   3687 		goto cleanup;
   3688 	}
   3689 
   3690 	result = ISC_R_UNEXPECTED;
   3691 
   3692  cleanup:
   3693 	dns_master_indent = saveindent;
   3694 	return (result);
   3695 }
   3696 
   3697 isc_result_t
   3698 dns_message_pseudosectiontotext(dns_message_t *msg,
   3699 				dns_pseudosection_t section,
   3700 				const dns_master_style_t *style,
   3701 				dns_messagetextflag_t flags,
   3702 				isc_buffer_t *target)
   3703 {
   3704 	dns_rdataset_t *ps = NULL;
   3705 	const dns_name_t *name = NULL;
   3706 	isc_result_t result;
   3707 	char buf[sizeof(" (65000 bytes)")];
   3708 	uint32_t mbz;
   3709 	dns_rdata_t rdata;
   3710 	isc_buffer_t optbuf;
   3711 	uint16_t optcode, optlen;
   3712 	unsigned char *optdata;
   3713 
   3714 	REQUIRE(DNS_MESSAGE_VALID(msg));
   3715 	REQUIRE(target != NULL);
   3716 	REQUIRE(VALID_PSEUDOSECTION(section));
   3717 
   3718 	if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0)
   3719 		return (dns_message_pseudosectiontoyaml(msg, section, style,
   3720 							flags, target));
   3721 	switch (section) {
   3722 	case DNS_PSEUDOSECTION_OPT:
   3723 		ps = dns_message_getopt(msg);
   3724 		if (ps == NULL)
   3725 			return (ISC_R_SUCCESS);
   3726 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
   3727 			INDENT(style);
   3728 			ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
   3729 		}
   3730 
   3731 		INDENT(style);
   3732 		ADD_STRING(target, "; EDNS: version: ");
   3733 		snprintf(buf, sizeof(buf), "%u",
   3734 			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
   3735 		ADD_STRING(target, buf);
   3736 		ADD_STRING(target, ", flags:");
   3737 		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
   3738 			ADD_STRING(target, " do");
   3739 		mbz = ps->ttl & 0xffff;
   3740 		mbz &= ~DNS_MESSAGEEXTFLAG_DO;		/* Known Flags. */
   3741 		if (mbz != 0) {
   3742 			ADD_STRING(target, "; MBZ: ");
   3743 			snprintf(buf, sizeof(buf), "0x%.4x", mbz);
   3744 			ADD_STRING(target, buf);
   3745 			ADD_STRING(target, ", udp: ");
   3746 		} else
   3747 			ADD_STRING(target, "; udp: ");
   3748 		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
   3749 		ADD_STRING(target, buf);
   3750 
   3751 		result = dns_rdataset_first(ps);
   3752 		if (result != ISC_R_SUCCESS)
   3753 			return (ISC_R_SUCCESS);
   3754 
   3755 		/*
   3756 		 * Print EDNS info, if any.
   3757 		 *
   3758 		 * WARNING: The option contents may be malformed as
   3759 		 * dig +ednsopt=value:<content> does no validity
   3760 		 * checking.
   3761 		 */
   3762 		dns_rdata_init(&rdata);
   3763 		dns_rdataset_current(ps, &rdata);
   3764 
   3765 		isc_buffer_init(&optbuf, rdata.data, rdata.length);
   3766 		isc_buffer_add(&optbuf, rdata.length);
   3767 		while (isc_buffer_remaininglength(&optbuf) != 0) {
   3768 			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
   3769 			optcode = isc_buffer_getuint16(&optbuf);
   3770 			optlen = isc_buffer_getuint16(&optbuf);
   3771 
   3772 			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
   3773 
   3774 			INDENT(style);
   3775 
   3776 			if (optcode == DNS_OPT_NSID) {
   3777 				ADD_STRING(target, "; NSID");
   3778 			} else if (optcode == DNS_OPT_COOKIE) {
   3779 				ADD_STRING(target, "; COOKIE");
   3780 			} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
   3781 				isc_buffer_t ecsbuf;
   3782 
   3783 				ADD_STRING(target, "; CLIENT-SUBNET");
   3784 				isc_buffer_init(&ecsbuf,
   3785 						isc_buffer_current(&optbuf),
   3786 						optlen);
   3787 				isc_buffer_add(&ecsbuf, optlen);
   3788 				result = render_ecs(&ecsbuf, target);
   3789 				if (result == ISC_R_NOSPACE)
   3790 					return (result);
   3791 				if (result == ISC_R_SUCCESS) {
   3792 					isc_buffer_forward(&optbuf, optlen);
   3793 					ADD_STRING(target, "\n");
   3794 					continue;
   3795 				}
   3796 			} else if (optcode == DNS_OPT_EXPIRE) {
   3797 				if (optlen == 4) {
   3798 					uint32_t secs;
   3799 					secs = isc_buffer_getuint32(&optbuf);
   3800 					ADD_STRING(target, "; EXPIRE: ");
   3801 					snprintf(buf, sizeof(buf), "%u", secs);
   3802 					ADD_STRING(target, buf);
   3803 					ADD_STRING(target, " (");
   3804 					result = dns_ttl_totext(secs,
   3805 								true,
   3806 								true,
   3807 								target);
   3808 					if (result != ISC_R_SUCCESS)
   3809 						return (result);
   3810 					ADD_STRING(target, ")\n");
   3811 					continue;
   3812 				}
   3813 				ADD_STRING(target, "; EXPIRE");
   3814 			} else if (optcode == DNS_OPT_TCP_KEEPALIVE) {
   3815 				if (optlen == 2) {
   3816 					unsigned int dsecs;
   3817 					dsecs = isc_buffer_getuint16(&optbuf);
   3818 					ADD_STRING(target, "; TCP KEEPALIVE:");
   3819 					snprintf(buf, sizeof(buf), " %u.%u",
   3820 						 dsecs / 10U, dsecs % 10U);
   3821 					ADD_STRING(target, buf);
   3822 					ADD_STRING(target, " secs\n");
   3823 					continue;
   3824 				}
   3825 				ADD_STRING(target, "; TCP KEEPALIVE");
   3826 			} else if (optcode == DNS_OPT_PAD) {
   3827 				ADD_STRING(target, "; PAD");
   3828 				if (optlen > 0U) {
   3829 					snprintf(buf, sizeof(buf),
   3830 						 " (%u bytes)", optlen);
   3831 					ADD_STRING(target, buf);
   3832 					isc_buffer_forward(&optbuf, optlen);
   3833 				}
   3834 				ADD_STRING(target, "\n");
   3835 				continue;
   3836 			} else if (optcode == DNS_OPT_KEY_TAG) {
   3837 				ADD_STRING(target, "; KEY-TAG");
   3838 				if (optlen > 0U && (optlen % 2U) == 0U) {
   3839 					const char *sep = ": ";
   3840 					uint16_t id;
   3841 					while (optlen > 0U) {
   3842 					    id = isc_buffer_getuint16(&optbuf);
   3843 					    snprintf(buf, sizeof(buf), "%s%u",
   3844 						     sep, id);
   3845 					    ADD_STRING(target, buf);
   3846 					    sep = ", ";
   3847 					    optlen -= 2;
   3848 					}
   3849 					ADD_STRING(target, "\n");
   3850 					continue;
   3851 				}
   3852 			} else {
   3853 				ADD_STRING(target, "; OPT=");
   3854 				snprintf(buf, sizeof(buf), "%u", optcode);
   3855 				ADD_STRING(target, buf);
   3856 			}
   3857 
   3858 			if (optlen != 0) {
   3859 				int i;
   3860 				ADD_STRING(target, ": ");
   3861 
   3862 				optdata = isc_buffer_current(&optbuf);
   3863 				for (i = 0; i < optlen; i++) {
   3864 					const char *sep;
   3865 					switch (optcode) {
   3866 					case DNS_OPT_COOKIE:
   3867 						sep = "";
   3868 						break;
   3869 					default:
   3870 						sep = " ";
   3871 						break;
   3872 					}
   3873 					snprintf(buf, sizeof(buf), "%02x%s",
   3874 						 optdata[i], sep);
   3875 					ADD_STRING(target, buf);
   3876 				}
   3877 
   3878 				isc_buffer_forward(&optbuf, optlen);
   3879 
   3880 				if (optcode == DNS_OPT_COOKIE) {
   3881 					/*
   3882 					 * Valid server cookie?
   3883 					 */
   3884 					if (msg->cc_ok && optlen >= 16)
   3885 						ADD_STRING(target, " (good)");
   3886 					/*
   3887 					 * Server cookie is not valid but
   3888 					 * we had our cookie echoed back.
   3889 					 */
   3890 					if (msg->cc_ok && optlen < 16)
   3891 						ADD_STRING(target, " (echoed)");
   3892 					/*
   3893 					 * We didn't get our cookie echoed
   3894 					 * back.
   3895 					 */
   3896 					if (msg->cc_bad)
   3897 						ADD_STRING(target, " (bad)");
   3898 					ADD_STRING(target, "\n");
   3899 					continue;
   3900 				}
   3901 
   3902 				if (optcode == DNS_OPT_CLIENT_SUBNET) {
   3903 					ADD_STRING(target, "\n");
   3904 					continue;
   3905 				}
   3906 
   3907 				/*
   3908 				 * For non-COOKIE options, add a printable
   3909 				 * version
   3910 				 */
   3911 				ADD_STRING(target, "(\"");
   3912 				if (isc_buffer_availablelength(target) < optlen)
   3913 					return (ISC_R_NOSPACE);
   3914 				for (i = 0; i < optlen; i++) {
   3915 					if (isprint(optdata[i]))
   3916 						isc_buffer_putmem(target,
   3917 								  &optdata[i],
   3918 								  1);
   3919 					else
   3920 						isc_buffer_putstr(target, ".");
   3921 				}
   3922 				ADD_STRING(target, "\")");
   3923 			}
   3924 			ADD_STRING(target, "\n");
   3925 		}
   3926 		return (ISC_R_SUCCESS);
   3927 	case DNS_PSEUDOSECTION_TSIG:
   3928 		ps = dns_message_gettsig(msg, &name);
   3929 		if (ps == NULL)
   3930 			return (ISC_R_SUCCESS);
   3931 		INDENT(style);
   3932 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
   3933 			ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
   3934 		result = dns_master_rdatasettotext(name, ps, style, target);
   3935 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
   3936 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
   3937 			ADD_STRING(target, "\n");
   3938 		return (result);
   3939 	case DNS_PSEUDOSECTION_SIG0:
   3940 		ps = dns_message_getsig0(msg, &name);
   3941 		if (ps == NULL)
   3942 			return (ISC_R_SUCCESS);
   3943 		INDENT(style);
   3944 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
   3945 			ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
   3946 		result = dns_master_rdatasettotext(name, ps, style, target);
   3947 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
   3948 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
   3949 			ADD_STRING(target, "\n");
   3950 		return (result);
   3951 	}
   3952 	result = ISC_R_UNEXPECTED;
   3953  cleanup:
   3954 	return (result);
   3955 }
   3956 
   3957 isc_result_t
   3958 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
   3959 		   dns_messagetextflag_t flags, isc_buffer_t *target)
   3960 {
   3961 	char buf[sizeof("1234567890")];
   3962 	isc_result_t result;
   3963 
   3964 	REQUIRE(DNS_MESSAGE_VALID(msg));
   3965 	REQUIRE(target != NULL);
   3966 
   3967 	if (((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) &&
   3968 	     (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML))
   3969 	{
   3970 		INDENT(style);
   3971 		ADD_STRING(target, "opcode: ");
   3972 		ADD_STRING(target, opcodetext[msg->opcode]);
   3973 		ADD_STRING(target, "\n");
   3974 		INDENT(style);
   3975 		ADD_STRING(target, "status: ");
   3976 		result = dns_rcode_totext(msg->rcode, target);
   3977 		if (result != ISC_R_SUCCESS)
   3978 			return (result);
   3979 		ADD_STRING(target, "\n");
   3980 		INDENT(style);
   3981 		ADD_STRING(target, "id: ");
   3982 		snprintf(buf, sizeof(buf), "%6u", msg->id);
   3983 		ADD_STRING(target, buf);
   3984 		ADD_STRING(target, "\n");
   3985 		INDENT(style);
   3986 		ADD_STRING(target, "flags:");
   3987 		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
   3988 			ADD_STRING(target, " qr");
   3989 		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
   3990 			ADD_STRING(target, " aa");
   3991 		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
   3992 			ADD_STRING(target, " tc");
   3993 		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
   3994 			ADD_STRING(target, " rd");
   3995 		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
   3996 			ADD_STRING(target, " ra");
   3997 		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
   3998 			ADD_STRING(target, " ad");
   3999 		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
   4000 			ADD_STRING(target, " cd");
   4001 		ADD_STRING(target, "\n");
   4002 		/*
   4003 		 * The final unnamed flag must be zero.
   4004 		 */
   4005 		if ((msg->flags & 0x0040U) != 0) {
   4006 			INDENT(style);
   4007 			ADD_STRING(target, "MBZ: 0x4");
   4008 			ADD_STRING(target, "\n");
   4009 		}
   4010 		if (msg->opcode != dns_opcode_update) {
   4011 			INDENT(style);
   4012 			ADD_STRING(target, "QUESTION: ");
   4013 		} else {
   4014 			ADD_STRING(target, "ZONE: ");
   4015 		}
   4016 		snprintf(buf, sizeof(buf), "%1u",
   4017 			 msg->counts[DNS_SECTION_QUESTION]);
   4018 		ADD_STRING(target, buf);
   4019 		ADD_STRING(target, "\n");
   4020 		if (msg->opcode != dns_opcode_update) {
   4021 			INDENT(style);
   4022 			ADD_STRING(target, "ANSWER: ");
   4023 		} else {
   4024 			INDENT(style);
   4025 			ADD_STRING(target, "PREREQ: ");
   4026 		}
   4027 		snprintf(buf, sizeof(buf), "%1u",
   4028 			 msg->counts[DNS_SECTION_ANSWER]);
   4029 		ADD_STRING(target, buf);
   4030 		ADD_STRING(target, "\n");
   4031 		if (msg->opcode != dns_opcode_update) {
   4032 			INDENT(style);
   4033 			ADD_STRING(target, "AUTHORITY: ");
   4034 		} else {
   4035 			INDENT(style);
   4036 			ADD_STRING(target, "UPDATE: ");
   4037 		}
   4038 		snprintf(buf, sizeof(buf), "%1u",
   4039 			msg->counts[DNS_SECTION_AUTHORITY]);
   4040 		ADD_STRING(target, buf);
   4041 		ADD_STRING(target, "\n");
   4042 		INDENT(style);
   4043 		ADD_STRING(target, "ADDITIONAL: ");
   4044 		snprintf(buf, sizeof(buf), "%1u",
   4045 			msg->counts[DNS_SECTION_ADDITIONAL]);
   4046 		ADD_STRING(target, buf);
   4047 		ADD_STRING(target, "\n");
   4048 	} else if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
   4049 		INDENT(style);
   4050 		ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
   4051 		ADD_STRING(target, opcodetext[msg->opcode]);
   4052 		ADD_STRING(target, ", status: ");
   4053 		result = dns_rcode_totext(msg->rcode, target);
   4054 		if (result != ISC_R_SUCCESS)
   4055 			return (result);
   4056 		ADD_STRING(target, ", id: ");
   4057 		snprintf(buf, sizeof(buf), "%6u", msg->id);
   4058 		ADD_STRING(target, buf);
   4059 		ADD_STRING(target, "\n");
   4060 		INDENT(style);
   4061 		ADD_STRING(target, ";; flags:");
   4062 		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
   4063 			ADD_STRING(target, " qr");
   4064 		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
   4065 			ADD_STRING(target, " aa");
   4066 		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
   4067 			ADD_STRING(target, " tc");
   4068 		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
   4069 			ADD_STRING(target, " rd");
   4070 		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
   4071 			ADD_STRING(target, " ra");
   4072 		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
   4073 			ADD_STRING(target, " ad");
   4074 		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
   4075 			ADD_STRING(target, " cd");
   4076 		/*
   4077 		 * The final unnamed flag must be zero.
   4078 		 */
   4079 		if ((msg->flags & 0x0040U) != 0) {
   4080 			INDENT(style);
   4081 			ADD_STRING(target, "; MBZ: 0x4");
   4082 		}
   4083 		if (msg->opcode != dns_opcode_update) {
   4084 			INDENT(style);
   4085 			ADD_STRING(target, "; QUESTION: ");
   4086 		} else {
   4087 			INDENT(style);
   4088 			ADD_STRING(target, "; ZONE: ");
   4089 		}
   4090 		snprintf(buf, sizeof(buf), "%1u",
   4091 			 msg->counts[DNS_SECTION_QUESTION]);
   4092 		ADD_STRING(target, buf);
   4093 		if (msg->opcode != dns_opcode_update) {
   4094 			ADD_STRING(target, ", ANSWER: ");
   4095 		} else {
   4096 			ADD_STRING(target, ", PREREQ: ");
   4097 		}
   4098 		snprintf(buf, sizeof(buf), "%1u",
   4099 			 msg->counts[DNS_SECTION_ANSWER]);
   4100 		ADD_STRING(target, buf);
   4101 		if (msg->opcode != dns_opcode_update) {
   4102 			ADD_STRING(target, ", AUTHORITY: ");
   4103 		} else {
   4104 			ADD_STRING(target, ", UPDATE: ");
   4105 		}
   4106 		snprintf(buf, sizeof(buf), "%1u",
   4107 			msg->counts[DNS_SECTION_AUTHORITY]);
   4108 		ADD_STRING(target, buf);
   4109 		ADD_STRING(target, ", ADDITIONAL: ");
   4110 		snprintf(buf, sizeof(buf), "%1u",
   4111 			msg->counts[DNS_SECTION_ADDITIONAL]);
   4112 		ADD_STRING(target, buf);
   4113 		ADD_STRING(target, "\n");
   4114 	}
   4115 	result = dns_message_pseudosectiontotext(msg,
   4116 						 DNS_PSEUDOSECTION_OPT,
   4117 						 style, flags, target);
   4118 	if (result != ISC_R_SUCCESS)
   4119 		return (result);
   4120 
   4121 	result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
   4122 					   style, flags, target);
   4123 	if (result != ISC_R_SUCCESS)
   4124 		return (result);
   4125 	result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
   4126 					   style, flags, target);
   4127 	if (result != ISC_R_SUCCESS)
   4128 		return (result);
   4129 	result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
   4130 					   style, flags, target);
   4131 	if (result != ISC_R_SUCCESS)
   4132 		return (result);
   4133 	result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
   4134 					   style, flags, target);
   4135 	if (result != ISC_R_SUCCESS)
   4136 		return (result);
   4137 
   4138 	result = dns_message_pseudosectiontotext(msg,
   4139 						 DNS_PSEUDOSECTION_TSIG,
   4140 						 style, flags, target);
   4141 	if (result != ISC_R_SUCCESS)
   4142 		return (result);
   4143 
   4144 	result = dns_message_pseudosectiontotext(msg,
   4145 						 DNS_PSEUDOSECTION_SIG0,
   4146 						 style, flags, target);
   4147 	if (result != ISC_R_SUCCESS)
   4148 		return (result);
   4149 
   4150  cleanup:
   4151 	return (result);
   4152 }
   4153 
   4154 isc_region_t *
   4155 dns_message_getrawmessage(dns_message_t *msg) {
   4156 	REQUIRE(DNS_MESSAGE_VALID(msg));
   4157 	return (&msg->saved);
   4158 }
   4159 
   4160 void
   4161 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
   4162 			 dns_aclenv_t *env, const dns_acl_t *acl,
   4163 			 const dns_aclelement_t *elem)
   4164 {
   4165 	REQUIRE(DNS_MESSAGE_VALID(msg));
   4166 	REQUIRE((order == NULL) == (env == NULL));
   4167 	REQUIRE(env == NULL || (acl != NULL || elem != NULL));
   4168 
   4169 	msg->order = order;
   4170 	msg->order_arg.env = env;
   4171 	msg->order_arg.acl = acl;
   4172 	msg->order_arg.element = elem;
   4173 }
   4174 
   4175 void
   4176 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
   4177 	REQUIRE(DNS_MESSAGE_VALID(msg));
   4178 	msg->timeadjust = timeadjust;
   4179 }
   4180 
   4181 int
   4182 dns_message_gettimeadjust(dns_message_t *msg) {
   4183 	REQUIRE(DNS_MESSAGE_VALID(msg));
   4184 	return (msg->timeadjust);
   4185 }
   4186 
   4187 isc_result_t
   4188 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
   4189 
   4190 	REQUIRE(opcode < 16);
   4191 
   4192 	if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
   4193 		return (ISC_R_NOSPACE);
   4194 	isc_buffer_putstr(target, opcodetext[opcode]);
   4195 	return (ISC_R_SUCCESS);
   4196 }
   4197 
   4198 void
   4199 dns_message_logpacket(dns_message_t *message,
   4200 		      const char *description, const isc_sockaddr_t *address,
   4201 		      isc_logcategory_t *category, isc_logmodule_t *module,
   4202 		      int level, isc_mem_t *mctx)
   4203 {
   4204 	REQUIRE(address != NULL);
   4205 
   4206 	logfmtpacket(message, description, address, category, module,
   4207 		     &dns_master_style_debug, level, mctx);
   4208 }
   4209 
   4210 void
   4211 dns_message_logfmtpacket(dns_message_t *message,
   4212 			 const char *description,
   4213 			 const isc_sockaddr_t *address,
   4214 			 isc_logcategory_t *category, isc_logmodule_t *module,
   4215 			 const dns_master_style_t *style, int level,
   4216 			 isc_mem_t *mctx)
   4217 {
   4218 	REQUIRE(address != NULL);
   4219 
   4220 	logfmtpacket(message, description, address, category, module, style,
   4221 		     level, mctx);
   4222 }
   4223 
   4224 static void
   4225 logfmtpacket(dns_message_t *message, const char *description,
   4226 	     const isc_sockaddr_t *address, isc_logcategory_t *category,
   4227 	     isc_logmodule_t *module, const dns_master_style_t *style,
   4228 	     int level, isc_mem_t *mctx)
   4229 {
   4230 	char addrbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
   4231 	const char *newline = "\n";
   4232 	const char *space = " ";
   4233 	isc_buffer_t buffer;
   4234 	char *buf = NULL;
   4235 	int len = 1024;
   4236 	isc_result_t result;
   4237 
   4238 	if (! isc_log_wouldlog(dns_lctx, level))
   4239 		return;
   4240 
   4241 	/*
   4242 	 * Note that these are multiline debug messages.  We want a newline
   4243 	 * to appear in the log after each message.
   4244 	 */
   4245 
   4246 	if (address != NULL)
   4247 		isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
   4248 	else
   4249 		newline = space = "";
   4250 
   4251 	do {
   4252 		buf = isc_mem_get(mctx, len);
   4253 		if (buf == NULL)
   4254 			break;
   4255 		isc_buffer_init(&buffer, buf, len);
   4256 		result = dns_message_totext(message, style, 0, &buffer);
   4257 		if (result == ISC_R_NOSPACE) {
   4258 			isc_mem_put(mctx, buf, len);
   4259 			len += 1024;
   4260 		} else if (result == ISC_R_SUCCESS)
   4261 			isc_log_write(dns_lctx, category, module, level,
   4262 				      "%s%s%s%s%.*s", description, space,
   4263 				      addrbuf, newline,
   4264 				      (int)isc_buffer_usedlength(&buffer),
   4265 				      buf);
   4266 	} while (result == ISC_R_NOSPACE);
   4267 
   4268 	if (buf != NULL)
   4269 		isc_mem_put(mctx, buf, len);
   4270 }
   4271 
   4272 isc_result_t
   4273 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
   4274 		     unsigned int version, uint16_t udpsize,
   4275 		     unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
   4276 {
   4277 	dns_rdataset_t *rdataset = NULL;
   4278 	dns_rdatalist_t *rdatalist = NULL;
   4279 	dns_rdata_t *rdata = NULL;
   4280 	isc_result_t result;
   4281 	unsigned int len = 0, i;
   4282 
   4283 	REQUIRE(DNS_MESSAGE_VALID(message));
   4284 	REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
   4285 
   4286 	result = dns_message_gettemprdatalist(message, &rdatalist);
   4287 	if (result != ISC_R_SUCCESS)
   4288 		return (result);
   4289 	result = dns_message_gettemprdata(message, &rdata);
   4290 	if (result != ISC_R_SUCCESS)
   4291 		goto cleanup;
   4292 	result = dns_message_gettemprdataset(message, &rdataset);
   4293 	if (result != ISC_R_SUCCESS)
   4294 		goto cleanup;
   4295 
   4296 	rdatalist->type = dns_rdatatype_opt;
   4297 
   4298 	/*
   4299 	 * Set Maximum UDP buffer size.
   4300 	 */
   4301 	rdatalist->rdclass = udpsize;
   4302 
   4303 	/*
   4304 	 * Set EXTENDED-RCODE and Z to 0.
   4305 	 */
   4306 	rdatalist->ttl = (version << 16);
   4307 	rdatalist->ttl |= (flags & 0xffff);
   4308 
   4309 	/*
   4310 	 * Set EDNS options if applicable
   4311 	 */
   4312 	if (count != 0U) {
   4313 		isc_buffer_t *buf = NULL;
   4314 		bool seenpad = false;
   4315 		for (i = 0; i < count; i++)
   4316 			len += ednsopts[i].length + 4;
   4317 
   4318 		if (len > 0xffffU) {
   4319 			result = ISC_R_NOSPACE;
   4320 			goto cleanup;
   4321 		}
   4322 
   4323 		result = isc_buffer_allocate(message->mctx, &buf, len);
   4324 		if (result != ISC_R_SUCCESS)
   4325 			goto cleanup;
   4326 
   4327 		for (i = 0; i < count; i++)  {
   4328 			if (ednsopts[i].code == DNS_OPT_PAD &&
   4329 			    ednsopts[i].length == 0U && !seenpad)
   4330 			{
   4331 				seenpad = true;
   4332 				continue;
   4333 			}
   4334 			isc_buffer_putuint16(buf, ednsopts[i].code);
   4335 			isc_buffer_putuint16(buf, ednsopts[i].length);
   4336 			if (ednsopts[i].length != 0) {
   4337 				isc_buffer_putmem(buf, ednsopts[i].value,
   4338 						  ednsopts[i].length);
   4339 			}
   4340 		}
   4341 
   4342 		/* Padding must be the final option */
   4343 		if (seenpad) {
   4344 			isc_buffer_putuint16(buf, DNS_OPT_PAD);
   4345 			isc_buffer_putuint16(buf, 0);
   4346 		}
   4347 		rdata->data = isc_buffer_base(buf);
   4348 		rdata->length = len;
   4349 		dns_message_takebuffer(message, &buf);
   4350 		if (seenpad)
   4351 			message->padding_off = len;
   4352 	} else {
   4353 		rdata->data = NULL;
   4354 		rdata->length = 0;
   4355 	}
   4356 
   4357 	rdata->rdclass = rdatalist->rdclass;
   4358 	rdata->type = rdatalist->type;
   4359 	rdata->flags = 0;
   4360 
   4361 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
   4362 	result = dns_rdatalist_tordataset(rdatalist, rdataset);
   4363 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4364 
   4365 	*rdatasetp = rdataset;
   4366 	return (ISC_R_SUCCESS);
   4367 
   4368  cleanup:
   4369 	if (rdata != NULL)
   4370 		dns_message_puttemprdata(message, &rdata);
   4371 	if (rdataset != NULL)
   4372 		dns_message_puttemprdataset(message, &rdataset);
   4373 	if (rdatalist != NULL)
   4374 		dns_message_puttemprdatalist(message, &rdatalist);
   4375 	return (result);
   4376 }
   4377 
   4378 void
   4379 dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
   4380 
   4381 	REQUIRE(DNS_MESSAGE_VALID(msg));
   4382 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
   4383 	REQUIRE(msg->state == DNS_SECTION_ANY);
   4384 	REQUIRE(msg->rdclass_set == 0);
   4385 
   4386 	msg->rdclass = rdclass;
   4387 	msg->rdclass_set = 1;
   4388 }
   4389 
   4390 void
   4391 dns_message_setpadding(dns_message_t *msg, uint16_t padding) {
   4392 	REQUIRE(DNS_MESSAGE_VALID(msg));
   4393 
   4394 	/* Avoid silly large padding */
   4395 	if (padding > 512)
   4396 		padding = 512;
   4397 	msg->padding = padding;
   4398 }
   4399