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

18
/* $Id: message.c,v 1.248 2009/10/26 23:14:54 each Exp $ */
19 20

/*! \file */
David Lawrence's avatar
David Lawrence committed
21

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

#include <config.h>
27
#include <ctype.h>
Michael Graff's avatar
Michael Graff committed
28

Mark Andrews's avatar
Mark Andrews committed
29
#include <isc/buffer.h>
30
#include <isc/mem.h>
Mark Andrews's avatar
Mark Andrews committed
31
#include <isc/print.h>
32
#include <isc/string.h>		/* Required for HP/UX (and others?) */
Bob Halley's avatar
Bob Halley committed
33
#include <isc/util.h>
Michael Graff's avatar
Michael Graff committed
34

35 36
#include <dns/dnssec.h>
#include <dns/keyvalues.h>
37
#include <dns/log.h>
38
#include <dns/masterdump.h>
Michael Graff's avatar
Michael Graff committed
39
#include <dns/message.h>
40
#include <dns/opcode.h>
Michael Graff's avatar
Michael Graff committed
41 42
#include <dns/rdata.h>
#include <dns/rdatalist.h>
43
#include <dns/rdataset.h>
44
#include <dns/rdatastruct.h>
45
#include <dns/result.h>
46
#include <dns/tsig.h>
Brian Wellington's avatar
Brian Wellington committed
47
#include <dns/view.h>
Michael Graff's avatar
Michael Graff committed
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
#ifdef SKAN_MSG_DEBUG
static void
hexdump(const char *msg, const char *msg2, void *base, size_t len) {
	unsigned char *p;
	unsigned int cnt;

	p = base;
	cnt = 0;

	printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);

	while (cnt < len) {
		if (cnt % 16 == 0)
			printf("%p: ", p);
		else if (cnt % 8 == 0)
			printf(" |");
		printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
		p++;
		cnt++;

		if (cnt % 16 == 0)
			printf("\n");
	}

	if (cnt % 16 != 0)
		printf("\n");
}
#endif

78
#define DNS_MESSAGE_OPCODE_MASK		0x7800U
Bob Halley's avatar
EDNS0  
Bob Halley committed
79
#define DNS_MESSAGE_OPCODE_SHIFT	11
Michael Graff's avatar
Michael Graff committed
80 81
#define DNS_MESSAGE_RCODE_MASK		0x000fU
#define DNS_MESSAGE_FLAG_MASK		0x8ff0U
Bob Halley's avatar
EDNS0  
Bob Halley committed
82 83 84 85
#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
86 87 88 89 90

#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))
Brian Wellington's avatar
Brian Wellington committed
91 92 93 94
#define ADD_STRING(b, s)	{if (strlen(s) >= \
				   isc_buffer_availablelength(b)) \
				       return(ISC_R_NOSPACE); else \
				       isc_buffer_putstr(b, s);}
95 96
#define VALID_PSEUDOSECTION(s)	(((s) >= DNS_PSEUDOSECTION_ANY) \
				 && ((s) < DNS_PSEUDOSECTION_MAX))
Michael Graff's avatar
Michael Graff committed
97

98 99
#define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)

100
/*%
Michael Graff's avatar
Michael Graff committed
101 102
 * 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
103
 * XXXMLG These should come from a config setting.
Michael Graff's avatar
Michael Graff committed
104
 */
Michael Graff's avatar
Michael Graff committed
105
#define SCRATCHPAD_SIZE		512
106
#define NAME_COUNT		  8
107
#define OFFSET_COUNT		  4
108 109 110
#define RDATA_COUNT		  8
#define RDATALIST_COUNT		  8
#define RDATASET_COUNT		 RDATALIST_COUNT
Michael Graff's avatar
Michael Graff committed
111

112
/*%
113 114 115
 * Text representation of the different items, for message_totext
 * functions.
 */
David Lawrence's avatar
David Lawrence committed
116
static const char *sectiontext[] = {
117 118 119 120 121 122
	"QUESTION",
	"ANSWER",
	"AUTHORITY",
	"ADDITIONAL"
};

123 124 125 126 127 128 129
static const char *updsectiontext[] = {
	"ZONE",
	"PREREQUISITE",
	"UPDATE",
	"ADDITIONAL"
};

David Lawrence's avatar
David Lawrence committed
130
static const char *opcodetext[] = {
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
	"QUERY",
	"IQUERY",
	"STATUS",
	"RESERVED3",
	"NOTIFY",
	"UPDATE",
	"RESERVED6",
	"RESERVED7",
	"RESERVED8",
	"RESERVED9",
	"RESERVED10",
	"RESERVED11",
	"RESERVED12",
	"RESERVED13",
	"RESERVED14",
	"RESERVED15"
};

David Lawrence's avatar
David Lawrence committed
149
static const char *rcodetext[] = {
150 151 152 153
	"NOERROR",
	"FORMERR",
	"SERVFAIL",
	"NXDOMAIN",
154
	"NOTIMP",
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
	"REFUSED",
	"YXDOMAIN",
	"YXRRSET",
	"NXRRSET",
	"NOTAUTH",
	"NOTZONE",
	"RESERVED11",
	"RESERVED12",
	"RESERVED13",
	"RESERVED14",
	"RESERVED15",
	"BADVERS"
};


170
/*%
Michael Graff's avatar
Michael Graff committed
171 172
 * "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
Francis Dupont's avatar
Francis Dupont committed
173
 * size, or the allocated elements will not be aligned correctly.
Michael Graff's avatar
Michael Graff committed
174 175
 */
struct dns_msgblock {
Michael Graff's avatar
Michael Graff committed
176
	unsigned int			count;
Michael Graff's avatar
Michael Graff committed
177 178 179
	unsigned int			remaining;
	ISC_LINK(dns_msgblock_t)	link;
}; /* dynamically sized */
Michael Graff's avatar
Michael Graff committed
180

Michael Graff's avatar
Michael Graff committed
181 182
static inline dns_msgblock_t *
msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
183

Michael Graff's avatar
Michael Graff committed
184
#define msgblock_get(block, type) \
Michael Graff's avatar
Michael Graff committed
185
	((type *)msgblock_internalget(block, sizeof(type)))
Michael Graff's avatar
Michael Graff committed
186 187

static inline void *
Michael Graff's avatar
Michael Graff committed
188 189 190
msgblock_internalget(dns_msgblock_t *, unsigned int);

static inline void
Michael Graff's avatar
Michael Graff committed
191
msgblock_reset(dns_msgblock_t *);
Michael Graff's avatar
Michael Graff committed
192

Michael Graff's avatar
Michael Graff committed
193 194
static inline void
msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
Michael Graff's avatar
Michael Graff committed
195 196 197 198 199 200

/*
 * 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
201 202
msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
		  unsigned int count)
Michael Graff's avatar
Michael Graff committed
203 204 205 206 207 208 209 210
{
	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
211
		return (NULL);
Michael Graff's avatar
Michael Graff committed
212

Michael Graff's avatar
Michael Graff committed
213
	block->count = count;
Michael Graff's avatar
Michael Graff committed
214 215 216 217 218 219 220 221 222 223 224 225
	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 *
226
msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
Michael Graff's avatar
Michael Graff committed
227 228
	void *ptr;

Andreas Gustafsson's avatar
Andreas Gustafsson committed
229
	if (block == NULL || block->remaining == 0)
Michael Graff's avatar
Michael Graff committed
230 231 232 233 234 235 236 237 238 239 240
		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
241
static inline void
242
msgblock_reset(dns_msgblock_t *block) {
Michael Graff's avatar
Michael Graff committed
243
	block->remaining = block->count;
Michael Graff's avatar
Michael Graff committed
244 245
}

Michael Graff's avatar
Michael Graff committed
246 247 248 249
/*
 * Release memory associated with a message block.
 */
static inline void
250
msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
Michael Graff's avatar
Michael Graff committed
251
{
Michael Graff's avatar
Michael Graff committed
252 253 254 255 256
	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
257
}
Michael Graff's avatar
Michael Graff committed
258

Michael Graff's avatar
Michael Graff committed
259 260 261 262 263
/*
 * 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)
 */
264
static inline isc_result_t
265
newbuffer(dns_message_t *msg, unsigned int size) {
Michael Graff's avatar
Michael Graff committed
266
	isc_result_t result;
267
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
268 269

	dynbuf = NULL;
270
	result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
Michael Graff's avatar
Michael Graff committed
271
	if (result != ISC_R_SUCCESS)
272
		return (ISC_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
273 274

	ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
275
	return (ISC_R_SUCCESS);
Michael Graff's avatar
Michael Graff committed
276 277 278
}

static inline isc_buffer_t *
279
currentbuffer(dns_message_t *msg) {
280
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
281 282

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

285
	return (dynbuf);
Michael Graff's avatar
Michael Graff committed
286 287 288
}

static inline void
289
releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
290
	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
Michael Graff's avatar
Michael Graff committed
291 292 293
}

static inline dns_rdata_t *
294
newrdata(dns_message_t *msg) {
Michael Graff's avatar
Michael Graff committed
295 296 297
	dns_msgblock_t *msgblock;
	dns_rdata_t *rdata;

298 299 300
	rdata = ISC_LIST_HEAD(msg->freerdata);
	if (rdata != NULL) {
		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
Michael Graff's avatar
Michael Graff committed
301 302 303
		return (rdata);
	}

Michael Graff's avatar
Michael Graff committed
304
	msgblock = ISC_LIST_TAIL(msg->rdatas);
Michael Graff's avatar
Michael Graff committed
305 306 307 308 309 310 311 312 313 314 315 316
	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);
	}

317
	dns_rdata_init(rdata);
Michael Graff's avatar
Michael Graff committed
318 319 320 321
	return (rdata);
}

static inline void
322
releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
323
	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
324 325 326
}

static inline dns_rdatalist_t *
327
newrdatalist(dns_message_t *msg) {
Michael Graff's avatar
Michael Graff committed
328 329 330
	dns_msgblock_t *msgblock;
	dns_rdatalist_t *rdatalist;

331 332 333
	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
	if (rdatalist != NULL) {
		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
Michael Graff's avatar
Michael Graff committed
334 335 336
		return (rdatalist);
	}

Michael Graff's avatar
Michael Graff committed
337
	msgblock = ISC_LIST_TAIL(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
	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);
}

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
static inline dns_offsets_t *
newoffsets(dns_message_t *msg) {
	dns_msgblock_t *msgblock;
	dns_offsets_t *offsets;

	msgblock = ISC_LIST_TAIL(msg->offsets);
	offsets = msgblock_get(msgblock, dns_offsets_t);
	if (offsets == NULL) {
		msgblock = msgblock_allocate(msg->mctx,
					     sizeof(dns_offsets_t),
					     OFFSET_COUNT);
		if (msgblock == NULL)
			return (NULL);

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

		offsets = msgblock_get(msgblock, dns_offsets_t);
	}

	return (offsets);
}

Michael Graff's avatar
Michael Graff committed
376
static inline void
377
msginitheader(dns_message_t *m) {
Michael Graff's avatar
Michael Graff committed
378 379 380 381
	m->id = 0;
	m->flags = 0;
	m->rcode = 0;
	m->opcode = 0;
Michael Graff's avatar
Michael Graff committed
382
	m->rdclass = 0;
383
}
Michael Graff's avatar
Michael Graff committed
384

385
static inline void
386
msginitprivate(dns_message_t *m) {
387 388 389
	unsigned int i;

	for (i = 0; i < DNS_SECTION_MAX; i++) {
Michael Graff's avatar
Michael Graff committed
390
		m->cursors[i] = NULL;
Michael Graff's avatar
Michael Graff committed
391
		m->counts[i] = 0;
Michael Graff's avatar
Michael Graff committed
392
	}
393
	m->opt = NULL;
394
	m->sig0 = NULL;
395
	m->sig0name = NULL;
396
	m->tsig = NULL;
397
	m->tsigname = NULL;
Michael Graff's avatar
Michael Graff committed
398
	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
399
	m->opt_reserved = 0;
400
	m->sig_reserved = 0;
Michael Graff's avatar
Michael Graff committed
401
	m->reserved = 0;
402
	m->buffer = NULL;
Michael Graff's avatar
Michael Graff committed
403 404
}

405
static inline void
406
msginittsig(dns_message_t *m) {
407 408
	m->tsigstatus = dns_rcode_noerror;
	m->querytsigstatus = dns_rcode_noerror;
409
	m->tsigkey = NULL;
410
	m->tsigctx = NULL;
411 412 413
	m->sigstart = -1;
	m->sig0key = NULL;
	m->sig0status = dns_rcode_noerror;
414
	m->timeadjust = 0;
415 416
}

Michael Graff's avatar
Michael Graff committed
417
/*
418 419
 * Init elements to default state.  Used both when allocating a new element
 * and when resetting one.
Michael Graff's avatar
Michael Graff committed
420
 */
421
static inline void
422
msginit(dns_message_t *m) {
423 424
	msginitheader(m);
	msginitprivate(m);
425
	msginittsig(m);
Bob Halley's avatar
Bob Halley committed
426 427
	m->header_ok = 0;
	m->question_ok = 0;
428
	m->tcp_continuation = 0;
429 430
	m->verified_sig = 0;
	m->verify_attempted = 0;
431 432
	m->order = NULL;
	m->order_arg = NULL;
433 434 435 436 437 438 439
	m->query.base = NULL;
	m->query.length = 0;
	m->free_query = 0;
	m->saved.base = NULL;
	m->saved.length = 0;
	m->free_saved = 0;
	m->querytsig = NULL;
440 441 442 443
}

static inline void
msgresetnames(dns_message_t *msg, unsigned int first_section) {
Michael Graff's avatar
Michael Graff committed
444
	unsigned int i;
445 446
	dns_name_t *name, *next_name;
	dns_rdataset_t *rds, *next_rds;
Michael Graff's avatar
Michael Graff committed
447 448 449 450

	/*
	 * Clean up name lists by calling the rdataset disassociate function.
	 */
451
	for (i = first_section; i < DNS_SECTION_MAX; i++) {
Michael Graff's avatar
Michael Graff committed
452 453 454 455 456 457 458 459 460 461
		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);

462
				INSIST(dns_rdataset_isassociated(rds));
Michael Graff's avatar
Michael Graff committed
463
				dns_rdataset_disassociate(rds);
464
				isc_mempool_put(msg->rdspool, rds);
Michael Graff's avatar
Michael Graff committed
465 466
				rds = next_rds;
			}
467 468
			if (dns_name_dynamic(name))
				dns_name_free(name, msg->mctx);
469
			isc_mempool_put(msg->namepool, name);
470
			name = next_name;
Michael Graff's avatar
Michael Graff committed
471 472
		}
	}
473 474
}

475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
static void
msgresetopt(dns_message_t *msg)
{
	if (msg->opt != NULL) {
		if (msg->opt_reserved > 0) {
			dns_message_renderrelease(msg, msg->opt_reserved);
			msg->opt_reserved = 0;
		}
		INSIST(dns_rdataset_isassociated(msg->opt));
		dns_rdataset_disassociate(msg->opt);
		isc_mempool_put(msg->rdspool, msg->opt);
		msg->opt = NULL;
	}
}

490
static void
491 492 493 494 495
msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
	if (msg->sig_reserved > 0) {
		dns_message_renderrelease(msg, msg->sig_reserved);
		msg->sig_reserved = 0;
	}
496 497
	if (msg->tsig != NULL) {
		INSIST(dns_rdataset_isassociated(msg->tsig));
498
		INSIST(msg->namepool != NULL);
499
		if (replying) {
500 501
			INSIST(msg->querytsig == NULL);
			msg->querytsig = msg->tsig;
502
		} else {
503 504 505 506 507
			dns_rdataset_disassociate(msg->tsig);
			isc_mempool_put(msg->rdspool, msg->tsig);
			if (msg->querytsig != NULL) {
				dns_rdataset_disassociate(msg->querytsig);
				isc_mempool_put(msg->rdspool, msg->querytsig);
508 509
			}
		}
510 511
		if (dns_name_dynamic(msg->tsigname))
			dns_name_free(msg->tsigname, msg->mctx);
512
		isc_mempool_put(msg->namepool, msg->tsigname);
513
		msg->tsig = NULL;
514
		msg->tsigname = NULL;
515
	} else if (msg->querytsig != NULL && !replying) {
516 517
		dns_rdataset_disassociate(msg->querytsig);
		isc_mempool_put(msg->rdspool, msg->querytsig);
518
		msg->querytsig = NULL;
519 520 521 522 523
	}
	if (msg->sig0 != NULL) {
		INSIST(dns_rdataset_isassociated(msg->sig0));
		dns_rdataset_disassociate(msg->sig0);
		isc_mempool_put(msg->rdspool, msg->sig0);
524 525 526
		if (msg->sig0name != NULL) {
			if (dns_name_dynamic(msg->sig0name))
				dns_name_free(msg->sig0name, msg->mctx);
527
			isc_mempool_put(msg->namepool, msg->sig0name);
528
		}
529
		msg->sig0 = NULL;
530
		msg->sig0name = NULL;
531 532 533
	}
}

534 535
/*
 * Free all but one (or everything) for this message.  This is used by
536
 * both dns_message_reset() and dns_message_destroy().
537 538
 */
static void
539
msgreset(dns_message_t *msg, isc_boolean_t everything) {
540
	dns_msgblock_t *msgblock, *next_msgblock;
541
	isc_buffer_t *dynbuf, *next_dynbuf;
542 543 544 545
	dns_rdata_t *rdata;
	dns_rdatalist_t *rdatalist;

	msgresetnames(msg, 0);
546
	msgresetopt(msg);
547
	msgresetsigs(msg, ISC_FALSE);
Bob Halley's avatar
EDNS0  
Bob Halley committed
548

Michael Graff's avatar
Michael Graff committed
549 550 551 552
	/*
	 * Clean up linked lists.
	 */

553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
	/*
	 * Run through the free lists, and just unlink anything found there.
	 * The memory isn't lost since these are part of message blocks we
	 * have allocated.
	 */
	rdata = ISC_LIST_HEAD(msg->freerdata);
	while (rdata != NULL) {
		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
		rdata = ISC_LIST_HEAD(msg->freerdata);
	}
	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
	while (rdatalist != NULL) {
		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
		rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
	}

Michael Graff's avatar
Michael Graff committed
569 570
	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
	INSIST(dynbuf != NULL);
Michael Graff's avatar
Michael Graff committed
571
	if (!everything) {
572
		isc_buffer_clear(dynbuf);
Michael Graff's avatar
Michael Graff committed
573 574 575 576 577
		dynbuf = ISC_LIST_NEXT(dynbuf, link);
	}
	while (dynbuf != NULL) {
		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
578
		isc_buffer_free(&dynbuf);
Michael Graff's avatar
Michael Graff committed
579 580 581 582
		dynbuf = next_dynbuf;
	}

	msgblock = ISC_LIST_HEAD(msg->rdatas);
583
	if (!everything && msgblock != NULL) {
Michael Graff's avatar
Michael Graff committed
584
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
585 586 587 588 589
		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
590
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
Michael Graff's avatar
Michael Graff committed
591 592 593
		msgblock = next_msgblock;
	}

Michael Graff's avatar
Michael Graff committed
594
	/*
Michael Graff's avatar
Michael Graff committed
595
	 * rdatalists could be empty.
Michael Graff's avatar
Michael Graff committed
596 597 598
	 */

	msgblock = ISC_LIST_HEAD(msg->rdatalists);
Michael Graff's avatar
Michael Graff committed
599 600
	if (!everything && msgblock != NULL) {
		msgblock_reset(msgblock);
Michael Graff's avatar
Michael Graff committed
601 602 603 604 605
		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
606
		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
Michael Graff's avatar
Michael Graff committed
607
		msgblock = next_msgblock;
Michael Graff's avatar
Michael Graff committed
608 609
	}

610
	msgblock = ISC_LIST_HEAD(msg->offsets);
611
	if (!everything && msgblock != NULL) {
612 613 614 615 616 617 618 619 620 621
		msgblock_reset(msgblock);
		msgblock = ISC_LIST_NEXT(msgblock, link);
	}
	while (msgblock != NULL) {
		next_msgblock = ISC_LIST_NEXT(msgblock, link);
		ISC_LIST_UNLINK(msg->offsets, msgblock, link);
		msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
		msgblock = next_msgblock;
	}

622
	if (msg->tsigkey != NULL) {
623
		dns_tsigkey_detach(&msg->tsigkey);
624 625 626
		msg->tsigkey = NULL;
	}

627 628 629
	if (msg->tsigctx != NULL)
		dst_context_destroy(&msg->tsigctx);

630
	if (msg->query.base != NULL) {
631 632 633
		if (msg->free_query != 0)
			isc_mem_put(msg->mctx, msg->query.base,
				    msg->query.length);
634 635
		msg->query.base = NULL;
		msg->query.length = 0;
636
	}
637

638
	if (msg->saved.base != NULL) {
639 640 641
		if (msg->free_saved != 0)
			isc_mem_put(msg->mctx, msg->saved.base,
				    msg->saved.length);
642 643
		msg->saved.base = NULL;
		msg->saved.length = 0;
Brian Wellington's avatar
Brian Wellington committed
644 645
	}

646 647 648 649 650 651
	/*
	 * cleanup the buffer cleanup list
	 */
	dynbuf = ISC_LIST_HEAD(msg->cleanup);
	while (dynbuf != NULL) {
		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
652
		ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
653 654 655 656
		isc_buffer_free(&dynbuf);
		dynbuf = next_dynbuf;
	}

Michael Graff's avatar
Michael Graff committed
657 658 659
	/*
	 * Set other bits to normal default values.
	 */
Michael Graff's avatar
Michael Graff committed
660 661
	if (!everything)
		msginit(msg);
662 663 664

	ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
	ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
Michael Graff's avatar
Michael Graff committed
665 666
}

667 668 669 670 671 672 673 674 675 676 677 678 679
static unsigned int
spacefortsig(dns_tsigkey_t *key, int otherlen) {
	isc_region_t r1, r2;
	unsigned int x;
	isc_result_t result;

	/*
	 * The space required for an TSIG record is:
	 *
	 *	n1 bytes for the name
	 *	2 bytes for the type
	 *	2 bytes for the class
	 *	4 bytes for the ttl
680 681
	 *	2 bytes for the rdlength
	 *	n2 bytes for the algorithm name
682 683 684 685 686 687 688 689 690
	 *	6 bytes for the time signed
	 *	2 bytes for the fudge
	 *	2 bytes for the MAC size
	 *	x bytes for the MAC
	 *	2 bytes for the original id
	 *	2 bytes for the error
	 *	2 bytes for the other data length
	 *	y bytes for the other data (at most)
	 * ---------------------------------
691
	 *     26 + n1 + n2 + x + y bytes
692 693 694
	 */

	dns_name_toregion(&key->name, &r1);
Brian Wellington's avatar
Brian Wellington committed
695
	dns_name_toregion(key->algorithm, &r2);
696 697 698 699 700 701 702
	if (key->key == NULL)
		x = 0;
	else {
		result = dst_key_sigsize(key->key, &x);
		if (result != ISC_R_SUCCESS)
			x = 0;
	}
703
	return (26 + r1.length + r2.length + x + otherlen);
704 705
}

706
isc_result_t
707
dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
Michael Graff's avatar
Michael Graff committed
708 709
{
	dns_message_t *m;
710
	isc_result_t result;
711
	isc_buffer_t *dynbuf;
Michael Graff's avatar
Michael Graff committed
712 713 714
	unsigned int i;

	REQUIRE(mctx != NULL);
715 716
	REQUIRE(msgp != NULL);
	REQUIRE(*msgp == NULL);
Michael Graff's avatar
Michael Graff committed
717 718
	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
		|| intent == DNS_MESSAGE_INTENTRENDER);
Michael Graff's avatar
Michael Graff committed
719 720 721

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

724 725 726 727 728
	/*
	 * No allocations until further notice.  Just initialize all lists
	 * and other members that are freed in the cleanup phase here.
	 */

729
	m->magic = DNS_MESSAGE_MAGIC;
Michael Graff's avatar
Michael Graff committed
730 731
	m->from_to_wire = intent;
	msginit(m);
732

733
	for (i = 0; i < DNS_SECTION_MAX; i++)
Michael Graff's avatar
Michael Graff committed
734 735
		ISC_LIST_INIT(m->sections[i]);
	m->mctx = mctx;
736

Michael Graff's avatar
Michael Graff committed
737
	ISC_LIST_INIT(m->scratchpad);
738 739
	ISC_LIST_INIT(m->cleanup);
	m->namepool = NULL;
740
	m->rdspool = NULL;
Michael Graff's avatar
Michael Graff committed
741 742
	ISC_LIST_INIT(m->rdatas);
	ISC_LIST_INIT(m->rdatalists);
743
	ISC_LIST_INIT(m->offsets);
744 745
	ISC_LIST_INIT(m->freerdata);
	ISC_LIST_INIT(m->freerdatalist);
Michael Graff's avatar
Michael Graff committed
746

747 748 749 750 751 752 753 754
	/*
	 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
	 */

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

757 758 759 760 761
	result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
				    &m->rdspool);
	if (result != ISC_R_SUCCESS)
		goto cleanup;
	isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
Michael Graff's avatar
Michael Graff committed
762
	isc_mempool_setname(m->rdspool, "msg:rdataset");
763

Michael Graff's avatar
Michael Graff committed
764
	dynbuf = NULL;
765
	result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
766 767
	if (result != ISC_R_SUCCESS)
		goto cleanup;
Michael Graff's avatar
Michael Graff committed
768 769
	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);

770 771
	m->cctx = NULL;

772
	*msgp = m;
773
	return (ISC_R_SUCCESS);
Michael Graff's avatar
Michael Graff committed
774 775 776 777

	/*
	 * Cleanup for error returns.
	 */
778
 cleanup:
Michael Graff's avatar
Michael Graff committed
779
	dynbuf = ISC_LIST_HEAD(m->scratchpad);
780 781
	if (dynbuf != NULL) {
		ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
782
		isc_buffer_free(&dynbuf);
783
	}
784 785
	if (m->namepool != NULL)
		isc_mempool_destroy(&m->namepool);
786 787
	if (m->rdspool != NULL)
		isc_mempool_destroy(&m->rdspool);
Michael Graff's avatar
Michael Graff committed
788 789 790
	m->magic = 0;
	isc_mem_put(mctx, m, sizeof(dns_message_t));

791
	return (ISC_R_NOMEMORY);
Michael Graff's avatar
Michael Graff committed
792 793 794
}

void
795
dns_message_reset(dns_message_t *msg, unsigned int intent) {
796 797 798 799
	REQUIRE(DNS_MESSAGE_VALID(msg));
	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
		|| intent == DNS_MESSAGE_INTENTRENDER);

Michael Graff's avatar
Michael Graff committed
800
	msgreset(msg, ISC_FALSE);
801
	msg->from_to_wire = intent;
Michael Graff's avatar
Michael Graff committed
802 803 804
}

void
805
dns_message_destroy(dns_message_t **msgp) {
Michael Graff's avatar
Michael Graff committed
806 807
	dns_message_t *msg;

808
	REQUIRE(msgp != NULL);
809
	REQUIRE(DNS_MESSAGE_VALID(*msgp));
Michael Graff's avatar
Michael Graff committed
810

811 812
	msg = *msgp;
	*msgp = NULL;
Michael Graff's avatar
Michael Graff committed
813 814

	msgreset(msg, ISC_TRUE);
815
	isc_mempool_destroy(&msg->namepool);
816
	isc_mempool_destroy(&msg->rdspool);
Michael Graff's avatar
Michael Graff committed
817 818 819 820
	msg->magic = 0;
	isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
}

821
static isc_result_t
822
findname(dns_name_t **foundname, dns_name_t *target,
823 824 825 826
	 dns_namelist_t *section)
{
	dns_name_t *curr;

827 828
	for (curr = ISC_LIST_TAIL(*section);
	     curr != NULL;
829 830 831 832 833 834 835 836 837 838 839
	     curr = ISC_LIST_PREV(curr, link)) {
		if (dns_name_equal(curr, target)) {
			if (foundname != NULL)
				*foundname = curr;
			return (ISC_R_SUCCESS);
		}
	}

	return (ISC_R_NOTFOUND);
}

840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
isc_result_t
dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
		 dns_rdatatype_t type, dns_rdatatype_t covers,
		 dns_rdataset_t **rdataset)
{
	dns_rdataset_t *curr;

	if (rdataset != NULL) {
		REQUIRE(*rdataset == NULL);
	}

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

	return (ISC_R_NOTFOUND);
}

865
isc_result_t
866 867
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
868 869 870
{
	dns_rdataset_t *curr;

871
	REQUIRE(name != NULL);
872 873 874 875
	if (rdataset != NULL) {
		REQUIRE(*rdataset == NULL);
	}

876 877
	for (curr = ISC_LIST_TAIL(name->list);
	     curr != NULL;
Michael Graff's avatar
Michael Graff committed
878
	     curr = ISC_LIST_PREV(curr, link)) {
Bob Halley's avatar
Bob Halley committed
879
		if (curr->type == type && curr->covers == covers) {
Michael Graff's avatar
Michael Graff committed
880 881
			if (rdataset != NULL)
				*rdataset = curr;
882
			return (ISC_R_SUCCESS);
Michael Graff's avatar
Michael Graff committed
883 884 885
		}
	}

886
	return (ISC_R_NOTFOUND);
Michael Graff's avatar
Michael Graff committed
887 888 889 890 891
}

/*
 * Read a name from buffer "source".
 */
892
static isc_result_t
Michael Graff's avatar
Michael Graff committed
893 894 895 896
getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
	dns_decompress_t *dctx)
{
	isc_buffer_t *scratch;
897
	isc_result_t result;
Michael Graff's avatar
Michael Graff committed
898 899 900 901
	unsigned int tries;

	scratch = currentbuffer(msg);

Michael Graff's avatar
Michael Graff committed
902 903 904 905
	/*
	 * First try:  use current buffer.
	 * Second try:  allocate a new buffer and use that.
	 */
Michael Graff's avatar
Michael Graff committed
906 907 908 909 910
	tries = 0;
	while (tries < 2) {
		result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
					   scratch);

911
		if (result == ISC_R_NOSPACE) {
Michael Graff's avatar
Michael Graff committed
912 913
			tries++;

914
			result = newbuffer(msg, SCRATCHPAD_SIZE);
915
			if (result != ISC_R_SUCCESS)
Michael Graff's avatar
Michael Graff committed
916 917 918
				return (result);

			scratch = currentbuffer(msg);
919
			dns_name_reset(name);
Michael Graff's avatar
Michael Graff committed
920 921 922 923 924
		} else {
			return (result);
		}
	}

Michael Graff's avatar
Michael Graff committed
925
	INSIST(0);  /* Cannot get here... */
926
	return (ISC_R_UNEXPECTED);
Michael Graff's avatar
Michael Graff committed
927 928
}

929
static isc_result_t
David Lawrence's avatar
David Lawrence committed
930 931 932
getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
	 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
	 unsigned int rdatalen, dns_rdata_t *rdata)
933 934
{
	isc_buffer_t *scratch;
935
	isc_result_t result;
936
	unsigned int tries;
937
	unsigned int trysize;
938 939 940 941 942

	scratch = currentbuffer(msg);

	isc_buffer_setactive(source, rdatalen);

Michael Graff's avatar
Michael Graff committed
943 944
	/*
	 * First try:  use current buffer.
945 946 947 948
	 * 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
949
	 */
950
	tries = 0;
951
	trysize = 0;
952
	/* XXX possibly change this to a while (tries < 2) loop */
953
	for (;;) {
954
		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
955
					    source, dctx, 0,
956 957
					    scratch);

958
		if (result == ISC_R_NOSPACE) {
959 960 961 962 963 964 965 966 967 968 969
			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;
			}
970
			tries++;
971
			result = newbuffer(msg, trysize);
972
			if (result != ISC_R_SUCCESS)
973 974 975 976 977 978 979 980
				return (result);

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

982 983 984 985 986 987 988 989 990 991
#define DO_FORMERR					\
	do {						\
		if (best_effort)			\
			seen_problem = ISC_TRUE;	\
		else {					\
			result = DNS_R_FORMERR;		\
			goto cleanup;			\
		}					\
	} while (0)

992
static isc_result_t
993 994
getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
	     unsigned int options)
Michael Graff's avatar
Michael Graff committed
995 996 997 998 999
{
	isc_region_t r;
	unsigned int count;
	dns_name_t *name;
	dns_name_t *name2;