message.c 49.4 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>
40
#include <dns/dnssec.h>
Michael Graff's avatar
Michael Graff committed
41

42
#define DNS_MESSAGE_OPCODE_MASK		0x7800U
Bob Halley's avatar
EDNS0    
Bob Halley committed
43
#define DNS_MESSAGE_OPCODE_SHIFT	11
Michael Graff's avatar
Michael Graff committed
44
45
#define DNS_MESSAGE_RCODE_MASK		0x000fU
#define DNS_MESSAGE_FLAG_MASK		0x8ff0U
Bob Halley's avatar
EDNS0    
Bob Halley committed
46
47
48
49
#define DNS_MESSAGE_EDNSRCODE_MASK	0xff000000U
#define DNS_MESSAGE_EDNSRCODE_SHIFT	24
#define DNS_MESSAGE_EDNSVERSION_MASK	0x00ff0000U
#define DNS_MESSAGE_EDNSVERSION_SHIFT	16
Michael Graff's avatar
Michael Graff committed
50
51
52
53
54
55
56
57
58

#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
59
 * XXXMLG These should come from a config setting.
Michael Graff's avatar
Michael Graff committed
60
 */
Michael Graff's avatar
Michael Graff committed
61
#define SCRATCHPAD_SIZE		512
62
63
64
65
#define NAME_COUNT		  8
#define RDATA_COUNT		  8
#define RDATALIST_COUNT		  8
#define RDATASET_COUNT		 RDATALIST_COUNT
Michael Graff's avatar
Michael Graff committed
66
67
68
69
70
71
72

/*
 * "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
73
	unsigned int			count;
Michael Graff's avatar
Michael Graff committed
74
75
76
	unsigned int			remaining;
	ISC_LINK(dns_msgblock_t)	link;
}; /* dynamically sized */
Michael Graff's avatar
Michael Graff committed
77

Michael Graff's avatar
Michael Graff committed
78
79
static inline dns_msgblock_t *
msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
80

Michael Graff's avatar
Michael Graff committed
81
#define msgblock_get(block, type) \
Michael Graff's avatar
Michael Graff committed
82
	((type *)msgblock_internalget(block, sizeof(type)))
Michael Graff's avatar
Michael Graff committed
83
84

static inline void *
Michael Graff's avatar
Michael Graff committed
85
86
87
msgblock_internalget(dns_msgblock_t *, unsigned int);

static inline void
Michael Graff's avatar
Michael Graff committed
88
msgblock_reset(dns_msgblock_t *);
Michael Graff's avatar
Michael Graff committed
89

Michael Graff's avatar
Michael Graff committed
90
91
static inline void
msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
Michael Graff's avatar
Michael Graff committed
92
93
94
95
96
97

/*
 * 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
98
99
msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
		  unsigned int count)
Michael Graff's avatar
Michael Graff committed
100
101
102
103
104
105
106
107
{
	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
108
		return (NULL);
Michael Graff's avatar
Michael Graff committed
109

Michael Graff's avatar
Michael Graff committed
110
	block->count = count;
Michael Graff's avatar
Michael Graff committed
111
112
113
114
115
116
117
118
119
120
121
122
	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
123
msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type)
Michael Graff's avatar
Michael Graff committed
124
125
126
{
	void *ptr;

Andreas Gustafsson's avatar
Andreas Gustafsson committed
127
	if (block == NULL || block->remaining == 0)
Michael Graff's avatar
Michael Graff committed
128
129
130
131
132
133
134
135
136
137
138
		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
139
static inline void
Michael Graff's avatar
Michael Graff committed
140
msgblock_reset(dns_msgblock_t *block)
Michael Graff's avatar
Michael Graff committed
141
{
Michael Graff's avatar
Michael Graff committed
142
	block->remaining = block->count;
Michael Graff's avatar
Michael Graff committed
143
144
}

Michael Graff's avatar
Michael Graff committed
145
146
147
148
/*
 * Release memory associated with a message block.
 */
static inline void
Michael Graff's avatar
Michael Graff committed
149
150
msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block,
	      unsigned int sizeof_type)
Michael Graff's avatar
Michael Graff committed
151
{
Michael Graff's avatar
Michael Graff committed
152
153
154
155
156
	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
157
}
Michael Graff's avatar
Michael Graff committed
158

Michael Graff's avatar
Michael Graff committed
159
160
161
162
163
164
/*
 * 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
165
newbuffer(dns_message_t *msg, unsigned int size)
Michael Graff's avatar
Michael Graff committed
166
167
{
	isc_result_t result;
168
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
169
170

	dynbuf = NULL;
171
	result = isc_buffer_allocate(msg->mctx, &dynbuf, size,
Michael Graff's avatar
Michael Graff committed
172
173
174
175
176
177
178
179
180
181
182
					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)
{
183
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
184
185

	dynbuf = ISC_LIST_TAIL(msg->scratchpad);
Michael Graff's avatar
Michael Graff committed
186
	INSIST(dynbuf != NULL);
Michael Graff's avatar
Michael Graff committed
187

188
	return (dynbuf);
Michael Graff's avatar
Michael Graff committed
189
190
191
192
193
}

static inline void
releaserdata(dns_message_t *msg, dns_rdata_t *rdata)
{
194
	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
Michael Graff's avatar
Michael Graff committed
195
196
197
198
199
200
201
202
}

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

203
204
205
	rdata = ISC_LIST_HEAD(msg->freerdata);
	if (rdata != NULL) {
		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
Michael Graff's avatar
Michael Graff committed
206
207
208
		return (rdata);
	}

Michael Graff's avatar
Michael Graff committed
209
	msgblock = ISC_LIST_TAIL(msg->rdatas);
Michael Graff's avatar
Michael Graff committed
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
	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)
{
228
	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
229
230
231
232
233
234
235
236
}

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

237
238
239
	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
	if (rdatalist != NULL) {
		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
240
241
242
		return (rdatalist);
	}

Michael Graff's avatar
Michael Graff committed
243
	msgblock = ISC_LIST_TAIL(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
	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);
}

Michael Graff's avatar
Michael Graff committed
260
static inline void
261
msginitheader(dns_message_t *m)
Michael Graff's avatar
Michael Graff committed
262
263
264
265
266
{
	m->id = 0;
	m->flags = 0;
	m->rcode = 0;
	m->opcode = 0;
Michael Graff's avatar
Michael Graff committed
267
	m->rdclass = 0;
268
}
Michael Graff's avatar
Michael Graff committed
269

270
271
272
273
274
275
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
276
		m->cursors[i] = NULL;
Michael Graff's avatar
Michael Graff committed
277
		m->counts[i] = 0;
Michael Graff's avatar
Michael Graff committed
278
	}
279
	m->opt = NULL;
Michael Graff's avatar
Michael Graff committed
280
	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
Michael Graff's avatar
Michael Graff committed
281
	m->reserved = 0;
282
	m->buffer = NULL;
283
	m->need_cctx_cleanup = 0;
Michael Graff's avatar
Michael Graff committed
284
285
}

286
287
288
289
290
291
static inline void
msginittsig(dns_message_t *m)
{
	m->tsigstatus = m->querytsigstatus = dns_rcode_noerror;
	m->tsig = m->querytsig = NULL;
	m->tsigkey = NULL;
292
	m->tsigctx = NULL;
293
294
295
296
	m->sigstart = -1;
	m->sig0key = NULL;
	m->sig0status = dns_rcode_noerror;
	m->query = NULL;
297
298
}

Michael Graff's avatar
Michael Graff committed
299
/*
300
301
 * Init elements to default state.  Used both when allocating a new element
 * and when resetting one.
Michael Graff's avatar
Michael Graff committed
302
 */
303
304
static inline void
msginit(dns_message_t *m)
Michael Graff's avatar
Michael Graff committed
305
{
306
307
	msginitheader(m);
	msginitprivate(m);
308
	msginittsig(m);
Bob Halley's avatar
Bob Halley committed
309
310
	m->header_ok = 0;
	m->question_ok = 0;
311
	m->tcp_continuation = 0;
312
313
	m->response_needs_sig0 = 0;
	m->verified_sig0 = 0;
314
315
316
317
}

static inline void
msgresetnames(dns_message_t *msg, unsigned int first_section) {
Michael Graff's avatar
Michael Graff committed
318
	unsigned int i;
319
320
	dns_name_t *name, *next_name;
	dns_rdataset_t *rds, *next_rds;
Michael Graff's avatar
Michael Graff committed
321
322
323
324

	/*
	 * Clean up name lists by calling the rdataset disassociate function.
	 */
325
	for (i = first_section; i < DNS_SECTION_MAX; i++) {
Michael Graff's avatar
Michael Graff committed
326
327
328
329
330
331
332
333
334
335
		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);

336
				INSIST(dns_rdataset_isassociated(rds));
Michael Graff's avatar
Michael Graff committed
337
				dns_rdataset_disassociate(rds);
338
				isc_mempool_put(msg->rdspool, rds);
Michael Graff's avatar
Michael Graff committed
339
340
				rds = next_rds;
			}
341
			isc_mempool_put(msg->namepool, name);
342
			name = next_name;
Michael Graff's avatar
Michael Graff committed
343
344
		}
	}
345
346
347
348
349
350
351
352
353
354
}

/*
 * 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;
355
	isc_buffer_t *dynbuf, *next_dynbuf;
356
357
358
359
	dns_rdata_t *rdata;
	dns_rdatalist_t *rdatalist;

	msgresetnames(msg, 0);
Michael Graff's avatar
Michael Graff committed
360

361
	if (msg->opt != NULL) {
362
		INSIST(dns_rdataset_isassociated(msg->opt));
Bob Halley's avatar
EDNS0    
Bob Halley committed
363
		dns_rdataset_disassociate(msg->opt);
364
365
366
		isc_mempool_put(msg->rdspool, msg->opt);
		msg->opt = NULL;
	}
Bob Halley's avatar
EDNS0    
Bob Halley committed
367

Michael Graff's avatar
Michael Graff committed
368
369
370
371
	/*
	 * Clean up linked lists.
	 */

372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
	/*
	 * 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.
	 */
	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);
	}

Michael Graff's avatar
Michael Graff committed
388
389
	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
	INSIST(dynbuf != NULL);
Michael Graff's avatar
Michael Graff committed
390
	if (!everything) {
391
		isc_buffer_clear(dynbuf);
Michael Graff's avatar
Michael Graff committed
392
393
394
395
396
		dynbuf = ISC_LIST_NEXT(dynbuf, link);
	}
	while (dynbuf != NULL) {
		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
397
		isc_buffer_free(&dynbuf);
Michael Graff's avatar
Michael Graff committed
398
399
400
401
402
		dynbuf = next_dynbuf;
	}

	msgblock = ISC_LIST_HEAD(msg->rdatas);
	INSIST(msgblock != NULL);
Michael Graff's avatar
Michael Graff committed
403
404
	if (!everything) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
405
406
407
408
409
		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
410
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
Michael Graff's avatar
Michael Graff committed
411
412
413
		msgblock = next_msgblock;
	}

Michael Graff's avatar
Michael Graff committed
414
	/*
Michael Graff's avatar
Michael Graff committed
415
	 * rdatalists could be empty.
Michael Graff's avatar
Michael Graff committed
416
417
418
	 */

	msgblock = ISC_LIST_HEAD(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
419
420
	if (!everything && msgblock != NULL) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
421
422
423
424
425
		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
426
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
Michael Graff's avatar
Michael Graff committed
427
		msgblock = next_msgblock;
Michael Graff's avatar
Michael Graff committed
428
429
	}

430
	if (msg->need_cctx_cleanup == 1)
Michael Graff's avatar
Michael Graff committed
431
432
		dns_compress_invalidate(&msg->cctx);

433
434
	if (msg->tsig != NULL) {
		dns_rdata_freestruct(msg->tsig);
Bob Halley's avatar
EDNS0    
Bob Halley committed
435
436
		isc_mem_put(msg->mctx, msg->tsig,
			    sizeof(dns_rdata_any_tsig_t));
437
		msg->tsig = NULL;
438
439
440
441
442
443
	}

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

447
	if (msg->tsigkey != NULL) {
448
		dns_tsigkey_free(&msg->tsigkey);
449
450
451
452
453
454
455
456
		msg->tsigkey = NULL;
	}

	if (msg->query != NULL) {
		isc_mem_put(msg->mctx, msg->query->base, msg->query->length);
		isc_mem_put(msg->mctx, msg->query, sizeof(isc_region_t));
		msg->query = NULL;
	}
457

458
459
460
461
462
463
	/*
	 * cleanup the buffer cleanup list
	 */
	dynbuf = ISC_LIST_HEAD(msg->cleanup);
	while (dynbuf != NULL) {
		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
464
		ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
465
466
467
468
		isc_buffer_free(&dynbuf);
		dynbuf = next_dynbuf;
	}

Michael Graff's avatar
Michael Graff committed
469
470
471
	/*
	 * Set other bits to normal default values.
	 */
Michael Graff's avatar
Michael Graff committed
472
473
	if (!everything)
		msginit(msg);
Michael Graff's avatar
Michael Graff committed
474
475
476
}

dns_result_t
477
dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
Michael Graff's avatar
Michael Graff committed
478
479
{
	dns_message_t *m;
480
	isc_result_t result;
Michael Graff's avatar
Michael Graff committed
481
	dns_msgblock_t *msgblock;
482
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
483
484
485
	unsigned int i;

	REQUIRE(mctx != NULL);
486
487
	REQUIRE(msgp != NULL);
	REQUIRE(*msgp == NULL);
Michael Graff's avatar
Michael Graff committed
488
489
	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
		|| intent == DNS_MESSAGE_INTENTRENDER);
Michael Graff's avatar
Michael Graff committed
490
491
492
493
494

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

495
496
497
498
499
	/*
	 * No allocations until further notice.  Just initialize all lists
	 * and other members that are freed in the cleanup phase here.
	 */

500
	m->magic = DNS_MESSAGE_MAGIC;
Michael Graff's avatar
Michael Graff committed
501
502
	m->from_to_wire = intent;
	msginit(m);
503

Michael Graff's avatar
Michael Graff committed
504
505
506
	for (i = 0 ; i < DNS_SECTION_MAX ; i++)
		ISC_LIST_INIT(m->sections[i]);
	m->mctx = mctx;
507

Michael Graff's avatar
Michael Graff committed
508
	ISC_LIST_INIT(m->scratchpad);
509
510
	ISC_LIST_INIT(m->cleanup);
	m->namepool = NULL;
511
	m->rdspool = NULL;
Michael Graff's avatar
Michael Graff committed
512
513
	ISC_LIST_INIT(m->rdatas);
	ISC_LIST_INIT(m->rdatalists);
514
515
	ISC_LIST_INIT(m->freerdata);
	ISC_LIST_INIT(m->freerdatalist);
Michael Graff's avatar
Michael Graff committed
516

517
518
519
520
521
522
523
524
525
	/*
	 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
	 */

	result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
	if (result != ISC_R_SUCCESS)
		goto cleanup;
	isc_mempool_setfreemax(m->namepool, NAME_COUNT);
	isc_mempool_setfillcount(m->namepool, NAME_COUNT);
Michael Graff's avatar
Michael Graff committed
526
	isc_mempool_setname(m->namepool, "msg:names");
527

528
529
530
531
532
533
	result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
				    &m->rdspool);
	if (result != ISC_R_SUCCESS)
		goto cleanup;
	isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
	isc_mempool_setfillcount(m->rdspool, NAME_COUNT);
Michael Graff's avatar
Michael Graff committed
534
	isc_mempool_setname(m->rdspool, "msg:rdataset");
535

Michael Graff's avatar
Michael Graff committed
536
	dynbuf = NULL;
537
538
539
540
	result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE,
				     ISC_BUFFERTYPE_BINARY);
	if (result != ISC_R_SUCCESS)
		goto cleanup;
Michael Graff's avatar
Michael Graff committed
541
542
543
544
545
	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);

	msgblock = msgblock_allocate(mctx, sizeof(dns_rdata_t),
				     RDATA_COUNT);
	if (msgblock == NULL)
546
		goto cleanup;
Michael Graff's avatar
Michael Graff committed
547
548
	ISC_LIST_APPEND(m->rdatas, msgblock, link);

Michael Graff's avatar
Michael Graff committed
549
	if (intent == DNS_MESSAGE_INTENTPARSE) {
Michael Graff's avatar
Michael Graff committed
550
551
552
		msgblock = msgblock_allocate(mctx, sizeof(dns_rdatalist_t),
					     RDATALIST_COUNT);
		if (msgblock == NULL)
553
			goto cleanup;
Michael Graff's avatar
Michael Graff committed
554
555
556
		ISC_LIST_APPEND(m->rdatalists, msgblock, link);
	}

557
	*msgp = m;
Michael Graff's avatar
Michael Graff committed
558
559
560
561
562
	return (DNS_R_SUCCESS);

	/*
	 * Cleanup for error returns.
	 */
563
 cleanup:
Michael Graff's avatar
Michael Graff committed
564
	msgblock = ISC_LIST_HEAD(m->rdatas);
565
566
	if (msgblock != NULL)
		msgblock_free(mctx, msgblock, sizeof(dns_rdata_t));
Michael Graff's avatar
Michael Graff committed
567
	dynbuf = ISC_LIST_HEAD(m->scratchpad);
568
569
570
571
	if (dynbuf != NULL)
		isc_buffer_free(&dynbuf);
	if (m->namepool != NULL)
		isc_mempool_destroy(&m->namepool);
572
573
	if (m->rdspool != NULL)
		isc_mempool_destroy(&m->rdspool);
Michael Graff's avatar
Michael Graff committed
574
575
576
577
578
579
580
	m->magic = 0;
	isc_mem_put(mctx, m, sizeof(dns_message_t));

	return (DNS_R_NOMEMORY);
}

void
581
dns_message_reset(dns_message_t *msg, unsigned int intent)
Michael Graff's avatar
Michael Graff committed
582
{
583
584
585
586
587
	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
588
589
590
591
	msgreset(msg, ISC_FALSE);
}

void
592
dns_message_destroy(dns_message_t **msgp)
Michael Graff's avatar
Michael Graff committed
593
594
595
{
	dns_message_t *msg;

596
	REQUIRE(msgp != NULL);
597
	REQUIRE(DNS_MESSAGE_VALID(*msgp));
Michael Graff's avatar
Michael Graff committed
598

599
600
	msg = *msgp;
	*msgp = NULL;
Michael Graff's avatar
Michael Graff committed
601
602

	msgreset(msg, ISC_TRUE);
603
	isc_mempool_destroy(&msg->namepool);
604
	isc_mempool_destroy(&msg->rdspool);
Michael Graff's avatar
Michael Graff committed
605
606
607
608
	msg->magic = 0;
	isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
}

Michael Graff's avatar
Michael Graff committed
609
static dns_result_t
610
611
findname(dns_name_t **foundname, dns_name_t *target, unsigned int attributes,
	 dns_namelist_t *section)
Michael Graff's avatar
Michael Graff committed
612
613
614
615
616
617
{
	dns_name_t *curr;

	for (curr = ISC_LIST_TAIL(*section) ;
	     curr != NULL ;
	     curr = ISC_LIST_PREV(curr, link)) {
618
619
		if (dns_name_equal(curr, target) &&
		    (curr->attributes & attributes) == attributes) {
Michael Graff's avatar
Michael Graff committed
620
621
622
623
624
625
626
627
628
			if (foundname != NULL)
				*foundname = curr;
			return (DNS_R_SUCCESS);
		}
	}

	return (DNS_R_NOTFOUND);
}

629
630
631
dns_result_t
dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
		     dns_rdatatype_t covers, dns_rdataset_t **rdataset)
Michael Graff's avatar
Michael Graff committed
632
633
634
{
	dns_rdataset_t *curr;

635
636
637
638
	if (rdataset != NULL) {
		REQUIRE(*rdataset == NULL);
	}

Michael Graff's avatar
Michael Graff committed
639
640
641
	for (curr = ISC_LIST_TAIL(name->list) ;
	     curr != NULL ;
	     curr = ISC_LIST_PREV(curr, link)) {
Bob Halley's avatar
Bob Halley committed
642
		if (curr->type == type && curr->covers == covers) {
Michael Graff's avatar
Michael Graff committed
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
			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
665
666
667
668
	/*
	 * First try:  use current buffer.
	 * Second try:  allocate a new buffer and use that.
	 */
Michael Graff's avatar
Michael Graff committed
669
670
	tries = 0;
	while (tries < 2) {
671
		dns_name_init(name, NULL);
Michael Graff's avatar
Michael Graff committed
672
673
674
675
676
677
		result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
					   scratch);

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

678
			result = newbuffer(msg, SCRATCHPAD_SIZE);
Michael Graff's avatar
Michael Graff committed
679
680
681
682
683
684
685
686
687
			if (result != DNS_R_SUCCESS)
				return (result);

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

Michael Graff's avatar
Michael Graff committed
688
689
	INSIST(0);  /* Cannot get here... */
	return (DNS_R_UNEXPECTED);
Michael Graff's avatar
Michael Graff committed
690
691
}

692
693
694
695
696
697
698
699
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;
700
	unsigned int trysize;
701

702
703
704
705
706
707
708
709
	/*
	 * 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
710
		rdata->data = (unsigned char *)""; 
711
		rdata->length = 0;
Bob Halley's avatar
Bob Halley committed
712
		rdata->rdclass = rdclass;
713
714
715
716
		rdata->type = rdtype;
		return DNS_R_SUCCESS;
	}
	    
717
718
719
720
721
	scratch = currentbuffer(msg);

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

Michael Graff's avatar
Michael Graff committed
722
723
	/*
	 * First try:  use current buffer.
724
725
726
727
	 * 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
728
	 */
729
	tries = 0;
730
731
	trysize = 0;
	for (;;) {
732
733
734
735
736
		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
					    source, dctx, ISC_FALSE,
					    scratch);

		if (result == DNS_R_NOSPACE) {
737
738
739
740
741
742
743
744
745
746
747
			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;
			}
748
			tries++;
749
			result = newbuffer(msg, trysize);
750
751
752
753
754
755
756
757
758
			if (result != DNS_R_SUCCESS)
				return (result);

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

Michael Graff's avatar
Michael Graff committed
760
761
762
763
764
765
766
767
768
769
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
770
771
772
	dns_rdatatype_t rdtype;
	dns_rdataclass_t rdclass;
	dns_namelist_t *section;
773
	isc_boolean_t free_name;
Michael Graff's avatar
Michael Graff committed
774

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

777
778
779
780
	name = NULL;
	rdataset = NULL;
	rdatalist = NULL;

Michael Graff's avatar
Michael Graff committed
781
	for (count = 0 ; count < msg->counts[DNS_SECTION_QUESTION] ; count++) {
782
		name = isc_mempool_get(msg->namepool);
Michael Graff's avatar
Michael Graff committed
783
784
		if (name == NULL)
			return (DNS_R_NOMEMORY);
785
		free_name = ISC_TRUE;
Michael Graff's avatar
Michael Graff committed
786
787
788
789

		/*
		 * Parse the name out of this packet.
		 */
790
791
		isc_buffer_remaining(source, &r);
		isc_buffer_setactive(source, r.length);
Michael Graff's avatar
Michael Graff committed
792
793
		result = getname(name, source, msg, dctx);
		if (result != DNS_R_SUCCESS)
794
			goto cleanup;
Michael Graff's avatar
Michael Graff committed
795
796
797
798
799
800
801

		/*
		 * 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.
		 */
802
		result = findname(&name2, name, 0, section);
Michael Graff's avatar
Michael Graff committed
803
804

		/*
805
806
807
808
		 * 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
809
810
811
812
		 * 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
813
		 */
814
815
816
		if (result != DNS_R_SUCCESS) {
			if (ISC_LIST_EMPTY(*section)) {
				ISC_LIST_APPEND(*section, name, link);
817
				free_name = ISC_FALSE;
818
			} else {
819
				result = DNS_R_FORMERR;
820
				goto cleanup;
821
822
			}
		} else {
823
			isc_mempool_put(msg->namepool, name);
824
			name = name2;
825
			name2 = NULL;
826
			free_name = ISC_FALSE;
827
		}
Michael Graff's avatar
Michael Graff committed
828
829
830
831

		/*
		 * Get type and class.
		 */
Michael Graff's avatar
Michael Graff committed
832
		isc_buffer_remaining(source, &r);
833
834
		if (r.length < 4) {
			result = DNS_R_UNEXPECTEDEND;
835
			goto cleanup;
836
		}
Michael Graff's avatar
Michael Graff committed
837
838
		rdtype = isc_buffer_getuint16(source);
		rdclass = isc_buffer_getuint16(source);
Michael Graff's avatar
Michael Graff committed
839
840

		/*
841
		 * If this class is different than the one we already read,
Michael Graff's avatar
Michael Graff committed
842
		 * this is an error.
Michael Graff's avatar
Michael Graff committed
843
		 */
Michael Graff's avatar
Michael Graff committed
844
845
846
		if (msg->state == DNS_SECTION_ANY) {
			msg->state = DNS_SECTION_QUESTION;
			msg->rdclass = rdclass;
847
			msg->state = DNS_SECTION_QUESTION;
848
849
		} else if (msg->rdclass != rdclass) {
			result = DNS_R_FORMERR;
850
			goto cleanup;
851
		}
Michael Graff's avatar
Michael Graff committed
852
		
Michael Graff's avatar
Michael Graff committed
853
		/*
Michael Graff's avatar
Michael Graff committed
854
		 * Can't ask the same question twice.
Michael Graff's avatar
Michael Graff committed
855
		 */
856
		result = dns_message_findtype(name, rdtype, 0, NULL);
857
858
		if (result == DNS_R_SUCCESS) {
			result = DNS_R_FORMERR;
859
			goto cleanup;
860
		}
Michael Graff's avatar
Michael Graff committed
861
862
863
864

		/*
		 * Allocate a new rdatalist.
		 */
Michael Graff's avatar
Michael Graff committed
865
		rdatalist = newrdatalist(msg);
866
867
		if (rdatalist == NULL) {
			result = DNS_R_NOMEMORY;
868
			goto cleanup;
869
		}
870
		rdataset =  isc_mempool_get(msg->rdspool);
871
872
		if (rdataset == NULL) {
			result = DNS_R_NOMEMORY;
873
			goto cleanup;
874
		}
Michael Graff's avatar
Michael Graff committed
875
876
877
878
879

		/*
		 * Convert rdatalist to rdataset, and attach the latter to
		 * the name.
		 */
Michael Graff's avatar
Michael Graff committed
880
881
882
883
884
		rdatalist->type = rdtype;
		rdatalist->rdclass = rdclass;
		rdatalist->ttl = 0;
		ISC_LIST_INIT(rdatalist->rdata);

885
		dns_rdataset_init(rdataset);
Michael Graff's avatar
Michael Graff committed
886
887
		result = dns_rdatalist_tordataset(rdatalist, rdataset);
		if (result != DNS_R_SUCCESS)
888
			goto cleanup;
889

890
		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
Michael Graff's avatar
Michael Graff committed
891
892

		ISC_LIST_APPEND(name->list, rdataset, link);
Michael Graff's avatar
Michael Graff committed
893
	}
894

Michael Graff's avatar
Michael Graff committed
895
	return (DNS_R_SUCCESS);
896

897
 cleanup:
898
899
	if (rdataset != NULL) {
		INSIST(!dns_rdataset_isassociated(rdataset));
900
		isc_mempool_put(msg->rdspool, rdataset);
901
	}
902
903
904
905
906
907
#if 0
	if (rdatalist != NULL)
		isc_mempool_put(msg->rdlpool, rdatalist);
#endif
	if (free_name)
		isc_mempool_put(msg->namepool, name);
908
909

	return (result);
Michael Graff's avatar
Michael Graff committed
910
911
912
913
}

static dns_result_t
getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
914
	   dns_section_t sectionid, isc_boolean_t preserve_order)
Michael Graff's avatar
Michael Graff committed
915
{
Michael Graff's avatar
Michael Graff committed
916
	isc_region_t r;
917
	unsigned int count, rdatalen, attributes;
Michael Graff's avatar
Michael Graff committed
918
919
920
921
922
	dns_name_t *name;
	dns_name_t *name2;
	dns_rdataset_t *rdataset;
	dns_rdatalist_t *rdatalist;
	dns_result_t result;
Bob Halley's avatar
Bob Halley committed
923
	dns_rdatatype_t rdtype, covers;
Michael Graff's avatar
Michael Graff committed
924
	dns_rdataclass_t rdclass;
925
	dns_rdata_t *rdata;
Michael Graff's avatar
Michael Graff committed
926
927
928
929
	dns_ttl_t ttl;
	dns_namelist_t *section;

	for (count = 0 ; count < msg->counts[sectionid] ; count++) {
930
		int recstart = source->current;
931
		isc_boolean_t skip_name_search, skip_type_search;
932
933
		section = &msg->sections[sectionid];

934
935
		skip_name_search = ISC_FALSE;
		skip_type_search = ISC_FALSE;
936
		name = isc_mempool_get(msg->namepool);
Michael Graff's avatar
Michael Graff committed
937
938
939
940
941
942
		if (name == NULL)
			return (DNS_R_NOMEMORY);

		/*
		 * Parse the name out of this packet.
		 */
943
944
		isc_buffer_remaining(source, &r);
		isc_buffer_setactive(source, r.length);
Michael Graff's avatar
Michael Graff committed
945
946
947
948
949
950
951
		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
952
		 * later.)
Michael Graff's avatar
Michael Graff committed
953
954
		 */
		isc_buffer_remaining(source, &r);
Michael Graff's avatar
Michael Graff committed
955
		if (r.length < 2 + 2 + 4 + 2)
Michael Graff's avatar
Michael Graff committed
956
957
958
959
			return (DNS_R_UNEXPECTEDEND);
		rdtype = isc_buffer_getuint16(source);
		rdclass = isc_buffer_getuint16(source);

960
961
962
963
964
965
966
967
968
969
970
		/*
		 * 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
971
		/*
972
973
		 * If this class is different than the one in the question
		 * section, bail.
Michael Graff's avatar
Michael Graff committed
974
		 */
Michael Graff's avatar
Michael Graff committed
975
		if (msg->opcode != dns_opcode_update
976
		    && rdtype != dns_rdatatype_tsig
Bob Halley's avatar
EDNS0    
Bob Halley committed
977
		    && rdtype != dns_rdatatype_opt
Brian Wellington's avatar
Brian Wellington committed
978
		    && rdtype != dns_rdatatype_key /* XXX in a TKEY query */
979
		    && rdtype != dns_rdatatype_sig /* XXX SIG(0) */
Michael Graff's avatar
Michael Graff committed
980
		    && msg->rdclass != rdclass)
Michael Graff's avatar
Michael Graff committed
981
			return (DNS_R_FORMERR);
982
983

		/*
Brian Wellington's avatar
Brian Wellington committed
984
		 * Special type handling for TSIG, OPT, and TKEY.
985
986
		 */
		if (rdtype == dns_rdatatype_tsig) {
Bob Halley's avatar
Bob Halley committed
987
988
989
990
991
			/*
			 * If it is a tsig, verify that it is in the
			 * additional data section, and switch sections for
			 * the rest of this rdata.
			 */
992
993
			if (sectionid != DNS_SECTION_ADDITIONAL)
				return (DNS_R_FORMERR);
994
995
			if (rdclass != dns_rdataclass_any)
				return (DNS_R_FORMERR);
996
			section = &msg->sections[DNS_SECTION_TSIG];
997
			msg->sigstart = recstart;
998
999
			skip_name_search = ISC_TRUE;
			skip_type_search = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
1000
		} else if (rdtype == dns_rdatatype_opt) {
For faster browsing, not all history is shown. View entire blame