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