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