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