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