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