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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static inline void
releasename(dns_message_t *msg, dns_name_t *name)
{
193
	ISC_LIST_PREPEND(msg->freename, name, link);
Michael Graff's avatar
Michael Graff committed
194
195
196
197
198
199
200
201
}

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

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

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

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

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

Michael Graff's avatar
Michael Graff committed
242
	msgblock = ISC_LIST_TAIL(msg->rdatas);
Michael Graff's avatar
Michael Graff committed
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
	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)
{
261
	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
262
263
264
265
266
267
268
269
}

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

270
271
272
	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
	if (rdatalist != NULL) {
		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
273
274
275
		return (rdatalist);
	}

Michael Graff's avatar
Michael Graff committed
276
	msgblock = ISC_LIST_TAIL(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
	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)
{
296
	ISC_LIST_PREPEND(msg->freerdataset, rdataset, link);
Michael Graff's avatar
Michael Graff committed
297
298
299
300
301
302
303
304
}

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

305
306
307
	rdataset = ISC_LIST_HEAD(msg->freerdataset);
	if (rdataset != NULL) {
		ISC_LIST_UNLINK(msg->freerdataset, rdataset, link);
Michael Graff's avatar
Michael Graff committed
308
309
310
		return (rdataset);
	}

Michael Graff's avatar
Michael Graff committed
311
	msgblock = ISC_LIST_TAIL(msg->rdatasets);
Michael Graff's avatar
Michael Graff committed
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
	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
327
static inline void
328
msginitheader(dns_message_t *m)
Michael Graff's avatar
Michael Graff committed
329
330
331
332
333
{
	m->id = 0;
	m->flags = 0;
	m->rcode = 0;
	m->opcode = 0;
Michael Graff's avatar
Michael Graff committed
334
	m->rdclass = 0;
335
}
Michael Graff's avatar
Michael Graff committed
336

337
338
339
340
341
342
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
343
		m->cursors[i] = NULL;
Michael Graff's avatar
Michael Graff committed
344
		m->counts[i] = 0;
Michael Graff's avatar
Michael Graff committed
345
	}
346
	m->opt = NULL;
Michael Graff's avatar
Michael Graff committed
347
	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
Michael Graff's avatar
Michael Graff committed
348
	m->reserved = 0;
349
	m->buffer = NULL;
350
	m->need_cctx_cleanup = 0;
Michael Graff's avatar
Michael Graff committed
351
352
}

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

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

	/*
	 * Clean up name lists by calling the rdataset disassociate function.
	 */
385
	for (i = first_section; i < DNS_SECTION_MAX; i++) {
Michael Graff's avatar
Michael Graff committed
386
387
388
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);

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

/*
 * 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;
412
	isc_buffer_t *dynbuf, *next_dynbuf;
413
414
415
416
417
418
	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
419

Bob Halley's avatar
EDNS0    
Bob Halley committed
420
421
422
423
	if (msg->opt != NULL)
		dns_rdataset_disassociate(msg->opt);
	msg->opt = NULL;

Michael Graff's avatar
Michael Graff committed
424
425
426
427
	/*
	 * Clean up linked lists.
	 */

428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
	/*
	 * 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
454
455
	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
	INSIST(dynbuf != NULL);
Michael Graff's avatar
Michael Graff committed
456
	if (!everything) {
457
		isc_buffer_clear(dynbuf);
Michael Graff's avatar
Michael Graff committed
458
459
460
461
462
		dynbuf = ISC_LIST_NEXT(dynbuf, link);
	}
	while (dynbuf != NULL) {
		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
463
		isc_buffer_free(&dynbuf);
Michael Graff's avatar
Michael Graff committed
464
465
466
467
468
		dynbuf = next_dynbuf;
	}

	msgblock = ISC_LIST_HEAD(msg->names);
	INSIST(msgblock != NULL);
Michael Graff's avatar
Michael Graff committed
469
470
	if (!everything) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
471
472
473
474
475
		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
476
		msgblock_free(msg->mctx, msgblock, sizeof(dns_name_t));
Michael Graff's avatar
Michael Graff committed
477
478
479
480
481
		msgblock = next_msgblock;
	}

	msgblock = ISC_LIST_HEAD(msg->rdatas);
	INSIST(msgblock != NULL);
Michael Graff's avatar
Michael Graff committed
482
483
	if (!everything) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
484
485
486
487
488
		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
489
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
Michael Graff's avatar
Michael Graff committed
490
491
492
		msgblock = next_msgblock;
	}

Michael Graff's avatar
Michael Graff committed
493
494
	msgblock = ISC_LIST_HEAD(msg->rdatasets);
	INSIST(msgblock != NULL);
Michael Graff's avatar
Michael Graff committed
495
496
	if (!everything) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
497
498
499
500
501
		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
502
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdataset_t));
Michael Graff's avatar
Michael Graff committed
503
504
505
		msgblock = next_msgblock;
	}

Michael Graff's avatar
Michael Graff committed
506
	/*
Michael Graff's avatar
Michael Graff committed
507
	 * rdatalists could be empty.
Michael Graff's avatar
Michael Graff committed
508
509
510
	 */

	msgblock = ISC_LIST_HEAD(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
511
512
	if (!everything && msgblock != NULL) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
513
514
515
516
517
		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
518
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
Michael Graff's avatar
Michael Graff committed
519
		msgblock = next_msgblock;
Michael Graff's avatar
Michael Graff committed
520
521
	}

522
	if (msg->need_cctx_cleanup == 1)
Michael Graff's avatar
Michael Graff committed
523
524
		dns_compress_invalidate(&msg->cctx);

525
526
	if (msg->tsig != NULL) {
		dns_rdata_freestruct(msg->tsig);
Bob Halley's avatar
EDNS0    
Bob Halley committed
527
528
		isc_mem_put(msg->mctx, msg->tsig,
			    sizeof(dns_rdata_any_tsig_t));
529
530
531
532
533
534
535
536
537
538
539
	}

	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
540
541
542
	/*
	 * Set other bits to normal default values.
	 */
Michael Graff's avatar
Michael Graff committed
543
544
	if (!everything)
		msginit(msg);
Michael Graff's avatar
Michael Graff committed
545
546
547
}

dns_result_t
548
dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
Michael Graff's avatar
Michael Graff committed
549
550
551
552
{
	dns_message_t *m;
	isc_result_t iresult;
	dns_msgblock_t *msgblock;
553
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
554
555
556
	unsigned int i;

	REQUIRE(mctx != NULL);
557
558
	REQUIRE(msgp != NULL);
	REQUIRE(*msgp == NULL);
Michael Graff's avatar
Michael Graff committed
559
560
	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
		|| intent == DNS_MESSAGE_INTENTRENDER);
Michael Graff's avatar
Michael Graff committed
561
562
563
564
565

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

566
	m->magic = DNS_MESSAGE_MAGIC;
Michael Graff's avatar
Michael Graff committed
567
568
569
570
571
572
573
574
	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);
575
	ISC_LIST_INIT(m->rdatasets);
Michael Graff's avatar
Michael Graff committed
576
	ISC_LIST_INIT(m->rdatalists);
577
578
579
580
	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
581
582

	dynbuf = NULL;
583
584
	iresult = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE,
				      ISC_BUFFERTYPE_BINARY);
Michael Graff's avatar
Michael Graff committed
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
	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
601
602
603
604
	msgblock = msgblock_allocate(mctx, sizeof(dns_rdataset_t),
				     RDATASET_COUNT);
	if (msgblock == NULL)
		goto cleanup4;
605
	ISC_LIST_APPEND(m->rdatasets, msgblock, link);
Michael Graff's avatar
Michael Graff committed
606

Michael Graff's avatar
Michael Graff committed
607
	if (intent == DNS_MESSAGE_INTENTPARSE) {
Michael Graff's avatar
Michael Graff committed
608
609
610
		msgblock = msgblock_allocate(mctx, sizeof(dns_rdatalist_t),
					     RDATALIST_COUNT);
		if (msgblock == NULL)
Michael Graff's avatar
Michael Graff committed
611
			goto cleanup5;
Michael Graff's avatar
Michael Graff committed
612
613
614
		ISC_LIST_APPEND(m->rdatalists, msgblock, link);
	}

615
	*msgp = m;
Michael Graff's avatar
Michael Graff committed
616
617
618
619
620
	return (DNS_R_SUCCESS);

	/*
	 * Cleanup for error returns.
	 */
Michael Graff's avatar
Michael Graff committed
621
622
 cleanup5:
	msgblock = ISC_LIST_HEAD(m->rdatasets);
Michael Graff's avatar
Michael Graff committed
623
	msgblock_free(mctx, msgblock, sizeof(dns_rdataset_t));
Michael Graff's avatar
Michael Graff committed
624
625
 cleanup4:
	msgblock = ISC_LIST_HEAD(m->rdatas);
Michael Graff's avatar
Michael Graff committed
626
	msgblock_free(mctx, msgblock, sizeof(dns_rdata_t));
Michael Graff's avatar
Michael Graff committed
627
628
 cleanup3:
	msgblock = ISC_LIST_HEAD(m->names);
Michael Graff's avatar
Michael Graff committed
629
	msgblock_free(mctx, msgblock, sizeof(dns_name_t));
Michael Graff's avatar
Michael Graff committed
630
631
 cleanup2:
	dynbuf = ISC_LIST_HEAD(m->scratchpad);
632
	isc_buffer_free(&dynbuf);
Michael Graff's avatar
Michael Graff committed
633
634
635
636
637
638
639
640
 cleanup1:
	m->magic = 0;
	isc_mem_put(mctx, m, sizeof(dns_message_t));

	return (DNS_R_NOMEMORY);
}

void
641
dns_message_reset(dns_message_t *msg, unsigned int intent)
Michael Graff's avatar
Michael Graff committed
642
{
643
644
645
646
647
	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
648
649
650
651
	msgreset(msg, ISC_FALSE);
}

void
652
dns_message_destroy(dns_message_t **msgp)
Michael Graff's avatar
Michael Graff committed
653
654
655
{
	dns_message_t *msg;

656
	REQUIRE(msgp != NULL);
657
	REQUIRE(DNS_MESSAGE_VALID(*msgp));
Michael Graff's avatar
Michael Graff committed
658

659
660
	msg = *msgp;
	*msgp = NULL;
Michael Graff's avatar
Michael Graff committed
661
662
663
664
665
666

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

Michael Graff's avatar
Michael Graff committed
667
668
669
670
671
672
673
674
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
675
		if (dns_name_equal(curr, target)) {
Michael Graff's avatar
Michael Graff committed
676
677
678
679
680
681
682
683
684
			if (foundname != NULL)
				*foundname = curr;
			return (DNS_R_SUCCESS);
		}
	}

	return (DNS_R_NOTFOUND);
}

685
686
687
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
688
689
690
{
	dns_rdataset_t *curr;

691
692
693
694
	if (rdataset != NULL) {
		REQUIRE(*rdataset == NULL);
	}

Michael Graff's avatar
Michael Graff committed
695
696
697
	for (curr = ISC_LIST_TAIL(name->list) ;
	     curr != NULL ;
	     curr = ISC_LIST_PREV(curr, link)) {
Bob Halley's avatar
Bob Halley committed
698
		if (curr->type == type && curr->covers == covers) {
Michael Graff's avatar
Michael Graff committed
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
			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
721
722
723
724
	/*
	 * First try:  use current buffer.
	 * Second try:  allocate a new buffer and use that.
	 */
Michael Graff's avatar
Michael Graff committed
725
726
	tries = 0;
	while (tries < 2) {
727
		dns_name_init(name, NULL);
Michael Graff's avatar
Michael Graff committed
728
729
730
731
732
733
		result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
					   scratch);

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

734
			result = newbuffer(msg, SCRATCHPAD_SIZE);
Michael Graff's avatar
Michael Graff committed
735
736
737
738
739
740
741
742
743
			if (result != DNS_R_SUCCESS)
				return (result);

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

Michael Graff's avatar
Michael Graff committed
744
745
	INSIST(0);  /* Cannot get here... */
	return (DNS_R_UNEXPECTED);
Michael Graff's avatar
Michael Graff committed
746
747
}

748
749
750
751
752
753
754
755
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;
756
	unsigned int trysize;
757

758
759
760
761
762
763
764
765
	/*
	 * 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
766
		rdata->data = (unsigned char *)""; 
767
		rdata->length = 0;
Bob Halley's avatar
Bob Halley committed
768
		rdata->rdclass = rdclass;
769
770
771
772
		rdata->type = rdtype;
		return DNS_R_SUCCESS;
	}
	    
773
774
775
776
777
	scratch = currentbuffer(msg);

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

Michael Graff's avatar
Michael Graff committed
778
779
	/*
	 * First try:  use current buffer.
780
781
782
783
	 * 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
784
	 */
785
	tries = 0;
786
787
	trysize = 0;
	for (;;) {
788
789
790
791
792
		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
					    source, dctx, ISC_FALSE,
					    scratch);

		if (result == DNS_R_NOSPACE) {
793
794
795
796
797
798
799
800
801
802
803
			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;
			}
804
			tries++;
805
			result = newbuffer(msg, trysize);
806
807
808
809
810
811
812
813
814
			if (result != DNS_R_SUCCESS)
				return (result);

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

Michael Graff's avatar
Michael Graff committed
816
817
818
819
820
821
822
823
824
825
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
826
827
828
	dns_rdatatype_t rdtype;
	dns_rdataclass_t rdclass;
	dns_namelist_t *section;
Michael Graff's avatar
Michael Graff committed
829

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

Michael Graff's avatar
Michael Graff committed
832
	for (count = 0 ; count < msg->counts[DNS_SECTION_QUESTION] ; count++) {
Michael Graff's avatar
Michael Graff committed
833
834
835
836
837
838
839
		name = newname(msg);
		if (name == NULL)
			return (DNS_R_NOMEMORY);

		/*
		 * Parse the name out of this packet.
		 */
840
841
		isc_buffer_remaining(source, &r);
		isc_buffer_setactive(source, r.length);
Michael Graff's avatar
Michael Graff committed
842
843
844
845
846
847
848
849
850
851
		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
852
		result = findname(&name2, name, section);
Michael Graff's avatar
Michael Graff committed
853
854

		/*
855
856
857
858
		 * 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
859
860
861
862
		 * 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
863
		 */
864
865
866
867
868
869
870
871
872
		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
873
874
875
876

		/*
		 * Get type and class.
		 */
Michael Graff's avatar
Michael Graff committed
877
878
879
880
881
		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
882
883

		/*
884
		 * If this class is different than the one we already read,
Michael Graff's avatar
Michael Graff committed
885
		 * this is an error.
Michael Graff's avatar
Michael Graff committed
886
		 */
Michael Graff's avatar
Michael Graff committed
887
888
889
		if (msg->state == DNS_SECTION_ANY) {
			msg->state = DNS_SECTION_QUESTION;
			msg->rdclass = rdclass;
890
			msg->state = DNS_SECTION_QUESTION;
Michael Graff's avatar
Michael Graff committed
891
892
893
		} else if (msg->rdclass != rdclass)
			return (DNS_R_FORMERR);
		
Michael Graff's avatar
Michael Graff committed
894
		/*
Michael Graff's avatar
Michael Graff committed
895
		 * Can't ask the same question twice.
Michael Graff's avatar
Michael Graff committed
896
		 */
897
		result = dns_message_findtype(name, rdtype, 0, NULL);
Michael Graff's avatar
Michael Graff committed
898
899
		if (result == DNS_R_SUCCESS)
			return (DNS_R_FORMERR);
Michael Graff's avatar
Michael Graff committed
900
901
902
903

		/*
		 * Allocate a new rdatalist.
		 */
Michael Graff's avatar
Michael Graff committed
904
		rdatalist = newrdatalist(msg);
Michael Graff's avatar
Michael Graff committed
905
906
		if (rdatalist == NULL)
			return (DNS_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
907
		rdataset = newrdataset(msg);
Michael Graff's avatar
Michael Graff committed
908
909
		if (rdataset == NULL)
			return (DNS_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
910
911
912
913
914

		/*
		 * Convert rdatalist to rdataset, and attach the latter to
		 * the name.
		 */
Michael Graff's avatar
Michael Graff committed
915
916
917
918
919
		rdatalist->type = rdtype;
		rdatalist->rdclass = rdclass;
		rdatalist->ttl = 0;
		ISC_LIST_INIT(rdatalist->rdata);

920
		dns_rdataset_init(rdataset);
Michael Graff's avatar
Michael Graff committed
921
922
923
		result = dns_rdatalist_tordataset(rdatalist, rdataset);
		if (result != DNS_R_SUCCESS)
			return (result);
924
		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
Michael Graff's avatar
Michael Graff committed
925
926

		ISC_LIST_APPEND(name->list, rdataset, link);
Michael Graff's avatar
Michael Graff committed
927
928
929
930
931
932
933
	}
	
	return (DNS_R_SUCCESS);
}

static dns_result_t
getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
934
	   dns_section_t sectionid, isc_boolean_t preserve_order)
Michael Graff's avatar
Michael Graff committed
935
{
Michael Graff's avatar
Michael Graff committed
936
937
	isc_region_t r;
	unsigned int count;
Michael Graff's avatar
Michael Graff committed
938
	unsigned int rdatalen;
Michael Graff's avatar
Michael Graff committed
939
940
941
942
943
	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
944
	dns_rdatatype_t rdtype, covers;
Michael Graff's avatar
Michael Graff committed
945
	dns_rdataclass_t rdclass;
946
	dns_rdata_t *rdata;
Michael Graff's avatar
Michael Graff committed
947
948
949
950
	dns_ttl_t ttl;
	dns_namelist_t *section;

	for (count = 0 ; count < msg->counts[sectionid] ; count++) {
951
		int recstart = source->current;
Bob Halley's avatar
Bob Halley committed
952
		isc_boolean_t skip_search;
953
954
		section = &msg->sections[sectionid];

Bob Halley's avatar
Bob Halley committed
955
		skip_search = ISC_FALSE;
Michael Graff's avatar
Michael Graff committed
956
957
958
959
960
961
962
		name = newname(msg);
		if (name == NULL)
			return (DNS_R_NOMEMORY);

		/*
		 * Parse the name out of this packet.
		 */
963
964
		isc_buffer_remaining(source, &r);
		isc_buffer_setactive(source, r.length);
Michael Graff's avatar
Michael Graff committed
965
966
967
968
969
970
971
		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
972
		 * later.)
Michael Graff's avatar
Michael Graff committed
973
974
		 */
		isc_buffer_remaining(source, &r);
Michael Graff's avatar
Michael Graff committed
975
		if (r.length < 2 + 2 + 4 + 2)
Michael Graff's avatar
Michael Graff committed
976
977
978
979
			return (DNS_R_UNEXPECTEDEND);
		rdtype = isc_buffer_getuint16(source);
		rdclass = isc_buffer_getuint16(source);

980
981
982
983
984
985
986
987
988
989
990
		/*
		 * 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
991
		/*
992
993
		 * If this class is different than the one in the question
		 * section, bail.
Michael Graff's avatar
Michael Graff committed
994
		 */
Michael Graff's avatar
Michael Graff committed
995
		if (msg->opcode != dns_opcode_update
996
		    && rdtype != dns_rdatatype_tsig
Bob Halley's avatar
EDNS0    
Bob Halley committed
997
		    && rdtype != dns_rdatatype_opt
Michael Graff's avatar
Michael Graff committed
998
		    && msg->rdclass != rdclass)
Michael Graff's avatar
Michael Graff committed
999
			return (DNS_R_FORMERR);
1000
1001

		/*
Bob Halley's avatar
Bob Halley committed
1002
		 * Special type handling for TSIG and OPT.
1003
1004
		 */
		if (rdtype == dns_rdatatype_tsig) {
Bob Halley's avatar
Bob Halley committed
1005
1006
1007
1008
1009
			/*
			 * If it is a tsig, verify that it is in the
			 * additional data section, and switch sections for
			 * the rest of this rdata.
			 */
1010
1011
			if (sectionid != DNS_SECTION_ADDITIONAL)
				return (DNS_R_FORMERR);
1012
1013
			if (rdclass != dns_rdataclass_any)
				return (DNS_R_FORMERR);
1014
			section = &msg->sections[DNS_SECTION_TSIG];
1015
			msg->tsigstart = recstart;
Bob Halley's avatar
Bob Halley committed
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
			skip_search = ISC_TRUE;
		} else if (rdtype == dns_rdatatype_opt) {
			/*
			 * The name of an OPT record must be ".", it
			 * must be in the additional data section, and
			 * it must be the first OPT we've seen.
			 */
			if (!dns_name_equal(dns_rootname, name) ||
			    sectionid != DNS_SECTION_ADDITIONAL ||
			    msg->opt != NULL)
				return (DNS_R_FORMERR);
			skip_search = ISC_TRUE;
1028
		}
Michael Graff's avatar
Michael Graff committed
1029
1030
1031
1032
1033
1034
		
		/*
		 * ... now get ttl and rdatalen, and check buffer.
		 */
		ttl = isc_buffer_getuint32(source);
		rdatalen = isc_buffer_getuint16(source);
Michael Graff's avatar
Michael Graff committed
1035
		r.length -= (2 + 2 + 4 + 2);
Michael Graff's avatar
Michael Graff committed
1036
1037
1038
		if (r.length < rdatalen)
			return (DNS_R_UNEXPECTEDEND);

1039
1040
1041
1042
		/*
		 * If we are doing a dynamic update don't bother searching
		 * for a name, just append this one to the end of the message.
		 */
Bob Halley's avatar
Bob Halley committed
1043
1044
		if (preserve_order || msg->opcode == dns_opcode_update ||
		    skip_search) {
Bob Halley's avatar
EDNS0    
Bob Halley committed
1045
1046
			if (rdtype != dns_rdatatype_opt)
				ISC_LIST_APPEND(*section, name, link);
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
		} else {
			/*
			 * 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.
			 */
			result = findname(&name2, name, section);

			/*
			 * If it is a new name, append to the section.
			 */
			if (result == DNS_R_SUCCESS) {
				releasename(msg, name);
				name = name2;
			} else {
				ISC_LIST_APPEND(*section, name, link);
			}
		}

Bob Halley's avatar
Bob Halley committed
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
		/*
		 * Read the rdata from the wire format.  Interpret the 
		 * rdata according to its actual class, even if it had a
		 * DynDNS meta-class in the packet (unless this is a TSIG).
		 * Then put the meta-class back into the finished rdata.
		 */
		rdata = newrdata(msg);
		if (rdata == NULL)
			return (DNS_R_NOMEMORY);
		if (rdtype != dns_rdatatype_tsig)
			result = getrdata(name, source, msg, dctx,
					  msg->rdclass, rdtype,
					  rdatalen, rdata);
		else
			result = getrdata(name, source, msg, dctx,
					  rdclass, rdtype, rdatalen, rdata);
		if (result != DNS_R_SUCCESS)
			return (result);
		rdata->rdclass = rdclass;
		if (rdtype == dns_rdatatype_sig && rdata->length > 0)
			covers = dns_rdata_covers(rdata);
		else
			covers = 0;

Michael Graff's avatar
Michael Graff committed
1091
1092
		/*
		 * Search name for the particular type and class.
1093
		 * Skip this stage if in update mode, or this is a TSIG.
Michael Graff's avatar
Michael Graff committed
1094
		 */
Bob Halley's avatar
Bob Halley committed
1095
1096
		if (preserve_order || msg->opcode == dns_opcode_update ||
		    skip_search)
1097
			result = DNS_R_NOTFOUND;
1098
1099
1100
1101
1102
		else {
			rdataset = NULL;
			result = dns_message_findtype(name, rdtype, covers,
						      &rdataset);
		}
Michael Graff's avatar
Michael Graff committed
1103
1104

		/*
1105
1106
1107
1108
1109
		 * If we found an rdataset that matches, we need to
		 * append this rdata to that set.  If we did not, we need
		 * to create a new rdatalist, store the important bits there,
		 * convert it to an rdataset, and link the latter to the name.
		 * Yuck.
Michael Graff's avatar
Michael Graff committed
1110
		 */
Michael Graff's avatar
Michael Graff committed
1111
		if (result == DNS_R_NOTFOUND) {
Michael Graff's avatar
Michael Graff committed
1112
1113
1114
			rdataset = newrdataset(msg);
			if (rdataset == NULL)
				return (DNS_R_NOMEMORY);
1115
1116
1117
			rdatalist = newrdatalist(msg);
			if (rdatalist == NULL)
				return (DNS_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
1118

1119
			rdatalist->type = rdtype;
Bob Halley's avatar
Bob Halley committed
1120
			rdatalist->covers = covers;
1121
1122
1123
			rdatalist->rdclass = rdclass;
			rdatalist->ttl = ttl;
			ISC_LIST_INIT(rdatalist->rdata);
Michael Graff's avatar
Michael Graff committed
1124

1125
1126
1127
			dns_rdataset_init(rdataset);
			dns_rdatalist_tordataset(rdatalist, rdataset);

Bob Halley's avatar
EDNS0    
Bob Halley committed
1128
1129
			if (rdtype != dns_rdatatype_opt)
				ISC_LIST_APPEND(name->list, rdataset, link);
1130
		}
Michael Graff's avatar
Michael Graff committed
1131
1132

		/*
Bob Halley's avatar
Bob Halley committed
1133
		 * XXXRTH  Normalize TTLs.
Michael Graff's avatar
Michael Graff committed
1134
1135
		 */

1136
		/*
Michael Graff's avatar
Michael Graff committed
1137
		 * XXXMLG Perform a totally ugly hack here to pull
1138
1139
1140
1141
1142
1143
1144
		 * the rdatalist out of the private field in the rdataset,
		 * and append this rdata to the rdatalist's linked list
		 * of rdata.
		 */
		rdatalist = (dns_rdatalist_t *)(rdataset->private1);

		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1145
1146

		/*
Bob Halley's avatar
EDNS0    
Bob Halley committed
1147
1148
		 * If this is an OPT record, remember it.  Also, set
		 * the extended rcode.
1149
		 */
Bob Halley's avatar
EDNS0    
Bob Halley committed
1150
1151
1152
		if (rdtype == dns_rdatatype_opt) {
			unsigned int ercode;

Bob Halley's avatar
Bob Halley committed
1153
			msg->opt = rdataset;
Bob Halley's avatar
EDNS0    
Bob Halley committed
1154
1155
1156
1157
			ercode = (msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
				>> 20;
			msg->rcode |= ercode;
		}
Michael Graff's avatar
Michael Graff committed
1158
1159
1160
	}
	
	return (DNS_R_SUCCESS);
Michael Graff's avatar
Michael Graff committed
1161
1162
}

Michael Graff's avatar
Michael Graff committed
1163
dns_result_t
1164
1165
dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
		  isc_boolean_t preserve_order)
Michael Graff's avatar
Michael Graff committed
1166
{
Michael Graff's avatar
Michael Graff committed
1167
1168
1169
	isc_region_t r;
	dns_decompress_t dctx;
	dns_result_t ret;
1170
	isc_uint16_t tmpflags;
Michael Graff's avatar
Michael Graff committed
1171

1172
	REQUIRE(DNS_MESSAGE_VALID(msg));
Michael Graff's avatar
Michael Graff committed
1173
	REQUIRE(source != NULL);
Michael Graff's avatar
Michael Graff committed
1174
	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
Michael Graff's avatar
Michael Graff committed
1175

1176
1177
1178
	msg->header_ok = 0;
	msg->question_ok = 0;

Michael Graff's avatar
Michael Graff committed
1179
	isc_buffer_remaining(source, &r);
Michael Graff's avatar
Michael Graff committed
1180
	if (r.length < DNS_MESSAGE_HEADERLEN)
Michael Graff's avatar
Michael Graff committed
1181
1182
1183
		return (DNS_R_UNEXPECTEDEND);

	msg->id = isc_buffer_getuint16(source);
1184
1185
1186
1187
	tmpflags = isc_buffer_getuint16(source);
	msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
		       >> DNS_MESSAGE_OPCODE_SHIFT);
	msg->rcode = (tmpflags & DNS_MESSAGE_RCODE_MASK);
1188
	msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
Michael Graff's avatar
Michael Graff committed
1189
1190
1191
1192
	msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
	msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
	msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
Michael Graff's avatar
Michael Graff committed
1193

1194
1195
	msg->header_ok = 1;

Michael Graff's avatar
Michael Graff committed
1196
1197
1198
	/*
	 * -1 means no EDNS.
	 */
Michael Graff's avatar
Michael Graff committed
1199
1200
	dns_decompress_init(&dctx, -1, ISC_FALSE);

Michael Graff's avatar
Michael Graff committed
1201
1202
1203
1204
1205
1206
	if (dns_decompress_edns(&dctx) > 1 || !dns_decompress_strict(&dctx))
		dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL);
	else
		dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);


Michael Graff's avatar
Michael Graff committed
1207
1208
1209
	ret = getquestions(source, msg, &dctx);
	if (ret != DNS_R_SUCCESS)
		return (ret);
1210
	msg->question_ok = 1;
Michael Graff's avatar
Michael Graff committed
1211

1212
1213
	ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER,
			 preserve_order);
Michael Graff's avatar
Michael Graff committed
1214
1215
1216
	if (ret != DNS_R_SUCCESS)
		return (ret);

1217
1218
	ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY,
			 preserve_order);
Michael Graff's avatar
Michael Graff committed
1219
1220
1221
	if (ret != DNS_R_SUCCESS)
		return (ret);

1222
1223
	ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL,
			 preserve_order);
Michael Graff's avatar
Michael Graff committed
1224
1225
1226
	if (ret != DNS_R_SUCCESS)
		return (ret);

1227
1228
1229
1230
	isc_buffer_remaining(source, &r);
	if (r.length != 0)
		return (DNS_R_FORMERR);

1231
1232
1233
1234
1235
	if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_TSIG])) {
		ret = dns_tsig_verify(source, msg);
		if (ret != DNS_R_SUCCESS)
			return ret;
	}
Michael Graff's avatar
Michael Graff committed
1236
1237

	return (DNS_R_SUCCESS);
Michael Graff's avatar
Michael Graff committed
1238
1239
1240
1241
1242
}

dns_result_t
dns_message_renderbegin(dns_message_t *msg, isc_buffer_t *buffer)
{
1243
	isc_region_t r;