message.c 72.7 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
/*
Bob Halley's avatar
Bob Halley committed
2
 * Copyright (C) 1999, 2000  Internet Software Consortium.
3
 *
Michael Graff's avatar
Michael Graff committed
4
5
6
 * 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.
7
 *
8
9
10
11
12
13
14
15
 * 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.
Michael Graff's avatar
Michael Graff committed
16
17
 */

18
/* $Id: message.c,v 1.159 2000/11/22 23:09:58 gson Exp $ */
David Lawrence's avatar
David Lawrence committed
19

Michael Graff's avatar
Michael Graff committed
20
21
22
23
24
25
/***
 *** Imports
 ***/

#include <config.h>

26
#include <isc/mem.h>
27
#include <isc/string.h>		/* Required for HP/UX (and others?) */
Bob Halley's avatar
Bob Halley committed
28
#include <isc/util.h>
29
#include <isc/buffer.h>
Michael Graff's avatar
Michael Graff committed
30

31
32
#include <dns/dnssec.h>
#include <dns/keyvalues.h>
33
#include <dns/log.h>
Michael Graff's avatar
Michael Graff committed
34
#include <dns/message.h>
35
#include <dns/opt.h>
Michael Graff's avatar
Michael Graff committed
36
37
#include <dns/rdata.h>
#include <dns/rdatalist.h>
38
#include <dns/rdataset.h>
39
#include <dns/rdatastruct.h>
40
#include <dns/result.h>
41
#include <dns/tsig.h>
Brian Wellington's avatar
Brian Wellington committed
42
#include <dns/view.h>
Michael Graff's avatar
Michael Graff committed
43

44
#define DNS_MESSAGE_OPCODE_MASK		0x7800U
Bob Halley's avatar
EDNS0    
Bob Halley committed
45
#define DNS_MESSAGE_OPCODE_SHIFT	11
Michael Graff's avatar
Michael Graff committed
46
47
#define DNS_MESSAGE_RCODE_MASK		0x000fU
#define DNS_MESSAGE_FLAG_MASK		0x8ff0U
Bob Halley's avatar
EDNS0    
Bob Halley committed
48
49
50
51
#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
52
53
54
55
56

#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))
57
58
59
60
#define ADD_STRING(b, s)        {if (strlen(s) >= \
                                   isc_buffer_availablelength(b)) \
                                       return(ISC_R_NOSPACE); else \
                                       isc_buffer_putstr(b, s);}
61
62
#define VALID_PSEUDOSECTION(s)	(((s) >= DNS_PSEUDOSECTION_ANY) \
				 && ((s) < DNS_PSEUDOSECTION_MAX))
Michael Graff's avatar
Michael Graff committed
63
64
65
66

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

75
76
77
78
/*
 * Text representation of the different items, for message_totext
 * functions.
 */
David Lawrence's avatar
David Lawrence committed
79
static const char *sectiontext[] = {
80
81
82
83
84
85
	"QUESTION",
	"ANSWER",
	"AUTHORITY",
	"ADDITIONAL"
};

86
87
88
89
90
91
92
static const char *updsectiontext[] = {
	"ZONE",
	"PREREQUISITE",
	"UPDATE",
	"ADDITIONAL"
};

David Lawrence's avatar
David Lawrence committed
93
static const char *opcodetext[] = {
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
	"QUERY",
	"IQUERY",
	"STATUS",
	"RESERVED3",
	"NOTIFY",
	"UPDATE",
	"RESERVED6",
	"RESERVED7",
	"RESERVED8",
	"RESERVED9",
	"RESERVED10",
	"RESERVED11",
	"RESERVED12",
	"RESERVED13",
	"RESERVED14",
	"RESERVED15"
};

David Lawrence's avatar
David Lawrence committed
112
static const char *rcodetext[] = {
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
	"NOERROR",
	"FORMERR",
	"SERVFAIL",
	"NXDOMAIN",
	"NOTIMPL",
	"REFUSED",
	"YXDOMAIN",
	"YXRRSET",
	"NXRRSET",
	"NOTAUTH",
	"NOTZONE",
	"RESERVED11",
	"RESERVED12",
	"RESERVED13",
	"RESERVED14",
	"RESERVED15",
	"BADVERS"
};


Michael Graff's avatar
Michael Graff committed
133
134
135
136
137
138
/*
 * "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
139
	unsigned int			count;
Michael Graff's avatar
Michael Graff committed
140
141
142
	unsigned int			remaining;
	ISC_LINK(dns_msgblock_t)	link;
}; /* dynamically sized */
Michael Graff's avatar
Michael Graff committed
143

Michael Graff's avatar
Michael Graff committed
144
145
static inline dns_msgblock_t *
msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
146

Michael Graff's avatar
Michael Graff committed
147
#define msgblock_get(block, type) \
Michael Graff's avatar
Michael Graff committed
148
	((type *)msgblock_internalget(block, sizeof(type)))
Michael Graff's avatar
Michael Graff committed
149
150

static inline void *
Michael Graff's avatar
Michael Graff committed
151
152
153
msgblock_internalget(dns_msgblock_t *, unsigned int);

static inline void
Michael Graff's avatar
Michael Graff committed
154
msgblock_reset(dns_msgblock_t *);
Michael Graff's avatar
Michael Graff committed
155

Michael Graff's avatar
Michael Graff committed
156
157
static inline void
msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
Michael Graff's avatar
Michael Graff committed
158
159
160
161
162
163

/*
 * 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
164
165
msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
		  unsigned int count)
Michael Graff's avatar
Michael Graff committed
166
167
168
169
170
171
172
173
{
	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
174
		return (NULL);
Michael Graff's avatar
Michael Graff committed
175

Michael Graff's avatar
Michael Graff committed
176
	block->count = count;
Michael Graff's avatar
Michael Graff committed
177
178
179
180
181
182
183
184
185
186
187
188
	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 *
189
msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
Michael Graff's avatar
Michael Graff committed
190
191
	void *ptr;

Andreas Gustafsson's avatar
Andreas Gustafsson committed
192
	if (block == NULL || block->remaining == 0)
Michael Graff's avatar
Michael Graff committed
193
194
195
196
197
198
199
200
201
202
203
		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
204
static inline void
205
msgblock_reset(dns_msgblock_t *block) {
Michael Graff's avatar
Michael Graff committed
206
	block->remaining = block->count;
Michael Graff's avatar
Michael Graff committed
207
208
}

Michael Graff's avatar
Michael Graff committed
209
210
211
212
/*
 * Release memory associated with a message block.
 */
static inline void
213
msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
Michael Graff's avatar
Michael Graff committed
214
{
Michael Graff's avatar
Michael Graff committed
215
216
217
218
219
	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
220
}
Michael Graff's avatar
Michael Graff committed
221

Michael Graff's avatar
Michael Graff committed
222
223
224
225
226
/*
 * 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)
 */
227
static inline isc_result_t
228
newbuffer(dns_message_t *msg, unsigned int size) {
Michael Graff's avatar
Michael Graff committed
229
	isc_result_t result;
230
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
231
232

	dynbuf = NULL;
233
	result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
Michael Graff's avatar
Michael Graff committed
234
	if (result != ISC_R_SUCCESS)
235
		return (ISC_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
236
237

	ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
238
	return (ISC_R_SUCCESS);
Michael Graff's avatar
Michael Graff committed
239
240
241
}

static inline isc_buffer_t *
242
currentbuffer(dns_message_t *msg) {
243
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
244
245

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

248
	return (dynbuf);
Michael Graff's avatar
Michael Graff committed
249
250
251
}

static inline void
252
releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
253
	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
Michael Graff's avatar
Michael Graff committed
254
255
256
}

static inline dns_rdata_t *
257
newrdata(dns_message_t *msg) {
Michael Graff's avatar
Michael Graff committed
258
259
260
	dns_msgblock_t *msgblock;
	dns_rdata_t *rdata;

261
262
263
	rdata = ISC_LIST_HEAD(msg->freerdata);
	if (rdata != NULL) {
		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
Michael Graff's avatar
Michael Graff committed
264
265
266
		return (rdata);
	}

Michael Graff's avatar
Michael Graff committed
267
	msgblock = ISC_LIST_TAIL(msg->rdatas);
Michael Graff's avatar
Michael Graff committed
268
269
270
271
272
273
274
275
276
277
278
279
	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);
	}

280
	dns_rdata_init(rdata);
Michael Graff's avatar
Michael Graff committed
281
282
283
284
	return (rdata);
}

static inline void
285
releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
286
	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
287
288
289
}

static inline dns_rdatalist_t *
290
newrdatalist(dns_message_t *msg) {
Michael Graff's avatar
Michael Graff committed
291
292
293
	dns_msgblock_t *msgblock;
	dns_rdatalist_t *rdatalist;

294
295
296
	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
	if (rdatalist != NULL) {
		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
297
298
299
		return (rdatalist);
	}

Michael Graff's avatar
Michael Graff committed
300
	msgblock = ISC_LIST_TAIL(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
	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
317
static inline void
318
msginitheader(dns_message_t *m) {
Michael Graff's avatar
Michael Graff committed
319
320
321
322
	m->id = 0;
	m->flags = 0;
	m->rcode = 0;
	m->opcode = 0;
Michael Graff's avatar
Michael Graff committed
323
	m->rdclass = 0;
324
}
Michael Graff's avatar
Michael Graff committed
325

326
static inline void
327
msginitprivate(dns_message_t *m) {
328
329
330
	unsigned int i;

	for (i = 0; i < DNS_SECTION_MAX; i++) {
Michael Graff's avatar
Michael Graff committed
331
		m->cursors[i] = NULL;
Michael Graff's avatar
Michael Graff committed
332
		m->counts[i] = 0;
Michael Graff's avatar
Michael Graff committed
333
	}
334
	m->opt = NULL;
335
	m->sig0 = NULL;
336
	m->sig0name = NULL;
337
	m->tsig = NULL;
338
	m->tsigname = NULL;
Michael Graff's avatar
Michael Graff committed
339
	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
340
	m->opt_reserved = 0;
341
	m->sig_reserved = 0;
Michael Graff's avatar
Michael Graff committed
342
	m->reserved = 0;
343
	m->buffer = NULL;
344
	m->need_cctx_cleanup = 0;
Michael Graff's avatar
Michael Graff committed
345
346
}

347
static inline void
348
msginittsig(dns_message_t *m) {
349
350
	m->tsigstatus = dns_rcode_noerror;
	m->querytsigstatus = dns_rcode_noerror;
351
	m->tsigkey = NULL;
352
	m->tsigctx = NULL;
353
354
355
356
	m->sigstart = -1;
	m->sig0key = NULL;
	m->sig0status = dns_rcode_noerror;
	m->query = NULL;
Brian Wellington's avatar
Brian Wellington committed
357
	m->saved = NULL;
358
	m->querytsig = NULL;
359
360
}

Michael Graff's avatar
Michael Graff committed
361
/*
362
363
 * Init elements to default state.  Used both when allocating a new element
 * and when resetting one.
Michael Graff's avatar
Michael Graff committed
364
 */
365
static inline void
366
msginit(dns_message_t *m) {
367
368
	msginitheader(m);
	msginitprivate(m);
369
	msginittsig(m);
Bob Halley's avatar
Bob Halley committed
370
371
	m->header_ok = 0;
	m->question_ok = 0;
372
	m->tcp_continuation = 0;
373
374
	m->verified_sig = 0;
	m->verify_attempted = 0;
375
376
	m->order = NULL;
	m->order_arg = NULL;
377
378
379
380
}

static inline void
msgresetnames(dns_message_t *msg, unsigned int first_section) {
Michael Graff's avatar
Michael Graff committed
381
	unsigned int i;
382
383
	dns_name_t *name, *next_name;
	dns_rdataset_t *rds, *next_rds;
Michael Graff's avatar
Michael Graff committed
384
385
386
387

	/*
	 * Clean up name lists by calling the rdataset disassociate function.
	 */
388
	for (i = first_section; i < DNS_SECTION_MAX; i++) {
Michael Graff's avatar
Michael Graff committed
389
390
391
392
393
394
395
396
397
398
		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);

399
				INSIST(dns_rdataset_isassociated(rds));
Michael Graff's avatar
Michael Graff committed
400
				dns_rdataset_disassociate(rds);
401
				isc_mempool_put(msg->rdspool, rds);
Michael Graff's avatar
Michael Graff committed
402
403
				rds = next_rds;
			}
404
405
			if (dns_name_dynamic(name))
				dns_name_free(name, msg->mctx);
406
			isc_mempool_put(msg->namepool, name);
407
			name = next_name;
Michael Graff's avatar
Michael Graff committed
408
409
		}
	}
410
411
}

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
static void
msgresetopt(dns_message_t *msg)
{
	if (msg->opt != NULL) {
		if (msg->opt_reserved > 0) {
			dns_message_renderrelease(msg, msg->opt_reserved);
			msg->opt_reserved = 0;
		}
		INSIST(dns_rdataset_isassociated(msg->opt));
		dns_rdataset_disassociate(msg->opt);
		isc_mempool_put(msg->rdspool, msg->opt);
		msg->opt = NULL;
	}
}

427
static void
428
429
430
431
432
msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
	if (msg->sig_reserved > 0) {
		dns_message_renderrelease(msg, msg->sig_reserved);
		msg->sig_reserved = 0;
	}
433
434
	if (msg->tsig != NULL) {
		INSIST(dns_rdataset_isassociated(msg->tsig));
435
		INSIST(msg->namepool != NULL);
436
		if (replying) {
437
438
			INSIST(msg->querytsig == NULL);
			msg->querytsig = msg->tsig;
439
		} else {
440
441
442
443
444
			dns_rdataset_disassociate(msg->tsig);
			isc_mempool_put(msg->rdspool, msg->tsig);
			if (msg->querytsig != NULL) {
				dns_rdataset_disassociate(msg->querytsig);
				isc_mempool_put(msg->rdspool, msg->querytsig);
445
446
			}
		}
447
448
		if (dns_name_dynamic(msg->tsigname))
			dns_name_free(msg->tsigname, msg->mctx);
449
		isc_mempool_put(msg->namepool, msg->tsigname);
450
		msg->tsig = NULL;
451
		msg->tsigname = NULL;
452
	} else if (msg->querytsig != NULL && !replying) {
453
454
		dns_rdataset_disassociate(msg->querytsig);
		isc_mempool_put(msg->rdspool, msg->querytsig);
455
		msg->querytsig = NULL;
456
457
458
459
460
	}
	if (msg->sig0 != NULL) {
		INSIST(dns_rdataset_isassociated(msg->sig0));
		dns_rdataset_disassociate(msg->sig0);
		isc_mempool_put(msg->rdspool, msg->sig0);
461
462
463
		if (msg->sig0name != NULL) {
			if (dns_name_dynamic(msg->sig0name))
				dns_name_free(msg->sig0name, msg->mctx);
464
			isc_mempool_put(msg->namepool, msg->sig0name);
465
		}
466
		msg->sig0 = NULL;
467
		msg->sig0name = NULL;
468
469
470
	}
}

471
472
/*
 * Free all but one (or everything) for this message.  This is used by
473
 * both dns_message_reset() and dns_message_destroy().
474
475
 */
static void
476
msgreset(dns_message_t *msg, isc_boolean_t everything) {
477
	dns_msgblock_t *msgblock, *next_msgblock;
478
	isc_buffer_t *dynbuf, *next_dynbuf;
479
480
481
482
	dns_rdata_t *rdata;
	dns_rdatalist_t *rdatalist;

	msgresetnames(msg, 0);
483
	msgresetopt(msg);
484
	msgresetsigs(msg, ISC_FALSE);
Bob Halley's avatar
EDNS0    
Bob Halley committed
485

Michael Graff's avatar
Michael Graff committed
486
487
488
489
	/*
	 * Clean up linked lists.
	 */

490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
	/*
	 * 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
506
507
	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
	INSIST(dynbuf != NULL);
Michael Graff's avatar
Michael Graff committed
508
	if (!everything) {
509
		isc_buffer_clear(dynbuf);
Michael Graff's avatar
Michael Graff committed
510
511
512
513
514
		dynbuf = ISC_LIST_NEXT(dynbuf, link);
	}
	while (dynbuf != NULL) {
		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
515
		isc_buffer_free(&dynbuf);
Michael Graff's avatar
Michael Graff committed
516
517
518
519
520
		dynbuf = next_dynbuf;
	}

	msgblock = ISC_LIST_HEAD(msg->rdatas);
	INSIST(msgblock != NULL);
Michael Graff's avatar
Michael Graff committed
521
522
	if (!everything) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
523
524
525
526
527
		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
528
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
Michael Graff's avatar
Michael Graff committed
529
530
531
		msgblock = next_msgblock;
	}

Michael Graff's avatar
Michael Graff committed
532
	/*
Michael Graff's avatar
Michael Graff committed
533
	 * rdatalists could be empty.
Michael Graff's avatar
Michael Graff committed
534
535
536
	 */

	msgblock = ISC_LIST_HEAD(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
537
538
	if (!everything && msgblock != NULL) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
539
540
541
542
543
		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
544
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
Michael Graff's avatar
Michael Graff committed
545
		msgblock = next_msgblock;
Michael Graff's avatar
Michael Graff committed
546
547
	}

548
	if (msg->need_cctx_cleanup == 1)
Michael Graff's avatar
Michael Graff committed
549
550
		dns_compress_invalidate(&msg->cctx);

551
	if (msg->tsigkey != NULL) {
552
		dns_tsigkey_detach(&msg->tsigkey);
553
554
555
556
557
558
559
560
		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;
	}
561

Brian Wellington's avatar
Brian Wellington committed
562
563
564
565
566
567
	if (msg->saved != NULL) {
		isc_mem_put(msg->mctx, msg->saved->base, msg->saved->length);
		isc_mem_put(msg->mctx, msg->saved, sizeof(isc_region_t));
		msg->saved = NULL;
	}

568
569
570
571
572
573
	/*
	 * cleanup the buffer cleanup list
	 */
	dynbuf = ISC_LIST_HEAD(msg->cleanup);
	while (dynbuf != NULL) {
		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
574
		ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
575
576
577
578
		isc_buffer_free(&dynbuf);
		dynbuf = next_dynbuf;
	}

Michael Graff's avatar
Michael Graff committed
579
580
581
	/*
	 * Set other bits to normal default values.
	 */
Michael Graff's avatar
Michael Graff committed
582
583
	if (!everything)
		msginit(msg);
Michael Graff's avatar
Michael Graff committed
584
585
}

586
587
588
589
590
591
592
593
594
595
596
597
598
static unsigned int
spacefortsig(dns_tsigkey_t *key, int otherlen) {
	isc_region_t r1, r2;
	unsigned int x;
	isc_result_t result;

	/*
	 * The space required for an TSIG record is:
	 *
	 *	n1 bytes for the name
	 *	2 bytes for the type
	 *	2 bytes for the class
	 *	4 bytes for the ttl
599
600
	 *	2 bytes for the rdlength
	 *	n2 bytes for the algorithm name
601
602
603
604
605
606
607
608
609
	 *	6 bytes for the time signed
	 *	2 bytes for the fudge
	 *	2 bytes for the MAC size
	 *	x bytes for the MAC
	 *	2 bytes for the original id
	 *	2 bytes for the error
	 *	2 bytes for the other data length
	 *	y bytes for the other data (at most)
	 * ---------------------------------
610
	 *     26 + n1 + n2 + x + y bytes
611
612
613
	 */

	dns_name_toregion(&key->name, &r1);
Brian Wellington's avatar
Brian Wellington committed
614
	dns_name_toregion(key->algorithm, &r2);
615
616
617
618
619
620
621
	if (key->key == NULL)
		x = 0;
	else {
		result = dst_key_sigsize(key->key, &x);
		if (result != ISC_R_SUCCESS)
			x = 0;
	}
622
	return (26 + r1.length + r2.length + x + otherlen);
623
624
}

625
isc_result_t
626
dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
Michael Graff's avatar
Michael Graff committed
627
628
{
	dns_message_t *m;
629
	isc_result_t result;
Michael Graff's avatar
Michael Graff committed
630
	dns_msgblock_t *msgblock;
631
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
632
633
634
	unsigned int i;

	REQUIRE(mctx != NULL);
635
636
	REQUIRE(msgp != NULL);
	REQUIRE(*msgp == NULL);
Michael Graff's avatar
Michael Graff committed
637
638
	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
		|| intent == DNS_MESSAGE_INTENTRENDER);
Michael Graff's avatar
Michael Graff committed
639
640
641

	m = isc_mem_get(mctx, sizeof(dns_message_t));
	if (m == NULL)
642
		return (ISC_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
643

644
645
646
647
648
	/*
	 * No allocations until further notice.  Just initialize all lists
	 * and other members that are freed in the cleanup phase here.
	 */

649
	m->magic = DNS_MESSAGE_MAGIC;
Michael Graff's avatar
Michael Graff committed
650
651
	m->from_to_wire = intent;
	msginit(m);
652

Michael Graff's avatar
Michael Graff committed
653
654
655
	for (i = 0 ; i < DNS_SECTION_MAX ; i++)
		ISC_LIST_INIT(m->sections[i]);
	m->mctx = mctx;
656

Michael Graff's avatar
Michael Graff committed
657
	ISC_LIST_INIT(m->scratchpad);
658
659
	ISC_LIST_INIT(m->cleanup);
	m->namepool = NULL;
660
	m->rdspool = NULL;
Michael Graff's avatar
Michael Graff committed
661
662
	ISC_LIST_INIT(m->rdatas);
	ISC_LIST_INIT(m->rdatalists);
663
664
	ISC_LIST_INIT(m->freerdata);
	ISC_LIST_INIT(m->freerdatalist);
Michael Graff's avatar
Michael Graff committed
665

666
667
668
669
670
671
672
673
674
	/*
	 * 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
675
	isc_mempool_setname(m->namepool, "msg:names");
676

677
678
679
680
681
682
	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
683
	isc_mempool_setname(m->rdspool, "msg:rdataset");
684

Michael Graff's avatar
Michael Graff committed
685
	dynbuf = NULL;
686
	result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
687
688
	if (result != ISC_R_SUCCESS)
		goto cleanup;
Michael Graff's avatar
Michael Graff committed
689
690
691
692
693
	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);

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

Michael Graff's avatar
Michael Graff committed
697
	if (intent == DNS_MESSAGE_INTENTPARSE) {
Michael Graff's avatar
Michael Graff committed
698
699
700
		msgblock = msgblock_allocate(mctx, sizeof(dns_rdatalist_t),
					     RDATALIST_COUNT);
		if (msgblock == NULL)
701
			goto cleanup;
Michael Graff's avatar
Michael Graff committed
702
703
704
		ISC_LIST_APPEND(m->rdatalists, msgblock, link);
	}

705
	*msgp = m;
706
	return (ISC_R_SUCCESS);
Michael Graff's avatar
Michael Graff committed
707
708
709
710

	/*
	 * Cleanup for error returns.
	 */
711
 cleanup:
Michael Graff's avatar
Michael Graff committed
712
	msgblock = ISC_LIST_HEAD(m->rdatas);
713
714
	if (msgblock != NULL)
		msgblock_free(mctx, msgblock, sizeof(dns_rdata_t));
Michael Graff's avatar
Michael Graff committed
715
	dynbuf = ISC_LIST_HEAD(m->scratchpad);
716
717
	if (dynbuf != NULL) {
		ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
718
		isc_buffer_free(&dynbuf);
719
	}
720
721
	if (m->namepool != NULL)
		isc_mempool_destroy(&m->namepool);
722
723
	if (m->rdspool != NULL)
		isc_mempool_destroy(&m->rdspool);
Michael Graff's avatar
Michael Graff committed
724
725
726
	m->magic = 0;
	isc_mem_put(mctx, m, sizeof(dns_message_t));

727
	return (ISC_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
728
729
730
}

void
731
dns_message_reset(dns_message_t *msg, unsigned int intent) {
732
733
734
735
	REQUIRE(DNS_MESSAGE_VALID(msg));
	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
		|| intent == DNS_MESSAGE_INTENTRENDER);

Michael Graff's avatar
Michael Graff committed
736
	msgreset(msg, ISC_FALSE);
737
	msg->from_to_wire = intent;
Michael Graff's avatar
Michael Graff committed
738
739
740
}

void
741
dns_message_destroy(dns_message_t **msgp) {
Michael Graff's avatar
Michael Graff committed
742
743
	dns_message_t *msg;

744
	REQUIRE(msgp != NULL);
745
	REQUIRE(DNS_MESSAGE_VALID(*msgp));
Michael Graff's avatar
Michael Graff committed
746

747
748
	msg = *msgp;
	*msgp = NULL;
Michael Graff's avatar
Michael Graff committed
749
750

	msgreset(msg, ISC_TRUE);
751
	isc_mempool_destroy(&msg->namepool);
752
	isc_mempool_destroy(&msg->rdspool);
Michael Graff's avatar
Michael Graff committed
753
754
755
756
	msg->magic = 0;
	isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
}

757
static isc_result_t
758
findname(dns_name_t **foundname, dns_name_t *target,
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
	 dns_namelist_t *section)
{
	dns_name_t *curr;

	for (curr = ISC_LIST_TAIL(*section) ;
	     curr != NULL ;
	     curr = ISC_LIST_PREV(curr, link)) {
		if (dns_name_equal(curr, target)) {
			if (foundname != NULL)
				*foundname = curr;
			return (ISC_R_SUCCESS);
		}
	}

	return (ISC_R_NOTFOUND);
}

776
isc_result_t
777
778
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
779
780
781
{
	dns_rdataset_t *curr;

782
783
784
785
	if (rdataset != NULL) {
		REQUIRE(*rdataset == NULL);
	}

Michael Graff's avatar
Michael Graff committed
786
787
788
	for (curr = ISC_LIST_TAIL(name->list) ;
	     curr != NULL ;
	     curr = ISC_LIST_PREV(curr, link)) {
Bob Halley's avatar
Bob Halley committed
789
		if (curr->type == type && curr->covers == covers) {
Michael Graff's avatar
Michael Graff committed
790
791
			if (rdataset != NULL)
				*rdataset = curr;
792
			return (ISC_R_SUCCESS);
Michael Graff's avatar
Michael Graff committed
793
794
795
		}
	}

796
	return (ISC_R_NOTFOUND);
Michael Graff's avatar
Michael Graff committed
797
798
799
800
801
}

/*
 * Read a name from buffer "source".
 */
802
static isc_result_t
Michael Graff's avatar
Michael Graff committed
803
804
805
806
getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
	dns_decompress_t *dctx)
{
	isc_buffer_t *scratch;
807
	isc_result_t result;
Michael Graff's avatar
Michael Graff committed
808
809
810
811
	unsigned int tries;

	scratch = currentbuffer(msg);

Michael Graff's avatar
Michael Graff committed
812
813
814
815
	/*
	 * First try:  use current buffer.
	 * Second try:  allocate a new buffer and use that.
	 */
Michael Graff's avatar
Michael Graff committed
816
817
	tries = 0;
	while (tries < 2) {
818
		dns_name_init(name, NULL);
Michael Graff's avatar
Michael Graff committed
819
820
821
		result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
					   scratch);

822
		if (result == ISC_R_NOSPACE) {
Michael Graff's avatar
Michael Graff committed
823
824
			tries++;

825
			result = newbuffer(msg, SCRATCHPAD_SIZE);
826
			if (result != ISC_R_SUCCESS)
Michael Graff's avatar
Michael Graff committed
827
828
829
830
831
832
833
834
				return (result);

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

Michael Graff's avatar
Michael Graff committed
835
	INSIST(0);  /* Cannot get here... */
836
	return (ISC_R_UNEXPECTED);
Michael Graff's avatar
Michael Graff committed
837
838
}

839
static isc_result_t
David Lawrence's avatar
David Lawrence committed
840
841
842
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)
843
844
{
	isc_buffer_t *scratch;
845
	isc_result_t result;
846
	unsigned int tries;
847
	unsigned int trysize;
848
849
850
851
852

	scratch = currentbuffer(msg);

	isc_buffer_setactive(source, rdatalen);

Michael Graff's avatar
Michael Graff committed
853
854
	/*
	 * First try:  use current buffer.
855
856
857
858
	 * 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
859
	 */
860
	tries = 0;
861
	trysize = 0;
862
	/* XXX possibly change this to a while (tries < 2) loop */
863
	for (;;) {
864
865
866
867
		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
					    source, dctx, ISC_FALSE,
					    scratch);

868
		if (result == ISC_R_NOSPACE) {
869
870
871
872
873
874
875
876
877
878
879
			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;
			}
880
			tries++;
881
			result = newbuffer(msg, trysize);
882
			if (result != ISC_R_SUCCESS)
883
884
885
886
887
888
889
890
				return (result);

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

892
893
894
895
896
897
898
899
900
901
#define DO_FORMERR					\
	do {						\
		if (best_effort)			\
			seen_problem = ISC_TRUE;	\
		else {					\
			result = DNS_R_FORMERR;		\
			goto cleanup;			\
		}					\
	} while (0)

902
static isc_result_t
903
904
getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
	     unsigned int options)
Michael Graff's avatar
Michael Graff committed
905
906
907
908
909
910
911
{
	isc_region_t r;
	unsigned int count;
	dns_name_t *name;
	dns_name_t *name2;
	dns_rdataset_t *rdataset;
	dns_rdatalist_t *rdatalist;
912
	isc_result_t result;
Michael Graff's avatar
Michael Graff committed
913
914
915
	dns_rdatatype_t rdtype;
	dns_rdataclass_t rdclass;
	dns_namelist_t *section;
916
	isc_boolean_t free_name;
917
918
	isc_boolean_t best_effort;
	isc_boolean_t seen_problem;
Michael Graff's avatar
Michael Graff committed
919

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

922
	best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
923
	seen_problem = ISC_FALSE;
924

925
926
927
928
	name = NULL;
	rdataset = NULL;
	rdatalist = NULL;

Michael Graff's avatar
Michael Graff committed
929
	for (count = 0 ; count < msg->counts[DNS_SECTION_QUESTION] ; count++) {
930
		name = isc_mempool_get(msg->namepool);
Michael Graff's avatar
Michael Graff committed
931
		if (name == NULL)
932
			return (ISC_R_NOMEMORY);
933
		free_name = ISC_TRUE;
Michael Graff's avatar
Michael Graff committed
934
935
936
937

		/*
		 * Parse the name out of this packet.
		 */
938
		isc_buffer_remainingregion(source, &r);
939
		isc_buffer_setactive(source, r.length);
Michael Graff's avatar
Michael Graff committed
940
		result = getname(name, source, msg, dctx);
941
		if (result != ISC_R_SUCCESS)
942
			goto cleanup;
Michael Graff's avatar
Michael Graff committed
943
944
945
946
947
948
949

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

		/*
953
954
955
956
		 * 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
957
958
959
960
		 * 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
961
		 */
962
		if (result != ISC_R_SUCCESS) {
963
964
			if (ISC_LIST_EMPTY(*section)) {
				ISC_LIST_APPEND(*section, name, link);
965
				free_name = ISC_FALSE;
966
967
			} else
				DO_FORMERR;
968
		} else {
969
			isc_mempool_put(msg->namepool, name);
970
			name = name2;
971
			name2 = NULL;
972
			free_name = ISC_FALSE;
973
		}
Michael Graff's avatar
Michael Graff committed
974
975
976
977

		/*
		 * Get type and class.
		 */
978
		isc_buffer_remainingregion(source, &r);
979
		if (r.length < 4) {
980
			result = ISC_R_UNEXPECTEDEND;
981
			goto cleanup;
982
		}
Michael Graff's avatar
Michael Graff committed
983
984
		rdtype = isc_buffer_getuint16(source);
		rdclass = isc_buffer_getuint16(source);
Michael Graff's avatar
Michael Graff committed
985
986

		/*
987
		 * If this class is different than the one we already read,
Michael Graff's avatar
Michael Graff committed
988
		 * this is an error.
Michael Graff's avatar
Michael Graff committed
989
		 */
Michael Graff's avatar
Michael Graff committed
990
991
992
		if (msg->state == DNS_SECTION_ANY) {
			msg->state = DNS_SECTION_QUESTION;
			msg->rdclass = rdclass;
993
994
		} else if (msg->rdclass != rdclass)
			DO_FORMERR;
995

Michael Graff's avatar
Michael Graff committed
996
		/*
Michael Graff's avatar
Michael Graff committed
997
		 * Can't ask the same question twice.
Michael Graff's avatar
Michael Graff committed
998
		 */
999
		result = dns_message_findtype(name, rdtype, 0, NULL);
1000
1001
		if (result == ISC_R_SUCCESS)
			DO_FORMERR;
Michael Graff's avatar
Michael Graff committed
1002
1003
1004
1005

		/*
		 * Allocate a new rdatalist.
		 */
Michael Graff's avatar
Michael Graff committed
1006
		rdatalist = newrdatalist(msg);
1007
		if (rdatalist == NULL) {
1008
			result = ISC_R_NOMEMORY;
1009
			goto cleanup;
1010
		}
1011
		rdataset =  isc_mempool_get(msg->rdspool);
1012
		if (rdataset == NULL) {
1013
			result = ISC_R_NOMEMORY;
1014
			goto cleanup;
1015
		}
Michael Graff's avatar
Michael Graff committed
1016
1017
1018
1019
1020

		/*
		 * Convert rdatalist to rdataset, and attach the latter to
		 * the name.
		 */
Michael Graff's avatar
Michael Graff committed
1021
		rdatalist->