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