message.c 41.1 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
 * Copyright (C) 1999  Internet Software Consortium.
 * 
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/***
 *** Imports
 ***/

#include <config.h>

#include <stddef.h>
#include <string.h>

#include <isc/assertions.h>
Michael Graff's avatar
Michael Graff committed
28
29
#include <isc/boolean.h>
#include <isc/region.h>
30
#include <isc/types.h>
Michael Graff's avatar
Michael Graff committed
31
32
33

#include <dns/message.h>
#include <dns/rdataset.h>
Michael Graff's avatar
Michael Graff committed
34
35
36
37
38
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdatatype.h>
#include <dns/rdatalist.h>
#include <dns/compress.h>
39
#include <dns/tsig.h>
Michael Graff's avatar
Michael Graff committed
40

41
#define DNS_MESSAGE_OPCODE_MASK		0x7800U
Michael Graff's avatar
Michael Graff committed
42
43
44
#define DNS_MESSAGE_OPCODE_SHIFT	    11
#define DNS_MESSAGE_RCODE_MASK		0x000fU
#define DNS_MESSAGE_FLAG_MASK		0x8ff0U
Michael Graff's avatar
Michael Graff committed
45
46
47
48
49
50
51
52
53

#define VALID_NAMED_SECTION(s)  (((s) > DNS_SECTION_ANY) \
				 && ((s) < DNS_SECTION_MAX))
#define VALID_SECTION(s)	(((s) >= DNS_SECTION_ANY) \
				 && ((s) < DNS_SECTION_MAX))

/*
 * This is the size of each individual scratchpad buffer, and the numbers
 * of various block allocations used within the server.
Michael Graff's avatar
Michael Graff committed
54
 * XXXMLG These should come from a config setting.
Michael Graff's avatar
Michael Graff committed
55
 */
Michael Graff's avatar
Michael Graff committed
56
#define SCRATCHPAD_SIZE		512
57
58
59
60
#define NAME_COUNT		  8
#define RDATA_COUNT		  8
#define RDATALIST_COUNT		  8
#define RDATASET_COUNT		 RDATALIST_COUNT
Michael Graff's avatar
Michael Graff committed
61
62
63
64
65
66
67

/*
 * "helper" type, which consists of a block of some type, and is linkable.
 * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
 * size, or the allocated elements will not be alligned correctly.
 */
struct dns_msgblock {
Michael Graff's avatar
Michael Graff committed
68
	unsigned int			count;
Michael Graff's avatar
Michael Graff committed
69
70
71
	unsigned int			remaining;
	ISC_LINK(dns_msgblock_t)	link;
}; /* dynamically sized */
Michael Graff's avatar
Michael Graff committed
72

Michael Graff's avatar
Michael Graff committed
73
74
static inline dns_msgblock_t *
msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
75

Michael Graff's avatar
Michael Graff committed
76
#define msgblock_get(block, type) \
Michael Graff's avatar
Michael Graff committed
77
	((type *)msgblock_internalget(block, sizeof(type)))
Michael Graff's avatar
Michael Graff committed
78
79

static inline void *
Michael Graff's avatar
Michael Graff committed
80
81
82
msgblock_internalget(dns_msgblock_t *, unsigned int);

static inline void
Michael Graff's avatar
Michael Graff committed
83
msgblock_reset(dns_msgblock_t *);
Michael Graff's avatar
Michael Graff committed
84

Michael Graff's avatar
Michael Graff committed
85
86
static inline void
msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
Michael Graff's avatar
Michael Graff committed
87
88
89
90
91
92

/*
 * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
 * is free, return NULL.
 */
static inline dns_msgblock_t *
Michael Graff's avatar
Michael Graff committed
93
94
msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
		  unsigned int count)
Michael Graff's avatar
Michael Graff committed
95
96
97
98
99
100
101
102
{
	dns_msgblock_t *block;
	unsigned int length;

	length = sizeof(dns_msgblock_t) + (sizeof_type * count);

	block = isc_mem_get(mctx, length);
	if (block == NULL)
Michael Graff's avatar
Michael Graff committed
103
		return (NULL);
Michael Graff's avatar
Michael Graff committed
104

Michael Graff's avatar
Michael Graff committed
105
	block->count = count;
Michael Graff's avatar
Michael Graff committed
106
107
108
109
110
111
112
113
114
115
116
117
	block->remaining = count;

	ISC_LINK_INIT(block, link);

	return (block);
}

/*
 * Return an element from the msgblock.  If no more are available, return
 * NULL.
 */
static inline void *
Michael Graff's avatar
Michael Graff committed
118
msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type)
Michael Graff's avatar
Michael Graff committed
119
120
121
{
	void *ptr;

Andreas Gustafsson's avatar
Andreas Gustafsson committed
122
	if (block == NULL || block->remaining == 0)
Michael Graff's avatar
Michael Graff committed
123
124
125
126
127
128
129
130
131
132
133
		return (NULL);

	block->remaining--;

	ptr = (((unsigned char *)block)
	       + sizeof(dns_msgblock_t)
	       + (sizeof_type * block->remaining));

	return (ptr);
}

Michael Graff's avatar
Michael Graff committed
134
static inline void
Michael Graff's avatar
Michael Graff committed
135
msgblock_reset(dns_msgblock_t *block)
Michael Graff's avatar
Michael Graff committed
136
{
Michael Graff's avatar
Michael Graff committed
137
	block->remaining = block->count;
Michael Graff's avatar
Michael Graff committed
138
139
}

Michael Graff's avatar
Michael Graff committed
140
141
142
143
/*
 * Release memory associated with a message block.
 */
static inline void
Michael Graff's avatar
Michael Graff committed
144
145
msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block,
	      unsigned int sizeof_type)
Michael Graff's avatar
Michael Graff committed
146
{
Michael Graff's avatar
Michael Graff committed
147
148
149
150
151
	unsigned int length;

	length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);

	isc_mem_put(mctx, block, length);
Michael Graff's avatar
Michael Graff committed
152
}
Michael Graff's avatar
Michael Graff committed
153

Michael Graff's avatar
Michael Graff committed
154
155
156
157
158
159
/*
 * Allocate a new dynamic buffer, and attach it to this message as the
 * "current" buffer.  (which is always the last on the list, for our
 * uses)
 */
static inline dns_result_t
160
newbuffer(dns_message_t *msg, unsigned int size)
Michael Graff's avatar
Michael Graff committed
161
162
163
164
165
{
	isc_result_t result;
	isc_dynbuffer_t *dynbuf;

	dynbuf = NULL;
166
	result = isc_dynbuffer_allocate(msg->mctx, &dynbuf, size,
Michael Graff's avatar
Michael Graff committed
167
168
169
170
171
172
173
174
175
176
177
178
179
180
					ISC_BUFFERTYPE_BINARY);
	if (result != ISC_R_SUCCESS)
		return (DNS_R_NOMEMORY);

	ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
	return (DNS_R_SUCCESS);
}

static inline isc_buffer_t *
currentbuffer(dns_message_t *msg)
{
	isc_dynbuffer_t *dynbuf;

	dynbuf = ISC_LIST_TAIL(msg->scratchpad);
Michael Graff's avatar
Michael Graff committed
181
	INSIST(dynbuf != NULL);
Michael Graff's avatar
Michael Graff committed
182
183
184
185
186
187
188

	return (&dynbuf->buffer);
}

static inline void
releasename(dns_message_t *msg, dns_name_t *name)
{
189
	ISC_LIST_PREPEND(msg->freename, name, link);
Michael Graff's avatar
Michael Graff committed
190
191
192
193
194
195
196
197
}

static inline dns_name_t *
newname(dns_message_t *msg)
{
	dns_msgblock_t *msgblock;
	dns_name_t *name;

198
199
200
	name = ISC_LIST_HEAD(msg->freename);
	if (name != NULL) {
		ISC_LIST_UNLINK(msg->freename, name, link);
Michael Graff's avatar
Michael Graff committed
201
202
203
		return (name);
	}

Michael Graff's avatar
Michael Graff committed
204
	msgblock = ISC_LIST_TAIL(msg->names);
Michael Graff's avatar
Michael Graff committed
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
	name = msgblock_get(msgblock, dns_name_t);
	if (name == NULL) {
		msgblock = msgblock_allocate(msg->mctx, sizeof(dns_name_t),
					     NAME_COUNT);
		if (msgblock == NULL)
			return (NULL);

		ISC_LIST_APPEND(msg->names, msgblock, link);

		name = msgblock_get(msgblock, dns_name_t);
	}

	return (name);
}

static inline void
releaserdata(dns_message_t *msg, dns_rdata_t *rdata)
{
223
	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
Michael Graff's avatar
Michael Graff committed
224
225
226
227
228
229
230
231
}

static inline dns_rdata_t *
newrdata(dns_message_t *msg)
{
	dns_msgblock_t *msgblock;
	dns_rdata_t *rdata;

232
233
234
	rdata = ISC_LIST_HEAD(msg->freerdata);
	if (rdata != NULL) {
		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
Michael Graff's avatar
Michael Graff committed
235
236
237
		return (rdata);
	}

Michael Graff's avatar
Michael Graff committed
238
	msgblock = ISC_LIST_TAIL(msg->rdatas);
Michael Graff's avatar
Michael Graff committed
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
	rdata = msgblock_get(msgblock, dns_rdata_t);
	if (rdata == NULL) {
		msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
					     RDATA_COUNT);
		if (msgblock == NULL)
			return (NULL);

		ISC_LIST_APPEND(msg->rdatas, msgblock, link);

		rdata = msgblock_get(msgblock, dns_rdata_t);
	}

	return (rdata);
}

static inline void
releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist)
{
257
	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
258
259
260
261
262
263
264
265
}

static inline dns_rdatalist_t *
newrdatalist(dns_message_t *msg)
{
	dns_msgblock_t *msgblock;
	dns_rdatalist_t *rdatalist;

266
267
268
	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
	if (rdatalist != NULL) {
		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
269
270
271
		return (rdatalist);
	}

Michael Graff's avatar
Michael Graff committed
272
	msgblock = ISC_LIST_TAIL(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
	rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
	if (rdatalist == NULL) {
		msgblock = msgblock_allocate(msg->mctx,
					     sizeof(dns_rdatalist_t),
					     RDATALIST_COUNT);
		if (msgblock == NULL)
			return (NULL);

		ISC_LIST_APPEND(msg->rdatalists, msgblock, link);

		rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
	}

	return (rdatalist);
}

static inline void
releaserdataset(dns_message_t *msg, dns_rdataset_t *rdataset)
{
292
	ISC_LIST_PREPEND(msg->freerdataset, rdataset, link);
Michael Graff's avatar
Michael Graff committed
293
294
295
296
297
298
299
300
}

static inline dns_rdataset_t *
newrdataset(dns_message_t *msg)
{
	dns_msgblock_t *msgblock;
	dns_rdataset_t *rdataset;

301
302
303
	rdataset = ISC_LIST_HEAD(msg->freerdataset);
	if (rdataset != NULL) {
		ISC_LIST_UNLINK(msg->freerdataset, rdataset, link);
Michael Graff's avatar
Michael Graff committed
304
305
306
		return (rdataset);
	}

Michael Graff's avatar
Michael Graff committed
307
	msgblock = ISC_LIST_TAIL(msg->rdatasets);
Michael Graff's avatar
Michael Graff committed
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
	rdataset = msgblock_get(msgblock, dns_rdataset_t);
	if (rdataset == NULL) {
		msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdataset_t),
					     RDATASET_COUNT);
		if (msgblock == NULL)
			return (NULL);

		ISC_LIST_APPEND(msg->rdatasets, msgblock, link);

		rdataset = msgblock_get(msgblock, dns_rdataset_t);
	}

	return (rdataset);
}

Michael Graff's avatar
Michael Graff committed
323
static inline void
324
msginitheader(dns_message_t *m)
Michael Graff's avatar
Michael Graff committed
325
326
327
328
329
{
	m->id = 0;
	m->flags = 0;
	m->rcode = 0;
	m->opcode = 0;
Michael Graff's avatar
Michael Graff committed
330
	m->rdclass = 0;
331
}
Michael Graff's avatar
Michael Graff committed
332

333
334
335
336
337
338
static inline void
msginitprivate(dns_message_t *m)
{
	unsigned int i;

	for (i = 0; i < DNS_SECTION_MAX; i++) {
Michael Graff's avatar
Michael Graff committed
339
		m->cursors[i] = NULL;
Michael Graff's avatar
Michael Graff committed
340
		m->counts[i] = 0;
Michael Graff's avatar
Michael Graff committed
341
	}
342
	m->opt = NULL;
Michael Graff's avatar
Michael Graff committed
343
	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
Michael Graff's avatar
Michael Graff committed
344
	m->reserved = 0;
345
	m->buffer = NULL;
346
	m->need_cctx_cleanup = 0;
Michael Graff's avatar
Michael Graff committed
347
348
}

349
350
351
352
353
354
355
356
357
static inline void
msginittsig(dns_message_t *m)
{
	m->tsigstatus = m->querytsigstatus = dns_rcode_noerror;
	m->tsig = m->querytsig = NULL;
	m->tsigkey = NULL;
	m->tsigstart = -1;
}

Michael Graff's avatar
Michael Graff committed
358
/*
359
360
 * Init elements to default state.  Used both when allocating a new element
 * and when resetting one.
Michael Graff's avatar
Michael Graff committed
361
 */
362
363
static inline void
msginit(dns_message_t *m)
Michael Graff's avatar
Michael Graff committed
364
{
365
366
	msginitheader(m);
	msginitprivate(m);
367
	msginittsig(m);
Bob Halley's avatar
Bob Halley committed
368
369
	m->header_ok = 0;
	m->question_ok = 0;
370
371
372
373
}

static inline void
msgresetnames(dns_message_t *msg, unsigned int first_section) {
Michael Graff's avatar
Michael Graff committed
374
	unsigned int i;
375
376
	dns_name_t *name, *next_name;
	dns_rdataset_t *rds, *next_rds;
Michael Graff's avatar
Michael Graff committed
377
378
379
380

	/*
	 * Clean up name lists by calling the rdataset disassociate function.
	 */
381
	for (i = first_section; i < DNS_SECTION_MAX; i++) {
Michael Graff's avatar
Michael Graff committed
382
383
384
385
386
387
388
389
390
391
392
393
394
		name = ISC_LIST_HEAD(msg->sections[i]);
		while (name != NULL) {
			next_name = ISC_LIST_NEXT(name, link);
			ISC_LIST_UNLINK(msg->sections[i], name, link);

			rds = ISC_LIST_HEAD(name->list);
			while (rds != NULL) {
				next_rds = ISC_LIST_NEXT(rds, link);
				ISC_LIST_UNLINK(name->list, rds, link);

				dns_rdataset_disassociate(rds);
				rds = next_rds;
			}
395
			name = next_name;
Michael Graff's avatar
Michael Graff committed
396
397
		}
	}
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
}

/*
 * Free all but one (or everything) for this message.  This is used by
 * both dns_message_reset() and dns_message_parse().
 */
static void
msgreset(dns_message_t *msg, isc_boolean_t everything)
{
	dns_msgblock_t *msgblock, *next_msgblock;
	isc_dynbuffer_t *dynbuf, *next_dynbuf;
	dns_rdataset_t *rds;
	dns_name_t *name;
	dns_rdata_t *rdata;
	dns_rdatalist_t *rdatalist;

	msgresetnames(msg, 0);
Michael Graff's avatar
Michael Graff committed
415
416
417
418
419

	/*
	 * Clean up linked lists.
	 */

420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
	/*
	 * Run through the free lists, and just unlink anything found there.
	 * The memory isn't lost since these are part of message blocks we
	 * have allocated.
	 */
	name = ISC_LIST_HEAD(msg->freename);
	while (name != NULL) {
		ISC_LIST_UNLINK(msg->freename, name, link);
		name = ISC_LIST_HEAD(msg->freename);
	}
	rdata = ISC_LIST_HEAD(msg->freerdata);
	while (rdata != NULL) {
		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
		rdata = ISC_LIST_HEAD(msg->freerdata);
	}
	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
	while (rdatalist != NULL) {
		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
		rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
	}
	rds = ISC_LIST_HEAD(msg->freerdataset);
	while (rds != NULL) {
		ISC_LIST_UNLINK(msg->freerdataset, rds, link);
		rds = ISC_LIST_HEAD(msg->freerdataset);
	}

Michael Graff's avatar
Michael Graff committed
446
447
	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
	INSIST(dynbuf != NULL);
Michael Graff's avatar
Michael Graff committed
448
	if (!everything) {
Michael Graff's avatar
Michael Graff committed
449
450
451
452
453
454
455
456
457
458
459
460
		isc_dynbuffer_reset(dynbuf);
		dynbuf = ISC_LIST_NEXT(dynbuf, link);
	}
	while (dynbuf != NULL) {
		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
		isc_dynbuffer_free(msg->mctx, &dynbuf);
		dynbuf = next_dynbuf;
	}

	msgblock = ISC_LIST_HEAD(msg->names);
	INSIST(msgblock != NULL);
Michael Graff's avatar
Michael Graff committed
461
462
	if (!everything) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
463
464
465
466
467
		msgblock = ISC_LIST_NEXT(msgblock, link);
	}
	while (msgblock != NULL) {
		next_msgblock = ISC_LIST_NEXT(msgblock, link);
		ISC_LIST_UNLINK(msg->names, msgblock, link);
Michael Graff's avatar
Michael Graff committed
468
		msgblock_free(msg->mctx, msgblock, sizeof(dns_name_t));
Michael Graff's avatar
Michael Graff committed
469
470
471
472
473
		msgblock = next_msgblock;
	}

	msgblock = ISC_LIST_HEAD(msg->rdatas);
	INSIST(msgblock != NULL);
Michael Graff's avatar
Michael Graff committed
474
475
	if (!everything) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
476
477
478
479
480
		msgblock = ISC_LIST_NEXT(msgblock, link);
	}
	while (msgblock != NULL) {
		next_msgblock = ISC_LIST_NEXT(msgblock, link);
		ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
Michael Graff's avatar
Michael Graff committed
481
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
Michael Graff's avatar
Michael Graff committed
482
483
484
		msgblock = next_msgblock;
	}

Michael Graff's avatar
Michael Graff committed
485
486
	msgblock = ISC_LIST_HEAD(msg->rdatasets);
	INSIST(msgblock != NULL);
Michael Graff's avatar
Michael Graff committed
487
488
	if (!everything) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
489
490
491
492
493
		msgblock = ISC_LIST_NEXT(msgblock, link);
	}
	while (msgblock != NULL) {
		next_msgblock = ISC_LIST_NEXT(msgblock, link);
		ISC_LIST_UNLINK(msg->rdatasets, msgblock, link);
Michael Graff's avatar
Michael Graff committed
494
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdataset_t));
Michael Graff's avatar
Michael Graff committed
495
496
497
		msgblock = next_msgblock;
	}

Michael Graff's avatar
Michael Graff committed
498
	/*
Michael Graff's avatar
Michael Graff committed
499
	 * rdatalists could be empty.
Michael Graff's avatar
Michael Graff committed
500
501
502
	 */

	msgblock = ISC_LIST_HEAD(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
503
504
	if (!everything && msgblock != NULL) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
505
506
507
508
509
		msgblock = ISC_LIST_NEXT(msgblock, link);
	}
	while (msgblock != NULL) {
		next_msgblock = ISC_LIST_NEXT(msgblock, link);
		ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
Michael Graff's avatar
Michael Graff committed
510
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
Michael Graff's avatar
Michael Graff committed
511
		msgblock = next_msgblock;
Michael Graff's avatar
Michael Graff committed
512
513
	}

514
	if (msg->need_cctx_cleanup == 1)
Michael Graff's avatar
Michael Graff committed
515
516
		dns_compress_invalidate(&msg->cctx);

517
518
519
520
521
522
523
524
525
526
527
528
529
530
	if (msg->tsig != NULL) {
		dns_rdata_freestruct(msg->tsig);
		isc_mem_put(msg->mctx, msg->tsig, sizeof(dns_rdata_any_tsig_t));
	}

	if (msg->querytsig != NULL) {
		dns_rdata_freestruct(msg->querytsig);
		isc_mem_put(msg->mctx, msg->querytsig,
			    sizeof(dns_rdata_any_tsig_t));
        }

	if (msg->tsigkey != NULL && dns_tsig_emptykey(msg->tsigkey))
		dns_tsig_key_free(&msg->tsigkey);

Michael Graff's avatar
Michael Graff committed
531
532
533
	/*
	 * Set other bits to normal default values.
	 */
Michael Graff's avatar
Michael Graff committed
534
535
	if (!everything)
		msginit(msg);
Michael Graff's avatar
Michael Graff committed
536
537
538
}

dns_result_t
539
dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
Michael Graff's avatar
Michael Graff committed
540
541
542
543
544
545
546
547
{
	dns_message_t *m;
	isc_result_t iresult;
	dns_msgblock_t *msgblock;
	isc_dynbuffer_t *dynbuf;
	unsigned int i;

	REQUIRE(mctx != NULL);
548
549
	REQUIRE(msgp != NULL);
	REQUIRE(*msgp == NULL);
Michael Graff's avatar
Michael Graff committed
550
551
	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
		|| intent == DNS_MESSAGE_INTENTRENDER);
Michael Graff's avatar
Michael Graff committed
552
553
554
555
556

	m = isc_mem_get(mctx, sizeof(dns_message_t));
	if (m == NULL)
		return(DNS_R_NOMEMORY);

557
	m->magic = DNS_MESSAGE_MAGIC;
Michael Graff's avatar
Michael Graff committed
558
559
560
561
562
563
564
565
	m->from_to_wire = intent;
	msginit(m);
	for (i = 0 ; i < DNS_SECTION_MAX ; i++)
		ISC_LIST_INIT(m->sections[i]);
	m->mctx = mctx;
	ISC_LIST_INIT(m->scratchpad);
	ISC_LIST_INIT(m->names);
	ISC_LIST_INIT(m->rdatas);
566
	ISC_LIST_INIT(m->rdatasets);
Michael Graff's avatar
Michael Graff committed
567
	ISC_LIST_INIT(m->rdatalists);
568
569
570
571
	ISC_LIST_INIT(m->freename);
	ISC_LIST_INIT(m->freerdata);
	ISC_LIST_INIT(m->freerdataset);
	ISC_LIST_INIT(m->freerdatalist);
Michael Graff's avatar
Michael Graff committed
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591

	dynbuf = NULL;
	iresult = isc_dynbuffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE,
					 ISC_BUFFERTYPE_BINARY);
	if (iresult != ISC_R_SUCCESS)
		goto cleanup1;
	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);

	msgblock = msgblock_allocate(mctx, sizeof(dns_name_t),
				     NAME_COUNT);
	if (msgblock == NULL)
		goto cleanup2;
	ISC_LIST_APPEND(m->names, msgblock, link);

	msgblock = msgblock_allocate(mctx, sizeof(dns_rdata_t),
				     RDATA_COUNT);
	if (msgblock == NULL)
		goto cleanup3;
	ISC_LIST_APPEND(m->rdatas, msgblock, link);

Michael Graff's avatar
Michael Graff committed
592
593
594
595
	msgblock = msgblock_allocate(mctx, sizeof(dns_rdataset_t),
				     RDATASET_COUNT);
	if (msgblock == NULL)
		goto cleanup4;
596
	ISC_LIST_APPEND(m->rdatasets, msgblock, link);
Michael Graff's avatar
Michael Graff committed
597

Michael Graff's avatar
Michael Graff committed
598
	if (intent == DNS_MESSAGE_INTENTPARSE) {
Michael Graff's avatar
Michael Graff committed
599
600
601
		msgblock = msgblock_allocate(mctx, sizeof(dns_rdatalist_t),
					     RDATALIST_COUNT);
		if (msgblock == NULL)
Michael Graff's avatar
Michael Graff committed
602
			goto cleanup5;
Michael Graff's avatar
Michael Graff committed
603
604
605
		ISC_LIST_APPEND(m->rdatalists, msgblock, link);
	}

606
	*msgp = m;
Michael Graff's avatar
Michael Graff committed
607
608
609
610
611
	return (DNS_R_SUCCESS);

	/*
	 * Cleanup for error returns.
	 */
Michael Graff's avatar
Michael Graff committed
612
613
 cleanup5:
	msgblock = ISC_LIST_HEAD(m->rdatasets);
Michael Graff's avatar
Michael Graff committed
614
	msgblock_free(mctx, msgblock, sizeof(dns_rdataset_t));
Michael Graff's avatar
Michael Graff committed
615
616
 cleanup4:
	msgblock = ISC_LIST_HEAD(m->rdatas);
Michael Graff's avatar
Michael Graff committed
617
	msgblock_free(mctx, msgblock, sizeof(dns_rdata_t));
Michael Graff's avatar
Michael Graff committed
618
619
 cleanup3:
	msgblock = ISC_LIST_HEAD(m->names);
Michael Graff's avatar
Michael Graff committed
620
	msgblock_free(mctx, msgblock, sizeof(dns_name_t));
Michael Graff's avatar
Michael Graff committed
621
622
623
624
625
626
627
628
629
630
631
 cleanup2:
	dynbuf = ISC_LIST_HEAD(m->scratchpad);
	isc_dynbuffer_free(mctx, &dynbuf);
 cleanup1:
	m->magic = 0;
	isc_mem_put(mctx, m, sizeof(dns_message_t));

	return (DNS_R_NOMEMORY);
}

void
632
dns_message_reset(dns_message_t *msg, unsigned int intent)
Michael Graff's avatar
Michael Graff committed
633
{
634
635
636
637
638
	REQUIRE(DNS_MESSAGE_VALID(msg));
	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
		|| intent == DNS_MESSAGE_INTENTRENDER);

	msg->from_to_wire = intent;
Michael Graff's avatar
Michael Graff committed
639
640
641
642
	msgreset(msg, ISC_FALSE);
}

void
643
dns_message_destroy(dns_message_t **msgp)
Michael Graff's avatar
Michael Graff committed
644
645
646
{
	dns_message_t *msg;

647
	REQUIRE(msgp != NULL);
648
	REQUIRE(DNS_MESSAGE_VALID(*msgp));
Michael Graff's avatar
Michael Graff committed
649

650
651
	msg = *msgp;
	*msgp = NULL;
Michael Graff's avatar
Michael Graff committed
652
653
654
655
656
657

	msgreset(msg, ISC_TRUE);
	msg->magic = 0;
	isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
}

Michael Graff's avatar
Michael Graff committed
658
659
660
661
662
663
664
665
static dns_result_t
findname(dns_name_t **foundname, dns_name_t *target, dns_namelist_t *section)
{
	dns_name_t *curr;

	for (curr = ISC_LIST_TAIL(*section) ;
	     curr != NULL ;
	     curr = ISC_LIST_PREV(curr, link)) {
Michael Graff's avatar
Michael Graff committed
666
		if (dns_name_equal(curr, target)) {
Michael Graff's avatar
Michael Graff committed
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
			if (foundname != NULL)
				*foundname = curr;
			return (DNS_R_SUCCESS);
		}
	}

	return (DNS_R_NOTFOUND);
}

static dns_result_t
findtype(dns_rdataset_t **rdataset, dns_name_t *name, dns_rdatatype_t type)
{
	dns_rdataset_t *curr;

	for (curr = ISC_LIST_TAIL(name->list) ;
	     curr != NULL ;
	     curr = ISC_LIST_PREV(curr, link)) {
		if (curr->type == type) {
			if (rdataset != NULL)
				*rdataset = curr;
			return (DNS_R_SUCCESS);
		}
	}

	return (DNS_R_NOTFOUND);
}

/*
 * Read a name from buffer "source".
 */
static dns_result_t
getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
	dns_decompress_t *dctx)
{
	isc_buffer_t *scratch;
	dns_result_t result;
	unsigned int tries;

	scratch = currentbuffer(msg);

Michael Graff's avatar
Michael Graff committed
707
708
709
710
	/*
	 * First try:  use current buffer.
	 * Second try:  allocate a new buffer and use that.
	 */
Michael Graff's avatar
Michael Graff committed
711
712
	tries = 0;
	while (tries < 2) {
713
		dns_name_init(name, NULL);
Michael Graff's avatar
Michael Graff committed
714
715
716
717
718
719
		result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
					   scratch);

		if (result == DNS_R_NOSPACE) {
			tries++;

720
			result = newbuffer(msg, SCRATCHPAD_SIZE);
Michael Graff's avatar
Michael Graff committed
721
722
723
724
725
726
727
728
729
			if (result != DNS_R_SUCCESS)
				return (result);

			scratch = currentbuffer(msg);
		} else {
			return (result);
		}
	}

Michael Graff's avatar
Michael Graff committed
730
731
	INSIST(0);  /* Cannot get here... */
	return (DNS_R_UNEXPECTED);
Michael Graff's avatar
Michael Graff committed
732
733
}

734
735
736
737
738
739
740
741
static dns_result_t
getrdata(dns_name_t *name, 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)
{
	isc_buffer_t *scratch;
	dns_result_t result;
	unsigned int tries;
742
	unsigned int trysize;
743

744
745
746
747
748
749
750
751
	/*
	 * In dynamic update messages, the rdata can be empty.
	 */
	if (msg->opcode == dns_opcode_update && rdatalen == 0) {
		/*
		 * When the rdata is empty, the data pointer is never
		 * dereferenced, but it must still be non-NULL.
		 */
Bob Halley's avatar
Bob Halley committed
752
		rdata->data = (unsigned char *)""; 
753
		rdata->length = 0;
Bob Halley's avatar
Bob Halley committed
754
		rdata->rdclass = rdclass;
755
756
757
758
		rdata->type = rdtype;
		return DNS_R_SUCCESS;
	}
	    
759
760
761
762
763
	scratch = currentbuffer(msg);

	isc_buffer_setactive(source, rdatalen);
	dns_decompress_localinit(dctx, name, source);

Michael Graff's avatar
Michael Graff committed
764
765
	/*
	 * First try:  use current buffer.
766
767
768
769
	 * Second try:  allocate a new buffer of size
	 *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
	 *     (the data will fit if it was not more than 50% compressed)
	 * Subsequent tries: double buffer size on each try.
Michael Graff's avatar
Michael Graff committed
770
	 */
771
	tries = 0;
772
773
	trysize = 0;
	for (;;) {
774
775
776
777
778
		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
					    source, dctx, ISC_FALSE,
					    scratch);

		if (result == DNS_R_NOSPACE) {
779
780
781
782
783
784
785
786
787
788
789
			if (tries == 0) {
				trysize = 2 * rdatalen;
				if (trysize < SCRATCHPAD_SIZE)
					trysize = SCRATCHPAD_SIZE;
			} else {
				INSIST(trysize != 0);
				if (trysize >= 65535)
					return (ISC_R_NOSPACE);
					/* XXX DNS_R_RRTOOLONG? */
				trysize *= 2;
			}
790
			tries++;
791
			result = newbuffer(msg, trysize);
792
793
794
795
796
797
798
799
800
			if (result != DNS_R_SUCCESS)
				return (result);

			scratch = currentbuffer(msg);
		} else {
			return (result);
		}
	}
}
Michael Graff's avatar
Michael Graff committed
801

Michael Graff's avatar
Michael Graff committed
802
803
804
805
806
807
808
809
810
811
static dns_result_t
getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx)
{
	isc_region_t r;
	unsigned int count;
	dns_name_t *name;
	dns_name_t *name2;
	dns_rdataset_t *rdataset;
	dns_rdatalist_t *rdatalist;
	dns_result_t result;
Michael Graff's avatar
Michael Graff committed
812
813
814
	dns_rdatatype_t rdtype;
	dns_rdataclass_t rdclass;
	dns_namelist_t *section;
Michael Graff's avatar
Michael Graff committed
815

Michael Graff's avatar
Michael Graff committed
816
	section = &msg->sections[DNS_SECTION_QUESTION];
Michael Graff's avatar
Michael Graff committed
817

Michael Graff's avatar
Michael Graff committed
818
	for (count = 0 ; count < msg->counts[DNS_SECTION_QUESTION] ; count++) {
Michael Graff's avatar
Michael Graff committed
819
820
821
822
823
824
825
		name = newname(msg);
		if (name == NULL)
			return (DNS_R_NOMEMORY);

		/*
		 * Parse the name out of this packet.
		 */
826
827
		isc_buffer_remaining(source, &r);
		isc_buffer_setactive(source, r.length);
Michael Graff's avatar
Michael Graff committed
828
829
830
831
832
833
834
835
836
837
		result = getname(name, source, msg, dctx);
		if (result != DNS_R_SUCCESS)
			return (result);

		/*
		 * Run through the section, looking to see if this name
		 * is already there.  If it is found, put back the allocated
		 * name since we no longer need it, and set our name pointer
		 * to point to the name we found.
		 */
Michael Graff's avatar
Michael Graff committed
838
		result = findname(&name2, name, section);
Michael Graff's avatar
Michael Graff committed
839
840

		/*
841
842
843
844
		 * If it is the first name in the section, accept it.
		 *
		 * If it is not, but is not the same as the name already
		 * in the question section, append to the section.  Note that
Michael Graff's avatar
Michael Graff committed
845
846
847
848
		 * here in the question section this is illegal, so return
		 * FORMERR.  In the future, check the opcode to see if
		 * this should be legal or not.  In either case we no longer
		 * need this name pointer.
Michael Graff's avatar
Michael Graff committed
849
		 */
850
851
852
853
854
855
856
857
858
		if (result != DNS_R_SUCCESS) {
			if (ISC_LIST_EMPTY(*section)) {
				ISC_LIST_APPEND(*section, name, link);
			} else {
				return (DNS_R_FORMERR);
			}
		} else {
			name = name2;
		}
Michael Graff's avatar
Michael Graff committed
859
860
861
862

		/*
		 * Get type and class.
		 */
Michael Graff's avatar
Michael Graff committed
863
864
865
866
867
		isc_buffer_remaining(source, &r);
		if (r.length < 4)
			return (DNS_R_UNEXPECTEDEND);
		rdtype = isc_buffer_getuint16(source);
		rdclass = isc_buffer_getuint16(source);
Michael Graff's avatar
Michael Graff committed
868
869

		/*
870
		 * If this class is different than the one we already read,
Michael Graff's avatar
Michael Graff committed
871
		 * this is an error.
Michael Graff's avatar
Michael Graff committed
872
		 */
Michael Graff's avatar
Michael Graff committed
873
874
875
		if (msg->state == DNS_SECTION_ANY) {
			msg->state = DNS_SECTION_QUESTION;
			msg->rdclass = rdclass;
876
			msg->state = DNS_SECTION_QUESTION;
Michael Graff's avatar
Michael Graff committed
877
878
879
		} else if (msg->rdclass != rdclass)
			return (DNS_R_FORMERR);
		
Michael Graff's avatar
Michael Graff committed
880
		/*
Michael Graff's avatar
Michael Graff committed
881
		 * Can't ask the same question twice.
Michael Graff's avatar
Michael Graff committed
882
		 */
Michael Graff's avatar
Michael Graff committed
883
884
885
		result = findtype(NULL, name, rdtype);
		if (result == DNS_R_SUCCESS)
			return (DNS_R_FORMERR);
Michael Graff's avatar
Michael Graff committed
886
887
888
889

		/*
		 * Allocate a new rdatalist.
		 */
Michael Graff's avatar
Michael Graff committed
890
		rdatalist = newrdatalist(msg);
Michael Graff's avatar
Michael Graff committed
891
892
		if (rdatalist == NULL)
			return (DNS_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
893
		rdataset = newrdataset(msg);
Michael Graff's avatar
Michael Graff committed
894
895
		if (rdataset == NULL)
			return (DNS_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
896
897
898
899
900

		/*
		 * Convert rdatalist to rdataset, and attach the latter to
		 * the name.
		 */
Michael Graff's avatar
Michael Graff committed
901
902
903
904
905
		rdatalist->type = rdtype;
		rdatalist->rdclass = rdclass;
		rdatalist->ttl = 0;
		ISC_LIST_INIT(rdatalist->rdata);

906
		dns_rdataset_init(rdataset);
Michael Graff's avatar
Michael Graff committed
907
908
909
		result = dns_rdatalist_tordataset(rdatalist, rdataset);
		if (result != DNS_R_SUCCESS)
			return (result);
910
		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
Michael Graff's avatar
Michael Graff committed
911
912

		ISC_LIST_APPEND(name->list, rdataset, link);
Michael Graff's avatar
Michael Graff committed
913
914
915
916
917
918
919
	}
	
	return (DNS_R_SUCCESS);
}

static dns_result_t
getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
920
	   dns_section_t sectionid, isc_boolean_t preserve_order)
Michael Graff's avatar
Michael Graff committed
921
{
Michael Graff's avatar
Michael Graff committed
922
923
	isc_region_t r;
	unsigned int count;
Michael Graff's avatar
Michael Graff committed
924
	unsigned int rdatalen;
Michael Graff's avatar
Michael Graff committed
925
926
927
928
929
930
931
	dns_name_t *name;
	dns_name_t *name2;
	dns_rdataset_t *rdataset;
	dns_rdatalist_t *rdatalist;
	dns_result_t result;
	dns_rdatatype_t rdtype;
	dns_rdataclass_t rdclass;
932
	dns_rdata_t *rdata;
Michael Graff's avatar
Michael Graff committed
933
934
935
936
	dns_ttl_t ttl;
	dns_namelist_t *section;

	for (count = 0 ; count < msg->counts[sectionid] ; count++) {
937
		int recstart = source->current;
938
939
		section = &msg->sections[sectionid];

Michael Graff's avatar
Michael Graff committed
940
941
942
943
944
945
946
		name = newname(msg);
		if (name == NULL)
			return (DNS_R_NOMEMORY);

		/*
		 * Parse the name out of this packet.
		 */
947
948
		isc_buffer_remaining(source, &r);
		isc_buffer_setactive(source, r.length);
Michael Graff's avatar
Michael Graff committed
949
950
951
952
953
954
955
		result = getname(name, source, msg, dctx);
		if (result != DNS_R_SUCCESS)
			return (result);

		/*
		 * Get type, class, ttl, and rdatalen.  Verify that at least
		 * rdatalen bytes remain.  (Some of this is deferred to
Michael Graff's avatar
Michael Graff committed
956
		 * later.)
Michael Graff's avatar
Michael Graff committed
957
958
		 */
		isc_buffer_remaining(source, &r);
Michael Graff's avatar
Michael Graff committed
959
		if (r.length < 2 + 2 + 4 + 2)
Michael Graff's avatar
Michael Graff committed
960
961
962
963
			return (DNS_R_UNEXPECTEDEND);
		rdtype = isc_buffer_getuint16(source);
		rdclass = isc_buffer_getuint16(source);

964
965
966
967
968
969
970
971
972
973
974
		/*
		 * If there was no question section, we may not yet have
		 * established a class.  Do so now.
		 */
		if (msg->state == DNS_SECTION_ANY) {
			if (rdclass == 0 || rdclass == dns_rdataclass_any)
				return (DNS_R_FORMERR);
			msg->rdclass = rdclass;
			msg->state = DNS_SECTION_QUESTION;
		}
		   
Michael Graff's avatar
Michael Graff committed
975
		/*
976
977
		 * If this class is different than the one in the question
		 * section, bail.
Michael Graff's avatar
Michael Graff committed
978
		 */
Michael Graff's avatar
Michael Graff committed
979
		if (msg->opcode != dns_opcode_update
980
		    && rdtype != dns_rdatatype_tsig
Michael Graff's avatar
Michael Graff committed
981
		    && msg->rdclass != rdclass)
Michael Graff's avatar
Michael Graff committed
982
			return (DNS_R_FORMERR);
983
984
985
986
987
988
989
990

		/*
		 * If it is a tsig, verify that it is in the additional data
		 * section, and switch sections for the rest of this rdata.
		 */
		if (rdtype == dns_rdatatype_tsig) {
			if (sectionid != DNS_SECTION_ADDITIONAL)
				return (DNS_R_FORMERR);
991
992
			if (rdclass != dns_rdataclass_any)
				return (DNS_R_FORMERR);
993
			section = &msg->sections[DNS_SECTION_TSIG];
994
			msg->tsigstart = recstart;
995
		}
Michael Graff's avatar
Michael Graff committed
996
997
998
999
1000
		
		/*
		 * ... now get ttl and rdatalen, and check buffer.
		 */
		ttl = isc_buffer_getuint32(source);
For faster browsing, not all history is shown. View entire blame