xref: /openbsd/usr.bin/dig/lib/dns/message.c (revision 9835a5e1)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: message.c,v 1.22 2024/12/27 09:04:48 florian Exp $ */
18 
19 /*! \file */
20 
21 /***
22  *** Imports
23  ***/
24 
25 #include <sys/socket.h>
26 #include <arpa/inet.h>
27 
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include <isc/buffer.h>
33 #include <isc/util.h>
34 
35 #include <dns/log.h>
36 #include <dns/masterdump.h>
37 #include <dns/message.h>
38 #include <dns/rdata.h>
39 #include <dns/rdatalist.h>
40 #include <dns/rdataset.h>
41 #include <dns/result.h>
42 #include <dns/tsig.h>
43 #include <dns/ttl.h>
44 
45 #define DNS_MESSAGE_OPCODE_MASK		0x7800U
46 #define DNS_MESSAGE_OPCODE_SHIFT	11
47 #define DNS_MESSAGE_RCODE_MASK		0x000fU
48 #define DNS_MESSAGE_FLAG_MASK		0x8ff0U
49 #define DNS_MESSAGE_EDNSRCODE_MASK	0xff000000U
50 
51 #define VALID_NAMED_SECTION(s)  (((s) > DNS_SECTION_ANY) \
52 				 && ((s) < DNS_SECTION_MAX))
53 #define VALID_SECTION(s)	(((s) >= DNS_SECTION_ANY) \
54 				 && ((s) < DNS_SECTION_MAX))
55 #define ADD_STRING(b, s)	{if (strlen(s) >= \
56 				   isc_buffer_availablelength(b)) \
57 				       return(ISC_R_NOSPACE); else \
58 				       isc_buffer_putstr(b, s);}
59 #define VALID_PSEUDOSECTION(s)	(((s) >= DNS_PSEUDOSECTION_ANY) \
60 				 && ((s) < DNS_PSEUDOSECTION_MAX))
61 
62 /*%
63  * This is the size of each individual scratchpad buffer, and the numbers
64  * of various block allocations used within the server.
65  * XXXMLG These should come from a config setting.
66  */
67 #define SCRATCHPAD_SIZE		512
68 #define OFFSET_COUNT		  4
69 #define RDATA_COUNT		  8
70 #define RDATALIST_COUNT		  8
71 
72 /*%
73  * Text representation of the different items, for message_totext
74  * functions.
75  */
76 static const char *sectiontext[] = {
77 	"QUESTION",
78 	"ANSWER",
79 	"AUTHORITY",
80 	"ADDITIONAL"
81 };
82 
83 static const char *updsectiontext[] = {
84 	"ZONE",
85 	"PREREQUISITE",
86 	"UPDATE",
87 	"ADDITIONAL"
88 };
89 
90 /*%
91  * "helper" type, which consists of a block of some type, and is linkable.
92  * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
93  * size, or the allocated elements will not be aligned correctly.
94  */
95 struct dns_msgblock {
96 	unsigned int			count;
97 	unsigned int			remaining;
98 	ISC_LINK(dns_msgblock_t)	link;
99 }; /* dynamically sized */
100 
101 static inline dns_msgblock_t *
102 msgblock_allocate(unsigned int, unsigned int);
103 
104 #define msgblock_get(block, type) \
105 	((type *)msgblock_internalget(block, sizeof(type)))
106 
107 static inline void *
108 msgblock_internalget(dns_msgblock_t *, unsigned int);
109 
110 static inline void
111 msgblock_reset(dns_msgblock_t *);
112 
113 /*
114  * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
115  * is free, return NULL.
116  */
117 static inline dns_msgblock_t *
msgblock_allocate(unsigned int sizeof_type,unsigned int count)118 msgblock_allocate(unsigned int sizeof_type,
119 		  unsigned int count)
120 {
121 	dns_msgblock_t *block;
122 	unsigned int length;
123 
124 	length = sizeof(dns_msgblock_t) + (sizeof_type * count);
125 
126 	block = malloc(length);
127 	if (block == NULL)
128 		return (NULL);
129 
130 	block->count = count;
131 	block->remaining = count;
132 
133 	ISC_LINK_INIT(block, link);
134 
135 	return (block);
136 }
137 
138 /*
139  * Return an element from the msgblock.  If no more are available, return
140  * NULL.
141  */
142 static inline void *
msgblock_internalget(dns_msgblock_t * block,unsigned int sizeof_type)143 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
144 	void *ptr;
145 
146 	if (block == NULL || block->remaining == 0)
147 		return (NULL);
148 
149 	block->remaining--;
150 
151 	ptr = (((unsigned char *)block)
152 	       + sizeof(dns_msgblock_t)
153 	       + (sizeof_type * block->remaining));
154 
155 	return (ptr);
156 }
157 
158 static inline void
msgblock_reset(dns_msgblock_t * block)159 msgblock_reset(dns_msgblock_t *block) {
160 	block->remaining = block->count;
161 }
162 
163 /*
164  * Allocate a new dynamic buffer, and attach it to this message as the
165  * "current" buffer.  (which is always the last on the list, for our
166  * uses)
167  */
168 static inline isc_result_t
newbuffer(dns_message_t * msg,unsigned int size)169 newbuffer(dns_message_t *msg, unsigned int size) {
170 	isc_result_t result;
171 	isc_buffer_t *dynbuf;
172 
173 	dynbuf = NULL;
174 	result = isc_buffer_allocate(&dynbuf, size);
175 	if (result != ISC_R_SUCCESS)
176 		return (ISC_R_NOMEMORY);
177 
178 	ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
179 	return (ISC_R_SUCCESS);
180 }
181 
182 static inline isc_buffer_t *
currentbuffer(dns_message_t * msg)183 currentbuffer(dns_message_t *msg) {
184 	isc_buffer_t *dynbuf;
185 
186 	dynbuf = ISC_LIST_TAIL(msg->scratchpad);
187 	INSIST(dynbuf != NULL);
188 
189 	return (dynbuf);
190 }
191 
192 static inline void
releaserdata(dns_message_t * msg,dns_rdata_t * rdata)193 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
194 	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
195 }
196 
197 static inline dns_rdata_t *
newrdata(dns_message_t * msg)198 newrdata(dns_message_t *msg) {
199 	dns_msgblock_t *msgblock;
200 	dns_rdata_t *rdata;
201 
202 	rdata = ISC_LIST_HEAD(msg->freerdata);
203 	if (rdata != NULL) {
204 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
205 		return (rdata);
206 	}
207 
208 	msgblock = ISC_LIST_TAIL(msg->rdatas);
209 	rdata = msgblock_get(msgblock, dns_rdata_t);
210 	if (rdata == NULL) {
211 		msgblock = msgblock_allocate(sizeof(dns_rdata_t), RDATA_COUNT);
212 		if (msgblock == NULL)
213 			return (NULL);
214 
215 		ISC_LIST_APPEND(msg->rdatas, msgblock, link);
216 
217 		rdata = msgblock_get(msgblock, dns_rdata_t);
218 	}
219 
220 	dns_rdata_init(rdata);
221 	return (rdata);
222 }
223 
224 static inline void
releaserdatalist(dns_message_t * msg,dns_rdatalist_t * rdatalist)225 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
226 	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
227 }
228 
229 static inline dns_rdatalist_t *
newrdatalist(dns_message_t * msg)230 newrdatalist(dns_message_t *msg) {
231 	dns_msgblock_t *msgblock;
232 	dns_rdatalist_t *rdatalist;
233 
234 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
235 	if (rdatalist != NULL) {
236 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
237 		goto out;
238 	}
239 
240 	msgblock = ISC_LIST_TAIL(msg->rdatalists);
241 	rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
242 	if (rdatalist == NULL) {
243 		msgblock = msgblock_allocate(sizeof(dns_rdatalist_t),
244 					     RDATALIST_COUNT);
245 		if (msgblock == NULL)
246 			return (NULL);
247 
248 		ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
249 
250 		rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
251 	}
252  out:
253 	if (rdatalist != NULL)
254 		dns_rdatalist_init(rdatalist);
255 
256 	return (rdatalist);
257 }
258 
259 static inline dns_offsets_t *
newoffsets(dns_message_t * msg)260 newoffsets(dns_message_t *msg) {
261 	dns_msgblock_t *msgblock;
262 	dns_offsets_t *offsets;
263 
264 	msgblock = ISC_LIST_TAIL(msg->offsets);
265 	offsets = msgblock_get(msgblock, dns_offsets_t);
266 	if (offsets == NULL) {
267 		msgblock = msgblock_allocate(sizeof(dns_offsets_t),
268 					     OFFSET_COUNT);
269 		if (msgblock == NULL)
270 			return (NULL);
271 
272 		ISC_LIST_APPEND(msg->offsets, msgblock, link);
273 
274 		offsets = msgblock_get(msgblock, dns_offsets_t);
275 	}
276 
277 	return (offsets);
278 }
279 
280 static inline void
msginitheader(dns_message_t * m)281 msginitheader(dns_message_t *m) {
282 	m->id = 0;
283 	m->flags = 0;
284 	m->rcode = 0;
285 	m->opcode = 0;
286 	m->rdclass = 0;
287 }
288 
289 static inline void
msginitprivate(dns_message_t * m)290 msginitprivate(dns_message_t *m) {
291 	unsigned int i;
292 
293 	for (i = 0; i < DNS_SECTION_MAX; i++) {
294 		m->cursors[i] = NULL;
295 		m->counts[i] = 0;
296 	}
297 	m->opt = NULL;
298 	m->sig0 = NULL;
299 	m->sig0name = NULL;
300 	m->tsig = NULL;
301 	m->tsigname = NULL;
302 	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
303 	m->opt_reserved = 0;
304 	m->sig_reserved = 0;
305 	m->reserved = 0;
306 	m->buffer = NULL;
307 }
308 
309 static inline void
msginittsig(dns_message_t * m)310 msginittsig(dns_message_t *m) {
311 	m->tsigstatus = dns_rcode_noerror;
312 	m->querytsigstatus = dns_rcode_noerror;
313 	m->tsigkey = NULL;
314 	m->tsigctx = NULL;
315 	m->sigstart = -1;
316 	m->sig0status = dns_rcode_noerror;
317 	m->timeadjust = 0;
318 }
319 
320 /*
321  * Init elements to default state.  Used both when allocating a new element
322  * and when resetting one.
323  */
324 static inline void
msginit(dns_message_t * m)325 msginit(dns_message_t *m) {
326 	msginitheader(m);
327 	msginitprivate(m);
328 	msginittsig(m);
329 	m->header_ok = 0;
330 	m->question_ok = 0;
331 	m->tcp_continuation = 0;
332 	m->verified_sig = 0;
333 	m->verify_attempted = 0;
334 	m->query.base = NULL;
335 	m->query.length = 0;
336 	m->free_query = 0;
337 	m->saved.base = NULL;
338 	m->saved.length = 0;
339 	m->free_saved = 0;
340 	m->sitok = 0;
341 	m->sitbad = 0;
342 	m->tkey = 0;
343 	m->rdclass_set = 0;
344 	m->querytsig = NULL;
345 }
346 
347 static inline void
msgresetnames(dns_message_t * msg,unsigned int first_section)348 msgresetnames(dns_message_t *msg, unsigned int first_section) {
349 	unsigned int i;
350 	dns_name_t *name, *next_name;
351 	dns_rdataset_t *rds, *next_rds;
352 
353 	/*
354 	 * Clean up name lists by calling the rdataset disassociate function.
355 	 */
356 	for (i = first_section; i < DNS_SECTION_MAX; i++) {
357 		name = ISC_LIST_HEAD(msg->sections[i]);
358 		while (name != NULL) {
359 			next_name = ISC_LIST_NEXT(name, link);
360 			ISC_LIST_UNLINK(msg->sections[i], name, link);
361 
362 			rds = ISC_LIST_HEAD(name->list);
363 			while (rds != NULL) {
364 				next_rds = ISC_LIST_NEXT(rds, link);
365 				ISC_LIST_UNLINK(name->list, rds, link);
366 
367 				INSIST(dns_rdataset_isassociated(rds));
368 				dns_rdataset_disassociate(rds);
369 				free(rds);
370 				rds = next_rds;
371 			}
372 			if (dns_name_dynamic(name))
373 				dns_name_free(name);
374 			free(name);
375 			name = next_name;
376 		}
377 	}
378 }
379 
380 static void
msgresetopt(dns_message_t * msg)381 msgresetopt(dns_message_t *msg)
382 {
383 	if (msg->opt != NULL) {
384 		if (msg->opt_reserved > 0) {
385 			dns_message_renderrelease(msg, msg->opt_reserved);
386 			msg->opt_reserved = 0;
387 		}
388 		INSIST(dns_rdataset_isassociated(msg->opt));
389 		dns_rdataset_disassociate(msg->opt);
390 		free(msg->opt);
391 		msg->opt = NULL;
392 		msg->sitok = 0;
393 		msg->sitbad = 0;
394 	}
395 }
396 
397 static void
msgresetsigs(dns_message_t * msg,int replying)398 msgresetsigs(dns_message_t *msg, int replying) {
399 	if (msg->sig_reserved > 0) {
400 		dns_message_renderrelease(msg, msg->sig_reserved);
401 		msg->sig_reserved = 0;
402 	}
403 	if (msg->tsig != NULL) {
404 		INSIST(dns_rdataset_isassociated(msg->tsig));
405 		if (replying) {
406 			INSIST(msg->querytsig == NULL);
407 			msg->querytsig = msg->tsig;
408 		} else {
409 			dns_rdataset_disassociate(msg->tsig);
410 			free(msg->tsig);
411 			if (msg->querytsig != NULL) {
412 				dns_rdataset_disassociate(msg->querytsig);
413 				free(msg->querytsig);
414 			}
415 		}
416 		if (dns_name_dynamic(msg->tsigname))
417 			dns_name_free(msg->tsigname);
418 		free(msg->tsigname);
419 		msg->tsig = NULL;
420 		msg->tsigname = NULL;
421 	} else if (msg->querytsig != NULL && !replying) {
422 		dns_rdataset_disassociate(msg->querytsig);
423 		free(msg->querytsig);
424 		msg->querytsig = NULL;
425 	}
426 	if (msg->sig0 != NULL) {
427 		INSIST(dns_rdataset_isassociated(msg->sig0));
428 		dns_rdataset_disassociate(msg->sig0);
429 		free(msg->sig0);
430 		if (msg->sig0name != NULL) {
431 			if (dns_name_dynamic(msg->sig0name))
432 				dns_name_free(msg->sig0name);
433 			free(msg->sig0name);
434 		}
435 		msg->sig0 = NULL;
436 		msg->sig0name = NULL;
437 	}
438 }
439 
440 /*
441  * Free all but one (or everything) for this message.  This is used by
442  * both dns_message_reset() and dns_message_destroy().
443  */
444 static void
msgreset(dns_message_t * msg,int everything)445 msgreset(dns_message_t *msg, int everything) {
446 	dns_msgblock_t *msgblock, *next_msgblock;
447 	isc_buffer_t *dynbuf, *next_dynbuf;
448 	dns_rdata_t *rdata;
449 	dns_rdatalist_t *rdatalist;
450 
451 	msgresetnames(msg, 0);
452 	msgresetopt(msg);
453 	msgresetsigs(msg, 0);
454 
455 	/*
456 	 * Clean up linked lists.
457 	 */
458 
459 	/*
460 	 * Run through the free lists, and just unlink anything found there.
461 	 * The memory isn't lost since these are part of message blocks we
462 	 * have allocated.
463 	 */
464 	rdata = ISC_LIST_HEAD(msg->freerdata);
465 	while (rdata != NULL) {
466 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
467 		rdata = ISC_LIST_HEAD(msg->freerdata);
468 	}
469 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
470 	while (rdatalist != NULL) {
471 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
472 		rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
473 	}
474 
475 	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
476 	INSIST(dynbuf != NULL);
477 	if (!everything) {
478 		isc_buffer_clear(dynbuf);
479 		dynbuf = ISC_LIST_NEXT(dynbuf, link);
480 	}
481 	while (dynbuf != NULL) {
482 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
483 		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
484 		isc_buffer_free(&dynbuf);
485 		dynbuf = next_dynbuf;
486 	}
487 
488 	msgblock = ISC_LIST_HEAD(msg->rdatas);
489 	if (!everything && msgblock != NULL) {
490 		msgblock_reset(msgblock);
491 		msgblock = ISC_LIST_NEXT(msgblock, link);
492 	}
493 	while (msgblock != NULL) {
494 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
495 		ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
496 		free(msgblock);
497 		msgblock = next_msgblock;
498 	}
499 
500 	/*
501 	 * rdatalists could be empty.
502 	 */
503 
504 	msgblock = ISC_LIST_HEAD(msg->rdatalists);
505 	if (!everything && msgblock != NULL) {
506 		msgblock_reset(msgblock);
507 		msgblock = ISC_LIST_NEXT(msgblock, link);
508 	}
509 	while (msgblock != NULL) {
510 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
511 		ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
512 		free(msgblock);
513 		msgblock = next_msgblock;
514 	}
515 
516 	msgblock = ISC_LIST_HEAD(msg->offsets);
517 	if (!everything && msgblock != NULL) {
518 		msgblock_reset(msgblock);
519 		msgblock = ISC_LIST_NEXT(msgblock, link);
520 	}
521 	while (msgblock != NULL) {
522 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
523 		ISC_LIST_UNLINK(msg->offsets, msgblock, link);
524 		free(msgblock);
525 		msgblock = next_msgblock;
526 	}
527 
528 	if (msg->tsigkey != NULL) {
529 		dns_tsigkey_detach(&msg->tsigkey);
530 		msg->tsigkey = NULL;
531 	}
532 
533 	if (msg->tsigctx != NULL)
534 		dst_context_destroy(&msg->tsigctx);
535 
536 	if (msg->query.base != NULL) {
537 		if (msg->free_query != 0)
538 			free(msg->query.base);
539 		msg->query.base = NULL;
540 		msg->query.length = 0;
541 	}
542 
543 	if (msg->saved.base != NULL) {
544 		if (msg->free_saved != 0)
545 			free(msg->saved.base);
546 		msg->saved.base = NULL;
547 		msg->saved.length = 0;
548 	}
549 
550 	/*
551 	 * cleanup the buffer cleanup list
552 	 */
553 	dynbuf = ISC_LIST_HEAD(msg->cleanup);
554 	while (dynbuf != NULL) {
555 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
556 		ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
557 		isc_buffer_free(&dynbuf);
558 		dynbuf = next_dynbuf;
559 	}
560 
561 	/*
562 	 * Set other bits to normal default values.
563 	 */
564 	if (!everything)
565 		msginit(msg);
566 }
567 
568 static unsigned int
spacefortsig(dns_tsigkey_t * key,int otherlen)569 spacefortsig(dns_tsigkey_t *key, int otherlen) {
570 	isc_region_t r1, r2;
571 	unsigned int x;
572 	isc_result_t result;
573 
574 	/*
575 	 * The space required for an TSIG record is:
576 	 *
577 	 *	n1 bytes for the name
578 	 *	2 bytes for the type
579 	 *	2 bytes for the class
580 	 *	4 bytes for the ttl
581 	 *	2 bytes for the rdlength
582 	 *	n2 bytes for the algorithm name
583 	 *	6 bytes for the time signed
584 	 *	2 bytes for the fudge
585 	 *	2 bytes for the MAC size
586 	 *	x bytes for the MAC
587 	 *	2 bytes for the original id
588 	 *	2 bytes for the error
589 	 *	2 bytes for the other data length
590 	 *	y bytes for the other data (at most)
591 	 * ---------------------------------
592 	 *     26 + n1 + n2 + x + y bytes
593 	 */
594 
595 	dns_name_toregion(&key->name, &r1);
596 	dns_name_toregion(key->algorithm, &r2);
597 	if (key->key == NULL)
598 		x = 0;
599 	else {
600 		result = dst_key_sigsize(key->key, &x);
601 		if (result != ISC_R_SUCCESS)
602 			x = 0;
603 	}
604 	return (26 + r1.length + r2.length + x + otherlen);
605 }
606 
607 isc_result_t
dns_message_create(unsigned int intent,dns_message_t ** msgp)608 dns_message_create(unsigned int intent, dns_message_t **msgp)
609 {
610 	dns_message_t *m;
611 	isc_result_t result;
612 	isc_buffer_t *dynbuf;
613 	unsigned int i;
614 
615 	REQUIRE(msgp != NULL);
616 	REQUIRE(*msgp == NULL);
617 	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
618 		|| intent == DNS_MESSAGE_INTENTRENDER);
619 
620 	m = malloc(sizeof(dns_message_t));
621 	if (m == NULL)
622 		return (ISC_R_NOMEMORY);
623 
624 	/*
625 	 * No allocations until further notice.  Just initialize all lists
626 	 * and other members that are freed in the cleanup phase here.
627 	 */
628 
629 	m->from_to_wire = intent;
630 	msginit(m);
631 
632 	for (i = 0; i < DNS_SECTION_MAX; i++)
633 		ISC_LIST_INIT(m->sections[i]);
634 
635 	ISC_LIST_INIT(m->scratchpad);
636 	ISC_LIST_INIT(m->cleanup);
637 	ISC_LIST_INIT(m->rdatas);
638 	ISC_LIST_INIT(m->rdatalists);
639 	ISC_LIST_INIT(m->offsets);
640 	ISC_LIST_INIT(m->freerdata);
641 	ISC_LIST_INIT(m->freerdatalist);
642 
643 	/*
644 	 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
645 	 */
646 
647 	dynbuf = NULL;
648 	result = isc_buffer_allocate(&dynbuf, SCRATCHPAD_SIZE);
649 	if (result != ISC_R_SUCCESS)
650 		goto cleanup;
651 	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
652 
653 	m->cctx = NULL;
654 
655 	*msgp = m;
656 	return (ISC_R_SUCCESS);
657 
658 	/*
659 	 * Cleanup for error returns.
660 	 */
661  cleanup:
662 	dynbuf = ISC_LIST_HEAD(m->scratchpad);
663 	if (dynbuf != NULL) {
664 		ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
665 		isc_buffer_free(&dynbuf);
666 	}
667 	free(m);
668 
669 	return (ISC_R_NOMEMORY);
670 }
671 
672 void
dns_message_destroy(dns_message_t ** msgp)673 dns_message_destroy(dns_message_t **msgp) {
674 	dns_message_t *msg;
675 
676 	REQUIRE(msgp != NULL);
677 
678 	msg = *msgp;
679 	*msgp = NULL;
680 
681 	msgreset(msg, 1);
682 	free(msg);
683 }
684 
685 static isc_result_t
findname(dns_name_t ** foundname,dns_name_t * target,dns_namelist_t * section)686 findname(dns_name_t **foundname, dns_name_t *target,
687 	 dns_namelist_t *section)
688 {
689 	dns_name_t *curr;
690 
691 	for (curr = ISC_LIST_TAIL(*section);
692 	     curr != NULL;
693 	     curr = ISC_LIST_PREV(curr, link)) {
694 		if (dns_name_equal(curr, target)) {
695 			if (foundname != NULL)
696 				*foundname = curr;
697 			return (ISC_R_SUCCESS);
698 		}
699 	}
700 
701 	return (ISC_R_NOTFOUND);
702 }
703 
704 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)705 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
706 		 dns_rdatatype_t type, dns_rdatatype_t covers,
707 		 dns_rdataset_t **rdataset)
708 {
709 	dns_rdataset_t *curr;
710 
711 	REQUIRE(name != NULL);
712 	REQUIRE(rdataset == NULL || *rdataset == NULL);
713 
714 	for (curr = ISC_LIST_TAIL(name->list);
715 	     curr != NULL;
716 	     curr = ISC_LIST_PREV(curr, link)) {
717 		if (curr->rdclass == rdclass &&
718 		    curr->type == type && curr->covers == covers) {
719 			if (rdataset != NULL)
720 				*rdataset = curr;
721 			return (ISC_R_SUCCESS);
722 		}
723 	}
724 
725 	return (ISC_R_NOTFOUND);
726 }
727 
728 isc_result_t
dns_message_findtype(dns_name_t * name,dns_rdatatype_t type,dns_rdatatype_t covers,dns_rdataset_t ** rdataset)729 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
730 		     dns_rdatatype_t covers, dns_rdataset_t **rdataset)
731 {
732 	dns_rdataset_t *curr;
733 
734 	REQUIRE(name != NULL);
735 	REQUIRE(rdataset == NULL || *rdataset == NULL);
736 
737 	for (curr = ISC_LIST_TAIL(name->list);
738 	     curr != NULL;
739 	     curr = ISC_LIST_PREV(curr, link)) {
740 		if (curr->type == type && curr->covers == covers) {
741 			if (rdataset != NULL)
742 				*rdataset = curr;
743 			return (ISC_R_SUCCESS);
744 		}
745 	}
746 
747 	return (ISC_R_NOTFOUND);
748 }
749 
750 /*
751  * Read a name from buffer "source".
752  */
753 static isc_result_t
getname(dns_name_t * name,isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx)754 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
755 	dns_decompress_t *dctx)
756 {
757 	isc_buffer_t *scratch;
758 	isc_result_t result;
759 	unsigned int tries;
760 
761 	scratch = currentbuffer(msg);
762 
763 	/*
764 	 * First try:  use current buffer.
765 	 * Second try:  allocate a new buffer and use that.
766 	 */
767 	tries = 0;
768 	while (tries < 2) {
769 		result = dns_name_fromwire(name, source, dctx, 0,
770 					   scratch);
771 
772 		if (result == ISC_R_NOSPACE) {
773 			tries++;
774 
775 			result = newbuffer(msg, SCRATCHPAD_SIZE);
776 			if (result != ISC_R_SUCCESS)
777 				return (result);
778 
779 			scratch = currentbuffer(msg);
780 			dns_name_reset(name);
781 		} else {
782 			return (result);
783 		}
784 	}
785 
786 	INSIST(0);  /* Cannot get here... */
787 	return (ISC_R_UNEXPECTED);
788 }
789 
790 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)791 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
792 	 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
793 	 unsigned int rdatalen, dns_rdata_t *rdata)
794 {
795 	isc_buffer_t *scratch;
796 	isc_result_t result;
797 	unsigned int tries;
798 	unsigned int trysize;
799 
800 	scratch = currentbuffer(msg);
801 
802 	isc_buffer_setactive(source, rdatalen);
803 
804 	/*
805 	 * First try:  use current buffer.
806 	 * Second try:  allocate a new buffer of size
807 	 *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
808 	 *     (the data will fit if it was not more than 50% compressed)
809 	 * Subsequent tries: double buffer size on each try.
810 	 */
811 	tries = 0;
812 	trysize = 0;
813 	/* XXX possibly change this to a while (tries < 2) loop */
814 	for (;;) {
815 		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
816 					    source, dctx, 0,
817 					    scratch);
818 
819 		if (result == ISC_R_NOSPACE) {
820 			if (tries == 0) {
821 				trysize = 2 * rdatalen;
822 				if (trysize < SCRATCHPAD_SIZE)
823 					trysize = SCRATCHPAD_SIZE;
824 			} else {
825 				INSIST(trysize != 0);
826 				if (trysize >= 65535)
827 					return (ISC_R_NOSPACE);
828 					/* XXX DNS_R_RRTOOLONG? */
829 				trysize *= 2;
830 			}
831 			tries++;
832 			result = newbuffer(msg, trysize);
833 			if (result != ISC_R_SUCCESS)
834 				return (result);
835 
836 			scratch = currentbuffer(msg);
837 		} else {
838 			return (result);
839 		}
840 	}
841 }
842 
843 #define DO_FORMERR					\
844 	do {						\
845 		if (best_effort)			\
846 			seen_problem = 1;	\
847 		else {					\
848 			result = DNS_R_FORMERR;		\
849 			goto cleanup;			\
850 		}					\
851 	} while (0)
852 
853 static isc_result_t
getquestions(isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx,unsigned int options)854 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
855 	     unsigned int options)
856 {
857 	isc_region_t r;
858 	unsigned int count;
859 	dns_name_t *name;
860 	dns_name_t *name2;
861 	dns_offsets_t *offsets;
862 	dns_rdataset_t *rdataset;
863 	dns_rdatalist_t *rdatalist;
864 	isc_result_t result;
865 	dns_rdatatype_t rdtype;
866 	dns_rdataclass_t rdclass;
867 	dns_namelist_t *section;
868 	int free_name;
869 	int best_effort;
870 	int seen_problem;
871 
872 	section = &msg->sections[DNS_SECTION_QUESTION];
873 
874 	best_effort = options & DNS_MESSAGEPARSE_BESTEFFORT;
875 	seen_problem = 0;
876 
877 	name = NULL;
878 	rdataset = NULL;
879 	rdatalist = NULL;
880 
881 	for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
882 		name = malloc(sizeof(dns_name_t));
883 		if (name == NULL)
884 			return (ISC_R_NOMEMORY);
885 		free_name = 1;
886 
887 		offsets = newoffsets(msg);
888 		if (offsets == NULL) {
889 			result = ISC_R_NOMEMORY;
890 			goto cleanup;
891 		}
892 		dns_name_init(name, *offsets);
893 
894 		/*
895 		 * Parse the name out of this packet.
896 		 */
897 		isc_buffer_remainingregion(source, &r);
898 		isc_buffer_setactive(source, r.length);
899 		result = getname(name, source, msg, dctx);
900 		if (result != ISC_R_SUCCESS)
901 			goto cleanup;
902 
903 		/*
904 		 * Run through the section, looking to see if this name
905 		 * is already there.  If it is found, put back the allocated
906 		 * name since we no longer need it, and set our name pointer
907 		 * to point to the name we found.
908 		 */
909 		result = findname(&name2, name, section);
910 
911 		/*
912 		 * If it is the first name in the section, accept it.
913 		 *
914 		 * If it is not, but is not the same as the name already
915 		 * in the question section, append to the section.  Note that
916 		 * here in the question section this is illegal, so return
917 		 * FORMERR.  In the future, check the opcode to see if
918 		 * this should be legal or not.  In either case we no longer
919 		 * need this name pointer.
920 		 */
921 		if (result != ISC_R_SUCCESS) {
922 			if (!ISC_LIST_EMPTY(*section))
923 				DO_FORMERR;
924 			ISC_LIST_APPEND(*section, name, link);
925 			free_name = 0;
926 		} else {
927 			free(name);
928 			name = name2;
929 			name2 = NULL;
930 			free_name = 0;
931 		}
932 
933 		/*
934 		 * Get type and class.
935 		 */
936 		isc_buffer_remainingregion(source, &r);
937 		if (r.length < 4) {
938 			result = ISC_R_UNEXPECTEDEND;
939 			goto cleanup;
940 		}
941 		rdtype = isc_buffer_getuint16(source);
942 		rdclass = isc_buffer_getuint16(source);
943 
944 		/*
945 		 * If this class is different than the one we already read,
946 		 * this is an error.
947 		 */
948 		if (msg->rdclass_set == 0) {
949 			msg->rdclass = rdclass;
950 			msg->rdclass_set = 1;
951 		} else if (msg->rdclass != rdclass)
952 			DO_FORMERR;
953 
954 		/*
955 		 * Is this a TKEY query?
956 		 */
957 		if (rdtype == dns_rdatatype_tkey)
958 			msg->tkey = 1;
959 
960 		/*
961 		 * Can't ask the same question twice.
962 		 */
963 		result = dns_message_find(name, rdclass, rdtype, 0, NULL);
964 		if (result == ISC_R_SUCCESS)
965 			DO_FORMERR;
966 
967 		/*
968 		 * Allocate a new rdatalist.
969 		 */
970 		rdatalist = newrdatalist(msg);
971 		if (rdatalist == NULL) {
972 			result = ISC_R_NOMEMORY;
973 			goto cleanup;
974 		}
975 		rdataset =  malloc(sizeof(dns_rdataset_t));
976 		if (rdataset == NULL) {
977 			result = ISC_R_NOMEMORY;
978 			goto cleanup;
979 		}
980 
981 		/*
982 		 * Convert rdatalist to rdataset, and attach the latter to
983 		 * the name.
984 		 */
985 		rdatalist->type = rdtype;
986 		rdatalist->covers = 0;
987 		rdatalist->rdclass = rdclass;
988 		rdatalist->ttl = 0;
989 		ISC_LIST_INIT(rdatalist->rdata);
990 
991 		dns_rdataset_init(rdataset);
992 		result = dns_rdatalist_tordataset(rdatalist, rdataset);
993 		if (result != ISC_R_SUCCESS)
994 			goto cleanup;
995 
996 		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
997 
998 		ISC_LIST_APPEND(name->list, rdataset, link);
999 		rdataset = NULL;
1000 	}
1001 
1002 	if (seen_problem)
1003 		return (DNS_R_RECOVERABLE);
1004 	return (ISC_R_SUCCESS);
1005 
1006  cleanup:
1007 	if (rdataset != NULL) {
1008 		INSIST(!dns_rdataset_isassociated(rdataset));
1009 		free(rdataset);
1010 	}
1011 	if (free_name)
1012 		free(name);
1013 
1014 	return (result);
1015 }
1016 
1017 static int
update(dns_section_t section,dns_rdataclass_t rdclass)1018 update(dns_section_t section, dns_rdataclass_t rdclass) {
1019 	if (section == DNS_SECTION_PREREQUISITE)
1020 		return (rdclass == dns_rdataclass_any ||
1021 			       rdclass == dns_rdataclass_none);
1022 	if (section == DNS_SECTION_UPDATE)
1023 		return (rdclass == dns_rdataclass_any);
1024 	return (0);
1025 }
1026 
1027 static isc_result_t
getsection(isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx,dns_section_t sectionid,unsigned int options)1028 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1029 	   dns_section_t sectionid, unsigned int options)
1030 {
1031 	isc_region_t r;
1032 	unsigned int count, rdatalen;
1033 	dns_name_t *name = NULL;
1034 	dns_offsets_t *offsets;
1035 	dns_rdataset_t *rdataset;
1036 	dns_rdatalist_t *rdatalist;
1037 	isc_result_t result;
1038 	dns_rdatatype_t rdtype, covers;
1039 	dns_rdataclass_t rdclass;
1040 	dns_rdata_t *rdata;
1041 	dns_ttl_t ttl;
1042 	dns_namelist_t *section;
1043 	int free_name = 0, free_rdataset = 0;
1044 	int best_effort, seen_problem;
1045 	int issigzero;
1046 
1047 	best_effort = options & DNS_MESSAGEPARSE_BESTEFFORT;
1048 	seen_problem = 0;
1049 
1050 	section = &msg->sections[sectionid];
1051 
1052 	for (count = 0; count < msg->counts[sectionid]; count++) {
1053 		int recstart = source->current;
1054 		free_rdataset = 0;
1055 
1056 		name = malloc(sizeof(dns_name_t));
1057 		if (name == NULL)
1058 			return (ISC_R_NOMEMORY);
1059 		free_name = 1;
1060 
1061 		offsets = newoffsets(msg);
1062 		if (offsets == NULL) {
1063 			result = ISC_R_NOMEMORY;
1064 			goto cleanup;
1065 		}
1066 		dns_name_init(name, *offsets);
1067 
1068 		/*
1069 		 * Parse the name out of this packet.
1070 		 */
1071 		isc_buffer_remainingregion(source, &r);
1072 		isc_buffer_setactive(source, r.length);
1073 		result = getname(name, source, msg, dctx);
1074 		if (result != ISC_R_SUCCESS)
1075 			goto cleanup;
1076 
1077 		/*
1078 		 * Get type, class, ttl, and rdatalen.  Verify that at least
1079 		 * rdatalen bytes remain.  (Some of this is deferred to
1080 		 * later.)
1081 		 */
1082 		isc_buffer_remainingregion(source, &r);
1083 		if (r.length < 2 + 2 + 4 + 2) {
1084 			result = ISC_R_UNEXPECTEDEND;
1085 			goto cleanup;
1086 		}
1087 		rdtype = isc_buffer_getuint16(source);
1088 		rdclass = isc_buffer_getuint16(source);
1089 
1090 		/*
1091 		 * If there was no question section, we may not yet have
1092 		 * established a class.  Do so now.
1093 		 */
1094 		if (msg->rdclass_set == 0 &&
1095 		    rdtype != dns_rdatatype_opt &&	/* class is UDP SIZE */
1096 		    rdtype != dns_rdatatype_tsig &&	/* class is ANY */
1097 		    rdtype != dns_rdatatype_tkey) {	/* class is undefined */
1098 			msg->rdclass = rdclass;
1099 			msg->rdclass_set = 1;
1100 		}
1101 
1102 		/*
1103 		 * If this class is different than the one in the question
1104 		 * section, bail.
1105 		 */
1106 		if (msg->opcode != dns_opcode_update
1107 		    && rdtype != dns_rdatatype_tsig
1108 		    && rdtype != dns_rdatatype_opt
1109 		    && rdtype != dns_rdatatype_key /* in a TKEY query */
1110 		    && rdtype != dns_rdatatype_sig /* SIG(0) */
1111 		    && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1112 		    && msg->rdclass != dns_rdataclass_any
1113 		    && msg->rdclass != rdclass)
1114 			DO_FORMERR;
1115 
1116 		/*
1117 		 * If this is not a TKEY query/response then the KEY
1118 		 * record's class needs to match.
1119 		 */
1120 		if (msg->opcode != dns_opcode_update && !msg->tkey &&
1121 		    rdtype == dns_rdatatype_key &&
1122 		    msg->rdclass != dns_rdataclass_any &&
1123 		    msg->rdclass != rdclass)
1124 			DO_FORMERR;
1125 
1126 		/*
1127 		 * Special type handling for TSIG, OPT, and TKEY.
1128 		 */
1129 		if (rdtype == dns_rdatatype_tsig) {
1130 			/*
1131 			 * If it is a tsig, verify that it is in the
1132 			 * additional data section.
1133 			 */
1134 			if (sectionid != DNS_SECTION_ADDITIONAL ||
1135 			    rdclass != dns_rdataclass_any ||
1136 			    count != msg->counts[sectionid]  - 1)
1137 				DO_FORMERR;
1138 			msg->sigstart = recstart;
1139 		} else if (rdtype == dns_rdatatype_opt) {
1140 			/*
1141 			 * The name of an OPT record must be ".", it
1142 			 * must be in the additional data section, and
1143 			 * it must be the first OPT we've seen.
1144 			 */
1145 			if (!dns_name_equal(dns_rootname, name) ||
1146 			    sectionid != DNS_SECTION_ADDITIONAL ||
1147 			    msg->opt != NULL)
1148 				DO_FORMERR;
1149 		} else if (rdtype == dns_rdatatype_tkey) {
1150 			/*
1151 			 * A TKEY must be in the additional section if this
1152 			 * is a query, and the answer section if this is a
1153 			 * response.  Unless it's a Win2000 client.
1154 			 *
1155 			 * Its class is ignored.
1156 			 */
1157 			dns_section_t tkeysection;
1158 
1159 			if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1160 				tkeysection = DNS_SECTION_ADDITIONAL;
1161 			else
1162 				tkeysection = DNS_SECTION_ANSWER;
1163 			if (sectionid != tkeysection &&
1164 			    sectionid != DNS_SECTION_ANSWER)
1165 				DO_FORMERR;
1166 		}
1167 
1168 		/*
1169 		 * ... now get ttl and rdatalen, and check buffer.
1170 		 */
1171 		ttl = isc_buffer_getuint32(source);
1172 		rdatalen = isc_buffer_getuint16(source);
1173 		r.length -= (2 + 2 + 4 + 2);
1174 		if (r.length < rdatalen) {
1175 			result = ISC_R_UNEXPECTEDEND;
1176 			goto cleanup;
1177 		}
1178 
1179 		/*
1180 		 * Read the rdata from the wire format.  Interpret the
1181 		 * rdata according to its actual class, even if it had a
1182 		 * DynDNS meta-class in the packet (unless this is a TSIG).
1183 		 * Then put the meta-class back into the finished rdata.
1184 		 */
1185 		rdata = newrdata(msg);
1186 		if (rdata == NULL) {
1187 			result = ISC_R_NOMEMORY;
1188 			goto cleanup;
1189 		}
1190 		if (msg->opcode == dns_opcode_update &&
1191 		    update(sectionid, rdclass)) {
1192 			if (rdatalen != 0) {
1193 				result = DNS_R_FORMERR;
1194 				goto cleanup;
1195 			}
1196 			/*
1197 			 * When the rdata is empty, the data pointer is
1198 			 * never dereferenced, but it must still be non-NULL.
1199 			 * Casting 1 rather than "" avoids warnings about
1200 			 * discarding the const attribute of a string,
1201 			 * for compilers that would warn about such things.
1202 			 */
1203 			rdata->data = (unsigned char *)1;
1204 			rdata->length = 0;
1205 			rdata->rdclass = rdclass;
1206 			rdata->type = rdtype;
1207 			rdata->flags = DNS_RDATA_UPDATE;
1208 			result = ISC_R_SUCCESS;
1209 		} else if (rdclass == dns_rdataclass_none &&
1210 			   msg->opcode == dns_opcode_update &&
1211 			   sectionid == DNS_SECTION_UPDATE) {
1212 			result = getrdata(source, msg, dctx, msg->rdclass,
1213 					  rdtype, rdatalen, rdata);
1214 		} else
1215 			result = getrdata(source, msg, dctx, rdclass,
1216 					  rdtype, rdatalen, rdata);
1217 		if (result != ISC_R_SUCCESS)
1218 			goto cleanup;
1219 		rdata->rdclass = rdclass;
1220 		issigzero = 0;
1221 		if (rdtype == dns_rdatatype_rrsig &&
1222 		    rdata->flags == 0) {
1223 			covers = dns_rdata_covers(rdata);
1224 			if (covers == 0)
1225 				DO_FORMERR;
1226 		} else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1227 			   rdata->flags == 0) {
1228 			covers = dns_rdata_covers(rdata);
1229 			if (covers == 0) {
1230 				if (sectionid != DNS_SECTION_ADDITIONAL ||
1231 				    count != msg->counts[sectionid]  - 1)
1232 					DO_FORMERR;
1233 				msg->sigstart = recstart;
1234 				issigzero = 1;
1235 			} else {
1236 				if (msg->rdclass != dns_rdataclass_any &&
1237 				    msg->rdclass != rdclass)
1238 					DO_FORMERR;
1239 			}
1240 		} else
1241 			covers = 0;
1242 
1243 		/*
1244 		 * Check the ownername of NSEC3 records
1245 		 */
1246 		if (rdtype == dns_rdatatype_nsec3 &&
1247 		    !dns_rdata_checkowner_nsec3(name, msg->rdclass, rdtype,
1248 					  0)) {
1249 			result = DNS_R_BADOWNERNAME;
1250 			goto cleanup;
1251 		}
1252 
1253 		if (rdtype != dns_rdatatype_opt &&
1254 		    rdtype != dns_rdatatype_tsig && !issigzero) {
1255 			ISC_LIST_APPEND(*section, name, link);
1256 			free_name = 0;
1257 		}
1258 
1259 		rdataset = malloc(sizeof(dns_rdataset_t));
1260 		if (rdataset == NULL) {
1261 			result = ISC_R_NOMEMORY;
1262 			goto cleanup;
1263 		}
1264 		free_rdataset = 1;
1265 
1266 		rdatalist = newrdatalist(msg);
1267 		if (rdatalist == NULL) {
1268 			result = ISC_R_NOMEMORY;
1269 			goto cleanup;
1270 		}
1271 
1272 		rdatalist->type = rdtype;
1273 		rdatalist->covers = covers;
1274 		rdatalist->rdclass = rdclass;
1275 		rdatalist->ttl = ttl;
1276 		ISC_LIST_INIT(rdatalist->rdata);
1277 
1278 		dns_rdataset_init(rdataset);
1279 		RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1280 							       rdataset)
1281 			      == ISC_R_SUCCESS);
1282 
1283 		if (rdtype != dns_rdatatype_opt &&
1284 		    rdtype != dns_rdatatype_tsig &&
1285 		    !issigzero)
1286 		{
1287 			ISC_LIST_APPEND(name->list, rdataset, link);
1288 			free_rdataset = 0;
1289 		}
1290 
1291 		/*
1292 		 * Minimize TTLs.
1293 		 *
1294 		 * Section 5.2 of RFC2181 says we should drop
1295 		 * nonauthoritative rrsets where the TTLs differ, but we
1296 		 * currently treat them the as if they were authoritative and
1297 		 * minimize them.
1298 		 */
1299 		if (ttl < rdataset->ttl)
1300 			rdataset->ttl = ttl;
1301 
1302 		/* Append this rdata to the rdataset. */
1303 		dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1304 		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1305 
1306 		/*
1307 		 * If this is an OPT, SIG(0) or TSIG record, remember it.
1308 		 * Also, set the extended rcode for TSIG.
1309 		 *
1310 		 * Note msg->opt, msg->sig0 and msg->tsig will only be
1311 		 * already set if best-effort parsing is enabled otherwise
1312 		 * there will only be at most one of each.
1313 		 */
1314 		if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1315 			dns_rcode_t ercode;
1316 
1317 			msg->opt = rdataset;
1318 			rdataset = NULL;
1319 			free_rdataset = 0;
1320 			ercode = (dns_rcode_t)
1321 				((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1322 				 >> 20);
1323 			msg->rcode |= ercode;
1324 			free(name);
1325 			free_name = 0;
1326 		} else if (issigzero && msg->sig0 == NULL) {
1327 			msg->sig0 = rdataset;
1328 			msg->sig0name = name;
1329 			rdataset = NULL;
1330 			free_rdataset = 0;
1331 			free_name = 0;
1332 		} else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1333 			msg->tsig = rdataset;
1334 			msg->tsigname = name;
1335 			/* Windows doesn't like TSIG names to be compressed. */
1336 			msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1337 			rdataset = NULL;
1338 			free_rdataset = 0;
1339 			free_name = 0;
1340 		}
1341 
1342 		if (seen_problem) {
1343 			if (free_name)
1344 				free(name);
1345 			if (free_rdataset)
1346 				free(rdataset);
1347 			free_name = free_rdataset = 0;
1348 		}
1349 		INSIST(!free_name);
1350 		INSIST(!free_rdataset);
1351 	}
1352 
1353 	if (seen_problem)
1354 		return (DNS_R_RECOVERABLE);
1355 	return (ISC_R_SUCCESS);
1356 
1357  cleanup:
1358 	if (free_name)
1359 		free(name);
1360 	if (free_rdataset)
1361 		free(rdataset);
1362 
1363 	return (result);
1364 }
1365 
1366 isc_result_t
dns_message_parse(dns_message_t * msg,isc_buffer_t * source,unsigned int options)1367 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1368 		  unsigned int options)
1369 {
1370 	isc_region_t r;
1371 	dns_decompress_t dctx;
1372 	isc_result_t ret;
1373 	uint16_t tmpflags;
1374 	isc_buffer_t origsource;
1375 	int seen_problem;
1376 	int ignore_tc;
1377 
1378 	REQUIRE(source != NULL);
1379 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1380 
1381 	seen_problem = 0;
1382 	ignore_tc = options & DNS_MESSAGEPARSE_IGNORETRUNCATION;
1383 
1384 	origsource = *source;
1385 
1386 	msg->header_ok = 0;
1387 	msg->question_ok = 0;
1388 
1389 	isc_buffer_remainingregion(source, &r);
1390 	if (r.length < DNS_MESSAGE_HEADERLEN)
1391 		return (ISC_R_UNEXPECTEDEND);
1392 
1393 	msg->id = isc_buffer_getuint16(source);
1394 	tmpflags = isc_buffer_getuint16(source);
1395 	msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1396 		       >> DNS_MESSAGE_OPCODE_SHIFT);
1397 	msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1398 	msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1399 	msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1400 	msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1401 	msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1402 	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1403 
1404 	msg->header_ok = 1;
1405 	msg->state = DNS_SECTION_QUESTION;
1406 
1407 	/*
1408 	 * -1 means no EDNS.
1409 	 */
1410 	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1411 
1412 	dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1413 
1414 	ret = getquestions(source, msg, &dctx, options);
1415 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1416 		goto truncated;
1417 	if (ret == DNS_R_RECOVERABLE) {
1418 		seen_problem = 1;
1419 		ret = ISC_R_SUCCESS;
1420 	}
1421 	if (ret != ISC_R_SUCCESS)
1422 		return (ret);
1423 	msg->question_ok = 1;
1424 
1425 	ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1426 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1427 		goto truncated;
1428 	if (ret == DNS_R_RECOVERABLE) {
1429 		seen_problem = 1;
1430 		ret = ISC_R_SUCCESS;
1431 	}
1432 	if (ret != ISC_R_SUCCESS)
1433 		return (ret);
1434 
1435 	ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1436 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1437 		goto truncated;
1438 	if (ret == DNS_R_RECOVERABLE) {
1439 		seen_problem = 1;
1440 		ret = ISC_R_SUCCESS;
1441 	}
1442 	if (ret != ISC_R_SUCCESS)
1443 		return (ret);
1444 
1445 	ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1446 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1447 		goto truncated;
1448 	if (ret == DNS_R_RECOVERABLE) {
1449 		seen_problem = 1;
1450 		ret = ISC_R_SUCCESS;
1451 	}
1452 	if (ret != ISC_R_SUCCESS)
1453 		return (ret);
1454 
1455 	isc_buffer_remainingregion(source, &r);
1456 	if (r.length != 0) {
1457 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1458 			      DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1459 			      "message has %u byte(s) of trailing garbage",
1460 			      r.length);
1461 	}
1462 
1463  truncated:
1464 	isc_buffer_usedregion(&origsource, &msg->saved);
1465 
1466 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1467 		return (DNS_R_RECOVERABLE);
1468 	if (seen_problem)
1469 		return (DNS_R_RECOVERABLE);
1470 	return (ISC_R_SUCCESS);
1471 }
1472 
1473 isc_result_t
dns_message_renderbegin(dns_message_t * msg,dns_compress_t * cctx,isc_buffer_t * buffer)1474 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1475 			isc_buffer_t *buffer)
1476 {
1477 	isc_region_t r;
1478 
1479 	REQUIRE(buffer != NULL);
1480 	REQUIRE(msg->buffer == NULL);
1481 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1482 
1483 	msg->cctx = cctx;
1484 
1485 	/*
1486 	 * Erase the contents of this buffer.
1487 	 */
1488 	isc_buffer_clear(buffer);
1489 
1490 	/*
1491 	 * Make certain there is enough for at least the header in this
1492 	 * buffer.
1493 	 */
1494 	isc_buffer_availableregion(buffer, &r);
1495 	if (r.length < DNS_MESSAGE_HEADERLEN)
1496 		return (ISC_R_NOSPACE);
1497 
1498 	if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
1499 		return (ISC_R_NOSPACE);
1500 
1501 	/*
1502 	 * Reserve enough space for the header in this buffer.
1503 	 */
1504 	isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1505 
1506 	msg->buffer = buffer;
1507 
1508 	return (ISC_R_SUCCESS);
1509 }
1510 
1511 void
dns_message_renderrelease(dns_message_t * msg,unsigned int space)1512 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1513 	REQUIRE(space <= msg->reserved);
1514 
1515 	msg->reserved -= space;
1516 }
1517 
1518 isc_result_t
dns_message_renderreserve(dns_message_t * msg,unsigned int space)1519 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1520 	isc_region_t r;
1521 
1522 	if (msg->buffer != NULL) {
1523 		isc_buffer_availableregion(msg->buffer, &r);
1524 		if (r.length < (space + msg->reserved))
1525 			return (ISC_R_NOSPACE);
1526 	}
1527 
1528 	msg->reserved += space;
1529 
1530 	return (ISC_R_SUCCESS);
1531 }
1532 
1533 static inline int
wrong_priority(dns_rdataset_t * rds,int pass)1534 wrong_priority(dns_rdataset_t *rds, int pass) {
1535 	int pass_needed;
1536 
1537 	/*
1538 	 * If we are not rendering class IN, this ordering is bogus.
1539 	 */
1540 	if (rds->rdclass != dns_rdataclass_in)
1541 		return (0);
1542 
1543 	switch (rds->type) {
1544 	case dns_rdatatype_a:
1545 	case dns_rdatatype_aaaa:
1546 		pass_needed = 3;
1547 		break;
1548 	case dns_rdatatype_rrsig:
1549 	case dns_rdatatype_dnskey:
1550 		pass_needed = 2;
1551 		break;
1552 	default:
1553 		pass_needed = 1;
1554 	}
1555 
1556 	if (pass_needed >= pass)
1557 		return (0);
1558 
1559 	return (1);
1560 }
1561 
1562 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 * countp)1563 renderset(dns_rdataset_t *rdataset, dns_name_t *owner_name,
1564 	  dns_compress_t *cctx, isc_buffer_t *target,
1565 	  unsigned int reserved, unsigned int *countp)
1566 {
1567 	isc_result_t result;
1568 
1569 	/*
1570 	 * Shrink the space in the buffer by the reserved amount.
1571 	 */
1572 	if (target->length - target->used < reserved)
1573 		return (ISC_R_NOSPACE);
1574 
1575 	target->length -= reserved;
1576 	result = dns_rdataset_towire(rdataset, owner_name,
1577 				     cctx, target, countp);
1578 	target->length += reserved;
1579 
1580 	return (result);
1581 }
1582 
1583 static void
maybe_clear_ad(dns_message_t * msg,dns_section_t sectionid)1584 maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) {
1585 	if (msg->counts[sectionid] == 0 &&
1586 	    (sectionid == DNS_SECTION_ANSWER ||
1587 	     (sectionid == DNS_SECTION_AUTHORITY &&
1588 	      msg->counts[DNS_SECTION_ANSWER] == 0)))
1589 		msg->flags &= ~DNS_MESSAGEFLAG_AD;
1590 }
1591 
1592 isc_result_t
dns_message_rendersection(dns_message_t * msg,dns_section_t sectionid)1593 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid)
1594 {
1595 	dns_namelist_t *section;
1596 	dns_name_t *name, *next_name;
1597 	dns_rdataset_t *rdataset, *next_rdataset;
1598 	unsigned int count, total;
1599 	isc_result_t result;
1600 	isc_buffer_t st; /* for rollbacks */
1601 	int pass;
1602 
1603 	REQUIRE(msg->buffer != NULL);
1604 	REQUIRE(VALID_NAMED_SECTION(sectionid));
1605 
1606 	section = &msg->sections[sectionid];
1607 
1608 	if (sectionid == DNS_SECTION_ADDITIONAL)
1609 		pass = 3;
1610 	else
1611 		pass = 1;
1612 
1613 	/*
1614 	 * Shrink the space in the buffer by the reserved amount.
1615 	 */
1616 	if (msg->buffer->length - msg->buffer->used < msg->reserved)
1617 		return (ISC_R_NOSPACE);
1618 	msg->buffer->length -= msg->reserved;
1619 
1620 	total = 0;
1621 
1622 	do {
1623 		name = ISC_LIST_HEAD(*section);
1624 		if (name == NULL) {
1625 			msg->buffer->length += msg->reserved;
1626 			msg->counts[sectionid] += total;
1627 			return (ISC_R_SUCCESS);
1628 		}
1629 
1630 		while (name != NULL) {
1631 			next_name = ISC_LIST_NEXT(name, link);
1632 
1633 			rdataset = ISC_LIST_HEAD(name->list);
1634 			while (rdataset != NULL) {
1635 				next_rdataset = ISC_LIST_NEXT(rdataset, link);
1636 
1637 				if ((rdataset->attributes &
1638 				     DNS_RDATASETATTR_RENDERED) != 0)
1639 					goto next;
1640 
1641 				if ((sectionid == DNS_SECTION_ADDITIONAL)
1642 				    && wrong_priority(rdataset, pass))
1643 					goto next;
1644 
1645 				st = *(msg->buffer);
1646 
1647 				count = 0;
1648 				result = dns_rdataset_towiresorted(
1649 						  rdataset,
1650 						  name,
1651 						  msg->cctx,
1652 						  msg->buffer,
1653 						  &count);
1654 
1655 				total += count;
1656 
1657 				/*
1658 				 * If out of space, record stats on what we
1659 				 * rendered so far, and return that status.
1660 				 *
1661 				 */
1662 				if (result != ISC_R_SUCCESS) {
1663 					INSIST(st.used < 65536);
1664 					dns_compress_rollback(msg->cctx,
1665 							(uint16_t)st.used);
1666 					*(msg->buffer) = st;  /* rollback */
1667 					msg->buffer->length += msg->reserved;
1668 					msg->counts[sectionid] += total;
1669 					maybe_clear_ad(msg, sectionid);
1670 					return (result);
1671 				}
1672 
1673 				/*
1674 				 * If we have rendered non-validated data,
1675 				 * ensure that the AD bit is not set.
1676 				 */
1677 				if ((sectionid == DNS_SECTION_ANSWER ||
1678 				     sectionid == DNS_SECTION_AUTHORITY))
1679 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
1680 
1681 				rdataset->attributes |=
1682 					DNS_RDATASETATTR_RENDERED;
1683 
1684 			next:
1685 				rdataset = next_rdataset;
1686 			}
1687 
1688 			name = next_name;
1689 		}
1690 	} while (--pass != 0);
1691 
1692 	msg->buffer->length += msg->reserved;
1693 	msg->counts[sectionid] += total;
1694 
1695 	return (ISC_R_SUCCESS);
1696 }
1697 
1698 void
dns_message_renderheader(dns_message_t * msg,isc_buffer_t * target)1699 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
1700 	uint16_t tmp;
1701 	isc_region_t r;
1702 
1703 	REQUIRE(target != NULL);
1704 
1705 	isc_buffer_availableregion(target, &r);
1706 	REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
1707 
1708 	isc_buffer_putuint16(target, msg->id);
1709 
1710 	tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
1711 	       & DNS_MESSAGE_OPCODE_MASK);
1712 	tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
1713 	tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
1714 
1715 	INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
1716 	       msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
1717 	       msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
1718 	       msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
1719 
1720 	isc_buffer_putuint16(target, tmp);
1721 	isc_buffer_putuint16(target,
1722 			    (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
1723 	isc_buffer_putuint16(target,
1724 			    (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
1725 	isc_buffer_putuint16(target,
1726 			    (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
1727 	isc_buffer_putuint16(target,
1728 			    (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
1729 }
1730 
1731 isc_result_t
dns_message_renderend(dns_message_t * msg)1732 dns_message_renderend(dns_message_t *msg) {
1733 	isc_buffer_t tmpbuf;
1734 	isc_region_t r;
1735 	int result;
1736 	unsigned int count;
1737 
1738 	REQUIRE(msg->buffer != NULL);
1739 
1740 	if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
1741 		/*
1742 		 * We have an extended rcode but are not using EDNS.
1743 		 */
1744 		return (DNS_R_FORMERR);
1745 	}
1746 
1747 	/*
1748 	 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
1749 	 * clear all rdatasets from the message except for the question
1750 	 * before adding the OPT, TSIG or SIG(0).  If the question doesn't
1751 	 * fit, don't include it.
1752 	 */
1753 	if ((msg->tsigkey != NULL || msg->opt) &&
1754 	    (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
1755 	{
1756 		isc_buffer_t *buf;
1757 
1758 		msgresetnames(msg, DNS_SECTION_ANSWER);
1759 		buf = msg->buffer;
1760 		dns_message_renderreset(msg);
1761 		msg->buffer = buf;
1762 		isc_buffer_clear(msg->buffer);
1763 		isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
1764 		dns_compress_rollback(msg->cctx, 0);
1765 		result = dns_message_rendersection(msg, DNS_SECTION_QUESTION);
1766 		if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
1767 			return (result);
1768 	}
1769 
1770 	/*
1771 	 * If we've got an OPT record, render it.
1772 	 */
1773 	if (msg->opt != NULL) {
1774 		dns_message_renderrelease(msg, msg->opt_reserved);
1775 		msg->opt_reserved = 0;
1776 		/*
1777 		 * Set the extended rcode.
1778 		 */
1779 		msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
1780 		msg->opt->ttl |= ((msg->rcode << 20) &
1781 				  DNS_MESSAGE_EDNSRCODE_MASK);
1782 		/*
1783 		 * Render.
1784 		 */
1785 		count = 0;
1786 		result = renderset(msg->opt, dns_rootname, msg->cctx,
1787 				   msg->buffer, msg->reserved, &count);
1788 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
1789 		if (result != ISC_R_SUCCESS)
1790 			return (result);
1791 	}
1792 
1793 	/*
1794 	 * If we're adding a TSIG record, generate and render it.
1795 	 */
1796 	if (msg->tsigkey != NULL) {
1797 		dns_message_renderrelease(msg, msg->sig_reserved);
1798 		msg->sig_reserved = 0;
1799 		result = dns_tsig_sign(msg);
1800 		if (result != ISC_R_SUCCESS)
1801 			return (result);
1802 		count = 0;
1803 		result = renderset(msg->tsig, msg->tsigname, msg->cctx,
1804 				   msg->buffer, msg->reserved, &count);
1805 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
1806 		if (result != ISC_R_SUCCESS)
1807 			return (result);
1808 	}
1809 
1810 	isc_buffer_usedregion(msg->buffer, &r);
1811 	isc_buffer_init(&tmpbuf, r.base, r.length);
1812 
1813 	dns_message_renderheader(msg, &tmpbuf);
1814 
1815 	msg->buffer = NULL;  /* forget about this buffer only on success XXX */
1816 
1817 	return (ISC_R_SUCCESS);
1818 }
1819 
1820 void
dns_message_renderreset(dns_message_t * msg)1821 dns_message_renderreset(dns_message_t *msg) {
1822 	unsigned int i;
1823 	dns_name_t *name;
1824 	dns_rdataset_t *rds;
1825 
1826 	/*
1827 	 * Reset the message so that it may be rendered again.
1828 	 */
1829 
1830 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1831 
1832 	msg->buffer = NULL;
1833 
1834 	for (i = 0; i < DNS_SECTION_MAX; i++) {
1835 		msg->cursors[i] = NULL;
1836 		msg->counts[i] = 0;
1837 		for (name = ISC_LIST_HEAD(msg->sections[i]);
1838 		     name != NULL;
1839 		     name = ISC_LIST_NEXT(name, link)) {
1840 			for (rds = ISC_LIST_HEAD(name->list);
1841 			     rds != NULL;
1842 			     rds = ISC_LIST_NEXT(rds, link)) {
1843 				rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
1844 			}
1845 		}
1846 	}
1847 	if (msg->tsigname != NULL)
1848 		dns_message_puttempname(msg, &msg->tsigname);
1849 	if (msg->tsig != NULL) {
1850 		dns_rdataset_disassociate(msg->tsig);
1851 		dns_message_puttemprdataset(msg, &msg->tsig);
1852 	}
1853 	if (msg->sig0 != NULL) {
1854 		dns_rdataset_disassociate(msg->sig0);
1855 		dns_message_puttemprdataset(msg, &msg->sig0);
1856 	}
1857 }
1858 
1859 isc_result_t
dns_message_firstname(dns_message_t * msg,dns_section_t section)1860 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
1861 	REQUIRE(VALID_NAMED_SECTION(section));
1862 
1863 	msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
1864 
1865 	if (msg->cursors[section] == NULL)
1866 		return (ISC_R_NOMORE);
1867 
1868 	return (ISC_R_SUCCESS);
1869 }
1870 
1871 isc_result_t
dns_message_nextname(dns_message_t * msg,dns_section_t section)1872 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
1873 	REQUIRE(VALID_NAMED_SECTION(section));
1874 	REQUIRE(msg->cursors[section] != NULL);
1875 
1876 	msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
1877 
1878 	if (msg->cursors[section] == NULL)
1879 		return (ISC_R_NOMORE);
1880 
1881 	return (ISC_R_SUCCESS);
1882 }
1883 
1884 void
dns_message_currentname(dns_message_t * msg,dns_section_t section,dns_name_t ** name)1885 dns_message_currentname(dns_message_t *msg, dns_section_t section,
1886 			dns_name_t **name)
1887 {
1888 	REQUIRE(VALID_NAMED_SECTION(section));
1889 	REQUIRE(name != NULL && *name == NULL);
1890 	REQUIRE(msg->cursors[section] != NULL);
1891 
1892 	*name = msg->cursors[section];
1893 }
1894 
1895 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)1896 dns_message_findname(dns_message_t *msg, dns_section_t section,
1897 		     dns_name_t *target, dns_rdatatype_t type,
1898 		     dns_rdatatype_t covers, dns_name_t **name,
1899 		     dns_rdataset_t **rdataset)
1900 {
1901 	dns_name_t *foundname;
1902 	isc_result_t result;
1903 
1904 	/*
1905 	 * XXX These requirements are probably too intensive, especially
1906 	 * where things can be NULL, but as they are they ensure that if
1907 	 * something is NON-NULL, indicating that the caller expects it
1908 	 * to be filled in, that we can in fact fill it in.
1909 	 */
1910 	REQUIRE(msg != NULL);
1911 	REQUIRE(VALID_SECTION(section));
1912 	REQUIRE(target != NULL);
1913 	REQUIRE(name == NULL || *name == NULL);
1914 
1915 	if (type == dns_rdatatype_any) {
1916 		REQUIRE(rdataset == NULL);
1917 	} else {
1918 		REQUIRE(rdataset == NULL || *rdataset == NULL);
1919 	}
1920 
1921 	result = findname(&foundname, target,
1922 			  &msg->sections[section]);
1923 
1924 	if (result == ISC_R_NOTFOUND)
1925 		return (DNS_R_NXDOMAIN);
1926 	else if (result != ISC_R_SUCCESS)
1927 		return (result);
1928 
1929 	if (name != NULL)
1930 		*name = foundname;
1931 
1932 	/*
1933 	 * And now look for the type.
1934 	 */
1935 	if (type == dns_rdatatype_any)
1936 		return (ISC_R_SUCCESS);
1937 
1938 	result = dns_message_findtype(foundname, type, covers, rdataset);
1939 	if (result == ISC_R_NOTFOUND)
1940 		return (DNS_R_NXRRSET);
1941 
1942 	return (result);
1943 }
1944 
1945 void
dns_message_addname(dns_message_t * msg,dns_name_t * name,dns_section_t section)1946 dns_message_addname(dns_message_t *msg, dns_name_t *name,
1947 		    dns_section_t section)
1948 {
1949 	REQUIRE(msg != NULL);
1950 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1951 	REQUIRE(name != NULL);
1952 	REQUIRE(VALID_NAMED_SECTION(section));
1953 
1954 	ISC_LIST_APPEND(msg->sections[section], name, link);
1955 }
1956 
1957 isc_result_t
dns_message_gettempname(dns_message_t * msg,dns_name_t ** item)1958 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
1959 	REQUIRE(item != NULL && *item == NULL);
1960 
1961 	UNUSED(msg);
1962 
1963 	*item = malloc(sizeof(dns_name_t));
1964 	if (*item == NULL)
1965 		return (ISC_R_NOMEMORY);
1966 	dns_name_init(*item, NULL);
1967 
1968 	return (ISC_R_SUCCESS);
1969 }
1970 
1971 isc_result_t
dns_message_gettemprdata(dns_message_t * msg,dns_rdata_t ** item)1972 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
1973 	REQUIRE(item != NULL && *item == NULL);
1974 
1975 	*item = newrdata(msg);
1976 	if (*item == NULL)
1977 		return (ISC_R_NOMEMORY);
1978 
1979 	return (ISC_R_SUCCESS);
1980 }
1981 
1982 isc_result_t
dns_message_gettemprdataset(dns_message_t * msg,dns_rdataset_t ** item)1983 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
1984 	REQUIRE(item != NULL && *item == NULL);
1985 
1986 	UNUSED(msg);
1987 
1988 	*item = malloc(sizeof(dns_rdataset_t));
1989 	if (*item == NULL)
1990 		return (ISC_R_NOMEMORY);
1991 
1992 	dns_rdataset_init(*item);
1993 
1994 	return (ISC_R_SUCCESS);
1995 }
1996 
1997 isc_result_t
dns_message_gettemprdatalist(dns_message_t * msg,dns_rdatalist_t ** item)1998 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
1999 	REQUIRE(item != NULL && *item == NULL);
2000 
2001 	*item = newrdatalist(msg);
2002 	if (*item == NULL)
2003 		return (ISC_R_NOMEMORY);
2004 
2005 	return (ISC_R_SUCCESS);
2006 }
2007 
2008 void
dns_message_puttempname(dns_message_t * msg,dns_name_t ** item)2009 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2010 	REQUIRE(item != NULL && *item != NULL);
2011 
2012 	UNUSED(msg);
2013 
2014 	if (dns_name_dynamic(*item))
2015 		dns_name_free(*item);
2016 	free(*item);
2017 	*item = NULL;
2018 }
2019 
2020 void
dns_message_puttemprdata(dns_message_t * msg,dns_rdata_t ** item)2021 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2022 	REQUIRE(item != NULL && *item != NULL);
2023 
2024 	releaserdata(msg, *item);
2025 	*item = NULL;
2026 }
2027 
2028 void
dns_message_puttemprdataset(dns_message_t * msg,dns_rdataset_t ** item)2029 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2030 	REQUIRE(item != NULL && *item != NULL);
2031 	REQUIRE(!dns_rdataset_isassociated(*item));
2032 
2033 	UNUSED(msg);
2034 
2035 	free(*item);
2036 	*item = NULL;
2037 }
2038 
2039 void
dns_message_puttemprdatalist(dns_message_t * msg,dns_rdatalist_t ** item)2040 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2041 	REQUIRE(item != NULL && *item != NULL);
2042 
2043 	releaserdatalist(msg, *item);
2044 	*item = NULL;
2045 }
2046 
2047 isc_result_t
dns_message_peekheader(isc_buffer_t * source,dns_messageid_t * idp,unsigned int * flagsp)2048 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2049 		       unsigned int *flagsp)
2050 {
2051 	isc_region_t r;
2052 	isc_buffer_t buffer;
2053 	dns_messageid_t id;
2054 	unsigned int flags;
2055 
2056 	REQUIRE(source != NULL);
2057 
2058 	buffer = *source;
2059 
2060 	isc_buffer_remainingregion(&buffer, &r);
2061 	if (r.length < DNS_MESSAGE_HEADERLEN)
2062 		return (ISC_R_UNEXPECTEDEND);
2063 
2064 	id = isc_buffer_getuint16(&buffer);
2065 	flags = isc_buffer_getuint16(&buffer);
2066 	flags &= DNS_MESSAGE_FLAG_MASK;
2067 
2068 	if (flagsp != NULL)
2069 		*flagsp = flags;
2070 	if (idp != NULL)
2071 		*idp = id;
2072 
2073 	return (ISC_R_SUCCESS);
2074 }
2075 
2076 dns_rdataset_t *
dns_message_getopt(dns_message_t * msg)2077 dns_message_getopt(dns_message_t *msg) {
2078 
2079 	/*
2080 	 * Get the OPT record for 'msg'.
2081 	 */
2082 	return (msg->opt);
2083 }
2084 
2085 isc_result_t
dns_message_setopt(dns_message_t * msg,dns_rdataset_t * opt)2086 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2087 	isc_result_t result;
2088 	dns_rdata_t rdata = DNS_RDATA_INIT;
2089 
2090 	/*
2091 	 * Set the OPT record for 'msg'.
2092 	 */
2093 
2094 	/*
2095 	 * The space required for an OPT record is:
2096 	 *
2097 	 *	1 byte for the name
2098 	 *	2 bytes for the type
2099 	 *	2 bytes for the class
2100 	 *	4 bytes for the ttl
2101 	 *	2 bytes for the rdata length
2102 	 * ---------------------------------
2103 	 *     11 bytes
2104 	 *
2105 	 * plus the length of the rdata.
2106 	 */
2107 
2108 	REQUIRE(opt->type == dns_rdatatype_opt);
2109 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2110 	REQUIRE(msg->state == DNS_SECTION_ANY);
2111 
2112 	msgresetopt(msg);
2113 
2114 	result = dns_rdataset_first(opt);
2115 	if (result != ISC_R_SUCCESS)
2116 		goto cleanup;
2117 	dns_rdataset_current(opt, &rdata);
2118 	msg->opt_reserved = 11 + rdata.length;
2119 	result = dns_message_renderreserve(msg, msg->opt_reserved);
2120 	if (result != ISC_R_SUCCESS) {
2121 		msg->opt_reserved = 0;
2122 		goto cleanup;
2123 	}
2124 
2125 	msg->opt = opt;
2126 
2127 	return (ISC_R_SUCCESS);
2128 
2129  cleanup:
2130 	dns_rdataset_disassociate(opt);
2131 	dns_message_puttemprdataset(msg, &opt);
2132 	return (result);
2133 }
2134 
2135 dns_rdataset_t *
dns_message_gettsig(dns_message_t * msg,dns_name_t ** owner)2136 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2137 
2138 	/*
2139 	 * Get the TSIG record and owner for 'msg'.
2140 	 */
2141 
2142 	REQUIRE(owner == NULL || *owner == NULL);
2143 
2144 	if (owner != NULL)
2145 		*owner = msg->tsigname;
2146 	return (msg->tsig);
2147 }
2148 
2149 isc_result_t
dns_message_settsigkey(dns_message_t * msg,dns_tsigkey_t * key)2150 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2151 	isc_result_t result;
2152 
2153 	/*
2154 	 * Set the TSIG key for 'msg'
2155 	 */
2156 
2157 	REQUIRE(msg->state == DNS_SECTION_ANY);
2158 
2159 	if (key == NULL && msg->tsigkey != NULL) {
2160 		if (msg->sig_reserved != 0) {
2161 			dns_message_renderrelease(msg, msg->sig_reserved);
2162 			msg->sig_reserved = 0;
2163 		}
2164 		dns_tsigkey_detach(&msg->tsigkey);
2165 	}
2166 	if (key != NULL) {
2167 		REQUIRE(msg->tsigkey == NULL);
2168 		dns_tsigkey_attach(key, &msg->tsigkey);
2169 		if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2170 			msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2171 			result = dns_message_renderreserve(msg,
2172 							   msg->sig_reserved);
2173 			if (result != ISC_R_SUCCESS) {
2174 				dns_tsigkey_detach(&msg->tsigkey);
2175 				msg->sig_reserved = 0;
2176 				return (result);
2177 			}
2178 		}
2179 	}
2180 	return (ISC_R_SUCCESS);
2181 }
2182 
2183 dns_tsigkey_t *
dns_message_gettsigkey(dns_message_t * msg)2184 dns_message_gettsigkey(dns_message_t *msg) {
2185 
2186 	/*
2187 	 * Get the TSIG key for 'msg'
2188 	 */
2189 	return (msg->tsigkey);
2190 }
2191 
2192 isc_result_t
dns_message_setquerytsig(dns_message_t * msg,isc_buffer_t * querytsig)2193 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2194 	dns_rdata_t *rdata = NULL;
2195 	dns_rdatalist_t *list = NULL;
2196 	dns_rdataset_t *set = NULL;
2197 	isc_buffer_t *buf = NULL;
2198 	isc_region_t r;
2199 	isc_result_t result;
2200 
2201 	REQUIRE(msg->querytsig == NULL);
2202 
2203 	if (querytsig == NULL)
2204 		return (ISC_R_SUCCESS);
2205 
2206 	result = dns_message_gettemprdata(msg, &rdata);
2207 	if (result != ISC_R_SUCCESS)
2208 		goto cleanup;
2209 
2210 	result = dns_message_gettemprdatalist(msg, &list);
2211 	if (result != ISC_R_SUCCESS)
2212 		goto cleanup;
2213 	result = dns_message_gettemprdataset(msg, &set);
2214 	if (result != ISC_R_SUCCESS)
2215 		goto cleanup;
2216 
2217 	isc_buffer_usedregion(querytsig, &r);
2218 	result = isc_buffer_allocate(&buf, r.length);
2219 	if (result != ISC_R_SUCCESS)
2220 		goto cleanup;
2221 	isc_buffer_putmem(buf, r.base, r.length);
2222 	isc_buffer_usedregion(buf, &r);
2223 	dns_rdata_init(rdata);
2224 	dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2225 	dns_message_takebuffer(msg, &buf);
2226 	ISC_LIST_APPEND(list->rdata, rdata, link);
2227 	result = dns_rdatalist_tordataset(list, set);
2228 	if (result != ISC_R_SUCCESS)
2229 		goto cleanup;
2230 
2231 	msg->querytsig = set;
2232 
2233 	return (result);
2234 
2235  cleanup:
2236 	if (rdata != NULL)
2237 		dns_message_puttemprdata(msg, &rdata);
2238 	if (list != NULL)
2239 		dns_message_puttemprdatalist(msg, &list);
2240 	if (set != NULL)
2241 		dns_message_puttemprdataset(msg, &set);
2242 	return (ISC_R_NOMEMORY);
2243 }
2244 
2245 isc_result_t
dns_message_getquerytsig(dns_message_t * msg,isc_buffer_t ** querytsig)2246 dns_message_getquerytsig(dns_message_t *msg, isc_buffer_t **querytsig) {
2247 	isc_result_t result;
2248 	dns_rdata_t rdata = DNS_RDATA_INIT;
2249 	isc_region_t r;
2250 
2251 	REQUIRE(querytsig != NULL && *querytsig == NULL);
2252 
2253 	if (msg->tsig == NULL)
2254 		return (ISC_R_SUCCESS);
2255 
2256 	result = dns_rdataset_first(msg->tsig);
2257 	if (result != ISC_R_SUCCESS)
2258 		return (result);
2259 	dns_rdataset_current(msg->tsig, &rdata);
2260 	dns_rdata_toregion(&rdata, &r);
2261 
2262 	result = isc_buffer_allocate(querytsig, r.length);
2263 	if (result != ISC_R_SUCCESS)
2264 		return (result);
2265 	isc_buffer_putmem(*querytsig, r.base, r.length);
2266 	return (ISC_R_SUCCESS);
2267 }
2268 
2269 dns_rdataset_t *
dns_message_getsig0(dns_message_t * msg,dns_name_t ** owner)2270 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2271 
2272 	/*
2273 	 * Get the SIG(0) record for 'msg'.
2274 	 */
2275 
2276 	REQUIRE(owner == NULL || *owner == NULL);
2277 
2278 	if (msg->sig0 != NULL && owner != NULL) {
2279 		/* If dns_message_getsig0 is called on a rendered message
2280 		 * after the SIG(0) has been applied, we need to return the
2281 		 * root name, not NULL.
2282 		 */
2283 		if (msg->sig0name == NULL)
2284 			*owner = dns_rootname;
2285 		else
2286 			*owner = msg->sig0name;
2287 	}
2288 	return (msg->sig0);
2289 }
2290 
2291 void
dns_message_takebuffer(dns_message_t * msg,isc_buffer_t ** buffer)2292 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2293 	REQUIRE(buffer != NULL);
2294 
2295 	ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2296 	*buffer = NULL;
2297 }
2298 
2299 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)2300 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
2301 			  const dns_master_style_t *style,
2302 			  dns_messagetextflag_t flags,
2303 			  isc_buffer_t *target) {
2304 	dns_name_t *name, empty_name;
2305 	dns_rdataset_t *rdataset;
2306 	isc_result_t result;
2307 	int seensoa = 0;
2308 
2309 	REQUIRE(target != NULL);
2310 	REQUIRE(VALID_SECTION(section));
2311 
2312 	if (ISC_LIST_EMPTY(msg->sections[section]))
2313 		return (ISC_R_SUCCESS);
2314 
2315 	if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
2316 		ADD_STRING(target, ";; ");
2317 		if (msg->opcode != dns_opcode_update) {
2318 			ADD_STRING(target, sectiontext[section]);
2319 		} else {
2320 			ADD_STRING(target, updsectiontext[section]);
2321 		}
2322 		ADD_STRING(target, " SECTION:\n");
2323 	}
2324 
2325 	dns_name_init(&empty_name, NULL);
2326 	result = dns_message_firstname(msg, section);
2327 	if (result != ISC_R_SUCCESS) {
2328 		return (result);
2329 	}
2330 	do {
2331 		name = NULL;
2332 		dns_message_currentname(msg, section, &name);
2333 		for (rdataset = ISC_LIST_HEAD(name->list);
2334 		     rdataset != NULL;
2335 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
2336 			if (section == DNS_SECTION_ANSWER &&
2337 			    rdataset->type == dns_rdatatype_soa) {
2338 				if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
2339 					continue;
2340 				if (seensoa &&
2341 				    (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
2342 					continue;
2343 				seensoa = 1;
2344 			}
2345 			if (section == DNS_SECTION_QUESTION) {
2346 				ADD_STRING(target, ";");
2347 				result = dns_master_questiontotext(name,
2348 								   rdataset,
2349 								   style,
2350 								   target);
2351 			} else {
2352 				result = dns_master_rdatasettotext(name,
2353 								   rdataset,
2354 								   style,
2355 								   target);
2356 			}
2357 			if (result != ISC_R_SUCCESS)
2358 				return (result);
2359 		}
2360 		result = dns_message_nextname(msg, section);
2361 	} while (result == ISC_R_SUCCESS);
2362 	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2363 	    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2364 		ADD_STRING(target, "\n");
2365 	if (result == ISC_R_NOMORE)
2366 		result = ISC_R_SUCCESS;
2367 	return (result);
2368 }
2369 
2370 static isc_result_t
render_ecs(isc_buffer_t * ecsbuf,isc_buffer_t * target)2371 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
2372 	int i;
2373 	char addr[16], addr_text[64];
2374 	uint16_t family;
2375 	uint8_t addrlen, addrbytes, scopelen;
2376 
2377 	/*
2378 	 * Note: This routine needs to handle malformed ECS options.
2379 	 */
2380 
2381 	if (isc_buffer_remaininglength(ecsbuf) < 4)
2382 		return (DNS_R_OPTERR);
2383 	family = isc_buffer_getuint16(ecsbuf);
2384 	addrlen = isc_buffer_getuint8(ecsbuf);
2385 	scopelen = isc_buffer_getuint8(ecsbuf);
2386 
2387 	addrbytes = (addrlen + 7) / 8;
2388 	if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
2389 		return (DNS_R_OPTERR);
2390 
2391 	if (addrbytes > sizeof(addr))
2392 		return (DNS_R_OPTERR);
2393 
2394 	memset(addr, 0, sizeof(addr));
2395 	for (i = 0; i < addrbytes; i ++)
2396 		addr[i] = isc_buffer_getuint8(ecsbuf);
2397 
2398 	switch (family) {
2399 	case 0:
2400 		if (addrlen != 0U || scopelen != 0U)
2401 			return (DNS_R_OPTERR);
2402 		strlcpy(addr_text, "0", sizeof(addr_text));
2403 		break;
2404 	case 1:
2405 		if (addrlen > 32 || scopelen > 32)
2406 			return (DNS_R_OPTERR);
2407 		inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
2408 		break;
2409 	case 2:
2410 		if (addrlen > 128 || scopelen > 128)
2411 			return (DNS_R_OPTERR);
2412 		inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
2413 		break;
2414 	default:
2415 		return (DNS_R_OPTERR);
2416 	}
2417 
2418 	ADD_STRING(target, ": ");
2419 	ADD_STRING(target, addr_text);
2420 	snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
2421 	ADD_STRING(target, addr_text);
2422 	return (ISC_R_SUCCESS);
2423 }
2424 
2425 static const char *
ede_info_code2str(uint16_t info_code)2426 ede_info_code2str(uint16_t info_code)
2427 {
2428 	if (info_code > 49151)
2429 		return "Private Use";
2430 
2431 	switch (info_code) {
2432 	case 0:
2433 		return "Other Error";
2434 	case 1:
2435 		return "Unsupported DNSKEY Algorithm";
2436 	case 2:
2437 		return "Unsupported DS Digest Type";
2438 	case 3:
2439 		return "Stale Answer";
2440 	case 4:
2441 		return "Forged Answer";
2442 	case 5:
2443 		return "DNSSEC Indeterminate";
2444 	case 6:
2445 		return "DNSSEC Bogus";
2446 	case 7:
2447 		return "Signature Expired";
2448 	case 8:
2449 		return "Signature Not Yet Valid";
2450 	case 9:
2451 		return "DNSKEY Missing";
2452 	case 10:
2453 		return "RRSIGs Missing";
2454 	case 11:
2455 		return "No Zone Key Bit Set";
2456 	case 12:
2457 		return "NSEC Missing";
2458 	case 13:
2459 		return "Cached Error";
2460 	case 14:
2461 		return "Not Ready";
2462 	case 15:
2463 		return "Blocked";
2464 	case 16:
2465 		return "Censored";
2466 	case 17:
2467 		return "Filtered";
2468 	case 18:
2469 		return "Prohibited";
2470 	case 19:
2471 		return "Stale NXDomain Answer";
2472 	case 20:
2473 		return "Not Authoritative";
2474 	case 21:
2475 		return "Not Supported";
2476 	case 22:
2477 		return "No Reachable Authority";
2478 	case 23:
2479 		return "Network Error";
2480 	case 24:
2481 		return "Invalid Data";
2482 	default:
2483 		return "Unassigned";
2484 	}
2485 }
2486 
2487 static const char *
zoneversion_zone(const char * zone,int labelcount)2488 zoneversion_zone(const char *zone, int labelcount)
2489 {
2490 	size_t pos;
2491 
2492 	if (zone == NULL || labelcount == 0)
2493 		return ".";
2494 
2495 	pos = strlen(zone);
2496 	if (pos == 0)
2497 		return ".";
2498 
2499 	pos--; /* go to last char in string */
2500 	if (zone[pos] == '.')
2501 		pos--; /* the labelcount does not count the empty root label */
2502 
2503 	for (; pos > 0; pos--) {
2504 		if (zone[pos] == '.') {
2505 			labelcount--;
2506 
2507 			if (labelcount == 0) {
2508 				pos++;
2509 				break;
2510 			}
2511 		}
2512 	}
2513 
2514 	return (zone + pos);
2515 }
2516 
2517 isc_result_t
dns_message_pseudosectiontotext(dns_message_t * msg,dns_pseudosection_t section,const dns_master_style_t * style,dns_messagetextflag_t flags,const char * textname,isc_buffer_t * target)2518 dns_message_pseudosectiontotext(dns_message_t *msg,
2519 				dns_pseudosection_t section,
2520 				const dns_master_style_t *style,
2521 				dns_messagetextflag_t flags,
2522 				const char *textname,
2523 				isc_buffer_t *target)
2524 {
2525 	dns_rdataset_t *ps = NULL;
2526 	dns_name_t *name = NULL;
2527 	isc_result_t result;
2528 	char buf[sizeof("1234567890")];
2529 	uint32_t mbz;
2530 	dns_rdata_t rdata;
2531 	isc_buffer_t optbuf;
2532 	uint16_t optcode, optlen;
2533 	unsigned char *optdata;
2534 
2535 	REQUIRE(target != NULL);
2536 	REQUIRE(VALID_PSEUDOSECTION(section));
2537 
2538 	switch (section) {
2539 	case DNS_PSEUDOSECTION_OPT:
2540 		ps = dns_message_getopt(msg);
2541 		if (ps == NULL)
2542 			return (ISC_R_SUCCESS);
2543 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2544 			ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
2545 		ADD_STRING(target, "; EDNS: version: ");
2546 		snprintf(buf, sizeof(buf), "%u",
2547 			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
2548 		ADD_STRING(target, buf);
2549 		ADD_STRING(target, ", flags:");
2550 		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
2551 			ADD_STRING(target, " do");
2552 		mbz = ps->ttl & 0xffff;
2553 		mbz &= ~DNS_MESSAGEEXTFLAG_DO;		/* Known Flags. */
2554 		if (mbz != 0) {
2555 			ADD_STRING(target, "; MBZ: ");
2556 			snprintf(buf, sizeof(buf), "0x%.4x", mbz);
2557 			ADD_STRING(target, buf);
2558 			ADD_STRING(target, ", udp: ");
2559 		} else
2560 			ADD_STRING(target, "; udp: ");
2561 		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
2562 		ADD_STRING(target, buf);
2563 
2564 		result = dns_rdataset_first(ps);
2565 		if (result != ISC_R_SUCCESS)
2566 			return (ISC_R_SUCCESS);
2567 
2568 		/*
2569 		 * Print EDNS info, if any.
2570 		 *
2571 		 * WARNING: The option contents may be malformed as
2572 		 * dig +ednsopt=value:<content> does not validity
2573 		 * checking.
2574 		 */
2575 		dns_rdata_init(&rdata);
2576 		dns_rdataset_current(ps, &rdata);
2577 
2578 		isc_buffer_init(&optbuf, rdata.data, rdata.length);
2579 		isc_buffer_add(&optbuf, rdata.length);
2580 		while (isc_buffer_remaininglength(&optbuf) != 0) {
2581 			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
2582 			optcode = isc_buffer_getuint16(&optbuf);
2583 			optlen = isc_buffer_getuint16(&optbuf);
2584 			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
2585 
2586 			if (optcode == DNS_OPT_NSID) {
2587 				ADD_STRING(target, "; NSID");
2588 			} else if (optcode == DNS_OPT_COOKIE) {
2589 				ADD_STRING(target, "; COOKIE");
2590 			} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
2591 				isc_buffer_t ecsbuf;
2592 
2593 				ADD_STRING(target, "; CLIENT-SUBNET");
2594 				isc_buffer_init(&ecsbuf,
2595 						isc_buffer_current(&optbuf),
2596 						optlen);
2597 				isc_buffer_add(&ecsbuf, optlen);
2598 				result = render_ecs(&ecsbuf, target);
2599 				if (result == ISC_R_NOSPACE)
2600 					return (result);
2601 				if (result == ISC_R_SUCCESS) {
2602 					isc_buffer_forward(&optbuf, optlen);
2603 					ADD_STRING(target, "\n");
2604 					continue;
2605 				}
2606 			} else if (optcode == DNS_OPT_EXPIRE) {
2607 				if (optlen == 4) {
2608 					uint32_t secs;
2609 					secs = isc_buffer_getuint32(&optbuf);
2610 					ADD_STRING(target, "; EXPIRE: ");
2611 					snprintf(buf, sizeof(buf), "%u", secs);
2612 					ADD_STRING(target, buf);
2613 					ADD_STRING(target, " (");
2614 					result = dns_ttl_totext(secs,
2615 								1,
2616 								target);
2617 					if (result != ISC_R_SUCCESS)
2618 						return (result);
2619 					ADD_STRING(target, ")\n");
2620 					continue;
2621 				}
2622 				ADD_STRING(target, "; EXPIRE");
2623 			} else if (optcode == DNS_OPT_PAD) {
2624 				ADD_STRING(target, "; PAD");
2625 			} else if (optcode == DNS_OPT_KEY_TAG) {
2626 				ADD_STRING(target, "; KEY-TAG");
2627 				if (optlen > 0U && (optlen % 2U) == 0U) {
2628 					const char *sep = ": ";
2629 					uint16_t id;
2630 					while (optlen > 0U) {
2631 					    id = isc_buffer_getuint16(&optbuf);
2632 					    snprintf(buf, sizeof(buf), "%s%u",
2633 						     sep, id);
2634 					    ADD_STRING(target, buf);
2635 					    sep = ", ";
2636 					    optlen -= 2;
2637 					}
2638 					ADD_STRING(target, "\n");
2639 					continue;
2640 				}
2641 			} else if (optcode == DNS_OPT_EDE) {
2642 				uint16_t info_code;
2643 				ADD_STRING(target, "; EDE");
2644 				if (optlen >= 2) {
2645 					info_code =
2646 					    isc_buffer_getuint16(&optbuf);
2647 					optlen -= 2;
2648 					snprintf(buf, sizeof(buf), ": %u (",
2649 					    info_code);
2650 					ADD_STRING(target, buf);
2651 					ADD_STRING(target,
2652 					    ede_info_code2str(info_code));
2653 					ADD_STRING(target, ")");
2654 				}
2655 			} else if (optcode == DNS_OPT_ZONEVERSION) {
2656 				int i;
2657 
2658 				ADD_STRING(target, "; ZONEVERSION: ");
2659 				optdata = isc_buffer_current(&optbuf);
2660 				for (i = 0; i < optlen; i++) {
2661 					snprintf(buf, sizeof(buf), "%02x ",
2662 						 optdata[i]);
2663 					ADD_STRING(target, buf);
2664 				}
2665 
2666 				if (optlen >= 2) {
2667 					uint8_t labelcount, type;
2668 					const char *zone;
2669 
2670 					labelcount =
2671 					    isc_buffer_getuint8(&optbuf);
2672 					optlen -= 1;
2673 					type = isc_buffer_getuint8(&optbuf);
2674 					optlen -= 1;
2675 					zone = zoneversion_zone(textname,
2676 					    labelcount);
2677 
2678 					if (type == 0 && optlen == 4) {
2679 						uint32_t serial;
2680 
2681 						serial = isc_buffer_getuint32(
2682 						    &optbuf);
2683 						optlen -= 4;
2684 						ADD_STRING(target,
2685 						    "(\"SOA-SERIAL: ");
2686 						snprintf(buf, sizeof(buf), "%u",
2687 						    serial);
2688 						ADD_STRING(target, buf);
2689 						ADD_STRING(target, " (");
2690 						ADD_STRING(target, zone);
2691 						ADD_STRING(target, ")");
2692 						ADD_STRING(target, "\")");
2693 					}
2694 				}
2695 			} else {
2696 				ADD_STRING(target, "; OPT=");
2697 				snprintf(buf, sizeof(buf), "%u", optcode);
2698 				ADD_STRING(target, buf);
2699 			}
2700 
2701 			if (optlen != 0) {
2702 				int i;
2703 				ADD_STRING(target, ": ");
2704 
2705 				optdata = isc_buffer_current(&optbuf);
2706 				for (i = 0; i < optlen; i++) {
2707 					const char *sep;
2708 					switch (optcode) {
2709 					case DNS_OPT_COOKIE:
2710 						sep = "";
2711 						break;
2712 					default:
2713 						sep = " ";
2714 						break;
2715 					}
2716 					snprintf(buf, sizeof(buf), "%02x%s",
2717 						 optdata[i], sep);
2718 					ADD_STRING(target, buf);
2719 				}
2720 
2721 				isc_buffer_forward(&optbuf, optlen);
2722 
2723 				if (optcode == DNS_OPT_COOKIE) {
2724 					if (msg->sitok)
2725 						ADD_STRING(target, " (good)");
2726 					if (msg->sitbad)
2727 						ADD_STRING(target, " (bad)");
2728 					ADD_STRING(target, "\n");
2729 					continue;
2730 				}
2731 
2732 				if (optcode == DNS_OPT_CLIENT_SUBNET) {
2733 					ADD_STRING(target, "\n");
2734 					continue;
2735 				}
2736 
2737 				/*
2738 				 * For non-SIT options, add a printable
2739 				 * version
2740 				 */
2741 				ADD_STRING(target, "(\"");
2742 				if (isc_buffer_availablelength(target) < optlen)
2743 					return (ISC_R_NOSPACE);
2744 				for (i = 0; i < optlen; i++) {
2745 					if (isprint(optdata[i]))
2746 						isc_buffer_putmem(target,
2747 								  &optdata[i],
2748 								  1);
2749 					else
2750 						isc_buffer_putstr(target, ".");
2751 				}
2752 				ADD_STRING(target, "\")");
2753 			}
2754 			ADD_STRING(target, "\n");
2755 		}
2756 		return (ISC_R_SUCCESS);
2757 	case DNS_PSEUDOSECTION_TSIG:
2758 		ps = dns_message_gettsig(msg, &name);
2759 		if (ps == NULL)
2760 			return (ISC_R_SUCCESS);
2761 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2762 			ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
2763 		result = dns_master_rdatasettotext(name, ps, style, target);
2764 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2765 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2766 			ADD_STRING(target, "\n");
2767 		return (result);
2768 	case DNS_PSEUDOSECTION_SIG0:
2769 		ps = dns_message_getsig0(msg, &name);
2770 		if (ps == NULL)
2771 			return (ISC_R_SUCCESS);
2772 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2773 			ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
2774 		result = dns_master_rdatasettotext(name, ps, style, target);
2775 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2776 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2777 			ADD_STRING(target, "\n");
2778 		return (result);
2779 	}
2780 	return (ISC_R_UNEXPECTED);
2781 }
2782 
2783 isc_result_t
dns_message_buildopt(dns_message_t * message,dns_rdataset_t ** rdatasetp,unsigned int version,uint16_t udpsize,unsigned int flags,dns_ednsopt_t * ednsopts,size_t count)2784 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
2785 		     unsigned int version, uint16_t udpsize,
2786 		     unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
2787 {
2788 	dns_rdataset_t *rdataset = NULL;
2789 	dns_rdatalist_t *rdatalist = NULL;
2790 	dns_rdata_t *rdata = NULL;
2791 	isc_result_t result;
2792 	unsigned int len = 0, i;
2793 
2794 	REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
2795 
2796 	result = dns_message_gettemprdatalist(message, &rdatalist);
2797 	if (result != ISC_R_SUCCESS)
2798 		return (result);
2799 	result = dns_message_gettemprdata(message, &rdata);
2800 	if (result != ISC_R_SUCCESS)
2801 		goto cleanup;
2802 	result = dns_message_gettemprdataset(message, &rdataset);
2803 	if (result != ISC_R_SUCCESS)
2804 		goto cleanup;
2805 
2806 	rdatalist->type = dns_rdatatype_opt;
2807 
2808 	/*
2809 	 * Set Maximum UDP buffer size.
2810 	 */
2811 	rdatalist->rdclass = udpsize;
2812 
2813 	/*
2814 	 * Set EXTENDED-RCODE and Z to 0.
2815 	 */
2816 	rdatalist->ttl = (version << 16);
2817 	rdatalist->ttl |= (flags & 0xffff);
2818 
2819 	/*
2820 	 * Set EDNS options if applicable
2821 	 */
2822 	if (count != 0U) {
2823 		isc_buffer_t *buf = NULL;
2824 		for (i = 0; i < count; i++)
2825 			len += ednsopts[i].length + 4;
2826 
2827 		if (len > 0xffffU) {
2828 			result = ISC_R_NOSPACE;
2829 			goto cleanup;
2830 		}
2831 
2832 		result = isc_buffer_allocate(&buf, len);
2833 		if (result != ISC_R_SUCCESS)
2834 			goto cleanup;
2835 
2836 		for (i = 0; i < count; i++)  {
2837 			isc_buffer_putuint16(buf, ednsopts[i].code);
2838 			isc_buffer_putuint16(buf, ednsopts[i].length);
2839 			if (ednsopts[i].length != 0) {
2840 				isc_buffer_putmem(buf, ednsopts[i].value,
2841 						  ednsopts[i].length);
2842 			}
2843 		}
2844 		rdata->data = isc_buffer_base(buf);
2845 		rdata->length = len;
2846 		dns_message_takebuffer(message, &buf);
2847 	} else {
2848 		rdata->data = NULL;
2849 		rdata->length = 0;
2850 	}
2851 
2852 	rdata->rdclass = rdatalist->rdclass;
2853 	rdata->type = rdatalist->type;
2854 	rdata->flags = 0;
2855 
2856 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
2857 	result = dns_rdatalist_tordataset(rdatalist, rdataset);
2858 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2859 
2860 	*rdatasetp = rdataset;
2861 	return (ISC_R_SUCCESS);
2862 
2863  cleanup:
2864 	if (rdata != NULL)
2865 		dns_message_puttemprdata(message, &rdata);
2866 	if (rdataset != NULL)
2867 		dns_message_puttemprdataset(message, &rdataset);
2868 	if (rdatalist != NULL)
2869 		dns_message_puttemprdatalist(message, &rdatalist);
2870 	return (result);
2871 }
2872