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