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