message.c 44.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>
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 167 168 169
{
	isc_result_t result;
	isc_dynbuffer_t *dynbuf;

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

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

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

	dynbuf = ISC_LIST_TAIL(msg->scratchpad);
Michael Graff's avatar
Michael Graff committed
185
	INSIST(dynbuf != NULL);
Michael Graff's avatar
Michael Graff committed
186 187 188 189 190 191 192

	return (&dynbuf->buffer);
}

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 412 413 414 415 416 417 418
}

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

	msgresetnames(msg, 0);
Michael Graff's avatar
Michael Graff committed
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) {
Michael Graff's avatar
Michael Graff committed
457 458 459 460 461 462 463 464 465 466 467 468
		isc_dynbuffer_reset(dynbuf);
		dynbuf = ISC_LIST_NEXT(dynbuf, link);
	}
	while (dynbuf != NULL) {
		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
		isc_dynbuffer_free(msg->mctx, &dynbuf);
		dynbuf = next_dynbuf;
	}

	msgblock = ISC_LIST_HEAD(msg->names);
	INSIST(msgblock != NULL);
Michael Graff's avatar
Michael Graff committed
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 553 554 555 556
{
	dns_message_t *m;
	isc_result_t iresult;
	dns_msgblock_t *msgblock;
	isc_dynbuffer_t *dynbuf;
	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 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600

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

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

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

Michael Graff's avatar
Michael Graff committed
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 632 633 634 635 636 637 638 639 640
 cleanup2:
	dynbuf = ISC_LIST_HEAD(m->scratchpad);
	isc_dynbuffer_free(mctx, &dynbuf);
 cleanup1:
	m->magic = 0;
	isc_mem_put(mctx, m, sizeof(dns_message_t));

	return (DNS_R_NOMEMORY);
}

void
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 685
			if (foundname != NULL)
				*foundname = curr;
			return (DNS_R_SUCCESS);
		}
	}

	return (DNS_R_NOTFOUND);
}

static dns_result_t
Bob Halley's avatar
Bob Halley committed
686 687
findtype(dns_rdataset_t **rdataset, dns_name_t *name, dns_rdatatype_t type,
	 dns_rdatatype_t covers)
Michael Graff's avatar
Michael Graff committed
688 689 690 691 692 693
{
	dns_rdataset_t *curr;

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

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

730
			result = newbuffer(msg, SCRATCHPAD_SIZE);
Michael Graff's avatar
Michael Graff committed
731 732 733 734 735 736 737 738 739
			if (result != DNS_R_SUCCESS)
				return (result);

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

Michael Graff's avatar
Michael Graff committed
740 741
	INSIST(0);  /* Cannot get here... */
	return (DNS_R_UNEXPECTED);
Michael Graff's avatar
Michael Graff committed
742 743
}

744 745 746 747 748 749 750 751
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;
752
	unsigned int trysize;
753

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

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

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

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

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

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

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

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

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

		/*
851 852 853 854
		 * 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
855 856 857 858
		 * 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
859
		 */
860 861 862 863 864 865 866 867 868
		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
869 870 871 872

		/*
		 * Get type and class.
		 */
Michael Graff's avatar
Michael Graff committed
873 874 875 876 877
		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
878 879

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

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

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

916
		dns_rdataset_init(rdataset);
Michael Graff's avatar
Michael Graff committed
917 918 919
		result = dns_rdatalist_tordataset(rdatalist, rdataset);
		if (result != DNS_R_SUCCESS)
			return (result);
920
		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
Michael Graff's avatar
Michael Graff committed
921 922

		ISC_LIST_APPEND(name->list, rdataset, link);
Michael Graff's avatar
Michael Graff committed
923 924 925 926 927 928 929
	}
	
	return (DNS_R_SUCCESS);
}

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

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

Bob Halley's avatar
Bob Halley committed
951
		skip_search = ISC_FALSE;
Michael Graff's avatar
Michael Graff committed
952 953 954 955 956 957 958
		name = newname(msg);
		if (name == NULL)
			return (DNS_R_NOMEMORY);

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

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

		/*
Bob Halley's avatar
Bob Halley committed
998
		 * Special type handling for TSIG and OPT.
999 1000
		 */
		if (rdtype == dns_rdatatype_tsig) {
Bob Halley's avatar
Bob Halley committed
1001 1002 1003 1004 1005
			/*
			 * If it is a tsig, verify that it is in the
			 * additional data section, and switch sections for
			 * the rest of this rdata.
			 */
1006 1007
			if (sectionid != DNS_SECTION_ADDITIONAL)
				return (DNS_R_FORMERR);
1008 1009
			if (rdclass != dns_rdataclass_any)
				return (DNS_R_FORMERR);
1010
			section = &msg->sections[DNS_SECTION_TSIG];
1011
			msg->tsigstart = recstart;
Bob Halley's avatar
Bob Halley committed
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
			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;
1024
		}
Michael Graff's avatar
Michael Graff committed
1025 1026 1027 1028 1029 1030
		
		/*
		 * ... 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
1031
		r.length -= (2 + 2 + 4 + 2);
Michael Graff's avatar
Michael Graff committed
1032 1033 1034
		if (r.length < rdatalen)
			return (DNS_R_UNEXPECTEDEND);

1035 1036 1037 1038
		/*
		 * 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
1039 1040
		if (preserve_order || msg->opcode == dns_opcode_update ||
		    skip_search) {
Bob Halley's avatar
EDNS0  
Bob Halley committed
1041 1042
			if (rdtype != dns_rdatatype_opt)
				ISC_LIST_APPEND(*section, name, link);
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
		} 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
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
		/*
		 * 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
1087 1088
		/*
		 * Search name for the particular type and class.
1089
		 * Skip this stage if in update mode, or this is a TSIG.
Michael Graff's avatar
Michael Graff committed
1090
		 */
Bob Halley's avatar
Bob Halley committed
1091 1092
		if (preserve_order || msg->opcode == dns_opcode_update ||
		    skip_search)
1093 1094
			result = DNS_R_NOTFOUND;
		else
Bob Halley's avatar
Bob Halley committed
1095
			result = findtype(&rdataset, name, rdtype, covers);
Michael Graff's avatar
Michael Graff committed
1096 1097

		/*
1098 1099 1100 1101 1102
		 * 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
1103
		 */
Michael Graff's avatar
Michael Graff committed
1104
		if (result == DNS_R_NOTFOUND) {
Michael Graff's avatar
Michael Graff committed
1105 1106 1107
			rdataset = newrdataset(msg);
			if (rdataset == NULL)
				return (DNS_R_NOMEMORY);
1108 1109 1110
			rdatalist = newrdatalist(msg);
			if (rdatalist == NULL)
				return (DNS_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
1111

1112
			rdatalist->type = rdtype;
Bob Halley's avatar
Bob Halley committed
1113
			rdatalist->covers = covers;
1114 1115 1116
			rdatalist->rdclass = rdclass;
			rdatalist->ttl = ttl;
			ISC_LIST_INIT(rdatalist->rdata);
Michael Graff's avatar
Michael Graff committed
1117

1118 1119 1120
			dns_rdataset_init(rdataset);
			dns_rdatalist_tordataset(rdatalist, rdataset);