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