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