message.c revision 1.21 1 /* $NetBSD: message.c,v 1.21 2025/07/17 19:01:45 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(msg->buffer != NULL);
2207 REQUIRE(target != NULL);
2208
2209 isc_buffer_availableregion(target, &r);
2210 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2211
2212 isc_buffer_putuint16(target, msg->id);
2213
2214 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT) &
2215 DNS_MESSAGE_OPCODE_MASK);
2216 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2217 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2218
2219 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
2220 msg->counts[DNS_SECTION_ANSWER] < 65536 &&
2221 msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2222 msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2223
2224 isc_buffer_putuint16(target, tmp);
2225 isc_buffer_putuint16(target,
2226 (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2227 isc_buffer_putuint16(target, (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2228 isc_buffer_putuint16(target,
2229 (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2230 isc_buffer_putuint16(target,
2231 (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2232 }
2233
2234 isc_result_t
2235 dns_message_renderend(dns_message_t *msg) {
2236 isc_buffer_t tmpbuf;
2237 isc_region_t r;
2238 int result;
2239 unsigned int count;
2240
2241 REQUIRE(DNS_MESSAGE_VALID(msg));
2242 REQUIRE(msg->buffer != NULL);
2243
2244 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2245 /*
2246 * We have an extended rcode but are not using EDNS.
2247 */
2248 return DNS_R_FORMERR;
2249 }
2250
2251 /*
2252 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
2253 * clear all rdatasets from the message except for the question
2254 * before adding the OPT, TSIG or SIG(0). If the question doesn't
2255 * fit, don't include it.
2256 */
2257 if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
2258 (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2259 {
2260 isc_buffer_t *buf;
2261
2262 msgresetnames(msg, DNS_SECTION_ANSWER);
2263 buf = msg->buffer;
2264 dns_message_renderreset(msg);
2265 msg->buffer = buf;
2266 isc_buffer_clear(msg->buffer);
2267 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2268 dns_compress_rollback(msg->cctx, 0);
2269 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2270 0);
2271 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) {
2272 return result;
2273 }
2274 }
2275
2276 /*
2277 * If we've got an OPT record, render it.
2278 */
2279 if (msg->opt != NULL) {
2280 dns_message_renderrelease(msg, msg->opt_reserved);
2281 msg->opt_reserved = 0;
2282 /*
2283 * Set the extended rcode. Cast msg->rcode to dns_ttl_t
2284 * so that we do a unsigned shift.
2285 */
2286 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2287 msg->opt->ttl |= (((dns_ttl_t)(msg->rcode) << 20) &
2288 DNS_MESSAGE_EDNSRCODE_MASK);
2289 /*
2290 * Render.
2291 */
2292 count = 0;
2293 result = renderset(msg->opt, dns_rootname, msg->cctx,
2294 msg->buffer, msg->reserved, 0, &count);
2295 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2296 if (result != ISC_R_SUCCESS) {
2297 return result;
2298 }
2299 }
2300
2301 /*
2302 * Deal with EDNS padding.
2303 *
2304 * padding_off is the length of the OPT with the 0-length PAD
2305 * at the end.
2306 */
2307 if (msg->padding_off > 0) {
2308 unsigned char *cp = isc_buffer_used(msg->buffer);
2309 unsigned int used, remaining;
2310 uint16_t len, padsize = 0;
2311
2312 /* Check PAD */
2313 if ((cp[-4] != 0) || (cp[-3] != DNS_OPT_PAD) || (cp[-2] != 0) ||
2314 (cp[-1] != 0))
2315 {
2316 return ISC_R_UNEXPECTED;
2317 }
2318
2319 /*
2320 * Zero-fill the PAD to the computed size;
2321 * patch PAD length and OPT rdlength
2322 */
2323
2324 /* Aligned used length + reserved to padding block */
2325 used = isc_buffer_usedlength(msg->buffer);
2326 if (msg->padding != 0) {
2327 padsize = ((uint16_t)used + msg->reserved) %
2328 msg->padding;
2329 }
2330 if (padsize != 0) {
2331 padsize = msg->padding - padsize;
2332 }
2333 /* Stay below the available length */
2334 remaining = isc_buffer_availablelength(msg->buffer);
2335 if (padsize > remaining) {
2336 padsize = remaining;
2337 }
2338
2339 isc_buffer_add(msg->buffer, padsize);
2340 memset(cp, 0, padsize);
2341 cp[-2] = (unsigned char)((padsize & 0xff00U) >> 8);
2342 cp[-1] = (unsigned char)(padsize & 0x00ffU);
2343 cp -= msg->padding_off;
2344 len = ((uint16_t)(cp[-2])) << 8;
2345 len |= ((uint16_t)(cp[-1]));
2346 len += padsize;
2347 cp[-2] = (unsigned char)((len & 0xff00U) >> 8);
2348 cp[-1] = (unsigned char)(len & 0x00ffU);
2349 }
2350
2351 /*
2352 * If we're adding a TSIG record, generate and render it.
2353 */
2354 if (msg->tsigkey != NULL) {
2355 dns_message_renderrelease(msg, msg->sig_reserved);
2356 msg->sig_reserved = 0;
2357 result = dns_tsig_sign(msg);
2358 if (result != ISC_R_SUCCESS) {
2359 return result;
2360 }
2361 count = 0;
2362 result = renderset(msg->tsig, msg->tsigname, msg->cctx,
2363 msg->buffer, msg->reserved, 0, &count);
2364 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2365 if (result != ISC_R_SUCCESS) {
2366 return result;
2367 }
2368 }
2369
2370 /*
2371 * If we're adding a SIG(0) record, generate and render it.
2372 */
2373 if (msg->sig0key != NULL) {
2374 dns_message_renderrelease(msg, msg->sig_reserved);
2375 msg->sig_reserved = 0;
2376 result = dns_dnssec_signmessage(msg, msg->sig0key);
2377 if (result != ISC_R_SUCCESS) {
2378 return result;
2379 }
2380 count = 0;
2381 /*
2382 * Note: dns_rootname is used here, not msg->sig0name, since
2383 * the owner name of a SIG(0) is irrelevant, and will not
2384 * be set in a message being rendered.
2385 */
2386 result = renderset(msg->sig0, dns_rootname, msg->cctx,
2387 msg->buffer, msg->reserved, 0, &count);
2388 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2389 if (result != ISC_R_SUCCESS) {
2390 return result;
2391 }
2392 }
2393
2394 isc_buffer_usedregion(msg->buffer, &r);
2395 isc_buffer_init(&tmpbuf, r.base, r.length);
2396
2397 dns_message_renderheader(msg, &tmpbuf);
2398
2399 msg->buffer = NULL; /* forget about this buffer only on success XXX */
2400
2401 return ISC_R_SUCCESS;
2402 }
2403
2404 void
2405 dns_message_renderreset(dns_message_t *msg) {
2406 /*
2407 * Reset the message so that it may be rendered again.
2408 */
2409
2410 REQUIRE(DNS_MESSAGE_VALID(msg));
2411 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2412
2413 msg->buffer = NULL;
2414
2415 for (size_t i = 0; i < DNS_SECTION_MAX; i++) {
2416 dns_name_t *name = NULL;
2417
2418 msg->cursors[i] = NULL;
2419 msg->counts[i] = 0;
2420 ISC_LIST_FOREACH (msg->sections[i], name, link) {
2421 dns_rdataset_t *rds = NULL;
2422 ISC_LIST_FOREACH (name->list, rds, link) {
2423 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2424 }
2425 }
2426 }
2427 if (msg->tsigname != NULL) {
2428 dns_message_puttempname(msg, &msg->tsigname);
2429 }
2430 if (msg->tsig != NULL) {
2431 dns__message_putassociatedrdataset(msg, &msg->tsig);
2432 }
2433 if (msg->sig0name != NULL) {
2434 dns_message_puttempname(msg, &msg->sig0name);
2435 }
2436 if (msg->sig0 != NULL) {
2437 dns__message_putassociatedrdataset(msg, &msg->sig0);
2438 }
2439 }
2440
2441 isc_result_t
2442 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2443 REQUIRE(DNS_MESSAGE_VALID(msg));
2444 REQUIRE(VALID_NAMED_SECTION(section));
2445
2446 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2447
2448 if (msg->cursors[section] == NULL) {
2449 return ISC_R_NOMORE;
2450 }
2451
2452 return ISC_R_SUCCESS;
2453 }
2454
2455 isc_result_t
2456 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2457 REQUIRE(DNS_MESSAGE_VALID(msg));
2458 REQUIRE(VALID_NAMED_SECTION(section));
2459 REQUIRE(msg->cursors[section] != NULL);
2460
2461 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2462
2463 if (msg->cursors[section] == NULL) {
2464 return ISC_R_NOMORE;
2465 }
2466
2467 return ISC_R_SUCCESS;
2468 }
2469
2470 void
2471 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2472 dns_name_t **name) {
2473 REQUIRE(DNS_MESSAGE_VALID(msg));
2474 REQUIRE(VALID_NAMED_SECTION(section));
2475 REQUIRE(name != NULL && *name == NULL);
2476 REQUIRE(msg->cursors[section] != NULL);
2477
2478 *name = msg->cursors[section];
2479 }
2480
2481 isc_result_t
2482 dns_message_findname(dns_message_t *msg, dns_section_t section,
2483 const dns_name_t *target, dns_rdatatype_t type,
2484 dns_rdatatype_t covers, dns_name_t **name,
2485 dns_rdataset_t **rdataset) {
2486 dns_name_t *foundname = NULL;
2487 isc_result_t result;
2488
2489 /*
2490 * XXX These requirements are probably too intensive, especially
2491 * where things can be NULL, but as they are they ensure that if
2492 * something is NON-NULL, indicating that the caller expects it
2493 * to be filled in, that we can in fact fill it in.
2494 */
2495 REQUIRE(msg != NULL);
2496 REQUIRE(VALID_NAMED_SECTION(section));
2497 REQUIRE(target != NULL);
2498 REQUIRE(name == NULL || *name == NULL);
2499
2500 if (type == dns_rdatatype_any) {
2501 REQUIRE(rdataset == NULL);
2502 } else {
2503 REQUIRE(rdataset == NULL || *rdataset == NULL);
2504 }
2505
2506 result = findname(&foundname, target, &msg->sections[section]);
2507
2508 if (result == ISC_R_NOTFOUND) {
2509 return DNS_R_NXDOMAIN;
2510 } else if (result != ISC_R_SUCCESS) {
2511 return result;
2512 }
2513
2514 SET_IF_NOT_NULL(name, foundname);
2515
2516 /*
2517 * And now look for the type.
2518 */
2519 if (type == dns_rdatatype_any) {
2520 return ISC_R_SUCCESS;
2521 }
2522
2523 result = dns_message_findtype(foundname, type, covers, rdataset);
2524 if (result == ISC_R_NOTFOUND) {
2525 return DNS_R_NXRRSET;
2526 }
2527
2528 return result;
2529 }
2530
2531 void
2532 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2533 dns_section_t section) {
2534 REQUIRE(msg != NULL);
2535 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2536 REQUIRE(dns_name_isabsolute(name));
2537 REQUIRE(VALID_NAMED_SECTION(section));
2538
2539 ISC_LIST_APPEND(msg->sections[section], name, link);
2540 }
2541
2542 void
2543 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2544 dns_section_t section) {
2545 REQUIRE(msg != NULL);
2546 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2547 REQUIRE(dns_name_isabsolute(name));
2548 REQUIRE(VALID_NAMED_SECTION(section));
2549
2550 ISC_LIST_UNLINK(msg->sections[section], name, link);
2551 }
2552
2553 void
2554 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2555 dns_fixedname_t *fn = NULL;
2556
2557 REQUIRE(DNS_MESSAGE_VALID(msg));
2558 REQUIRE(item != NULL && *item == NULL);
2559
2560 fn = isc_mempool_get(msg->namepool);
2561 *item = dns_fixedname_initname(fn);
2562 }
2563
2564 void
2565 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2566 REQUIRE(DNS_MESSAGE_VALID(msg));
2567 REQUIRE(item != NULL && *item == NULL);
2568
2569 *item = newrdata(msg);
2570 }
2571
2572 void
2573 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2574 REQUIRE(DNS_MESSAGE_VALID(msg));
2575 REQUIRE(item != NULL && *item == NULL);
2576
2577 *item = isc_mempool_get(msg->rdspool);
2578 dns_rdataset_init(*item);
2579 }
2580
2581 void
2582 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2583 REQUIRE(DNS_MESSAGE_VALID(msg));
2584 REQUIRE(item != NULL && *item == NULL);
2585
2586 *item = newrdatalist(msg);
2587 }
2588
2589 void
2590 dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) {
2591 dns_name_t *item = NULL;
2592
2593 REQUIRE(DNS_MESSAGE_VALID(msg));
2594 REQUIRE(itemp != NULL && *itemp != NULL);
2595
2596 item = *itemp;
2597 *itemp = NULL;
2598
2599 REQUIRE(!ISC_LINK_LINKED(item, link));
2600 REQUIRE(ISC_LIST_HEAD(item->list) == NULL);
2601
2602 if (item->hashmap != NULL) {
2603 isc_hashmap_destroy(&item->hashmap);
2604 }
2605
2606 /*
2607 * we need to check this in case dns_name_dup() was used.
2608 */
2609 if (dns_name_dynamic(item)) {
2610 dns_name_free(item, msg->mctx);
2611 }
2612
2613 /*
2614 * 'name' is the first field in dns_fixedname_t, so putting
2615 * back the address of name is the same as putting back
2616 * the fixedname.
2617 */
2618 isc_mempool_put(msg->namepool, item);
2619 }
2620
2621 void
2622 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2623 REQUIRE(DNS_MESSAGE_VALID(msg));
2624 REQUIRE(item != NULL && *item != NULL);
2625
2626 releaserdata(msg, *item);
2627 *item = NULL;
2628 }
2629
2630 static void
2631 dns__message_putassociatedrdataset(dns_message_t *msg, dns_rdataset_t **item) {
2632 dns_rdataset_disassociate(*item);
2633 dns_message_puttemprdataset(msg, item);
2634 }
2635
2636 void
2637 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2638 REQUIRE(DNS_MESSAGE_VALID(msg));
2639 REQUIRE(item != NULL && *item != NULL);
2640
2641 REQUIRE(!dns_rdataset_isassociated(*item));
2642 isc_mempool_put(msg->rdspool, *item);
2643 *item = NULL;
2644 }
2645
2646 void
2647 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2648 REQUIRE(DNS_MESSAGE_VALID(msg));
2649 REQUIRE(item != NULL && *item != NULL);
2650
2651 releaserdatalist(msg, *item);
2652 *item = NULL;
2653 }
2654
2655 isc_result_t
2656 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2657 unsigned int *flagsp) {
2658 isc_region_t r;
2659 isc_buffer_t buffer;
2660 dns_messageid_t id;
2661 unsigned int flags;
2662
2663 REQUIRE(source != NULL);
2664
2665 buffer = *source;
2666
2667 isc_buffer_remainingregion(&buffer, &r);
2668 if (r.length < DNS_MESSAGE_HEADERLEN) {
2669 return ISC_R_UNEXPECTEDEND;
2670 }
2671
2672 id = isc_buffer_getuint16(&buffer);
2673 flags = isc_buffer_getuint16(&buffer);
2674 flags &= DNS_MESSAGE_FLAG_MASK;
2675
2676 SET_IF_NOT_NULL(flagsp, flags);
2677 SET_IF_NOT_NULL(idp, id);
2678
2679 return ISC_R_SUCCESS;
2680 }
2681
2682 isc_result_t
2683 dns_message_reply(dns_message_t *msg, bool want_question_section) {
2684 unsigned int clear_from;
2685 isc_result_t result;
2686
2687 REQUIRE(DNS_MESSAGE_VALID(msg));
2688 REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2689
2690 if (!msg->header_ok) {
2691 return DNS_R_FORMERR;
2692 }
2693 if (msg->opcode != dns_opcode_query && msg->opcode != dns_opcode_notify)
2694 {
2695 want_question_section = false;
2696 }
2697 if (msg->opcode == dns_opcode_update) {
2698 clear_from = DNS_SECTION_PREREQUISITE;
2699 } else if (want_question_section) {
2700 if (!msg->question_ok) {
2701 return DNS_R_FORMERR;
2702 }
2703 clear_from = DNS_SECTION_ANSWER;
2704 } else {
2705 clear_from = DNS_SECTION_QUESTION;
2706 }
2707 msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2708 msgresetnames(msg, clear_from);
2709 msgresetopt(msg);
2710 msgresetsigs(msg, true);
2711 msginitprivate(msg);
2712 /*
2713 * We now clear most flags and then set QR, ensuring that the
2714 * reply's flags will be in a reasonable state.
2715 */
2716 if (msg->opcode == dns_opcode_query) {
2717 msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2718 } else {
2719 msg->flags = 0;
2720 }
2721 msg->flags |= DNS_MESSAGEFLAG_QR;
2722
2723 /*
2724 * This saves the query TSIG status, if the query was signed, and
2725 * reserves space in the reply for the TSIG.
2726 */
2727 if (msg->tsigkey != NULL) {
2728 unsigned int otherlen = 0;
2729 msg->querytsigstatus = msg->tsigstatus;
2730 msg->tsigstatus = dns_rcode_noerror;
2731 if (msg->querytsigstatus == dns_tsigerror_badtime) {
2732 otherlen = 6;
2733 }
2734 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2735 result = dns_message_renderreserve(msg, msg->sig_reserved);
2736 if (result != ISC_R_SUCCESS) {
2737 msg->sig_reserved = 0;
2738 return result;
2739 }
2740 }
2741 if (msg->saved.base != NULL) {
2742 msg->query.base = msg->saved.base;
2743 msg->query.length = msg->saved.length;
2744 msg->free_query = msg->free_saved;
2745 msg->saved.base = NULL;
2746 msg->saved.length = 0;
2747 msg->free_saved = 0;
2748 }
2749
2750 return ISC_R_SUCCESS;
2751 }
2752
2753 dns_rdataset_t *
2754 dns_message_getopt(dns_message_t *msg) {
2755 /*
2756 * Get the OPT record for 'msg'.
2757 */
2758
2759 REQUIRE(DNS_MESSAGE_VALID(msg));
2760
2761 return msg->opt;
2762 }
2763
2764 isc_result_t
2765 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2766 isc_result_t result;
2767 dns_rdata_t rdata = DNS_RDATA_INIT;
2768
2769 /*
2770 * Set the OPT record for 'msg'.
2771 */
2772
2773 /*
2774 * The space required for an OPT record is:
2775 *
2776 * 1 byte for the name
2777 * 2 bytes for the type
2778 * 2 bytes for the class
2779 * 4 bytes for the ttl
2780 * 2 bytes for the rdata length
2781 * ---------------------------------
2782 * 11 bytes
2783 *
2784 * plus the length of the rdata.
2785 */
2786
2787 REQUIRE(DNS_MESSAGE_VALID(msg));
2788 REQUIRE(opt == NULL || DNS_RDATASET_VALID(opt));
2789 REQUIRE(opt == NULL || opt->type == dns_rdatatype_opt);
2790 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2791 REQUIRE(msg->state == DNS_SECTION_ANY);
2792
2793 msgresetopt(msg);
2794
2795 if (opt == NULL) {
2796 return ISC_R_SUCCESS;
2797 }
2798
2799 result = dns_rdataset_first(opt);
2800 if (result != ISC_R_SUCCESS) {
2801 goto cleanup;
2802 }
2803 dns_rdataset_current(opt, &rdata);
2804 msg->opt_reserved = 11 + rdata.length;
2805 result = dns_message_renderreserve(msg, msg->opt_reserved);
2806 if (result != ISC_R_SUCCESS) {
2807 msg->opt_reserved = 0;
2808 goto cleanup;
2809 }
2810
2811 msg->opt = opt;
2812
2813 return ISC_R_SUCCESS;
2814
2815 cleanup:
2816 dns__message_putassociatedrdataset(msg, &opt);
2817 return result;
2818 }
2819
2820 dns_rdataset_t *
2821 dns_message_gettsig(dns_message_t *msg, const dns_name_t **owner) {
2822 /*
2823 * Get the TSIG record and owner for 'msg'.
2824 */
2825
2826 REQUIRE(DNS_MESSAGE_VALID(msg));
2827 REQUIRE(owner == NULL || *owner == NULL);
2828
2829 SET_IF_NOT_NULL(owner, msg->tsigname);
2830 return msg->tsig;
2831 }
2832
2833 isc_result_t
2834 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2835 isc_result_t result;
2836
2837 /*
2838 * Set the TSIG key for 'msg'
2839 */
2840
2841 REQUIRE(DNS_MESSAGE_VALID(msg));
2842
2843 if (key == NULL && msg->tsigkey != NULL) {
2844 if (msg->sig_reserved != 0) {
2845 dns_message_renderrelease(msg, msg->sig_reserved);
2846 msg->sig_reserved = 0;
2847 }
2848 dns_tsigkey_detach(&msg->tsigkey);
2849 }
2850 if (key != NULL) {
2851 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2852 dns_tsigkey_attach(key, &msg->tsigkey);
2853 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2854 msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2855 result = dns_message_renderreserve(msg,
2856 msg->sig_reserved);
2857 if (result != ISC_R_SUCCESS) {
2858 dns_tsigkey_detach(&msg->tsigkey);
2859 msg->sig_reserved = 0;
2860 return result;
2861 }
2862 }
2863 }
2864 return ISC_R_SUCCESS;
2865 }
2866
2867 dns_tsigkey_t *
2868 dns_message_gettsigkey(dns_message_t *msg) {
2869 /*
2870 * Get the TSIG key for 'msg'
2871 */
2872
2873 REQUIRE(DNS_MESSAGE_VALID(msg));
2874
2875 return msg->tsigkey;
2876 }
2877
2878 void
2879 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2880 dns_rdata_t *rdata = NULL;
2881 dns_rdatalist_t *list = NULL;
2882 dns_rdataset_t *set = NULL;
2883 isc_buffer_t *buf = NULL;
2884 isc_region_t r;
2885
2886 REQUIRE(DNS_MESSAGE_VALID(msg));
2887 REQUIRE(msg->querytsig == NULL);
2888
2889 if (querytsig == NULL) {
2890 return;
2891 }
2892
2893 dns_message_gettemprdata(msg, &rdata);
2894
2895 dns_message_gettemprdatalist(msg, &list);
2896 dns_message_gettemprdataset(msg, &set);
2897
2898 isc_buffer_usedregion(querytsig, &r);
2899 isc_buffer_allocate(msg->mctx, &buf, r.length);
2900 isc_buffer_putmem(buf, r.base, r.length);
2901 isc_buffer_usedregion(buf, &r);
2902 dns_rdata_init(rdata);
2903 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2904 dns_message_takebuffer(msg, &buf);
2905 ISC_LIST_APPEND(list->rdata, rdata, link);
2906 dns_rdatalist_tordataset(list, set);
2907
2908 msg->querytsig = set;
2909 }
2910
2911 isc_result_t
2912 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2913 isc_buffer_t **querytsig) {
2914 isc_result_t result;
2915 dns_rdata_t rdata = DNS_RDATA_INIT;
2916 isc_region_t r;
2917
2918 REQUIRE(DNS_MESSAGE_VALID(msg));
2919 REQUIRE(mctx != NULL);
2920 REQUIRE(querytsig != NULL && *querytsig == NULL);
2921
2922 if (msg->tsig == NULL) {
2923 return ISC_R_SUCCESS;
2924 }
2925
2926 result = dns_rdataset_first(msg->tsig);
2927 if (result != ISC_R_SUCCESS) {
2928 return result;
2929 }
2930 dns_rdataset_current(msg->tsig, &rdata);
2931 dns_rdata_toregion(&rdata, &r);
2932
2933 isc_buffer_allocate(mctx, querytsig, r.length);
2934 isc_buffer_putmem(*querytsig, r.base, r.length);
2935 return ISC_R_SUCCESS;
2936 }
2937
2938 dns_rdataset_t *
2939 dns_message_getsig0(dns_message_t *msg, const dns_name_t **owner) {
2940 /*
2941 * Get the SIG(0) record for 'msg'.
2942 */
2943
2944 REQUIRE(DNS_MESSAGE_VALID(msg));
2945 REQUIRE(owner == NULL || *owner == NULL);
2946
2947 if (msg->sig0 != NULL && owner != NULL) {
2948 /* If dns_message_getsig0 is called on a rendered message
2949 * after the SIG(0) has been applied, we need to return the
2950 * root name, not NULL.
2951 */
2952 if (msg->sig0name == NULL) {
2953 *owner = dns_rootname;
2954 } else {
2955 *owner = msg->sig0name;
2956 }
2957 }
2958 return msg->sig0;
2959 }
2960
2961 isc_result_t
2962 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2963 isc_region_t r;
2964 unsigned int x;
2965 isc_result_t result;
2966
2967 /*
2968 * Set the SIG(0) key for 'msg'
2969 */
2970
2971 /*
2972 * The space required for an SIG(0) record is:
2973 *
2974 * 1 byte for the name
2975 * 2 bytes for the type
2976 * 2 bytes for the class
2977 * 4 bytes for the ttl
2978 * 2 bytes for the type covered
2979 * 1 byte for the algorithm
2980 * 1 bytes for the labels
2981 * 4 bytes for the original ttl
2982 * 4 bytes for the signature expiration
2983 * 4 bytes for the signature inception
2984 * 2 bytes for the key tag
2985 * n bytes for the signer's name
2986 * x bytes for the signature
2987 * ---------------------------------
2988 * 27 + n + x bytes
2989 */
2990 REQUIRE(DNS_MESSAGE_VALID(msg));
2991 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2992 REQUIRE(msg->state == DNS_SECTION_ANY);
2993
2994 if (key != NULL) {
2995 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2996 dns_name_toregion(dst_key_name(key), &r);
2997 result = dst_key_sigsize(key, &x);
2998 if (result != ISC_R_SUCCESS) {
2999 msg->sig_reserved = 0;
3000 return result;
3001 }
3002 msg->sig_reserved = 27 + r.length + x;
3003 result = dns_message_renderreserve(msg, msg->sig_reserved);
3004 if (result != ISC_R_SUCCESS) {
3005 msg->sig_reserved = 0;
3006 return result;
3007 }
3008 msg->sig0key = key;
3009 }
3010 return ISC_R_SUCCESS;
3011 }
3012
3013 dst_key_t *
3014 dns_message_getsig0key(dns_message_t *msg) {
3015 /*
3016 * Get the SIG(0) key for 'msg'
3017 */
3018
3019 REQUIRE(DNS_MESSAGE_VALID(msg));
3020
3021 return msg->sig0key;
3022 }
3023
3024 void
3025 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
3026 REQUIRE(DNS_MESSAGE_VALID(msg));
3027 REQUIRE(buffer != NULL);
3028 REQUIRE(ISC_BUFFER_VALID(*buffer));
3029
3030 ISC_LIST_APPEND(msg->cleanup, *buffer, link);
3031 *buffer = NULL;
3032 }
3033
3034 isc_result_t
3035 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
3036 isc_result_t result = ISC_R_SUCCESS;
3037 dns_rdata_t rdata = DNS_RDATA_INIT;
3038
3039 REQUIRE(DNS_MESSAGE_VALID(msg));
3040 REQUIRE(signer != NULL);
3041 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
3042
3043 if (msg->tsig == NULL && msg->sig0 == NULL) {
3044 return ISC_R_NOTFOUND;
3045 }
3046
3047 if (msg->verify_attempted == 0) {
3048 return DNS_R_NOTVERIFIEDYET;
3049 }
3050
3051 if (!dns_name_hasbuffer(signer)) {
3052 isc_buffer_t *dynbuf = NULL;
3053 isc_buffer_allocate(msg->mctx, &dynbuf, 512);
3054 dns_name_setbuffer(signer, dynbuf);
3055 dns_message_takebuffer(msg, &dynbuf);
3056 }
3057
3058 if (msg->sig0 != NULL) {
3059 dns_rdata_sig_t sig;
3060
3061 result = dns_rdataset_first(msg->sig0);
3062 INSIST(result == ISC_R_SUCCESS);
3063 dns_rdataset_current(msg->sig0, &rdata);
3064
3065 result = dns_rdata_tostruct(&rdata, &sig, NULL);
3066 if (result != ISC_R_SUCCESS) {
3067 return result;
3068 }
3069
3070 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror) {
3071 result = ISC_R_SUCCESS;
3072 } else {
3073 result = DNS_R_SIGINVALID;
3074 }
3075 dns_name_clone(&sig.signer, signer);
3076 dns_rdata_freestruct(&sig);
3077 } else {
3078 const dns_name_t *identity;
3079 dns_rdata_any_tsig_t tsig;
3080
3081 result = dns_rdataset_first(msg->tsig);
3082 INSIST(result == ISC_R_SUCCESS);
3083 dns_rdataset_current(msg->tsig, &rdata);
3084
3085 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
3086 INSIST(result == ISC_R_SUCCESS);
3087 if (msg->verified_sig && msg->tsigstatus == dns_rcode_noerror &&
3088 tsig.error == dns_rcode_noerror)
3089 {
3090 result = ISC_R_SUCCESS;
3091 } else if ((!msg->verified_sig) ||
3092 (msg->tsigstatus != dns_rcode_noerror))
3093 {
3094 result = DNS_R_TSIGVERIFYFAILURE;
3095 } else {
3096 INSIST(tsig.error != dns_rcode_noerror);
3097 result = DNS_R_TSIGERRORSET;
3098 }
3099 dns_rdata_freestruct(&tsig);
3100
3101 if (msg->tsigkey == NULL) {
3102 /*
3103 * If msg->tsigstatus & tsig.error are both
3104 * dns_rcode_noerror, the message must have been
3105 * verified, which means msg->tsigkey will be
3106 * non-NULL.
3107 */
3108 INSIST(result != ISC_R_SUCCESS);
3109 } else {
3110 identity = dns_tsigkey_identity(msg->tsigkey);
3111 if (identity == NULL) {
3112 if (result == ISC_R_SUCCESS) {
3113 result = DNS_R_NOIDENTITY;
3114 }
3115 identity = msg->tsigkey->name;
3116 }
3117 dns_name_clone(identity, signer);
3118 }
3119 }
3120
3121 return result;
3122 }
3123
3124 void
3125 dns_message_resetsig(dns_message_t *msg) {
3126 REQUIRE(DNS_MESSAGE_VALID(msg));
3127 msg->verified_sig = 0;
3128 msg->verify_attempted = 0;
3129 msg->tsigstatus = dns_rcode_noerror;
3130 msg->sig0status = dns_rcode_noerror;
3131 msg->timeadjust = 0;
3132 if (msg->tsigkey != NULL) {
3133 dns_tsigkey_detach(&msg->tsigkey);
3134 msg->tsigkey = NULL;
3135 }
3136 }
3137
3138 #ifdef SKAN_MSG_DEBUG
3139 void
3140 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
3141 dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
3142 dns_rdata_any_tsig_t querytsig;
3143 isc_result_t result;
3144
3145 if (msg->tsig != NULL) {
3146 result = dns_rdataset_first(msg->tsig);
3147 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3148 dns_rdataset_current(msg->tsig, &querytsigrdata);
3149 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3150 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3151 hexdump(txt1, "TSIG", querytsig.signature, querytsig.siglen);
3152 }
3153
3154 if (msg->querytsig != NULL) {
3155 result = dns_rdataset_first(msg->querytsig);
3156 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3157 dns_rdataset_current(msg->querytsig, &querytsigrdata);
3158 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3159 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3160 hexdump(txt1, "QUERYTSIG", querytsig.signature,
3161 querytsig.siglen);
3162 }
3163 }
3164 #endif /* ifdef SKAN_MSG_DEBUG */
3165
3166 static void
3167 checksig_done(void *arg);
3168
3169 static void
3170 checksig_run(void *arg) {
3171 checksig_ctx_t *chsigctx = arg;
3172
3173 chsigctx->result = dns_message_checksig(chsigctx->msg, chsigctx->view);
3174
3175 isc_async_run(chsigctx->loop, checksig_done, chsigctx);
3176 }
3177
3178 static void
3179 checksig_done(void *arg) {
3180 checksig_ctx_t *chsigctx = arg;
3181 dns_message_t *msg = chsigctx->msg;
3182
3183 chsigctx->cb(chsigctx->cbarg, chsigctx->result);
3184
3185 dns_view_detach(&chsigctx->view);
3186 isc_loop_detach(&chsigctx->loop);
3187 isc_mem_put(msg->mctx, chsigctx, sizeof(*chsigctx));
3188 dns_message_detach(&msg);
3189 }
3190
3191 isc_result_t
3192 dns_message_checksig_async(dns_message_t *msg, dns_view_t *view,
3193 isc_loop_t *loop, dns_message_cb_t cb, void *cbarg) {
3194 REQUIRE(DNS_MESSAGE_VALID(msg));
3195 REQUIRE(view != NULL);
3196 REQUIRE(loop != NULL);
3197 REQUIRE(cb != NULL);
3198
3199 checksig_ctx_t *chsigctx = isc_mem_get(msg->mctx, sizeof(*chsigctx));
3200 *chsigctx = (checksig_ctx_t){
3201 .cb = cb,
3202 .cbarg = cbarg,
3203 .result = ISC_R_UNSET,
3204 .loop = isc_loop_ref(loop),
3205 };
3206 dns_message_attach(msg, &chsigctx->msg);
3207 dns_view_attach(view, &chsigctx->view);
3208
3209 dns_message_clonebuffer(msg);
3210 isc_helper_run(loop, checksig_run, chsigctx);
3211
3212 return DNS_R_WAIT;
3213 }
3214
3215 isc_result_t
3216 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3217 isc_buffer_t b, msgb;
3218
3219 REQUIRE(DNS_MESSAGE_VALID(msg));
3220
3221 if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL) {
3222 return ISC_R_SUCCESS;
3223 }
3224
3225 INSIST(msg->saved.base != NULL);
3226 isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3227 isc_buffer_add(&msgb, msg->saved.length);
3228 if (msg->tsigkey != NULL || msg->tsig != NULL) {
3229 #ifdef SKAN_MSG_DEBUG
3230 dns_message_dumpsig(msg, "dns_message_checksig#1");
3231 #endif /* ifdef SKAN_MSG_DEBUG */
3232 if (view != NULL) {
3233 return dns_view_checksig(view, &msgb, msg);
3234 } else {
3235 return dns_tsig_verify(&msgb, msg, NULL, NULL);
3236 }
3237 } else {
3238 dns_rdata_t rdata = DNS_RDATA_INIT;
3239 dns_rdata_sig_t sig;
3240 dns_rdataset_t keyset;
3241 isc_result_t result;
3242 uint32_t key_checks, message_checks;
3243
3244 result = dns_rdataset_first(msg->sig0);
3245 INSIST(result == ISC_R_SUCCESS);
3246 dns_rdataset_current(msg->sig0, &rdata);
3247
3248 /*
3249 * This can occur when the message is a dynamic update, since
3250 * the rdata length checking is relaxed. This should not
3251 * happen in a well-formed message, since the SIG(0) is only
3252 * looked for in the additional section, and the dynamic update
3253 * meta-records are in the prerequisite and update sections.
3254 */
3255 if (rdata.length == 0) {
3256 return ISC_R_UNEXPECTEDEND;
3257 }
3258
3259 result = dns_rdata_tostruct(&rdata, &sig, NULL);
3260 if (result != ISC_R_SUCCESS) {
3261 return result;
3262 }
3263
3264 dns_rdataset_init(&keyset);
3265 if (view == NULL) {
3266 result = DNS_R_KEYUNAUTHORIZED;
3267 goto freesig;
3268 }
3269 result = dns_view_simplefind(view, &sig.signer,
3270 dns_rdatatype_key /* SIG(0) */, 0,
3271 0, false, &keyset, NULL);
3272
3273 if (result != ISC_R_SUCCESS) {
3274 result = DNS_R_KEYUNAUTHORIZED;
3275 goto freesig;
3276 } else if (keyset.trust < dns_trust_ultimate) {
3277 result = DNS_R_KEYUNAUTHORIZED;
3278 goto freesig;
3279 }
3280 result = dns_rdataset_first(&keyset);
3281 INSIST(result == ISC_R_SUCCESS);
3282
3283 /*
3284 * In order to protect from a possible DoS attack, this function
3285 * supports limitations on how many keyid checks and how many
3286 * key checks (message verifications using a matched key) are
3287 * going to be allowed.
3288 */
3289 const uint32_t max_key_checks =
3290 view->sig0key_checks_limit > 0
3291 ? view->sig0key_checks_limit
3292 : UINT32_MAX;
3293 const uint32_t max_message_checks =
3294 view->sig0message_checks_limit > 0
3295 ? view->sig0message_checks_limit
3296 : UINT32_MAX;
3297
3298 for (key_checks = 0, message_checks = 0;
3299 result == ISC_R_SUCCESS && key_checks < max_key_checks &&
3300 message_checks < max_message_checks;
3301 key_checks++, result = dns_rdataset_next(&keyset))
3302 {
3303 dst_key_t *key = NULL;
3304
3305 dns_rdata_reset(&rdata);
3306 dns_rdataset_current(&keyset, &rdata);
3307 isc_buffer_init(&b, rdata.data, rdata.length);
3308 isc_buffer_add(&b, rdata.length);
3309
3310 result = dst_key_fromdns(&sig.signer, rdata.rdclass, &b,
3311 view->mctx, &key);
3312 if (result != ISC_R_SUCCESS) {
3313 continue;
3314 }
3315 if (dst_key_alg(key) != sig.algorithm ||
3316 dst_key_id(key) != sig.keyid ||
3317 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3318 dst_key_proto(key) == DNS_KEYPROTO_ANY))
3319 {
3320 dst_key_free(&key);
3321 continue;
3322 }
3323 result = dns_dnssec_verifymessage(&msgb, msg, key);
3324 dst_key_free(&key);
3325 if (result == ISC_R_SUCCESS) {
3326 break;
3327 }
3328 message_checks++;
3329 }
3330 if (result == ISC_R_NOMORE) {
3331 result = DNS_R_KEYUNAUTHORIZED;
3332 } else if (key_checks == max_key_checks) {
3333 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
3334 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
3335 "sig0key-checks-limit reached when "
3336 "trying to check a message signature");
3337 result = DNS_R_KEYUNAUTHORIZED;
3338 } else if (message_checks == max_message_checks) {
3339 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
3340 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
3341 "sig0message-checks-limit reached when "
3342 "trying to check a message signature");
3343 result = DNS_R_KEYUNAUTHORIZED;
3344 }
3345
3346 freesig:
3347 if (dns_rdataset_isassociated(&keyset)) {
3348 dns_rdataset_disassociate(&keyset);
3349 }
3350 dns_rdata_freestruct(&sig);
3351 return result;
3352 }
3353 }
3354
3355 #define INDENT(sp) \
3356 do { \
3357 unsigned int __i; \
3358 dns_masterstyle_flags_t __flags = dns_master_styleflags(sp); \
3359 if ((__flags & DNS_STYLEFLAG_INDENT) == 0ULL && \
3360 (__flags & DNS_STYLEFLAG_YAML) == 0ULL) \
3361 { \
3362 break; \
3363 } \
3364 for (__i = 0; __i < msg->indent.count; __i++) { \
3365 ADD_STRING(target, msg->indent.string); \
3366 } \
3367 } while (0)
3368
3369 isc_result_t
3370 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3371 const dns_master_style_t *style,
3372 dns_messagetextflag_t flags, isc_buffer_t *target) {
3373 dns_name_t empty_name;
3374 isc_result_t result = ISC_R_SUCCESS;
3375 bool seensoa = false;
3376 size_t saved_count;
3377 dns_masterstyle_flags_t sflags;
3378
3379 REQUIRE(DNS_MESSAGE_VALID(msg));
3380 REQUIRE(target != NULL);
3381 REQUIRE(VALID_NAMED_SECTION(section));
3382
3383 saved_count = msg->indent.count;
3384
3385 if (ISC_LIST_EMPTY(msg->sections[section])) {
3386 goto cleanup;
3387 }
3388
3389 sflags = dns_master_styleflags(style);
3390
3391 INDENT(style);
3392 if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3393 if (msg->opcode != dns_opcode_update) {
3394 ADD_STRING(target, sectiontext[section]);
3395 } else {
3396 ADD_STRING(target, updsectiontext[section]);
3397 }
3398 ADD_STRING(target, "_SECTION:\n");
3399 } else if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3400 ADD_STRING(target, ";; ");
3401 if (msg->opcode != dns_opcode_update) {
3402 ADD_STRING(target, sectiontext[section]);
3403 } else {
3404 ADD_STRING(target, updsectiontext[section]);
3405 }
3406 ADD_STRING(target, " SECTION:\n");
3407 }
3408
3409 dns_name_init(&empty_name, NULL);
3410 result = dns_message_firstname(msg, section);
3411 if (result != ISC_R_SUCCESS) {
3412 goto cleanup;
3413 }
3414 if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3415 msg->indent.count++;
3416 }
3417 do {
3418 dns_name_t *name = NULL;
3419 dns_message_currentname(msg, section, &name);
3420
3421 dns_rdataset_t *rds = NULL;
3422 ISC_LIST_FOREACH (name->list, rds, link) {
3423 if (section == DNS_SECTION_ANSWER &&
3424 rds->type == dns_rdatatype_soa)
3425 {
3426 if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3427 {
3428 continue;
3429 }
3430 if (seensoa &&
3431 (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3432 {
3433 continue;
3434 }
3435 seensoa = true;
3436 }
3437 if (section == DNS_SECTION_QUESTION) {
3438 INDENT(style);
3439 if ((sflags & DNS_STYLEFLAG_YAML) == 0) {
3440 ADD_STRING(target, ";");
3441 }
3442 result = dns_master_questiontotext(
3443 name, rds, style, target);
3444 } else {
3445 result = dns_master_rdatasettotext(
3446 name, rds, style, &msg->indent, target);
3447 }
3448 if (result != ISC_R_SUCCESS) {
3449 goto cleanup;
3450 }
3451 }
3452 result = dns_message_nextname(msg, section);
3453 } while (result == ISC_R_SUCCESS);
3454 if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3455 msg->indent.count--;
3456 }
3457 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3458 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0 &&
3459 (sflags & DNS_STYLEFLAG_YAML) == 0)
3460 {
3461 INDENT(style);
3462 ADD_STRING(target, "\n");
3463 }
3464 if (result == ISC_R_NOMORE) {
3465 result = ISC_R_SUCCESS;
3466 }
3467
3468 cleanup:
3469 msg->indent.count = saved_count;
3470 return result;
3471 }
3472
3473 static isc_result_t
3474 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
3475 int i;
3476 char addr[16] = { 0 }, addr_text[64];
3477 uint16_t family;
3478 uint8_t addrlen, addrbytes, scopelen;
3479 isc_result_t result;
3480
3481 /*
3482 * Note: This routine needs to handle malformed ECS options.
3483 */
3484
3485 if (isc_buffer_remaininglength(ecsbuf) < 4) {
3486 return DNS_R_OPTERR;
3487 }
3488 family = isc_buffer_getuint16(ecsbuf);
3489 addrlen = isc_buffer_getuint8(ecsbuf);
3490 scopelen = isc_buffer_getuint8(ecsbuf);
3491
3492 addrbytes = (addrlen + 7) / 8;
3493 if (isc_buffer_remaininglength(ecsbuf) < addrbytes) {
3494 return DNS_R_OPTERR;
3495 }
3496
3497 if (addrbytes > sizeof(addr)) {
3498 return DNS_R_OPTERR;
3499 }
3500
3501 for (i = 0; i < addrbytes; i++) {
3502 addr[i] = isc_buffer_getuint8(ecsbuf);
3503 }
3504
3505 switch (family) {
3506 case 0:
3507 if (addrlen != 0U || scopelen != 0U) {
3508 return DNS_R_OPTERR;
3509 }
3510 strlcpy(addr_text, "0", sizeof(addr_text));
3511 break;
3512 case 1:
3513 if (addrlen > 32 || scopelen > 32) {
3514 return DNS_R_OPTERR;
3515 }
3516 inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
3517 break;
3518 case 2:
3519 if (addrlen > 128 || scopelen > 128) {
3520 return DNS_R_OPTERR;
3521 }
3522 inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
3523 break;
3524 default:
3525 return DNS_R_OPTERR;
3526 }
3527
3528 ADD_STRING(target, " ");
3529 ADD_STRING(target, addr_text);
3530 snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
3531 ADD_STRING(target, addr_text);
3532
3533 result = ISC_R_SUCCESS;
3534
3535 cleanup:
3536 return result;
3537 }
3538
3539 static isc_result_t
3540 render_llq(isc_buffer_t *optbuf, dns_message_t *msg,
3541 const dns_master_style_t *style, isc_buffer_t *target) {
3542 char buf[sizeof("18446744073709551615")]; /* 2^64-1 */
3543 isc_result_t result = ISC_R_SUCCESS;
3544 uint32_t u;
3545 uint64_t q;
3546 const char *sep1 = " ", *sep2 = ", ";
3547 size_t count = msg->indent.count;
3548 bool yaml = false;
3549
3550 if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0) {
3551 sep1 = sep2 = "\n";
3552 msg->indent.count++;
3553 yaml = true;
3554 }
3555
3556 u = isc_buffer_getuint16(optbuf);
3557 ADD_STRING(target, sep1);
3558 INDENT(style);
3559 if (yaml) {
3560 ADD_STRING(target, "LLQ-VERSION: ");
3561 } else {
3562 ADD_STRING(target, "Version: ");
3563 }
3564 snprintf(buf, sizeof(buf), "%u", u);
3565 ADD_STRING(target, buf);
3566
3567 u = isc_buffer_getuint16(optbuf);
3568 ADD_STRING(target, sep2);
3569 INDENT(style);
3570 if (yaml) {
3571 ADD_STRING(target, "LLQ-OPCODE: ");
3572 } else {
3573 ADD_STRING(target, "Opcode: ");
3574 }
3575 snprintf(buf, sizeof(buf), "%u", u);
3576 ADD_STRING(target, buf);
3577
3578 u = isc_buffer_getuint16(optbuf);
3579 ADD_STRING(target, sep2);
3580 INDENT(style);
3581 if (yaml) {
3582 ADD_STRING(target, "LLQ-ERROR: ");
3583 } else {
3584 ADD_STRING(target, "Error: ");
3585 }
3586 snprintf(buf, sizeof(buf), "%u", u);
3587 ADD_STRING(target, buf);
3588
3589 q = isc_buffer_getuint32(optbuf);
3590 q <<= 32;
3591 q |= isc_buffer_getuint32(optbuf);
3592 ADD_STRING(target, sep2);
3593 INDENT(style);
3594 if (yaml) {
3595 ADD_STRING(target, "LLQ-ID: ");
3596 } else {
3597 ADD_STRING(target, "Identifier: ");
3598 }
3599 snprintf(buf, sizeof(buf), "%" PRIu64, q);
3600 ADD_STRING(target, buf);
3601
3602 u = isc_buffer_getuint32(optbuf);
3603 ADD_STRING(target, sep2);
3604 INDENT(style);
3605 if (yaml) {
3606 ADD_STRING(target, "LLQ-LEASE: ");
3607 } else {
3608 ADD_STRING(target, "Lifetime: ");
3609 }
3610 snprintf(buf, sizeof(buf), "%u", u);
3611 ADD_STRING(target, buf);
3612
3613 cleanup:
3614 msg->indent.count = count;
3615 return result;
3616 }
3617
3618 static isc_result_t
3619 put_yamlstr(isc_buffer_t *target, unsigned char *namebuf, size_t len,
3620 bool utfok) {
3621 isc_result_t result = ISC_R_SUCCESS;
3622
3623 for (size_t i = 0; i < len; i++) {
3624 if (isprint(namebuf[i]) || (utfok && namebuf[i] > 127)) {
3625 if (namebuf[i] == '\\' || namebuf[i] == '"') {
3626 ADD_STRING(target, "\\");
3627 }
3628 if (isc_buffer_availablelength(target) < 1) {
3629 return ISC_R_NOSPACE;
3630 }
3631 isc_buffer_putmem(target, &namebuf[i], 1);
3632 } else {
3633 ADD_STRING(target, ".");
3634 }
3635 }
3636 cleanup:
3637 return result;
3638 }
3639
3640 static isc_result_t
3641 render_nameopt(isc_buffer_t *optbuf, bool yaml, isc_buffer_t *target) {
3642 dns_decompress_t dctx = DNS_DECOMPRESS_NEVER;
3643 dns_fixedname_t fixed;
3644 dns_name_t *name = dns_fixedname_initname(&fixed);
3645 char namebuf[DNS_NAME_FORMATSIZE];
3646 isc_result_t result;
3647
3648 result = dns_name_fromwire(name, optbuf, dctx, NULL);
3649 if (result == ISC_R_SUCCESS && isc_buffer_activelength(optbuf) == 0) {
3650 dns_name_format(name, namebuf, sizeof(namebuf));
3651 ADD_STRING(target, " \"");
3652 if (yaml) {
3653 PUT_YAMLSTR(target, (unsigned char *)namebuf,
3654 strlen(namebuf), false);
3655 } else {
3656 ADD_STRING(target, namebuf);
3657 }
3658 ADD_STRING(target, "\"");
3659 return result;
3660 }
3661 result = ISC_R_FAILURE;
3662 cleanup:
3663 return result;
3664 }
3665
3666 static const char *option_names[] = {
3667 [DNS_OPT_LLQ] = "LLQ",
3668 [DNS_OPT_UL] = "UPDATE-LEASE",
3669 [DNS_OPT_NSID] = "NSID",
3670 [DNS_OPT_DAU] = "DAU",
3671 [DNS_OPT_DHU] = "DHU",
3672 [DNS_OPT_N3U] = "N3U",
3673 [DNS_OPT_CLIENT_SUBNET] = "CLIENT-SUBNET",
3674 [DNS_OPT_EXPIRE] = "EXPIRE",
3675 [DNS_OPT_COOKIE] = "COOKIE",
3676 [DNS_OPT_TCP_KEEPALIVE] = "TCP-KEEPALIVE",
3677 [DNS_OPT_PAD] = "PADDING",
3678 [DNS_OPT_CHAIN] = "CHAIN",
3679 [DNS_OPT_KEY_TAG] = "KEY-TAG",
3680 [DNS_OPT_EDE] = "EDE",
3681 [DNS_OPT_CLIENT_TAG] = "CLIENT-TAG",
3682 [DNS_OPT_SERVER_TAG] = "SERVER-TAG",
3683 [DNS_OPT_REPORT_CHANNEL] = "Report-Channel",
3684 [DNS_OPT_ZONEVERSION] = "ZONEVERSION",
3685 };
3686
3687 static isc_result_t
3688 dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section,
3689 const dns_master_style_t *style,
3690 dns_messagetextflag_t flags,
3691 isc_buffer_t *target) {
3692 dns_rdataset_t *ps = NULL;
3693 const dns_name_t *name = NULL;
3694 isc_result_t result = ISC_R_SUCCESS;
3695 char buf[sizeof("/1234567890")];
3696 uint32_t mbz;
3697 dns_rdata_t rdata;
3698 isc_buffer_t optbuf;
3699 uint16_t optcode, optlen;
3700 size_t saved_count;
3701 unsigned char *optdata = NULL;
3702 unsigned int indent;
3703 isc_buffer_t ecsbuf;
3704
3705 REQUIRE(DNS_MESSAGE_VALID(msg));
3706 REQUIRE(target != NULL);
3707 REQUIRE(VALID_NAMED_PSEUDOSECTION(section));
3708
3709 saved_count = msg->indent.count;
3710
3711 switch (section) {
3712 case DNS_PSEUDOSECTION_OPT:
3713 ps = dns_message_getopt(msg);
3714 if (ps == NULL) {
3715 goto cleanup;
3716 }
3717
3718 INDENT(style);
3719 ADD_STRING(target, "OPT_PSEUDOSECTION:\n");
3720 msg->indent.count++;
3721
3722 INDENT(style);
3723 ADD_STRING(target, "EDNS:\n");
3724 indent = ++msg->indent.count;
3725
3726 INDENT(style);
3727 ADD_STRING(target, "version: ");
3728 snprintf(buf, sizeof(buf), "%u",
3729 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3730 ADD_STRING(target, buf);
3731 ADD_STRING(target, "\n");
3732 INDENT(style);
3733 ADD_STRING(target, "flags:");
3734 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) {
3735 ADD_STRING(target, " do");
3736 }
3737 if ((ps->ttl & DNS_MESSAGEEXTFLAG_CO) != 0) {
3738 ADD_STRING(target, " co");
3739 }
3740 ADD_STRING(target, "\n");
3741 mbz = ps->ttl & 0xffff;
3742 /* Exclude Known Flags. */
3743 mbz &= ~(DNS_MESSAGEEXTFLAG_DO | DNS_MESSAGEEXTFLAG_CO);
3744 if (mbz != 0) {
3745 INDENT(style);
3746 ADD_STRING(target, "MBZ: ");
3747 snprintf(buf, sizeof(buf), "0x%.4x", mbz);
3748 ADD_STRING(target, buf);
3749 ADD_STRING(target, "\n");
3750 }
3751 INDENT(style);
3752 ADD_STRING(target, "udp: ");
3753 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3754 ADD_STRING(target, buf);
3755 result = dns_rdataset_first(ps);
3756 if (result != ISC_R_SUCCESS) {
3757 result = ISC_R_SUCCESS;
3758 goto cleanup;
3759 }
3760
3761 /*
3762 * Print EDNS info, if any.
3763 *
3764 * WARNING: The option contents may be malformed as
3765 * dig +ednsopt=value:<content> does not perform validity
3766 * checking.
3767 */
3768 dns_rdata_init(&rdata);
3769 dns_rdataset_current(ps, &rdata);
3770
3771 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3772 isc_buffer_add(&optbuf, rdata.length);
3773 while (isc_buffer_remaininglength(&optbuf) != 0) {
3774 bool extra_text = false;
3775 const char *option_name = NULL;
3776
3777 msg->indent.count = indent;
3778 INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3779 optcode = isc_buffer_getuint16(&optbuf);
3780 optlen = isc_buffer_getuint16(&optbuf);
3781 INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3782
3783 INDENT(style);
3784 if (optcode < ARRAY_SIZE(option_names)) {
3785 option_name = option_names[optcode];
3786 }
3787 if (option_name != NULL) {
3788 ADD_STRING(target, option_names[optcode])
3789 } else {
3790 snprintf(buf, sizeof(buf), "OPT=%u", optcode);
3791 ADD_STRING(target, buf);
3792 }
3793 ADD_STRING(target, ":");
3794
3795 switch (optcode) {
3796 case DNS_OPT_LLQ:
3797 if (optlen == 18U) {
3798 result = render_llq(&optbuf, msg, style,
3799 target);
3800 if (result != ISC_R_SUCCESS) {
3801 goto cleanup;
3802 }
3803 ADD_STRING(target, "\n");
3804 continue;
3805 }
3806 break;
3807 case DNS_OPT_UL:
3808 if (optlen == 4U || optlen == 8U) {
3809 uint32_t secs, key = 0;
3810 msg->indent.count++;
3811
3812 secs = isc_buffer_getuint32(&optbuf);
3813 ADD_STRING(target, "\n");
3814 INDENT(style);
3815 ADD_STRING(target, "LEASE:");
3816 snprintf(buf, sizeof(buf), " %u", secs);
3817 ADD_STRING(target, buf);
3818
3819 ADD_STRING(target, " # ");
3820 result = dns_ttl_totext(secs, true,
3821 true, target);
3822 if (result != ISC_R_SUCCESS) {
3823 goto cleanup;
3824 }
3825 ADD_STRING(target, "\n");
3826
3827 if (optlen == 8U) {
3828 key = isc_buffer_getuint32(
3829 &optbuf);
3830 INDENT(style);
3831 ADD_STRING(target,
3832 "KEY-LEASE:");
3833 snprintf(buf, sizeof(buf),
3834 " %u", key);
3835 ADD_STRING(target, buf);
3836
3837 ADD_STRING(target, " # ");
3838 result = dns_ttl_totext(
3839 key, true, true,
3840 target);
3841 if (result != ISC_R_SUCCESS) {
3842 goto cleanup;
3843 }
3844 ADD_STRING(target, "\n");
3845 }
3846 continue;
3847 }
3848 break;
3849 case DNS_OPT_CLIENT_SUBNET:
3850 isc_buffer_init(&ecsbuf,
3851 isc_buffer_current(&optbuf),
3852 optlen);
3853 isc_buffer_add(&ecsbuf, optlen);
3854 result = render_ecs(&ecsbuf, target);
3855 if (result == ISC_R_NOSPACE) {
3856 goto cleanup;
3857 }
3858 if (result == ISC_R_SUCCESS) {
3859 isc_buffer_forward(&optbuf, optlen);
3860 ADD_STRING(target, "\n");
3861 continue;
3862 }
3863 ADD_STRING(target, "\n");
3864 break;
3865 case DNS_OPT_EXPIRE:
3866 if (optlen == 4) {
3867 uint32_t secs;
3868 secs = isc_buffer_getuint32(&optbuf);
3869 snprintf(buf, sizeof(buf), " %u", secs);
3870 ADD_STRING(target, buf);
3871 ADD_STRING(target, " # ");
3872 result = dns_ttl_totext(secs, true,
3873 true, target);
3874 if (result != ISC_R_SUCCESS) {
3875 goto cleanup;
3876 }
3877 ADD_STRING(target, "\n");
3878 continue;
3879 }
3880 break;
3881 case DNS_OPT_TCP_KEEPALIVE:
3882 if (optlen == 2) {
3883 unsigned int dsecs;
3884 dsecs = isc_buffer_getuint16(&optbuf);
3885 snprintf(buf, sizeof(buf), " %u.%u",
3886 dsecs / 10U, dsecs % 10U);
3887 ADD_STRING(target, buf);
3888 ADD_STRING(target, " secs\n");
3889 continue;
3890 }
3891 break;
3892 case DNS_OPT_CHAIN:
3893 case DNS_OPT_REPORT_CHANNEL:
3894 if (optlen > 0U) {
3895 isc_buffer_t sb = optbuf;
3896 isc_buffer_setactive(&optbuf, optlen);
3897 result = render_nameopt(&optbuf, true,
3898 target);
3899 if (result == ISC_R_SUCCESS) {
3900 ADD_STRING(target, "\n");
3901 continue;
3902 }
3903 optbuf = sb;
3904 }
3905 break;
3906 case DNS_OPT_KEY_TAG:
3907 if (optlen > 0U && (optlen % 2U) == 0U) {
3908 const char *sep = " [";
3909 while (optlen > 0U) {
3910 uint16_t id =
3911 isc_buffer_getuint16(
3912 &optbuf);
3913 snprintf(buf, sizeof(buf),
3914 "%s %u", sep, id);
3915 ADD_STRING(target, buf);
3916 sep = ",";
3917 optlen -= 2;
3918 }
3919 ADD_STRING(target, " ]\n");
3920 continue;
3921 }
3922 break;
3923 case DNS_OPT_EDE:
3924 if (optlen >= 2U) {
3925 uint16_t ede;
3926 ADD_STRING(target, "\n");
3927 msg->indent.count++;
3928 INDENT(style);
3929 ADD_STRING(target, "INFO-CODE:");
3930 ede = isc_buffer_getuint16(&optbuf);
3931 snprintf(buf, sizeof(buf), " %u", ede);
3932 ADD_STRING(target, buf);
3933 if (ede < ARRAY_SIZE(edetext)) {
3934 ADD_STRING(target, " (");
3935 ADD_STRING(target,
3936 edetext[ede]);
3937 ADD_STRING(target, ")");
3938 }
3939 ADD_STRING(target, "\n");
3940 optlen -= 2;
3941 if (optlen != 0) {
3942 INDENT(style);
3943 ADD_STRING(target,
3944 "EXTRA-TEXT:");
3945 extra_text = true;
3946 }
3947 }
3948 break;
3949 case DNS_OPT_CLIENT_TAG:
3950 case DNS_OPT_SERVER_TAG:
3951 if (optlen == 2U) {
3952 uint16_t id =
3953 isc_buffer_getuint16(&optbuf);
3954 snprintf(buf, sizeof(buf), " %u\n", id);
3955 ADD_STRING(target, buf);
3956 continue;
3957 }
3958 break;
3959 case DNS_OPT_COOKIE:
3960 if (optlen == 8 ||
3961 (optlen >= 16 && optlen < 40))
3962 {
3963 size_t i;
3964
3965 msg->indent.count++;
3966 optdata = isc_buffer_current(&optbuf);
3967
3968 ADD_STRING(target, "\n");
3969 INDENT(style);
3970 ADD_STRING(target, "CLIENT: ");
3971 for (i = 0; i < 8; i++) {
3972 snprintf(buf, sizeof(buf),
3973 "%02x", optdata[i]);
3974 ADD_STRING(target, buf);
3975 }
3976 ADD_STRING(target, "\n");
3977
3978 if (optlen >= 16) {
3979 INDENT(style);
3980 ADD_STRING(target, "SERVER: ");
3981 for (; i < optlen; i++) {
3982 snprintf(buf,
3983 sizeof(buf),
3984 "%02x",
3985 optdata[i]);
3986 ADD_STRING(target, buf);
3987 }
3988 ADD_STRING(target, "\n");
3989 }
3990
3991 /*
3992 * Valid server cookie?
3993 */
3994 if (msg->cc_ok && optlen >= 16) {
3995 INDENT(style);
3996 ADD_STRING(target,
3997 "STATUS: good\n");
3998 }
3999 /*
4000 * Server cookie is not valid but
4001 * we had our cookie echoed back.
4002 */
4003 if (msg->cc_ok && optlen < 16) {
4004 INDENT(style);
4005 ADD_STRING(target,
4006 "STATUS: echoed\n");
4007 }
4008 /*
4009 * We didn't get our cookie echoed
4010 * back.
4011 */
4012 if (msg->cc_bad) {
4013 INDENT(style);
4014 ADD_STRING(target,
4015 "STATUS: bad\n)");
4016 }
4017 isc_buffer_forward(&optbuf, optlen);
4018 continue;
4019 }
4020 break;
4021 default:
4022 break;
4023 }
4024
4025 if (optlen != 0) {
4026 int i;
4027 bool utf8ok = false;
4028
4029 ADD_STRING(target, " ");
4030
4031 optdata = isc_buffer_current(&optbuf);
4032 if (extra_text) {
4033 utf8ok = isc_utf8_valid(optdata,
4034 optlen);
4035 }
4036 if (!utf8ok) {
4037 for (i = 0; i < optlen; i++) {
4038 const char *sep;
4039 switch (optcode) {
4040 case DNS_OPT_COOKIE:
4041 sep = "";
4042 break;
4043 default:
4044 sep = " ";
4045 break;
4046 }
4047 snprintf(buf, sizeof(buf),
4048 "%02x%s", optdata[i],
4049 sep);
4050 ADD_STRING(target, buf);
4051 }
4052 }
4053
4054 isc_buffer_forward(&optbuf, optlen);
4055
4056 if (optcode == DNS_OPT_COOKIE ||
4057 optcode == DNS_OPT_CLIENT_SUBNET)
4058 {
4059 ADD_STRING(target, "\n");
4060 continue;
4061 }
4062
4063 /*
4064 * For non-COOKIE options, add a printable
4065 * version
4066 */
4067 if (!extra_text) {
4068 ADD_STRING(target, "(\"");
4069 } else {
4070 ADD_STRING(target, "\"");
4071 }
4072 PUT_YAMLSTR(target, optdata, optlen, utf8ok);
4073 if (!extra_text) {
4074 ADD_STRING(target, "\")");
4075 } else {
4076 ADD_STRING(target, "\"");
4077 }
4078 }
4079 ADD_STRING(target, "\n");
4080 }
4081 msg->indent.count = indent;
4082 result = ISC_R_SUCCESS;
4083 goto cleanup;
4084 case DNS_PSEUDOSECTION_TSIG:
4085 ps = dns_message_gettsig(msg, &name);
4086 if (ps == NULL) {
4087 result = ISC_R_SUCCESS;
4088 goto cleanup;
4089 }
4090 INDENT(style);
4091 ADD_STRING(target, "TSIG_PSEUDOSECTION:\n");
4092 result = dns_master_rdatasettotext(name, ps, style,
4093 &msg->indent, target);
4094 ADD_STRING(target, "\n");
4095 goto cleanup;
4096 case DNS_PSEUDOSECTION_SIG0:
4097 ps = dns_message_getsig0(msg, &name);
4098 if (ps == NULL) {
4099 result = ISC_R_SUCCESS;
4100 goto cleanup;
4101 }
4102 INDENT(style);
4103 ADD_STRING(target, "SIG0_PSEUDOSECTION:\n");
4104 result = dns_master_rdatasettotext(name, ps, style,
4105 &msg->indent, target);
4106 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
4107 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4108 {
4109 ADD_STRING(target, "\n");
4110 }
4111 goto cleanup;
4112 }
4113
4114 result = ISC_R_UNEXPECTED;
4115
4116 cleanup:
4117 msg->indent.count = saved_count;
4118 return result;
4119 }
4120
4121 isc_result_t
4122 dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section,
4123 const dns_master_style_t *style,
4124 dns_messagetextflag_t flags,
4125 isc_buffer_t *target) {
4126 dns_rdataset_t *ps = NULL;
4127 const dns_name_t *name = NULL;
4128 isc_result_t result;
4129 char buf[sizeof(" (65000 bytes)")];
4130 uint32_t mbz;
4131 dns_rdata_t rdata;
4132 isc_buffer_t optbuf;
4133 uint16_t optcode, optlen;
4134 unsigned char *optdata = NULL;
4135 isc_buffer_t ecsbuf;
4136
4137 REQUIRE(DNS_MESSAGE_VALID(msg));
4138 REQUIRE(target != NULL);
4139 REQUIRE(VALID_NAMED_PSEUDOSECTION(section));
4140
4141 if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0) {
4142 return dns_message_pseudosectiontoyaml(msg, section, style,
4143 flags, target);
4144 }
4145
4146 switch (section) {
4147 case DNS_PSEUDOSECTION_OPT:
4148 ps = dns_message_getopt(msg);
4149 if (ps == NULL) {
4150 return ISC_R_SUCCESS;
4151 }
4152 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
4153 INDENT(style);
4154 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
4155 }
4156
4157 INDENT(style);
4158 ADD_STRING(target, "; EDNS: version: ");
4159 snprintf(buf, sizeof(buf), "%u",
4160 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
4161 ADD_STRING(target, buf);
4162 ADD_STRING(target, ", flags:");
4163 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) {
4164 ADD_STRING(target, " do");
4165 }
4166 if ((ps->ttl & DNS_MESSAGEEXTFLAG_CO) != 0) {
4167 ADD_STRING(target, " co");
4168 }
4169 mbz = ps->ttl & 0xffff;
4170 /* Exclude Known Flags. */
4171 mbz &= ~(DNS_MESSAGEEXTFLAG_DO | DNS_MESSAGEEXTFLAG_CO);
4172 if (mbz != 0) {
4173 ADD_STRING(target, "; MBZ: ");
4174 snprintf(buf, sizeof(buf), "0x%.4x", mbz);
4175 ADD_STRING(target, buf);
4176 ADD_STRING(target, ", udp: ");
4177 } else {
4178 ADD_STRING(target, "; udp: ");
4179 }
4180 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
4181 ADD_STRING(target, buf);
4182
4183 result = dns_rdataset_first(ps);
4184 if (result != ISC_R_SUCCESS) {
4185 return ISC_R_SUCCESS;
4186 }
4187
4188 /*
4189 * Print EDNS info, if any.
4190 *
4191 * WARNING: The option contents may be malformed as
4192 * dig +ednsopt=value:<content> does no validity
4193 * checking.
4194 */
4195 dns_rdata_init(&rdata);
4196 dns_rdataset_current(ps, &rdata);
4197
4198 isc_buffer_init(&optbuf, rdata.data, rdata.length);
4199 isc_buffer_add(&optbuf, rdata.length);
4200 while (isc_buffer_remaininglength(&optbuf) != 0) {
4201 const char *option_name = NULL;
4202
4203 INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
4204 optcode = isc_buffer_getuint16(&optbuf);
4205 optlen = isc_buffer_getuint16(&optbuf);
4206
4207 INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
4208
4209 INDENT(style);
4210 ADD_STRING(target, "; ");
4211 if (optcode < ARRAY_SIZE(option_names)) {
4212 option_name = option_names[optcode];
4213 }
4214 if (option_name != NULL) {
4215 ADD_STRING(target, option_names[optcode])
4216 } else {
4217 snprintf(buf, sizeof(buf), "OPT=%u", optcode);
4218 ADD_STRING(target, buf);
4219 }
4220 ADD_STRING(target, ":");
4221
4222 switch (optcode) {
4223 case DNS_OPT_LLQ:
4224 if (optlen == 18U) {
4225 result = render_llq(&optbuf, msg, style,
4226 target);
4227 if (result != ISC_R_SUCCESS) {
4228 return result;
4229 }
4230 ADD_STRING(target, "\n");
4231 continue;
4232 }
4233 break;
4234 case DNS_OPT_UL:
4235 if (optlen == 4U || optlen == 8U) {
4236 uint32_t secs, key = 0;
4237 secs = isc_buffer_getuint32(&optbuf);
4238 snprintf(buf, sizeof(buf), " %u", secs);
4239 ADD_STRING(target, buf);
4240 if (optlen == 8U) {
4241 key = isc_buffer_getuint32(
4242 &optbuf);
4243 snprintf(buf, sizeof(buf),
4244 "/%u", key);
4245 ADD_STRING(target, buf);
4246 }
4247 ADD_STRING(target, " (");
4248 result = dns_ttl_totext(secs, true,
4249 true, target);
4250 if (result != ISC_R_SUCCESS) {
4251 goto cleanup;
4252 }
4253 if (optlen == 8U) {
4254 ADD_STRING(target, "/");
4255 result = dns_ttl_totext(
4256 key, true, true,
4257 target);
4258 if (result != ISC_R_SUCCESS) {
4259 goto cleanup;
4260 }
4261 }
4262 ADD_STRING(target, ")\n");
4263 continue;
4264 }
4265 break;
4266 case DNS_OPT_CLIENT_SUBNET:
4267 isc_buffer_init(&ecsbuf,
4268 isc_buffer_current(&optbuf),
4269 optlen);
4270 isc_buffer_add(&ecsbuf, optlen);
4271 result = render_ecs(&ecsbuf, target);
4272 if (result == ISC_R_NOSPACE) {
4273 return result;
4274 }
4275 if (result == ISC_R_SUCCESS) {
4276 isc_buffer_forward(&optbuf, optlen);
4277 ADD_STRING(target, "\n");
4278 continue;
4279 }
4280 break;
4281 case DNS_OPT_EXPIRE:
4282 if (optlen == 4) {
4283 uint32_t secs;
4284 secs = isc_buffer_getuint32(&optbuf);
4285 snprintf(buf, sizeof(buf), " %u", secs);
4286 ADD_STRING(target, buf);
4287 ADD_STRING(target, " (");
4288 result = dns_ttl_totext(secs, true,
4289 true, target);
4290 if (result != ISC_R_SUCCESS) {
4291 return result;
4292 }
4293 ADD_STRING(target, ")\n");
4294 continue;
4295 }
4296 break;
4297 case DNS_OPT_TCP_KEEPALIVE:
4298 if (optlen == 2) {
4299 unsigned int dsecs;
4300 dsecs = isc_buffer_getuint16(&optbuf);
4301 snprintf(buf, sizeof(buf), " %u.%u",
4302 dsecs / 10U, dsecs % 10U);
4303 ADD_STRING(target, buf);
4304 ADD_STRING(target, " secs\n");
4305 continue;
4306 }
4307 break;
4308 case DNS_OPT_PAD:
4309 if (optlen > 0U) {
4310 snprintf(buf, sizeof(buf),
4311 " (%u bytes)", optlen);
4312 ADD_STRING(target, buf);
4313 isc_buffer_forward(&optbuf, optlen);
4314 }
4315 ADD_STRING(target, "\n");
4316 continue;
4317 case DNS_OPT_CHAIN:
4318 case DNS_OPT_REPORT_CHANNEL:
4319 if (optlen > 0U) {
4320 isc_buffer_t sb = optbuf;
4321 isc_buffer_setactive(&optbuf, optlen);
4322 result = render_nameopt(&optbuf, false,
4323 target);
4324 if (result == ISC_R_SUCCESS) {
4325 ADD_STRING(target, "\n");
4326 continue;
4327 }
4328 optbuf = sb;
4329 }
4330 ADD_STRING(target, "\n");
4331 break;
4332 case DNS_OPT_KEY_TAG:
4333 if (optlen > 0U && (optlen % 2U) == 0U) {
4334 const char *sep = "";
4335 while (optlen > 0U) {
4336 uint16_t id =
4337 isc_buffer_getuint16(
4338 &optbuf);
4339 snprintf(buf, sizeof(buf),
4340 "%s %u", sep, id);
4341 ADD_STRING(target, buf);
4342 sep = ",";
4343 optlen -= 2;
4344 }
4345 ADD_STRING(target, "\n");
4346 continue;
4347 }
4348 break;
4349 case DNS_OPT_EDE:
4350 if (optlen >= 2U) {
4351 uint16_t ede;
4352 ede = isc_buffer_getuint16(&optbuf);
4353 snprintf(buf, sizeof(buf), " %u", ede);
4354 ADD_STRING(target, buf);
4355 if (ede < ARRAY_SIZE(edetext)) {
4356 ADD_STRING(target, " (");
4357 ADD_STRING(target,
4358 edetext[ede]);
4359 ADD_STRING(target, ")");
4360 }
4361 optlen -= 2;
4362 if (optlen != 0) {
4363 ADD_STRING(target, ":");
4364 }
4365 } else if (optlen == 1U) {
4366 /* Malformed */
4367 optdata = isc_buffer_current(&optbuf);
4368 snprintf(buf, sizeof(buf),
4369 " %02x (\"%c\")\n", optdata[0],
4370 isprint(optdata[0])
4371 ? optdata[0]
4372 : '.');
4373 isc_buffer_forward(&optbuf, optlen);
4374 ADD_STRING(target, buf);
4375 continue;
4376 }
4377 break;
4378 case DNS_OPT_CLIENT_TAG:
4379 case DNS_OPT_SERVER_TAG:
4380 if (optlen == 2U) {
4381 uint16_t id =
4382 isc_buffer_getuint16(&optbuf);
4383 snprintf(buf, sizeof(buf), " %u\n", id);
4384 ADD_STRING(target, buf);
4385 continue;
4386 }
4387 break;
4388 default:
4389 break;
4390 }
4391
4392 if (optlen != 0) {
4393 int i;
4394 bool utf8ok = false;
4395
4396 ADD_STRING(target, " ");
4397
4398 optdata = isc_buffer_current(&optbuf);
4399 if (optcode == DNS_OPT_EDE) {
4400 utf8ok = isc_utf8_valid(optdata,
4401 optlen);
4402 }
4403 if (!utf8ok) {
4404 for (i = 0; i < optlen; i++) {
4405 const char *sep;
4406 switch (optcode) {
4407 case DNS_OPT_COOKIE:
4408 sep = "";
4409 break;
4410 default:
4411 sep = " ";
4412 break;
4413 }
4414 snprintf(buf, sizeof(buf),
4415 "%02x%s", optdata[i],
4416 sep);
4417 ADD_STRING(target, buf);
4418 }
4419 }
4420
4421 isc_buffer_forward(&optbuf, optlen);
4422
4423 if (optcode == DNS_OPT_COOKIE) {
4424 /*
4425 * Valid server cookie?
4426 */
4427 if (msg->cc_ok && optlen >= 16) {
4428 ADD_STRING(target, " (good)");
4429 }
4430 /*
4431 * Server cookie is not valid but
4432 * we had our cookie echoed back.
4433 */
4434 if (msg->cc_ok && optlen < 16) {
4435 ADD_STRING(target, " (echoed)");
4436 }
4437 /*
4438 * We didn't get our cookie echoed
4439 * back.
4440 */
4441 if (msg->cc_bad) {
4442 ADD_STRING(target, " (bad)");
4443 }
4444 ADD_STRING(target, "\n");
4445 continue;
4446 }
4447
4448 if (optcode == DNS_OPT_CLIENT_SUBNET) {
4449 ADD_STRING(target, "\n");
4450 continue;
4451 }
4452
4453 /*
4454 * For non-COOKIE options, add a printable
4455 * version.
4456 */
4457 if (optcode != DNS_OPT_EDE) {
4458 ADD_STRING(target, "(\"");
4459 } else {
4460 ADD_STRING(target, "(");
4461 }
4462 if (isc_buffer_availablelength(target) < optlen)
4463 {
4464 return ISC_R_NOSPACE;
4465 }
4466 for (i = 0; i < optlen; i++) {
4467 if (isprint(optdata[i]) ||
4468 (utf8ok && optdata[i] > 127))
4469 {
4470 isc_buffer_putmem(
4471 target, &optdata[i], 1);
4472 } else {
4473 isc_buffer_putstr(target, ".");
4474 }
4475 }
4476 if (optcode != DNS_OPT_EDE) {
4477 ADD_STRING(target, "\")");
4478 } else {
4479 ADD_STRING(target, ")");
4480 }
4481 }
4482 ADD_STRING(target, "\n");
4483 }
4484 return ISC_R_SUCCESS;
4485 case DNS_PSEUDOSECTION_TSIG:
4486 ps = dns_message_gettsig(msg, &name);
4487 if (ps == NULL) {
4488 return ISC_R_SUCCESS;
4489 }
4490 INDENT(style);
4491 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
4492 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
4493 }
4494 result = dns_master_rdatasettotext(name, ps, style,
4495 &msg->indent, target);
4496 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
4497 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4498 {
4499 ADD_STRING(target, "\n");
4500 }
4501 return result;
4502 case DNS_PSEUDOSECTION_SIG0:
4503 ps = dns_message_getsig0(msg, &name);
4504 if (ps == NULL) {
4505 return ISC_R_SUCCESS;
4506 }
4507 INDENT(style);
4508 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
4509 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
4510 }
4511 result = dns_master_rdatasettotext(name, ps, style,
4512 &msg->indent, target);
4513 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
4514 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4515 {
4516 ADD_STRING(target, "\n");
4517 }
4518 return result;
4519 }
4520 result = ISC_R_UNEXPECTED;
4521 cleanup:
4522 return result;
4523 }
4524
4525 isc_result_t
4526 dns_message_headertotext(dns_message_t *msg, const dns_master_style_t *style,
4527 dns_messagetextflag_t flags, isc_buffer_t *target) {
4528 char buf[sizeof("1234567890")];
4529 isc_result_t result;
4530
4531 REQUIRE(DNS_MESSAGE_VALID(msg));
4532 REQUIRE(target != NULL);
4533
4534 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) != 0) {
4535 return ISC_R_SUCCESS;
4536 }
4537
4538 if (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) {
4539 INDENT(style);
4540 ADD_STRING(target, "opcode: ");
4541 ADD_STRING(target, opcodetext[msg->opcode]);
4542 ADD_STRING(target, "\n");
4543 INDENT(style);
4544 ADD_STRING(target, "status: ");
4545 result = dns_rcode_totext(msg->rcode, target);
4546 if (result != ISC_R_SUCCESS) {
4547 return result;
4548 }
4549 ADD_STRING(target, "\n");
4550 INDENT(style);
4551 ADD_STRING(target, "id: ");
4552 snprintf(buf, sizeof(buf), "%u", msg->id);
4553 ADD_STRING(target, buf);
4554 ADD_STRING(target, "\n");
4555 INDENT(style);
4556 ADD_STRING(target, "flags:");
4557 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
4558 ADD_STRING(target, " qr");
4559 }
4560 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
4561 ADD_STRING(target, " aa");
4562 }
4563 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
4564 ADD_STRING(target, " tc");
4565 }
4566 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
4567 ADD_STRING(target, " rd");
4568 }
4569 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
4570 ADD_STRING(target, " ra");
4571 }
4572 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
4573 ADD_STRING(target, " ad");
4574 }
4575 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
4576 ADD_STRING(target, " cd");
4577 }
4578 ADD_STRING(target, "\n");
4579 /*
4580 * The final unnamed flag must be zero.
4581 */
4582 if ((msg->flags & 0x0040U) != 0) {
4583 INDENT(style);
4584 ADD_STRING(target, "MBZ: 0x4");
4585 ADD_STRING(target, "\n");
4586 }
4587 if (msg->opcode != dns_opcode_update) {
4588 INDENT(style);
4589 ADD_STRING(target, "QUESTION: ");
4590 } else {
4591 INDENT(style);
4592 ADD_STRING(target, "ZONE: ");
4593 }
4594 snprintf(buf, sizeof(buf), "%1u",
4595 msg->counts[DNS_SECTION_QUESTION]);
4596 ADD_STRING(target, buf);
4597 ADD_STRING(target, "\n");
4598 if (msg->opcode != dns_opcode_update) {
4599 INDENT(style);
4600 ADD_STRING(target, "ANSWER: ");
4601 } else {
4602 INDENT(style);
4603 ADD_STRING(target, "PREREQ: ");
4604 }
4605 snprintf(buf, sizeof(buf), "%1u",
4606 msg->counts[DNS_SECTION_ANSWER]);
4607 ADD_STRING(target, buf);
4608 ADD_STRING(target, "\n");
4609 if (msg->opcode != dns_opcode_update) {
4610 INDENT(style);
4611 ADD_STRING(target, "AUTHORITY: ");
4612 } else {
4613 INDENT(style);
4614 ADD_STRING(target, "UPDATE: ");
4615 }
4616 snprintf(buf, sizeof(buf), "%1u",
4617 msg->counts[DNS_SECTION_AUTHORITY]);
4618 ADD_STRING(target, buf);
4619 ADD_STRING(target, "\n");
4620 INDENT(style);
4621 ADD_STRING(target, "ADDITIONAL: ");
4622 snprintf(buf, sizeof(buf), "%1u",
4623 msg->counts[DNS_SECTION_ADDITIONAL]);
4624 ADD_STRING(target, buf);
4625 ADD_STRING(target, "\n");
4626 } else {
4627 INDENT(style);
4628 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
4629 ADD_STRING(target, opcodetext[msg->opcode]);
4630 ADD_STRING(target, ", status: ");
4631 result = dns_rcode_totext(msg->rcode, target);
4632 if (result != ISC_R_SUCCESS) {
4633 return result;
4634 }
4635 ADD_STRING(target, ", id: ");
4636 snprintf(buf, sizeof(buf), "%6u", msg->id);
4637 ADD_STRING(target, buf);
4638 ADD_STRING(target, "\n");
4639 INDENT(style);
4640 ADD_STRING(target, ";; flags:");
4641 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
4642 ADD_STRING(target, " qr");
4643 }
4644 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
4645 ADD_STRING(target, " aa");
4646 }
4647 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
4648 ADD_STRING(target, " tc");
4649 }
4650 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
4651 ADD_STRING(target, " rd");
4652 }
4653 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
4654 ADD_STRING(target, " ra");
4655 }
4656 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
4657 ADD_STRING(target, " ad");
4658 }
4659 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
4660 ADD_STRING(target, " cd");
4661 }
4662 /*
4663 * The final unnamed flag must be zero.
4664 */
4665 if ((msg->flags & 0x0040U) != 0) {
4666 INDENT(style);
4667 ADD_STRING(target, "; MBZ: 0x4");
4668 }
4669 if (msg->opcode != dns_opcode_update) {
4670 INDENT(style);
4671 ADD_STRING(target, "; QUESTION: ");
4672 } else {
4673 INDENT(style);
4674 ADD_STRING(target, "; ZONE: ");
4675 }
4676 snprintf(buf, sizeof(buf), "%1u",
4677 msg->counts[DNS_SECTION_QUESTION]);
4678 ADD_STRING(target, buf);
4679 if (msg->opcode != dns_opcode_update) {
4680 ADD_STRING(target, ", ANSWER: ");
4681 } else {
4682 ADD_STRING(target, ", PREREQ: ");
4683 }
4684 snprintf(buf, sizeof(buf), "%1u",
4685 msg->counts[DNS_SECTION_ANSWER]);
4686 ADD_STRING(target, buf);
4687 if (msg->opcode != dns_opcode_update) {
4688 ADD_STRING(target, ", AUTHORITY: ");
4689 } else {
4690 ADD_STRING(target, ", UPDATE: ");
4691 }
4692 snprintf(buf, sizeof(buf), "%1u",
4693 msg->counts[DNS_SECTION_AUTHORITY]);
4694 ADD_STRING(target, buf);
4695 ADD_STRING(target, ", ADDITIONAL: ");
4696 snprintf(buf, sizeof(buf), "%1u",
4697 msg->counts[DNS_SECTION_ADDITIONAL]);
4698 ADD_STRING(target, buf);
4699 ADD_STRING(target, "\n");
4700 }
4701
4702 cleanup:
4703 return result;
4704 }
4705
4706 isc_result_t
4707 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
4708 dns_messagetextflag_t flags, isc_buffer_t *target) {
4709 isc_result_t result;
4710
4711 REQUIRE(DNS_MESSAGE_VALID(msg));
4712 REQUIRE(target != NULL);
4713
4714 result = dns_message_headertotext(msg, style, flags, target);
4715 if (result != ISC_R_SUCCESS) {
4716 return result;
4717 }
4718
4719 result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_OPT,
4720 style, flags, target);
4721 if (result != ISC_R_SUCCESS) {
4722 return result;
4723 }
4724
4725 result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION, style,
4726 flags, target);
4727 if (result != ISC_R_SUCCESS) {
4728 return result;
4729 }
4730
4731 result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER, style,
4732 flags, target);
4733 if (result != ISC_R_SUCCESS) {
4734 return result;
4735 }
4736
4737 result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY, style,
4738 flags, target);
4739 if (result != ISC_R_SUCCESS) {
4740 return result;
4741 }
4742
4743 result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL, style,
4744 flags, target);
4745 if (result != ISC_R_SUCCESS) {
4746 return result;
4747 }
4748
4749 result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_TSIG,
4750 style, flags, target);
4751 if (result != ISC_R_SUCCESS) {
4752 return result;
4753 }
4754
4755 result = dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_SIG0,
4756 style, flags, target);
4757 return result;
4758 }
4759
4760 isc_region_t *
4761 dns_message_getrawmessage(dns_message_t *msg) {
4762 REQUIRE(DNS_MESSAGE_VALID(msg));
4763 return &msg->saved;
4764 }
4765
4766 void
4767 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
4768 dns_aclenv_t *env, dns_acl_t *acl,
4769 const dns_aclelement_t *elem) {
4770 REQUIRE(DNS_MESSAGE_VALID(msg));
4771 REQUIRE((order == NULL) == (env == NULL));
4772 REQUIRE(env == NULL || (acl != NULL || elem != NULL));
4773
4774 msg->order = order;
4775 if (env != NULL) {
4776 dns_aclenv_attach(env, &msg->order_arg.env);
4777 }
4778 if (acl != NULL) {
4779 dns_acl_attach(acl, &msg->order_arg.acl);
4780 }
4781 msg->order_arg.element = elem;
4782 }
4783
4784 void
4785 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
4786 REQUIRE(DNS_MESSAGE_VALID(msg));
4787 msg->timeadjust = timeadjust;
4788 }
4789
4790 int
4791 dns_message_gettimeadjust(dns_message_t *msg) {
4792 REQUIRE(DNS_MESSAGE_VALID(msg));
4793 return msg->timeadjust;
4794 }
4795
4796 isc_result_t
4797 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
4798 REQUIRE(opcode < 16);
4799
4800 if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode])) {
4801 return ISC_R_NOSPACE;
4802 }
4803 isc_buffer_putstr(target, opcodetext[opcode]);
4804 return ISC_R_SUCCESS;
4805 }
4806
4807 void
4808 dns_message_logpacket(dns_message_t *message, const char *description,
4809 const isc_sockaddr_t *address,
4810 isc_logcategory_t *category, isc_logmodule_t *module,
4811 int level, isc_mem_t *mctx) {
4812 REQUIRE(address != NULL);
4813
4814 logfmtpacket(message, description, address, category, module,
4815 &dns_master_style_debug, level, mctx);
4816 }
4817
4818 void
4819 dns_message_logfmtpacket(dns_message_t *message, const char *description,
4820 const isc_sockaddr_t *address,
4821 isc_logcategory_t *category, isc_logmodule_t *module,
4822 const dns_master_style_t *style, int level,
4823 isc_mem_t *mctx) {
4824 REQUIRE(address != NULL);
4825
4826 logfmtpacket(message, description, address, category, module, style,
4827 level, mctx);
4828 }
4829
4830 static void
4831 logfmtpacket(dns_message_t *message, const char *description,
4832 const isc_sockaddr_t *address, isc_logcategory_t *category,
4833 isc_logmodule_t *module, const dns_master_style_t *style,
4834 int level, isc_mem_t *mctx) {
4835 char addrbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
4836 const char *newline = "\n";
4837 const char *space = " ";
4838 isc_buffer_t buffer;
4839 char *buf = NULL;
4840 int len = 1024;
4841 isc_result_t result;
4842
4843 if (!isc_log_wouldlog(dns_lctx, level)) {
4844 return;
4845 }
4846
4847 /*
4848 * Note that these are multiline debug messages. We want a newline
4849 * to appear in the log after each message.
4850 */
4851
4852 if (address != NULL) {
4853 isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
4854 } else {
4855 newline = space = "";
4856 }
4857
4858 do {
4859 buf = isc_mem_get(mctx, len);
4860 isc_buffer_init(&buffer, buf, len);
4861 result = dns_message_totext(message, style, 0, &buffer);
4862 if (result == ISC_R_NOSPACE) {
4863 isc_mem_put(mctx, buf, len);
4864 len += 1024;
4865 } else if (result == ISC_R_SUCCESS) {
4866 isc_log_write(dns_lctx, category, module, level,
4867 "%s%s%s%s%.*s", description, space,
4868 addrbuf, newline,
4869 (int)isc_buffer_usedlength(&buffer), buf);
4870 }
4871 } while (result == ISC_R_NOSPACE);
4872
4873 if (buf != NULL) {
4874 isc_mem_put(mctx, buf, len);
4875 }
4876 }
4877
4878 isc_result_t
4879 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
4880 unsigned int version, uint16_t udpsize, unsigned int flags,
4881 dns_ednsopt_t *ednsopts, size_t count) {
4882 dns_rdataset_t *rdataset = NULL;
4883 dns_rdatalist_t *rdatalist = NULL;
4884 dns_rdata_t *rdata = NULL;
4885 isc_result_t result;
4886 unsigned int len = 0, i;
4887
4888 REQUIRE(DNS_MESSAGE_VALID(message));
4889 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
4890
4891 dns_message_gettemprdatalist(message, &rdatalist);
4892 dns_message_gettemprdata(message, &rdata);
4893 dns_message_gettemprdataset(message, &rdataset);
4894
4895 rdatalist->type = dns_rdatatype_opt;
4896
4897 /*
4898 * Set Maximum UDP buffer size.
4899 */
4900 rdatalist->rdclass = udpsize;
4901
4902 /*
4903 * Set EXTENDED-RCODE and Z to 0.
4904 */
4905 rdatalist->ttl = (version << 16);
4906 rdatalist->ttl |= (flags & 0xffff);
4907
4908 /*
4909 * Set EDNS options if applicable
4910 */
4911 if (count != 0U) {
4912 isc_buffer_t *buf = NULL;
4913 bool seenpad = false;
4914 for (i = 0; i < count; i++) {
4915 len += ednsopts[i].length + 4;
4916 }
4917
4918 if (len > 0xffffU) {
4919 result = ISC_R_NOSPACE;
4920 goto cleanup;
4921 }
4922
4923 isc_buffer_allocate(message->mctx, &buf, len);
4924
4925 for (i = 0; i < count; i++) {
4926 if (ednsopts[i].code == DNS_OPT_PAD &&
4927 ednsopts[i].length == 0U && !seenpad)
4928 {
4929 seenpad = true;
4930 continue;
4931 }
4932 isc_buffer_putuint16(buf, ednsopts[i].code);
4933 isc_buffer_putuint16(buf, ednsopts[i].length);
4934 if (ednsopts[i].length != 0) {
4935 isc_buffer_putmem(buf, ednsopts[i].value,
4936 ednsopts[i].length);
4937 }
4938 }
4939
4940 /* Padding must be the final option */
4941 if (seenpad) {
4942 isc_buffer_putuint16(buf, DNS_OPT_PAD);
4943 isc_buffer_putuint16(buf, 0);
4944 }
4945 rdata->data = isc_buffer_base(buf);
4946 rdata->length = len;
4947 dns_message_takebuffer(message, &buf);
4948 if (seenpad) {
4949 message->padding_off = len;
4950 }
4951 } else {
4952 rdata->data = NULL;
4953 rdata->length = 0;
4954 }
4955
4956 rdata->rdclass = rdatalist->rdclass;
4957 rdata->type = rdatalist->type;
4958 rdata->flags = 0;
4959
4960 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
4961 dns_rdatalist_tordataset(rdatalist, rdataset);
4962
4963 *rdatasetp = rdataset;
4964 return ISC_R_SUCCESS;
4965
4966 cleanup:
4967 dns_message_puttemprdata(message, &rdata);
4968 dns_message_puttemprdataset(message, &rdataset);
4969 dns_message_puttemprdatalist(message, &rdatalist);
4970 return result;
4971 }
4972
4973 void
4974 dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
4975 REQUIRE(DNS_MESSAGE_VALID(msg));
4976 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
4977 REQUIRE(msg->state == DNS_SECTION_ANY);
4978 REQUIRE(msg->rdclass_set == 0);
4979
4980 msg->rdclass = rdclass;
4981 msg->rdclass_set = 1;
4982 }
4983
4984 void
4985 dns_message_setpadding(dns_message_t *msg, uint16_t padding) {
4986 REQUIRE(DNS_MESSAGE_VALID(msg));
4987
4988 /* Avoid silly large padding */
4989 if (padding > 512) {
4990 padding = 512;
4991 }
4992 msg->padding = padding;
4993 }
4994
4995 void
4996 dns_message_clonebuffer(dns_message_t *msg) {
4997 REQUIRE(DNS_MESSAGE_VALID(msg));
4998
4999 if (msg->free_saved == 0 && msg->saved.base != NULL) {
5000 msg->saved.base =
5001 memmove(isc_mem_get(msg->mctx, msg->saved.length),
5002 msg->saved.base, msg->saved.length);
5003 msg->free_saved = 1;
5004 }
5005 if (msg->free_query == 0 && msg->query.base != NULL) {
5006 msg->query.base =
5007 memmove(isc_mem_get(msg->mctx, msg->query.length),
5008 msg->query.base, msg->query.length);
5009 msg->free_query = 1;
5010 }
5011 }
5012
5013 static isc_result_t
5014 rdataset_soa_min(dns_rdataset_t *rds, dns_ttl_t *ttlp) {
5015 isc_result_t result;
5016 /* loop over the rdatas */
5017 for (result = dns_rdataset_first(rds); result == ISC_R_SUCCESS;
5018 result = dns_rdataset_next(rds))
5019 {
5020 dns_name_t tmp;
5021 isc_region_t r = { 0 };
5022 dns_rdata_t rdata = DNS_RDATA_INIT;
5023
5024 dns_rdataset_current(rds, &rdata);
5025
5026 switch (rdata.type) {
5027 case dns_rdatatype_soa:
5028 /* SOA rdataset */
5029 break;
5030 case dns_rdatatype_none:
5031 /*
5032 * Negative cache rdataset: we need
5033 * to inspect the rdata to determine
5034 * whether it's an SOA.
5035 */
5036 dns_rdata_toregion(&rdata, &r);
5037 dns_name_init(&tmp, NULL);
5038 dns_name_fromregion(&tmp, &r);
5039 isc_region_consume(&r, tmp.length);
5040 if (r.length < 2) {
5041 continue;
5042 }
5043 rdata.type = r.base[0] << 8 | r.base[1];
5044 if (rdata.type != dns_rdatatype_soa) {
5045 continue;
5046 }
5047 break;
5048 default:
5049 continue;
5050 }
5051
5052 if (rdata.type == dns_rdatatype_soa) {
5053 *ttlp = ISC_MIN(rds->ttl, dns_soa_getminimum(&rdata));
5054 return ISC_R_SUCCESS;
5055 }
5056 }
5057
5058 return ISC_R_NOTFOUND;
5059 }
5060
5061 static isc_result_t
5062 message_authority_soa_min(dns_message_t *msg, dns_ttl_t *ttlp) {
5063 isc_result_t result;
5064
5065 if (msg->counts[DNS_SECTION_AUTHORITY] == 0) {
5066 return ISC_R_NOTFOUND;
5067 }
5068
5069 for (result = dns_message_firstname(msg, DNS_SECTION_AUTHORITY);
5070 result == ISC_R_SUCCESS;
5071 result = dns_message_nextname(msg, DNS_SECTION_AUTHORITY))
5072 {
5073 dns_name_t *name = NULL;
5074 dns_message_currentname(msg, DNS_SECTION_AUTHORITY, &name);
5075
5076 dns_rdataset_t *rds = NULL;
5077 ISC_LIST_FOREACH (name->list, rds, link) {
5078 if ((rds->attributes & DNS_RDATASETATTR_RENDERED) == 0)
5079 {
5080 continue;
5081 }
5082
5083 result = rdataset_soa_min(rds, ttlp);
5084 if (result == ISC_R_SUCCESS) {
5085 return ISC_R_SUCCESS;
5086 }
5087 }
5088 }
5089
5090 return ISC_R_NOTFOUND;
5091 }
5092
5093 isc_result_t
5094 dns_message_minttl(dns_message_t *msg, const dns_section_t sectionid,
5095 dns_ttl_t *pttl) {
5096 REQUIRE(DNS_MESSAGE_VALID(msg));
5097 REQUIRE(pttl != NULL);
5098
5099 if (!msg->minttl[sectionid].is_set) {
5100 return ISC_R_NOTFOUND;
5101 }
5102
5103 *pttl = msg->minttl[sectionid].ttl;
5104 return ISC_R_SUCCESS;
5105 }
5106
5107 isc_result_t
5108 dns_message_response_minttl(dns_message_t *msg, dns_ttl_t *pttl) {
5109 isc_result_t result;
5110
5111 REQUIRE(DNS_MESSAGE_VALID(msg));
5112 REQUIRE(pttl != NULL);
5113
5114 result = dns_message_minttl(msg, DNS_SECTION_ANSWER, pttl);
5115 if (result != ISC_R_SUCCESS) {
5116 return message_authority_soa_min(msg, pttl);
5117 }
5118
5119 return ISC_R_SUCCESS;
5120 }
5121
5122 void
5123 dns_message_createpools(isc_mem_t *mctx, isc_mempool_t **namepoolp,
5124 isc_mempool_t **rdspoolp) {
5125 REQUIRE(mctx != NULL);
5126 REQUIRE(namepoolp != NULL && *namepoolp == NULL);
5127 REQUIRE(rdspoolp != NULL && *rdspoolp == NULL);
5128
5129 isc_mempool_create(mctx, sizeof(dns_fixedname_t), namepoolp);
5130 isc_mempool_setfillcount(*namepoolp, NAME_FILLCOUNT);
5131 isc_mempool_setfreemax(*namepoolp, NAME_FREEMAX);
5132 isc_mempool_setname(*namepoolp, "dns_fixedname_pool");
5133
5134 isc_mempool_create(mctx, sizeof(dns_rdataset_t), rdspoolp);
5135 isc_mempool_setfillcount(*rdspoolp, RDATASET_FILLCOUNT);
5136 isc_mempool_setfreemax(*rdspoolp, RDATASET_FREEMAX);
5137 isc_mempool_setname(*rdspoolp, "dns_rdataset_pool");
5138 }
5139
5140 void
5141 dns_message_destroypools(isc_mempool_t **namepoolp, isc_mempool_t **rdspoolp) {
5142 REQUIRE(namepoolp != NULL && *namepoolp != NULL);
5143 REQUIRE(rdspoolp != NULL && *rdspoolp != NULL);
5144
5145 ENSURE(isc_mempool_getallocated(*namepoolp) == 0);
5146 ENSURE(isc_mempool_getallocated(*rdspoolp) == 0);
5147
5148 isc_mempool_destroy(rdspoolp);
5149 isc_mempool_destroy(namepoolp);
5150 }
5151