1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 /*! \file */
13 
14 /***
15  *** Imports
16  ***/
17 
18 #include <config.h>
19 #include <ctype.h>
20 #include <inttypes.h>
21 #include <stdbool.h>
22 
23 #include <isc/buffer.h>
24 #include <isc/mem.h>
25 #include <isc/print.h>
26 #include <isc/refcount.h>
27 #include <isc/string.h> /* Required for HP/UX (and others?) */
28 #include <isc/utf8.h>
29 #include <isc/util.h>
30 
31 #include <dns/dnssec.h>
32 #include <dns/keyvalues.h>
33 #include <dns/log.h>
34 #include <dns/masterdump.h>
35 #include <dns/message.h>
36 #include <dns/opcode.h>
37 #include <dns/rcode.h>
38 #include <dns/rdata.h>
39 #include <dns/rdatalist.h>
40 #include <dns/rdataset.h>
41 #include <dns/rdatastruct.h>
42 #include <dns/result.h>
43 #include <dns/tsig.h>
44 #include <dns/ttl.h>
45 #include <dns/view.h>
46 
47 #ifdef SKAN_MSG_DEBUG
48 static void
hexdump(const char * msg,const char * msg2,void * base,size_t len)49 hexdump(const char *msg, const char *msg2, void *base, size_t len) {
50 	unsigned char *p;
51 	unsigned int cnt;
52 
53 	p = base;
54 	cnt = 0;
55 
56 	printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, (unsigned)len, base);
57 
58 	while (cnt < len) {
59 		if (cnt % 16 == 0)
60 			printf("%p: ", p);
61 		else if (cnt % 8 == 0)
62 			printf(" |");
63 		printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
64 		p++;
65 		cnt++;
66 
67 		if (cnt % 16 == 0)
68 			printf("\n");
69 	}
70 
71 	if (cnt % 16 != 0)
72 		printf("\n");
73 }
74 #endif
75 
76 #define DNS_MESSAGE_OPCODE_MASK		0x7800U
77 #define DNS_MESSAGE_OPCODE_SHIFT	11
78 #define DNS_MESSAGE_RCODE_MASK		0x000fU
79 #define DNS_MESSAGE_FLAG_MASK		0x8ff0U
80 #define DNS_MESSAGE_EDNSRCODE_MASK	0xff000000U
81 #define DNS_MESSAGE_EDNSRCODE_SHIFT	24
82 #define DNS_MESSAGE_EDNSVERSION_MASK	0x00ff0000U
83 #define DNS_MESSAGE_EDNSVERSION_SHIFT	16
84 
85 #define VALID_NAMED_SECTION(s)  (((s) > DNS_SECTION_ANY) \
86 				 && ((s) < DNS_SECTION_MAX))
87 #define VALID_SECTION(s)	(((s) >= DNS_SECTION_ANY) \
88 				 && ((s) < DNS_SECTION_MAX))
89 #define ADD_STRING(b, s)	{if (strlen(s) >= \
90 				   isc_buffer_availablelength(b)) { \
91 				       result = ISC_R_NOSPACE; \
92 				       goto cleanup; \
93 				 } 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		 64
107 #define OFFSET_COUNT		  4
108 #define RDATA_COUNT		  8
109 #define RDATALIST_COUNT		  8
110 #define RDATASET_COUNT	         64
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 static const char *edetext[] = { "Other",
150 				 "Unsupported DNSKEY Algorithm",
151 				 "Unsupported DS Digest Type",
152 				 "Stale Answer",
153 				 "Forged Answer",
154 				 "DNSSEC Indeterminate",
155 				 "DNSSEC Bogus",
156 				 "Signature Expired",
157 				 "Signature Not Yet Valid",
158 				 "DNSKEY Missing",
159 				 "RRSIGs Missing",
160 				 "No Zone Key Bit Set",
161 				 "NSEC Missing",
162 				 "Cached Error",
163 				 "Not Ready",
164 				 "Blocked",
165 				 "Censored",
166 				 "Filtered",
167 				 "Prohibited",
168 				 "Stale NXDOMAIN Answer",
169 				 "Not Authoritative",
170 				 "Not Supported",
171 				 "No Reachable Authority",
172 				 "Network Error",
173 				 "Invalid Data" };
174 
175 /*%
176  * "helper" type, which consists of a block of some type, and is linkable.
177  * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
178  * size, or the allocated elements will not be aligned correctly.
179  */
180 struct dns_msgblock {
181 	unsigned int			count;
182 	unsigned int			remaining;
183 	ISC_LINK(dns_msgblock_t)	link;
184 }; /* dynamically sized */
185 
186 static inline dns_msgblock_t *
187 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
188 
189 #define msgblock_get(block, type) \
190 	((type *)msgblock_internalget(block, sizeof(type)))
191 
192 static inline void *
193 msgblock_internalget(dns_msgblock_t *, unsigned int);
194 
195 static inline void
196 msgblock_reset(dns_msgblock_t *);
197 
198 static inline void
199 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
200 
201 static void
202 logfmtpacket(dns_message_t *message, const char *description,
203 	     isc_sockaddr_t *address, isc_logcategory_t *category,
204 	     isc_logmodule_t *module, const dns_master_style_t *style,
205 	     int level, isc_mem_t *mctx);
206 
207 /*
208  * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
209  * is free, return NULL.
210  */
211 static inline dns_msgblock_t *
msgblock_allocate(isc_mem_t * mctx,unsigned int sizeof_type,unsigned int count)212 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
213 		  unsigned int count)
214 {
215 	dns_msgblock_t *block;
216 	unsigned int length;
217 
218 	length = sizeof(dns_msgblock_t) + (sizeof_type * count);
219 
220 	block = isc_mem_get(mctx, length);
221 	if (block == NULL)
222 		return (NULL);
223 
224 	block->count = count;
225 	block->remaining = count;
226 
227 	ISC_LINK_INIT(block, link);
228 
229 	return (block);
230 }
231 
232 /*
233  * Return an element from the msgblock.  If no more are available, return
234  * NULL.
235  */
236 static inline void *
msgblock_internalget(dns_msgblock_t * block,unsigned int sizeof_type)237 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
238 	void *ptr;
239 
240 	if (block == NULL || block->remaining == 0)
241 		return (NULL);
242 
243 	block->remaining--;
244 
245 	ptr = (((unsigned char *)block)
246 	       + sizeof(dns_msgblock_t)
247 	       + (sizeof_type * block->remaining));
248 
249 	return (ptr);
250 }
251 
252 static inline void
msgblock_reset(dns_msgblock_t * block)253 msgblock_reset(dns_msgblock_t *block) {
254 	block->remaining = block->count;
255 }
256 
257 /*
258  * Release memory associated with a message block.
259  */
260 static inline void
msgblock_free(isc_mem_t * mctx,dns_msgblock_t * block,unsigned int sizeof_type)261 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
262 {
263 	unsigned int length;
264 
265 	length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
266 
267 	isc_mem_put(mctx, block, length);
268 }
269 
270 /*
271  * Allocate a new dynamic buffer, and attach it to this message as the
272  * "current" buffer.  (which is always the last on the list, for our
273  * uses)
274  */
275 static inline isc_result_t
newbuffer(dns_message_t * msg,unsigned int size)276 newbuffer(dns_message_t *msg, unsigned int size) {
277 	isc_result_t result;
278 	isc_buffer_t *dynbuf;
279 
280 	dynbuf = NULL;
281 	result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
282 	if (result != ISC_R_SUCCESS)
283 		return (ISC_R_NOMEMORY);
284 
285 	ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
286 	return (ISC_R_SUCCESS);
287 }
288 
289 static inline isc_buffer_t *
currentbuffer(dns_message_t * msg)290 currentbuffer(dns_message_t *msg) {
291 	isc_buffer_t *dynbuf;
292 
293 	dynbuf = ISC_LIST_TAIL(msg->scratchpad);
294 	INSIST(dynbuf != NULL);
295 
296 	return (dynbuf);
297 }
298 
299 static inline void
releaserdata(dns_message_t * msg,dns_rdata_t * rdata)300 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
301 	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
302 }
303 
304 static inline dns_rdata_t *
newrdata(dns_message_t * msg)305 newrdata(dns_message_t *msg) {
306 	dns_msgblock_t *msgblock;
307 	dns_rdata_t *rdata;
308 
309 	rdata = ISC_LIST_HEAD(msg->freerdata);
310 	if (rdata != NULL) {
311 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
312 		return (rdata);
313 	}
314 
315 	msgblock = ISC_LIST_TAIL(msg->rdatas);
316 	rdata = msgblock_get(msgblock, dns_rdata_t);
317 	if (rdata == NULL) {
318 		msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
319 					     RDATA_COUNT);
320 		if (msgblock == NULL)
321 			return (NULL);
322 
323 		ISC_LIST_APPEND(msg->rdatas, msgblock, link);
324 
325 		rdata = msgblock_get(msgblock, dns_rdata_t);
326 	}
327 
328 	dns_rdata_init(rdata);
329 	return (rdata);
330 }
331 
332 static inline void
releaserdatalist(dns_message_t * msg,dns_rdatalist_t * rdatalist)333 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
334 	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
335 }
336 
337 static inline dns_rdatalist_t *
newrdatalist(dns_message_t * msg)338 newrdatalist(dns_message_t *msg) {
339 	dns_msgblock_t *msgblock;
340 	dns_rdatalist_t *rdatalist;
341 
342 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
343 	if (rdatalist != NULL) {
344 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
345 		goto out;
346 	}
347 
348 	msgblock = ISC_LIST_TAIL(msg->rdatalists);
349 	rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
350 	if (rdatalist == NULL) {
351 		msgblock = msgblock_allocate(msg->mctx,
352 					     sizeof(dns_rdatalist_t),
353 					     RDATALIST_COUNT);
354 		if (msgblock == NULL)
355 			return (NULL);
356 
357 		ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
358 
359 		rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
360 	}
361  out:
362 	if (rdatalist != NULL)
363 		dns_rdatalist_init(rdatalist);
364 
365 	return (rdatalist);
366 }
367 
368 static inline dns_offsets_t *
newoffsets(dns_message_t * msg)369 newoffsets(dns_message_t *msg) {
370 	dns_msgblock_t *msgblock;
371 	dns_offsets_t *offsets;
372 
373 	msgblock = ISC_LIST_TAIL(msg->offsets);
374 	offsets = msgblock_get(msgblock, dns_offsets_t);
375 	if (offsets == NULL) {
376 		msgblock = msgblock_allocate(msg->mctx,
377 					     sizeof(dns_offsets_t),
378 					     OFFSET_COUNT);
379 		if (msgblock == NULL)
380 			return (NULL);
381 
382 		ISC_LIST_APPEND(msg->offsets, msgblock, link);
383 
384 		offsets = msgblock_get(msgblock, dns_offsets_t);
385 	}
386 
387 	return (offsets);
388 }
389 
390 static inline void
msginitheader(dns_message_t * m)391 msginitheader(dns_message_t *m) {
392 	m->id = 0;
393 	m->flags = 0;
394 	m->rcode = 0;
395 	m->opcode = 0;
396 	m->rdclass = 0;
397 }
398 
399 static inline void
msginitprivate(dns_message_t * m)400 msginitprivate(dns_message_t *m) {
401 	unsigned int i;
402 
403 	for (i = 0; i < DNS_SECTION_MAX; i++) {
404 		m->cursors[i] = NULL;
405 		m->counts[i] = 0;
406 	}
407 	m->opt = NULL;
408 	m->sig0 = NULL;
409 	m->sig0name = NULL;
410 	m->tsig = NULL;
411 	m->tsigname = NULL;
412 	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
413 	m->opt_reserved = 0;
414 	m->sig_reserved = 0;
415 	m->reserved = 0;
416 	m->buffer = NULL;
417 }
418 
419 static inline void
msginittsig(dns_message_t * m)420 msginittsig(dns_message_t *m) {
421 	m->tsigstatus = dns_rcode_noerror;
422 	m->querytsigstatus = dns_rcode_noerror;
423 	m->tsigkey = NULL;
424 	m->tsigctx = NULL;
425 	m->sigstart = -1;
426 	m->sig0key = NULL;
427 	m->sig0status = dns_rcode_noerror;
428 	m->timeadjust = 0;
429 }
430 
431 /*
432  * Init elements to default state.  Used both when allocating a new element
433  * and when resetting one.
434  */
435 static inline void
msginit(dns_message_t * m)436 msginit(dns_message_t *m) {
437 	msginitheader(m);
438 	msginitprivate(m);
439 	msginittsig(m);
440 	m->header_ok = 0;
441 	m->question_ok = 0;
442 	m->tcp_continuation = 0;
443 	m->verified_sig = 0;
444 	m->verify_attempted = 0;
445 	m->order = NULL;
446 	m->order_arg = NULL;
447 	m->query.base = NULL;
448 	m->query.length = 0;
449 	m->free_query = 0;
450 	m->saved.base = NULL;
451 	m->saved.length = 0;
452 	m->free_saved = 0;
453 	m->cc_ok = 0;
454 	m->cc_bad = 0;
455 	m->tkey = 0;
456 	m->rdclass_set = 0;
457 	m->querytsig = NULL;
458 	m->indent.string = dns_master_indentstr;
459 	m->indent.count = dns_master_indent;
460 }
461 
462 static inline void
msgresetnames(dns_message_t * msg,unsigned int first_section)463 msgresetnames(dns_message_t *msg, unsigned int first_section) {
464 	unsigned int i;
465 	dns_name_t *name, *next_name;
466 	dns_rdataset_t *rds, *next_rds;
467 
468 	/*
469 	 * Clean up name lists by calling the rdataset disassociate function.
470 	 */
471 	for (i = first_section; i < DNS_SECTION_MAX; i++) {
472 		name = ISC_LIST_HEAD(msg->sections[i]);
473 		while (name != NULL) {
474 			next_name = ISC_LIST_NEXT(name, link);
475 			ISC_LIST_UNLINK(msg->sections[i], name, link);
476 
477 			rds = ISC_LIST_HEAD(name->list);
478 			while (rds != NULL) {
479 				next_rds = ISC_LIST_NEXT(rds, link);
480 				ISC_LIST_UNLINK(name->list, rds, link);
481 
482 				INSIST(dns_rdataset_isassociated(rds));
483 				dns_rdataset_disassociate(rds);
484 				isc_mempool_put(msg->rdspool, rds);
485 				rds = next_rds;
486 			}
487 			if (dns_name_dynamic(name))
488 				dns_name_free(name, msg->mctx);
489 			isc_mempool_put(msg->namepool, name);
490 			name = next_name;
491 		}
492 	}
493 }
494 
495 static void
msgresetopt(dns_message_t * msg)496 msgresetopt(dns_message_t *msg)
497 {
498 	if (msg->opt != NULL) {
499 		if (msg->opt_reserved > 0) {
500 			dns_message_renderrelease(msg, msg->opt_reserved);
501 			msg->opt_reserved = 0;
502 		}
503 		INSIST(dns_rdataset_isassociated(msg->opt));
504 		dns_rdataset_disassociate(msg->opt);
505 		isc_mempool_put(msg->rdspool, msg->opt);
506 		msg->opt = NULL;
507 		msg->cc_ok = 0;
508 		msg->cc_bad = 0;
509 	}
510 }
511 
512 static void
msgresetsigs(dns_message_t * msg,bool replying)513 msgresetsigs(dns_message_t *msg, bool replying) {
514 	if (msg->sig_reserved > 0) {
515 		dns_message_renderrelease(msg, msg->sig_reserved);
516 		msg->sig_reserved = 0;
517 	}
518 	if (msg->tsig != NULL) {
519 		INSIST(dns_rdataset_isassociated(msg->tsig));
520 		INSIST(msg->namepool != NULL);
521 		if (replying) {
522 			INSIST(msg->querytsig == NULL);
523 			msg->querytsig = msg->tsig;
524 		} else {
525 			dns_rdataset_disassociate(msg->tsig);
526 			isc_mempool_put(msg->rdspool, msg->tsig);
527 			if (msg->querytsig != NULL) {
528 				dns_rdataset_disassociate(msg->querytsig);
529 				isc_mempool_put(msg->rdspool, msg->querytsig);
530 			}
531 		}
532 		if (dns_name_dynamic(msg->tsigname))
533 			dns_name_free(msg->tsigname, msg->mctx);
534 		isc_mempool_put(msg->namepool, msg->tsigname);
535 		msg->tsig = NULL;
536 		msg->tsigname = NULL;
537 	} else if (msg->querytsig != NULL && !replying) {
538 		dns_rdataset_disassociate(msg->querytsig);
539 		isc_mempool_put(msg->rdspool, msg->querytsig);
540 		msg->querytsig = NULL;
541 	}
542 	if (msg->sig0 != NULL) {
543 		INSIST(dns_rdataset_isassociated(msg->sig0));
544 		dns_rdataset_disassociate(msg->sig0);
545 		isc_mempool_put(msg->rdspool, msg->sig0);
546 		if (msg->sig0name != NULL) {
547 			if (dns_name_dynamic(msg->sig0name))
548 				dns_name_free(msg->sig0name, msg->mctx);
549 			isc_mempool_put(msg->namepool, msg->sig0name);
550 		}
551 		msg->sig0 = NULL;
552 		msg->sig0name = NULL;
553 	}
554 }
555 
556 /*
557  * Free all but one (or everything) for this message.  This is used by
558  * both dns_message_reset() and dns__message_destroy().
559  */
560 static void
msgreset(dns_message_t * msg,bool everything)561 msgreset(dns_message_t *msg, bool everything) {
562 	dns_msgblock_t *msgblock, *next_msgblock;
563 	isc_buffer_t *dynbuf, *next_dynbuf;
564 	dns_rdata_t *rdata;
565 	dns_rdatalist_t *rdatalist;
566 
567 	msgresetnames(msg, 0);
568 	msgresetopt(msg);
569 	msgresetsigs(msg, false);
570 
571 	/*
572 	 * Clean up linked lists.
573 	 */
574 
575 	/*
576 	 * Run through the free lists, and just unlink anything found there.
577 	 * The memory isn't lost since these are part of message blocks we
578 	 * have allocated.
579 	 */
580 	rdata = ISC_LIST_HEAD(msg->freerdata);
581 	while (rdata != NULL) {
582 		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
583 		rdata = ISC_LIST_HEAD(msg->freerdata);
584 	}
585 	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
586 	while (rdatalist != NULL) {
587 		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
588 		rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
589 	}
590 
591 	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
592 	INSIST(dynbuf != NULL);
593 	if (!everything) {
594 		isc_buffer_clear(dynbuf);
595 		dynbuf = ISC_LIST_NEXT(dynbuf, link);
596 	}
597 	while (dynbuf != NULL) {
598 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
599 		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
600 		isc_buffer_free(&dynbuf);
601 		dynbuf = next_dynbuf;
602 	}
603 
604 	msgblock = ISC_LIST_HEAD(msg->rdatas);
605 	if (!everything && msgblock != NULL) {
606 		msgblock_reset(msgblock);
607 		msgblock = ISC_LIST_NEXT(msgblock, link);
608 	}
609 	while (msgblock != NULL) {
610 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
611 		ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
612 		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
613 		msgblock = next_msgblock;
614 	}
615 
616 	/*
617 	 * rdatalists could be empty.
618 	 */
619 
620 	msgblock = ISC_LIST_HEAD(msg->rdatalists);
621 	if (!everything && msgblock != NULL) {
622 		msgblock_reset(msgblock);
623 		msgblock = ISC_LIST_NEXT(msgblock, link);
624 	}
625 	while (msgblock != NULL) {
626 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
627 		ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
628 		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
629 		msgblock = next_msgblock;
630 	}
631 
632 	msgblock = ISC_LIST_HEAD(msg->offsets);
633 	if (!everything && msgblock != NULL) {
634 		msgblock_reset(msgblock);
635 		msgblock = ISC_LIST_NEXT(msgblock, link);
636 	}
637 	while (msgblock != NULL) {
638 		next_msgblock = ISC_LIST_NEXT(msgblock, link);
639 		ISC_LIST_UNLINK(msg->offsets, msgblock, link);
640 		msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
641 		msgblock = next_msgblock;
642 	}
643 
644 	if (msg->tsigkey != NULL) {
645 		dns_tsigkey_detach(&msg->tsigkey);
646 		msg->tsigkey = NULL;
647 	}
648 
649 	if (msg->tsigctx != NULL)
650 		dst_context_destroy(&msg->tsigctx);
651 
652 	if (msg->query.base != NULL) {
653 		if (msg->free_query != 0)
654 			isc_mem_put(msg->mctx, msg->query.base,
655 				    msg->query.length);
656 		msg->query.base = NULL;
657 		msg->query.length = 0;
658 	}
659 
660 	if (msg->saved.base != NULL) {
661 		if (msg->free_saved != 0)
662 			isc_mem_put(msg->mctx, msg->saved.base,
663 				    msg->saved.length);
664 		msg->saved.base = NULL;
665 		msg->saved.length = 0;
666 	}
667 
668 	/*
669 	 * cleanup the buffer cleanup list
670 	 */
671 	dynbuf = ISC_LIST_HEAD(msg->cleanup);
672 	while (dynbuf != NULL) {
673 		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
674 		ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
675 		isc_buffer_free(&dynbuf);
676 		dynbuf = next_dynbuf;
677 	}
678 
679 	/*
680 	 * Set other bits to normal default values.
681 	 */
682 	if (!everything)
683 		msginit(msg);
684 
685 	ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
686 	ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
687 }
688 
689 static unsigned int
spacefortsig(dns_tsigkey_t * key,int otherlen)690 spacefortsig(dns_tsigkey_t *key, int otherlen) {
691 	isc_region_t r1, r2;
692 	unsigned int x;
693 	isc_result_t result;
694 
695 	/*
696 	 * The space required for an TSIG record is:
697 	 *
698 	 *	n1 bytes for the name
699 	 *	2 bytes for the type
700 	 *	2 bytes for the class
701 	 *	4 bytes for the ttl
702 	 *	2 bytes for the rdlength
703 	 *	n2 bytes for the algorithm name
704 	 *	6 bytes for the time signed
705 	 *	2 bytes for the fudge
706 	 *	2 bytes for the MAC size
707 	 *	x bytes for the MAC
708 	 *	2 bytes for the original id
709 	 *	2 bytes for the error
710 	 *	2 bytes for the other data length
711 	 *	y bytes for the other data (at most)
712 	 * ---------------------------------
713 	 *     26 + n1 + n2 + x + y bytes
714 	 */
715 
716 	dns_name_toregion(&key->name, &r1);
717 	dns_name_toregion(key->algorithm, &r2);
718 	if (key->key == NULL)
719 		x = 0;
720 	else {
721 		result = dst_key_sigsize(key->key, &x);
722 		if (result != ISC_R_SUCCESS)
723 			x = 0;
724 	}
725 	return (26 + r1.length + r2.length + x + otherlen);
726 }
727 
728 isc_result_t
dns_message_create(isc_mem_t * mctx,unsigned int intent,dns_message_t ** msgp)729 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
730 {
731 	dns_message_t *m;
732 	isc_result_t result;
733 	isc_buffer_t *dynbuf;
734 	unsigned int i;
735 
736 	REQUIRE(mctx != NULL);
737 	REQUIRE(msgp != NULL);
738 	REQUIRE(*msgp == NULL);
739 	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
740 		|| intent == DNS_MESSAGE_INTENTRENDER);
741 
742 	m = isc_mem_get(mctx, sizeof(dns_message_t));
743 	if (m == NULL)
744 		return (ISC_R_NOMEMORY);
745 
746 	/*
747 	 * No allocations until further notice.  Just initialize all lists
748 	 * and other members that are freed in the cleanup phase here.
749 	 */
750 
751 	m->magic = DNS_MESSAGE_MAGIC;
752 	m->from_to_wire = intent;
753 	msginit(m);
754 
755 	for (i = 0; i < DNS_SECTION_MAX; i++)
756 		ISC_LIST_INIT(m->sections[i]);
757 
758 	m->mctx = NULL;
759 	isc_mem_attach(mctx, &m->mctx);
760 
761 	ISC_LIST_INIT(m->scratchpad);
762 	ISC_LIST_INIT(m->cleanup);
763 	m->namepool = NULL;
764 	m->rdspool = NULL;
765 	ISC_LIST_INIT(m->rdatas);
766 	ISC_LIST_INIT(m->rdatalists);
767 	ISC_LIST_INIT(m->offsets);
768 	ISC_LIST_INIT(m->freerdata);
769 	ISC_LIST_INIT(m->freerdatalist);
770 
771 	/*
772 	 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
773 	 */
774 
775 	result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
776 	if (result != ISC_R_SUCCESS)
777 		goto cleanup;
778 	isc_mempool_setfillcount(m->namepool, NAME_COUNT);
779 	isc_mempool_setfreemax(m->namepool, NAME_COUNT);
780 	isc_mempool_setname(m->namepool, "msg:names");
781 
782 	result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
783 				    &m->rdspool);
784 	if (result != ISC_R_SUCCESS)
785 		goto cleanup;
786 	isc_mempool_setfillcount(m->rdspool, RDATASET_COUNT);
787 	isc_mempool_setfreemax(m->rdspool, RDATASET_COUNT);
788 	isc_mempool_setname(m->rdspool, "msg:rdataset");
789 
790 	dynbuf = NULL;
791 	result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
792 	if (result != ISC_R_SUCCESS)
793 		goto cleanup;
794 	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
795 
796 	m->cctx = NULL;
797 
798 	isc_refcount_init(&m->refcount, 1);
799 
800 	*msgp = m;
801 	return (ISC_R_SUCCESS);
802 
803 	/*
804 	 * Cleanup for error returns.
805 	 */
806  cleanup:
807 	dynbuf = ISC_LIST_HEAD(m->scratchpad);
808 	if (dynbuf != NULL) {
809 		ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
810 		isc_buffer_free(&dynbuf);
811 	}
812 	if (m->namepool != NULL)
813 		isc_mempool_destroy(&m->namepool);
814 	if (m->rdspool != NULL)
815 		isc_mempool_destroy(&m->rdspool);
816 	m->magic = 0;
817 	isc_mem_putanddetach(&mctx, m, sizeof(dns_message_t));
818 
819 	return (ISC_R_NOMEMORY);
820 }
821 
822 void
dns_message_reset(dns_message_t * msg,unsigned int intent)823 dns_message_reset(dns_message_t *msg, unsigned int intent) {
824 	REQUIRE(DNS_MESSAGE_VALID(msg));
825 	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
826 		|| intent == DNS_MESSAGE_INTENTRENDER);
827 
828 	msgreset(msg, false);
829 	msg->from_to_wire = intent;
830 }
831 
832 static void
dns__message_destroy(dns_message_t * msg)833 dns__message_destroy(dns_message_t *msg) {
834 	REQUIRE(msg != NULL);
835 	REQUIRE(DNS_MESSAGE_VALID(msg));
836 
837 	msgreset(msg, true);
838 	isc_mempool_destroy(&msg->namepool);
839 	isc_mempool_destroy(&msg->rdspool);
840 	isc_refcount_destroy(&msg->refcount);
841 	msg->magic = 0;
842 	isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
843 }
844 
845 void
dns_message_attach(dns_message_t * source,dns_message_t ** target)846 dns_message_attach(dns_message_t *source, dns_message_t **target) {
847 	REQUIRE(DNS_MESSAGE_VALID(source));
848 
849 	isc_refcount_increment(&source->refcount, NULL);
850 	*target = source;
851 }
852 
853 void
dns_message_detach(dns_message_t ** messagep)854 dns_message_detach(dns_message_t **messagep) {
855 	REQUIRE(messagep != NULL && DNS_MESSAGE_VALID(*messagep));
856 	dns_message_t *msg = *messagep;
857 	*messagep = NULL;
858 	int32_t refs;
859 
860 	isc_refcount_decrement(&msg->refcount, &refs);
861 	if (refs == 0) {
862 		dns__message_destroy(msg);
863 	}
864 }
865 
866 static isc_result_t
findname(dns_name_t ** foundname,dns_name_t * target,dns_namelist_t * section)867 findname(dns_name_t **foundname, dns_name_t *target,
868 	 dns_namelist_t *section)
869 {
870 	dns_name_t *curr;
871 
872 	for (curr = ISC_LIST_TAIL(*section);
873 	     curr != NULL;
874 	     curr = ISC_LIST_PREV(curr, link)) {
875 		if (dns_name_equal(curr, target)) {
876 			if (foundname != NULL)
877 				*foundname = curr;
878 			return (ISC_R_SUCCESS);
879 		}
880 	}
881 
882 	return (ISC_R_NOTFOUND);
883 }
884 
885 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)886 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
887 		 dns_rdatatype_t type, dns_rdatatype_t covers,
888 		 dns_rdataset_t **rdataset)
889 {
890 	dns_rdataset_t *curr;
891 
892 	REQUIRE(name != NULL);
893 	REQUIRE(rdataset == NULL || *rdataset == NULL);
894 
895 	for (curr = ISC_LIST_TAIL(name->list);
896 	     curr != NULL;
897 	     curr = ISC_LIST_PREV(curr, link)) {
898 		if (curr->rdclass == rdclass &&
899 		    curr->type == type && curr->covers == covers) {
900 			if (rdataset != NULL)
901 				*rdataset = curr;
902 			return (ISC_R_SUCCESS);
903 		}
904 	}
905 
906 	return (ISC_R_NOTFOUND);
907 }
908 
909 isc_result_t
dns_message_findtype(dns_name_t * name,dns_rdatatype_t type,dns_rdatatype_t covers,dns_rdataset_t ** rdataset)910 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
911 		     dns_rdatatype_t covers, dns_rdataset_t **rdataset)
912 {
913 	dns_rdataset_t *curr;
914 
915 	REQUIRE(name != NULL);
916 	REQUIRE(rdataset == NULL || *rdataset == NULL);
917 
918 	for (curr = ISC_LIST_TAIL(name->list);
919 	     curr != NULL;
920 	     curr = ISC_LIST_PREV(curr, link)) {
921 		if (curr->type == type && curr->covers == covers) {
922 			if (ISC_UNLIKELY(rdataset != NULL))
923 				*rdataset = curr;
924 			return (ISC_R_SUCCESS);
925 		}
926 	}
927 
928 	return (ISC_R_NOTFOUND);
929 }
930 
931 /*
932  * Read a name from buffer "source".
933  */
934 static isc_result_t
getname(dns_name_t * name,isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx)935 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
936 	dns_decompress_t *dctx)
937 {
938 	isc_buffer_t *scratch;
939 	isc_result_t result;
940 	unsigned int tries;
941 
942 	scratch = currentbuffer(msg);
943 
944 	/*
945 	 * First try:  use current buffer.
946 	 * Second try:  allocate a new buffer and use that.
947 	 */
948 	tries = 0;
949 	while (tries < 2) {
950 		result = dns_name_fromwire(name, source, dctx, 0,
951 					   scratch);
952 
953 		if (result == ISC_R_NOSPACE) {
954 			tries++;
955 
956 			result = newbuffer(msg, SCRATCHPAD_SIZE);
957 			if (result != ISC_R_SUCCESS)
958 				return (result);
959 
960 			scratch = currentbuffer(msg);
961 			dns_name_reset(name);
962 		} else {
963 			return (result);
964 		}
965 	}
966 
967 	INSIST(0);
968 	ISC_UNREACHABLE();
969 }
970 
971 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)972 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
973 	 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
974 	 unsigned int rdatalen, dns_rdata_t *rdata)
975 {
976 	isc_buffer_t *scratch;
977 	isc_result_t result;
978 	unsigned int tries;
979 	unsigned int trysize;
980 
981 	scratch = currentbuffer(msg);
982 
983 	isc_buffer_setactive(source, rdatalen);
984 
985 	/*
986 	 * First try:  use current buffer.
987 	 * Second try:  allocate a new buffer of size
988 	 *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
989 	 *     (the data will fit if it was not more than 50% compressed)
990 	 * Subsequent tries: double buffer size on each try.
991 	 */
992 	tries = 0;
993 	trysize = 0;
994 	/* XXX possibly change this to a while (tries < 2) loop */
995 	for (;;) {
996 		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
997 					    source, dctx, 0,
998 					    scratch);
999 
1000 		if (result == ISC_R_NOSPACE) {
1001 			if (tries == 0) {
1002 				trysize = 2 * rdatalen;
1003 				if (trysize < SCRATCHPAD_SIZE)
1004 					trysize = SCRATCHPAD_SIZE;
1005 			} else {
1006 				INSIST(trysize != 0);
1007 				if (trysize >= 65535)
1008 					return (ISC_R_NOSPACE);
1009 					/* XXX DNS_R_RRTOOLONG? */
1010 				trysize *= 2;
1011 			}
1012 			tries++;
1013 			result = newbuffer(msg, trysize);
1014 			if (result != ISC_R_SUCCESS)
1015 				return (result);
1016 
1017 			scratch = currentbuffer(msg);
1018 		} else {
1019 			return (result);
1020 		}
1021 	}
1022 }
1023 
1024 #define DO_ERROR(r)					\
1025 	do {						\
1026 		if (best_effort)			\
1027 			seen_problem = true;	\
1028 		else {					\
1029 			result = r;			\
1030 			goto cleanup;			\
1031 		}					\
1032 	} while (0)
1033 
1034 static isc_result_t
getquestions(isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx,unsigned int options)1035 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1036 	     unsigned int options)
1037 {
1038 	isc_region_t r;
1039 	unsigned int count;
1040 	dns_name_t *name;
1041 	dns_name_t *name2;
1042 	dns_offsets_t *offsets;
1043 	dns_rdataset_t *rdataset;
1044 	dns_rdatalist_t *rdatalist;
1045 	isc_result_t result;
1046 	dns_rdatatype_t rdtype;
1047 	dns_rdataclass_t rdclass;
1048 	dns_namelist_t *section;
1049 	bool free_name;
1050 	bool best_effort;
1051 	bool seen_problem;
1052 
1053 	section = &msg->sections[DNS_SECTION_QUESTION];
1054 
1055 	best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
1056 	seen_problem = false;
1057 
1058 	name = NULL;
1059 	rdataset = NULL;
1060 	rdatalist = NULL;
1061 
1062 	for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1063 		name = isc_mempool_get(msg->namepool);
1064 		if (name == NULL)
1065 			return (ISC_R_NOMEMORY);
1066 		free_name = true;
1067 
1068 		offsets = newoffsets(msg);
1069 		if (offsets == NULL) {
1070 			result = ISC_R_NOMEMORY;
1071 			goto cleanup;
1072 		}
1073 		dns_name_init(name, *offsets);
1074 
1075 		/*
1076 		 * Parse the name out of this packet.
1077 		 */
1078 		isc_buffer_remainingregion(source, &r);
1079 		isc_buffer_setactive(source, r.length);
1080 		result = getname(name, source, msg, dctx);
1081 		if (result != ISC_R_SUCCESS)
1082 			goto cleanup;
1083 
1084 		/*
1085 		 * Run through the section, looking to see if this name
1086 		 * is already there.  If it is found, put back the allocated
1087 		 * name since we no longer need it, and set our name pointer
1088 		 * to point to the name we found.
1089 		 */
1090 		result = findname(&name2, name, section);
1091 
1092 		/*
1093 		 * If it is the first name in the section, accept it.
1094 		 *
1095 		 * If it is not, but is not the same as the name already
1096 		 * in the question section, append to the section.  Note that
1097 		 * here in the question section this is illegal, so return
1098 		 * FORMERR.  In the future, check the opcode to see if
1099 		 * this should be legal or not.  In either case we no longer
1100 		 * need this name pointer.
1101 		 */
1102 		if (result != ISC_R_SUCCESS) {
1103 			if (!ISC_LIST_EMPTY(*section))
1104 				DO_ERROR(DNS_R_FORMERR);
1105 			ISC_LIST_APPEND(*section, name, link);
1106 			free_name = false;
1107 		} else {
1108 			isc_mempool_put(msg->namepool, name);
1109 			name = name2;
1110 			name2 = NULL;
1111 			free_name = false;
1112 		}
1113 
1114 		/*
1115 		 * Get type and class.
1116 		 */
1117 		isc_buffer_remainingregion(source, &r);
1118 		if (r.length < 4) {
1119 			result = ISC_R_UNEXPECTEDEND;
1120 			goto cleanup;
1121 		}
1122 		rdtype = isc_buffer_getuint16(source);
1123 		rdclass = isc_buffer_getuint16(source);
1124 
1125 		/*
1126 		 * If this class is different than the one we already read,
1127 		 * this is an error.
1128 		 */
1129 		if (msg->rdclass_set == 0) {
1130 			msg->rdclass = rdclass;
1131 			msg->rdclass_set = 1;
1132 		} else if (msg->rdclass != rdclass)
1133 			DO_ERROR(DNS_R_FORMERR);
1134 
1135 		/*
1136 		 * Is this a TKEY query?
1137 		 */
1138 		if (rdtype == dns_rdatatype_tkey)
1139 			msg->tkey = 1;
1140 
1141 		/*
1142 		 * Can't ask the same question twice.
1143 		 */
1144 		result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1145 		if (result == ISC_R_SUCCESS)
1146 			DO_ERROR(DNS_R_FORMERR);
1147 
1148 		/*
1149 		 * Allocate a new rdatalist.
1150 		 */
1151 		rdatalist = newrdatalist(msg);
1152 		if (rdatalist == NULL) {
1153 			result = ISC_R_NOMEMORY;
1154 			goto cleanup;
1155 		}
1156 		rdataset =  isc_mempool_get(msg->rdspool);
1157 		if (rdataset == NULL) {
1158 			result = ISC_R_NOMEMORY;
1159 			goto cleanup;
1160 		}
1161 
1162 		/*
1163 		 * Convert rdatalist to rdataset, and attach the latter to
1164 		 * the name.
1165 		 */
1166 		rdatalist->type = rdtype;
1167 		rdatalist->rdclass = rdclass;
1168 
1169 		dns_rdataset_init(rdataset);
1170 		result = dns_rdatalist_tordataset(rdatalist, rdataset);
1171 		if (result != ISC_R_SUCCESS)
1172 			goto cleanup;
1173 
1174 		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1175 
1176 		ISC_LIST_APPEND(name->list, rdataset, link);
1177 		rdataset = NULL;
1178 	}
1179 
1180 	if (seen_problem)
1181 		return (DNS_R_RECOVERABLE);
1182 	return (ISC_R_SUCCESS);
1183 
1184  cleanup:
1185 	if (rdataset != NULL) {
1186 		INSIST(!dns_rdataset_isassociated(rdataset));
1187 		isc_mempool_put(msg->rdspool, rdataset);
1188 	}
1189 #if 0
1190 	if (rdatalist != NULL)
1191 		isc_mempool_put(msg->rdlpool, rdatalist);
1192 #endif
1193 	if (free_name)
1194 		isc_mempool_put(msg->namepool, name);
1195 
1196 	return (result);
1197 }
1198 
1199 static bool
update(dns_section_t section,dns_rdataclass_t rdclass)1200 update(dns_section_t section, dns_rdataclass_t rdclass) {
1201 	if (section == DNS_SECTION_PREREQUISITE)
1202 		return (rdclass == dns_rdataclass_any ||
1203 			 rdclass == dns_rdataclass_none);
1204 	if (section == DNS_SECTION_UPDATE)
1205 		return (rdclass == dns_rdataclass_any);
1206 	return (false);
1207 }
1208 
1209 /*
1210  * Check to confirm that all DNSSEC records (DS, NSEC, NSEC3) have
1211  * covering RRSIGs.
1212  */
1213 static bool
auth_signed(dns_namelist_t * section)1214 auth_signed(dns_namelist_t *section) {
1215 	dns_name_t *name;
1216 
1217 	for (name = ISC_LIST_HEAD(*section);
1218 	     name != NULL;
1219 	     name = ISC_LIST_NEXT(name, link))
1220 	{
1221 		int auth_dnssec = 0, auth_rrsig = 0;
1222 		dns_rdataset_t *rds;
1223 
1224 		for (rds = ISC_LIST_HEAD(name->list);
1225 		     rds != NULL;
1226 		     rds = ISC_LIST_NEXT(rds, link))
1227 		{
1228 			switch (rds->type) {
1229 			case dns_rdatatype_ds:
1230 				auth_dnssec |= 0x1;
1231 				break;
1232 			case dns_rdatatype_nsec:
1233 				auth_dnssec |= 0x2;
1234 				break;
1235 			case dns_rdatatype_nsec3:
1236 				auth_dnssec |= 0x4;
1237 				break;
1238 			case dns_rdatatype_rrsig:
1239 				break;
1240 			default:
1241 				continue;
1242 			}
1243 
1244 			switch (rds->covers) {
1245 			case dns_rdatatype_ds:
1246 				auth_rrsig |= 0x1;
1247 				break;
1248 			case dns_rdatatype_nsec:
1249 				auth_rrsig |= 0x2;
1250 				break;
1251 			case dns_rdatatype_nsec3:
1252 				auth_rrsig |= 0x4;
1253 				break;
1254 			default:
1255 				break;
1256 			}
1257 		}
1258 
1259 		if (auth_dnssec != auth_rrsig)
1260 			return (false);
1261 	}
1262 
1263 	return (true);
1264 }
1265 
1266 static isc_result_t
getsection(isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx,dns_section_t sectionid,unsigned int options)1267 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1268 	   dns_section_t sectionid, unsigned int options)
1269 {
1270 	isc_region_t r;
1271 	unsigned int count, rdatalen;
1272 	dns_name_t *name = NULL;
1273 	dns_name_t *name2 = NULL;
1274 	dns_offsets_t *offsets;
1275 	dns_rdataset_t *rdataset;
1276 	dns_rdatalist_t *rdatalist;
1277 	isc_result_t result;
1278 	dns_rdatatype_t rdtype, covers;
1279 	dns_rdataclass_t rdclass;
1280 	dns_rdata_t *rdata;
1281 	dns_ttl_t ttl;
1282 	dns_namelist_t *section;
1283 	bool free_name = false, free_rdataset = false;
1284 	bool preserve_order, best_effort, seen_problem;
1285 	bool isedns, issigzero, istsig;
1286 
1287 	preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0);
1288 	best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
1289 	seen_problem = false;
1290 
1291 	section = &msg->sections[sectionid];
1292 
1293 	for (count = 0; count < msg->counts[sectionid]; count++) {
1294 		int recstart = source->current;
1295 		bool skip_name_search, skip_type_search;
1296 
1297 		skip_name_search = false;
1298 		skip_type_search = false;
1299 		free_rdataset = false;
1300 		isedns = false;
1301 		issigzero = false;
1302 		istsig = false;
1303 
1304 		name = isc_mempool_get(msg->namepool);
1305 		if (name == NULL)
1306 			return (ISC_R_NOMEMORY);
1307 		free_name = true;
1308 
1309 		offsets = newoffsets(msg);
1310 		if (offsets == NULL) {
1311 			result = ISC_R_NOMEMORY;
1312 			goto cleanup;
1313 		}
1314 		dns_name_init(name, *offsets);
1315 
1316 		/*
1317 		 * Parse the name out of this packet.
1318 		 */
1319 		isc_buffer_remainingregion(source, &r);
1320 		isc_buffer_setactive(source, r.length);
1321 		result = getname(name, source, msg, dctx);
1322 		if (result != ISC_R_SUCCESS)
1323 			goto cleanup;
1324 
1325 		/*
1326 		 * Get type, class, ttl, and rdatalen.  Verify that at least
1327 		 * rdatalen bytes remain.  (Some of this is deferred to
1328 		 * later.)
1329 		 */
1330 		isc_buffer_remainingregion(source, &r);
1331 		if (r.length < 2 + 2 + 4 + 2) {
1332 			result = ISC_R_UNEXPECTEDEND;
1333 			goto cleanup;
1334 		}
1335 		rdtype = isc_buffer_getuint16(source);
1336 		rdclass = isc_buffer_getuint16(source);
1337 
1338 		/*
1339 		 * If there was no question section, we may not yet have
1340 		 * established a class.  Do so now.
1341 		 */
1342 		if (msg->rdclass_set == 0 &&
1343 		    rdtype != dns_rdatatype_opt &&	/* class is UDP SIZE */
1344 		    rdtype != dns_rdatatype_tsig &&	/* class is ANY */
1345 		    rdtype != dns_rdatatype_tkey) {	/* class is undefined */
1346 			msg->rdclass = rdclass;
1347 			msg->rdclass_set = 1;
1348 		}
1349 
1350 		/*
1351 		 * If this class is different than the one in the question
1352 		 * section, bail.
1353 		 */
1354 		if (msg->opcode != dns_opcode_update
1355 		    && rdtype != dns_rdatatype_tsig
1356 		    && rdtype != dns_rdatatype_opt
1357 		    && rdtype != dns_rdatatype_key /* in a TKEY query */
1358 		    && rdtype != dns_rdatatype_sig /* SIG(0) */
1359 		    && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1360 		    && msg->rdclass != dns_rdataclass_any
1361 		    && msg->rdclass != rdclass)
1362 			DO_ERROR(DNS_R_FORMERR);
1363 
1364 		/*
1365 		 * If this is not a TKEY query/response then the KEY
1366 		 * record's class needs to match.
1367 		 */
1368 		if (msg->opcode != dns_opcode_update && !msg->tkey &&
1369 		    rdtype == dns_rdatatype_key &&
1370 		    msg->rdclass != dns_rdataclass_any &&
1371 		    msg->rdclass != rdclass)
1372 			DO_ERROR(DNS_R_FORMERR);
1373 
1374 		/*
1375 		 * Special type handling for TSIG, OPT, and TKEY.
1376 		 */
1377 		if (rdtype == dns_rdatatype_tsig) {
1378 			/*
1379 			 * If it is a tsig, verify that it is in the
1380 			 * additional data section.
1381 			 */
1382 			if (sectionid != DNS_SECTION_ADDITIONAL ||
1383 			    rdclass != dns_rdataclass_any ||
1384 			    count != msg->counts[sectionid]  - 1) {
1385 				DO_ERROR(DNS_R_BADTSIG);
1386 			} else {
1387 				skip_name_search = true;
1388 				skip_type_search = true;
1389 				istsig = true;
1390 			}
1391 		} else if (rdtype == dns_rdatatype_opt) {
1392 			/*
1393 			 * The name of an OPT record must be ".", it
1394 			 * must be in the additional data section, and
1395 			 * it must be the first OPT we've seen.
1396 			 */
1397 			if (!dns_name_equal(dns_rootname, name) ||
1398 			    sectionid != DNS_SECTION_ADDITIONAL ||
1399 			    msg->opt != NULL) {
1400 				DO_ERROR(DNS_R_FORMERR);
1401 			} else {
1402 				skip_name_search = true;
1403 				skip_type_search = true;
1404 				isedns = true;
1405 			}
1406 		} else if (rdtype == dns_rdatatype_tkey) {
1407 			/*
1408 			 * A TKEY must be in the additional section if this
1409 			 * is a query, and the answer section if this is a
1410 			 * response.  Unless it's a Win2000 client.
1411 			 *
1412 			 * Its class is ignored.
1413 			 */
1414 			dns_section_t tkeysection;
1415 
1416 			if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1417 				tkeysection = DNS_SECTION_ADDITIONAL;
1418 			else
1419 				tkeysection = DNS_SECTION_ANSWER;
1420 			if (sectionid != tkeysection &&
1421 			    sectionid != DNS_SECTION_ANSWER)
1422 				DO_ERROR(DNS_R_FORMERR);
1423 		}
1424 
1425 		/*
1426 		 * ... now get ttl and rdatalen, and check buffer.
1427 		 */
1428 		ttl = isc_buffer_getuint32(source);
1429 		rdatalen = isc_buffer_getuint16(source);
1430 		r.length -= (2 + 2 + 4 + 2);
1431 		if (r.length < rdatalen) {
1432 			result = ISC_R_UNEXPECTEDEND;
1433 			goto cleanup;
1434 		}
1435 
1436 		/*
1437 		 * Read the rdata from the wire format.  Interpret the
1438 		 * rdata according to its actual class, even if it had a
1439 		 * DynDNS meta-class in the packet (unless this is a TSIG).
1440 		 * Then put the meta-class back into the finished rdata.
1441 		 */
1442 		rdata = newrdata(msg);
1443 		if (rdata == NULL) {
1444 			result = ISC_R_NOMEMORY;
1445 			goto cleanup;
1446 		}
1447 		if (msg->opcode == dns_opcode_update &&
1448 		    update(sectionid, rdclass)) {
1449 			if (rdatalen != 0) {
1450 				result = DNS_R_FORMERR;
1451 				goto cleanup;
1452 			}
1453 			/*
1454 			 * When the rdata is empty, the data pointer is
1455 			 * never dereferenced, but it must still be non-NULL.
1456 			 * Casting 1 rather than "" avoids warnings about
1457 			 * discarding the const attribute of a string,
1458 			 * for compilers that would warn about such things.
1459 			 */
1460 			rdata->data = (unsigned char *)1;
1461 			rdata->length = 0;
1462 			rdata->rdclass = rdclass;
1463 			rdata->type = rdtype;
1464 			rdata->flags = DNS_RDATA_UPDATE;
1465 			result = ISC_R_SUCCESS;
1466 		} else if (rdclass == dns_rdataclass_none &&
1467 			   msg->opcode == dns_opcode_update &&
1468 			   sectionid == DNS_SECTION_UPDATE) {
1469 			result = getrdata(source, msg, dctx, msg->rdclass,
1470 					  rdtype, rdatalen, rdata);
1471 		} else
1472 			result = getrdata(source, msg, dctx, rdclass,
1473 					  rdtype, rdatalen, rdata);
1474 		if (result != ISC_R_SUCCESS)
1475 			goto cleanup;
1476 		rdata->rdclass = rdclass;
1477 		if (rdtype == dns_rdatatype_rrsig &&
1478 		    rdata->flags == 0) {
1479 			covers = dns_rdata_covers(rdata);
1480 			if (covers == 0)
1481 				DO_ERROR(DNS_R_FORMERR);
1482 		} else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1483 			   rdata->flags == 0) {
1484 			covers = dns_rdata_covers(rdata);
1485 			if (covers == 0) {
1486 				if (sectionid != DNS_SECTION_ADDITIONAL ||
1487 				    count != msg->counts[sectionid]  - 1) {
1488 					DO_ERROR(DNS_R_BADSIG0);
1489 				} else {
1490 					skip_name_search = true;
1491 					skip_type_search = true;
1492 					issigzero = true;
1493 				}
1494 			} else {
1495 				if (msg->rdclass != dns_rdataclass_any &&
1496 				    msg->rdclass != rdclass)
1497 					DO_ERROR(DNS_R_FORMERR);
1498 			}
1499 		} else
1500 			covers = 0;
1501 
1502 		/*
1503 		 * Check the ownername of NSEC3 records
1504 		 */
1505 		if (rdtype == dns_rdatatype_nsec3 &&
1506 		    !dns_rdata_checkowner(name, msg->rdclass, rdtype,
1507 					  false)) {
1508 			result = DNS_R_BADOWNERNAME;
1509 			goto cleanup;
1510 		}
1511 
1512 		/*
1513 		 * If we are doing a dynamic update or this is a meta-type,
1514 		 * don't bother searching for a name, just append this one
1515 		 * to the end of the message.
1516 		 */
1517 		if (preserve_order || msg->opcode == dns_opcode_update ||
1518 		    skip_name_search) {
1519 			if (!isedns && !istsig && !issigzero) {
1520 				ISC_LIST_APPEND(*section, name, link);
1521 				free_name = false;
1522 			}
1523 		} else {
1524 			/*
1525 			 * Run through the section, looking to see if this name
1526 			 * is already there.  If it is found, put back the
1527 			 * allocated name since we no longer need it, and set
1528 			 * our name pointer to point to the name we found.
1529 			 */
1530 			result = findname(&name2, name, section);
1531 
1532 			/*
1533 			 * If it is a new name, append to the section.
1534 			 */
1535 			if (result == ISC_R_SUCCESS) {
1536 				isc_mempool_put(msg->namepool, name);
1537 				name = name2;
1538 			} else {
1539 				ISC_LIST_APPEND(*section, name, link);
1540 			}
1541 			free_name = false;
1542 		}
1543 
1544 		/*
1545 		 * Search name for the particular type and class.
1546 		 * Skip this stage if in update mode or this is a meta-type.
1547 		 */
1548 		if (preserve_order || msg->opcode == dns_opcode_update ||
1549 		    skip_type_search)
1550 			result = ISC_R_NOTFOUND;
1551 		else {
1552 			/*
1553 			 * If this is a type that can only occur in
1554 			 * the question section, fail.
1555 			 */
1556 			if (dns_rdatatype_questiononly(rdtype))
1557 				DO_ERROR(DNS_R_FORMERR);
1558 
1559 			rdataset = NULL;
1560 			result = dns_message_find(name, rdclass, rdtype,
1561 						   covers, &rdataset);
1562 		}
1563 
1564 		/*
1565 		 * If we found an rdataset that matches, we need to
1566 		 * append this rdata to that set.  If we did not, we need
1567 		 * to create a new rdatalist, store the important bits there,
1568 		 * convert it to an rdataset, and link the latter to the name.
1569 		 * Yuck.  When appending, make certain that the type isn't
1570 		 * a singleton type, such as SOA or CNAME.
1571 		 *
1572 		 * Note that this check will be bypassed when preserving order,
1573 		 * the opcode is an update, or the type search is skipped.
1574 		 */
1575 		if (result == ISC_R_SUCCESS) {
1576 			if (dns_rdatatype_issingleton(rdtype)) {
1577 				dns_rdata_t *first;
1578 				dns_rdatalist_fromrdataset(rdataset,
1579 							   &rdatalist);
1580 				first = ISC_LIST_HEAD(rdatalist->rdata);
1581 				INSIST(first != NULL);
1582 				if (dns_rdata_compare(rdata, first) != 0)
1583 					DO_ERROR(DNS_R_FORMERR);
1584 			}
1585 		}
1586 
1587 		if (result == ISC_R_NOTFOUND) {
1588 			rdataset = isc_mempool_get(msg->rdspool);
1589 			if (rdataset == NULL) {
1590 				result = ISC_R_NOMEMORY;
1591 				goto cleanup;
1592 			}
1593 			free_rdataset = true;
1594 
1595 			rdatalist = newrdatalist(msg);
1596 			if (rdatalist == NULL) {
1597 				result = ISC_R_NOMEMORY;
1598 				goto cleanup;
1599 			}
1600 
1601 			rdatalist->type = rdtype;
1602 			rdatalist->covers = covers;
1603 			rdatalist->rdclass = rdclass;
1604 			rdatalist->ttl = ttl;
1605 
1606 			dns_rdataset_init(rdataset);
1607 			RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1608 							       rdataset)
1609 				      == ISC_R_SUCCESS);
1610 			dns_rdataset_setownercase(rdataset, name);
1611 
1612 			if (!isedns && !istsig && !issigzero) {
1613 				ISC_LIST_APPEND(name->list, rdataset, link);
1614 				free_rdataset = false;
1615 			}
1616 		}
1617 
1618 		/*
1619 		 * Minimize TTLs.
1620 		 *
1621 		 * Section 5.2 of RFC2181 says we should drop
1622 		 * nonauthoritative rrsets where the TTLs differ, but we
1623 		 * currently treat them the as if they were authoritative and
1624 		 * minimize them.
1625 		 */
1626 		if (ttl != rdataset->ttl) {
1627 			rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1628 			if (ttl < rdataset->ttl)
1629 				rdataset->ttl = ttl;
1630 		}
1631 
1632 		/* Append this rdata to the rdataset. */
1633 		dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1634 		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1635 
1636 		/*
1637 		 * If this is an OPT, SIG(0) or TSIG record, remember it.
1638 		 * Also, set the extended rcode for TSIG.
1639 		 *
1640 		 * Note msg->opt, msg->sig0 and msg->tsig will only be
1641 		 * already set if best-effort parsing is enabled otherwise
1642 		 * there will only be at most one of each.
1643 		 */
1644 		if (isedns) {
1645 			dns_rcode_t ercode;
1646 
1647 			msg->opt = rdataset;
1648 			rdataset = NULL;
1649 			free_rdataset = false;
1650 			ercode = (dns_rcode_t)
1651 				((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1652 				 >> 20);
1653 			msg->rcode |= ercode;
1654 			isc_mempool_put(msg->namepool, name);
1655 			free_name = false;
1656 		} else if (issigzero) {
1657 			msg->sig0 = rdataset;
1658 			msg->sig0name = name;
1659 			msg->sigstart = recstart;
1660 			rdataset = NULL;
1661 			free_rdataset = false;
1662 			free_name = false;
1663 		} else if (istsig) {
1664 			msg->tsig = rdataset;
1665 			msg->tsigname = name;
1666 			msg->sigstart = recstart;
1667 			/*
1668 			 * Windows doesn't like TSIG names to be compressed.
1669 			 */
1670 			msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1671 			rdataset = NULL;
1672 			free_rdataset = false;
1673 			free_name = false;
1674 		}
1675 
1676 		if (seen_problem) {
1677 			if (free_name)
1678 				isc_mempool_put(msg->namepool, name);
1679 			if (free_rdataset)
1680 				isc_mempool_put(msg->rdspool, rdataset);
1681 			free_name = free_rdataset = false;
1682 		}
1683 		INSIST(free_name == false);
1684 		INSIST(free_rdataset == false);
1685 	}
1686 
1687 	/*
1688 	 * If any of DS, NSEC or NSEC3 appeared in the
1689 	 * authority section of a query response without
1690 	 * a covering RRSIG, FORMERR
1691 	 */
1692 	if (sectionid == DNS_SECTION_AUTHORITY &&
1693 	    msg->opcode == dns_opcode_query &&
1694 	    ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) &&
1695 	    ((msg->flags & DNS_MESSAGEFLAG_TC) == 0) &&
1696 	    !preserve_order &&
1697 	    !auth_signed(section))
1698 		DO_ERROR(DNS_R_FORMERR);
1699 
1700 	if (seen_problem)
1701 		return (DNS_R_RECOVERABLE);
1702 	return (ISC_R_SUCCESS);
1703 
1704  cleanup:
1705 	if (free_name)
1706 		isc_mempool_put(msg->namepool, name);
1707 	if (free_rdataset)
1708 		isc_mempool_put(msg->rdspool, rdataset);
1709 
1710 	return (result);
1711 }
1712 
1713 isc_result_t
dns_message_parse(dns_message_t * msg,isc_buffer_t * source,unsigned int options)1714 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1715 		  unsigned int options)
1716 {
1717 	isc_region_t r;
1718 	dns_decompress_t dctx;
1719 	isc_result_t ret;
1720 	uint16_t tmpflags;
1721 	isc_buffer_t origsource;
1722 	bool seen_problem;
1723 	bool ignore_tc;
1724 
1725 	REQUIRE(DNS_MESSAGE_VALID(msg));
1726 	REQUIRE(source != NULL);
1727 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1728 
1729 	seen_problem = false;
1730 	ignore_tc = ((options & DNS_MESSAGEPARSE_IGNORETRUNCATION) != 0);
1731 
1732 	origsource = *source;
1733 
1734 	msg->header_ok = 0;
1735 	msg->question_ok = 0;
1736 
1737 	if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0) {
1738 		isc_buffer_usedregion(&origsource, &msg->saved);
1739 	} else {
1740 		msg->saved.length = isc_buffer_usedlength(&origsource);
1741 		msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1742 		if (msg->saved.base == NULL) {
1743 			return (ISC_R_NOMEMORY);
1744 		}
1745 		memmove(msg->saved.base, isc_buffer_base(&origsource),
1746 			msg->saved.length);
1747 		msg->free_saved = 1;
1748 	}
1749 
1750 	isc_buffer_remainingregion(source, &r);
1751 	if (r.length < DNS_MESSAGE_HEADERLEN)
1752 		return (ISC_R_UNEXPECTEDEND);
1753 
1754 	msg->id = isc_buffer_getuint16(source);
1755 	tmpflags = isc_buffer_getuint16(source);
1756 	msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1757 		       >> DNS_MESSAGE_OPCODE_SHIFT);
1758 	msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1759 	msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1760 	msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1761 	msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1762 	msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1763 	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1764 
1765 	msg->header_ok = 1;
1766 	msg->state = DNS_SECTION_QUESTION;
1767 
1768 	/*
1769 	 * -1 means no EDNS.
1770 	 */
1771 	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1772 
1773 	dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1774 
1775 	ret = getquestions(source, msg, &dctx, options);
1776 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1777 		goto truncated;
1778 	if (ret == DNS_R_RECOVERABLE) {
1779 		seen_problem = true;
1780 		ret = ISC_R_SUCCESS;
1781 	}
1782 	if (ret != ISC_R_SUCCESS)
1783 		return (ret);
1784 	msg->question_ok = 1;
1785 
1786 	ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1787 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1788 		goto truncated;
1789 	if (ret == DNS_R_RECOVERABLE) {
1790 		seen_problem = true;
1791 		ret = ISC_R_SUCCESS;
1792 	}
1793 	if (ret != ISC_R_SUCCESS)
1794 		return (ret);
1795 
1796 	ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1797 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1798 		goto truncated;
1799 	if (ret == DNS_R_RECOVERABLE) {
1800 		seen_problem = true;
1801 		ret = ISC_R_SUCCESS;
1802 	}
1803 	if (ret != ISC_R_SUCCESS)
1804 		return (ret);
1805 
1806 	ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1807 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1808 		goto truncated;
1809 	if (ret == DNS_R_RECOVERABLE) {
1810 		seen_problem = true;
1811 		ret = ISC_R_SUCCESS;
1812 	}
1813 	if (ret != ISC_R_SUCCESS)
1814 		return (ret);
1815 
1816 	isc_buffer_remainingregion(source, &r);
1817 	if (r.length != 0) {
1818 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1819 			      DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1820 			      "message has %u byte(s) of trailing garbage",
1821 			      r.length);
1822 	}
1823 
1824  truncated:
1825 
1826 	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1827 		return (DNS_R_RECOVERABLE);
1828 	if (seen_problem == true)
1829 		return (DNS_R_RECOVERABLE);
1830 	return (ISC_R_SUCCESS);
1831 }
1832 
1833 isc_result_t
dns_message_renderbegin(dns_message_t * msg,dns_compress_t * cctx,isc_buffer_t * buffer)1834 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1835 			isc_buffer_t *buffer)
1836 {
1837 	isc_region_t r;
1838 
1839 	REQUIRE(DNS_MESSAGE_VALID(msg));
1840 	REQUIRE(buffer != NULL);
1841 	REQUIRE(msg->buffer == NULL);
1842 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1843 
1844 	msg->cctx = cctx;
1845 
1846 	/*
1847 	 * Erase the contents of this buffer.
1848 	 */
1849 	isc_buffer_clear(buffer);
1850 
1851 	/*
1852 	 * Make certain there is enough for at least the header in this
1853 	 * buffer.
1854 	 */
1855 	isc_buffer_availableregion(buffer, &r);
1856 	if (r.length < DNS_MESSAGE_HEADERLEN)
1857 		return (ISC_R_NOSPACE);
1858 
1859 	if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
1860 		return (ISC_R_NOSPACE);
1861 
1862 	/*
1863 	 * Reserve enough space for the header in this buffer.
1864 	 */
1865 	isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1866 
1867 	msg->buffer = buffer;
1868 
1869 	return (ISC_R_SUCCESS);
1870 }
1871 
1872 isc_result_t
dns_message_renderchangebuffer(dns_message_t * msg,isc_buffer_t * buffer)1873 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1874 	isc_region_t r, rn;
1875 
1876 	REQUIRE(DNS_MESSAGE_VALID(msg));
1877 	REQUIRE(buffer != NULL);
1878 	REQUIRE(msg->buffer != NULL);
1879 
1880 	/*
1881 	 * Ensure that the new buffer is empty, and has enough space to
1882 	 * hold the current contents.
1883 	 */
1884 	isc_buffer_clear(buffer);
1885 
1886 	isc_buffer_availableregion(buffer, &rn);
1887 	isc_buffer_usedregion(msg->buffer, &r);
1888 	REQUIRE(rn.length > r.length);
1889 
1890 	/*
1891 	 * Copy the contents from the old to the new buffer.
1892 	 */
1893 	isc_buffer_add(buffer, r.length);
1894 	memmove(rn.base, r.base, r.length);
1895 
1896 	msg->buffer = buffer;
1897 
1898 	return (ISC_R_SUCCESS);
1899 }
1900 
1901 void
dns_message_renderrelease(dns_message_t * msg,unsigned int space)1902 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1903 	REQUIRE(DNS_MESSAGE_VALID(msg));
1904 	REQUIRE(space <= msg->reserved);
1905 
1906 	msg->reserved -= space;
1907 }
1908 
1909 isc_result_t
dns_message_renderreserve(dns_message_t * msg,unsigned int space)1910 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1911 	isc_region_t r;
1912 
1913 	REQUIRE(DNS_MESSAGE_VALID(msg));
1914 
1915 	if (msg->buffer != NULL) {
1916 		isc_buffer_availableregion(msg->buffer, &r);
1917 		if (r.length < (space + msg->reserved))
1918 			return (ISC_R_NOSPACE);
1919 	}
1920 
1921 	msg->reserved += space;
1922 
1923 	return (ISC_R_SUCCESS);
1924 }
1925 
1926 static inline bool
wrong_priority(dns_rdataset_t * rds,int pass,dns_rdatatype_t preferred_glue)1927 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1928 	int pass_needed;
1929 
1930 	/*
1931 	 * If we are not rendering class IN, this ordering is bogus.
1932 	 */
1933 	if (rds->rdclass != dns_rdataclass_in)
1934 		return (false);
1935 
1936 	switch (rds->type) {
1937 	case dns_rdatatype_a:
1938 	case dns_rdatatype_aaaa:
1939 		if (preferred_glue == rds->type)
1940 			pass_needed = 4;
1941 		else
1942 			pass_needed = 3;
1943 		break;
1944 	case dns_rdatatype_rrsig:
1945 	case dns_rdatatype_dnskey:
1946 		pass_needed = 2;
1947 		break;
1948 	default:
1949 		pass_needed = 1;
1950 	}
1951 
1952 	if (pass_needed >= pass)
1953 		return (false);
1954 
1955 	return (true);
1956 }
1957 
1958 #ifdef ALLOW_FILTER_AAAA
1959 /*
1960  * Decide whether to not answer with an AAAA record and its RRSIG
1961  */
1962 static inline bool
norender_rdataset(const dns_rdataset_t * rdataset,unsigned int options,dns_section_t sectionid)1963 norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options,
1964 		  dns_section_t sectionid)
1965 {
1966 	if (sectionid == DNS_SECTION_QUESTION)
1967 		return (false);
1968 
1969 	switch (rdataset->type) {
1970 	case dns_rdatatype_ns:
1971 		if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1972 		    sectionid != DNS_SECTION_AUTHORITY)
1973 			return (false);
1974 		break;
1975 
1976 	case dns_rdatatype_aaaa:
1977 		if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
1978 			return (false);
1979 		break;
1980 
1981 	case dns_rdatatype_rrsig:
1982 		if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1983 		    (rdataset->covers != dns_rdatatype_ns &&
1984 		     rdataset->covers != dns_rdatatype_aaaa))
1985 			return (false);
1986 		if ((rdataset->covers == dns_rdatatype_ns) &&
1987 		    (sectionid != DNS_SECTION_AUTHORITY))
1988 			return (false);
1989 		break;
1990 
1991 	default:
1992 		return (false);
1993 	}
1994 
1995 	if (rdataset->rdclass != dns_rdataclass_in)
1996 		return (false);
1997 
1998 	return (true);
1999 }
2000 #endif
2001 
2002 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)2003 renderset(dns_rdataset_t *rdataset, dns_name_t *owner_name,
2004 	  dns_compress_t *cctx, isc_buffer_t *target,
2005 	  unsigned int reserved, unsigned int options, unsigned int *countp)
2006 {
2007 	isc_result_t result;
2008 
2009 	/*
2010 	 * Shrink the space in the buffer by the reserved amount.
2011 	 */
2012 	if (target->length - target->used < reserved)
2013 		return (ISC_R_NOSPACE);
2014 
2015 	target->length -= reserved;
2016 	result = dns_rdataset_towire(rdataset, owner_name,
2017 				     cctx, target, options, countp);
2018 	target->length += reserved;
2019 
2020 	return (result);
2021 }
2022 
2023 static void
maybe_clear_ad(dns_message_t * msg,dns_section_t sectionid)2024 maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) {
2025 	if (msg->counts[sectionid] == 0 &&
2026 	    (sectionid == DNS_SECTION_ANSWER ||
2027 	     (sectionid == DNS_SECTION_AUTHORITY &&
2028 	      msg->counts[DNS_SECTION_ANSWER] == 0)))
2029 		msg->flags &= ~DNS_MESSAGEFLAG_AD;
2030 }
2031 
2032 isc_result_t
dns_message_rendersection(dns_message_t * msg,dns_section_t sectionid,unsigned int options)2033 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
2034 			  unsigned int options)
2035 {
2036 	dns_namelist_t *section;
2037 	dns_name_t *name, *next_name;
2038 	dns_rdataset_t *rdataset, *next_rdataset;
2039 	unsigned int count, total;
2040 	isc_result_t result;
2041 	isc_buffer_t st; /* for rollbacks */
2042 	int pass;
2043 	bool partial = false;
2044 	unsigned int rd_options;
2045 	dns_rdatatype_t preferred_glue = 0;
2046 
2047 	REQUIRE(DNS_MESSAGE_VALID(msg));
2048 	REQUIRE(msg->buffer != NULL);
2049 	REQUIRE(VALID_NAMED_SECTION(sectionid));
2050 
2051 	section = &msg->sections[sectionid];
2052 
2053 	if ((sectionid == DNS_SECTION_ADDITIONAL)
2054 	    && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
2055 		if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
2056 			preferred_glue = dns_rdatatype_a;
2057 			pass = 4;
2058 		} else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
2059 			preferred_glue = dns_rdatatype_aaaa;
2060 			pass = 4;
2061 		} else
2062 			pass = 3;
2063 	} else
2064 		pass = 1;
2065 
2066 	if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
2067 		rd_options = 0;
2068 	else
2069 		rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
2070 
2071 	/*
2072 	 * Shrink the space in the buffer by the reserved amount.
2073 	 */
2074 	if (msg->buffer->length - msg->buffer->used < msg->reserved)
2075 		return (ISC_R_NOSPACE);
2076 	msg->buffer->length -= msg->reserved;
2077 
2078 	total = 0;
2079 	if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
2080 		partial = true;
2081 
2082 	/*
2083 	 * Render required glue first.  Set TC if it won't fit.
2084 	 */
2085 	name = ISC_LIST_HEAD(*section);
2086 	if (name != NULL) {
2087 		rdataset = ISC_LIST_HEAD(name->list);
2088 		if (rdataset != NULL &&
2089 		    (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
2090 		    (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
2091 			const void *order_arg = msg->order_arg;
2092 			st = *(msg->buffer);
2093 			count = 0;
2094 			if (partial)
2095 				result = dns_rdataset_towirepartial(rdataset,
2096 								    name,
2097 								    msg->cctx,
2098 								    msg->buffer,
2099 								    msg->order,
2100 								    order_arg,
2101 								    rd_options,
2102 								    &count,
2103 								    NULL);
2104 			else
2105 				result = dns_rdataset_towiresorted(rdataset,
2106 								   name,
2107 								   msg->cctx,
2108 								   msg->buffer,
2109 								   msg->order,
2110 								   order_arg,
2111 								   rd_options,
2112 								   &count);
2113 			total += count;
2114 			if (partial && result == ISC_R_NOSPACE) {
2115 				msg->flags |= DNS_MESSAGEFLAG_TC;
2116 				msg->buffer->length += msg->reserved;
2117 				msg->counts[sectionid] += total;
2118 				return (result);
2119 			}
2120 			if (result == ISC_R_NOSPACE)
2121 				msg->flags |= DNS_MESSAGEFLAG_TC;
2122 			if (result != ISC_R_SUCCESS) {
2123 				INSIST(st.used < 65536);
2124 				dns_compress_rollback(msg->cctx,
2125 						      (uint16_t)st.used);
2126 				*(msg->buffer) = st;  /* rollback */
2127 				msg->buffer->length += msg->reserved;
2128 				msg->counts[sectionid] += total;
2129 				return (result);
2130 			}
2131 			rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
2132 		}
2133 	}
2134 
2135 	do {
2136 		name = ISC_LIST_HEAD(*section);
2137 		if (name == NULL) {
2138 			msg->buffer->length += msg->reserved;
2139 			msg->counts[sectionid] += total;
2140 			return (ISC_R_SUCCESS);
2141 		}
2142 
2143 		while (name != NULL) {
2144 			next_name = ISC_LIST_NEXT(name, link);
2145 
2146 			rdataset = ISC_LIST_HEAD(name->list);
2147 			while (rdataset != NULL) {
2148 				next_rdataset = ISC_LIST_NEXT(rdataset, link);
2149 
2150 				if ((rdataset->attributes &
2151 				     DNS_RDATASETATTR_RENDERED) != 0)
2152 					goto next;
2153 
2154 				if (((options & DNS_MESSAGERENDER_ORDERED)
2155 				     == 0)
2156 				    && (sectionid == DNS_SECTION_ADDITIONAL)
2157 				    && wrong_priority(rdataset, pass,
2158 						      preferred_glue))
2159 					goto next;
2160 
2161 #ifdef ALLOW_FILTER_AAAA
2162 				/*
2163 				 * Suppress AAAAs if asked and we are
2164 				 * not doing DNSSEC or are breaking DNSSEC.
2165 				 * Say so in the AD bit if we break DNSSEC.
2166 				 */
2167 				if (norender_rdataset(rdataset, options, sectionid)) {
2168 					if (sectionid == DNS_SECTION_ANSWER ||
2169 					    sectionid == DNS_SECTION_AUTHORITY)
2170 					    msg->flags &= ~DNS_MESSAGEFLAG_AD;
2171 					if (OPTOUT(rdataset))
2172 					    msg->flags &= ~DNS_MESSAGEFLAG_AD;
2173 					goto next;
2174 				}
2175 
2176 #endif
2177 				st = *(msg->buffer);
2178 
2179 				count = 0;
2180 				if (partial)
2181 					result = dns_rdataset_towirepartial(
2182 							  rdataset,
2183 							  name,
2184 							  msg->cctx,
2185 							  msg->buffer,
2186 							  msg->order,
2187 							  msg->order_arg,
2188 							  rd_options,
2189 							  &count,
2190 							  NULL);
2191 				else
2192 					result = dns_rdataset_towiresorted(
2193 							  rdataset,
2194 							  name,
2195 							  msg->cctx,
2196 							  msg->buffer,
2197 							  msg->order,
2198 							  msg->order_arg,
2199 							  rd_options,
2200 							  &count);
2201 
2202 				total += count;
2203 
2204 				/*
2205 				 * If out of space, record stats on what we
2206 				 * rendered so far, and return that status.
2207 				 *
2208 				 * XXXMLG Need to change this when
2209 				 * dns_rdataset_towire() can render partial
2210 				 * sets starting at some arbitrary point in the
2211 				 * set.  This will include setting a bit in the
2212 				 * rdataset to indicate that a partial
2213 				 * rendering was done, and some state saved
2214 				 * somewhere (probably in the message struct)
2215 				 * to indicate where to continue from.
2216 				 */
2217 				if (partial && result == ISC_R_NOSPACE) {
2218 					msg->buffer->length += msg->reserved;
2219 					msg->counts[sectionid] += total;
2220 					return (result);
2221 				}
2222 				if (result != ISC_R_SUCCESS) {
2223 					INSIST(st.used < 65536);
2224 					dns_compress_rollback(msg->cctx,
2225 							(uint16_t)st.used);
2226 					*(msg->buffer) = st;  /* rollback */
2227 					msg->buffer->length += msg->reserved;
2228 					msg->counts[sectionid] += total;
2229 					maybe_clear_ad(msg, sectionid);
2230 					return (result);
2231 				}
2232 
2233 				/*
2234 				 * If we have rendered non-validated data,
2235 				 * ensure that the AD bit is not set.
2236 				 */
2237 				if (rdataset->trust != dns_trust_secure &&
2238 				    (sectionid == DNS_SECTION_ANSWER ||
2239 				     sectionid == DNS_SECTION_AUTHORITY))
2240 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
2241 				if (OPTOUT(rdataset))
2242 					msg->flags &= ~DNS_MESSAGEFLAG_AD;
2243 
2244 				rdataset->attributes |=
2245 					DNS_RDATASETATTR_RENDERED;
2246 
2247 			next:
2248 				rdataset = next_rdataset;
2249 			}
2250 
2251 			name = next_name;
2252 		}
2253 	} while (--pass != 0);
2254 
2255 	msg->buffer->length += msg->reserved;
2256 	msg->counts[sectionid] += total;
2257 
2258 	return (ISC_R_SUCCESS);
2259 }
2260 
2261 void
dns_message_renderheader(dns_message_t * msg,isc_buffer_t * target)2262 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2263 	uint16_t tmp;
2264 	isc_region_t r;
2265 
2266 	REQUIRE(DNS_MESSAGE_VALID(msg));
2267 	REQUIRE(target != NULL);
2268 
2269 	isc_buffer_availableregion(target, &r);
2270 	REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2271 
2272 	isc_buffer_putuint16(target, msg->id);
2273 
2274 	tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2275 	       & DNS_MESSAGE_OPCODE_MASK);
2276 	tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2277 	tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2278 
2279 	INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
2280 	       msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
2281 	       msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2282 	       msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2283 
2284 	isc_buffer_putuint16(target, tmp);
2285 	isc_buffer_putuint16(target,
2286 			    (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2287 	isc_buffer_putuint16(target,
2288 			    (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2289 	isc_buffer_putuint16(target,
2290 			    (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2291 	isc_buffer_putuint16(target,
2292 			    (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2293 }
2294 
2295 isc_result_t
dns_message_renderend(dns_message_t * msg)2296 dns_message_renderend(dns_message_t *msg) {
2297 	isc_buffer_t tmpbuf;
2298 	isc_region_t r;
2299 	int result;
2300 	unsigned int count;
2301 
2302 	REQUIRE(DNS_MESSAGE_VALID(msg));
2303 	REQUIRE(msg->buffer != NULL);
2304 
2305 	if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2306 		/*
2307 		 * We have an extended rcode but are not using EDNS.
2308 		 */
2309 		return (DNS_R_FORMERR);
2310 	}
2311 
2312 	/*
2313 	 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
2314 	 * clear all rdatasets from the message except for the question
2315 	 * before adding the OPT, TSIG or SIG(0).  If the question doesn't
2316 	 * fit, don't include it.
2317 	 */
2318 	if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
2319 	    (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2320 	{
2321 		isc_buffer_t *buf;
2322 
2323 		msgresetnames(msg, DNS_SECTION_ANSWER);
2324 		buf = msg->buffer;
2325 		dns_message_renderreset(msg);
2326 		msg->buffer = buf;
2327 		isc_buffer_clear(msg->buffer);
2328 		isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2329 		dns_compress_rollback(msg->cctx, 0);
2330 		result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2331 						   0);
2332 		if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2333 			return (result);
2334 	}
2335 
2336 	/*
2337 	 * If we've got an OPT record, render it.
2338 	 */
2339 	if (msg->opt != NULL) {
2340 		dns_message_renderrelease(msg, msg->opt_reserved);
2341 		msg->opt_reserved = 0;
2342 		/*
2343 		 * Set the extended rcode.  Cast msg->rcode to dns_ttl_t
2344 		 * so that we do a unsigned shift.
2345 		 */
2346 		msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2347 		msg->opt->ttl |= (((dns_ttl_t)(msg->rcode) << 20) &
2348 				  DNS_MESSAGE_EDNSRCODE_MASK);
2349 		/*
2350 		 * Render.
2351 		 */
2352 		count = 0;
2353 		result = renderset(msg->opt, dns_rootname, msg->cctx,
2354 				   msg->buffer, msg->reserved, 0, &count);
2355 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2356 		if (result != ISC_R_SUCCESS)
2357 			return (result);
2358 	}
2359 
2360 	/*
2361 	 * If we're adding a TSIG record, generate and render it.
2362 	 */
2363 	if (msg->tsigkey != NULL) {
2364 		dns_message_renderrelease(msg, msg->sig_reserved);
2365 		msg->sig_reserved = 0;
2366 		result = dns_tsig_sign(msg);
2367 		if (result != ISC_R_SUCCESS)
2368 			return (result);
2369 		count = 0;
2370 		result = renderset(msg->tsig, msg->tsigname, msg->cctx,
2371 				   msg->buffer, msg->reserved, 0, &count);
2372 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2373 		if (result != ISC_R_SUCCESS)
2374 			return (result);
2375 	}
2376 
2377 	/*
2378 	 * If we're adding a SIG(0) record, generate and render it.
2379 	 */
2380 	if (msg->sig0key != NULL) {
2381 		dns_message_renderrelease(msg, msg->sig_reserved);
2382 		msg->sig_reserved = 0;
2383 		result = dns_dnssec_signmessage(msg, msg->sig0key);
2384 		if (result != ISC_R_SUCCESS)
2385 			return (result);
2386 		count = 0;
2387 		/*
2388 		 * Note: dns_rootname is used here, not msg->sig0name, since
2389 		 * the owner name of a SIG(0) is irrelevant, and will not
2390 		 * be set in a message being rendered.
2391 		 */
2392 		result = renderset(msg->sig0, dns_rootname, msg->cctx,
2393 				   msg->buffer, msg->reserved, 0, &count);
2394 		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2395 		if (result != ISC_R_SUCCESS)
2396 			return (result);
2397 	}
2398 
2399 	isc_buffer_usedregion(msg->buffer, &r);
2400 	isc_buffer_init(&tmpbuf, r.base, r.length);
2401 
2402 	dns_message_renderheader(msg, &tmpbuf);
2403 
2404 	msg->buffer = NULL;  /* forget about this buffer only on success XXX */
2405 
2406 	return (ISC_R_SUCCESS);
2407 }
2408 
2409 void
dns_message_renderreset(dns_message_t * msg)2410 dns_message_renderreset(dns_message_t *msg) {
2411 	unsigned int i;
2412 	dns_name_t *name;
2413 	dns_rdataset_t *rds;
2414 
2415 	/*
2416 	 * Reset the message so that it may be rendered again.
2417 	 */
2418 
2419 	REQUIRE(DNS_MESSAGE_VALID(msg));
2420 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2421 
2422 	msg->buffer = NULL;
2423 
2424 	for (i = 0; i < DNS_SECTION_MAX; i++) {
2425 		msg->cursors[i] = NULL;
2426 		msg->counts[i] = 0;
2427 		for (name = ISC_LIST_HEAD(msg->sections[i]);
2428 		     name != NULL;
2429 		     name = ISC_LIST_NEXT(name, link)) {
2430 			for (rds = ISC_LIST_HEAD(name->list);
2431 			     rds != NULL;
2432 			     rds = ISC_LIST_NEXT(rds, link)) {
2433 				rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2434 			}
2435 		}
2436 	}
2437 	if (msg->tsigname != NULL)
2438 		dns_message_puttempname(msg, &msg->tsigname);
2439 	if (msg->tsig != NULL) {
2440 		dns_rdataset_disassociate(msg->tsig);
2441 		dns_message_puttemprdataset(msg, &msg->tsig);
2442 	}
2443 	if (msg->sig0 != NULL) {
2444 		dns_rdataset_disassociate(msg->sig0);
2445 		dns_message_puttemprdataset(msg, &msg->sig0);
2446 	}
2447 }
2448 
2449 isc_result_t
dns_message_firstname(dns_message_t * msg,dns_section_t section)2450 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2451 	REQUIRE(DNS_MESSAGE_VALID(msg));
2452 	REQUIRE(VALID_NAMED_SECTION(section));
2453 
2454 	msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2455 
2456 	if (msg->cursors[section] == NULL)
2457 		return (ISC_R_NOMORE);
2458 
2459 	return (ISC_R_SUCCESS);
2460 }
2461 
2462 isc_result_t
dns_message_nextname(dns_message_t * msg,dns_section_t section)2463 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2464 	REQUIRE(DNS_MESSAGE_VALID(msg));
2465 	REQUIRE(VALID_NAMED_SECTION(section));
2466 	REQUIRE(msg->cursors[section] != NULL);
2467 
2468 	msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2469 
2470 	if (msg->cursors[section] == NULL)
2471 		return (ISC_R_NOMORE);
2472 
2473 	return (ISC_R_SUCCESS);
2474 }
2475 
2476 void
dns_message_currentname(dns_message_t * msg,dns_section_t section,dns_name_t ** name)2477 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2478 			dns_name_t **name)
2479 {
2480 	REQUIRE(DNS_MESSAGE_VALID(msg));
2481 	REQUIRE(VALID_NAMED_SECTION(section));
2482 	REQUIRE(name != NULL && *name == NULL);
2483 	REQUIRE(msg->cursors[section] != NULL);
2484 
2485 	*name = msg->cursors[section];
2486 }
2487 
2488 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)2489 dns_message_findname(dns_message_t *msg, dns_section_t section,
2490 		     dns_name_t *target, dns_rdatatype_t type,
2491 		     dns_rdatatype_t covers, dns_name_t **name,
2492 		     dns_rdataset_t **rdataset)
2493 {
2494 	dns_name_t *foundname;
2495 	isc_result_t result;
2496 
2497 	/*
2498 	 * XXX These requirements are probably too intensive, especially
2499 	 * where things can be NULL, but as they are they ensure that if
2500 	 * something is NON-NULL, indicating that the caller expects it
2501 	 * to be filled in, that we can in fact fill it in.
2502 	 */
2503 	REQUIRE(msg != NULL);
2504 	REQUIRE(VALID_SECTION(section));
2505 	REQUIRE(target != NULL);
2506 	REQUIRE(name == NULL || *name == NULL);
2507 
2508 	if (type == dns_rdatatype_any) {
2509 		REQUIRE(rdataset == NULL);
2510 	} else {
2511 		REQUIRE(rdataset == NULL || *rdataset == NULL);
2512 	}
2513 
2514 	result = findname(&foundname, target,
2515 			  &msg->sections[section]);
2516 
2517 	if (result == ISC_R_NOTFOUND)
2518 		return (DNS_R_NXDOMAIN);
2519 	else if (result != ISC_R_SUCCESS)
2520 		return (result);
2521 
2522 	if (name != NULL)
2523 		*name = foundname;
2524 
2525 	/*
2526 	 * And now look for the type.
2527 	 */
2528 	if (ISC_UNLIKELY(type == dns_rdatatype_any))
2529 		return (ISC_R_SUCCESS);
2530 
2531 	result = dns_message_findtype(foundname, type, covers, rdataset);
2532 	if (result == ISC_R_NOTFOUND)
2533 		return (DNS_R_NXRRSET);
2534 
2535 	return (result);
2536 }
2537 
2538 void
dns_message_movename(dns_message_t * msg,dns_name_t * name,dns_section_t fromsection,dns_section_t tosection)2539 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2540 		     dns_section_t fromsection,
2541 		     dns_section_t tosection)
2542 {
2543 	REQUIRE(msg != NULL);
2544 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2545 	REQUIRE(name != NULL);
2546 	REQUIRE(VALID_NAMED_SECTION(fromsection));
2547 	REQUIRE(VALID_NAMED_SECTION(tosection));
2548 
2549 	/*
2550 	 * Unlink the name from the old section
2551 	 */
2552 	ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2553 	ISC_LIST_APPEND(msg->sections[tosection], name, link);
2554 }
2555 
2556 void
dns_message_addname(dns_message_t * msg,dns_name_t * name,dns_section_t section)2557 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2558 		    dns_section_t section)
2559 {
2560 	REQUIRE(msg != NULL);
2561 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2562 	REQUIRE(name != NULL);
2563 	REQUIRE(VALID_NAMED_SECTION(section));
2564 
2565 	ISC_LIST_APPEND(msg->sections[section], name, link);
2566 }
2567 
2568 void
dns_message_removename(dns_message_t * msg,dns_name_t * name,dns_section_t section)2569 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2570 		       dns_section_t section)
2571 {
2572 	REQUIRE(msg != NULL);
2573 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2574 	REQUIRE(name != NULL);
2575 	REQUIRE(VALID_NAMED_SECTION(section));
2576 
2577 	ISC_LIST_UNLINK(msg->sections[section], name, link);
2578 }
2579 
2580 isc_result_t
dns_message_gettempname(dns_message_t * msg,dns_name_t ** item)2581 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2582 	REQUIRE(DNS_MESSAGE_VALID(msg));
2583 	REQUIRE(item != NULL && *item == NULL);
2584 
2585 	*item = isc_mempool_get(msg->namepool);
2586 	if (*item == NULL)
2587 		return (ISC_R_NOMEMORY);
2588 	dns_name_init(*item, NULL);
2589 
2590 	return (ISC_R_SUCCESS);
2591 }
2592 
2593 isc_result_t
dns_message_gettempoffsets(dns_message_t * msg,dns_offsets_t ** item)2594 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2595 	REQUIRE(DNS_MESSAGE_VALID(msg));
2596 	REQUIRE(item != NULL && *item == NULL);
2597 
2598 	*item = newoffsets(msg);
2599 	if (*item == NULL)
2600 		return (ISC_R_NOMEMORY);
2601 
2602 	return (ISC_R_SUCCESS);
2603 }
2604 
2605 isc_result_t
dns_message_gettemprdata(dns_message_t * msg,dns_rdata_t ** item)2606 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2607 	REQUIRE(DNS_MESSAGE_VALID(msg));
2608 	REQUIRE(item != NULL && *item == NULL);
2609 
2610 	*item = newrdata(msg);
2611 	if (*item == NULL)
2612 		return (ISC_R_NOMEMORY);
2613 
2614 	return (ISC_R_SUCCESS);
2615 }
2616 
2617 isc_result_t
dns_message_gettemprdataset(dns_message_t * msg,dns_rdataset_t ** item)2618 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2619 	REQUIRE(DNS_MESSAGE_VALID(msg));
2620 	REQUIRE(item != NULL && *item == NULL);
2621 
2622 	*item = isc_mempool_get(msg->rdspool);
2623 	if (*item == NULL)
2624 		return (ISC_R_NOMEMORY);
2625 
2626 	dns_rdataset_init(*item);
2627 
2628 	return (ISC_R_SUCCESS);
2629 }
2630 
2631 isc_result_t
dns_message_gettemprdatalist(dns_message_t * msg,dns_rdatalist_t ** item)2632 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2633 	REQUIRE(DNS_MESSAGE_VALID(msg));
2634 	REQUIRE(item != NULL && *item == NULL);
2635 
2636 	*item = newrdatalist(msg);
2637 	if (*item == NULL)
2638 		return (ISC_R_NOMEMORY);
2639 
2640 	return (ISC_R_SUCCESS);
2641 }
2642 
2643 void
dns_message_puttempname(dns_message_t * msg,dns_name_t ** item)2644 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2645 	REQUIRE(DNS_MESSAGE_VALID(msg));
2646 	REQUIRE(item != NULL && *item != NULL);
2647 
2648 	if (dns_name_dynamic(*item))
2649 		dns_name_free(*item, msg->mctx);
2650 	isc_mempool_put(msg->namepool, *item);
2651 	*item = NULL;
2652 }
2653 
2654 void
dns_message_puttemprdata(dns_message_t * msg,dns_rdata_t ** item)2655 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2656 	REQUIRE(DNS_MESSAGE_VALID(msg));
2657 	REQUIRE(item != NULL && *item != NULL);
2658 
2659 	releaserdata(msg, *item);
2660 	*item = NULL;
2661 }
2662 
2663 void
dns_message_puttemprdataset(dns_message_t * msg,dns_rdataset_t ** item)2664 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2665 	REQUIRE(DNS_MESSAGE_VALID(msg));
2666 	REQUIRE(item != NULL && *item != NULL);
2667 
2668 	REQUIRE(!dns_rdataset_isassociated(*item));
2669 	isc_mempool_put(msg->rdspool, *item);
2670 	*item = NULL;
2671 }
2672 
2673 void
dns_message_puttemprdatalist(dns_message_t * msg,dns_rdatalist_t ** item)2674 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2675 	REQUIRE(DNS_MESSAGE_VALID(msg));
2676 	REQUIRE(item != NULL && *item != NULL);
2677 
2678 	releaserdatalist(msg, *item);
2679 	*item = NULL;
2680 }
2681 
2682 isc_result_t
dns_message_peekheader(isc_buffer_t * source,dns_messageid_t * idp,unsigned int * flagsp)2683 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2684 		       unsigned int *flagsp)
2685 {
2686 	isc_region_t r;
2687 	isc_buffer_t buffer;
2688 	dns_messageid_t id;
2689 	unsigned int flags;
2690 
2691 	REQUIRE(source != NULL);
2692 
2693 	buffer = *source;
2694 
2695 	isc_buffer_remainingregion(&buffer, &r);
2696 	if (r.length < DNS_MESSAGE_HEADERLEN)
2697 		return (ISC_R_UNEXPECTEDEND);
2698 
2699 	id = isc_buffer_getuint16(&buffer);
2700 	flags = isc_buffer_getuint16(&buffer);
2701 	flags &= DNS_MESSAGE_FLAG_MASK;
2702 
2703 	if (flagsp != NULL)
2704 		*flagsp = flags;
2705 	if (idp != NULL)
2706 		*idp = id;
2707 
2708 	return (ISC_R_SUCCESS);
2709 }
2710 
2711 isc_result_t
dns_message_reply(dns_message_t * msg,bool want_question_section)2712 dns_message_reply(dns_message_t *msg, bool want_question_section) {
2713 	unsigned int clear_from;
2714 	isc_result_t result;
2715 
2716 	REQUIRE(DNS_MESSAGE_VALID(msg));
2717 	REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2718 
2719 	if (!msg->header_ok)
2720 		return (DNS_R_FORMERR);
2721 	if (msg->opcode != dns_opcode_query &&
2722 	    msg->opcode != dns_opcode_notify)
2723 		want_question_section = false;
2724 	if (msg->opcode == dns_opcode_update)
2725 		clear_from = DNS_SECTION_PREREQUISITE;
2726 	else if (want_question_section) {
2727 		if (!msg->question_ok)
2728 			return (DNS_R_FORMERR);
2729 		clear_from = DNS_SECTION_ANSWER;
2730 	} else
2731 		clear_from = DNS_SECTION_QUESTION;
2732 	msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2733 	msgresetnames(msg, clear_from);
2734 	msgresetopt(msg);
2735 	msgresetsigs(msg, true);
2736 	msginitprivate(msg);
2737 	/*
2738 	 * We now clear most flags and then set QR, ensuring that the
2739 	 * reply's flags will be in a reasonable state.
2740 	 */
2741 	if (msg->opcode == dns_opcode_query)
2742 		msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2743 	else
2744 		msg->flags = 0;
2745 	msg->flags |= DNS_MESSAGEFLAG_QR;
2746 
2747 	/*
2748 	 * This saves the query TSIG status, if the query was signed, and
2749 	 * reserves space in the reply for the TSIG.
2750 	 */
2751 	if (msg->tsigkey != NULL) {
2752 		unsigned int otherlen = 0;
2753 		msg->querytsigstatus = msg->tsigstatus;
2754 		msg->tsigstatus = dns_rcode_noerror;
2755 		if (msg->querytsigstatus == dns_tsigerror_badtime)
2756 			otherlen = 6;
2757 		msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2758 		result = dns_message_renderreserve(msg, msg->sig_reserved);
2759 		if (result != ISC_R_SUCCESS) {
2760 			msg->sig_reserved = 0;
2761 			return (result);
2762 		}
2763 	}
2764 	if (msg->saved.base != NULL) {
2765 		msg->query.base = msg->saved.base;
2766 		msg->query.length = msg->saved.length;
2767 		msg->free_query = msg->free_saved;
2768 		msg->saved.base = NULL;
2769 		msg->saved.length = 0;
2770 		msg->free_saved = 0;
2771 	}
2772 
2773 	return (ISC_R_SUCCESS);
2774 }
2775 
2776 dns_rdataset_t *
dns_message_getopt(dns_message_t * msg)2777 dns_message_getopt(dns_message_t *msg) {
2778 
2779 	/*
2780 	 * Get the OPT record for 'msg'.
2781 	 */
2782 
2783 	REQUIRE(DNS_MESSAGE_VALID(msg));
2784 
2785 	return (msg->opt);
2786 }
2787 
2788 isc_result_t
dns_message_setopt(dns_message_t * msg,dns_rdataset_t * opt)2789 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2790 	isc_result_t result;
2791 	dns_rdata_t rdata = DNS_RDATA_INIT;
2792 
2793 	/*
2794 	 * Set the OPT record for 'msg'.
2795 	 */
2796 
2797 	/*
2798 	 * The space required for an OPT record is:
2799 	 *
2800 	 *	1 byte for the name
2801 	 *	2 bytes for the type
2802 	 *	2 bytes for the class
2803 	 *	4 bytes for the ttl
2804 	 *	2 bytes for the rdata length
2805 	 * ---------------------------------
2806 	 *     11 bytes
2807 	 *
2808 	 * plus the length of the rdata.
2809 	 */
2810 
2811 	REQUIRE(DNS_MESSAGE_VALID(msg));
2812 	REQUIRE(opt->type == dns_rdatatype_opt);
2813 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2814 	REQUIRE(msg->state == DNS_SECTION_ANY);
2815 
2816 	msgresetopt(msg);
2817 
2818 	result = dns_rdataset_first(opt);
2819 	if (result != ISC_R_SUCCESS)
2820 		goto cleanup;
2821 	dns_rdataset_current(opt, &rdata);
2822 	msg->opt_reserved = 11 + rdata.length;
2823 	result = dns_message_renderreserve(msg, msg->opt_reserved);
2824 	if (result != ISC_R_SUCCESS) {
2825 		msg->opt_reserved = 0;
2826 		goto cleanup;
2827 	}
2828 
2829 	msg->opt = opt;
2830 
2831 	return (ISC_R_SUCCESS);
2832 
2833  cleanup:
2834 	dns_rdataset_disassociate(opt);
2835 	dns_message_puttemprdataset(msg, &opt);
2836 	return (result);
2837 }
2838 
2839 dns_rdataset_t *
dns_message_gettsig(dns_message_t * msg,dns_name_t ** owner)2840 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2841 
2842 	/*
2843 	 * Get the TSIG record and owner for 'msg'.
2844 	 */
2845 
2846 	REQUIRE(DNS_MESSAGE_VALID(msg));
2847 	REQUIRE(owner == NULL || *owner == NULL);
2848 
2849 	if (owner != NULL)
2850 		*owner = msg->tsigname;
2851 	return (msg->tsig);
2852 }
2853 
2854 isc_result_t
dns_message_settsigkey(dns_message_t * msg,dns_tsigkey_t * key)2855 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2856 	isc_result_t result;
2857 
2858 	/*
2859 	 * Set the TSIG key for 'msg'
2860 	 */
2861 
2862 	REQUIRE(DNS_MESSAGE_VALID(msg));
2863 
2864 	if (key == NULL && msg->tsigkey != NULL) {
2865 		if (msg->sig_reserved != 0) {
2866 			dns_message_renderrelease(msg, msg->sig_reserved);
2867 			msg->sig_reserved = 0;
2868 		}
2869 		dns_tsigkey_detach(&msg->tsigkey);
2870 	}
2871 	if (key != NULL) {
2872 		REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2873 		dns_tsigkey_attach(key, &msg->tsigkey);
2874 		if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2875 			msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2876 			result = dns_message_renderreserve(msg,
2877 							   msg->sig_reserved);
2878 			if (result != ISC_R_SUCCESS) {
2879 				dns_tsigkey_detach(&msg->tsigkey);
2880 				msg->sig_reserved = 0;
2881 				return (result);
2882 			}
2883 		}
2884 	}
2885 	return (ISC_R_SUCCESS);
2886 }
2887 
2888 dns_tsigkey_t *
dns_message_gettsigkey(dns_message_t * msg)2889 dns_message_gettsigkey(dns_message_t *msg) {
2890 
2891 	/*
2892 	 * Get the TSIG key for 'msg'
2893 	 */
2894 
2895 	REQUIRE(DNS_MESSAGE_VALID(msg));
2896 
2897 	return (msg->tsigkey);
2898 }
2899 
2900 isc_result_t
dns_message_setquerytsig(dns_message_t * msg,isc_buffer_t * querytsig)2901 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2902 	dns_rdata_t *rdata = NULL;
2903 	dns_rdatalist_t *list = NULL;
2904 	dns_rdataset_t *set = NULL;
2905 	isc_buffer_t *buf = NULL;
2906 	isc_region_t r;
2907 	isc_result_t result;
2908 
2909 	REQUIRE(DNS_MESSAGE_VALID(msg));
2910 	REQUIRE(msg->querytsig == NULL);
2911 
2912 	if (querytsig == NULL)
2913 		return (ISC_R_SUCCESS);
2914 
2915 	result = dns_message_gettemprdata(msg, &rdata);
2916 	if (result != ISC_R_SUCCESS)
2917 		goto cleanup;
2918 
2919 	result = dns_message_gettemprdatalist(msg, &list);
2920 	if (result != ISC_R_SUCCESS)
2921 		goto cleanup;
2922 	result = dns_message_gettemprdataset(msg, &set);
2923 	if (result != ISC_R_SUCCESS)
2924 		goto cleanup;
2925 
2926 	isc_buffer_usedregion(querytsig, &r);
2927 	result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2928 	if (result != ISC_R_SUCCESS)
2929 		goto cleanup;
2930 	isc_buffer_putmem(buf, r.base, r.length);
2931 	isc_buffer_usedregion(buf, &r);
2932 	dns_rdata_init(rdata);
2933 	dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2934 	dns_message_takebuffer(msg, &buf);
2935 	ISC_LIST_APPEND(list->rdata, rdata, link);
2936 	result = dns_rdatalist_tordataset(list, set);
2937 	if (result != ISC_R_SUCCESS)
2938 		goto cleanup;
2939 
2940 	msg->querytsig = set;
2941 
2942 	return (result);
2943 
2944  cleanup:
2945 	if (rdata != NULL)
2946 		dns_message_puttemprdata(msg, &rdata);
2947 	if (list != NULL)
2948 		dns_message_puttemprdatalist(msg, &list);
2949 	if (set != NULL)
2950 		dns_message_puttemprdataset(msg, &set);
2951 	return (ISC_R_NOMEMORY);
2952 }
2953 
2954 isc_result_t
dns_message_getquerytsig(dns_message_t * msg,isc_mem_t * mctx,isc_buffer_t ** querytsig)2955 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2956 			 isc_buffer_t **querytsig) {
2957 	isc_result_t result;
2958 	dns_rdata_t rdata = DNS_RDATA_INIT;
2959 	isc_region_t r;
2960 
2961 	REQUIRE(DNS_MESSAGE_VALID(msg));
2962 	REQUIRE(mctx != NULL);
2963 	REQUIRE(querytsig != NULL && *querytsig == NULL);
2964 
2965 	if (msg->tsig == NULL)
2966 		return (ISC_R_SUCCESS);
2967 
2968 	result = dns_rdataset_first(msg->tsig);
2969 	if (result != ISC_R_SUCCESS)
2970 		return (result);
2971 	dns_rdataset_current(msg->tsig, &rdata);
2972 	dns_rdata_toregion(&rdata, &r);
2973 
2974 	result = isc_buffer_allocate(mctx, querytsig, r.length);
2975 	if (result != ISC_R_SUCCESS)
2976 		return (result);
2977 	isc_buffer_putmem(*querytsig, r.base, r.length);
2978 	return (ISC_R_SUCCESS);
2979 }
2980 
2981 dns_rdataset_t *
dns_message_getsig0(dns_message_t * msg,dns_name_t ** owner)2982 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2983 
2984 	/*
2985 	 * Get the SIG(0) record for 'msg'.
2986 	 */
2987 
2988 	REQUIRE(DNS_MESSAGE_VALID(msg));
2989 	REQUIRE(owner == NULL || *owner == NULL);
2990 
2991 	if (msg->sig0 != NULL && owner != NULL) {
2992 		/* If dns_message_getsig0 is called on a rendered message
2993 		 * after the SIG(0) has been applied, we need to return the
2994 		 * root name, not NULL.
2995 		 */
2996 		if (msg->sig0name == NULL)
2997 			*owner = dns_rootname;
2998 		else
2999 			*owner = msg->sig0name;
3000 	}
3001 	return (msg->sig0);
3002 }
3003 
3004 isc_result_t
dns_message_setsig0key(dns_message_t * msg,dst_key_t * key)3005 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
3006 	isc_region_t r;
3007 	unsigned int x;
3008 	isc_result_t result;
3009 
3010 	/*
3011 	 * Set the SIG(0) key for 'msg'
3012 	 */
3013 
3014 	/*
3015 	 * The space required for an SIG(0) record is:
3016 	 *
3017 	 *	1 byte for the name
3018 	 *	2 bytes for the type
3019 	 *	2 bytes for the class
3020 	 *	4 bytes for the ttl
3021 	 *	2 bytes for the type covered
3022 	 *	1 byte for the algorithm
3023 	 *	1 bytes for the labels
3024 	 *	4 bytes for the original ttl
3025 	 *	4 bytes for the signature expiration
3026 	 *	4 bytes for the signature inception
3027 	 *	2 bytes for the key tag
3028 	 *	n bytes for the signer's name
3029 	 *	x bytes for the signature
3030 	 * ---------------------------------
3031 	 *     27 + n + x bytes
3032 	 */
3033 	REQUIRE(DNS_MESSAGE_VALID(msg));
3034 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
3035 	REQUIRE(msg->state == DNS_SECTION_ANY);
3036 
3037 	if (key != NULL) {
3038 		REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
3039 		dns_name_toregion(dst_key_name(key), &r);
3040 		result = dst_key_sigsize(key, &x);
3041 		if (result != ISC_R_SUCCESS) {
3042 			msg->sig_reserved = 0;
3043 			return (result);
3044 		}
3045 		msg->sig_reserved = 27 + r.length + x;
3046 		result = dns_message_renderreserve(msg, msg->sig_reserved);
3047 		if (result != ISC_R_SUCCESS) {
3048 			msg->sig_reserved = 0;
3049 			return (result);
3050 		}
3051 		msg->sig0key = key;
3052 	}
3053 	return (ISC_R_SUCCESS);
3054 }
3055 
3056 dst_key_t *
dns_message_getsig0key(dns_message_t * msg)3057 dns_message_getsig0key(dns_message_t *msg) {
3058 
3059 	/*
3060 	 * Get the SIG(0) key for 'msg'
3061 	 */
3062 
3063 	REQUIRE(DNS_MESSAGE_VALID(msg));
3064 
3065 	return (msg->sig0key);
3066 }
3067 
3068 void
dns_message_takebuffer(dns_message_t * msg,isc_buffer_t ** buffer)3069 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
3070 	REQUIRE(DNS_MESSAGE_VALID(msg));
3071 	REQUIRE(buffer != NULL);
3072 	REQUIRE(ISC_BUFFER_VALID(*buffer));
3073 
3074 	ISC_LIST_APPEND(msg->cleanup, *buffer, link);
3075 	*buffer = NULL;
3076 }
3077 
3078 isc_result_t
dns_message_signer(dns_message_t * msg,dns_name_t * signer)3079 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
3080 	isc_result_t result = ISC_R_SUCCESS;
3081 	dns_rdata_t rdata = DNS_RDATA_INIT;
3082 
3083 	REQUIRE(DNS_MESSAGE_VALID(msg));
3084 	REQUIRE(signer != NULL);
3085 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
3086 
3087 	if (msg->tsig == NULL && msg->sig0 == NULL)
3088 		return (ISC_R_NOTFOUND);
3089 
3090 	if (msg->verify_attempted == 0)
3091 		return (DNS_R_NOTVERIFIEDYET);
3092 
3093 	if (!dns_name_hasbuffer(signer)) {
3094 		isc_buffer_t *dynbuf = NULL;
3095 		result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
3096 		if (result != ISC_R_SUCCESS)
3097 			return (result);
3098 		dns_name_setbuffer(signer, dynbuf);
3099 		dns_message_takebuffer(msg, &dynbuf);
3100 	}
3101 
3102 	if (msg->sig0 != NULL) {
3103 		dns_rdata_sig_t sig;
3104 
3105 		result = dns_rdataset_first(msg->sig0);
3106 		INSIST(result == ISC_R_SUCCESS);
3107 		dns_rdataset_current(msg->sig0, &rdata);
3108 
3109 		result = dns_rdata_tostruct(&rdata, &sig, NULL);
3110 		if (result != ISC_R_SUCCESS)
3111 			return (result);
3112 
3113 		if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
3114 			result = ISC_R_SUCCESS;
3115 		else
3116 			result = DNS_R_SIGINVALID;
3117 		dns_name_clone(&sig.signer, signer);
3118 		dns_rdata_freestruct(&sig);
3119 	} else {
3120 		const dns_name_t *identity;
3121 		dns_rdata_any_tsig_t tsig;
3122 
3123 		result = dns_rdataset_first(msg->tsig);
3124 		INSIST(result == ISC_R_SUCCESS);
3125 		dns_rdataset_current(msg->tsig, &rdata);
3126 
3127 		result = dns_rdata_tostruct(&rdata, &tsig, NULL);
3128 		INSIST(result == ISC_R_SUCCESS);
3129 		if (msg->verified_sig &&
3130 		    msg->tsigstatus == dns_rcode_noerror &&
3131 		    tsig.error == dns_rcode_noerror)
3132 		{
3133 			result = ISC_R_SUCCESS;
3134 		} else if ((!msg->verified_sig) ||
3135 			   (msg->tsigstatus != dns_rcode_noerror))
3136 		{
3137 			result = DNS_R_TSIGVERIFYFAILURE;
3138 		} else {
3139 			INSIST(tsig.error != dns_rcode_noerror);
3140 			result = DNS_R_TSIGERRORSET;
3141 		}
3142 		dns_rdata_freestruct(&tsig);
3143 
3144 		if (msg->tsigkey == NULL) {
3145 			/*
3146 			 * If msg->tsigstatus & tsig.error are both
3147 			 * dns_rcode_noerror, the message must have been
3148 			 * verified, which means msg->tsigkey will be
3149 			 * non-NULL.
3150 			 */
3151 			INSIST(result != ISC_R_SUCCESS);
3152 		} else {
3153 			identity = dns_tsigkey_identity(msg->tsigkey);
3154 			if (identity == NULL) {
3155 				if (result == ISC_R_SUCCESS)
3156 					result = DNS_R_NOIDENTITY;
3157 				identity = &msg->tsigkey->name;
3158 			}
3159 			dns_name_clone(identity, signer);
3160 		}
3161 	}
3162 
3163 	return (result);
3164 }
3165 
3166 void
dns_message_resetsig(dns_message_t * msg)3167 dns_message_resetsig(dns_message_t *msg) {
3168 	REQUIRE(DNS_MESSAGE_VALID(msg));
3169 	msg->verified_sig = 0;
3170 	msg->verify_attempted = 0;
3171 	msg->tsigstatus = dns_rcode_noerror;
3172 	msg->sig0status = dns_rcode_noerror;
3173 	msg->timeadjust = 0;
3174 	if (msg->tsigkey != NULL) {
3175 		dns_tsigkey_detach(&msg->tsigkey);
3176 		msg->tsigkey = NULL;
3177 	}
3178 }
3179 
3180 isc_result_t
dns_message_rechecksig(dns_message_t * msg,dns_view_t * view)3181 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
3182 	dns_message_resetsig(msg);
3183 	return (dns_message_checksig(msg, view));
3184 }
3185 
3186 #ifdef SKAN_MSG_DEBUG
3187 void
dns_message_dumpsig(dns_message_t * msg,char * txt1)3188 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
3189 	dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
3190 	dns_rdata_any_tsig_t querytsig;
3191 	isc_result_t result;
3192 
3193 	if (msg->tsig != NULL) {
3194 		result = dns_rdataset_first(msg->tsig);
3195 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3196 		dns_rdataset_current(msg->tsig, &querytsigrdata);
3197 		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3198 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3199 		hexdump(txt1, "TSIG", querytsig.signature,
3200 			querytsig.siglen);
3201 	}
3202 
3203 	if (msg->querytsig != NULL) {
3204 		result = dns_rdataset_first(msg->querytsig);
3205 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3206 		dns_rdataset_current(msg->querytsig, &querytsigrdata);
3207 		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3208 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3209 		hexdump(txt1, "QUERYTSIG", querytsig.signature,
3210 			querytsig.siglen);
3211 	}
3212 }
3213 #endif
3214 
3215 isc_result_t
dns_message_checksig(dns_message_t * msg,dns_view_t * view)3216 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3217 	isc_buffer_t b, msgb;
3218 
3219 	REQUIRE(DNS_MESSAGE_VALID(msg));
3220 
3221 	if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
3222 		return (ISC_R_SUCCESS);
3223 
3224 	INSIST(msg->saved.base != NULL);
3225 	isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3226 	isc_buffer_add(&msgb, msg->saved.length);
3227 	if (msg->tsigkey != NULL || msg->tsig != NULL) {
3228 #ifdef SKAN_MSG_DEBUG
3229 		dns_message_dumpsig(msg, "dns_message_checksig#1");
3230 #endif
3231 		if (view != NULL)
3232 			return (dns_view_checksig(view, &msgb, msg));
3233 		else
3234 			return (dns_tsig_verify(&msgb, msg, NULL, NULL));
3235 	} else {
3236 		dns_rdata_t rdata = DNS_RDATA_INIT;
3237 		dns_rdata_sig_t sig;
3238 		dns_rdataset_t keyset;
3239 		isc_result_t result;
3240 
3241 		result = dns_rdataset_first(msg->sig0);
3242 		INSIST(result == ISC_R_SUCCESS);
3243 		dns_rdataset_current(msg->sig0, &rdata);
3244 
3245 		/*
3246 		 * This can occur when the message is a dynamic update, since
3247 		 * the rdata length checking is relaxed.  This should not
3248 		 * happen in a well-formed message, since the SIG(0) is only
3249 		 * looked for in the additional section, and the dynamic update
3250 		 * meta-records are in the prerequisite and update sections.
3251 		 */
3252 		if (rdata.length == 0)
3253 			return (ISC_R_UNEXPECTEDEND);
3254 
3255 		result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3256 		if (result != ISC_R_SUCCESS)
3257 			return (result);
3258 
3259 		dns_rdataset_init(&keyset);
3260 		if (view == NULL)
3261 			return (DNS_R_KEYUNAUTHORIZED);
3262 		result = dns_view_simplefind(view, &sig.signer,
3263 					     dns_rdatatype_key /* SIG(0) */,
3264 					     0, 0, false, &keyset, NULL);
3265 
3266 		if (result != ISC_R_SUCCESS) {
3267 			/* XXXBEW Should possibly create a fetch here */
3268 			result = DNS_R_KEYUNAUTHORIZED;
3269 			goto freesig;
3270 		} else if (keyset.trust < dns_trust_secure) {
3271 			/* XXXBEW Should call a validator here */
3272 			result = DNS_R_KEYUNAUTHORIZED;
3273 			goto freesig;
3274 		}
3275 		result = dns_rdataset_first(&keyset);
3276 		INSIST(result == ISC_R_SUCCESS);
3277 		for (;
3278 		     result == ISC_R_SUCCESS;
3279 		     result = dns_rdataset_next(&keyset))
3280 		{
3281 			dst_key_t *key = NULL;
3282 
3283 			dns_rdata_reset(&rdata);
3284 			dns_rdataset_current(&keyset, &rdata);
3285 			isc_buffer_init(&b, rdata.data, rdata.length);
3286 			isc_buffer_add(&b, rdata.length);
3287 
3288 			result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3289 						 &b, view->mctx, &key);
3290 			if (result != ISC_R_SUCCESS)
3291 				continue;
3292 			if (dst_key_alg(key) != sig.algorithm ||
3293 			    dst_key_id(key) != sig.keyid ||
3294 			    !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3295 			      dst_key_proto(key) == DNS_KEYPROTO_ANY))
3296 			{
3297 				dst_key_free(&key);
3298 				continue;
3299 			}
3300 			result = dns_dnssec_verifymessage(&msgb, msg, key);
3301 			dst_key_free(&key);
3302 			if (result == ISC_R_SUCCESS)
3303 				break;
3304 		}
3305 		if (result == ISC_R_NOMORE)
3306 			result = DNS_R_KEYUNAUTHORIZED;
3307 
3308  freesig:
3309 		if (dns_rdataset_isassociated(&keyset))
3310 			dns_rdataset_disassociate(&keyset);
3311 		dns_rdata_freestruct(&sig);
3312 		return (result);
3313 	}
3314 }
3315 
3316 #define INDENT(sp) \
3317 	do { \
3318 		unsigned int __i; \
3319 		dns_masterstyle_flags_t  __flags = dns_master_styleflags(sp); \
3320 		if ((__flags & DNS_STYLEFLAG_INDENT) == 0ULL && \
3321 		    (__flags & DNS_STYLEFLAG_YAML) == 0ULL) \
3322 			break; \
3323 		for (__i = 0; __i < msg->indent.count; __i++) { \
3324 			ADD_STRING(target, msg->indent.string); \
3325 		} \
3326 	} while (0)
3327 
3328 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)3329 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3330 			  const dns_master_style_t *style,
3331 			  dns_messagetextflag_t flags,
3332 			  isc_buffer_t *target) {
3333 	dns_name_t *name, empty_name;
3334 	dns_rdataset_t *rdataset;
3335 	isc_result_t result = ISC_R_SUCCESS;
3336 	bool seensoa = false;
3337 	unsigned int saveindent;
3338 	dns_masterstyle_flags_t sflags;
3339 
3340 	REQUIRE(DNS_MESSAGE_VALID(msg));
3341 	REQUIRE(target != NULL);
3342 	REQUIRE(VALID_SECTION(section));
3343 
3344 	saveindent = msg->indent.count;
3345 	sflags = dns_master_styleflags(style);
3346 	if (ISC_LIST_EMPTY(msg->sections[section]))
3347 		goto cleanup;
3348 
3349 
3350 	INDENT(style);
3351 	if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3352 		if (msg->opcode != dns_opcode_update) {
3353 			ADD_STRING(target, sectiontext[section]);
3354 		} else {
3355 			ADD_STRING(target, updsectiontext[section]);
3356 		}
3357 		ADD_STRING(target, "_SECTION:\n");
3358 	} else if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3359 		ADD_STRING(target, ";; ");
3360 		if (msg->opcode != dns_opcode_update) {
3361 			ADD_STRING(target, sectiontext[section]);
3362 		} else {
3363 			ADD_STRING(target, updsectiontext[section]);
3364 		}
3365 		ADD_STRING(target, " SECTION:\n");
3366 	}
3367 
3368 	dns_name_init(&empty_name, NULL);
3369 	result = dns_message_firstname(msg, section);
3370 	if (result != ISC_R_SUCCESS) {
3371 		goto cleanup;
3372 	}
3373 	if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3374 		msg->indent.count++;
3375 	}
3376 	do {
3377 		name = NULL;
3378 		dns_message_currentname(msg, section, &name);
3379 		for (rdataset = ISC_LIST_HEAD(name->list);
3380 		     rdataset != NULL;
3381 		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
3382 			if (section == DNS_SECTION_ANSWER &&
3383 			    rdataset->type == dns_rdatatype_soa) {
3384 				if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3385 					continue;
3386 				if (seensoa &&
3387 				    (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3388 					continue;
3389 				seensoa = true;
3390 			}
3391 			if (section == DNS_SECTION_QUESTION) {
3392 				INDENT(style);
3393 				if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3394 					ADD_STRING(target, "- ");
3395 				} else {
3396 					ADD_STRING(target, ";");
3397 				}
3398 				result = dns_master_questiontotext(name,
3399 								   rdataset,
3400 								   style,
3401 								   target);
3402 			} else {
3403 				result = dns_master_rdatasettotext(name,
3404 								   rdataset,
3405 								   style,
3406 								   target);
3407 			}
3408 			if (result != ISC_R_SUCCESS)
3409 				goto cleanup;
3410 		}
3411 		result = dns_message_nextname(msg, section);
3412 	} while (result == ISC_R_SUCCESS);
3413 	if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3414 		msg->indent.count--;
3415 	}
3416 	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3417 	    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0 &&
3418 	    (sflags & DNS_STYLEFLAG_YAML) == 0)
3419 	{
3420 		INDENT(style);
3421 		ADD_STRING(target, "\n");
3422 	}
3423 	if (result == ISC_R_NOMORE)
3424 		result = ISC_R_SUCCESS;
3425 
3426  cleanup:
3427 	msg->indent.count = saveindent;
3428 	return (result);
3429 }
3430 
3431 static isc_result_t
render_ecs(isc_buffer_t * ecsbuf,isc_buffer_t * target)3432 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
3433 	int i;
3434 	char addr[16], addr_text[64];
3435 	uint16_t family;
3436 	uint8_t addrlen, addrbytes, scopelen;
3437 	isc_result_t result;
3438 
3439 	/*
3440 	 * Note: This routine needs to handle malformed ECS options.
3441 	 */
3442 
3443 	if (isc_buffer_remaininglength(ecsbuf) < 4)
3444 		return (DNS_R_OPTERR);
3445 	family = isc_buffer_getuint16(ecsbuf);
3446 	addrlen = isc_buffer_getuint8(ecsbuf);
3447 	scopelen = isc_buffer_getuint8(ecsbuf);
3448 
3449 	addrbytes = (addrlen + 7) / 8;
3450 	if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
3451 		return (DNS_R_OPTERR);
3452 
3453 	if (addrbytes > sizeof(addr))
3454 		return (DNS_R_OPTERR);
3455 
3456 	memset(addr, 0, sizeof(addr));
3457 	for (i = 0; i < addrbytes; i ++)
3458 		addr[i] = isc_buffer_getuint8(ecsbuf);
3459 
3460 	switch (family) {
3461 	case 0:
3462 		if (addrlen != 0U || scopelen != 0U)
3463 			return (DNS_R_OPTERR);
3464 		strlcpy(addr_text, "0", sizeof(addr_text));
3465 		break;
3466 	case 1:
3467 		if (addrlen > 32 || scopelen > 32)
3468 			return (DNS_R_OPTERR);
3469 		inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
3470 		break;
3471 	case 2:
3472 		if (addrlen > 128 || scopelen > 128)
3473 			return (DNS_R_OPTERR);
3474 		inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
3475 		break;
3476 	default:
3477 		return (DNS_R_OPTERR);
3478 	}
3479 
3480 	ADD_STRING(target, ": ");
3481 	ADD_STRING(target, addr_text);
3482 	snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
3483 	ADD_STRING(target, addr_text);
3484 
3485 	result = ISC_R_SUCCESS;
3486 
3487  cleanup:
3488 	return (result);
3489 }
3490 
3491 static isc_result_t
render_llq(isc_buffer_t * optbuf,isc_buffer_t * target)3492 render_llq(isc_buffer_t *optbuf, isc_buffer_t *target) {
3493 	char buf[sizeof("18446744073709551615")]; /* 2^64-1 */
3494 	isc_result_t result = ISC_R_SUCCESS;
3495 	uint32_t u;
3496 	uint64_t q;
3497 
3498 	u = isc_buffer_getuint16(optbuf);
3499 	ADD_STRING(target, " Version: ");
3500 	snprintf(buf, sizeof(buf), "%u", u);
3501 	ADD_STRING(target, buf);
3502 
3503 	u = isc_buffer_getuint16(optbuf);
3504 	ADD_STRING(target, ", Opcode: ");
3505 	snprintf(buf, sizeof(buf), "%u", u);
3506 	ADD_STRING(target, buf);
3507 
3508 	u = isc_buffer_getuint16(optbuf);
3509 	ADD_STRING(target, ", Error: ");
3510 	snprintf(buf, sizeof(buf), "%u", u);
3511 	ADD_STRING(target, buf);
3512 
3513 	q = isc_buffer_getuint32(optbuf);
3514 	q <<= 32;
3515 	q |= isc_buffer_getuint32(optbuf);
3516 	ADD_STRING(target, ", Identifier: ");
3517 	snprintf(buf, sizeof(buf), "%" PRIu64, q);
3518 	ADD_STRING(target, buf);
3519 
3520 	u = isc_buffer_getuint32(optbuf);
3521 	ADD_STRING(target, ", Lifetime: ");
3522 	snprintf(buf, sizeof(buf), "%u", u);
3523 	ADD_STRING(target, buf);
3524  cleanup:
3525 	return (result);
3526 }
3527 
3528 static isc_result_t
dns_message_pseudosectiontoyaml(dns_message_t * msg,dns_pseudosection_t section,const dns_master_style_t * style,dns_messagetextflag_t flags,isc_buffer_t * target)3529 dns_message_pseudosectiontoyaml(dns_message_t *msg,
3530 				dns_pseudosection_t section,
3531 				const dns_master_style_t *style,
3532 				dns_messagetextflag_t flags,
3533 				isc_buffer_t *target)
3534 {
3535 	dns_rdataset_t *ps = NULL;
3536 	dns_name_t *name = NULL;
3537 	isc_result_t result = ISC_R_SUCCESS;
3538 	char buf[sizeof("1234567890")];
3539 	uint32_t mbz;
3540 	dns_rdata_t rdata;
3541 	isc_buffer_t optbuf;
3542 	uint16_t optcode, optlen;
3543 	unsigned char *optdata;
3544 	unsigned int saveindent = msg->indent.count;
3545 	unsigned int optindent;
3546 
3547 	REQUIRE(DNS_MESSAGE_VALID(msg));
3548 	REQUIRE(target != NULL);
3549 	REQUIRE(VALID_PSEUDOSECTION(section));
3550 
3551 	switch (section) {
3552 	case DNS_PSEUDOSECTION_OPT:
3553 		ps = dns_message_getopt(msg);
3554 		if (ps == NULL) {
3555 			goto cleanup;
3556 		}
3557 
3558 		INDENT(style);
3559 		ADD_STRING(target, "OPT_PSEUDOSECTION:\n");
3560 		msg->indent.count++;
3561 
3562 		INDENT(style);
3563 		ADD_STRING(target, "EDNS:\n");
3564 		msg->indent.count++;
3565 
3566 		INDENT(style);
3567 		ADD_STRING(target, "version: ");
3568 		snprintf(buf, sizeof(buf), "%u",
3569 			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3570 		ADD_STRING(target, buf);
3571 		ADD_STRING(target, "\n");
3572 		INDENT(style);
3573 		ADD_STRING(target, "flags:");
3574 		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3575 			ADD_STRING(target, " do");
3576 		ADD_STRING(target, "\n");
3577 		mbz = ps->ttl & 0xffff;
3578 		mbz &= ~DNS_MESSAGEEXTFLAG_DO;		/* Known Flags. */
3579 		if (mbz != 0) {
3580 			INDENT(style);
3581 			ADD_STRING(target, "MBZ: ");
3582 			snprintf(buf, sizeof(buf), "0x%.4x", mbz);
3583 			ADD_STRING(target, buf);
3584 			ADD_STRING(target, "\n");
3585 		}
3586 		INDENT(style);
3587 		ADD_STRING(target, "udp: ");
3588 		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3589 		ADD_STRING(target, buf);
3590 		result = dns_rdataset_first(ps);
3591 		if (result != ISC_R_SUCCESS) {
3592 			result = ISC_R_SUCCESS;
3593 			goto cleanup;
3594 		}
3595 
3596 		/*
3597 		 * Print EDNS info, if any.
3598 		 *
3599 		 * WARNING: The option contents may be malformed as
3600 		 * dig +ednsopt=value:<content> does not perform validity
3601 		 * checking.
3602 		 */
3603 		dns_rdata_init(&rdata);
3604 		dns_rdataset_current(ps, &rdata);
3605 
3606 		isc_buffer_init(&optbuf, rdata.data, rdata.length);
3607 		isc_buffer_add(&optbuf, rdata.length);
3608 		optindent = msg->indent.count;
3609 		while (isc_buffer_remaininglength(&optbuf) != 0) {
3610 			bool extra_text = false;
3611 			msg->indent.count = optindent;
3612 			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3613 			optcode = isc_buffer_getuint16(&optbuf);
3614 			optlen = isc_buffer_getuint16(&optbuf);
3615 			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3616 
3617 			if (optcode == DNS_OPT_LLQ) {
3618 				INDENT(style);
3619 				if (optlen == 18U) {
3620 					ADD_STRING(target, "LLQ: ");
3621 					result = render_llq(&optbuf, target);
3622 					if (result != ISC_R_SUCCESS) {
3623 						goto cleanup;
3624 					}
3625 					ADD_STRING(target, "\n");
3626 					continue;
3627 				}
3628 				ADD_STRING(target, "LLQ");
3629 			} else if (optcode == DNS_OPT_NSID) {
3630 				INDENT(style);
3631 				ADD_STRING(target, "NSID");
3632 			} else if (optcode == DNS_OPT_COOKIE) {
3633 				INDENT(style);
3634 				ADD_STRING(target, "COOKIE");
3635 			} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
3636 				isc_buffer_t ecsbuf;
3637 				INDENT(style);
3638 				ADD_STRING(target, "CLIENT-SUBNET");
3639 				isc_buffer_init(&ecsbuf,
3640 						isc_buffer_current(&optbuf),
3641 						optlen);
3642 				isc_buffer_add(&ecsbuf, optlen);
3643 				result = render_ecs(&ecsbuf, target);
3644 				if (result == ISC_R_NOSPACE)
3645 					goto cleanup;
3646 				if (result == ISC_R_SUCCESS) {
3647 					isc_buffer_forward(&optbuf, optlen);
3648 					ADD_STRING(target, "\n");
3649 					continue;
3650 				}
3651 				ADD_STRING(target, "\n");
3652 			} else if (optcode == DNS_OPT_EXPIRE) {
3653 				if (optlen == 4) {
3654 					uint32_t secs;
3655 					secs = isc_buffer_getuint32(&optbuf);
3656 					INDENT(style);
3657 					ADD_STRING(target, "EXPIRE: ");
3658 					snprintf(buf, sizeof(buf), "%u", secs);
3659 					ADD_STRING(target, buf);
3660 					ADD_STRING(target, " (");
3661 					result = dns_ttl_totext(secs,
3662 								true,
3663 								target);
3664 					if (result != ISC_R_SUCCESS)
3665 						goto cleanup;
3666 					ADD_STRING(target, ")\n");
3667 					continue;
3668 				}
3669 				INDENT(style);
3670 				ADD_STRING(target, "EXPIRE");
3671 			} else if (optcode == DNS_OPT_PAD) {
3672 				INDENT(style);
3673 				ADD_STRING(target, "PAD");
3674 			} else if (optcode == DNS_OPT_KEY_TAG) {
3675 				INDENT(style);
3676 				ADD_STRING(target, "KEY-TAG");
3677 				if (optlen > 0U && (optlen % 2U) == 0U) {
3678 					const char *sep = ": ";
3679 					uint16_t id;
3680 					while (optlen > 0U) {
3681 					    id = isc_buffer_getuint16(&optbuf);
3682 					    snprintf(buf, sizeof(buf), "%s%u",
3683 						     sep, id);
3684 					    ADD_STRING(target, buf);
3685 					    sep = ", ";
3686 					    optlen -= 2;
3687 					}
3688 					ADD_STRING(target, "\n");
3689 					continue;
3690 				}
3691 			} else if (optcode == DNS_OPT_EDE) {
3692 				INDENT(style);
3693 				ADD_STRING(target, "EDE");
3694 				if (optlen >= 2U) {
3695 					uint16_t ede;
3696 					ADD_STRING(target, ":\n");
3697 					msg->indent.count++;
3698 					INDENT(style);
3699 					ADD_STRING(target, "INFO-CODE:");
3700 					ede = isc_buffer_getuint16(&optbuf);
3701 					snprintf(buf, sizeof(buf), " %u", ede);
3702 					ADD_STRING(target, buf);
3703 					if (ede < ARRAY_SIZE(edetext)) {
3704 						ADD_STRING(target, " (");
3705 						ADD_STRING(target,
3706 							   edetext[ede]);
3707 						ADD_STRING(target, ")");
3708 					}
3709 					ADD_STRING(target, "\n");
3710 					optlen -= 2;
3711 					if (optlen != 0) {
3712 						INDENT(style);
3713 						ADD_STRING(target,
3714 							   "EXTRA-TEXT");
3715 						extra_text = true;
3716 					}
3717 				}
3718 			} else if (optcode == DNS_OPT_CLIENT_TAG) {
3719 				uint16_t id;
3720 				INDENT(style);
3721 				ADD_STRING(target, "CLIENT-TAG");
3722 				if (optlen == 2U) {
3723 					id = isc_buffer_getuint16(&optbuf);
3724 					snprintf(buf, sizeof(buf), ": %u\n",
3725 						 id);
3726 					ADD_STRING(target, buf);
3727 					optlen -= 2;
3728 					POST(optlen);
3729 					continue;
3730 				}
3731 			} else if (optcode == DNS_OPT_SERVER_TAG) {
3732 				uint16_t id;
3733 				INDENT(style);
3734 				ADD_STRING(target, "SERVER-TAG");
3735 				if (optlen == 2U) {
3736 					id = isc_buffer_getuint16(&optbuf);
3737 					snprintf(buf, sizeof(buf), ": %u\n",
3738 						 id);
3739 					ADD_STRING(target, buf);
3740 					optlen -= 2;
3741 					POST(optlen);
3742 					continue;
3743 				}
3744 			} else {
3745 				INDENT(style);
3746 				ADD_STRING(target, "OPT: ");
3747 				snprintf(buf, sizeof(buf), "%u", optcode);
3748 				ADD_STRING(target, buf);
3749 				ADD_STRING(target, "\n");
3750 			}
3751 
3752 			if (optlen != 0) {
3753 				int i;
3754 				bool utf8ok = false;
3755 
3756 				ADD_STRING(target, ": ");
3757 
3758 				optdata = isc_buffer_current(&optbuf);
3759 				if (extra_text) {
3760 					utf8ok = isc_utf8_valid(optdata,
3761 								optlen);
3762 				}
3763 				if (!utf8ok) {
3764 					for (i = 0; i < optlen; i++) {
3765 						const char *sep;
3766 						switch (optcode) {
3767 						case DNS_OPT_COOKIE:
3768 							sep = "";
3769 							break;
3770 						default:
3771 							sep = " ";
3772 							break;
3773 						}
3774 						snprintf(buf, sizeof(buf),
3775 							 "%02x%s", optdata[i],
3776 							 sep);
3777 						ADD_STRING(target, buf);
3778 					}
3779 				}
3780 
3781 				isc_buffer_forward(&optbuf, optlen);
3782 
3783 				if (optcode == DNS_OPT_COOKIE) {
3784 					/*
3785 					 * Valid server cookie?
3786 					 */
3787 					if (msg->cc_ok && optlen >= 16)
3788 						ADD_STRING(target, " (good)");
3789 					/*
3790 					 * Server cookie is not valid but
3791 					 * we had our cookie echoed back.
3792 					 */
3793 					if (msg->cc_ok && optlen < 16)
3794 						ADD_STRING(target, " (echoed)");
3795 					/*
3796 					 * We didn't get our cookie echoed
3797 					 * back.
3798 					 */
3799 					if (msg->cc_bad)
3800 						ADD_STRING(target, " (bad)");
3801 					ADD_STRING(target, "\n");
3802 					continue;
3803 				}
3804 
3805 				if (optcode == DNS_OPT_CLIENT_SUBNET) {
3806 					ADD_STRING(target, "\n");
3807 					continue;
3808 				}
3809 
3810 				/*
3811 				 * For non-COOKIE options, add a printable
3812 				 * version
3813 				 */
3814 				if (!extra_text) {
3815 					ADD_STRING(target, "(\"");
3816 				} else {
3817 					ADD_STRING(target, "\"");
3818 				}
3819 				if (isc_buffer_availablelength(target) < optlen)
3820 				{
3821 					result = ISC_R_NOSPACE;
3822 					goto cleanup;
3823 				}
3824 				for (i = 0; i < optlen; i++) {
3825 					if (isprint(optdata[i]) ||
3826 					    (utf8ok && optdata[i] > 127)) {
3827 						isc_buffer_putmem(
3828 							target, &optdata[i], 1);
3829 					} else {
3830 						isc_buffer_putstr(target, ".");
3831 					}
3832 				}
3833 				if (!extra_text) {
3834 					ADD_STRING(target, "\")");
3835 				} else {
3836 					ADD_STRING(target, "\"");
3837 				}
3838 			}
3839 			ADD_STRING(target, "\n");
3840 		}
3841 		msg->indent.count = optindent;
3842 		result = ISC_R_SUCCESS;
3843 		goto cleanup;
3844 	case DNS_PSEUDOSECTION_TSIG:
3845 		ps = dns_message_gettsig(msg, &name);
3846 		if (ps == NULL) {
3847 			result = ISC_R_SUCCESS;
3848 			goto cleanup;
3849 		}
3850 		INDENT(style);
3851 		ADD_STRING(target, "TSIG_PSEUDOSECTION:\n");
3852 		result = dns_master_rdatasettotext(name, ps, style, target);
3853 		ADD_STRING(target, "\n");
3854 		goto cleanup;
3855 	case DNS_PSEUDOSECTION_SIG0:
3856 		ps = dns_message_getsig0(msg, &name);
3857 		if (ps == NULL) {
3858 			result = ISC_R_SUCCESS;
3859 			goto cleanup;
3860 		}
3861 		INDENT(style);
3862 		ADD_STRING(target, "SIG0_PSEUDOSECTION:\n");
3863 		result = dns_master_rdatasettotext(name, ps, style, target);
3864 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3865 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3866 			ADD_STRING(target, "\n");
3867 		goto cleanup;
3868 	}
3869 
3870 	result = ISC_R_UNEXPECTED;
3871 
3872  cleanup:
3873 	msg->indent.count = saveindent;
3874 	return (result);
3875 }
3876 
3877 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)3878 dns_message_pseudosectiontotext(dns_message_t *msg,
3879 				dns_pseudosection_t section,
3880 				const dns_master_style_t *style,
3881 				dns_messagetextflag_t flags,
3882 				isc_buffer_t *target)
3883 {
3884 	dns_rdataset_t *ps = NULL;
3885 	dns_name_t *name = NULL;
3886 	isc_result_t result;
3887 	char buf[sizeof("1234567890 ")];
3888 	uint32_t mbz;
3889 	dns_rdata_t rdata;
3890 	isc_buffer_t optbuf;
3891 	uint16_t optcode, optlen;
3892 	unsigned char *optdata;
3893 
3894 	REQUIRE(DNS_MESSAGE_VALID(msg));
3895 	REQUIRE(target != NULL);
3896 	REQUIRE(VALID_PSEUDOSECTION(section));
3897 
3898 	if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0)
3899 		return (dns_message_pseudosectiontoyaml(msg, section, style,
3900 							flags, target));
3901 	switch (section) {
3902 	case DNS_PSEUDOSECTION_OPT:
3903 		ps = dns_message_getopt(msg);
3904 		if (ps == NULL)
3905 			return (ISC_R_SUCCESS);
3906 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3907 			INDENT(style);
3908 			ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3909 		}
3910 
3911 		INDENT(style);
3912 		ADD_STRING(target, "; EDNS: version: ");
3913 		snprintf(buf, sizeof(buf), "%u",
3914 			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3915 		ADD_STRING(target, buf);
3916 		ADD_STRING(target, ", flags:");
3917 		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3918 			ADD_STRING(target, " do");
3919 		mbz = ps->ttl & 0xffff;
3920 		mbz &= ~DNS_MESSAGEEXTFLAG_DO;		/* Known Flags. */
3921 		if (mbz != 0) {
3922 			ADD_STRING(target, "; MBZ: ");
3923 			snprintf(buf, sizeof(buf), "0x%.4x", mbz);
3924 			ADD_STRING(target, buf);
3925 			ADD_STRING(target, ", udp: ");
3926 		} else
3927 			ADD_STRING(target, "; udp: ");
3928 		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3929 		ADD_STRING(target, buf);
3930 
3931 		result = dns_rdataset_first(ps);
3932 		if (result != ISC_R_SUCCESS)
3933 			return (ISC_R_SUCCESS);
3934 
3935 		/*
3936 		 * Print EDNS info, if any.
3937 		 *
3938 		 * WARNING: The option contents may be malformed as
3939 		 * dig +ednsopt=value:<content> does not validity
3940 		 * checking.
3941 		 */
3942 		dns_rdata_init(&rdata);
3943 		dns_rdataset_current(ps, &rdata);
3944 
3945 		isc_buffer_init(&optbuf, rdata.data, rdata.length);
3946 		isc_buffer_add(&optbuf, rdata.length);
3947 		while (isc_buffer_remaininglength(&optbuf) != 0) {
3948 			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3949 			optcode = isc_buffer_getuint16(&optbuf);
3950 			optlen = isc_buffer_getuint16(&optbuf);
3951 			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3952 
3953 			INDENT(style);
3954 
3955 			if (optcode == DNS_OPT_LLQ) {
3956 				if (optlen == 18U) {
3957 					ADD_STRING(target, "; LLQ:");
3958 					result = render_llq(&optbuf, target);
3959 					if (result != ISC_R_SUCCESS) {
3960 						return (result);
3961 					}
3962 					ADD_STRING(target, "\n");
3963 					continue;
3964 				}
3965 				ADD_STRING(target, "; LLQ");
3966 			} else if (optcode == DNS_OPT_NSID) {
3967 				ADD_STRING(target, "; NSID");
3968 			} else if (optcode == DNS_OPT_COOKIE) {
3969 				ADD_STRING(target, "; COOKIE");
3970 			} else if (optcode == DNS_OPT_CLIENT_SUBNET) {
3971 				isc_buffer_t ecsbuf;
3972 
3973 				ADD_STRING(target, "; CLIENT-SUBNET");
3974 				isc_buffer_init(&ecsbuf,
3975 						isc_buffer_current(&optbuf),
3976 						optlen);
3977 				isc_buffer_add(&ecsbuf, optlen);
3978 				result = render_ecs(&ecsbuf, target);
3979 				if (result == ISC_R_NOSPACE)
3980 					return (result);
3981 				if (result == ISC_R_SUCCESS) {
3982 					isc_buffer_forward(&optbuf, optlen);
3983 					ADD_STRING(target, "\n");
3984 					continue;
3985 				}
3986 			} else if (optcode == DNS_OPT_EXPIRE) {
3987 				if (optlen == 4) {
3988 					uint32_t secs;
3989 					secs = isc_buffer_getuint32(&optbuf);
3990 					ADD_STRING(target, "; EXPIRE: ");
3991 					snprintf(buf, sizeof(buf), "%u", secs);
3992 					ADD_STRING(target, buf);
3993 					ADD_STRING(target, " (");
3994 					result = dns_ttl_totext(secs,
3995 								true,
3996 								target);
3997 					if (result != ISC_R_SUCCESS)
3998 						return (result);
3999 					ADD_STRING(target, ")\n");
4000 					continue;
4001 				}
4002 				ADD_STRING(target, "; EXPIRE");
4003 			} else if (optcode == DNS_OPT_PAD) {
4004 				ADD_STRING(target, "; PAD");
4005 			} else if (optcode == DNS_OPT_KEY_TAG) {
4006 				ADD_STRING(target, "; KEY-TAG");
4007 				if (optlen > 0U && (optlen % 2U) == 0U) {
4008 					const char *sep = ": ";
4009 					uint16_t id;
4010 					while (optlen > 0U) {
4011 					    id = isc_buffer_getuint16(&optbuf);
4012 					    snprintf(buf, sizeof(buf), "%s%u",
4013 						     sep, id);
4014 					    ADD_STRING(target, buf);
4015 					    sep = ", ";
4016 					    optlen -= 2;
4017 					}
4018 					ADD_STRING(target, "\n");
4019 					continue;
4020 				}
4021 			} else if (optcode == DNS_OPT_EDE) {
4022 				ADD_STRING(target, "; EDE");
4023 				if (optlen >= 2U) {
4024 					uint16_t ede;
4025 					ede = isc_buffer_getuint16(&optbuf);
4026 					snprintf(buf, sizeof(buf), ": %u", ede);
4027 					ADD_STRING(target, buf);
4028 					if (ede < ARRAY_SIZE(edetext)) {
4029 						ADD_STRING(target, " (");
4030 						ADD_STRING(target,
4031 							   edetext[ede]);
4032 						ADD_STRING(target, ")");
4033 					}
4034 					optlen -= 2;
4035 				} else if (optlen == 1U) {
4036 					/* Malformed */
4037 					optdata = isc_buffer_current(&optbuf);
4038 					snprintf(buf, sizeof(buf),
4039 						 ": %02x (\"%c\")\n",
4040 						 optdata[0],
4041 						 isprint(optdata[0])
4042 							 ? optdata[0]
4043 							 : '.');
4044 					isc_buffer_forward(&optbuf, optlen);
4045 					ADD_STRING(target, buf);
4046 					continue;
4047 				}
4048 			} else if (optcode == DNS_OPT_CLIENT_TAG) {
4049 				uint16_t id;
4050 				ADD_STRING(target, "; CLIENT-TAG");
4051 				if (optlen == 2U) {
4052 					id = isc_buffer_getuint16(&optbuf);
4053 					snprintf(buf, sizeof(buf), ": %u\n",
4054 						 id);
4055 					ADD_STRING(target, buf);
4056 					optlen -= 2;
4057 					POST(optlen);
4058 					continue;
4059 				}
4060 			} else if (optcode == DNS_OPT_SERVER_TAG) {
4061 				uint16_t id;
4062 				ADD_STRING(target, "; SERVER-TAG");
4063 				if (optlen == 2U) {
4064 					id = isc_buffer_getuint16(&optbuf);
4065 					snprintf(buf, sizeof(buf), ": %u\n",
4066 						 id);
4067 					ADD_STRING(target, buf);
4068 					optlen -= 2;
4069 					POST(optlen);
4070 					continue;
4071 				}
4072 			} else {
4073 				ADD_STRING(target, "; OPT=");
4074 				snprintf(buf, sizeof(buf), "%u", optcode);
4075 				ADD_STRING(target, buf);
4076 			}
4077 
4078 			if (optlen != 0) {
4079 				int i;
4080 				bool utf8ok = false;
4081 				ADD_STRING(target, ": ");
4082 
4083 				optdata = isc_buffer_current(&optbuf);
4084 				if (optcode == DNS_OPT_EDE) {
4085 					utf8ok = isc_utf8_valid(optdata,
4086 								optlen);
4087 				}
4088 				if (!utf8ok) {
4089 					for (i = 0; i < optlen; i++) {
4090 						const char *sep;
4091 						switch (optcode) {
4092 						case DNS_OPT_COOKIE:
4093 							sep = "";
4094 							break;
4095 						default:
4096 							sep = " ";
4097 							break;
4098 						}
4099 						snprintf(buf, sizeof(buf),
4100 							 "%02x%s", optdata[i],
4101 							 sep);
4102 						ADD_STRING(target, buf);
4103 					}
4104 				}
4105 
4106 				isc_buffer_forward(&optbuf, optlen);
4107 
4108 				if (optcode == DNS_OPT_COOKIE) {
4109 					/*
4110 					 * Valid server cookie?
4111 					 */
4112 					if (msg->cc_ok && optlen >= 16)
4113 						ADD_STRING(target, " (good)");
4114 					/*
4115 					 * Server cookie is not valid but
4116 					 * we had our cookie echoed back.
4117 					 */
4118 					if (msg->cc_ok && optlen < 16)
4119 						ADD_STRING(target, " (echoed)");
4120 					/*
4121 					 * We didn't get our cookie echoed
4122 					 * back.
4123 					 */
4124 					if (msg->cc_bad)
4125 						ADD_STRING(target, " (bad)");
4126 					ADD_STRING(target, "\n");
4127 					continue;
4128 				}
4129 
4130 				if (optcode == DNS_OPT_CLIENT_SUBNET) {
4131 					ADD_STRING(target, "\n");
4132 					continue;
4133 				}
4134 
4135 				/*
4136 				 * For non-COOKIE options, add a printable
4137 				 * version.
4138 				 */
4139 				if (optcode != DNS_OPT_EDE) {
4140 					ADD_STRING(target, "(\"");
4141 				} else {
4142 					ADD_STRING(target, "(");
4143 				}
4144 				if (isc_buffer_availablelength(target) < optlen)
4145 					return (ISC_R_NOSPACE);
4146 				for (i = 0; i < optlen; i++) {
4147 					if (isprint(optdata[i]) ||
4148 					    (utf8ok && optdata[i] > 127)) {
4149 						isc_buffer_putmem(
4150 							target, &optdata[i], 1);
4151 					} else {
4152 						isc_buffer_putstr(target, ".");
4153 					}
4154 				}
4155 				if (optcode != DNS_OPT_EDE) {
4156 					ADD_STRING(target, "\")");
4157 				} else {
4158 					ADD_STRING(target, ")");
4159 				}
4160 			}
4161 			ADD_STRING(target, "\n");
4162 		}
4163 		return (ISC_R_SUCCESS);
4164 	case DNS_PSEUDOSECTION_TSIG:
4165 		ps = dns_message_gettsig(msg, &name);
4166 		if (ps == NULL)
4167 			return (ISC_R_SUCCESS);
4168 		INDENT(style);
4169 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4170 			ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
4171 		result = dns_master_rdatasettotext(name, ps, style, target);
4172 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
4173 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4174 			ADD_STRING(target, "\n");
4175 		return (result);
4176 	case DNS_PSEUDOSECTION_SIG0:
4177 		ps = dns_message_getsig0(msg, &name);
4178 		if (ps == NULL)
4179 			return (ISC_R_SUCCESS);
4180 		INDENT(style);
4181 		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4182 			ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
4183 		result = dns_master_rdatasettotext(name, ps, style, target);
4184 		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
4185 		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4186 			ADD_STRING(target, "\n");
4187 		return (result);
4188 	}
4189 	result = ISC_R_UNEXPECTED;
4190  cleanup:
4191 	return (result);
4192 }
4193 
4194 isc_result_t
dns_message_totext(dns_message_t * msg,const dns_master_style_t * style,dns_messagetextflag_t flags,isc_buffer_t * target)4195 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
4196 		   dns_messagetextflag_t flags, isc_buffer_t *target)
4197 {
4198 	char buf[sizeof("1234567890")];
4199 	isc_result_t result;
4200 
4201 	REQUIRE(DNS_MESSAGE_VALID(msg));
4202 	REQUIRE(target != NULL);
4203 
4204 	if (((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) &&
4205 	     (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML))
4206 	{
4207 		INDENT(style);
4208 		ADD_STRING(target, "opcode: ");
4209 		ADD_STRING(target, opcodetext[msg->opcode]);
4210 		ADD_STRING(target, "\n");
4211 		INDENT(style);
4212 		ADD_STRING(target, "status: ");
4213 		result = dns_rcode_totext(msg->rcode, target);
4214 		if (result != ISC_R_SUCCESS)
4215 			return (result);
4216 		ADD_STRING(target, "\n");
4217 		INDENT(style);
4218 		ADD_STRING(target, "id: ");
4219 		snprintf(buf, sizeof(buf), "%6u", msg->id);
4220 		ADD_STRING(target, buf);
4221 		ADD_STRING(target, "\n");
4222 		INDENT(style);
4223 		ADD_STRING(target, "flags:");
4224 		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
4225 			ADD_STRING(target, " qr");
4226 		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
4227 			ADD_STRING(target, " aa");
4228 		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
4229 			ADD_STRING(target, " tc");
4230 		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
4231 			ADD_STRING(target, " rd");
4232 		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
4233 			ADD_STRING(target, " ra");
4234 		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
4235 			ADD_STRING(target, " ad");
4236 		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
4237 			ADD_STRING(target, " cd");
4238 		ADD_STRING(target, "\n");
4239 		/*
4240 		 * The final unnamed flag must be zero.
4241 		 */
4242 		if ((msg->flags & 0x0040U) != 0) {
4243 			INDENT(style);
4244 			ADD_STRING(target, "MBZ: 0x4");
4245 			ADD_STRING(target, "\n");
4246 		}
4247 		if (msg->opcode != dns_opcode_update) {
4248 			INDENT(style);
4249 			ADD_STRING(target, "QUESTION: ");
4250 		} else {
4251 			ADD_STRING(target, "ZONE: ");
4252 		}
4253 		snprintf(buf, sizeof(buf), "%1u",
4254 			 msg->counts[DNS_SECTION_QUESTION]);
4255 		ADD_STRING(target, buf);
4256 		ADD_STRING(target, "\n");
4257 		if (msg->opcode != dns_opcode_update) {
4258 			INDENT(style);
4259 			ADD_STRING(target, "ANSWER: ");
4260 		} else {
4261 			INDENT(style);
4262 			ADD_STRING(target, "PREREQ: ");
4263 		}
4264 		snprintf(buf, sizeof(buf), "%1u",
4265 			 msg->counts[DNS_SECTION_ANSWER]);
4266 		ADD_STRING(target, buf);
4267 		ADD_STRING(target, "\n");
4268 		if (msg->opcode != dns_opcode_update) {
4269 			INDENT(style);
4270 			ADD_STRING(target, "AUTHORITY: ");
4271 		} else {
4272 			INDENT(style);
4273 			ADD_STRING(target, "UPDATE: ");
4274 		}
4275 		snprintf(buf, sizeof(buf), "%1u",
4276 			msg->counts[DNS_SECTION_AUTHORITY]);
4277 		ADD_STRING(target, buf);
4278 		ADD_STRING(target, "\n");
4279 		INDENT(style);
4280 		ADD_STRING(target, "ADDITIONAL: ");
4281 		snprintf(buf, sizeof(buf), "%1u",
4282 			msg->counts[DNS_SECTION_ADDITIONAL]);
4283 		ADD_STRING(target, buf);
4284 		ADD_STRING(target, "\n");
4285 	} else if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
4286 		INDENT(style);
4287 		ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
4288 		ADD_STRING(target, opcodetext[msg->opcode]);
4289 		ADD_STRING(target, ", status: ");
4290 		result = dns_rcode_totext(msg->rcode, target);
4291 		if (result != ISC_R_SUCCESS)
4292 			return (result);
4293 		ADD_STRING(target, ", id: ");
4294 		snprintf(buf, sizeof(buf), "%6u", msg->id);
4295 		ADD_STRING(target, buf);
4296 		ADD_STRING(target, "\n");
4297 		INDENT(style);
4298 		ADD_STRING(target, ";; flags:");
4299 		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
4300 			ADD_STRING(target, " qr");
4301 		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
4302 			ADD_STRING(target, " aa");
4303 		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
4304 			ADD_STRING(target, " tc");
4305 		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
4306 			ADD_STRING(target, " rd");
4307 		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
4308 			ADD_STRING(target, " ra");
4309 		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
4310 			ADD_STRING(target, " ad");
4311 		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
4312 			ADD_STRING(target, " cd");
4313 		/*
4314 		 * The final unnamed flag must be zero.
4315 		 */
4316 		if ((msg->flags & 0x0040U) != 0) {
4317 			INDENT(style);
4318 			ADD_STRING(target, "; MBZ: 0x4");
4319 		}
4320 		if (msg->opcode != dns_opcode_update) {
4321 			INDENT(style);
4322 			ADD_STRING(target, "; QUESTION: ");
4323 		} else {
4324 			INDENT(style);
4325 			ADD_STRING(target, "; ZONE: ");
4326 		}
4327 		snprintf(buf, sizeof(buf), "%1u",
4328 			 msg->counts[DNS_SECTION_QUESTION]);
4329 		ADD_STRING(target, buf);
4330 		if (msg->opcode != dns_opcode_update) {
4331 			ADD_STRING(target, ", ANSWER: ");
4332 		} else {
4333 			ADD_STRING(target, ", PREREQ: ");
4334 		}
4335 		snprintf(buf, sizeof(buf), "%1u",
4336 			 msg->counts[DNS_SECTION_ANSWER]);
4337 		ADD_STRING(target, buf);
4338 		if (msg->opcode != dns_opcode_update) {
4339 			ADD_STRING(target, ", AUTHORITY: ");
4340 		} else {
4341 			ADD_STRING(target, ", UPDATE: ");
4342 		}
4343 		snprintf(buf, sizeof(buf), "%1u",
4344 			msg->counts[DNS_SECTION_AUTHORITY]);
4345 		ADD_STRING(target, buf);
4346 		ADD_STRING(target, ", ADDITIONAL: ");
4347 		snprintf(buf, sizeof(buf), "%1u",
4348 			msg->counts[DNS_SECTION_ADDITIONAL]);
4349 		ADD_STRING(target, buf);
4350 		ADD_STRING(target, "\n");
4351 	}
4352 	result = dns_message_pseudosectiontotext(msg,
4353 						 DNS_PSEUDOSECTION_OPT,
4354 						 style, flags, target);
4355 	if (result != ISC_R_SUCCESS)
4356 		return (result);
4357 
4358 	result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
4359 					   style, flags, target);
4360 	if (result != ISC_R_SUCCESS)
4361 		return (result);
4362 	result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
4363 					   style, flags, target);
4364 	if (result != ISC_R_SUCCESS)
4365 		return (result);
4366 	result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
4367 					   style, flags, target);
4368 	if (result != ISC_R_SUCCESS)
4369 		return (result);
4370 	result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
4371 					   style, flags, target);
4372 	if (result != ISC_R_SUCCESS)
4373 		return (result);
4374 
4375 	result = dns_message_pseudosectiontotext(msg,
4376 						 DNS_PSEUDOSECTION_TSIG,
4377 						 style, flags, target);
4378 	if (result != ISC_R_SUCCESS)
4379 		return (result);
4380 
4381 	result = dns_message_pseudosectiontotext(msg,
4382 						 DNS_PSEUDOSECTION_SIG0,
4383 						 style, flags, target);
4384 	if (result != ISC_R_SUCCESS)
4385 		return (result);
4386 
4387  cleanup:
4388 	return (result);
4389 }
4390 
4391 isc_region_t *
dns_message_getrawmessage(dns_message_t * msg)4392 dns_message_getrawmessage(dns_message_t *msg) {
4393 	REQUIRE(DNS_MESSAGE_VALID(msg));
4394 	return (&msg->saved);
4395 }
4396 
4397 void
dns_message_setsortorder(dns_message_t * msg,dns_rdatasetorderfunc_t order,const void * order_arg)4398 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
4399 			 const void *order_arg)
4400 {
4401 	REQUIRE(DNS_MESSAGE_VALID(msg));
4402 	msg->order = order;
4403 	msg->order_arg = order_arg;
4404 }
4405 
4406 void
dns_message_settimeadjust(dns_message_t * msg,int timeadjust)4407 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
4408 	REQUIRE(DNS_MESSAGE_VALID(msg));
4409 	msg->timeadjust = timeadjust;
4410 }
4411 
4412 int
dns_message_gettimeadjust(dns_message_t * msg)4413 dns_message_gettimeadjust(dns_message_t *msg) {
4414 	REQUIRE(DNS_MESSAGE_VALID(msg));
4415 	return (msg->timeadjust);
4416 }
4417 
4418 isc_result_t
dns_opcode_totext(dns_opcode_t opcode,isc_buffer_t * target)4419 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
4420 
4421 	REQUIRE(opcode < 16);
4422 
4423 	if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
4424 		return (ISC_R_NOSPACE);
4425 	isc_buffer_putstr(target, opcodetext[opcode]);
4426 	return (ISC_R_SUCCESS);
4427 }
4428 
4429 void
dns_message_logpacket(dns_message_t * message,const char * description,isc_logcategory_t * category,isc_logmodule_t * module,int level,isc_mem_t * mctx)4430 dns_message_logpacket(dns_message_t *message, const char *description,
4431 		      isc_logcategory_t *category, isc_logmodule_t *module,
4432 		      int level, isc_mem_t *mctx)
4433 {
4434 	logfmtpacket(message, description, NULL, category, module,
4435 		     &dns_master_style_debug, level, mctx);
4436 }
4437 
4438 void
dns_message_logpacket2(dns_message_t * message,const char * description,isc_sockaddr_t * address,isc_logcategory_t * category,isc_logmodule_t * module,int level,isc_mem_t * mctx)4439 dns_message_logpacket2(dns_message_t *message,
4440 		       const char *description, isc_sockaddr_t *address,
4441 		       isc_logcategory_t *category, isc_logmodule_t *module,
4442 		       int level, isc_mem_t *mctx)
4443 {
4444 	REQUIRE(address != NULL);
4445 
4446 	logfmtpacket(message, description, address, category, module,
4447 		     &dns_master_style_debug, level, mctx);
4448 }
4449 
4450 void
dns_message_logfmtpacket(dns_message_t * message,const char * description,isc_logcategory_t * category,isc_logmodule_t * module,const dns_master_style_t * style,int level,isc_mem_t * mctx)4451 dns_message_logfmtpacket(dns_message_t *message, const char *description,
4452 			 isc_logcategory_t *category, isc_logmodule_t *module,
4453 			 const dns_master_style_t *style, int level,
4454 			 isc_mem_t *mctx)
4455 {
4456 	logfmtpacket(message, description, NULL, category, module, style,
4457 		     level, mctx);
4458 }
4459 
4460 void
dns_message_logfmtpacket2(dns_message_t * message,const char * description,isc_sockaddr_t * address,isc_logcategory_t * category,isc_logmodule_t * module,const dns_master_style_t * style,int level,isc_mem_t * mctx)4461 dns_message_logfmtpacket2(dns_message_t *message,
4462 			  const char *description, isc_sockaddr_t *address,
4463 			  isc_logcategory_t *category, isc_logmodule_t *module,
4464 			  const dns_master_style_t *style, int level,
4465 			  isc_mem_t *mctx)
4466 {
4467 	REQUIRE(address != NULL);
4468 
4469 	logfmtpacket(message, description, address, category, module, style,
4470 		     level, mctx);
4471 }
4472 
4473 static void
logfmtpacket(dns_message_t * message,const char * description,isc_sockaddr_t * address,isc_logcategory_t * category,isc_logmodule_t * module,const dns_master_style_t * style,int level,isc_mem_t * mctx)4474 logfmtpacket(dns_message_t *message, const char *description,
4475 	     isc_sockaddr_t *address, isc_logcategory_t *category,
4476 	     isc_logmodule_t *module, const dns_master_style_t *style,
4477 	     int level, isc_mem_t *mctx)
4478 {
4479 	char addrbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
4480 	const char *newline = "\n";
4481 	const char *space = " ";
4482 	isc_buffer_t buffer;
4483 	char *buf = NULL;
4484 	int len = 1024;
4485 	isc_result_t result;
4486 
4487 	if (! isc_log_wouldlog(dns_lctx, level))
4488 		return;
4489 
4490 	/*
4491 	 * Note that these are multiline debug messages.  We want a newline
4492 	 * to appear in the log after each message.
4493 	 */
4494 
4495 	if (address != NULL)
4496 		isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
4497 	else
4498 		newline = space = "";
4499 
4500 	do {
4501 		buf = isc_mem_get(mctx, len);
4502 		if (buf == NULL)
4503 			break;
4504 		isc_buffer_init(&buffer, buf, len);
4505 		result = dns_message_totext(message, style, 0, &buffer);
4506 		if (result == ISC_R_NOSPACE) {
4507 			isc_mem_put(mctx, buf, len);
4508 			len += 1024;
4509 		} else if (result == ISC_R_SUCCESS)
4510 			isc_log_write(dns_lctx, category, module, level,
4511 				      "%s%s%s%s%.*s", description, space,
4512 				      addrbuf, newline,
4513 				      (int)isc_buffer_usedlength(&buffer),
4514 				      buf);
4515 	} while (result == ISC_R_NOSPACE);
4516 
4517 	if (buf != NULL)
4518 		isc_mem_put(mctx, buf, len);
4519 }
4520 
4521 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)4522 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
4523 		     unsigned int version, uint16_t udpsize,
4524 		     unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
4525 {
4526 	dns_rdataset_t *rdataset = NULL;
4527 	dns_rdatalist_t *rdatalist = NULL;
4528 	dns_rdata_t *rdata = NULL;
4529 	isc_result_t result;
4530 	unsigned int len = 0, i;
4531 
4532 	REQUIRE(DNS_MESSAGE_VALID(message));
4533 	REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
4534 
4535 	result = dns_message_gettemprdatalist(message, &rdatalist);
4536 	if (result != ISC_R_SUCCESS)
4537 		return (result);
4538 	result = dns_message_gettemprdata(message, &rdata);
4539 	if (result != ISC_R_SUCCESS)
4540 		goto cleanup;
4541 	result = dns_message_gettemprdataset(message, &rdataset);
4542 	if (result != ISC_R_SUCCESS)
4543 		goto cleanup;
4544 
4545 	rdatalist->type = dns_rdatatype_opt;
4546 
4547 	/*
4548 	 * Set Maximum UDP buffer size.
4549 	 */
4550 	rdatalist->rdclass = udpsize;
4551 
4552 	/*
4553 	 * Set EXTENDED-RCODE and Z to 0.
4554 	 */
4555 	rdatalist->ttl = (version << 16);
4556 	rdatalist->ttl |= (flags & 0xffff);
4557 
4558 	/*
4559 	 * Set EDNS options if applicable
4560 	 */
4561 	if (count != 0U) {
4562 		isc_buffer_t *buf = NULL;
4563 		for (i = 0; i < count; i++)
4564 			len += ednsopts[i].length + 4;
4565 
4566 		if (len > 0xffffU) {
4567 			result = ISC_R_NOSPACE;
4568 			goto cleanup;
4569 		}
4570 
4571 		result = isc_buffer_allocate(message->mctx, &buf, len);
4572 		if (result != ISC_R_SUCCESS)
4573 			goto cleanup;
4574 
4575 		for (i = 0; i < count; i++)  {
4576 			isc_buffer_putuint16(buf, ednsopts[i].code);
4577 			isc_buffer_putuint16(buf, ednsopts[i].length);
4578 			if (ednsopts[i].length != 0) {
4579 				isc_buffer_putmem(buf, ednsopts[i].value,
4580 						  ednsopts[i].length);
4581 			}
4582 		}
4583 		rdata->data = isc_buffer_base(buf);
4584 		rdata->length = len;
4585 		dns_message_takebuffer(message, &buf);
4586 	} else {
4587 		rdata->data = NULL;
4588 		rdata->length = 0;
4589 	}
4590 
4591 	rdata->rdclass = rdatalist->rdclass;
4592 	rdata->type = rdatalist->type;
4593 	rdata->flags = 0;
4594 
4595 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
4596 	result = dns_rdatalist_tordataset(rdatalist, rdataset);
4597 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
4598 
4599 	*rdatasetp = rdataset;
4600 	return (ISC_R_SUCCESS);
4601 
4602  cleanup:
4603 	if (rdata != NULL)
4604 		dns_message_puttemprdata(message, &rdata);
4605 	if (rdataset != NULL)
4606 		dns_message_puttemprdataset(message, &rdataset);
4607 	if (rdatalist != NULL)
4608 		dns_message_puttemprdatalist(message, &rdatalist);
4609 	return (result);
4610 }
4611 
4612 void
dns_message_setclass(dns_message_t * msg,dns_rdataclass_t rdclass)4613 dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
4614 
4615 	REQUIRE(DNS_MESSAGE_VALID(msg));
4616 	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
4617 	REQUIRE(msg->state == DNS_SECTION_ANY);
4618 	REQUIRE(msg->rdclass_set == 0);
4619 
4620 	msg->rdclass = rdclass;
4621 	msg->rdclass_set = 1;
4622 }
4623