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