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