1 /*
2  * Copyright (C) 2004-2016  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /*! \file */
19 
20 /***
21  *** Imports
22  ***/
23 
24 #include <config.h>
25 #include <ctype.h>
26 
27 #include <isc/buffer.h>
28 #include <isc/mem.h>
29 #include <isc/print.h>
30 #include <isc/string.h>		/* Required for HP/UX (and others?) */
31 #include <isc/util.h>
32 
33 #include <dns/dnssec.h>
34 #include <dns/keyvalues.h>
35 #include <dns/log.h>
36 #include <dns/masterdump.h>
37 #include <dns/message.h>
38 #include <dns/opcode.h>
39 #include <dns/rcode.h>
40 #include <dns/rdata.h>
41 #include <dns/rdatalist.h>
42 #include <dns/rdataset.h>
43 #include <dns/rdatastruct.h>
44 #include <dns/result.h>
45 #include <dns/tsig.h>
46 #include <dns/ttl.h>
47 #include <dns/view.h>
48 
49 #ifdef SKAN_MSG_DEBUG
50 static void
hexdump(const char * msg,const char * msg2,void * base,size_t len)51 hexdump(const char *msg, const char *msg2, void *base, size_t len) {
52 	unsigned char *p;
53 	unsigned int cnt;
54 
55 	p = base;
56 	cnt = 0;
57 
58 	printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);
59 
60 	while (cnt < len) {
61 		if (cnt % 16 == 0)
62 			printf("%p: ", p);
63 		else if (cnt % 8 == 0)
64 			printf(" |");
65 		printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
66 		p++;
67 		cnt++;
68 
69 		if (cnt % 16 == 0)
70 			printf("\n");
71 	}
72 
73 	if (cnt % 16 != 0)
74 		printf("\n");
75 }
76 #endif
77 
78 #define DNS_MESSAGE_OPCODE_MASK		0x7800U
79 #define DNS_MESSAGE_OPCODE_SHIFT	11
80 #define DNS_MESSAGE_RCODE_MASK		0x000fU
81 #define DNS_MESSAGE_FLAG_MASK		0x8ff0U
82 #define DNS_MESSAGE_EDNSRCODE_MASK	0xff000000U
83 #define DNS_MESSAGE_EDNSRCODE_SHIFT	24
84 #define DNS_MESSAGE_EDNSVERSION_MASK	0x00ff0000U
85 #define DNS_MESSAGE_EDNSVERSION_SHIFT	16
86 
87 #define VALID_NAMED_SECTION(s)  (((s) > DNS_SECTION_ANY) \
88 				 && ((s) < DNS_SECTION_MAX))
89 #define VALID_SECTION(s)	(((s) >= DNS_SECTION_ANY) \
90 				 && ((s) < DNS_SECTION_MAX))
91 #define ADD_STRING(b, s)	{if (strlen(s) >= \
92 				   isc_buffer_availablelength(b)) \
93 				       return(ISC_R_NOSPACE); else \
94 				       isc_buffer_putstr(b, s);}
95 #define VALID_PSEUDOSECTION(s)	(((s) >= DNS_PSEUDOSECTION_ANY) \
96 				 && ((s) < DNS_PSEUDOSECTION_MAX))
97 
98 #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
99 
100 /*%
101  * This is the size of each individual scratchpad buffer, and the numbers
102  * of various block allocations used within the server.
103  * XXXMLG These should come from a config setting.
104  */
105 #define SCRATCHPAD_SIZE		512
106 #define NAME_COUNT		  8
107 #define OFFSET_COUNT		  4
108 #define RDATA_COUNT		  8
109 #define RDATALIST_COUNT		  8
110 #define RDATASET_COUNT		 RDATALIST_COUNT
111 
112 /*%
113  * Text representation of the different items, for message_totext
114  * functions.
115  */
116 static const char *sectiontext[] = {
117 	"QUESTION",
118 	"ANSWER",
119 	"AUTHORITY",
120 	"ADDITIONAL"
121 };
122 
123 static const char *updsectiontext[] = {
124 	"ZONE",
125 	"PREREQUISITE",
126 	"UPDATE",
127 	"ADDITIONAL"
128 };
129 
130 static const char *opcodetext[] = {
131 	"QUERY",
132 	"IQUERY",
133 	"STATUS",
134 	"RESERVED3",
135 	"NOTIFY",
136 	"UPDATE",
137 	"RESERVED6",
138 	"RESERVED7",
139 	"RESERVED8",
140 	"RESERVED9",
141 	"RESERVED10",
142 	"RESERVED11",
143 	"RESERVED12",
144 	"RESERVED13",
145 	"RESERVED14",
146 	"RESERVED15"
147 };
148 
149 /*%
150  * "helper" type, which consists of a block of some type, and is linkable.
151  * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
152  * size, or the allocated elements will not be aligned correctly.
153  */
154 struct dns_msgblock {
155 	unsigned int			count;
156 	unsigned int			remaining;
157 	ISC_LINK(dns_msgblock_t)	link;
158 }; /* dynamically sized */
159 
160 static inline dns_msgblock_t *
161 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
162 
163 #define msgblock_get(block, type) \
164 	((type *)msgblock_internalget(block, sizeof(type)))
165 
166 static inline void *
167 msgblock_internalget(dns_msgblock_t *, unsigned int);
168 
169 static inline void
170 msgblock_reset(dns_msgblock_t *);
171 
172 static inline void
173 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
174 
175 /*
176  * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
177  * is free, return NULL.
178  */
179 static inline dns_msgblock_t *
msgblock_allocate(isc_mem_t * mctx,unsigned int sizeof_type,unsigned int count)180 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
181 		  unsigned int count)
182 {
183 	dns_msgblock_t *block;
184 	unsigned int length;
185 
186 	length = sizeof(dns_msgblock_t) + (sizeof_type * count);
187 
188 	block = isc_mem_get(mctx, length);
189 	if (block == NULL)
190 		return (NULL);
191 
192 	block->count = count;
193 	block->remaining = count;
194 
195 	ISC_LINK_INIT(block, link);
196 
197 	return (block);
198 }
199 
200 /*
201  * Return an element from the msgblock.  If no more are available, return
202  * NULL.
203  */
204 static inline void *
msgblock_internalget(dns_msgblock_t * block,unsigned int sizeof_type)205 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
206 	void *ptr;
207 
208 	if (block == NULL || block->remaining == 0)
209 		return (NULL);
210 
211 	block->remaining--;
212 
213 	ptr = (((unsigned char *)block)
214 	       + sizeof(dns_msgblock_t)
215 	       + (sizeof_type * block->remaining));
216 
217 	return (ptr);
218 }
219 
220 static inline void
msgblock_reset(dns_msgblock_t * block)221 msgblock_reset(dns_msgblock_t *block) {
222 	block->remaining = block->count;
223 }
224 
225 /*
226  * Release memory associated with a message block.
227  */
228 static inline void
msgblock_free(isc_mem_t * mctx,dns_msgblock_t * block,unsigned int sizeof_type)229 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
230 {
231 	unsigned int length;
232 
233 	length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
234 
235 	isc_mem_put(mctx, block, length);
236 }
237 
238 /*
239  * Allocate a new dynamic buffer, and attach it to this message as the
240  * "current" buffer.  (which is always the last on the list, for our
241  * uses)
242  */
243 static inline isc_result_t
newbuffer(dns_message_t * msg,unsigned int size)244 newbuffer(dns_message_t *msg, unsigned int size) {
245 	isc_result_t result;
246 	isc_buffer_t *dynbuf;
247 
248 	dynbuf = NULL;
249 	result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
250 	if (result != ISC_R_SUCCESS)
251 		return (ISC_R_NOMEMORY);
252 
253 	ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
254 	return (ISC_R_SUCCESS);
255 }
256 
257 static inline isc_buffer_t *
currentbuffer(dns_message_t * msg)258 currentbuffer(dns_message_t *msg) {
259 	isc_buffer_t *dynbuf;
260 
261 	dynbuf = ISC_LIST_TAIL(msg->scratchpad);
262 	INSIST(dynbuf != NULL);
263 
264 	return (dynbuf);
265 }
266 
267 static inline void
releaserdata(dns_message_t * msg,dns_rdata_t * rdata)268 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
269 	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
270 }
271 
272 static inline dns_rdata_t *
newrdata(dns_message_t * msg)273 newrdata(dns_message_t *msg) {
274 	dns_msgblock_t *msgblock;
275 	dns_rdata_t *rdata;
276 
277 	rdata = ISC_LIST_HEAD(msg->freerdata);
278 	if (rdata != NULL) {
279 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
280 		return (rdata);
281 	}
282 
283 	msgblock = ISC_LIST_TAIL(msg->rdatas);
284 	rdata = msgblock_get(msgblock, dns_rdata_t);
285 	if (rdata == NULL) {
286 		msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
287 					     RDATA_COUNT);
288 		if (msgblock == NULL)
289 			return (NULL);
290 
291 		ISC_LIST_APPEND(msg->rdatas, msgblock, link);
292 
293 		rdata = msgblock_get(msgblock, dns_rdata_t);
294 	}
295 
296 	dns_rdata_init(rdata);
297 	return (rdata);
298 }
299 
300 static inline void
releaserdatalist(dns_message_t * msg,dns_rdatalist_t * rdatalist)301 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
302 	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
303 }
304 
305 static inline dns_rdatalist_t *
newrdatalist(dns_message_t * msg)306 newrdatalist(dns_message_t *msg) {
307 	dns_msgblock_t *msgblock;
308 	dns_rdatalist_t *rdatalist;
309 
310 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
311 	if (rdatalist != NULL) {
312 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
313 		goto out;
314 	}
315 
316 	msgblock = ISC_LIST_TAIL(msg->rdatalists);
317 	rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
318 	if (rdatalist == NULL) {
319 		msgblock = msgblock_allocate(msg->mctx,
320 					     sizeof(dns_rdatalist_t),
321 					     RDATALIST_COUNT);
322 		if (msgblock == NULL)
323 			return (NULL);
324 
325 		ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
326 
327 		rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
328 	}
329  out:
330 	if (rdatalist != NULL)
331 		dns_rdatalist_init(rdatalist);
332 
333 	return (rdatalist);
334 }
335 
336 static inline dns_offsets_t *
newoffsets(dns_message_t * msg)337 newoffsets(dns_message_t *msg) {
338 	dns_msgblock_t *msgblock;
339 	dns_offsets_t *offsets;
340 
341 	msgblock = ISC_LIST_TAIL(msg->offsets);
342 	offsets = msgblock_get(msgblock, dns_offsets_t);
343 	if (offsets == NULL) {
344 		msgblock = msgblock_allocate(msg->mctx,
345 					     sizeof(dns_offsets_t),
346 					     OFFSET_COUNT);
347 		if (msgblock == NULL)
348 			return (NULL);
349 
350 		ISC_LIST_APPEND(msg->offsets, msgblock, link);
351 
352 		offsets = msgblock_get(msgblock, dns_offsets_t);
353 	}
354 
355 	return (offsets);
356 }
357 
358 static inline void
msginitheader(dns_message_t * m)359 msginitheader(dns_message_t *m) {
360 	m->id = 0;
361 	m->flags = 0;
362 	m->rcode = 0;
363 	m->opcode = 0;
364 	m->rdclass = 0;
365 }
366 
367 static inline void
msginitprivate(dns_message_t * m)368 msginitprivate(dns_message_t *m) {
369 	unsigned int i;
370 
371 	for (i = 0; i < DNS_SECTION_MAX; i++) {
372 		m->cursors[i] = NULL;
373 		m->counts[i] = 0;
374 	}
375 	m->opt = NULL;
376 	m->sig0 = NULL;
377 	m->sig0name = NULL;
378 	m->tsig = NULL;
379 	m->tsigname = NULL;
380 	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
381 	m->opt_reserved = 0;
382 	m->sig_reserved = 0;
383 	m->reserved = 0;
384 	m->buffer = NULL;
385 }
386 
387 static inline void
msginittsig(dns_message_t * m)388 msginittsig(dns_message_t *m) {
389 	m->tsigstatus = dns_rcode_noerror;
390 	m->querytsigstatus = dns_rcode_noerror;
391 	m->tsigkey = NULL;
392 	m->tsigctx = NULL;
393 	m->sigstart = -1;
394 	m->sig0key = NULL;
395 	m->sig0status = dns_rcode_noerror;
396 	m->timeadjust = 0;
397 }
398 
399 /*
400  * Init elements to default state.  Used both when allocating a new element
401  * and when resetting one.
402  */
403 static inline void
msginit(dns_message_t * m)404 msginit(dns_message_t *m) {
405 	msginitheader(m);
406 	msginitprivate(m);
407 	msginittsig(m);
408 	m->header_ok = 0;
409 	m->question_ok = 0;
410 	m->tcp_continuation = 0;
411 	m->verified_sig = 0;
412 	m->verify_attempted = 0;
413 	m->order = NULL;
414 	m->order_arg = NULL;
415 	m->query.base = NULL;
416 	m->query.length = 0;
417 	m->free_query = 0;
418 	m->saved.base = NULL;
419 	m->saved.length = 0;
420 	m->free_saved = 0;
421 	m->tkey = 0;
422 	m->rdclass_set = 0;
423 	m->querytsig = NULL;
424 }
425 
426 static inline void
msgresetnames(dns_message_t * msg,unsigned int first_section)427 msgresetnames(dns_message_t *msg, unsigned int first_section) {
428 	unsigned int i;
429 	dns_name_t *name, *next_name;
430 	dns_rdataset_t *rds, *next_rds;
431 
432 	/*
433 	 * Clean up name lists by calling the rdataset disassociate function.
434 	 */
435 	for (i = first_section; i < DNS_SECTION_MAX; i++) {
436 		name = ISC_LIST_HEAD(msg->sections[i]);
437 		while (name != NULL) {
438 			next_name = ISC_LIST_NEXT(name, link);
439 			ISC_LIST_UNLINK(msg->sections[i], name, link);
440 
441 			rds = ISC_LIST_HEAD(name->list);
442 			while (rds != NULL) {
443 				next_rds = ISC_LIST_NEXT(rds, link);
444 				ISC_LIST_UNLINK(name->list, rds, link);
445 
446 				INSIST(dns_rdataset_isassociated(rds));
447 				dns_rdataset_disassociate(rds);
448 				isc_mempool_put(msg->rdspool, rds);
449 				rds = next_rds;
450 			}
451 			if (dns_name_dynamic(name))
452 				dns_name_free(name, msg->mctx);
453 			isc_mempool_put(msg->namepool, name);
454 			name = next_name;
455 		}
456 	}
457 }
458 
459 static void
msgresetopt(dns_message_t * msg)460 msgresetopt(dns_message_t *msg)
461 {
462 	if (msg->opt != NULL) {
463 		if (msg->opt_reserved > 0) {
464 			dns_message_renderrelease(msg, msg->opt_reserved);
465 			msg->opt_reserved = 0;
466 		}
467 		INSIST(dns_rdataset_isassociated(msg->opt));
468 		dns_rdataset_disassociate(msg->opt);
469 		isc_mempool_put(msg->rdspool, msg->opt);
470 		msg->opt = NULL;
471 	}
472 }
473 
474 static void
msgresetsigs(dns_message_t * msg,isc_boolean_t replying)475 msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
476 	if (msg->sig_reserved > 0) {
477 		dns_message_renderrelease(msg, msg->sig_reserved);
478 		msg->sig_reserved = 0;
479 	}
480 	if (msg->tsig != NULL) {
481 		INSIST(dns_rdataset_isassociated(msg->tsig));
482 		INSIST(msg->namepool != NULL);
483 		if (replying) {
484 			INSIST(msg->querytsig == NULL);
485 			msg->querytsig = msg->tsig;
486 		} else {
487 			dns_rdataset_disassociate(msg->tsig);
488 			isc_mempool_put(msg->rdspool, msg->tsig);
489 			if (msg->querytsig != NULL) {
490 				dns_rdataset_disassociate(msg->querytsig);
491 				isc_mempool_put(msg->rdspool, msg->querytsig);
492 			}
493 		}
494 		if (dns_name_dynamic(msg->tsigname))
495 			dns_name_free(msg->tsigname, msg->mctx);
496 		isc_mempool_put(msg->namepool, msg->tsigname);
497 		msg->tsig = NULL;
498 		msg->tsigname = NULL;
499 	} else if (msg->querytsig != NULL && !replying) {
500 		dns_rdataset_disassociate(msg->querytsig);
501 		isc_mempool_put(msg->rdspool, msg->querytsig);
502 		msg->querytsig = NULL;
503 	}
504 	if (msg->sig0 != NULL) {
505 		INSIST(dns_rdataset_isassociated(msg->sig0));
506 		dns_rdataset_disassociate(msg->sig0);
507 		isc_mempool_put(msg->rdspool, msg->sig0);
508 		if (msg->sig0name != NULL) {
509 			if (dns_name_dynamic(msg->sig0name))
510 				dns_name_free(msg->sig0name, msg->mctx);
511 			isc_mempool_put(msg->namepool, msg->sig0name);
512 		}
513 		msg->sig0 = NULL;
514 		msg->sig0name = NULL;
515 	}
516 }
517 
518 /*
519  * Free all but one (or everything) for this message.  This is used by
520  * both dns_message_reset() and dns_message_destroy().
521  */
522 static void
msgreset(dns_message_t * msg,isc_boolean_t everything)523 msgreset(dns_message_t *msg, isc_boolean_t everything) {
524 	dns_msgblock_t *msgblock, *next_msgblock;
525 	isc_buffer_t *dynbuf, *next_dynbuf;
526 	dns_rdata_t *rdata;
527 	dns_rdatalist_t *rdatalist;
528 
529 	msgresetnames(msg, 0);
530 	msgresetopt(msg);
531 	msgresetsigs(msg, ISC_FALSE);
532 
533 	/*
534 	 * Clean up linked lists.
535 	 */
536 
537 	/*
538 	 * Run through the free lists, and just unlink anything found there.
539 	 * The memory isn't lost since these are part of message blocks we
540 	 * have allocated.
541 	 */
542 	rdata = ISC_LIST_HEAD(msg->freerdata);
543 	while (rdata != NULL) {
544 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
545 		rdata = ISC_LIST_HEAD(msg->freerdata);
546 	}
547 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
548 	while (rdatalist != NULL) {
549 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
550 		rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
551 	}
552 
553 	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
554 	INSIST(dynbuf != NULL);
555 	if (!everything) {
556 		isc_buffer_clear(dynbuf);
557 		dynbuf = ISC_LIST_NEXT(dynbuf, link);
558 	}
559 	while (dynbuf != NULL) {
560 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
561 		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
562 		isc_buffer_free(&dynbuf);
563 		dynbuf = next_dynbuf;
564 	}
565 
566 	msgblock = ISC_LIST_HEAD(msg->rdatas);
567 	if (!everything && msgblock != NULL) {
568 		msgblock_reset(msgblock);
569 		msgblock = ISC_LIST_NEXT(msgblock, link);
570 	}
571 	while (msgblock != NULL) {
572 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
573 		ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
574 		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
575 		msgblock = next_msgblock;
576 	}
577 
578 	/*
579 	 * rdatalists could be empty.
580 	 */
581 
582 	msgblock = ISC_LIST_HEAD(msg->rdatalists);
583 	if (!everything && msgblock != NULL) {
584 		msgblock_reset(msgblock);
585 		msgblock = ISC_LIST_NEXT(msgblock, link);
586 	}
587 	while (msgblock != NULL) {
588 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
589 		ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
590 		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
591 		msgblock = next_msgblock;
592 	}
593 
594 	msgblock = ISC_LIST_HEAD(msg->offsets);
595 	if (!everything && msgblock != NULL) {
596 		msgblock_reset(msgblock);
597 		msgblock = ISC_LIST_NEXT(msgblock, link);
598 	}
599 	while (msgblock != NULL) {
600 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
601 		ISC_LIST_UNLINK(msg->offsets, msgblock, link);
602 		msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
603 		msgblock = next_msgblock;
604 	}
605 
606 	if (msg->tsigkey != NULL) {
607 		dns_tsigkey_detach(&msg->tsigkey);
608 		msg->tsigkey = NULL;
609 	}
610 
611 	if (msg->tsigctx != NULL)
612 		dst_context_destroy(&msg->tsigctx);
613 
614 	if (msg->query.base != NULL) {
615 		if (msg->free_query != 0)
616 			isc_mem_put(msg->mctx, msg->query.base,
617 				    msg->query.length);
618 		msg->query.base = NULL;
619 		msg->query.length = 0;
620 	}
621 
622 	if (msg->saved.base != NULL) {
623 		if (msg->free_saved != 0)
624 			isc_mem_put(msg->mctx, msg->saved.base,
625 				    msg->saved.length);
626 		msg->saved.base = NULL;
627 		msg->saved.length = 0;
628 	}
629 
630 	/*
631 	 * cleanup the buffer cleanup list
632 	 */
633 	dynbuf = ISC_LIST_HEAD(msg->cleanup);
634 	while (dynbuf != NULL) {
635 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
636 		ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
637 		isc_buffer_free(&dynbuf);
638 		dynbuf = next_dynbuf;
639 	}
640 
641 	/*
642 	 * Set other bits to normal default values.
643 	 */
644 	if (!everything)
645 		msginit(msg);
646 
647 	ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
648 	ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
649 }
650 
651 static unsigned int
spacefortsig(dns_tsigkey_t * key,int otherlen)652 spacefortsig(dns_tsigkey_t *key, int otherlen) {
653 	isc_region_t r1, r2;
654 	unsigned int x;
655 	isc_result_t result;
656 
657 	/*
658 	 * The space required for an TSIG record is:
659 	 *
660 	 *	n1 bytes for the name
661 	 *	2 bytes for the type
662 	 *	2 bytes for the class
663 	 *	4 bytes for the ttl
664 	 *	2 bytes for the rdlength
665 	 *	n2 bytes for the algorithm name
666 	 *	6 bytes for the time signed
667 	 *	2 bytes for the fudge
668 	 *	2 bytes for the MAC size
669 	 *	x bytes for the MAC
670 	 *	2 bytes for the original id
671 	 *	2 bytes for the error
672 	 *	2 bytes for the other data length
673 	 *	y bytes for the other data (at most)
674 	 * ---------------------------------
675 	 *     26 + n1 + n2 + x + y bytes
676 	 */
677 
678 	dns_name_toregion(&key->name, &r1);
679 	dns_name_toregion(key->algorithm, &r2);
680 	if (key->key == NULL)
681 		x = 0;
682 	else {
683 		result = dst_key_sigsize(key->key, &x);
684 		if (result != ISC_R_SUCCESS)
685 			x = 0;
686 	}
687 	return (26 + r1.length + r2.length + x + otherlen);
688 }
689 
690 isc_result_t
dns_message_create(isc_mem_t * mctx,unsigned int intent,dns_message_t ** msgp)691 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
692 {
693 	dns_message_t *m;
694 	isc_result_t result;
695 	isc_buffer_t *dynbuf;
696 	unsigned int i;
697 
698 	REQUIRE(mctx != NULL);
699 	REQUIRE(msgp != NULL);
700 	REQUIRE(*msgp == NULL);
701 	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
702 		|| intent == DNS_MESSAGE_INTENTRENDER);
703 
704 	m = isc_mem_get(mctx, sizeof(dns_message_t));
705 	if (m == NULL)
706 		return (ISC_R_NOMEMORY);
707 
708 	/*
709 	 * No allocations until further notice.  Just initialize all lists
710 	 * and other members that are freed in the cleanup phase here.
711 	 */
712 
713 	m->magic = DNS_MESSAGE_MAGIC;
714 	m->from_to_wire = intent;
715 	msginit(m);
716 
717 	for (i = 0; i < DNS_SECTION_MAX; i++)
718 		ISC_LIST_INIT(m->sections[i]);
719 
720 	m->mctx = NULL;
721 	isc_mem_attach(mctx, &m->mctx);
722 
723 	ISC_LIST_INIT(m->scratchpad);
724 	ISC_LIST_INIT(m->cleanup);
725 	m->namepool = NULL;
726 	m->rdspool = NULL;
727 	ISC_LIST_INIT(m->rdatas);
728 	ISC_LIST_INIT(m->rdatalists);
729 	ISC_LIST_INIT(m->offsets);
730 	ISC_LIST_INIT(m->freerdata);
731 	ISC_LIST_INIT(m->freerdatalist);
732 
733 	/*
734 	 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
735 	 */
736 
737 	result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
738 	if (result != ISC_R_SUCCESS)
739 		goto cleanup;
740 	isc_mempool_setfreemax(m->namepool, NAME_COUNT);
741 	isc_mempool_setname(m->namepool, "msg:names");
742 
743 	result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
744 				    &m->rdspool);
745 	if (result != ISC_R_SUCCESS)
746 		goto cleanup;
747 	isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
748 	isc_mempool_setname(m->rdspool, "msg:rdataset");
749 
750 	dynbuf = NULL;
751 	result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
752 	if (result != ISC_R_SUCCESS)
753 		goto cleanup;
754 	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
755 
756 	m->cctx = NULL;
757 
758 	*msgp = m;
759 	return (ISC_R_SUCCESS);
760 
761 	/*
762 	 * Cleanup for error returns.
763 	 */
764  cleanup:
765 	dynbuf = ISC_LIST_HEAD(m->scratchpad);
766 	if (dynbuf != NULL) {
767 		ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
768 		isc_buffer_free(&dynbuf);
769 	}
770 	if (m->namepool != NULL)
771 		isc_mempool_destroy(&m->namepool);
772 	if (m->rdspool != NULL)
773 		isc_mempool_destroy(&m->rdspool);
774 	m->magic = 0;
775 	isc_mem_putanddetach(&mctx, m, sizeof(dns_message_t));
776 
777 	return (ISC_R_NOMEMORY);
778 }
779 
780 void
dns_message_reset(dns_message_t * msg,unsigned int intent)781 dns_message_reset(dns_message_t *msg, unsigned int intent) {
782 	REQUIRE(DNS_MESSAGE_VALID(msg));
783 	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
784 		|| intent == DNS_MESSAGE_INTENTRENDER);
785 
786 	msgreset(msg, ISC_FALSE);
787 	msg->from_to_wire = intent;
788 }
789 
790 void
dns_message_destroy(dns_message_t ** msgp)791 dns_message_destroy(dns_message_t **msgp) {
792 	dns_message_t *msg;
793 
794 	REQUIRE(msgp != NULL);
795 	REQUIRE(DNS_MESSAGE_VALID(*msgp));
796 
797 	msg = *msgp;
798 	*msgp = NULL;
799 
800 	msgreset(msg, ISC_TRUE);
801 	isc_mempool_destroy(&msg->namepool);
802 	isc_mempool_destroy(&msg->rdspool);
803 	msg->magic = 0;
804 	isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
805 }
806 
807 static isc_result_t
findname(dns_name_t ** foundname,dns_name_t * target,dns_namelist_t * section)808 findname(dns_name_t **foundname, dns_name_t *target,
809 	 dns_namelist_t *section)
810 {
811 	dns_name_t *curr;
812 
813 	for (curr = ISC_LIST_TAIL(*section);
814 	     curr != NULL;
815 	     curr = ISC_LIST_PREV(curr, link)) {
816 		if (dns_name_equal(curr, target)) {
817 			if (foundname != NULL)
818 				*foundname = curr;
819 			return (ISC_R_SUCCESS);
820 		}
821 	}
822 
823 	return (ISC_R_NOTFOUND);
824 }
825 
826 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)827 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
828 		 dns_rdatatype_t type, dns_rdatatype_t covers,
829 		 dns_rdataset_t **rdataset)
830 {
831 	dns_rdataset_t *curr;
832 
833 	REQUIRE(name != NULL);
834 	REQUIRE(rdataset == NULL || *rdataset == NULL);
835 
836 	for (curr = ISC_LIST_TAIL(name->list);
837 	     curr != NULL;
838 	     curr = ISC_LIST_PREV(curr, link)) {
839 		if (curr->rdclass == rdclass &&
840 		    curr->type == type && curr->covers == covers) {
841 			if (rdataset != NULL)
842 				*rdataset = curr;
843 			return (ISC_R_SUCCESS);
844 		}
845 	}
846 
847 	return (ISC_R_NOTFOUND);
848 }
849 
850 isc_result_t
dns_message_findtype(dns_name_t * name,dns_rdatatype_t type,dns_rdatatype_t covers,dns_rdataset_t ** rdataset)851 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
852 		     dns_rdatatype_t covers, dns_rdataset_t **rdataset)
853 {
854 	dns_rdataset_t *curr;
855 
856 	REQUIRE(name != NULL);
857 	REQUIRE(rdataset == NULL || *rdataset == NULL);
858 
859 	for (curr = ISC_LIST_TAIL(name->list);
860 	     curr != NULL;
861 	     curr = ISC_LIST_PREV(curr, link)) {
862 		if (curr->type == type && curr->covers == covers) {
863 			if (ISC_UNLIKELY(rdataset != NULL))
864 				*rdataset = curr;
865 			return (ISC_R_SUCCESS);
866 		}
867 	}
868 
869 	return (ISC_R_NOTFOUND);
870 }
871 
872 /*
873  * Read a name from buffer "source".
874  */
875 static isc_result_t
getname(dns_name_t * name,isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx)876 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
877 	dns_decompress_t *dctx)
878 {
879 	isc_buffer_t *scratch;
880 	isc_result_t result;
881 	unsigned int tries;
882 
883 	scratch = currentbuffer(msg);
884 
885 	/*
886 	 * First try:  use current buffer.
887 	 * Second try:  allocate a new buffer and use that.
888 	 */
889 	tries = 0;
890 	while (tries < 2) {
891 		result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
892 					   scratch);
893 
894 		if (result == ISC_R_NOSPACE) {
895 			tries++;
896 
897 			result = newbuffer(msg, SCRATCHPAD_SIZE);
898 			if (result != ISC_R_SUCCESS)
899 				return (result);
900 
901 			scratch = currentbuffer(msg);
902 			dns_name_reset(name);
903 		} else {
904 			return (result);
905 		}
906 	}
907 
908 	INSIST(0);  /* Cannot get here... */
909 	return (ISC_R_UNEXPECTED);
910 }
911 
912 static isc_result_t
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)913 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
914 	 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
915 	 unsigned int rdatalen, dns_rdata_t *rdata)
916 {
917 	isc_buffer_t *scratch;
918 	isc_result_t result;
919 	unsigned int tries;
920 	unsigned int trysize;
921 
922 	scratch = currentbuffer(msg);
923 
924 	isc_buffer_setactive(source, rdatalen);
925 
926 	/*
927 	 * First try:  use current buffer.
928 	 * Second try:  allocate a new buffer of size
929 	 *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
930 	 *     (the data will fit if it was not more than 50% compressed)
931 	 * Subsequent tries: double buffer size on each try.
932 	 */
933 	tries = 0;
934 	trysize = 0;
935 	/* XXX possibly change this to a while (tries < 2) loop */
936 	for (;;) {
937 		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
938 					    source, dctx, 0,
939 					    scratch);
940 
941 		if (result == ISC_R_NOSPACE) {
942 			if (tries == 0) {
943 				trysize = 2 * rdatalen;
944 				if (trysize < SCRATCHPAD_SIZE)
945 					trysize = SCRATCHPAD_SIZE;
946 			} else {
947 				INSIST(trysize != 0);
948 				if (trysize >= 65535)
949 					return (ISC_R_NOSPACE);
950 					/* XXX DNS_R_RRTOOLONG? */
951 				trysize *= 2;
952 			}
953 			tries++;
954 			result = newbuffer(msg, trysize);
955 			if (result != ISC_R_SUCCESS)
956 				return (result);
957 
958 			scratch = currentbuffer(msg);
959 		} else {
960 			return (result);
961 		}
962 	}
963 }
964 
965 #define DO_FORMERR					\
966 	do {						\
967 		if (best_effort)			\
968 			seen_problem = ISC_TRUE;	\
969 		else {					\
970 			result = DNS_R_FORMERR;		\
971 			goto cleanup;			\
972 		}					\
973 	} while (0)
974 
975 static isc_result_t
getquestions(isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx,unsigned int options)976 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
977 	     unsigned int options)
978 {
979 	isc_region_t r;
980 	unsigned int count;
981 	dns_name_t *name;
982 	dns_name_t *name2;
983 	dns_offsets_t *offsets;
984 	dns_rdataset_t *rdataset;
985 	dns_rdatalist_t *rdatalist;
986 	isc_result_t result;
987 	dns_rdatatype_t rdtype;
988 	dns_rdataclass_t rdclass;
989 	dns_namelist_t *section;
990 	isc_boolean_t free_name;
991 	isc_boolean_t best_effort;
992 	isc_boolean_t seen_problem;
993 
994 	section = &msg->sections[DNS_SECTION_QUESTION];
995 
996 	best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
997 	seen_problem = ISC_FALSE;
998 
999 	name = NULL;
1000 	rdataset = NULL;
1001 	rdatalist = NULL;
1002 
1003 	for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1004 		name = isc_mempool_get(msg->namepool);
1005 		if (name == NULL)
1006 			return (ISC_R_NOMEMORY);
1007 		free_name = ISC_TRUE;
1008 
1009 		offsets = newoffsets(msg);
1010 		if (offsets == NULL) {
1011 			result = ISC_R_NOMEMORY;
1012 			goto cleanup;
1013 		}
1014 		dns_name_init(name, *offsets);
1015 
1016 		/*
1017 		 * Parse the name out of this packet.
1018 		 */
1019 		isc_buffer_remainingregion(source, &r);
1020 		isc_buffer_setactive(source, r.length);
1021 		result = getname(name, source, msg, dctx);
1022 		if (result != ISC_R_SUCCESS)
1023 			goto cleanup;
1024 
1025 		/*
1026 		 * Run through the section, looking to see if this name
1027 		 * is already there.  If it is found, put back the allocated
1028 		 * name since we no longer need it, and set our name pointer
1029 		 * to point to the name we found.
1030 		 */
1031 		result = findname(&name2, name, section);
1032 
1033 		/*
1034 		 * If it is the first name in the section, accept it.
1035 		 *
1036 		 * If it is not, but is not the same as the name already
1037 		 * in the question section, append to the section.  Note that
1038 		 * here in the question section this is illegal, so return
1039 		 * FORMERR.  In the future, check the opcode to see if
1040 		 * this should be legal or not.  In either case we no longer
1041 		 * need this name pointer.
1042 		 */
1043 		if (result != ISC_R_SUCCESS) {
1044 			if (!ISC_LIST_EMPTY(*section))
1045 				DO_FORMERR;
1046 			ISC_LIST_APPEND(*section, name, link);
1047 			free_name = ISC_FALSE;
1048 		} else {
1049 			isc_mempool_put(msg->namepool, name);
1050 			name = name2;
1051 			name2 = NULL;
1052 			free_name = ISC_FALSE;
1053 		}
1054 
1055 		/*
1056 		 * Get type and class.
1057 		 */
1058 		isc_buffer_remainingregion(source, &r);
1059 		if (r.length < 4) {
1060 			result = ISC_R_UNEXPECTEDEND;
1061 			goto cleanup;
1062 		}
1063 		rdtype = isc_buffer_getuint16(source);
1064 		rdclass = isc_buffer_getuint16(source);
1065 
1066 		/*
1067 		 * If this class is different than the one we already read,
1068 		 * this is an error.
1069 		 */
1070 		if (msg->rdclass_set == 0) {
1071 			msg->rdclass = rdclass;
1072 			msg->rdclass_set = 1;
1073 		} else if (msg->rdclass != rdclass)
1074 			DO_FORMERR;
1075 
1076 		/*
1077 		 * Is this a TKEY query?
1078 		 */
1079 		if (rdtype == dns_rdatatype_tkey)
1080 			msg->tkey = 1;
1081 
1082 		/*
1083 		 * Can't ask the same question twice.
1084 		 */
1085 		result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1086 		if (result == ISC_R_SUCCESS)
1087 			DO_FORMERR;
1088 
1089 		/*
1090 		 * Allocate a new rdatalist.
1091 		 */
1092 		rdatalist = newrdatalist(msg);
1093 		if (rdatalist == NULL) {
1094 			result = ISC_R_NOMEMORY;
1095 			goto cleanup;
1096 		}
1097 		rdataset =  isc_mempool_get(msg->rdspool);
1098 		if (rdataset == NULL) {
1099 			result = ISC_R_NOMEMORY;
1100 			goto cleanup;
1101 		}
1102 
1103 		/*
1104 		 * Convert rdatalist to rdataset, and attach the latter to
1105 		 * the name.
1106 		 */
1107 		rdatalist->type = rdtype;
1108 		rdatalist->covers = 0;
1109 		rdatalist->rdclass = rdclass;
1110 		rdatalist->ttl = 0;
1111 		ISC_LIST_INIT(rdatalist->rdata);
1112 
1113 		dns_rdataset_init(rdataset);
1114 		result = dns_rdatalist_tordataset(rdatalist, rdataset);
1115 		if (result != ISC_R_SUCCESS)
1116 			goto cleanup;
1117 
1118 		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1119 
1120 		ISC_LIST_APPEND(name->list, rdataset, link);
1121 		rdataset = NULL;
1122 	}
1123 
1124 	if (seen_problem)
1125 		return (DNS_R_RECOVERABLE);
1126 	return (ISC_R_SUCCESS);
1127 
1128  cleanup:
1129 	if (rdataset != NULL) {
1130 		INSIST(!dns_rdataset_isassociated(rdataset));
1131 		isc_mempool_put(msg->rdspool, rdataset);
1132 	}
1133 #if 0
1134 	if (rdatalist != NULL)
1135 		isc_mempool_put(msg->rdlpool, rdatalist);
1136 #endif
1137 	if (free_name)
1138 		isc_mempool_put(msg->namepool, name);
1139 
1140 	return (result);
1141 }
1142 
1143 static isc_boolean_t
update(dns_section_t section,dns_rdataclass_t rdclass)1144 update(dns_section_t section, dns_rdataclass_t rdclass) {
1145 	if (section == DNS_SECTION_PREREQUISITE)
1146 		return (ISC_TF(rdclass == dns_rdataclass_any ||
1147 			       rdclass == dns_rdataclass_none));
1148 	if (section == DNS_SECTION_UPDATE)
1149 		return (ISC_TF(rdclass == dns_rdataclass_any));
1150 	return (ISC_FALSE);
1151 }
1152 
1153 static isc_result_t
getsection(isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx,dns_section_t sectionid,unsigned int options)1154 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1155 	   dns_section_t sectionid, unsigned int options)
1156 {
1157 	isc_region_t r;
1158 	unsigned int count, rdatalen;
1159 	dns_name_t *name;
1160 	dns_name_t *name2;
1161 	dns_offsets_t *offsets;
1162 	dns_rdataset_t *rdataset;
1163 	dns_rdatalist_t *rdatalist;
1164 	isc_result_t result;
1165 	dns_rdatatype_t rdtype, covers;
1166 	dns_rdataclass_t rdclass;
1167 	dns_rdata_t *rdata;
1168 	dns_ttl_t ttl;
1169 	dns_namelist_t *section;
1170 	isc_boolean_t free_name, free_rdataset;
1171 	isc_boolean_t preserve_order, best_effort, seen_problem;
1172 	isc_boolean_t issigzero;
1173 
1174 	preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1175 	best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1176 	seen_problem = ISC_FALSE;
1177 
1178 	for (count = 0; count < msg->counts[sectionid]; count++) {
1179 		int recstart = source->current;
1180 		isc_boolean_t skip_name_search, skip_type_search;
1181 
1182 		section = &msg->sections[sectionid];
1183 
1184 		skip_name_search = ISC_FALSE;
1185 		skip_type_search = ISC_FALSE;
1186 		free_rdataset = ISC_FALSE;
1187 
1188 		name = isc_mempool_get(msg->namepool);
1189 		if (name == NULL)
1190 			return (ISC_R_NOMEMORY);
1191 		free_name = ISC_TRUE;
1192 
1193 		offsets = newoffsets(msg);
1194 		if (offsets == NULL) {
1195 			result = ISC_R_NOMEMORY;
1196 			goto cleanup;
1197 		}
1198 		dns_name_init(name, *offsets);
1199 
1200 		/*
1201 		 * Parse the name out of this packet.
1202 		 */
1203 		isc_buffer_remainingregion(source, &r);
1204 		isc_buffer_setactive(source, r.length);
1205 		result = getname(name, source, msg, dctx);
1206 		if (result != ISC_R_SUCCESS)
1207 			goto cleanup;
1208 
1209 		/*
1210 		 * Get type, class, ttl, and rdatalen.  Verify that at least
1211 		 * rdatalen bytes remain.  (Some of this is deferred to
1212 		 * later.)
1213 		 */
1214 		isc_buffer_remainingregion(source, &r);
1215 		if (r.length < 2 + 2 + 4 + 2) {
1216 			result = ISC_R_UNEXPECTEDEND;
1217 			goto cleanup;
1218 		}
1219 		rdtype = isc_buffer_getuint16(source);
1220 		rdclass = isc_buffer_getuint16(source);
1221 
1222 		/*
1223 		 * If there was no question section, we may not yet have
1224 		 * established a class.  Do so now.
1225 		 */
1226 		if (msg->rdclass_set == 0 &&
1227 		    rdtype != dns_rdatatype_opt &&	/* class is UDP SIZE */
1228 		    rdtype != dns_rdatatype_tsig &&	/* class is ANY */
1229 		    rdtype != dns_rdatatype_tkey) {	/* class is undefined */
1230 			msg->rdclass = rdclass;
1231 			msg->rdclass_set = 1;
1232 		}
1233 
1234 		/*
1235 		 * If this class is different than the one in the question
1236 		 * section, bail.
1237 		 */
1238 		if (msg->opcode != dns_opcode_update
1239 		    && rdtype != dns_rdatatype_tsig
1240 		    && rdtype != dns_rdatatype_opt
1241 		    && rdtype != dns_rdatatype_key /* in a TKEY query */
1242 		    && rdtype != dns_rdatatype_sig /* SIG(0) */
1243 		    && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1244 		    && msg->rdclass != dns_rdataclass_any
1245 		    && msg->rdclass != rdclass)
1246 			DO_FORMERR;
1247 
1248 		/*
1249 		 * If this is not a TKEY query/response then the KEY
1250 		 * record's class needs to match.
1251 		 */
1252 		if (msg->opcode != dns_opcode_update && !msg->tkey &&
1253 		    rdtype == dns_rdatatype_key &&
1254 		    msg->rdclass != dns_rdataclass_any &&
1255 		    msg->rdclass != rdclass)
1256 			DO_FORMERR;
1257 
1258 		/*
1259 		 * Special type handling for TSIG, OPT, and TKEY.
1260 		 */
1261 		if (rdtype == dns_rdatatype_tsig) {
1262 			/*
1263 			 * If it is a tsig, verify that it is in the
1264 			 * additional data section.
1265 			 */
1266 			if (sectionid != DNS_SECTION_ADDITIONAL ||
1267 			    rdclass != dns_rdataclass_any ||
1268 			    count != msg->counts[sectionid]  - 1)
1269 				DO_FORMERR;
1270 			msg->sigstart = recstart;
1271 			skip_name_search = ISC_TRUE;
1272 			skip_type_search = ISC_TRUE;
1273 		} else if (rdtype == dns_rdatatype_opt) {
1274 			/*
1275 			 * The name of an OPT record must be ".", it
1276 			 * must be in the additional data section, and
1277 			 * it must be the first OPT we've seen.
1278 			 */
1279 			if (!dns_name_equal(dns_rootname, name) ||
1280 			    sectionid != DNS_SECTION_ADDITIONAL ||
1281 			    msg->opt != NULL)
1282 				DO_FORMERR;
1283 			skip_name_search = ISC_TRUE;
1284 			skip_type_search = ISC_TRUE;
1285 		} else if (rdtype == dns_rdatatype_tkey) {
1286 			/*
1287 			 * A TKEY must be in the additional section if this
1288 			 * is a query, and the answer section if this is a
1289 			 * response.  Unless it's a Win2000 client.
1290 			 *
1291 			 * Its class is ignored.
1292 			 */
1293 			dns_section_t tkeysection;
1294 
1295 			if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1296 				tkeysection = DNS_SECTION_ADDITIONAL;
1297 			else
1298 				tkeysection = DNS_SECTION_ANSWER;
1299 			if (sectionid != tkeysection &&
1300 			    sectionid != DNS_SECTION_ANSWER)
1301 				DO_FORMERR;
1302 		}
1303 
1304 		/*
1305 		 * ... now get ttl and rdatalen, and check buffer.
1306 		 */
1307 		ttl = isc_buffer_getuint32(source);
1308 		rdatalen = isc_buffer_getuint16(source);
1309 		r.length -= (2 + 2 + 4 + 2);
1310 		if (r.length < rdatalen) {
1311 			result = ISC_R_UNEXPECTEDEND;
1312 			goto cleanup;
1313 		}
1314 
1315 		/*
1316 		 * Read the rdata from the wire format.  Interpret the
1317 		 * rdata according to its actual class, even if it had a
1318 		 * DynDNS meta-class in the packet (unless this is a TSIG).
1319 		 * Then put the meta-class back into the finished rdata.
1320 		 */
1321 		rdata = newrdata(msg);
1322 		if (rdata == NULL) {
1323 			result = ISC_R_NOMEMORY;
1324 			goto cleanup;
1325 		}
1326 		if (msg->opcode == dns_opcode_update &&
1327 		    update(sectionid, rdclass)) {
1328 			if (rdatalen != 0) {
1329 				result = DNS_R_FORMERR;
1330 				goto cleanup;
1331 			}
1332 			/*
1333 			 * When the rdata is empty, the data pointer is
1334 			 * never dereferenced, but it must still be non-NULL.
1335 			 * Casting 1 rather than "" avoids warnings about
1336 			 * discarding the const attribute of a string,
1337 			 * for compilers that would warn about such things.
1338 			 */
1339 			rdata->data = (unsigned char *)1;
1340 			rdata->length = 0;
1341 			rdata->rdclass = rdclass;
1342 			rdata->type = rdtype;
1343 			rdata->flags = DNS_RDATA_UPDATE;
1344 			result = ISC_R_SUCCESS;
1345 		} else if (rdclass == dns_rdataclass_none &&
1346 			   msg->opcode == dns_opcode_update &&
1347 			   sectionid == DNS_SECTION_UPDATE) {
1348 			result = getrdata(source, msg, dctx, msg->rdclass,
1349 					  rdtype, rdatalen, rdata);
1350 		} else
1351 			result = getrdata(source, msg, dctx, rdclass,
1352 					  rdtype, rdatalen, rdata);
1353 		if (result != ISC_R_SUCCESS)
1354 			goto cleanup;
1355 		rdata->rdclass = rdclass;
1356 		issigzero = ISC_FALSE;
1357 		if (rdtype == dns_rdatatype_rrsig  &&
1358 		    rdata->flags == 0) {
1359 			covers = dns_rdata_covers(rdata);
1360 			if (covers == 0)
1361 				DO_FORMERR;
1362 		} else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1363 			   rdata->flags == 0) {
1364 			covers = dns_rdata_covers(rdata);
1365 			if (covers == 0) {
1366 				if (sectionid != DNS_SECTION_ADDITIONAL ||
1367 				    count != msg->counts[sectionid]  - 1)
1368 					DO_FORMERR;
1369 				msg->sigstart = recstart;
1370 				skip_name_search = ISC_TRUE;
1371 				skip_type_search = ISC_TRUE;
1372 				issigzero = ISC_TRUE;
1373 			} else {
1374 				if (msg->rdclass != dns_rdataclass_any &&
1375 				    msg->rdclass != rdclass)
1376 					DO_FORMERR;
1377 			}
1378 		} else
1379 			covers = 0;
1380 
1381 		/*
1382 		 * Check the ownername of NSEC3 records
1383 		 */
1384 		if (rdtype == dns_rdatatype_nsec3 &&
1385 		    !dns_rdata_checkowner(name, msg->rdclass, rdtype,
1386 					  ISC_FALSE)) {
1387 			result = DNS_R_BADOWNERNAME;
1388 			goto cleanup;
1389 		}
1390 
1391 		/*
1392 		 * If we are doing a dynamic update or this is a meta-type,
1393 		 * don't bother searching for a name, just append this one
1394 		 * to the end of the message.
1395 		 */
1396 		if (preserve_order || msg->opcode == dns_opcode_update ||
1397 		    skip_name_search) {
1398 			if (rdtype != dns_rdatatype_opt &&
1399 			    rdtype != dns_rdatatype_tsig &&
1400 			    !issigzero)
1401 			{
1402 				ISC_LIST_APPEND(*section, name, link);
1403 				free_name = ISC_FALSE;
1404 			}
1405 		} else {
1406 			/*
1407 			 * Run through the section, looking to see if this name
1408 			 * is already there.  If it is found, put back the
1409 			 * allocated name since we no longer need it, and set
1410 			 * our name pointer to point to the name we found.
1411 			 */
1412 			result = findname(&name2, name, section);
1413 
1414 			/*
1415 			 * If it is a new name, append to the section.
1416 			 */
1417 			if (result == ISC_R_SUCCESS) {
1418 				isc_mempool_put(msg->namepool, name);
1419 				name = name2;
1420 			} else {
1421 				ISC_LIST_APPEND(*section, name, link);
1422 			}
1423 			free_name = ISC_FALSE;
1424 		}
1425 
1426 		/*
1427 		 * Search name for the particular type and class.
1428 		 * Skip this stage if in update mode or this is a meta-type.
1429 		 */
1430 		if (preserve_order || msg->opcode == dns_opcode_update ||
1431 		    skip_type_search)
1432 			result = ISC_R_NOTFOUND;
1433 		else {
1434 			/*
1435 			 * If this is a type that can only occur in
1436 			 * the question section, fail.
1437 			 */
1438 			if (dns_rdatatype_questiononly(rdtype))
1439 				DO_FORMERR;
1440 
1441 			rdataset = NULL;
1442 			result = dns_message_find(name, rdclass, rdtype,
1443 						   covers, &rdataset);
1444 		}
1445 
1446 		/*
1447 		 * If we found an rdataset that matches, we need to
1448 		 * append this rdata to that set.  If we did not, we need
1449 		 * to create a new rdatalist, store the important bits there,
1450 		 * convert it to an rdataset, and link the latter to the name.
1451 		 * Yuck.  When appending, make certain that the type isn't
1452 		 * a singleton type, such as SOA or CNAME.
1453 		 *
1454 		 * Note that this check will be bypassed when preserving order,
1455 		 * the opcode is an update, or the type search is skipped.
1456 		 */
1457 		if (result == ISC_R_SUCCESS) {
1458 			if (dns_rdatatype_issingleton(rdtype)) {
1459 				dns_rdata_t *first;
1460 				dns_rdatalist_fromrdataset(rdataset,
1461 							   &rdatalist);
1462 				first = ISC_LIST_HEAD(rdatalist->rdata);
1463 				INSIST(first != NULL);
1464 				if (dns_rdata_compare(rdata, first) != 0)
1465 					DO_FORMERR;
1466 			}
1467 		}
1468 
1469 		if (result == ISC_R_NOTFOUND) {
1470 			rdataset = isc_mempool_get(msg->rdspool);
1471 			if (rdataset == NULL) {
1472 				result = ISC_R_NOMEMORY;
1473 				goto cleanup;
1474 			}
1475 			free_rdataset = ISC_TRUE;
1476 
1477 			rdatalist = newrdatalist(msg);
1478 			if (rdatalist == NULL) {
1479 				result = ISC_R_NOMEMORY;
1480 				goto cleanup;
1481 			}
1482 
1483 			rdatalist->type = rdtype;
1484 			rdatalist->covers = covers;
1485 			rdatalist->rdclass = rdclass;
1486 			rdatalist->ttl = ttl;
1487 			ISC_LIST_INIT(rdatalist->rdata);
1488 
1489 			dns_rdataset_init(rdataset);
1490 			RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1491 							       rdataset)
1492 				      == ISC_R_SUCCESS);
1493 
1494 			if (rdtype != dns_rdatatype_opt &&
1495 			    rdtype != dns_rdatatype_tsig &&
1496 			    !issigzero)
1497 			{
1498 				ISC_LIST_APPEND(name->list, rdataset, link);
1499 				free_rdataset = ISC_FALSE;
1500 			}
1501 		}
1502 
1503 		/*
1504 		 * Minimize TTLs.
1505 		 *
1506 		 * Section 5.2 of RFC2181 says we should drop
1507 		 * nonauthoritative rrsets where the TTLs differ, but we
1508 		 * currently treat them the as if they were authoritative and
1509 		 * minimize them.
1510 		 */
1511 		if (ttl != rdataset->ttl) {
1512 			rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1513 			if (ttl < rdataset->ttl)
1514 				rdataset->ttl = ttl;
1515 		}
1516 
1517 		/* Append this rdata to the rdataset. */
1518 		dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1519 		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1520 
1521 		/*
1522 		 * If this is an OPT, SIG(0) or TSIG record, remember it.
1523 		 * Also, set the extended rcode for TSIG.
1524 		 *
1525 		 * Note msg->opt, msg->sig0 and msg->tsig will only be
1526 		 * already set if best-effort parsing is enabled otherwise
1527 		 * there will only be at most one of each.
1528 		 */
1529 		if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1530 			dns_rcode_t ercode;
1531 
1532 			msg->opt = rdataset;
1533 			rdataset = NULL;
1534 			free_rdataset = ISC_FALSE;
1535 			ercode = (dns_rcode_t)
1536 				((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1537 				 >> 20);
1538 			msg->rcode |= ercode;
1539 			isc_mempool_put(msg->namepool, name);
1540 			free_name = ISC_FALSE;
1541 		} else if (issigzero && msg->sig0 == NULL) {
1542 			msg->sig0 = rdataset;
1543 			msg->sig0name = name;
1544 			rdataset = NULL;
1545 			free_rdataset = ISC_FALSE;
1546 			free_name = ISC_FALSE;
1547 		} else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1548 			msg->tsig = rdataset;
1549 			msg->tsigname = name;
1550 			/* Windows doesn't like TSIG names to be compressed. */
1551 			msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1552 			rdataset = NULL;
1553 			free_rdataset = ISC_FALSE;
1554 			free_name = ISC_FALSE;
1555 		}
1556 
1557 		if (seen_problem) {
1558 			if (free_name)
1559 				isc_mempool_put(msg->namepool, name);
1560 			if (free_rdataset)
1561 				isc_mempool_put(msg->rdspool, rdataset);
1562 			free_name = free_rdataset = ISC_FALSE;
1563 		}
1564 		INSIST(free_name == ISC_FALSE);
1565 		INSIST(free_rdataset == ISC_FALSE);
1566 	}
1567 
1568 	if (seen_problem)
1569 		return (DNS_R_RECOVERABLE);
1570 	return (ISC_R_SUCCESS);
1571 
1572  cleanup:
1573 	if (free_name)
1574 		isc_mempool_put(msg->namepool, name);
1575 	if (free_rdataset)
1576 		isc_mempool_put(msg->rdspool, rdataset);
1577 
1578 	return (result);
1579 }
1580 
1581 isc_result_t
dns_message_parse(dns_message_t * msg,isc_buffer_t * source,unsigned int options)1582 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1583 		  unsigned int options)
1584 {
1585 	isc_region_t r;
1586 	dns_decompress_t dctx;
1587 	isc_result_t ret;
1588 	isc_uint16_t tmpflags;
1589 	isc_buffer_t origsource;
1590 	isc_boolean_t seen_problem;
1591 	isc_boolean_t ignore_tc;
1592 
1593 	REQUIRE(DNS_MESSAGE_VALID(msg));
1594 	REQUIRE(source != NULL);
1595 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1596 
1597 	seen_problem = ISC_FALSE;
1598 	ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1599 
1600 	origsource = *source;
1601 
1602 	msg->header_ok = 0;
1603 	msg->question_ok = 0;
1604 
1605 	isc_buffer_remainingregion(source, &r);
1606 	if (r.length < DNS_MESSAGE_HEADERLEN)
1607 		return (ISC_R_UNEXPECTEDEND);
1608 
1609 	msg->id = isc_buffer_getuint16(source);
1610 	tmpflags = isc_buffer_getuint16(source);
1611 	msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1612 		       >> DNS_MESSAGE_OPCODE_SHIFT);
1613 	msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1614 	msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1615 	msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1616 	msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1617 	msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1618 	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1619 
1620 	msg->header_ok = 1;
1621 	msg->state = DNS_SECTION_QUESTION;
1622 
1623 	/*
1624 	 * -1 means no EDNS.
1625 	 */
1626 	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1627 
1628 	dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1629 
1630 	ret = getquestions(source, msg, &dctx, options);
1631 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1632 		goto truncated;
1633 	if (ret == DNS_R_RECOVERABLE) {
1634 		seen_problem = ISC_TRUE;
1635 		ret = ISC_R_SUCCESS;
1636 	}
1637 	if (ret != ISC_R_SUCCESS)
1638 		return (ret);
1639 	msg->question_ok = 1;
1640 
1641 	ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1642 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1643 		goto truncated;
1644 	if (ret == DNS_R_RECOVERABLE) {
1645 		seen_problem = ISC_TRUE;
1646 		ret = ISC_R_SUCCESS;
1647 	}
1648 	if (ret != ISC_R_SUCCESS)
1649 		return (ret);
1650 
1651 	ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1652 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1653 		goto truncated;
1654 	if (ret == DNS_R_RECOVERABLE) {
1655 		seen_problem = ISC_TRUE;
1656 		ret = ISC_R_SUCCESS;
1657 	}
1658 	if (ret != ISC_R_SUCCESS)
1659 		return (ret);
1660 
1661 	ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1662 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1663 		goto truncated;
1664 	if (ret == DNS_R_RECOVERABLE) {
1665 		seen_problem = ISC_TRUE;
1666 		ret = ISC_R_SUCCESS;
1667 	}
1668 	if (ret != ISC_R_SUCCESS)
1669 		return (ret);
1670 
1671 	isc_buffer_remainingregion(source, &r);
1672 	if (r.length != 0) {
1673 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1674 			      DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1675 			      "message has %u byte(s) of trailing garbage",
1676 			      r.length);
1677 	}
1678 
1679  truncated:
1680 	if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1681 		isc_buffer_usedregion(&origsource, &msg->saved);
1682 	else {
1683 		msg->saved.length = isc_buffer_usedlength(&origsource);
1684 		msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1685 		if (msg->saved.base == NULL)
1686 			return (ISC_R_NOMEMORY);
1687 		memmove(msg->saved.base, isc_buffer_base(&origsource),
1688 			msg->saved.length);
1689 		msg->free_saved = 1;
1690 	}
1691 
1692 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1693 		return (DNS_R_RECOVERABLE);
1694 	if (seen_problem == ISC_TRUE)
1695 		return (DNS_R_RECOVERABLE);
1696 	return (ISC_R_SUCCESS);
1697 }
1698 
1699 isc_result_t
dns_message_renderbegin(dns_message_t * msg,dns_compress_t * cctx,isc_buffer_t * buffer)1700 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1701 			isc_buffer_t *buffer)
1702 {
1703 	isc_region_t r;
1704 
1705 	REQUIRE(DNS_MESSAGE_VALID(msg));
1706 	REQUIRE(buffer != NULL);
1707 	REQUIRE(msg->buffer == NULL);
1708 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1709 
1710 	msg->cctx = cctx;
1711 
1712 	/*
1713 	 * Erase the contents of this buffer.
1714 	 */
1715 	isc_buffer_clear(buffer);
1716 
1717 	/*
1718 	 * Make certain there is enough for at least the header in this
1719 	 * buffer.
1720 	 */
1721 	isc_buffer_availableregion(buffer, &r);
1722 	if (r.length < DNS_MESSAGE_HEADERLEN)
1723 		return (ISC_R_NOSPACE);
1724 
1725 	if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
1726 		return (ISC_R_NOSPACE);
1727 
1728 	/*
1729 	 * Reserve enough space for the header in this buffer.
1730 	 */
1731 	isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1732 
1733 	msg->buffer = buffer;
1734 
1735 	return (ISC_R_SUCCESS);
1736 }
1737 
1738 isc_result_t
dns_message_renderchangebuffer(dns_message_t * msg,isc_buffer_t * buffer)1739 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1740 	isc_region_t r, rn;
1741 
1742 	REQUIRE(DNS_MESSAGE_VALID(msg));
1743 	REQUIRE(buffer != NULL);
1744 	REQUIRE(msg->buffer != NULL);
1745 
1746 	/*
1747 	 * Ensure that the new buffer is empty, and has enough space to
1748 	 * hold the current contents.
1749 	 */
1750 	isc_buffer_clear(buffer);
1751 
1752 	isc_buffer_availableregion(buffer, &rn);
1753 	isc_buffer_usedregion(msg->buffer, &r);
1754 	REQUIRE(rn.length > r.length);
1755 
1756 	/*
1757 	 * Copy the contents from the old to the new buffer.
1758 	 */
1759 	isc_buffer_add(buffer, r.length);
1760 	memmove(rn.base, r.base, r.length);
1761 
1762 	msg->buffer = buffer;
1763 
1764 	return (ISC_R_SUCCESS);
1765 }
1766 
1767 void
dns_message_renderrelease(dns_message_t * msg,unsigned int space)1768 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1769 	REQUIRE(DNS_MESSAGE_VALID(msg));
1770 	REQUIRE(space <= msg->reserved);
1771 
1772 	msg->reserved -= space;
1773 }
1774 
1775 isc_result_t
dns_message_renderreserve(dns_message_t * msg,unsigned int space)1776 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1777 	isc_region_t r;
1778 
1779 	REQUIRE(DNS_MESSAGE_VALID(msg));
1780 
1781 	if (msg->buffer != NULL) {
1782 		isc_buffer_availableregion(msg->buffer, &r);
1783 		if (r.length < (space + msg->reserved))
1784 			return (ISC_R_NOSPACE);
1785 	}
1786 
1787 	msg->reserved += space;
1788 
1789 	return (ISC_R_SUCCESS);
1790 }
1791 
1792 static inline isc_boolean_t
wrong_priority(dns_rdataset_t * rds,int pass,dns_rdatatype_t preferred_glue)1793 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1794 	int pass_needed;
1795 
1796 	/*
1797 	 * If we are not rendering class IN, this ordering is bogus.
1798 	 */
1799 	if (rds->rdclass != dns_rdataclass_in)
1800 		return (ISC_FALSE);
1801 
1802 	switch (rds->type) {
1803 	case dns_rdatatype_a:
1804 	case dns_rdatatype_aaaa:
1805 		if (preferred_glue == rds->type)
1806 			pass_needed = 4;
1807 		else
1808 			pass_needed = 3;
1809 		break;
1810 	case dns_rdatatype_rrsig:
1811 	case dns_rdatatype_dnskey:
1812 		pass_needed = 2;
1813 		break;
1814 	default:
1815 		pass_needed = 1;
1816 	}
1817 
1818 	if (pass_needed >= pass)
1819 		return (ISC_FALSE);
1820 
1821 	return (ISC_TRUE);
1822 }
1823 
1824 #ifdef ALLOW_FILTER_AAAA_ON_V4
1825 /*
1826  * Decide whether to not answer with an AAAA record and its RRSIG
1827  */
1828 static inline isc_boolean_t
norender_rdataset(const dns_rdataset_t * rdataset,unsigned int options,dns_section_t sectionid)1829 norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options,
1830 		  dns_section_t sectionid)
1831 {
1832 	if (sectionid == DNS_SECTION_QUESTION)
1833 		return (ISC_FALSE);
1834 
1835 	switch (rdataset->type) {
1836 	case dns_rdatatype_ns:
1837 		if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1838 		    sectionid != DNS_SECTION_AUTHORITY)
1839 			return (ISC_FALSE);
1840 		break;
1841 
1842 	case dns_rdatatype_aaaa:
1843 		if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
1844 			return (ISC_FALSE);
1845 		break;
1846 
1847 	case dns_rdatatype_rrsig:
1848 		if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1849 		    (rdataset->covers != dns_rdatatype_ns &&
1850 		     rdataset->covers != dns_rdatatype_aaaa))
1851 			return (ISC_FALSE);
1852 		if ((rdataset->covers == dns_rdatatype_ns) &&
1853 		    (sectionid != DNS_SECTION_AUTHORITY))
1854 			return (ISC_FALSE);
1855 		break;
1856 
1857 	default:
1858 		return (ISC_FALSE);
1859 	}
1860 
1861 	if (rdataset->rdclass != dns_rdataclass_in)
1862 		return (ISC_FALSE);
1863 
1864 	return (ISC_TRUE);
1865 }
1866 #endif
1867 
1868 static isc_result_t
renderset(dns_rdataset_t * rdataset,dns_name_t * owner_name,dns_compress_t * cctx,isc_buffer_t * target,unsigned int reserved,unsigned int options,unsigned int * countp)1869 renderset(dns_rdataset_t *rdataset, dns_name_t *owner_name,
1870 	  dns_compress_t *cctx, isc_buffer_t *target,
1871 	  unsigned int reserved, unsigned int options, unsigned int *countp)
1872 {
1873 	isc_result_t result;
1874 
1875 	/*
1876 	 * Shrink the space in the buffer by the reserved amount.
1877 	 */
1878 	if (target->length - target->used < reserved)
1879 		return (ISC_R_NOSPACE);
1880 
1881 	target->length -= reserved;
1882 	result = dns_rdataset_towire(rdataset, owner_name,
1883 				     cctx, target, options, countp);
1884 	target->length += reserved;
1885 
1886 	return (result);
1887 }
1888 
1889 isc_result_t
dns_message_rendersection(dns_message_t * msg,dns_section_t sectionid,unsigned int options)1890 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1891 			  unsigned int options)
1892 {
1893 	dns_namelist_t *section;
1894 	dns_name_t *name, *next_name;
1895 	dns_rdataset_t *rdataset, *next_rdataset;
1896 	unsigned int count, total;
1897 	isc_result_t result;
1898 	isc_buffer_t st; /* for rollbacks */
1899 	int pass;
1900 	isc_boolean_t partial = ISC_FALSE;
1901 	unsigned int rd_options;
1902 	dns_rdatatype_t preferred_glue = 0;
1903 
1904 	REQUIRE(DNS_MESSAGE_VALID(msg));
1905 	REQUIRE(msg->buffer != NULL);
1906 	REQUIRE(VALID_NAMED_SECTION(sectionid));
1907 
1908 	section = &msg->sections[sectionid];
1909 
1910 	if ((sectionid == DNS_SECTION_ADDITIONAL)
1911 	    && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1912 		if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1913 			preferred_glue = dns_rdatatype_a;
1914 			pass = 4;
1915 		} else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1916 			preferred_glue = dns_rdatatype_aaaa;
1917 			pass = 4;
1918 		} else
1919 			pass = 3;
1920 	} else
1921 		pass = 1;
1922 
1923 	if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1924 		rd_options = 0;
1925 	else
1926 		rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1927 
1928 	/*
1929 	 * Shrink the space in the buffer by the reserved amount.
1930 	 */
1931 	if (msg->buffer->length - msg->buffer->used < msg->reserved)
1932 		return (ISC_R_NOSPACE);
1933 	msg->buffer->length -= msg->reserved;
1934 
1935 	total = 0;
1936 	if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1937 		partial = ISC_TRUE;
1938 
1939 	/*
1940 	 * Render required glue first.  Set TC if it won't fit.
1941 	 */
1942 	name = ISC_LIST_HEAD(*section);
1943 	if (name != NULL) {
1944 		rdataset = ISC_LIST_HEAD(name->list);
1945 		if (rdataset != NULL &&
1946 		    (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1947 		    (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1948 			const void *order_arg = msg->order_arg;
1949 			st = *(msg->buffer);
1950 			count = 0;
1951 			if (partial)
1952 				result = dns_rdataset_towirepartial(rdataset,
1953 								    name,
1954 								    msg->cctx,
1955 								    msg->buffer,
1956 								    msg->order,
1957 								    order_arg,
1958 								    rd_options,
1959 								    &count,
1960 								    NULL);
1961 			else
1962 				result = dns_rdataset_towiresorted(rdataset,
1963 								   name,
1964 								   msg->cctx,
1965 								   msg->buffer,
1966 								   msg->order,
1967 								   order_arg,
1968 								   rd_options,
1969 								   &count);
1970 			total += count;
1971 			if (partial && result == ISC_R_NOSPACE) {
1972 				msg->flags |= DNS_MESSAGEFLAG_TC;
1973 				msg->buffer->length += msg->reserved;
1974 				msg->counts[sectionid] += total;
1975 				return (result);
1976 			}
1977 			if (result == ISC_R_NOSPACE)
1978 				msg->flags |= DNS_MESSAGEFLAG_TC;
1979 			if (result != ISC_R_SUCCESS) {
1980 				INSIST(st.used < 65536);
1981 				dns_compress_rollback(msg->cctx,
1982 						      (isc_uint16_t)st.used);
1983 				*(msg->buffer) = st;  /* rollback */
1984 				msg->buffer->length += msg->reserved;
1985 				msg->counts[sectionid] += total;
1986 				return (result);
1987 			}
1988 			rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1989 		}
1990 	}
1991 
1992 	do {
1993 		name = ISC_LIST_HEAD(*section);
1994 		if (name == NULL) {
1995 			msg->buffer->length += msg->reserved;
1996 			msg->counts[sectionid] += total;
1997 			return (ISC_R_SUCCESS);
1998 		}
1999 
2000 		while (name != NULL) {
2001 			next_name = ISC_LIST_NEXT(name, link);
2002 
2003 			rdataset = ISC_LIST_HEAD(name->list);
2004 			while (rdataset != NULL) {
2005 				next_rdataset = ISC_LIST_NEXT(rdataset, link);
2006 
2007 				if ((rdataset->attributes &
2008 				     DNS_RDATASETATTR_RENDERED) != 0)
2009 					goto next;
2010 
2011 				if (((options & DNS_MESSAGERENDER_ORDERED)
2012 				     == 0)
2013 				    && (sectionid == DNS_SECTION_ADDITIONAL)
2014 				    && wrong_priority(rdataset, pass,
2015 						      preferred_glue))
2016 					goto next;
2017 
2018 #ifdef ALLOW_FILTER_AAAA_ON_V4
2019 				/*
2020 				 * Suppress AAAAs if asked and we are
2021 				 * not doing DNSSEC or are breaking DNSSEC.
2022 				 * Say so in the AD bit if we break DNSSEC.
2023 				 */
2024 				if (norender_rdataset(rdataset, options, sectionid)) {
2025 					if (sectionid == DNS_SECTION_ANSWER ||
2026 					    sectionid == DNS_SECTION_AUTHORITY)
2027 					    msg->flags &= ~DNS_MESSAGEFLAG_AD;
2028 					if (OPTOUT(rdataset))
2029 					    msg->flags &= ~DNS_MESSAGEFLAG_AD;
2030 					goto next;
2031 				}
2032 
2033 #endif
2034 				st = *(msg->buffer);
2035 
2036 				count = 0;
2037 				if (partial)
2038 					result = dns_rdataset_towirepartial(
2039 							  rdataset,
2040 							  name,
2041 							  msg->cctx,
2042 							  msg->buffer,
2043 							  msg->order,
2044 							  msg->order_arg,
2045 							  rd_options,
2046 							  &count,
2047 							  NULL);
2048 				else
2049 					result = dns_rdataset_towiresorted(
2050 							  rdataset,
2051 							  name,
2052 							  msg->cctx,
2053 							  msg->buffer,
2054 							  msg->order,
2055 							  msg->order_arg,
2056 							  rd_options,
2057 							  &count);
2058 
2059 				total += count;
2060 
2061 				/*
2062 				 * If out of space, record stats on what we
2063 				 * rendered so far, and return that status.
2064 				 *
2065 				 * XXXMLG Need to change this when
2066 				 * dns_rdataset_towire() can render partial
2067 				 * sets starting at some arbitrary point in the
2068 				 * set.  This will include setting a bit in the
2069 				 * rdataset to indicate that a partial
2070 				 * rendering was done, and some state saved
2071 				 * somewhere (probably in the message struct)
2072 				 * to indicate where to continue from.
2073 				 */
2074 				if (partial && result == ISC_R_NOSPACE) {
2075 					msg->buffer->length += msg->reserved;
2076 					msg->counts[sectionid] += total;
2077 					return (result);
2078 				}
2079 				if (result != ISC_R_SUCCESS) {
2080 					INSIST(st.used < 65536);
2081 					dns_compress_rollback(msg->cctx,
2082 							(isc_uint16_t)st.used);
2083 					*(msg->buffer) = st;  /* rollback */
2084 					msg->buffer->length += msg->reserved;
2085 					msg->counts[sectionid] += total;
2086 					return (result);
2087 				}
2088 
2089 				/*
2090 				 * If we have rendered non-validated data,
2091 				 * ensure that the AD bit is not set.
2092 				 */
2093 				if (rdataset->trust != dns_trust_secure &&
2094 				    (sectionid == DNS_SECTION_ANSWER ||
2095 				     sectionid == DNS_SECTION_AUTHORITY))
2096 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
2097 				if (OPTOUT(rdataset))
2098 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
2099 
2100 				rdataset->attributes |=
2101 					DNS_RDATASETATTR_RENDERED;
2102 
2103 			next:
2104 				rdataset = next_rdataset;
2105 			}
2106 
2107 			name = next_name;
2108 		}
2109 	} while (--pass != 0);
2110 
2111 	msg->buffer->length += msg->reserved;
2112 	msg->counts[sectionid] += total;
2113 
2114 	return (ISC_R_SUCCESS);
2115 }
2116 
2117 void
dns_message_renderheader(dns_message_t * msg,isc_buffer_t * target)2118 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2119 	isc_uint16_t tmp;
2120 	isc_region_t r;
2121 
2122 	REQUIRE(DNS_MESSAGE_VALID(msg));
2123 	REQUIRE(target != NULL);
2124 
2125 	isc_buffer_availableregion(target, &r);
2126 	REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2127 
2128 	isc_buffer_putuint16(target, msg->id);
2129 
2130 	tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2131 	       & DNS_MESSAGE_OPCODE_MASK);
2132 	tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2133 	tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2134 
2135 	INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
2136 	       msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
2137 	       msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2138 	       msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2139 
2140 	isc_buffer_putuint16(target, tmp);
2141 	isc_buffer_putuint16(target,
2142 			    (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2143 	isc_buffer_putuint16(target,
2144 			    (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2145 	isc_buffer_putuint16(target,
2146 			    (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2147 	isc_buffer_putuint16(target,
2148 			    (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2149 }
2150 
2151 isc_result_t
dns_message_renderend(dns_message_t * msg)2152 dns_message_renderend(dns_message_t *msg) {
2153 	isc_buffer_t tmpbuf;
2154 	isc_region_t r;
2155 	int result;
2156 	unsigned int count;
2157 
2158 	REQUIRE(DNS_MESSAGE_VALID(msg));
2159 	REQUIRE(msg->buffer != NULL);
2160 
2161 	if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2162 		/*
2163 		 * We have an extended rcode but are not using EDNS.
2164 		 */
2165 		return (DNS_R_FORMERR);
2166 	}
2167 
2168 	/*
2169 	 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
2170 	 * clear all rdatasets from the message except for the question
2171 	 * before adding the OPT, TSIG or SIG(0).  If the question doesn't
2172 	 * fit, don't include it.
2173 	 */
2174 	if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
2175 	    (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2176 	{
2177 		isc_buffer_t *buf;
2178 
2179 		msgresetnames(msg, DNS_SECTION_ANSWER);
2180 		buf = msg->buffer;
2181 		dns_message_renderreset(msg);
2182 		msg->buffer = buf;
2183 		isc_buffer_clear(msg->buffer);
2184 		isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2185 		dns_compress_rollback(msg->cctx, 0);
2186 		result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2187 						   0);
2188 		if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2189 			return (result);
2190 	}
2191 
2192 	/*
2193 	 * If we've got an OPT record, render it.
2194 	 */
2195 	if (msg->opt != NULL) {
2196 		dns_message_renderrelease(msg, msg->opt_reserved);
2197 		msg->opt_reserved = 0;
2198 		/*
2199 		 * Set the extended rcode.
2200 		 */
2201 		msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2202 		msg->opt->ttl |= ((msg->rcode << 20) &
2203 				  DNS_MESSAGE_EDNSRCODE_MASK);
2204 		/*
2205 		 * Render.
2206 		 */
2207 		count = 0;
2208 		result = renderset(msg->opt, dns_rootname, msg->cctx,
2209 				   msg->buffer, msg->reserved, 0, &count);
2210 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2211 		if (result != ISC_R_SUCCESS)
2212 			return (result);
2213 	}
2214 
2215 	/*
2216 	 * If we're adding a TSIG record, generate and render it.
2217 	 */
2218 	if (msg->tsigkey != NULL) {
2219 		dns_message_renderrelease(msg, msg->sig_reserved);
2220 		msg->sig_reserved = 0;
2221 		result = dns_tsig_sign(msg);
2222 		if (result != ISC_R_SUCCESS)
2223 			return (result);
2224 		count = 0;
2225 		result = renderset(msg->tsig, msg->tsigname, msg->cctx,
2226 				   msg->buffer, msg->reserved, 0, &count);
2227 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2228 		if (result != ISC_R_SUCCESS)
2229 			return (result);
2230 	}
2231 
2232 	/*
2233 	 * If we're adding a SIG(0) record, generate and render it.
2234 	 */
2235 	if (msg->sig0key != NULL) {
2236 		dns_message_renderrelease(msg, msg->sig_reserved);
2237 		msg->sig_reserved = 0;
2238 		result = dns_dnssec_signmessage(msg, msg->sig0key);
2239 		if (result != ISC_R_SUCCESS)
2240 			return (result);
2241 		count = 0;
2242 		/*
2243 		 * Note: dns_rootname is used here, not msg->sig0name, since
2244 		 * the owner name of a SIG(0) is irrelevant, and will not
2245 		 * be set in a message being rendered.
2246 		 */
2247 		result = renderset(msg->sig0, dns_rootname, msg->cctx,
2248 				   msg->buffer, msg->reserved, 0, &count);
2249 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2250 		if (result != ISC_R_SUCCESS)
2251 			return (result);
2252 	}
2253 
2254 	isc_buffer_usedregion(msg->buffer, &r);
2255 	isc_buffer_init(&tmpbuf, r.base, r.length);
2256 
2257 	dns_message_renderheader(msg, &tmpbuf);
2258 
2259 	msg->buffer = NULL;  /* forget about this buffer only on success XXX */
2260 
2261 	return (ISC_R_SUCCESS);
2262 }
2263 
2264 void
dns_message_renderreset(dns_message_t * msg)2265 dns_message_renderreset(dns_message_t *msg) {
2266 	unsigned int i;
2267 	dns_name_t *name;
2268 	dns_rdataset_t *rds;
2269 
2270 	/*
2271 	 * Reset the message so that it may be rendered again.
2272 	 */
2273 
2274 	REQUIRE(DNS_MESSAGE_VALID(msg));
2275 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2276 
2277 	msg->buffer = NULL;
2278 
2279 	for (i = 0; i < DNS_SECTION_MAX; i++) {
2280 		msg->cursors[i] = NULL;
2281 		msg->counts[i] = 0;
2282 		for (name = ISC_LIST_HEAD(msg->sections[i]);
2283 		     name != NULL;
2284 		     name = ISC_LIST_NEXT(name, link)) {
2285 			for (rds = ISC_LIST_HEAD(name->list);
2286 			     rds != NULL;
2287 			     rds = ISC_LIST_NEXT(rds, link)) {
2288 				rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2289 			}
2290 		}
2291 	}
2292 	if (msg->tsigname != NULL)
2293 		dns_message_puttempname(msg, &msg->tsigname);
2294 	if (msg->tsig != NULL) {
2295 		dns_rdataset_disassociate(msg->tsig);
2296 		dns_message_puttemprdataset(msg, &msg->tsig);
2297 	}
2298 	if (msg->sig0 != NULL) {
2299 		dns_rdataset_disassociate(msg->sig0);
2300 		dns_message_puttemprdataset(msg, &msg->sig0);
2301 	}
2302 }
2303 
2304 isc_result_t
dns_message_firstname(dns_message_t * msg,dns_section_t section)2305 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2306 	REQUIRE(DNS_MESSAGE_VALID(msg));
2307 	REQUIRE(VALID_NAMED_SECTION(section));
2308 
2309 	msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2310 
2311 	if (msg->cursors[section] == NULL)
2312 		return (ISC_R_NOMORE);
2313 
2314 	return (ISC_R_SUCCESS);
2315 }
2316 
2317 isc_result_t
dns_message_nextname(dns_message_t * msg,dns_section_t section)2318 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2319 	REQUIRE(DNS_MESSAGE_VALID(msg));
2320 	REQUIRE(VALID_NAMED_SECTION(section));
2321 	REQUIRE(msg->cursors[section] != NULL);
2322 
2323 	msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2324 
2325 	if (msg->cursors[section] == NULL)
2326 		return (ISC_R_NOMORE);
2327 
2328 	return (ISC_R_SUCCESS);
2329 }
2330 
2331 void
dns_message_currentname(dns_message_t * msg,dns_section_t section,dns_name_t ** name)2332 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2333 			dns_name_t **name)
2334 {
2335 	REQUIRE(DNS_MESSAGE_VALID(msg));
2336 	REQUIRE(VALID_NAMED_SECTION(section));
2337 	REQUIRE(name != NULL && *name == NULL);
2338 	REQUIRE(msg->cursors[section] != NULL);
2339 
2340 	*name = msg->cursors[section];
2341 }
2342 
2343 isc_result_t
dns_message_findname(dns_message_t * msg,dns_section_t section,dns_name_t * target,dns_rdatatype_t type,dns_rdatatype_t covers,dns_name_t ** name,dns_rdataset_t ** rdataset)2344 dns_message_findname(dns_message_t *msg, dns_section_t section,
2345 		     dns_name_t *target, dns_rdatatype_t type,
2346 		     dns_rdatatype_t covers, dns_name_t **name,
2347 		     dns_rdataset_t **rdataset)
2348 {
2349 	dns_name_t *foundname;
2350 	isc_result_t result;
2351 
2352 	/*
2353 	 * XXX These requirements are probably too intensive, especially
2354 	 * where things can be NULL, but as they are they ensure that if
2355 	 * something is NON-NULL, indicating that the caller expects it
2356 	 * to be filled in, that we can in fact fill it in.
2357 	 */
2358 	REQUIRE(msg != NULL);
2359 	REQUIRE(VALID_SECTION(section));
2360 	REQUIRE(target != NULL);
2361 	REQUIRE(name == NULL || *name == NULL);
2362 
2363 	if (type == dns_rdatatype_any) {
2364 		REQUIRE(rdataset == NULL);
2365 	} else {
2366 		REQUIRE(rdataset == NULL || *rdataset == NULL);
2367 	}
2368 
2369 	result = findname(&foundname, target,
2370 			  &msg->sections[section]);
2371 
2372 	if (result == ISC_R_NOTFOUND)
2373 		return (DNS_R_NXDOMAIN);
2374 	else if (result != ISC_R_SUCCESS)
2375 		return (result);
2376 
2377 	if (name != NULL)
2378 		*name = foundname;
2379 
2380 	/*
2381 	 * And now look for the type.
2382 	 */
2383 	if (ISC_UNLIKELY(type == dns_rdatatype_any))
2384 		return (ISC_R_SUCCESS);
2385 
2386 	result = dns_message_findtype(foundname, type, covers, rdataset);
2387 	if (result == ISC_R_NOTFOUND)
2388 		return (DNS_R_NXRRSET);
2389 
2390 	return (result);
2391 }
2392 
2393 void
dns_message_movename(dns_message_t * msg,dns_name_t * name,dns_section_t fromsection,dns_section_t tosection)2394 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2395 		     dns_section_t fromsection,
2396 		     dns_section_t tosection)
2397 {
2398 	REQUIRE(msg != NULL);
2399 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2400 	REQUIRE(name != NULL);
2401 	REQUIRE(VALID_NAMED_SECTION(fromsection));
2402 	REQUIRE(VALID_NAMED_SECTION(tosection));
2403 
2404 	/*
2405 	 * Unlink the name from the old section
2406 	 */
2407 	ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2408 	ISC_LIST_APPEND(msg->sections[tosection], name, link);
2409 }
2410 
2411 void
dns_message_addname(dns_message_t * msg,dns_name_t * name,dns_section_t section)2412 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2413 		    dns_section_t section)
2414 {
2415 	REQUIRE(msg != NULL);
2416 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2417 	REQUIRE(name != NULL);
2418 	REQUIRE(VALID_NAMED_SECTION(section));
2419 
2420 	ISC_LIST_APPEND(msg->sections[section], name, link);
2421 }
2422 
2423 void
dns_message_removename(dns_message_t * msg,dns_name_t * name,dns_section_t section)2424 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2425 		       dns_section_t section)
2426 {
2427 	REQUIRE(msg != NULL);
2428 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2429 	REQUIRE(name != NULL);
2430 	REQUIRE(VALID_NAMED_SECTION(section));
2431 
2432 	ISC_LIST_UNLINK(msg->sections[section], name, link);
2433 }
2434 
2435 isc_result_t
dns_message_gettempname(dns_message_t * msg,dns_name_t ** item)2436 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2437 	REQUIRE(DNS_MESSAGE_VALID(msg));
2438 	REQUIRE(item != NULL && *item == NULL);
2439 
2440 	*item = isc_mempool_get(msg->namepool);
2441 	if (*item == NULL)
2442 		return (ISC_R_NOMEMORY);
2443 	dns_name_init(*item, NULL);
2444 
2445 	return (ISC_R_SUCCESS);
2446 }
2447 
2448 isc_result_t
dns_message_gettempoffsets(dns_message_t * msg,dns_offsets_t ** item)2449 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2450 	REQUIRE(DNS_MESSAGE_VALID(msg));
2451 	REQUIRE(item != NULL && *item == NULL);
2452 
2453 	*item = newoffsets(msg);
2454 	if (*item == NULL)
2455 		return (ISC_R_NOMEMORY);
2456 
2457 	return (ISC_R_SUCCESS);
2458 }
2459 
2460 isc_result_t
dns_message_gettemprdata(dns_message_t * msg,dns_rdata_t ** item)2461 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2462 	REQUIRE(DNS_MESSAGE_VALID(msg));
2463 	REQUIRE(item != NULL && *item == NULL);
2464 
2465 	*item = newrdata(msg);
2466 	if (*item == NULL)
2467 		return (ISC_R_NOMEMORY);
2468 
2469 	return (ISC_R_SUCCESS);
2470 }
2471 
2472 isc_result_t
dns_message_gettemprdataset(dns_message_t * msg,dns_rdataset_t ** item)2473 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2474 	REQUIRE(DNS_MESSAGE_VALID(msg));
2475 	REQUIRE(item != NULL && *item == NULL);
2476 
2477 	*item = isc_mempool_get(msg->rdspool);
2478 	if (*item == NULL)
2479 		return (ISC_R_NOMEMORY);
2480 
2481 	dns_rdataset_init(*item);
2482 
2483 	return (ISC_R_SUCCESS);
2484 }
2485 
2486 isc_result_t
dns_message_gettemprdatalist(dns_message_t * msg,dns_rdatalist_t ** item)2487 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2488 	REQUIRE(DNS_MESSAGE_VALID(msg));
2489 	REQUIRE(item != NULL && *item == NULL);
2490 
2491 	*item = newrdatalist(msg);
2492 	if (*item == NULL)
2493 		return (ISC_R_NOMEMORY);
2494 
2495 	return (ISC_R_SUCCESS);
2496 }
2497 
2498 void
dns_message_puttempname(dns_message_t * msg,dns_name_t ** item)2499 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2500 	REQUIRE(DNS_MESSAGE_VALID(msg));
2501 	REQUIRE(item != NULL && *item != NULL);
2502 
2503 	if (dns_name_dynamic(*item))
2504 		dns_name_free(*item, msg->mctx);
2505 	isc_mempool_put(msg->namepool, *item);
2506 	*item = NULL;
2507 }
2508 
2509 void
dns_message_puttemprdata(dns_message_t * msg,dns_rdata_t ** item)2510 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2511 	REQUIRE(DNS_MESSAGE_VALID(msg));
2512 	REQUIRE(item != NULL && *item != NULL);
2513 
2514 	releaserdata(msg, *item);
2515 	*item = NULL;
2516 }
2517 
2518 void
dns_message_puttemprdataset(dns_message_t * msg,dns_rdataset_t ** item)2519 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2520 	REQUIRE(DNS_MESSAGE_VALID(msg));
2521 	REQUIRE(item != NULL && *item != NULL);
2522 
2523 	REQUIRE(!dns_rdataset_isassociated(*item));
2524 	isc_mempool_put(msg->rdspool, *item);
2525 	*item = NULL;
2526 }
2527 
2528 void
dns_message_puttemprdatalist(dns_message_t * msg,dns_rdatalist_t ** item)2529 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2530 	REQUIRE(DNS_MESSAGE_VALID(msg));
2531 	REQUIRE(item != NULL && *item != NULL);
2532 
2533 	releaserdatalist(msg, *item);
2534 	*item = NULL;
2535 }
2536 
2537 isc_result_t
dns_message_peekheader(isc_buffer_t * source,dns_messageid_t * idp,unsigned int * flagsp)2538 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2539 		       unsigned int *flagsp)
2540 {
2541 	isc_region_t r;
2542 	isc_buffer_t buffer;
2543 	dns_messageid_t id;
2544 	unsigned int flags;
2545 
2546 	REQUIRE(source != NULL);
2547 
2548 	buffer = *source;
2549 
2550 	isc_buffer_remainingregion(&buffer, &r);
2551 	if (r.length < DNS_MESSAGE_HEADERLEN)
2552 		return (ISC_R_UNEXPECTEDEND);
2553 
2554 	id = isc_buffer_getuint16(&buffer);
2555 	flags = isc_buffer_getuint16(&buffer);
2556 	flags &= DNS_MESSAGE_FLAG_MASK;
2557 
2558 	if (flagsp != NULL)
2559 		*flagsp = flags;
2560 	if (idp != NULL)
2561 		*idp = id;
2562 
2563 	return (ISC_R_SUCCESS);
2564 }
2565 
2566 isc_result_t
dns_message_reply(dns_message_t * msg,isc_boolean_t want_question_section)2567 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2568 	unsigned int clear_from;
2569 	isc_result_t result;
2570 
2571 	REQUIRE(DNS_MESSAGE_VALID(msg));
2572 	REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2573 
2574 	if (!msg->header_ok)
2575 		return (DNS_R_FORMERR);
2576 	if (msg->opcode != dns_opcode_query &&
2577 	    msg->opcode != dns_opcode_notify)
2578 		want_question_section = ISC_FALSE;
2579 	if (msg->opcode == dns_opcode_update)
2580 		clear_from = DNS_SECTION_PREREQUISITE;
2581 	else if (want_question_section) {
2582 		if (!msg->question_ok)
2583 			return (DNS_R_FORMERR);
2584 		clear_from = DNS_SECTION_ANSWER;
2585 	} else
2586 		clear_from = DNS_SECTION_QUESTION;
2587 	msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2588 	msgresetnames(msg, clear_from);
2589 	msgresetopt(msg);
2590 	msgresetsigs(msg, ISC_TRUE);
2591 	msginitprivate(msg);
2592 	/*
2593 	 * We now clear most flags and then set QR, ensuring that the
2594 	 * reply's flags will be in a reasonable state.
2595 	 */
2596 	msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2597 	msg->flags |= DNS_MESSAGEFLAG_QR;
2598 
2599 	/*
2600 	 * This saves the query TSIG status, if the query was signed, and
2601 	 * reserves space in the reply for the TSIG.
2602 	 */
2603 	if (msg->tsigkey != NULL) {
2604 		unsigned int otherlen = 0;
2605 		msg->querytsigstatus = msg->tsigstatus;
2606 		msg->tsigstatus = dns_rcode_noerror;
2607 		if (msg->querytsigstatus == dns_tsigerror_badtime)
2608 			otherlen = 6;
2609 		msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2610 		result = dns_message_renderreserve(msg, msg->sig_reserved);
2611 		if (result != ISC_R_SUCCESS) {
2612 			msg->sig_reserved = 0;
2613 			return (result);
2614 		}
2615 	}
2616 	if (msg->saved.base != NULL) {
2617 		msg->query.base = msg->saved.base;
2618 		msg->query.length = msg->saved.length;
2619 		msg->free_query = msg->free_saved;
2620 		msg->saved.base = NULL;
2621 		msg->saved.length = 0;
2622 		msg->free_saved = 0;
2623 	}
2624 
2625 	return (ISC_R_SUCCESS);
2626 }
2627 
2628 dns_rdataset_t *
dns_message_getopt(dns_message_t * msg)2629 dns_message_getopt(dns_message_t *msg) {
2630 
2631 	/*
2632 	 * Get the OPT record for 'msg'.
2633 	 */
2634 
2635 	REQUIRE(DNS_MESSAGE_VALID(msg));
2636 
2637 	return (msg->opt);
2638 }
2639 
2640 isc_result_t
dns_message_setopt(dns_message_t * msg,dns_rdataset_t * opt)2641 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2642 	isc_result_t result;
2643 	dns_rdata_t rdata = DNS_RDATA_INIT;
2644 
2645 	/*
2646 	 * Set the OPT record for 'msg'.
2647 	 */
2648 
2649 	/*
2650 	 * The space required for an OPT record is:
2651 	 *
2652 	 *	1 byte for the name
2653 	 *	2 bytes for the type
2654 	 *	2 bytes for the class
2655 	 *	4 bytes for the ttl
2656 	 *	2 bytes for the rdata length
2657 	 * ---------------------------------
2658 	 *     11 bytes
2659 	 *
2660 	 * plus the length of the rdata.
2661 	 */
2662 
2663 	REQUIRE(DNS_MESSAGE_VALID(msg));
2664 	REQUIRE(opt->type == dns_rdatatype_opt);
2665 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2666 	REQUIRE(msg->state == DNS_SECTION_ANY);
2667 
2668 	msgresetopt(msg);
2669 
2670 	result = dns_rdataset_first(opt);
2671 	if (result != ISC_R_SUCCESS)
2672 		goto cleanup;
2673 	dns_rdataset_current(opt, &rdata);
2674 	msg->opt_reserved = 11 + rdata.length;
2675 	result = dns_message_renderreserve(msg, msg->opt_reserved);
2676 	if (result != ISC_R_SUCCESS) {
2677 		msg->opt_reserved = 0;
2678 		goto cleanup;
2679 	}
2680 
2681 	msg->opt = opt;
2682 
2683 	return (ISC_R_SUCCESS);
2684 
2685  cleanup:
2686 	dns_rdataset_disassociate(opt);
2687 	dns_message_puttemprdataset(msg, &opt);
2688 	return (result);
2689 }
2690 
2691 dns_rdataset_t *
dns_message_gettsig(dns_message_t * msg,dns_name_t ** owner)2692 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2693 
2694 	/*
2695 	 * Get the TSIG record and owner for 'msg'.
2696 	 */
2697 
2698 	REQUIRE(DNS_MESSAGE_VALID(msg));
2699 	REQUIRE(owner == NULL || *owner == NULL);
2700 
2701 	if (owner != NULL)
2702 		*owner = msg->tsigname;
2703 	return (msg->tsig);
2704 }
2705 
2706 isc_result_t
dns_message_settsigkey(dns_message_t * msg,dns_tsigkey_t * key)2707 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2708 	isc_result_t result;
2709 
2710 	/*
2711 	 * Set the TSIG key for 'msg'
2712 	 */
2713 
2714 	REQUIRE(DNS_MESSAGE_VALID(msg));
2715 	REQUIRE(msg->state == DNS_SECTION_ANY);
2716 
2717 	if (key == NULL && msg->tsigkey != NULL) {
2718 		if (msg->sig_reserved != 0) {
2719 			dns_message_renderrelease(msg, msg->sig_reserved);
2720 			msg->sig_reserved = 0;
2721 		}
2722 		dns_tsigkey_detach(&msg->tsigkey);
2723 	}
2724 	if (key != NULL) {
2725 		REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2726 		dns_tsigkey_attach(key, &msg->tsigkey);
2727 		if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2728 			msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2729 			result = dns_message_renderreserve(msg,
2730 							   msg->sig_reserved);
2731 			if (result != ISC_R_SUCCESS) {
2732 				dns_tsigkey_detach(&msg->tsigkey);
2733 				msg->sig_reserved = 0;
2734 				return (result);
2735 			}
2736 		}
2737 	}
2738 	return (ISC_R_SUCCESS);
2739 }
2740 
2741 dns_tsigkey_t *
dns_message_gettsigkey(dns_message_t * msg)2742 dns_message_gettsigkey(dns_message_t *msg) {
2743 
2744 	/*
2745 	 * Get the TSIG key for 'msg'
2746 	 */
2747 
2748 	REQUIRE(DNS_MESSAGE_VALID(msg));
2749 
2750 	return (msg->tsigkey);
2751 }
2752 
2753 isc_result_t
dns_message_setquerytsig(dns_message_t * msg,isc_buffer_t * querytsig)2754 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2755 	dns_rdata_t *rdata = NULL;
2756 	dns_rdatalist_t *list = NULL;
2757 	dns_rdataset_t *set = NULL;
2758 	isc_buffer_t *buf = NULL;
2759 	isc_region_t r;
2760 	isc_result_t result;
2761 
2762 	REQUIRE(DNS_MESSAGE_VALID(msg));
2763 	REQUIRE(msg->querytsig == NULL);
2764 
2765 	if (querytsig == NULL)
2766 		return (ISC_R_SUCCESS);
2767 
2768 	result = dns_message_gettemprdata(msg, &rdata);
2769 	if (result != ISC_R_SUCCESS)
2770 		goto cleanup;
2771 
2772 	result = dns_message_gettemprdatalist(msg, &list);
2773 	if (result != ISC_R_SUCCESS)
2774 		goto cleanup;
2775 	result = dns_message_gettemprdataset(msg, &set);
2776 	if (result != ISC_R_SUCCESS)
2777 		goto cleanup;
2778 
2779 	isc_buffer_usedregion(querytsig, &r);
2780 	result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2781 	if (result != ISC_R_SUCCESS)
2782 		goto cleanup;
2783 	isc_buffer_putmem(buf, r.base, r.length);
2784 	isc_buffer_usedregion(buf, &r);
2785 	dns_rdata_init(rdata);
2786 	dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2787 	dns_message_takebuffer(msg, &buf);
2788 	ISC_LIST_APPEND(list->rdata, rdata, link);
2789 	result = dns_rdatalist_tordataset(list, set);
2790 	if (result != ISC_R_SUCCESS)
2791 		goto cleanup;
2792 
2793 	msg->querytsig = set;
2794 
2795 	return (result);
2796 
2797  cleanup:
2798 	if (rdata != NULL)
2799 		dns_message_puttemprdata(msg, &rdata);
2800 	if (list != NULL)
2801 		dns_message_puttemprdatalist(msg, &list);
2802 	if (set != NULL)
2803 		dns_message_puttemprdataset(msg, &set);
2804 	return (ISC_R_NOMEMORY);
2805 }
2806 
2807 isc_result_t
dns_message_getquerytsig(dns_message_t * msg,isc_mem_t * mctx,isc_buffer_t ** querytsig)2808 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2809 			 isc_buffer_t **querytsig) {
2810 	isc_result_t result;
2811 	dns_rdata_t rdata = DNS_RDATA_INIT;
2812 	isc_region_t r;
2813 
2814 	REQUIRE(DNS_MESSAGE_VALID(msg));
2815 	REQUIRE(mctx != NULL);
2816 	REQUIRE(querytsig != NULL && *querytsig == NULL);
2817 
2818 	if (msg->tsig == NULL)
2819 		return (ISC_R_SUCCESS);
2820 
2821 	result = dns_rdataset_first(msg->tsig);
2822 	if (result != ISC_R_SUCCESS)
2823 		return (result);
2824 	dns_rdataset_current(msg->tsig, &rdata);
2825 	dns_rdata_toregion(&rdata, &r);
2826 
2827 	result = isc_buffer_allocate(mctx, querytsig, r.length);
2828 	if (result != ISC_R_SUCCESS)
2829 		return (result);
2830 	isc_buffer_putmem(*querytsig, r.base, r.length);
2831 	return (ISC_R_SUCCESS);
2832 }
2833 
2834 dns_rdataset_t *
dns_message_getsig0(dns_message_t * msg,dns_name_t ** owner)2835 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2836 
2837 	/*
2838 	 * Get the SIG(0) record for 'msg'.
2839 	 */
2840 
2841 	REQUIRE(DNS_MESSAGE_VALID(msg));
2842 	REQUIRE(owner == NULL || *owner == NULL);
2843 
2844 	if (msg->sig0 != NULL && owner != NULL) {
2845 		/* If dns_message_getsig0 is called on a rendered message
2846 		 * after the SIG(0) has been applied, we need to return the
2847 		 * root name, not NULL.
2848 		 */
2849 		if (msg->sig0name == NULL)
2850 			*owner = dns_rootname;
2851 		else
2852 			*owner = msg->sig0name;
2853 	}
2854 	return (msg->sig0);
2855 }
2856 
2857 isc_result_t
dns_message_setsig0key(dns_message_t * msg,dst_key_t * key)2858 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2859 	isc_region_t r;
2860 	unsigned int x;
2861 	isc_result_t result;
2862 
2863 	/*
2864 	 * Set the SIG(0) key for 'msg'
2865 	 */
2866 
2867 	/*
2868 	 * The space required for an SIG(0) record is:
2869 	 *
2870 	 *	1 byte for the name
2871 	 *	2 bytes for the type
2872 	 *	2 bytes for the class
2873 	 *	4 bytes for the ttl
2874 	 *	2 bytes for the type covered
2875 	 *	1 byte for the algorithm
2876 	 *	1 bytes for the labels
2877 	 *	4 bytes for the original ttl
2878 	 *	4 bytes for the signature expiration
2879 	 *	4 bytes for the signature inception
2880 	 *	2 bytes for the key tag
2881 	 *	n bytes for the signer's name
2882 	 *	x bytes for the signature
2883 	 * ---------------------------------
2884 	 *     27 + n + x bytes
2885 	 */
2886 	REQUIRE(DNS_MESSAGE_VALID(msg));
2887 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2888 	REQUIRE(msg->state == DNS_SECTION_ANY);
2889 
2890 	if (key != NULL) {
2891 		REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2892 		dns_name_toregion(dst_key_name(key), &r);
2893 		result = dst_key_sigsize(key, &x);
2894 		if (result != ISC_R_SUCCESS) {
2895 			msg->sig_reserved = 0;
2896 			return (result);
2897 		}
2898 		msg->sig_reserved = 27 + r.length + x;
2899 		result = dns_message_renderreserve(msg, msg->sig_reserved);
2900 		if (result != ISC_R_SUCCESS) {
2901 			msg->sig_reserved = 0;
2902 			return (result);
2903 		}
2904 		msg->sig0key = key;
2905 	}
2906 	return (ISC_R_SUCCESS);
2907 }
2908 
2909 dst_key_t *
dns_message_getsig0key(dns_message_t * msg)2910 dns_message_getsig0key(dns_message_t *msg) {
2911 
2912 	/*
2913 	 * Get the SIG(0) key for 'msg'
2914 	 */
2915 
2916 	REQUIRE(DNS_MESSAGE_VALID(msg));
2917 
2918 	return (msg->sig0key);
2919 }
2920 
2921 void
dns_message_takebuffer(dns_message_t * msg,isc_buffer_t ** buffer)2922 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2923 	REQUIRE(DNS_MESSAGE_VALID(msg));
2924 	REQUIRE(buffer != NULL);
2925 	REQUIRE(ISC_BUFFER_VALID(*buffer));
2926 
2927 	ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2928 	*buffer = NULL;
2929 }
2930 
2931 isc_result_t
dns_message_signer(dns_message_t * msg,dns_name_t * signer)2932 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2933 	isc_result_t result = ISC_R_SUCCESS;
2934 	dns_rdata_t rdata = DNS_RDATA_INIT;
2935 
2936 	REQUIRE(DNS_MESSAGE_VALID(msg));
2937 	REQUIRE(signer != NULL);
2938 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2939 
2940 	if (msg->tsig == NULL && msg->sig0 == NULL)
2941 		return (ISC_R_NOTFOUND);
2942 
2943 	if (msg->verify_attempted == 0)
2944 		return (DNS_R_NOTVERIFIEDYET);
2945 
2946 	if (!dns_name_hasbuffer(signer)) {
2947 		isc_buffer_t *dynbuf = NULL;
2948 		result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2949 		if (result != ISC_R_SUCCESS)
2950 			return (result);
2951 		dns_name_setbuffer(signer, dynbuf);
2952 		dns_message_takebuffer(msg, &dynbuf);
2953 	}
2954 
2955 	if (msg->sig0 != NULL) {
2956 		dns_rdata_sig_t sig;
2957 
2958 		result = dns_rdataset_first(msg->sig0);
2959 		INSIST(result == ISC_R_SUCCESS);
2960 		dns_rdataset_current(msg->sig0, &rdata);
2961 
2962 		result = dns_rdata_tostruct(&rdata, &sig, NULL);
2963 		if (result != ISC_R_SUCCESS)
2964 			return (result);
2965 
2966 		if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2967 			result = ISC_R_SUCCESS;
2968 		else
2969 			result = DNS_R_SIGINVALID;
2970 		dns_name_clone(&sig.signer, signer);
2971 		dns_rdata_freestruct(&sig);
2972 	} else {
2973 		dns_name_t *identity;
2974 		dns_rdata_any_tsig_t tsig;
2975 
2976 		result = dns_rdataset_first(msg->tsig);
2977 		INSIST(result == ISC_R_SUCCESS);
2978 		dns_rdataset_current(msg->tsig, &rdata);
2979 
2980 		result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2981 		INSIST(result == ISC_R_SUCCESS);
2982 		if (msg->tsigstatus != dns_rcode_noerror)
2983 			result = DNS_R_TSIGVERIFYFAILURE;
2984 		else if (tsig.error != dns_rcode_noerror)
2985 			result = DNS_R_TSIGERRORSET;
2986 		else
2987 			result = ISC_R_SUCCESS;
2988 		dns_rdata_freestruct(&tsig);
2989 
2990 		if (msg->tsigkey == NULL) {
2991 			/*
2992 			 * If msg->tsigstatus & tsig.error are both
2993 			 * dns_rcode_noerror, the message must have been
2994 			 * verified, which means msg->tsigkey will be
2995 			 * non-NULL.
2996 			 */
2997 			INSIST(result != ISC_R_SUCCESS);
2998 		} else {
2999 			identity = dns_tsigkey_identity(msg->tsigkey);
3000 			if (identity == NULL) {
3001 				if (result == ISC_R_SUCCESS)
3002 					result = DNS_R_NOIDENTITY;
3003 				identity = &msg->tsigkey->name;
3004 			}
3005 			dns_name_clone(identity, signer);
3006 		}
3007 	}
3008 
3009 	return (result);
3010 }
3011 
3012 void
dns_message_resetsig(dns_message_t * msg)3013 dns_message_resetsig(dns_message_t *msg) {
3014 	REQUIRE(DNS_MESSAGE_VALID(msg));
3015 	msg->verified_sig = 0;
3016 	msg->verify_attempted = 0;
3017 	msg->tsigstatus = dns_rcode_noerror;
3018 	msg->sig0status = dns_rcode_noerror;
3019 	msg->timeadjust = 0;
3020 	if (msg->tsigkey != NULL) {
3021 		dns_tsigkey_detach(&msg->tsigkey);
3022 		msg->tsigkey = NULL;
3023 	}
3024 }
3025 
3026 isc_result_t
dns_message_rechecksig(dns_message_t * msg,dns_view_t * view)3027 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
3028 	dns_message_resetsig(msg);
3029 	return (dns_message_checksig(msg, view));
3030 }
3031 
3032 #ifdef SKAN_MSG_DEBUG
3033 void
dns_message_dumpsig(dns_message_t * msg,char * txt1)3034 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
3035 	dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
3036 	dns_rdata_any_tsig_t querytsig;
3037 	isc_result_t result;
3038 
3039 	if (msg->tsig != NULL) {
3040 		result = dns_rdataset_first(msg->tsig);
3041 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3042 		dns_rdataset_current(msg->tsig, &querytsigrdata);
3043 		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3044 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3045 		hexdump(txt1, "TSIG", querytsig.signature,
3046 			querytsig.siglen);
3047 	}
3048 
3049 	if (msg->querytsig != NULL) {
3050 		result = dns_rdataset_first(msg->querytsig);
3051 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3052 		dns_rdataset_current(msg->querytsig, &querytsigrdata);
3053 		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3054 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3055 		hexdump(txt1, "QUERYTSIG", querytsig.signature,
3056 			querytsig.siglen);
3057 	}
3058 }
3059 #endif
3060 
3061 isc_result_t
dns_message_checksig(dns_message_t * msg,dns_view_t * view)3062 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3063 	isc_buffer_t b, msgb;
3064 
3065 	REQUIRE(DNS_MESSAGE_VALID(msg));
3066 
3067 	if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
3068 		return (ISC_R_SUCCESS);
3069 
3070 	INSIST(msg->saved.base != NULL);
3071 	isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3072 	isc_buffer_add(&msgb, msg->saved.length);
3073 	if (msg->tsigkey != NULL || msg->tsig != NULL) {
3074 #ifdef SKAN_MSG_DEBUG
3075 		dns_message_dumpsig(msg, "dns_message_checksig#1");
3076 #endif
3077 		if (view != NULL)
3078 			return (dns_view_checksig(view, &msgb, msg));
3079 		else
3080 			return (dns_tsig_verify(&msgb, msg, NULL, NULL));
3081 	} else {
3082 		dns_rdata_t rdata = DNS_RDATA_INIT;
3083 		dns_rdata_sig_t sig;
3084 		dns_rdataset_t keyset;
3085 		isc_result_t result;
3086 
3087 		result = dns_rdataset_first(msg->sig0);
3088 		INSIST(result == ISC_R_SUCCESS);
3089 		dns_rdataset_current(msg->sig0, &rdata);
3090 
3091 		/*
3092 		 * This can occur when the message is a dynamic update, since
3093 		 * the rdata length checking is relaxed.  This should not
3094 		 * happen in a well-formed message, since the SIG(0) is only
3095 		 * looked for in the additional section, and the dynamic update
3096 		 * meta-records are in the prerequisite and update sections.
3097 		 */
3098 		if (rdata.length == 0)
3099 			return (ISC_R_UNEXPECTEDEND);
3100 
3101 		result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3102 		if (result != ISC_R_SUCCESS)
3103 			return (result);
3104 
3105 		dns_rdataset_init(&keyset);
3106 		if (view == NULL)
3107 			return (DNS_R_KEYUNAUTHORIZED);
3108 		result = dns_view_simplefind(view, &sig.signer,
3109 					     dns_rdatatype_key /* SIG(0) */,
3110 					     0, 0, ISC_FALSE, &keyset, NULL);
3111 
3112 		if (result != ISC_R_SUCCESS) {
3113 			/* XXXBEW Should possibly create a fetch here */
3114 			result = DNS_R_KEYUNAUTHORIZED;
3115 			goto freesig;
3116 		} else if (keyset.trust < dns_trust_secure) {
3117 			/* XXXBEW Should call a validator here */
3118 			result = DNS_R_KEYUNAUTHORIZED;
3119 			goto freesig;
3120 		}
3121 		result = dns_rdataset_first(&keyset);
3122 		INSIST(result == ISC_R_SUCCESS);
3123 		for (;
3124 		     result == ISC_R_SUCCESS;
3125 		     result = dns_rdataset_next(&keyset))
3126 		{
3127 			dst_key_t *key = NULL;
3128 
3129 			dns_rdata_reset(&rdata);
3130 			dns_rdataset_current(&keyset, &rdata);
3131 			isc_buffer_init(&b, rdata.data, rdata.length);
3132 			isc_buffer_add(&b, rdata.length);
3133 
3134 			result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3135 						 &b, view->mctx, &key);
3136 			if (result != ISC_R_SUCCESS)
3137 				continue;
3138 			if (dst_key_alg(key) != sig.algorithm ||
3139 			    dst_key_id(key) != sig.keyid ||
3140 			    !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3141 			      dst_key_proto(key) == DNS_KEYPROTO_ANY))
3142 			{
3143 				dst_key_free(&key);
3144 				continue;
3145 			}
3146 			result = dns_dnssec_verifymessage(&msgb, msg, key);
3147 			dst_key_free(&key);
3148 			if (result == ISC_R_SUCCESS)
3149 				break;
3150 		}
3151 		if (result == ISC_R_NOMORE)
3152 			result = DNS_R_KEYUNAUTHORIZED;
3153 
3154  freesig:
3155 		if (dns_rdataset_isassociated(&keyset))
3156 			dns_rdataset_disassociate(&keyset);
3157 		dns_rdata_freestruct(&sig);
3158 		return (result);
3159 	}
3160 }
3161 
3162 isc_result_t
dns_message_sectiontotext(dns_message_t * msg,dns_section_t section,const dns_master_style_t * style,dns_messagetextflag_t flags,isc_buffer_t * target)3163 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3164 			  const dns_master_style_t *style,
3165 			  dns_messagetextflag_t flags,
3166 			  isc_buffer_t *target) {
3167 	dns_name_t *name, empty_name;
3168 	dns_rdataset_t *rdataset;
3169 	isc_result_t result;
3170 	isc_boolean_t seensoa = ISC_FALSE;
3171 
3172 	REQUIRE(DNS_MESSAGE_VALID(msg));
3173 	REQUIRE(target != NULL);
3174 	REQUIRE(VALID_SECTION(section));
3175 
3176 	if (ISC_LIST_EMPTY(msg->sections[section]))
3177 		return (ISC_R_SUCCESS);
3178 
3179 	if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3180 		ADD_STRING(target, ";; ");
3181 		if (msg->opcode != dns_opcode_update) {
3182 			ADD_STRING(target, sectiontext[section]);
3183 		} else {
3184 			ADD_STRING(target, updsectiontext[section]);
3185 		}
3186 		ADD_STRING(target, " SECTION:\n");
3187 	}
3188 
3189 	dns_name_init(&empty_name, NULL);
3190 	result = dns_message_firstname(msg, section);
3191 	if (result != ISC_R_SUCCESS) {
3192 		return (result);
3193 	}
3194 	do {
3195 		name = NULL;
3196 		dns_message_currentname(msg, section, &name);
3197 		for (rdataset = ISC_LIST_HEAD(name->list);
3198 		     rdataset != NULL;
3199 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
3200 			if (section == DNS_SECTION_ANSWER &&
3201 			    rdataset->type == dns_rdatatype_soa) {
3202 				if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3203 					continue;
3204 				if (seensoa &&
3205 				    (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3206 					continue;
3207 				seensoa = ISC_TRUE;
3208 			}
3209 			if (section == DNS_SECTION_QUESTION) {
3210 				ADD_STRING(target, ";");
3211 				result = dns_master_questiontotext(name,
3212 								   rdataset,
3213 								   style,
3214 								   target);
3215 			} else {
3216 				result = dns_master_rdatasettotext(name,
3217 								   rdataset,
3218 								   style,
3219 								   target);
3220 			}
3221 			if (result != ISC_R_SUCCESS)
3222 				return (result);
3223 		}
3224 		result = dns_message_nextname(msg, section);
3225 	} while (result == ISC_R_SUCCESS);
3226 	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3227 	    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3228 		ADD_STRING(target, "\n");
3229 	if (result == ISC_R_NOMORE)
3230 		result = ISC_R_SUCCESS;
3231 	return (result);
3232 }
3233 
3234 isc_result_t
dns_message_pseudosectiontotext(dns_message_t * msg,dns_pseudosection_t section,const dns_master_style_t * style,dns_messagetextflag_t flags,isc_buffer_t * target)3235 dns_message_pseudosectiontotext(dns_message_t *msg,
3236 				dns_pseudosection_t section,
3237 				const dns_master_style_t *style,
3238 				dns_messagetextflag_t flags,
3239 				isc_buffer_t *target)
3240 {
3241 	dns_rdataset_t *ps = NULL;
3242 	dns_name_t *name = NULL;
3243 	isc_result_t result;
3244 	char buf[sizeof("1234567890")];
3245 	isc_uint32_t mbz;
3246 	dns_rdata_t rdata;
3247 	isc_buffer_t optbuf;
3248 	isc_uint16_t optcode, optlen;
3249 	unsigned char *optdata;
3250 
3251 	REQUIRE(DNS_MESSAGE_VALID(msg));
3252 	REQUIRE(target != NULL);
3253 	REQUIRE(VALID_PSEUDOSECTION(section));
3254 
3255 	switch (section) {
3256 	case DNS_PSEUDOSECTION_OPT:
3257 		ps = dns_message_getopt(msg);
3258 		if (ps == NULL)
3259 			return (ISC_R_SUCCESS);
3260 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3261 			ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3262 		ADD_STRING(target, "; EDNS: version: ");
3263 		snprintf(buf, sizeof(buf), "%u",
3264 			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3265 		ADD_STRING(target, buf);
3266 		ADD_STRING(target, ", flags:");
3267 		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3268 			ADD_STRING(target, " do");
3269 		mbz = ps->ttl & 0xffff;
3270 		mbz &= ~DNS_MESSAGEEXTFLAG_DO;		/* Known Flags. */
3271 		if (mbz != 0) {
3272 			ADD_STRING(target, "; MBZ: ");
3273 			snprintf(buf, sizeof(buf), "0x%.4x", mbz);
3274 			ADD_STRING(target, buf);
3275 			ADD_STRING(target, ", udp: ");
3276 		} else
3277 			ADD_STRING(target, "; udp: ");
3278 		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3279 		ADD_STRING(target, buf);
3280 
3281 		result = dns_rdataset_first(ps);
3282 		if (result != ISC_R_SUCCESS)
3283 			return (ISC_R_SUCCESS);
3284 
3285 		/* Print EDNS info, if any */
3286 		dns_rdata_init(&rdata);
3287 		dns_rdataset_current(ps, &rdata);
3288 
3289 		isc_buffer_init(&optbuf, rdata.data, rdata.length);
3290 		isc_buffer_add(&optbuf, rdata.length);
3291 		while (isc_buffer_remaininglength(&optbuf) != 0) {
3292 			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3293 			optcode = isc_buffer_getuint16(&optbuf);
3294 			optlen = isc_buffer_getuint16(&optbuf);
3295 			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3296 
3297 			if (optcode == DNS_OPT_NSID) {
3298 				ADD_STRING(target, "; NSID");
3299 			} else if (optcode == DNS_OPT_COOKIE) {
3300 				ADD_STRING(target, "; COOKIE");
3301 			} else if (optcode == DNS_OPT_EXPIRE) {
3302 				if (optlen == 4) {
3303 					isc_uint32_t secs;
3304 					secs = isc_buffer_getuint32(&optbuf);
3305 					ADD_STRING(target, "; EXPIRE: ");
3306 					snprintf(buf, sizeof(buf), "%u", secs);
3307 					ADD_STRING(target, buf);
3308 					ADD_STRING(target, " (");
3309 					result = dns_ttl_totext(secs,
3310 								ISC_TRUE,
3311 								target);
3312 					if (result != ISC_R_SUCCESS)
3313 						return (result);
3314 					ADD_STRING(target, ")\n");
3315 					continue;
3316 				}
3317 				ADD_STRING(target, "; EXPIRE");
3318 			} else if (optcode == DNS_OPT_PAD) {
3319 				ADD_STRING(target, "; PAD");
3320 			} else {
3321 				ADD_STRING(target, "; OPT=");
3322 				snprintf(buf, sizeof(buf), "%u", optcode);
3323 				ADD_STRING(target, buf);
3324 			}
3325 
3326 			if (optlen != 0) {
3327 				int i;
3328 				ADD_STRING(target, ": ");
3329 
3330 				optdata = isc_buffer_current(&optbuf);
3331 				for (i = 0; i < optlen; i++) {
3332 					const char *sep;
3333 					switch (optcode) {
3334 					case DNS_OPT_COOKIE:
3335 						sep = "";
3336 						break;
3337 					default:
3338 						sep = " ";
3339 						break;
3340 					}
3341 					snprintf(buf, sizeof(buf), "%02x%s",
3342 						 optdata[i], sep);
3343 					ADD_STRING(target, buf);
3344 				}
3345 
3346 				isc_buffer_forward(&optbuf, optlen);
3347 
3348 				if (optcode == DNS_OPT_COOKIE) {
3349 					ADD_STRING(target, "\n");
3350 					continue;
3351 				}
3352 
3353 				/*
3354 				 * For non-COOKIE options, add a printable
3355 				 * version
3356 				 */
3357 				for (i = 0; i < optlen; i++) {
3358 					ADD_STRING(target, " (");
3359 					if (!isc_buffer_availablelength(target))
3360 						return (ISC_R_NOSPACE);
3361 					if (isprint(optdata[i]))
3362 						isc_buffer_putmem(target,
3363 								  &optdata[i],
3364 								  1);
3365 					else
3366 						isc_buffer_putstr(target, ".");
3367 					ADD_STRING(target, ")");
3368 				}
3369 			}
3370 			ADD_STRING(target, "\n");
3371 		}
3372 		return (ISC_R_SUCCESS);
3373 	case DNS_PSEUDOSECTION_TSIG:
3374 		ps = dns_message_gettsig(msg, &name);
3375 		if (ps == NULL)
3376 			return (ISC_R_SUCCESS);
3377 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3378 			ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3379 		result = dns_master_rdatasettotext(name, ps, style, target);
3380 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3381 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3382 			ADD_STRING(target, "\n");
3383 		return (result);
3384 	case DNS_PSEUDOSECTION_SIG0:
3385 		ps = dns_message_getsig0(msg, &name);
3386 		if (ps == NULL)
3387 			return (ISC_R_SUCCESS);
3388 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3389 			ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3390 		result = dns_master_rdatasettotext(name, ps, style, target);
3391 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3392 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3393 			ADD_STRING(target, "\n");
3394 		return (result);
3395 	}
3396 	return (ISC_R_UNEXPECTED);
3397 }
3398 
3399 isc_result_t
dns_message_totext(dns_message_t * msg,const dns_master_style_t * style,dns_messagetextflag_t flags,isc_buffer_t * target)3400 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3401 		   dns_messagetextflag_t flags, isc_buffer_t *target)
3402 {
3403 	char buf[sizeof("1234567890")];
3404 	isc_result_t result;
3405 
3406 	REQUIRE(DNS_MESSAGE_VALID(msg));
3407 	REQUIRE(target != NULL);
3408 
3409 	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3410 		ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3411 		ADD_STRING(target, opcodetext[msg->opcode]);
3412 		ADD_STRING(target, ", status: ");
3413 		result = dns_rcode_totext(msg->rcode, target);
3414 		if (result != ISC_R_SUCCESS)
3415 			return (result);
3416 		ADD_STRING(target, ", id: ");
3417 		snprintf(buf, sizeof(buf), "%6u", msg->id);
3418 		ADD_STRING(target, buf);
3419 		ADD_STRING(target, "\n;; flags:");
3420 		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3421 			ADD_STRING(target, " qr");
3422 		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3423 			ADD_STRING(target, " aa");
3424 		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3425 			ADD_STRING(target, " tc");
3426 		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3427 			ADD_STRING(target, " rd");
3428 		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3429 			ADD_STRING(target, " ra");
3430 		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3431 			ADD_STRING(target, " ad");
3432 		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3433 			ADD_STRING(target, " cd");
3434 		/*
3435 		 * The final unnamed flag must be zero.
3436 		 */
3437 		if ((msg->flags & 0x0040U) != 0)
3438 			ADD_STRING(target, "; MBZ: 0x4");
3439 		if (msg->opcode != dns_opcode_update) {
3440 			ADD_STRING(target, "; QUESTION: ");
3441 		} else {
3442 			ADD_STRING(target, "; ZONE: ");
3443 		}
3444 		snprintf(buf, sizeof(buf), "%1u",
3445 			 msg->counts[DNS_SECTION_QUESTION]);
3446 		ADD_STRING(target, buf);
3447 		if (msg->opcode != dns_opcode_update) {
3448 			ADD_STRING(target, ", ANSWER: ");
3449 		} else {
3450 			ADD_STRING(target, ", PREREQ: ");
3451 		}
3452 		snprintf(buf, sizeof(buf), "%1u",
3453 			 msg->counts[DNS_SECTION_ANSWER]);
3454 		ADD_STRING(target, buf);
3455 		if (msg->opcode != dns_opcode_update) {
3456 			ADD_STRING(target, ", AUTHORITY: ");
3457 		} else {
3458 			ADD_STRING(target, ", UPDATE: ");
3459 		}
3460 		snprintf(buf, sizeof(buf), "%1u",
3461 			msg->counts[DNS_SECTION_AUTHORITY]);
3462 		ADD_STRING(target, buf);
3463 		ADD_STRING(target, ", ADDITIONAL: ");
3464 		snprintf(buf, sizeof(buf), "%1u",
3465 			msg->counts[DNS_SECTION_ADDITIONAL]);
3466 		ADD_STRING(target, buf);
3467 		ADD_STRING(target, "\n");
3468 	}
3469 	result = dns_message_pseudosectiontotext(msg,
3470 						 DNS_PSEUDOSECTION_OPT,
3471 						 style, flags, target);
3472 	if (result != ISC_R_SUCCESS)
3473 		return (result);
3474 
3475 	result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3476 					   style, flags, target);
3477 	if (result != ISC_R_SUCCESS)
3478 		return (result);
3479 	result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3480 					   style, flags, target);
3481 	if (result != ISC_R_SUCCESS)
3482 		return (result);
3483 	result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3484 					   style, flags, target);
3485 	if (result != ISC_R_SUCCESS)
3486 		return (result);
3487 	result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3488 					   style, flags, target);
3489 	if (result != ISC_R_SUCCESS)
3490 		return (result);
3491 
3492 	result = dns_message_pseudosectiontotext(msg,
3493 						 DNS_PSEUDOSECTION_TSIG,
3494 						 style, flags, target);
3495 	if (result != ISC_R_SUCCESS)
3496 		return (result);
3497 
3498 	result = dns_message_pseudosectiontotext(msg,
3499 						 DNS_PSEUDOSECTION_SIG0,
3500 						 style, flags, target);
3501 	if (result != ISC_R_SUCCESS)
3502 		return (result);
3503 
3504 	return (ISC_R_SUCCESS);
3505 }
3506 
3507 isc_region_t *
dns_message_getrawmessage(dns_message_t * msg)3508 dns_message_getrawmessage(dns_message_t *msg) {
3509 	REQUIRE(DNS_MESSAGE_VALID(msg));
3510 	return (&msg->saved);
3511 }
3512 
3513 void
dns_message_setsortorder(dns_message_t * msg,dns_rdatasetorderfunc_t order,const void * order_arg)3514 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3515 			 const void *order_arg)
3516 {
3517 	REQUIRE(DNS_MESSAGE_VALID(msg));
3518 	msg->order = order;
3519 	msg->order_arg = order_arg;
3520 }
3521 
3522 void
dns_message_settimeadjust(dns_message_t * msg,int timeadjust)3523 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3524 	REQUIRE(DNS_MESSAGE_VALID(msg));
3525 	msg->timeadjust = timeadjust;
3526 }
3527 
3528 int
dns_message_gettimeadjust(dns_message_t * msg)3529 dns_message_gettimeadjust(dns_message_t *msg) {
3530 	REQUIRE(DNS_MESSAGE_VALID(msg));
3531 	return (msg->timeadjust);
3532 }
3533 
3534 isc_result_t
dns_opcode_totext(dns_opcode_t opcode,isc_buffer_t * target)3535 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3536 
3537 	REQUIRE(opcode < 16);
3538 
3539 	if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3540 		return (ISC_R_NOSPACE);
3541 	isc_buffer_putstr(target, opcodetext[opcode]);
3542 	return (ISC_R_SUCCESS);
3543 }
3544 
3545 isc_result_t
dns_message_buildopt(dns_message_t * message,dns_rdataset_t ** rdatasetp,unsigned int version,isc_uint16_t udpsize,unsigned int flags,dns_ednsopt_t * ednsopts,size_t count)3546 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
3547 		     unsigned int version, isc_uint16_t udpsize,
3548 		     unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
3549 {
3550 	dns_rdataset_t *rdataset = NULL;
3551 	dns_rdatalist_t *rdatalist = NULL;
3552 	dns_rdata_t *rdata = NULL;
3553 	isc_result_t result;
3554 	unsigned int len = 0, i;
3555 
3556 	REQUIRE(DNS_MESSAGE_VALID(message));
3557 	REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
3558 
3559 	result = dns_message_gettemprdatalist(message, &rdatalist);
3560 	if (result != ISC_R_SUCCESS)
3561 		return (result);
3562 	result = dns_message_gettemprdata(message, &rdata);
3563 	if (result != ISC_R_SUCCESS)
3564 		goto cleanup;
3565 	result = dns_message_gettemprdataset(message, &rdataset);
3566 	if (result != ISC_R_SUCCESS)
3567 		goto cleanup;
3568 	dns_rdataset_init(rdataset);
3569 
3570 	rdatalist->type = dns_rdatatype_opt;
3571 
3572 	/*
3573 	 * Set Maximum UDP buffer size.
3574 	 */
3575 	rdatalist->rdclass = udpsize;
3576 
3577 	/*
3578 	 * Set EXTENDED-RCODE and Z to 0.
3579 	 */
3580 	rdatalist->ttl = (version << 16);
3581 	rdatalist->ttl |= (flags & 0xffff);
3582 
3583 	/*
3584 	 * Set EDNS options if applicable
3585 	 */
3586 	if (count != 0U) {
3587 		isc_buffer_t *buf = NULL;
3588 		for (i = 0; i < count; i++)
3589 			len += ednsopts[i].length + 4;
3590 
3591 		if (len > 0xffffU) {
3592 			result = ISC_R_NOSPACE;
3593 			goto cleanup;
3594 		}
3595 
3596 		result = isc_buffer_allocate(message->mctx, &buf, len);
3597 		if (result != ISC_R_SUCCESS)
3598 			goto cleanup;
3599 
3600 		for (i = 0; i < count; i++)  {
3601 			isc_buffer_putuint16(buf, ednsopts[i].code);
3602 			isc_buffer_putuint16(buf, ednsopts[i].length);
3603 			isc_buffer_putmem(buf, ednsopts[i].value,
3604 					  ednsopts[i].length);
3605 		}
3606 		rdata->data = isc_buffer_base(buf);
3607 		rdata->length = len;
3608 		dns_message_takebuffer(message, &buf);
3609 	} else {
3610 		rdata->data = NULL;
3611 		rdata->length = 0;
3612 	}
3613 
3614 	rdata->rdclass = rdatalist->rdclass;
3615 	rdata->type = rdatalist->type;
3616 	rdata->flags = 0;
3617 
3618 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3619 	result = dns_rdatalist_tordataset(rdatalist, rdataset);
3620 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
3621 
3622 	*rdatasetp = rdataset;
3623 	return (ISC_R_SUCCESS);
3624 
3625  cleanup:
3626 	if (rdata != NULL)
3627 		dns_message_puttemprdata(message, &rdata);
3628 	if (rdataset != NULL)
3629 		dns_message_puttemprdataset(message, &rdataset);
3630 	if (rdatalist != NULL)
3631 		dns_message_puttemprdatalist(message, &rdatalist);
3632 	return (result);
3633 }
3634 
3635 void
dns_message_setclass(dns_message_t * msg,dns_rdataclass_t rdclass)3636 dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
3637 
3638 	REQUIRE(DNS_MESSAGE_VALID(msg));
3639 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
3640 	REQUIRE(msg->state == DNS_SECTION_ANY);
3641 	REQUIRE(msg->rdclass_set == 0);
3642 
3643 	msg->rdclass = rdclass;
3644 	msg->rdclass_set = 1;
3645 }
3646