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