message.c revision 1.4 1 /* $NetBSD: message.c,v 1.4 2019/02/24 20:01:30 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, false,
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 issigzero;
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
1259 name = isc_mempool_get(msg->namepool);
1260 if (name == NULL)
1261 return (ISC_R_NOMEMORY);
1262 free_name = true;
1263
1264 offsets = newoffsets(msg);
1265 if (offsets == NULL) {
1266 result = ISC_R_NOMEMORY;
1267 goto cleanup;
1268 }
1269 dns_name_init(name, *offsets);
1270
1271 /*
1272 * Parse the name out of this packet.
1273 */
1274 isc_buffer_remainingregion(source, &r);
1275 isc_buffer_setactive(source, r.length);
1276 result = getname(name, source, msg, dctx);
1277 if (result != ISC_R_SUCCESS)
1278 goto cleanup;
1279
1280 /*
1281 * Get type, class, ttl, and rdatalen. Verify that at least
1282 * rdatalen bytes remain. (Some of this is deferred to
1283 * later.)
1284 */
1285 isc_buffer_remainingregion(source, &r);
1286 if (r.length < 2 + 2 + 4 + 2) {
1287 result = ISC_R_UNEXPECTEDEND;
1288 goto cleanup;
1289 }
1290 rdtype = isc_buffer_getuint16(source);
1291 rdclass = isc_buffer_getuint16(source);
1292
1293 /*
1294 * If there was no question section, we may not yet have
1295 * established a class. Do so now.
1296 */
1297 if (msg->rdclass_set == 0 &&
1298 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
1299 rdtype != dns_rdatatype_tsig && /* class is ANY */
1300 rdtype != dns_rdatatype_tkey) { /* class is undefined */
1301 msg->rdclass = rdclass;
1302 msg->rdclass_set = 1;
1303 }
1304
1305 /*
1306 * If this class is different than the one in the question
1307 * section, bail.
1308 */
1309 if (msg->opcode != dns_opcode_update
1310 && rdtype != dns_rdatatype_tsig
1311 && rdtype != dns_rdatatype_opt
1312 && rdtype != dns_rdatatype_key /* in a TKEY query */
1313 && rdtype != dns_rdatatype_sig /* SIG(0) */
1314 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1315 && msg->rdclass != dns_rdataclass_any
1316 && msg->rdclass != rdclass)
1317 DO_ERROR(DNS_R_FORMERR);
1318
1319 /*
1320 * If this is not a TKEY query/response then the KEY
1321 * record's class needs to match.
1322 */
1323 if (msg->opcode != dns_opcode_update && !msg->tkey &&
1324 rdtype == dns_rdatatype_key &&
1325 msg->rdclass != dns_rdataclass_any &&
1326 msg->rdclass != rdclass)
1327 DO_ERROR(DNS_R_FORMERR);
1328
1329 /*
1330 * Special type handling for TSIG, OPT, and TKEY.
1331 */
1332 if (rdtype == dns_rdatatype_tsig) {
1333 /*
1334 * If it is a tsig, verify that it is in the
1335 * additional data section.
1336 */
1337 if (sectionid != DNS_SECTION_ADDITIONAL ||
1338 rdclass != dns_rdataclass_any ||
1339 count != msg->counts[sectionid] - 1)
1340 DO_ERROR(DNS_R_BADTSIG);
1341 msg->sigstart = recstart;
1342 skip_name_search = true;
1343 skip_type_search = true;
1344 } else if (rdtype == dns_rdatatype_opt) {
1345 /*
1346 * The name of an OPT record must be ".", it
1347 * must be in the additional data section, and
1348 * it must be the first OPT we've seen.
1349 */
1350 if (!dns_name_equal(dns_rootname, name) ||
1351 sectionid != DNS_SECTION_ADDITIONAL ||
1352 msg->opt != NULL)
1353 DO_ERROR(DNS_R_FORMERR);
1354 skip_name_search = true;
1355 skip_type_search = true;
1356 } else if (rdtype == dns_rdatatype_tkey) {
1357 /*
1358 * A TKEY must be in the additional section if this
1359 * is a query, and the answer section if this is a
1360 * response. Unless it's a Win2000 client.
1361 *
1362 * Its class is ignored.
1363 */
1364 dns_section_t tkeysection;
1365
1366 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1367 tkeysection = DNS_SECTION_ADDITIONAL;
1368 else
1369 tkeysection = DNS_SECTION_ANSWER;
1370 if (sectionid != tkeysection &&
1371 sectionid != DNS_SECTION_ANSWER)
1372 DO_ERROR(DNS_R_FORMERR);
1373 }
1374
1375 /*
1376 * ... now get ttl and rdatalen, and check buffer.
1377 */
1378 ttl = isc_buffer_getuint32(source);
1379 rdatalen = isc_buffer_getuint16(source);
1380 r.length -= (2 + 2 + 4 + 2);
1381 if (r.length < rdatalen) {
1382 result = ISC_R_UNEXPECTEDEND;
1383 goto cleanup;
1384 }
1385
1386 /*
1387 * Read the rdata from the wire format. Interpret the
1388 * rdata according to its actual class, even if it had a
1389 * DynDNS meta-class in the packet (unless this is a TSIG).
1390 * Then put the meta-class back into the finished rdata.
1391 */
1392 rdata = newrdata(msg);
1393 if (rdata == NULL) {
1394 result = ISC_R_NOMEMORY;
1395 goto cleanup;
1396 }
1397 if (msg->opcode == dns_opcode_update &&
1398 update(sectionid, rdclass)) {
1399 if (rdatalen != 0) {
1400 result = DNS_R_FORMERR;
1401 goto cleanup;
1402 }
1403 /*
1404 * When the rdata is empty, the data pointer is
1405 * never dereferenced, but it must still be non-NULL.
1406 * Casting 1 rather than "" avoids warnings about
1407 * discarding the const attribute of a string,
1408 * for compilers that would warn about such things.
1409 */
1410 rdata->data = (unsigned char *)1;
1411 rdata->length = 0;
1412 rdata->rdclass = rdclass;
1413 rdata->type = rdtype;
1414 rdata->flags = DNS_RDATA_UPDATE;
1415 result = ISC_R_SUCCESS;
1416 } else if (rdclass == dns_rdataclass_none &&
1417 msg->opcode == dns_opcode_update &&
1418 sectionid == DNS_SECTION_UPDATE) {
1419 result = getrdata(source, msg, dctx, msg->rdclass,
1420 rdtype, rdatalen, rdata);
1421 } else
1422 result = getrdata(source, msg, dctx, rdclass,
1423 rdtype, rdatalen, rdata);
1424 if (result != ISC_R_SUCCESS)
1425 goto cleanup;
1426 rdata->rdclass = rdclass;
1427 issigzero = false;
1428 if (rdtype == dns_rdatatype_rrsig &&
1429 rdata->flags == 0) {
1430 covers = dns_rdata_covers(rdata);
1431 if (covers == 0)
1432 DO_ERROR(DNS_R_FORMERR);
1433 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1434 rdata->flags == 0) {
1435 covers = dns_rdata_covers(rdata);
1436 if (covers == 0) {
1437 if (sectionid != DNS_SECTION_ADDITIONAL ||
1438 count != msg->counts[sectionid] - 1)
1439 DO_ERROR(DNS_R_BADSIG0);
1440 msg->sigstart = recstart;
1441 skip_name_search = true;
1442 skip_type_search = true;
1443 issigzero = true;
1444 } else {
1445 if (msg->rdclass != dns_rdataclass_any &&
1446 msg->rdclass != rdclass)
1447 DO_ERROR(DNS_R_FORMERR);
1448 }
1449 } else
1450 covers = 0;
1451
1452 /*
1453 * Check the ownername of NSEC3 records
1454 */
1455 if (rdtype == dns_rdatatype_nsec3 &&
1456 !dns_rdata_checkowner(name, msg->rdclass, rdtype,
1457 false)) {
1458 result = DNS_R_BADOWNERNAME;
1459 goto cleanup;
1460 }
1461
1462 /*
1463 * If we are doing a dynamic update or this is a meta-type,
1464 * don't bother searching for a name, just append this one
1465 * to the end of the message.
1466 */
1467 if (preserve_order || msg->opcode == dns_opcode_update ||
1468 skip_name_search) {
1469 if (rdtype != dns_rdatatype_opt &&
1470 rdtype != dns_rdatatype_tsig &&
1471 !issigzero)
1472 {
1473 ISC_LIST_APPEND(*section, name, link);
1474 free_name = false;
1475 }
1476 } else {
1477 /*
1478 * Run through the section, looking to see if this name
1479 * is already there. If it is found, put back the
1480 * allocated name since we no longer need it, and set
1481 * our name pointer to point to the name we found.
1482 */
1483 result = findname(&name2, name, section);
1484
1485 /*
1486 * If it is a new name, append to the section.
1487 */
1488 if (result == ISC_R_SUCCESS) {
1489 isc_mempool_put(msg->namepool, name);
1490 name = name2;
1491 } else {
1492 ISC_LIST_APPEND(*section, name, link);
1493 }
1494 free_name = false;
1495 }
1496
1497 /*
1498 * Search name for the particular type and class.
1499 * Skip this stage if in update mode or this is a meta-type.
1500 */
1501 if (preserve_order || msg->opcode == dns_opcode_update ||
1502 skip_type_search)
1503 result = ISC_R_NOTFOUND;
1504 else {
1505 /*
1506 * If this is a type that can only occur in
1507 * the question section, fail.
1508 */
1509 if (dns_rdatatype_questiononly(rdtype))
1510 DO_ERROR(DNS_R_FORMERR);
1511
1512 rdataset = NULL;
1513 result = dns_message_find(name, rdclass, rdtype,
1514 covers, &rdataset);
1515 }
1516
1517 /*
1518 * If we found an rdataset that matches, we need to
1519 * append this rdata to that set. If we did not, we need
1520 * to create a new rdatalist, store the important bits there,
1521 * convert it to an rdataset, and link the latter to the name.
1522 * Yuck. When appending, make certain that the type isn't
1523 * a singleton type, such as SOA or CNAME.
1524 *
1525 * Note that this check will be bypassed when preserving order,
1526 * the opcode is an update, or the type search is skipped.
1527 */
1528 if (result == ISC_R_SUCCESS) {
1529 if (dns_rdatatype_issingleton(rdtype)) {
1530 dns_rdata_t *first;
1531 dns_rdatalist_fromrdataset(rdataset,
1532 &rdatalist);
1533 first = ISC_LIST_HEAD(rdatalist->rdata);
1534 INSIST(first != NULL);
1535 if (dns_rdata_compare(rdata, first) != 0)
1536 DO_ERROR(DNS_R_FORMERR);
1537 }
1538 }
1539
1540 if (result == ISC_R_NOTFOUND) {
1541 rdataset = isc_mempool_get(msg->rdspool);
1542 if (rdataset == NULL) {
1543 result = ISC_R_NOMEMORY;
1544 goto cleanup;
1545 }
1546 free_rdataset = true;
1547
1548 rdatalist = newrdatalist(msg);
1549 if (rdatalist == NULL) {
1550 result = ISC_R_NOMEMORY;
1551 goto cleanup;
1552 }
1553
1554 rdatalist->type = rdtype;
1555 rdatalist->covers = covers;
1556 rdatalist->rdclass = rdclass;
1557 rdatalist->ttl = ttl;
1558
1559 dns_rdataset_init(rdataset);
1560 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1561 rdataset)
1562 == ISC_R_SUCCESS);
1563 dns_rdataset_setownercase(rdataset, name);
1564
1565 if (rdtype != dns_rdatatype_opt &&
1566 rdtype != dns_rdatatype_tsig &&
1567 !issigzero)
1568 {
1569 ISC_LIST_APPEND(name->list, rdataset, link);
1570 free_rdataset = false;
1571 }
1572 }
1573
1574 /*
1575 * Minimize TTLs.
1576 *
1577 * Section 5.2 of RFC2181 says we should drop
1578 * nonauthoritative rrsets where the TTLs differ, but we
1579 * currently treat them the as if they were authoritative and
1580 * minimize them.
1581 */
1582 if (ttl != rdataset->ttl) {
1583 rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1584 if (ttl < rdataset->ttl)
1585 rdataset->ttl = ttl;
1586 }
1587
1588 /* Append this rdata to the rdataset. */
1589 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1590 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1591
1592 /*
1593 * If this is an OPT, SIG(0) or TSIG record, remember it.
1594 * Also, set the extended rcode for TSIG.
1595 *
1596 * Note msg->opt, msg->sig0 and msg->tsig will only be
1597 * already set if best-effort parsing is enabled otherwise
1598 * there will only be at most one of each.
1599 */
1600 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1601 dns_rcode_t ercode;
1602
1603 msg->opt = rdataset;
1604 rdataset = NULL;
1605 free_rdataset = false;
1606 ercode = (dns_rcode_t)
1607 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1608 >> 20);
1609 msg->rcode |= ercode;
1610 isc_mempool_put(msg->namepool, name);
1611 free_name = false;
1612 } else if (issigzero && msg->sig0 == NULL) {
1613 msg->sig0 = rdataset;
1614 msg->sig0name = name;
1615 rdataset = NULL;
1616 free_rdataset = false;
1617 free_name = false;
1618 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1619 msg->tsig = rdataset;
1620 msg->tsigname = name;
1621 /* Windows doesn't like TSIG names to be compressed. */
1622 msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1623 rdataset = NULL;
1624 free_rdataset = false;
1625 free_name = false;
1626 }
1627
1628 if (seen_problem) {
1629 if (free_name)
1630 isc_mempool_put(msg->namepool, name);
1631 if (free_rdataset)
1632 isc_mempool_put(msg->rdspool, rdataset);
1633 free_name = free_rdataset = false;
1634 }
1635 INSIST(free_name == false);
1636 INSIST(free_rdataset == false);
1637 }
1638
1639 /*
1640 * If any of DS, NSEC or NSEC3 appeared in the
1641 * authority section of a query response without
1642 * a covering RRSIG, FORMERR
1643 */
1644 if (sectionid == DNS_SECTION_AUTHORITY &&
1645 msg->opcode == dns_opcode_query &&
1646 ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) &&
1647 ((msg->flags & DNS_MESSAGEFLAG_TC) == 0) &&
1648 !preserve_order &&
1649 !auth_signed(section))
1650 DO_ERROR(DNS_R_FORMERR);
1651
1652 if (seen_problem)
1653 return (DNS_R_RECOVERABLE);
1654 return (ISC_R_SUCCESS);
1655
1656 cleanup:
1657 if (free_name)
1658 isc_mempool_put(msg->namepool, name);
1659 if (free_rdataset)
1660 isc_mempool_put(msg->rdspool, rdataset);
1661
1662 return (result);
1663 }
1664
1665 isc_result_t
1666 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1667 unsigned int options)
1668 {
1669 isc_region_t r;
1670 dns_decompress_t dctx;
1671 isc_result_t ret;
1672 uint16_t tmpflags;
1673 isc_buffer_t origsource;
1674 bool seen_problem;
1675 bool ignore_tc;
1676
1677 REQUIRE(DNS_MESSAGE_VALID(msg));
1678 REQUIRE(source != NULL);
1679 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1680
1681 seen_problem = false;
1682 ignore_tc = ((options & DNS_MESSAGEPARSE_IGNORETRUNCATION) != 0);
1683
1684 origsource = *source;
1685
1686 msg->header_ok = 0;
1687 msg->question_ok = 0;
1688
1689 isc_buffer_remainingregion(source, &r);
1690 if (r.length < DNS_MESSAGE_HEADERLEN)
1691 return (ISC_R_UNEXPECTEDEND);
1692
1693 msg->id = isc_buffer_getuint16(source);
1694 tmpflags = isc_buffer_getuint16(source);
1695 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1696 >> DNS_MESSAGE_OPCODE_SHIFT);
1697 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1698 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1699 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1700 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1701 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1702 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1703
1704 msg->header_ok = 1;
1705 msg->state = DNS_SECTION_QUESTION;
1706
1707 /*
1708 * -1 means no EDNS.
1709 */
1710 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1711
1712 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1713
1714 ret = getquestions(source, msg, &dctx, options);
1715 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1716 goto truncated;
1717 if (ret == DNS_R_RECOVERABLE) {
1718 seen_problem = true;
1719 ret = ISC_R_SUCCESS;
1720 }
1721 if (ret != ISC_R_SUCCESS)
1722 return (ret);
1723 msg->question_ok = 1;
1724
1725 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1726 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1727 goto truncated;
1728 if (ret == DNS_R_RECOVERABLE) {
1729 seen_problem = true;
1730 ret = ISC_R_SUCCESS;
1731 }
1732 if (ret != ISC_R_SUCCESS)
1733 return (ret);
1734
1735 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1736 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1737 goto truncated;
1738 if (ret == DNS_R_RECOVERABLE) {
1739 seen_problem = true;
1740 ret = ISC_R_SUCCESS;
1741 }
1742 if (ret != ISC_R_SUCCESS)
1743 return (ret);
1744
1745 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1746 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1747 goto truncated;
1748 if (ret == DNS_R_RECOVERABLE) {
1749 seen_problem = true;
1750 ret = ISC_R_SUCCESS;
1751 }
1752 if (ret != ISC_R_SUCCESS)
1753 return (ret);
1754
1755 isc_buffer_remainingregion(source, &r);
1756 if (r.length != 0) {
1757 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1758 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1759 "message has %u byte(s) of trailing garbage",
1760 r.length);
1761 }
1762
1763 truncated:
1764 if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1765 isc_buffer_usedregion(&origsource, &msg->saved);
1766 else {
1767 msg->saved.length = isc_buffer_usedlength(&origsource);
1768 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1769 if (msg->saved.base == NULL)
1770 return (ISC_R_NOMEMORY);
1771 memmove(msg->saved.base, isc_buffer_base(&origsource),
1772 msg->saved.length);
1773 msg->free_saved = 1;
1774 }
1775
1776 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1777 return (DNS_R_RECOVERABLE);
1778 if (seen_problem == true)
1779 return (DNS_R_RECOVERABLE);
1780 return (ISC_R_SUCCESS);
1781 }
1782
1783 isc_result_t
1784 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1785 isc_buffer_t *buffer)
1786 {
1787 isc_region_t r;
1788
1789 REQUIRE(DNS_MESSAGE_VALID(msg));
1790 REQUIRE(buffer != NULL);
1791 REQUIRE(msg->buffer == NULL);
1792 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1793
1794 msg->cctx = cctx;
1795
1796 /*
1797 * Erase the contents of this buffer.
1798 */
1799 isc_buffer_clear(buffer);
1800
1801 /*
1802 * Make certain there is enough for at least the header in this
1803 * buffer.
1804 */
1805 isc_buffer_availableregion(buffer, &r);
1806 if (r.length < DNS_MESSAGE_HEADERLEN)
1807 return (ISC_R_NOSPACE);
1808
1809 if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
1810 return (ISC_R_NOSPACE);
1811
1812 /*
1813 * Reserve enough space for the header in this buffer.
1814 */
1815 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1816
1817 msg->buffer = buffer;
1818
1819 return (ISC_R_SUCCESS);
1820 }
1821
1822 isc_result_t
1823 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1824 isc_region_t r, rn;
1825
1826 REQUIRE(DNS_MESSAGE_VALID(msg));
1827 REQUIRE(buffer != NULL);
1828 REQUIRE(msg->buffer != NULL);
1829
1830 /*
1831 * Ensure that the new buffer is empty, and has enough space to
1832 * hold the current contents.
1833 */
1834 isc_buffer_clear(buffer);
1835
1836 isc_buffer_availableregion(buffer, &rn);
1837 isc_buffer_usedregion(msg->buffer, &r);
1838 REQUIRE(rn.length > r.length);
1839
1840 /*
1841 * Copy the contents from the old to the new buffer.
1842 */
1843 isc_buffer_add(buffer, r.length);
1844 memmove(rn.base, r.base, r.length);
1845
1846 msg->buffer = buffer;
1847
1848 return (ISC_R_SUCCESS);
1849 }
1850
1851 void
1852 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1853 REQUIRE(DNS_MESSAGE_VALID(msg));
1854 REQUIRE(space <= msg->reserved);
1855
1856 msg->reserved -= space;
1857 }
1858
1859 isc_result_t
1860 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1861 isc_region_t r;
1862
1863 REQUIRE(DNS_MESSAGE_VALID(msg));
1864
1865 if (msg->buffer != NULL) {
1866 isc_buffer_availableregion(msg->buffer, &r);
1867 if (r.length < (space + msg->reserved))
1868 return (ISC_R_NOSPACE);
1869 }
1870
1871 msg->reserved += space;
1872
1873 return (ISC_R_SUCCESS);
1874 }
1875
1876 static inline bool
1877 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1878 int pass_needed;
1879
1880 /*
1881 * If we are not rendering class IN, this ordering is bogus.
1882 */
1883 if (rds->rdclass != dns_rdataclass_in)
1884 return (false);
1885
1886 switch (rds->type) {
1887 case dns_rdatatype_a:
1888 case dns_rdatatype_aaaa:
1889 if (preferred_glue == rds->type)
1890 pass_needed = 4;
1891 else
1892 pass_needed = 3;
1893 break;
1894 case dns_rdatatype_rrsig:
1895 case dns_rdatatype_dnskey:
1896 pass_needed = 2;
1897 break;
1898 default:
1899 pass_needed = 1;
1900 }
1901
1902 if (pass_needed >= pass)
1903 return (false);
1904
1905 return (true);
1906 }
1907
1908 static isc_result_t
1909 renderset(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
1910 dns_compress_t *cctx, isc_buffer_t *target,
1911 unsigned int reserved, unsigned int options, unsigned int *countp)
1912 {
1913 isc_result_t result;
1914
1915 /*
1916 * Shrink the space in the buffer by the reserved amount.
1917 */
1918 if (target->length - target->used < reserved)
1919 return (ISC_R_NOSPACE);
1920
1921 target->length -= reserved;
1922 result = dns_rdataset_towire(rdataset, owner_name,
1923 cctx, target, options, countp);
1924 target->length += reserved;
1925
1926 return (result);
1927 }
1928
1929 static void
1930 maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) {
1931 if (msg->counts[sectionid] == 0 &&
1932 (sectionid == DNS_SECTION_ANSWER ||
1933 (sectionid == DNS_SECTION_AUTHORITY &&
1934 msg->counts[DNS_SECTION_ANSWER] == 0)))
1935 msg->flags &= ~DNS_MESSAGEFLAG_AD;
1936 }
1937
1938 isc_result_t
1939 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1940 unsigned int options)
1941 {
1942 dns_namelist_t *section;
1943 dns_name_t *name, *next_name;
1944 dns_rdataset_t *rdataset, *next_rdataset;
1945 unsigned int count, total;
1946 isc_result_t result;
1947 isc_buffer_t st; /* for rollbacks */
1948 int pass;
1949 bool partial = false;
1950 unsigned int rd_options;
1951 dns_rdatatype_t preferred_glue = 0;
1952
1953 REQUIRE(DNS_MESSAGE_VALID(msg));
1954 REQUIRE(msg->buffer != NULL);
1955 REQUIRE(VALID_NAMED_SECTION(sectionid));
1956
1957 section = &msg->sections[sectionid];
1958
1959 if ((sectionid == DNS_SECTION_ADDITIONAL)
1960 && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1961 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1962 preferred_glue = dns_rdatatype_a;
1963 pass = 4;
1964 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1965 preferred_glue = dns_rdatatype_aaaa;
1966 pass = 4;
1967 } else
1968 pass = 3;
1969 } else
1970 pass = 1;
1971
1972 if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1973 rd_options = 0;
1974 else
1975 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1976
1977 /*
1978 * Shrink the space in the buffer by the reserved amount.
1979 */
1980 if (msg->buffer->length - msg->buffer->used < msg->reserved)
1981 return (ISC_R_NOSPACE);
1982 msg->buffer->length -= msg->reserved;
1983
1984 total = 0;
1985 if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1986 partial = true;
1987
1988 /*
1989 * Render required glue first. Set TC if it won't fit.
1990 */
1991 name = ISC_LIST_HEAD(*section);
1992 if (name != NULL) {
1993 rdataset = ISC_LIST_HEAD(name->list);
1994 if (rdataset != NULL &&
1995 (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1996 (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1997 const void *order_arg = &msg->order_arg;
1998 st = *(msg->buffer);
1999 count = 0;
2000 if (partial)
2001 result = dns_rdataset_towirepartial(rdataset,
2002 name,
2003 msg->cctx,
2004 msg->buffer,
2005 msg->order,
2006 order_arg,
2007 rd_options,
2008 &count,
2009 NULL);
2010 else
2011 result = dns_rdataset_towiresorted(rdataset,
2012 name,
2013 msg->cctx,
2014 msg->buffer,
2015 msg->order,
2016 order_arg,
2017 rd_options,
2018 &count);
2019 total += count;
2020 if (partial && result == ISC_R_NOSPACE) {
2021 msg->flags |= DNS_MESSAGEFLAG_TC;
2022 msg->buffer->length += msg->reserved;
2023 msg->counts[sectionid] += total;
2024 return (result);
2025 }
2026 if (result == ISC_R_NOSPACE)
2027 msg->flags |= DNS_MESSAGEFLAG_TC;
2028 if (result != ISC_R_SUCCESS) {
2029 INSIST(st.used < 65536);
2030 dns_compress_rollback(msg->cctx,
2031 (uint16_t)st.used);
2032 *(msg->buffer) = st; /* rollback */
2033 msg->buffer->length += msg->reserved;
2034 msg->counts[sectionid] += total;
2035 return (result);
2036 }
2037 rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
2038 }
2039 }
2040
2041 do {
2042 name = ISC_LIST_HEAD(*section);
2043 if (name == NULL) {
2044 msg->buffer->length += msg->reserved;
2045 msg->counts[sectionid] += total;
2046 return (ISC_R_SUCCESS);
2047 }
2048
2049 while (name != NULL) {
2050 next_name = ISC_LIST_NEXT(name, link);
2051
2052 rdataset = ISC_LIST_HEAD(name->list);
2053 while (rdataset != NULL) {
2054 next_rdataset = ISC_LIST_NEXT(rdataset, link);
2055
2056 if ((rdataset->attributes &
2057 DNS_RDATASETATTR_RENDERED) != 0)
2058 goto next;
2059
2060 if (((options & DNS_MESSAGERENDER_ORDERED)
2061 == 0)
2062 && (sectionid == DNS_SECTION_ADDITIONAL)
2063 && wrong_priority(rdataset, pass,
2064 preferred_glue))
2065 goto next;
2066
2067 st = *(msg->buffer);
2068
2069 count = 0;
2070 if (partial)
2071 result = dns_rdataset_towirepartial(
2072 rdataset,
2073 name,
2074 msg->cctx,
2075 msg->buffer,
2076 msg->order,
2077 &msg->order_arg,
2078 rd_options,
2079 &count,
2080 NULL);
2081 else
2082 result = dns_rdataset_towiresorted(
2083 rdataset,
2084 name,
2085 msg->cctx,
2086 msg->buffer,
2087 msg->order,
2088 &msg->order_arg,
2089 rd_options,
2090 &count);
2091
2092 total += count;
2093
2094 /*
2095 * If out of space, record stats on what we
2096 * rendered so far, and return that status.
2097 *
2098 * XXXMLG Need to change this when
2099 * dns_rdataset_towire() can render partial
2100 * sets starting at some arbitrary point in the
2101 * set. This will include setting a bit in the
2102 * rdataset to indicate that a partial
2103 * rendering was done, and some state saved
2104 * somewhere (probably in the message struct)
2105 * to indicate where to continue from.
2106 */
2107 if (partial && result == ISC_R_NOSPACE) {
2108 msg->buffer->length += msg->reserved;
2109 msg->counts[sectionid] += total;
2110 return (result);
2111 }
2112 if (result != ISC_R_SUCCESS) {
2113 INSIST(st.used < 65536);
2114 dns_compress_rollback(msg->cctx,
2115 (uint16_t)st.used);
2116 *(msg->buffer) = st; /* rollback */
2117 msg->buffer->length += msg->reserved;
2118 msg->counts[sectionid] += total;
2119 maybe_clear_ad(msg, sectionid);
2120 return (result);
2121 }
2122
2123 /*
2124 * If we have rendered non-validated data,
2125 * ensure that the AD bit is not set.
2126 */
2127 if (rdataset->trust != dns_trust_secure &&
2128 (sectionid == DNS_SECTION_ANSWER ||
2129 sectionid == DNS_SECTION_AUTHORITY))
2130 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2131 if (OPTOUT(rdataset))
2132 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2133
2134 rdataset->attributes |=
2135 DNS_RDATASETATTR_RENDERED;
2136
2137 next:
2138 rdataset = next_rdataset;
2139 }
2140
2141 name = next_name;
2142 }
2143 } while (--pass != 0);
2144
2145 msg->buffer->length += msg->reserved;
2146 msg->counts[sectionid] += total;
2147
2148 return (ISC_R_SUCCESS);
2149 }
2150
2151 void
2152 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2153 uint16_t tmp;
2154 isc_region_t r;
2155
2156 REQUIRE(DNS_MESSAGE_VALID(msg));
2157 REQUIRE(target != NULL);
2158
2159 isc_buffer_availableregion(target, &r);
2160 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2161
2162 isc_buffer_putuint16(target, msg->id);
2163
2164 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2165 & DNS_MESSAGE_OPCODE_MASK);
2166 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2167 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2168
2169 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
2170 msg->counts[DNS_SECTION_ANSWER] < 65536 &&
2171 msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2172 msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2173
2174 isc_buffer_putuint16(target, tmp);
2175 isc_buffer_putuint16(target,
2176 (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2177 isc_buffer_putuint16(target,
2178 (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2179 isc_buffer_putuint16(target,
2180 (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2181 isc_buffer_putuint16(target,
2182 (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2183 }
2184
2185 isc_result_t
2186 dns_message_renderend(dns_message_t *msg) {
2187 isc_buffer_t tmpbuf;
2188 isc_region_t r;
2189 int result;
2190 unsigned int count;
2191
2192 REQUIRE(DNS_MESSAGE_VALID(msg));
2193 REQUIRE(msg->buffer != NULL);
2194
2195 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2196 /*
2197 * We have an extended rcode but are not using EDNS.
2198 */
2199 return (DNS_R_FORMERR);
2200 }
2201
2202 /*
2203 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
2204 * clear all rdatasets from the message except for the question
2205 * before adding the OPT, TSIG or SIG(0). If the question doesn't
2206 * fit, don't include it.
2207 */
2208 if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
2209 (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2210 {
2211 isc_buffer_t *buf;
2212
2213 msgresetnames(msg, DNS_SECTION_ANSWER);
2214 buf = msg->buffer;
2215 dns_message_renderreset(msg);
2216 msg->buffer = buf;
2217 isc_buffer_clear(msg->buffer);
2218 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2219 dns_compress_rollback(msg->cctx, 0);
2220 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2221 0);
2222 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2223 return (result);
2224 }
2225
2226 /*
2227 * If we've got an OPT record, render it.
2228 */
2229 if (msg->opt != NULL) {
2230 dns_message_renderrelease(msg, msg->opt_reserved);
2231 msg->opt_reserved = 0;
2232 /*
2233 * Set the extended rcode.
2234 */
2235 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2236 msg->opt->ttl |= ((msg->rcode << 20) &
2237 DNS_MESSAGE_EDNSRCODE_MASK);
2238 /*
2239 * Render.
2240 */
2241 count = 0;
2242 result = renderset(msg->opt, dns_rootname, msg->cctx,
2243 msg->buffer, msg->reserved, 0, &count);
2244 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2245 if (result != ISC_R_SUCCESS)
2246 return (result);
2247 }
2248
2249 /*
2250 * Deal with EDNS padding.
2251 *
2252 * padding_off is the length of the OPT with the 0-length PAD
2253 * at the end.
2254 */
2255 if (msg->padding_off > 0) {
2256 unsigned char *cp = isc_buffer_used(msg->buffer);
2257 unsigned int used, remaining;
2258 uint16_t len, padsize = 0;
2259
2260 /* Check PAD */
2261 if ((cp[-4] != 0) ||
2262 (cp[-3] != DNS_OPT_PAD) ||
2263 (cp[-2] != 0) ||
2264 (cp[-1] != 0))
2265 return (ISC_R_UNEXPECTED);
2266
2267 /*
2268 * Zero-fill the PAD to the computed size;
2269 * patch PAD length and OPT rdlength
2270 */
2271
2272 /* Aligned used length + reserved to padding block */
2273 used = isc_buffer_usedlength(msg->buffer);
2274 if (msg->padding != 0) {
2275 padsize = ((uint16_t)used + msg->reserved)
2276 % msg->padding;
2277 }
2278 if (padsize != 0) {
2279 padsize = msg->padding - padsize;
2280 }
2281 /* Stay below the available length */
2282 remaining = isc_buffer_availablelength(msg->buffer);
2283 if (padsize > remaining)
2284 padsize = remaining;
2285
2286 isc_buffer_add(msg->buffer, padsize);
2287 memset(cp, 0, padsize);
2288 cp[-2] = (unsigned char)((padsize & 0xff00U) >> 8);
2289 cp[-1] = (unsigned char)(padsize & 0x00ffU);
2290 cp -= msg->padding_off;
2291 len = ((uint16_t)(cp[-2])) << 8;
2292 len |= ((uint16_t)(cp[-1]));
2293 len += padsize;
2294 cp[-2] = (unsigned char)((len & 0xff00U) >> 8);
2295 cp[-1] = (unsigned char)(len & 0x00ffU);
2296 }
2297
2298 /*
2299 * If we're adding a TSIG record, generate and render it.
2300 */
2301 if (msg->tsigkey != NULL) {
2302 dns_message_renderrelease(msg, msg->sig_reserved);
2303 msg->sig_reserved = 0;
2304 result = dns_tsig_sign(msg);
2305 if (result != ISC_R_SUCCESS)
2306 return (result);
2307 count = 0;
2308 result = renderset(msg->tsig, msg->tsigname, msg->cctx,
2309 msg->buffer, msg->reserved, 0, &count);
2310 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2311 if (result != ISC_R_SUCCESS)
2312 return (result);
2313 }
2314
2315 /*
2316 * If we're adding a SIG(0) record, generate and render it.
2317 */
2318 if (msg->sig0key != NULL) {
2319 dns_message_renderrelease(msg, msg->sig_reserved);
2320 msg->sig_reserved = 0;
2321 result = dns_dnssec_signmessage(msg, msg->sig0key);
2322 if (result != ISC_R_SUCCESS)
2323 return (result);
2324 count = 0;
2325 /*
2326 * Note: dns_rootname is used here, not msg->sig0name, since
2327 * the owner name of a SIG(0) is irrelevant, and will not
2328 * be set in a message being rendered.
2329 */
2330 result = renderset(msg->sig0, dns_rootname, msg->cctx,
2331 msg->buffer, msg->reserved, 0, &count);
2332 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2333 if (result != ISC_R_SUCCESS)
2334 return (result);
2335 }
2336
2337 isc_buffer_usedregion(msg->buffer, &r);
2338 isc_buffer_init(&tmpbuf, r.base, r.length);
2339
2340 dns_message_renderheader(msg, &tmpbuf);
2341
2342 msg->buffer = NULL; /* forget about this buffer only on success XXX */
2343
2344 return (ISC_R_SUCCESS);
2345 }
2346
2347 void
2348 dns_message_renderreset(dns_message_t *msg) {
2349 unsigned int i;
2350 dns_name_t *name;
2351 dns_rdataset_t *rds;
2352
2353 /*
2354 * Reset the message so that it may be rendered again.
2355 */
2356
2357 REQUIRE(DNS_MESSAGE_VALID(msg));
2358 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2359
2360 msg->buffer = NULL;
2361
2362 for (i = 0; i < DNS_SECTION_MAX; i++) {
2363 msg->cursors[i] = NULL;
2364 msg->counts[i] = 0;
2365 for (name = ISC_LIST_HEAD(msg->sections[i]);
2366 name != NULL;
2367 name = ISC_LIST_NEXT(name, link)) {
2368 for (rds = ISC_LIST_HEAD(name->list);
2369 rds != NULL;
2370 rds = ISC_LIST_NEXT(rds, link)) {
2371 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2372 }
2373 }
2374 }
2375 if (msg->tsigname != NULL)
2376 dns_message_puttempname(msg, &msg->tsigname);
2377 if (msg->tsig != NULL) {
2378 dns_rdataset_disassociate(msg->tsig);
2379 dns_message_puttemprdataset(msg, &msg->tsig);
2380 }
2381 if (msg->sig0 != NULL) {
2382 dns_rdataset_disassociate(msg->sig0);
2383 dns_message_puttemprdataset(msg, &msg->sig0);
2384 }
2385 }
2386
2387 isc_result_t
2388 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2389 REQUIRE(DNS_MESSAGE_VALID(msg));
2390 REQUIRE(VALID_NAMED_SECTION(section));
2391
2392 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2393
2394 if (msg->cursors[section] == NULL)
2395 return (ISC_R_NOMORE);
2396
2397 return (ISC_R_SUCCESS);
2398 }
2399
2400 isc_result_t
2401 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2402 REQUIRE(DNS_MESSAGE_VALID(msg));
2403 REQUIRE(VALID_NAMED_SECTION(section));
2404 REQUIRE(msg->cursors[section] != NULL);
2405
2406 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2407
2408 if (msg->cursors[section] == NULL)
2409 return (ISC_R_NOMORE);
2410
2411 return (ISC_R_SUCCESS);
2412 }
2413
2414 void
2415 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2416 dns_name_t **name)
2417 {
2418 REQUIRE(DNS_MESSAGE_VALID(msg));
2419 REQUIRE(VALID_NAMED_SECTION(section));
2420 REQUIRE(name != NULL && *name == NULL);
2421 REQUIRE(msg->cursors[section] != NULL);
2422
2423 *name = msg->cursors[section];
2424 }
2425
2426 isc_result_t
2427 dns_message_findname(dns_message_t *msg, dns_section_t section,
2428 const dns_name_t *target, dns_rdatatype_t type,
2429 dns_rdatatype_t covers, dns_name_t **name,
2430 dns_rdataset_t **rdataset)
2431 {
2432 dns_name_t *foundname;
2433 isc_result_t result;
2434
2435 /*
2436 * XXX These requirements are probably too intensive, especially
2437 * where things can be NULL, but as they are they ensure that if
2438 * something is NON-NULL, indicating that the caller expects it
2439 * to be filled in, that we can in fact fill it in.
2440 */
2441 REQUIRE(msg != NULL);
2442 REQUIRE(VALID_SECTION(section));
2443 REQUIRE(target != NULL);
2444 REQUIRE(name == NULL || *name == NULL);
2445
2446 if (type == dns_rdatatype_any) {
2447 REQUIRE(rdataset == NULL);
2448 } else {
2449 REQUIRE(rdataset == NULL || *rdataset == NULL);
2450 }
2451
2452 result = findname(&foundname, target,
2453 &msg->sections[section]);
2454
2455 if (result == ISC_R_NOTFOUND)
2456 return (DNS_R_NXDOMAIN);
2457 else if (result != ISC_R_SUCCESS)
2458 return (result);
2459
2460 if (name != NULL)
2461 *name = foundname;
2462
2463 /*
2464 * And now look for the type.
2465 */
2466 if (ISC_UNLIKELY(type == dns_rdatatype_any))
2467 return (ISC_R_SUCCESS);
2468
2469 result = dns_message_findtype(foundname, type, covers, rdataset);
2470 if (result == ISC_R_NOTFOUND)
2471 return (DNS_R_NXRRSET);
2472
2473 return (result);
2474 }
2475
2476 void
2477 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2478 dns_section_t fromsection,
2479 dns_section_t tosection)
2480 {
2481 REQUIRE(msg != NULL);
2482 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2483 REQUIRE(name != NULL);
2484 REQUIRE(VALID_NAMED_SECTION(fromsection));
2485 REQUIRE(VALID_NAMED_SECTION(tosection));
2486
2487 /*
2488 * Unlink the name from the old section
2489 */
2490 ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2491 ISC_LIST_APPEND(msg->sections[tosection], name, link);
2492 }
2493
2494 void
2495 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2496 dns_section_t section)
2497 {
2498 REQUIRE(msg != NULL);
2499 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2500 REQUIRE(name != NULL);
2501 REQUIRE(VALID_NAMED_SECTION(section));
2502
2503 ISC_LIST_APPEND(msg->sections[section], name, link);
2504 }
2505
2506 void
2507 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2508 dns_section_t section)
2509 {
2510 REQUIRE(msg != NULL);
2511 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2512 REQUIRE(name != NULL);
2513 REQUIRE(VALID_NAMED_SECTION(section));
2514
2515 ISC_LIST_UNLINK(msg->sections[section], name, link);
2516 }
2517
2518 isc_result_t
2519 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2520 REQUIRE(DNS_MESSAGE_VALID(msg));
2521 REQUIRE(item != NULL && *item == NULL);
2522
2523 *item = isc_mempool_get(msg->namepool);
2524 if (*item == NULL)
2525 return (ISC_R_NOMEMORY);
2526 dns_name_init(*item, NULL);
2527
2528 return (ISC_R_SUCCESS);
2529 }
2530
2531 isc_result_t
2532 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2533 REQUIRE(DNS_MESSAGE_VALID(msg));
2534 REQUIRE(item != NULL && *item == NULL);
2535
2536 *item = newoffsets(msg);
2537 if (*item == NULL)
2538 return (ISC_R_NOMEMORY);
2539
2540 return (ISC_R_SUCCESS);
2541 }
2542
2543 isc_result_t
2544 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2545 REQUIRE(DNS_MESSAGE_VALID(msg));
2546 REQUIRE(item != NULL && *item == NULL);
2547
2548 *item = newrdata(msg);
2549 if (*item == NULL)
2550 return (ISC_R_NOMEMORY);
2551
2552 return (ISC_R_SUCCESS);
2553 }
2554
2555 isc_result_t
2556 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2557 REQUIRE(DNS_MESSAGE_VALID(msg));
2558 REQUIRE(item != NULL && *item == NULL);
2559
2560 *item = isc_mempool_get(msg->rdspool);
2561 if (*item == NULL)
2562 return (ISC_R_NOMEMORY);
2563
2564 dns_rdataset_init(*item);
2565
2566 return (ISC_R_SUCCESS);
2567 }
2568
2569 isc_result_t
2570 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2571 REQUIRE(DNS_MESSAGE_VALID(msg));
2572 REQUIRE(item != NULL && *item == NULL);
2573
2574 *item = newrdatalist(msg);
2575 if (*item == NULL)
2576 return (ISC_R_NOMEMORY);
2577
2578 return (ISC_R_SUCCESS);
2579 }
2580
2581 void
2582 dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) {
2583 dns_name_t *item;
2584
2585 REQUIRE(DNS_MESSAGE_VALID(msg));
2586 REQUIRE(itemp != NULL && *itemp != NULL);
2587 item = *itemp;
2588 REQUIRE(!ISC_LINK_LINKED(item, link));
2589 REQUIRE(ISC_LIST_HEAD(item->list) == NULL);
2590
2591 *itemp = NULL;
2592 if (dns_name_dynamic(item))
2593 dns_name_free(item, msg->mctx);
2594 isc_mempool_put(msg->namepool, item);
2595 }
2596
2597 void
2598 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2599 REQUIRE(DNS_MESSAGE_VALID(msg));
2600 REQUIRE(item != NULL && *item != NULL);
2601
2602 releaserdata(msg, *item);
2603 *item = NULL;
2604 }
2605
2606 void
2607 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2608 REQUIRE(DNS_MESSAGE_VALID(msg));
2609 REQUIRE(item != NULL && *item != NULL);
2610
2611 REQUIRE(!dns_rdataset_isassociated(*item));
2612 isc_mempool_put(msg->rdspool, *item);
2613 *item = NULL;
2614 }
2615
2616 void
2617 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2618 REQUIRE(DNS_MESSAGE_VALID(msg));
2619 REQUIRE(item != NULL && *item != NULL);
2620
2621 releaserdatalist(msg, *item);
2622 *item = NULL;
2623 }
2624
2625 isc_result_t
2626 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2627 unsigned int *flagsp)
2628 {
2629 isc_region_t r;
2630 isc_buffer_t buffer;
2631 dns_messageid_t id;
2632 unsigned int flags;
2633
2634 REQUIRE(source != NULL);
2635
2636 buffer = *source;
2637
2638 isc_buffer_remainingregion(&buffer, &r);
2639 if (r.length < DNS_MESSAGE_HEADERLEN)
2640 return (ISC_R_UNEXPECTEDEND);
2641
2642 id = isc_buffer_getuint16(&buffer);
2643 flags = isc_buffer_getuint16(&buffer);
2644 flags &= DNS_MESSAGE_FLAG_MASK;
2645
2646 if (flagsp != NULL)
2647 *flagsp = flags;
2648 if (idp != NULL)
2649 *idp = id;
2650
2651 return (ISC_R_SUCCESS);
2652 }
2653
2654 isc_result_t
2655 dns_message_reply(dns_message_t *msg, bool want_question_section) {
2656 unsigned int clear_from;
2657 isc_result_t result;
2658
2659 REQUIRE(DNS_MESSAGE_VALID(msg));
2660 REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2661
2662 if (!msg->header_ok)
2663 return (DNS_R_FORMERR);
2664 if (msg->opcode != dns_opcode_query &&
2665 msg->opcode != dns_opcode_notify)
2666 want_question_section = false;
2667 if (msg->opcode == dns_opcode_update)
2668 clear_from = DNS_SECTION_PREREQUISITE;
2669 else if (want_question_section) {
2670 if (!msg->question_ok)
2671 return (DNS_R_FORMERR);
2672 clear_from = DNS_SECTION_ANSWER;
2673 } else
2674 clear_from = DNS_SECTION_QUESTION;
2675 msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2676 msgresetnames(msg, clear_from);
2677 msgresetopt(msg);
2678 msgresetsigs(msg, true);
2679 msginitprivate(msg);
2680 /*
2681 * We now clear most flags and then set QR, ensuring that the
2682 * reply's flags will be in a reasonable state.
2683 */
2684 if (msg->opcode == dns_opcode_query)
2685 msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2686 else
2687 msg->flags = 0;
2688 msg->flags |= DNS_MESSAGEFLAG_QR;
2689
2690 /*
2691 * This saves the query TSIG status, if the query was signed, and
2692 * reserves space in the reply for the TSIG.
2693 */
2694 if (msg->tsigkey != NULL) {
2695 unsigned int otherlen = 0;
2696 msg->querytsigstatus = msg->tsigstatus;
2697 msg->tsigstatus = dns_rcode_noerror;
2698 if (msg->querytsigstatus == dns_tsigerror_badtime)
2699 otherlen = 6;
2700 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2701 result = dns_message_renderreserve(msg, msg->sig_reserved);
2702 if (result != ISC_R_SUCCESS) {
2703 msg->sig_reserved = 0;
2704 return (result);
2705 }
2706 }
2707 if (msg->saved.base != NULL) {
2708 msg->query.base = msg->saved.base;
2709 msg->query.length = msg->saved.length;
2710 msg->free_query = msg->free_saved;
2711 msg->saved.base = NULL;
2712 msg->saved.length = 0;
2713 msg->free_saved = 0;
2714 }
2715
2716 return (ISC_R_SUCCESS);
2717 }
2718
2719 dns_rdataset_t *
2720 dns_message_getopt(dns_message_t *msg) {
2721
2722 /*
2723 * Get the OPT record for 'msg'.
2724 */
2725
2726 REQUIRE(DNS_MESSAGE_VALID(msg));
2727
2728 return (msg->opt);
2729 }
2730
2731 isc_result_t
2732 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2733 isc_result_t result;
2734 dns_rdata_t rdata = DNS_RDATA_INIT;
2735
2736 /*
2737 * Set the OPT record for 'msg'.
2738 */
2739
2740 /*
2741 * The space required for an OPT record is:
2742 *
2743 * 1 byte for the name
2744 * 2 bytes for the type
2745 * 2 bytes for the class
2746 * 4 bytes for the ttl
2747 * 2 bytes for the rdata length
2748 * ---------------------------------
2749 * 11 bytes
2750 *
2751 * plus the length of the rdata.
2752 */
2753
2754 REQUIRE(DNS_MESSAGE_VALID(msg));
2755 REQUIRE(opt->type == dns_rdatatype_opt);
2756 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2757 REQUIRE(msg->state == DNS_SECTION_ANY);
2758
2759 msgresetopt(msg);
2760
2761 result = dns_rdataset_first(opt);
2762 if (result != ISC_R_SUCCESS)
2763 goto cleanup;
2764 dns_rdataset_current(opt, &rdata);
2765 msg->opt_reserved = 11 + rdata.length;
2766 result = dns_message_renderreserve(msg, msg->opt_reserved);
2767 if (result != ISC_R_SUCCESS) {
2768 msg->opt_reserved = 0;
2769 goto cleanup;
2770 }
2771
2772 msg->opt = opt;
2773
2774 return (ISC_R_SUCCESS);
2775
2776 cleanup:
2777 dns_rdataset_disassociate(opt);
2778 dns_message_puttemprdataset(msg, &opt);
2779 return (result);
2780 }
2781
2782 dns_rdataset_t *
2783 dns_message_gettsig(dns_message_t *msg, const dns_name_t **owner) {
2784
2785 /*
2786 * Get the TSIG record and owner for 'msg'.
2787 */
2788
2789 REQUIRE(DNS_MESSAGE_VALID(msg));
2790 REQUIRE(owner == NULL || *owner == NULL);
2791
2792 if (owner != NULL)
2793 *owner = msg->tsigname;
2794 return (msg->tsig);
2795 }
2796
2797 isc_result_t
2798 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2799 isc_result_t result;
2800
2801 /*
2802 * Set the TSIG key for 'msg'
2803 */
2804
2805 REQUIRE(DNS_MESSAGE_VALID(msg));
2806
2807 if (key == NULL && msg->tsigkey != NULL) {
2808 if (msg->sig_reserved != 0) {
2809 dns_message_renderrelease(msg, msg->sig_reserved);
2810 msg->sig_reserved = 0;
2811 }
2812 dns_tsigkey_detach(&msg->tsigkey);
2813 }
2814 if (key != NULL) {
2815 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2816 dns_tsigkey_attach(key, &msg->tsigkey);
2817 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2818 msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2819 result = dns_message_renderreserve(msg,
2820 msg->sig_reserved);
2821 if (result != ISC_R_SUCCESS) {
2822 dns_tsigkey_detach(&msg->tsigkey);
2823 msg->sig_reserved = 0;
2824 return (result);
2825 }
2826 }
2827 }
2828 return (ISC_R_SUCCESS);
2829 }
2830
2831 dns_tsigkey_t *
2832 dns_message_gettsigkey(dns_message_t *msg) {
2833
2834 /*
2835 * Get the TSIG key for 'msg'
2836 */
2837
2838 REQUIRE(DNS_MESSAGE_VALID(msg));
2839
2840 return (msg->tsigkey);
2841 }
2842
2843 isc_result_t
2844 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2845 dns_rdata_t *rdata = NULL;
2846 dns_rdatalist_t *list = NULL;
2847 dns_rdataset_t *set = NULL;
2848 isc_buffer_t *buf = NULL;
2849 isc_region_t r;
2850 isc_result_t result;
2851
2852 REQUIRE(DNS_MESSAGE_VALID(msg));
2853 REQUIRE(msg->querytsig == NULL);
2854
2855 if (querytsig == NULL)
2856 return (ISC_R_SUCCESS);
2857
2858 result = dns_message_gettemprdata(msg, &rdata);
2859 if (result != ISC_R_SUCCESS)
2860 goto cleanup;
2861
2862 result = dns_message_gettemprdatalist(msg, &list);
2863 if (result != ISC_R_SUCCESS)
2864 goto cleanup;
2865 result = dns_message_gettemprdataset(msg, &set);
2866 if (result != ISC_R_SUCCESS)
2867 goto cleanup;
2868
2869 isc_buffer_usedregion(querytsig, &r);
2870 result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2871 if (result != ISC_R_SUCCESS)
2872 goto cleanup;
2873 isc_buffer_putmem(buf, r.base, r.length);
2874 isc_buffer_usedregion(buf, &r);
2875 dns_rdata_init(rdata);
2876 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2877 dns_message_takebuffer(msg, &buf);
2878 ISC_LIST_APPEND(list->rdata, rdata, link);
2879 result = dns_rdatalist_tordataset(list, set);
2880 if (result != ISC_R_SUCCESS)
2881 goto cleanup;
2882
2883 msg->querytsig = set;
2884
2885 return (result);
2886
2887 cleanup:
2888 if (rdata != NULL)
2889 dns_message_puttemprdata(msg, &rdata);
2890 if (list != NULL)
2891 dns_message_puttemprdatalist(msg, &list);
2892 if (set != NULL)
2893 dns_message_puttemprdataset(msg, &set);
2894 return (ISC_R_NOMEMORY);
2895 }
2896
2897 isc_result_t
2898 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2899 isc_buffer_t **querytsig) {
2900 isc_result_t result;
2901 dns_rdata_t rdata = DNS_RDATA_INIT;
2902 isc_region_t r;
2903
2904 REQUIRE(DNS_MESSAGE_VALID(msg));
2905 REQUIRE(mctx != NULL);
2906 REQUIRE(querytsig != NULL && *querytsig == NULL);
2907
2908 if (msg->tsig == NULL)
2909 return (ISC_R_SUCCESS);
2910
2911 result = dns_rdataset_first(msg->tsig);
2912 if (result != ISC_R_SUCCESS)
2913 return (result);
2914 dns_rdataset_current(msg->tsig, &rdata);
2915 dns_rdata_toregion(&rdata, &r);
2916
2917 result = isc_buffer_allocate(mctx, querytsig, r.length);
2918 if (result != ISC_R_SUCCESS)
2919 return (result);
2920 isc_buffer_putmem(*querytsig, r.base, r.length);
2921 return (ISC_R_SUCCESS);
2922 }
2923
2924 dns_rdataset_t *
2925 dns_message_getsig0(dns_message_t *msg, const dns_name_t **owner) {
2926
2927 /*
2928 * Get the SIG(0) record for 'msg'.
2929 */
2930
2931 REQUIRE(DNS_MESSAGE_VALID(msg));
2932 REQUIRE(owner == NULL || *owner == NULL);
2933
2934 if (msg->sig0 != NULL && owner != NULL) {
2935 /* If dns_message_getsig0 is called on a rendered message
2936 * after the SIG(0) has been applied, we need to return the
2937 * root name, not NULL.
2938 */
2939 if (msg->sig0name == NULL)
2940 *owner = dns_rootname;
2941 else
2942 *owner = msg->sig0name;
2943 }
2944 return (msg->sig0);
2945 }
2946
2947 isc_result_t
2948 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2949 isc_region_t r;
2950 unsigned int x;
2951 isc_result_t result;
2952
2953 /*
2954 * Set the SIG(0) key for 'msg'
2955 */
2956
2957 /*
2958 * The space required for an SIG(0) record is:
2959 *
2960 * 1 byte for the name
2961 * 2 bytes for the type
2962 * 2 bytes for the class
2963 * 4 bytes for the ttl
2964 * 2 bytes for the type covered
2965 * 1 byte for the algorithm
2966 * 1 bytes for the labels
2967 * 4 bytes for the original ttl
2968 * 4 bytes for the signature expiration
2969 * 4 bytes for the signature inception
2970 * 2 bytes for the key tag
2971 * n bytes for the signer's name
2972 * x bytes for the signature
2973 * ---------------------------------
2974 * 27 + n + x bytes
2975 */
2976 REQUIRE(DNS_MESSAGE_VALID(msg));
2977 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2978 REQUIRE(msg->state == DNS_SECTION_ANY);
2979
2980 if (key != NULL) {
2981 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2982 dns_name_toregion(dst_key_name(key), &r);
2983 result = dst_key_sigsize(key, &x);
2984 if (result != ISC_R_SUCCESS) {
2985 msg->sig_reserved = 0;
2986 return (result);
2987 }
2988 msg->sig_reserved = 27 + r.length + x;
2989 result = dns_message_renderreserve(msg, msg->sig_reserved);
2990 if (result != ISC_R_SUCCESS) {
2991 msg->sig_reserved = 0;
2992 return (result);
2993 }
2994 msg->sig0key = key;
2995 }
2996 return (ISC_R_SUCCESS);
2997 }
2998
2999 dst_key_t *
3000 dns_message_getsig0key(dns_message_t *msg) {
3001
3002 /*
3003 * Get the SIG(0) key for 'msg'
3004 */
3005
3006 REQUIRE(DNS_MESSAGE_VALID(msg));
3007
3008 return (msg->sig0key);
3009 }
3010
3011 void
3012 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
3013 REQUIRE(DNS_MESSAGE_VALID(msg));
3014 REQUIRE(buffer != NULL);
3015 REQUIRE(ISC_BUFFER_VALID(*buffer));
3016
3017 ISC_LIST_APPEND(msg->cleanup, *buffer, link);
3018 *buffer = NULL;
3019 }
3020
3021 isc_result_t
3022 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
3023 isc_result_t result = ISC_R_SUCCESS;
3024 dns_rdata_t rdata = DNS_RDATA_INIT;
3025
3026 REQUIRE(DNS_MESSAGE_VALID(msg));
3027 REQUIRE(signer != NULL);
3028 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
3029
3030 if (msg->tsig == NULL && msg->sig0 == NULL)
3031 return (ISC_R_NOTFOUND);
3032
3033 if (msg->verify_attempted == 0)
3034 return (DNS_R_NOTVERIFIEDYET);
3035
3036 if (!dns_name_hasbuffer(signer)) {
3037 isc_buffer_t *dynbuf = NULL;
3038 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
3039 if (result != ISC_R_SUCCESS)
3040 return (result);
3041 dns_name_setbuffer(signer, dynbuf);
3042 dns_message_takebuffer(msg, &dynbuf);
3043 }
3044
3045 if (msg->sig0 != NULL) {
3046 dns_rdata_sig_t sig;
3047
3048 result = dns_rdataset_first(msg->sig0);
3049 INSIST(result == ISC_R_SUCCESS);
3050 dns_rdataset_current(msg->sig0, &rdata);
3051
3052 result = dns_rdata_tostruct(&rdata, &sig, NULL);
3053 if (result != ISC_R_SUCCESS)
3054 return (result);
3055
3056 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
3057 result = ISC_R_SUCCESS;
3058 else
3059 result = DNS_R_SIGINVALID;
3060 dns_name_clone(&sig.signer, signer);
3061 dns_rdata_freestruct(&sig);
3062 } else {
3063 dns_name_t *identity;
3064 dns_rdata_any_tsig_t tsig;
3065
3066 result = dns_rdataset_first(msg->tsig);
3067 INSIST(result == ISC_R_SUCCESS);
3068 dns_rdataset_current(msg->tsig, &rdata);
3069
3070 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
3071 INSIST(result == ISC_R_SUCCESS);
3072 if (msg->verified_sig &&
3073 msg->tsigstatus == dns_rcode_noerror &&
3074 tsig.error == dns_rcode_noerror)
3075 {
3076 result = ISC_R_SUCCESS;
3077 } else if ((!msg->verified_sig) ||
3078 (msg->tsigstatus != dns_rcode_noerror))
3079 {
3080 result = DNS_R_TSIGVERIFYFAILURE;
3081 } else {
3082 INSIST(tsig.error != dns_rcode_noerror);
3083 result = DNS_R_TSIGERRORSET;
3084 }
3085 dns_rdata_freestruct(&tsig);
3086
3087 if (msg->tsigkey == NULL) {
3088 /*
3089 * If msg->tsigstatus & tsig.error are both
3090 * dns_rcode_noerror, the message must have been
3091 * verified, which means msg->tsigkey will be
3092 * non-NULL.
3093 */
3094 INSIST(result != ISC_R_SUCCESS);
3095 } else {
3096 identity = dns_tsigkey_identity(msg->tsigkey);
3097 if (identity == NULL) {
3098 if (result == ISC_R_SUCCESS)
3099 result = DNS_R_NOIDENTITY;
3100 identity = &msg->tsigkey->name;
3101 }
3102 dns_name_clone(identity, signer);
3103 }
3104 }
3105
3106 return (result);
3107 }
3108
3109 void
3110 dns_message_resetsig(dns_message_t *msg) {
3111 REQUIRE(DNS_MESSAGE_VALID(msg));
3112 msg->verified_sig = 0;
3113 msg->verify_attempted = 0;
3114 msg->tsigstatus = dns_rcode_noerror;
3115 msg->sig0status = dns_rcode_noerror;
3116 msg->timeadjust = 0;
3117 if (msg->tsigkey != NULL) {
3118 dns_tsigkey_detach(&msg->tsigkey);
3119 msg->tsigkey = NULL;
3120 }
3121 }
3122
3123 isc_result_t
3124 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
3125 dns_message_resetsig(msg);
3126 return (dns_message_checksig(msg, view));
3127 }
3128
3129 #ifdef SKAN_MSG_DEBUG
3130 void
3131 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
3132 dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
3133 dns_rdata_any_tsig_t querytsig;
3134 isc_result_t result;
3135
3136 if (msg->tsig != NULL) {
3137 result = dns_rdataset_first(msg->tsig);
3138 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3139 dns_rdataset_current(msg->tsig, &querytsigrdata);
3140 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3141 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3142 hexdump(txt1, "TSIG", querytsig.signature,
3143 querytsig.siglen);
3144 }
3145
3146 if (msg->querytsig != NULL) {
3147 result = dns_rdataset_first(msg->querytsig);
3148 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3149 dns_rdataset_current(msg->querytsig, &querytsigrdata);
3150 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3151 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3152 hexdump(txt1, "QUERYTSIG", querytsig.signature,
3153 querytsig.siglen);
3154 }
3155 }
3156 #endif
3157
3158 isc_result_t
3159 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3160 isc_buffer_t b, msgb;
3161
3162 REQUIRE(DNS_MESSAGE_VALID(msg));
3163
3164 if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
3165 return (ISC_R_SUCCESS);
3166
3167 INSIST(msg->saved.base != NULL);
3168 isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3169 isc_buffer_add(&msgb, msg->saved.length);
3170 if (msg->tsigkey != NULL || msg->tsig != NULL) {
3171 #ifdef SKAN_MSG_DEBUG
3172 dns_message_dumpsig(msg, "dns_message_checksig#1");
3173 #endif
3174 if (view != NULL)
3175 return (dns_view_checksig(view, &msgb, msg));
3176 else
3177 return (dns_tsig_verify(&msgb, msg, NULL, NULL));
3178 } else {
3179 dns_rdata_t rdata = DNS_RDATA_INIT;
3180 dns_rdata_sig_t sig;
3181 dns_rdataset_t keyset;
3182 isc_result_t result;
3183
3184 result = dns_rdataset_first(msg->sig0);
3185 INSIST(result == ISC_R_SUCCESS);
3186 dns_rdataset_current(msg->sig0, &rdata);
3187
3188 /*
3189 * This can occur when the message is a dynamic update, since
3190 * the rdata length checking is relaxed. This should not
3191 * happen in a well-formed message, since the SIG(0) is only
3192 * looked for in the additional section, and the dynamic update
3193 * meta-records are in the prerequisite and update sections.
3194 */
3195 if (rdata.length == 0)
3196 return (ISC_R_UNEXPECTEDEND);
3197
3198 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3199 if (result != ISC_R_SUCCESS)
3200 return (result);
3201
3202 dns_rdataset_init(&keyset);
3203 if (view == NULL)
3204 return (DNS_R_KEYUNAUTHORIZED);
3205 result = dns_view_simplefind(view, &sig.signer,
3206 dns_rdatatype_key /* SIG(0) */,
3207 0, 0, false, &keyset, NULL);
3208
3209 if (result != ISC_R_SUCCESS) {
3210 /* XXXBEW Should possibly create a fetch here */
3211 result = DNS_R_KEYUNAUTHORIZED;
3212 goto freesig;
3213 } else if (keyset.trust < dns_trust_secure) {
3214 /* XXXBEW Should call a validator here */
3215 result = DNS_R_KEYUNAUTHORIZED;
3216 goto freesig;
3217 }
3218 result = dns_rdataset_first(&keyset);
3219 INSIST(result == ISC_R_SUCCESS);
3220 for (;
3221 result == ISC_R_SUCCESS;
3222 result = dns_rdataset_next(&keyset))
3223 {
3224 dst_key_t *key = NULL;
3225
3226 dns_rdata_reset(&rdata);
3227 dns_rdataset_current(&keyset, &rdata);
3228 isc_buffer_init(&b, rdata.data, rdata.length);
3229 isc_buffer_add(&b, rdata.length);
3230
3231 result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3232 &b, view->mctx, &key);
3233 if (result != ISC_R_SUCCESS)
3234 continue;
3235 if (dst_key_alg(key) != sig.algorithm ||
3236 dst_key_id(key) != sig.keyid ||
3237 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3238 dst_key_proto(key) == DNS_KEYPROTO_ANY))
3239 {
3240 dst_key_free(&key);
3241 continue;
3242 }
3243 result = dns_dnssec_verifymessage(&msgb, msg, key);
3244 dst_key_free(&key);
3245 if (result == ISC_R_SUCCESS)
3246 break;
3247 }
3248 if (result == ISC_R_NOMORE)
3249 result = DNS_R_KEYUNAUTHORIZED;
3250
3251 freesig:
3252 if (dns_rdataset_isassociated(&keyset))
3253 dns_rdataset_disassociate(&keyset);
3254 dns_rdata_freestruct(&sig);
3255 return (result);
3256 }
3257 }
3258
3259 #define INDENT(sp) \
3260 do { \
3261 unsigned int __i; \
3262 dns_masterstyle_flags_t __flags = dns_master_styleflags(sp); \
3263 if ((__flags & DNS_STYLEFLAG_INDENT) == 0ULL && \
3264 (__flags & DNS_STYLEFLAG_YAML) == 0ULL) \
3265 break; \
3266 for (__i = 0; __i < dns_master_indent; __i++) { \
3267 ADD_STRING(target, dns_master_indentstr); \
3268 } \
3269 } while (0)
3270
3271 isc_result_t
3272 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3273 const dns_master_style_t *style,
3274 dns_messagetextflag_t flags,
3275 isc_buffer_t *target) {
3276 dns_name_t *name, empty_name;
3277 dns_rdataset_t *rdataset;
3278 isc_result_t result = ISC_R_SUCCESS;
3279 bool seensoa = false;
3280 unsigned int saveindent;
3281 dns_masterstyle_flags_t sflags;
3282
3283 REQUIRE(DNS_MESSAGE_VALID(msg));
3284 REQUIRE(target != NULL);
3285 REQUIRE(VALID_SECTION(section));
3286
3287 saveindent = dns_master_indent;
3288 sflags = dns_master_styleflags(style);
3289 if (ISC_LIST_EMPTY(msg->sections[section]))
3290 goto cleanup;
3291
3292
3293 INDENT(style);
3294 if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3295 if (msg->opcode != dns_opcode_update) {
3296 ADD_STRING(target, sectiontext[section]);
3297 } else {
3298 ADD_STRING(target, updsectiontext[section]);
3299 }
3300 ADD_STRING(target, "_SECTION:\n");
3301 } else if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3302 ADD_STRING(target, ";; ");
3303 if (msg->opcode != dns_opcode_update) {
3304 ADD_STRING(target, sectiontext[section]);
3305 } else {
3306 ADD_STRING(target, updsectiontext[section]);
3307 }
3308 ADD_STRING(target, " SECTION:\n");
3309 }
3310
3311 dns_name_init(&empty_name, NULL);
3312 result = dns_message_firstname(msg, section);
3313 if (result != ISC_R_SUCCESS) {
3314 goto cleanup;
3315 }
3316 if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3317 dns_master_indent++;
3318 }
3319 do {
3320 name = NULL;
3321 dns_message_currentname(msg, section, &name);
3322 for (rdataset = ISC_LIST_HEAD(name->list);
3323 rdataset != NULL;
3324 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3325 if (section == DNS_SECTION_ANSWER &&
3326 rdataset->type == dns_rdatatype_soa) {
3327 if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3328 continue;
3329 if (seensoa &&
3330 (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3331 continue;
3332 seensoa = true;
3333 }
3334 if (section == DNS_SECTION_QUESTION) {
3335 INDENT(style);
3336 if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3337 ADD_STRING(target, "- ");
3338 } else {
3339 ADD_STRING(target, ";");
3340 }
3341 result = dns_master_questiontotext(name,
3342 rdataset,
3343 style,
3344 target);
3345 } else {
3346 result = dns_master_rdatasettotext(name,
3347 rdataset,
3348 style,
3349 target);
3350 }
3351 if (result != ISC_R_SUCCESS)
3352 goto cleanup;
3353 }
3354 result = dns_message_nextname(msg, section);
3355 } while (result == ISC_R_SUCCESS);
3356 if ((sflags & DNS_STYLEFLAG_YAML) != 0) {
3357 dns_master_indent--;
3358 }
3359 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3360 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0 &&
3361 (sflags & DNS_STYLEFLAG_YAML) == 0)
3362 {
3363 INDENT(style);
3364 ADD_STRING(target, "\n");
3365 }
3366 if (result == ISC_R_NOMORE)
3367 result = ISC_R_SUCCESS;
3368
3369 cleanup:
3370 dns_master_indent = saveindent;
3371 return (result);
3372 }
3373
3374 static isc_result_t
3375 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
3376 int i;
3377 char addr[16], addr_text[64];
3378 uint16_t family;
3379 uint8_t addrlen, addrbytes, scopelen;
3380 isc_result_t result;
3381
3382 /*
3383 * Note: This routine needs to handle malformed ECS options.
3384 */
3385
3386 if (isc_buffer_remaininglength(ecsbuf) < 4)
3387 return (DNS_R_OPTERR);
3388 family = isc_buffer_getuint16(ecsbuf);
3389 addrlen = isc_buffer_getuint8(ecsbuf);
3390 scopelen = isc_buffer_getuint8(ecsbuf);
3391
3392 addrbytes = (addrlen + 7) / 8;
3393 if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
3394 return (DNS_R_OPTERR);
3395
3396 if (addrbytes > sizeof(addr))
3397 return (DNS_R_OPTERR);
3398
3399 memset(addr, 0, sizeof(addr));
3400 for (i = 0; i < addrbytes; i ++)
3401 addr[i] = isc_buffer_getuint8(ecsbuf);
3402
3403 switch (family) {
3404 case 0:
3405 if (addrlen != 0U || scopelen != 0U)
3406 return (DNS_R_OPTERR);
3407 strlcpy(addr_text, "0", sizeof(addr_text));
3408 break;
3409 case 1:
3410 if (addrlen > 32 || scopelen > 32)
3411 return (DNS_R_OPTERR);
3412 inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
3413 break;
3414 case 2:
3415 if (addrlen > 128 || scopelen > 128)
3416 return (DNS_R_OPTERR);
3417 inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
3418 break;
3419 default:
3420 return (DNS_R_OPTERR);
3421 }
3422
3423 ADD_STRING(target, ": ");
3424 ADD_STRING(target, addr_text);
3425 snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
3426 ADD_STRING(target, addr_text);
3427
3428 result = ISC_R_SUCCESS;
3429
3430 cleanup:
3431 return (result);
3432 }
3433
3434
3435 static isc_result_t
3436 dns_message_pseudosectiontoyaml(dns_message_t *msg,
3437 dns_pseudosection_t section,
3438 const dns_master_style_t *style,
3439 dns_messagetextflag_t flags,
3440 isc_buffer_t *target)
3441 {
3442 dns_rdataset_t *ps = NULL;
3443 const dns_name_t *name = NULL;
3444 isc_result_t result = ISC_R_SUCCESS;
3445 char buf[sizeof("1234567890")];
3446 uint32_t mbz;
3447 dns_rdata_t rdata;
3448 isc_buffer_t optbuf;
3449 uint16_t optcode, optlen;
3450 unsigned char *optdata;
3451 unsigned int saveindent = dns_master_indent;
3452
3453 REQUIRE(DNS_MESSAGE_VALID(msg));
3454 REQUIRE(target != NULL);
3455 REQUIRE(VALID_PSEUDOSECTION(section));
3456
3457 switch (section) {
3458 case DNS_PSEUDOSECTION_OPT:
3459 ps = dns_message_getopt(msg);
3460 if (ps == NULL) {
3461 goto cleanup;
3462 }
3463
3464 INDENT(style);
3465 ADD_STRING(target, "OPT_PSEUDOSECTION:\n");
3466 dns_master_indent++;
3467
3468 INDENT(style);
3469 ADD_STRING(target, "EDNS:\n");
3470 dns_master_indent++;
3471
3472 INDENT(style);
3473 ADD_STRING(target, "version: ");
3474 snprintf(buf, sizeof(buf), "%u",
3475 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3476 ADD_STRING(target, buf);
3477 ADD_STRING(target, "\n");
3478 INDENT(style);
3479 ADD_STRING(target, "flags:");
3480 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3481 ADD_STRING(target, " do");
3482 ADD_STRING(target, "\n");
3483 mbz = ps->ttl & 0xffff;
3484 mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */
3485 if (mbz != 0) {
3486 INDENT(style);
3487 ADD_STRING(target, "MBZ: ");
3488 snprintf(buf, sizeof(buf), "0x%.4x", mbz);
3489 ADD_STRING(target, buf);
3490 ADD_STRING(target, "\n");
3491 }
3492 INDENT(style);
3493 ADD_STRING(target, "udp: ");
3494 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3495 ADD_STRING(target, buf);
3496 result = dns_rdataset_first(ps);
3497 if (result != ISC_R_SUCCESS) {
3498 result = ISC_R_SUCCESS;
3499 goto cleanup;
3500 }
3501
3502 /*
3503 * Print EDNS info, if any.
3504 *
3505 * WARNING: The option contents may be malformed as
3506 * dig +ednsopt=value:<content> does not validity
3507 * checking.
3508 */
3509 dns_rdata_init(&rdata);
3510 dns_rdataset_current(ps, &rdata);
3511
3512 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3513 isc_buffer_add(&optbuf, rdata.length);
3514 while (isc_buffer_remaininglength(&optbuf) != 0) {
3515 INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3516 optcode = isc_buffer_getuint16(&optbuf);
3517 optlen = isc_buffer_getuint16(&optbuf);
3518 INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3519
3520 if (optcode == DNS_OPT_NSID) {
3521 INDENT(style);
3522 ADD_STRING(target, "NSID");
3523 } else if (optcode == DNS_OPT_COOKIE) {
3524 INDENT(style);
3525 ADD_STRING(target, "COOKIE");
3526 } else if (optcode == DNS_OPT_CLIENT_SUBNET) {
3527 isc_buffer_t ecsbuf;
3528 INDENT(style);
3529 ADD_STRING(target, "CLIENT-SUBNET");
3530 isc_buffer_init(&ecsbuf,
3531 isc_buffer_current(&optbuf),
3532 optlen);
3533 isc_buffer_add(&ecsbuf, optlen);
3534 result = render_ecs(&ecsbuf, target);
3535 if (result == ISC_R_NOSPACE)
3536 goto cleanup;
3537 if (result == ISC_R_SUCCESS) {
3538 isc_buffer_forward(&optbuf, optlen);
3539 ADD_STRING(target, "\n");
3540 continue;
3541 }
3542 ADD_STRING(target, "\n");
3543 } else if (optcode == DNS_OPT_EXPIRE) {
3544 if (optlen == 4) {
3545 uint32_t secs;
3546 secs = isc_buffer_getuint32(&optbuf);
3547 INDENT(style);
3548 ADD_STRING(target, "EXPIRE: ");
3549 snprintf(buf, sizeof(buf), "%u", secs);
3550 ADD_STRING(target, buf);
3551 ADD_STRING(target, " (");
3552 result = dns_ttl_totext(secs,
3553 true,
3554 true,
3555 target);
3556 if (result != ISC_R_SUCCESS)
3557 goto cleanup;
3558 ADD_STRING(target, ")\n");
3559 continue;
3560 }
3561 INDENT(style);
3562 ADD_STRING(target, "EXPIRE");
3563 } else if (optcode == DNS_OPT_PAD) {
3564 INDENT(style);
3565 ADD_STRING(target, "PAD");
3566 } else if (optcode == DNS_OPT_KEY_TAG) {
3567 INDENT(style);
3568 ADD_STRING(target, "KEY-TAG");
3569 if (optlen > 0U && (optlen % 2U) == 0U) {
3570 const char *sep = ": ";
3571 uint16_t id;
3572 while (optlen > 0U) {
3573 id = isc_buffer_getuint16(&optbuf);
3574 snprintf(buf, sizeof(buf), "%s%u",
3575 sep, id);
3576 ADD_STRING(target, buf);
3577 sep = ", ";
3578 optlen -= 2;
3579 }
3580 ADD_STRING(target, "\n");
3581 continue;
3582 }
3583 } else {
3584 INDENT(style);
3585 ADD_STRING(target, "OPT: ");
3586 snprintf(buf, sizeof(buf), "%u", optcode);
3587 ADD_STRING(target, buf);
3588 ADD_STRING(target, "\n");
3589 }
3590
3591 if (optlen != 0) {
3592 int i;
3593 ADD_STRING(target, ": ");
3594
3595 optdata = isc_buffer_current(&optbuf);
3596 for (i = 0; i < optlen; i++) {
3597 const char *sep;
3598 switch (optcode) {
3599 case DNS_OPT_COOKIE:
3600 sep = "";
3601 break;
3602 default:
3603 sep = " ";
3604 break;
3605 }
3606 snprintf(buf, sizeof(buf), "%02x%s",
3607 optdata[i], sep);
3608 ADD_STRING(target, buf);
3609 }
3610
3611 isc_buffer_forward(&optbuf, optlen);
3612
3613 if (optcode == DNS_OPT_COOKIE) {
3614 /*
3615 * Valid server cookie?
3616 */
3617 if (msg->cc_ok && optlen >= 16)
3618 ADD_STRING(target, " (good)");
3619 /*
3620 * Server cookie is not valid but
3621 * we had our cookie echoed back.
3622 */
3623 if (msg->cc_ok && optlen < 16)
3624 ADD_STRING(target, " (echoed)");
3625 /*
3626 * We didn't get our cookie echoed
3627 * back.
3628 */
3629 if (msg->cc_bad)
3630 ADD_STRING(target, " (bad)");
3631 ADD_STRING(target, "\n");
3632 continue;
3633 }
3634
3635 if (optcode == DNS_OPT_CLIENT_SUBNET) {
3636 ADD_STRING(target, "\n");
3637 continue;
3638 }
3639
3640 /*
3641 * For non-COOKIE options, add a printable
3642 * version
3643 */
3644 ADD_STRING(target, "(\"");
3645 if (isc_buffer_availablelength(target) < optlen)
3646 {
3647 result = ISC_R_NOSPACE;
3648 goto cleanup;
3649 }
3650 for (i = 0; i < optlen; i++) {
3651 if (isprint(optdata[i]))
3652 isc_buffer_putmem(target,
3653 &optdata[i],
3654 1);
3655 else
3656 isc_buffer_putstr(target, ".");
3657 }
3658 ADD_STRING(target, "\")");
3659 }
3660 ADD_STRING(target, "\n");
3661 }
3662 result = ISC_R_SUCCESS;
3663 goto cleanup;
3664 case DNS_PSEUDOSECTION_TSIG:
3665 ps = dns_message_gettsig(msg, &name);
3666 if (ps == NULL) {
3667 result = ISC_R_SUCCESS;
3668 goto cleanup;
3669 }
3670 INDENT(style);
3671 ADD_STRING(target, "TSIG_PSEUDOSECTION:\n");
3672 result = dns_master_rdatasettotext(name, ps, style, target);
3673 ADD_STRING(target, "\n");
3674 goto cleanup;
3675 case DNS_PSEUDOSECTION_SIG0:
3676 ps = dns_message_getsig0(msg, &name);
3677 if (ps == NULL) {
3678 result = ISC_R_SUCCESS;
3679 goto cleanup;
3680 }
3681 INDENT(style);
3682 ADD_STRING(target, "SIG0_PSEUDOSECTION:\n");
3683 result = dns_master_rdatasettotext(name, ps, style, target);
3684 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3685 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3686 ADD_STRING(target, "\n");
3687 goto cleanup;
3688 }
3689
3690 result = ISC_R_UNEXPECTED;
3691
3692 cleanup:
3693 dns_master_indent = saveindent;
3694 return (result);
3695 }
3696
3697 isc_result_t
3698 dns_message_pseudosectiontotext(dns_message_t *msg,
3699 dns_pseudosection_t section,
3700 const dns_master_style_t *style,
3701 dns_messagetextflag_t flags,
3702 isc_buffer_t *target)
3703 {
3704 dns_rdataset_t *ps = NULL;
3705 const dns_name_t *name = NULL;
3706 isc_result_t result;
3707 char buf[sizeof(" (65000 bytes)")];
3708 uint32_t mbz;
3709 dns_rdata_t rdata;
3710 isc_buffer_t optbuf;
3711 uint16_t optcode, optlen;
3712 unsigned char *optdata;
3713
3714 REQUIRE(DNS_MESSAGE_VALID(msg));
3715 REQUIRE(target != NULL);
3716 REQUIRE(VALID_PSEUDOSECTION(section));
3717
3718 if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0)
3719 return (dns_message_pseudosectiontoyaml(msg, section, style,
3720 flags, target));
3721 switch (section) {
3722 case DNS_PSEUDOSECTION_OPT:
3723 ps = dns_message_getopt(msg);
3724 if (ps == NULL)
3725 return (ISC_R_SUCCESS);
3726 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3727 INDENT(style);
3728 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3729 }
3730
3731 INDENT(style);
3732 ADD_STRING(target, "; EDNS: version: ");
3733 snprintf(buf, sizeof(buf), "%u",
3734 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3735 ADD_STRING(target, buf);
3736 ADD_STRING(target, ", flags:");
3737 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3738 ADD_STRING(target, " do");
3739 mbz = ps->ttl & 0xffff;
3740 mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */
3741 if (mbz != 0) {
3742 ADD_STRING(target, "; MBZ: ");
3743 snprintf(buf, sizeof(buf), "0x%.4x", mbz);
3744 ADD_STRING(target, buf);
3745 ADD_STRING(target, ", udp: ");
3746 } else
3747 ADD_STRING(target, "; udp: ");
3748 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3749 ADD_STRING(target, buf);
3750
3751 result = dns_rdataset_first(ps);
3752 if (result != ISC_R_SUCCESS)
3753 return (ISC_R_SUCCESS);
3754
3755 /*
3756 * Print EDNS info, if any.
3757 *
3758 * WARNING: The option contents may be malformed as
3759 * dig +ednsopt=value:<content> does no validity
3760 * checking.
3761 */
3762 dns_rdata_init(&rdata);
3763 dns_rdataset_current(ps, &rdata);
3764
3765 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3766 isc_buffer_add(&optbuf, rdata.length);
3767 while (isc_buffer_remaininglength(&optbuf) != 0) {
3768 INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3769 optcode = isc_buffer_getuint16(&optbuf);
3770 optlen = isc_buffer_getuint16(&optbuf);
3771
3772 INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3773
3774 INDENT(style);
3775
3776 if (optcode == DNS_OPT_NSID) {
3777 ADD_STRING(target, "; NSID");
3778 } else if (optcode == DNS_OPT_COOKIE) {
3779 ADD_STRING(target, "; COOKIE");
3780 } else if (optcode == DNS_OPT_CLIENT_SUBNET) {
3781 isc_buffer_t ecsbuf;
3782
3783 ADD_STRING(target, "; CLIENT-SUBNET");
3784 isc_buffer_init(&ecsbuf,
3785 isc_buffer_current(&optbuf),
3786 optlen);
3787 isc_buffer_add(&ecsbuf, optlen);
3788 result = render_ecs(&ecsbuf, target);
3789 if (result == ISC_R_NOSPACE)
3790 return (result);
3791 if (result == ISC_R_SUCCESS) {
3792 isc_buffer_forward(&optbuf, optlen);
3793 ADD_STRING(target, "\n");
3794 continue;
3795 }
3796 } else if (optcode == DNS_OPT_EXPIRE) {
3797 if (optlen == 4) {
3798 uint32_t secs;
3799 secs = isc_buffer_getuint32(&optbuf);
3800 ADD_STRING(target, "; EXPIRE: ");
3801 snprintf(buf, sizeof(buf), "%u", secs);
3802 ADD_STRING(target, buf);
3803 ADD_STRING(target, " (");
3804 result = dns_ttl_totext(secs,
3805 true,
3806 true,
3807 target);
3808 if (result != ISC_R_SUCCESS)
3809 return (result);
3810 ADD_STRING(target, ")\n");
3811 continue;
3812 }
3813 ADD_STRING(target, "; EXPIRE");
3814 } else if (optcode == DNS_OPT_TCP_KEEPALIVE) {
3815 if (optlen == 2) {
3816 unsigned int dsecs;
3817 dsecs = isc_buffer_getuint16(&optbuf);
3818 ADD_STRING(target, "; TCP KEEPALIVE:");
3819 snprintf(buf, sizeof(buf), " %u.%u",
3820 dsecs / 10U, dsecs % 10U);
3821 ADD_STRING(target, buf);
3822 ADD_STRING(target, " secs\n");
3823 continue;
3824 }
3825 ADD_STRING(target, "; TCP KEEPALIVE");
3826 } else if (optcode == DNS_OPT_PAD) {
3827 ADD_STRING(target, "; PAD");
3828 if (optlen > 0U) {
3829 snprintf(buf, sizeof(buf),
3830 " (%u bytes)", optlen);
3831 ADD_STRING(target, buf);
3832 isc_buffer_forward(&optbuf, optlen);
3833 }
3834 ADD_STRING(target, "\n");
3835 continue;
3836 } else if (optcode == DNS_OPT_KEY_TAG) {
3837 ADD_STRING(target, "; KEY-TAG");
3838 if (optlen > 0U && (optlen % 2U) == 0U) {
3839 const char *sep = ": ";
3840 uint16_t id;
3841 while (optlen > 0U) {
3842 id = isc_buffer_getuint16(&optbuf);
3843 snprintf(buf, sizeof(buf), "%s%u",
3844 sep, id);
3845 ADD_STRING(target, buf);
3846 sep = ", ";
3847 optlen -= 2;
3848 }
3849 ADD_STRING(target, "\n");
3850 continue;
3851 }
3852 } else {
3853 ADD_STRING(target, "; OPT=");
3854 snprintf(buf, sizeof(buf), "%u", optcode);
3855 ADD_STRING(target, buf);
3856 }
3857
3858 if (optlen != 0) {
3859 int i;
3860 ADD_STRING(target, ": ");
3861
3862 optdata = isc_buffer_current(&optbuf);
3863 for (i = 0; i < optlen; i++) {
3864 const char *sep;
3865 switch (optcode) {
3866 case DNS_OPT_COOKIE:
3867 sep = "";
3868 break;
3869 default:
3870 sep = " ";
3871 break;
3872 }
3873 snprintf(buf, sizeof(buf), "%02x%s",
3874 optdata[i], sep);
3875 ADD_STRING(target, buf);
3876 }
3877
3878 isc_buffer_forward(&optbuf, optlen);
3879
3880 if (optcode == DNS_OPT_COOKIE) {
3881 /*
3882 * Valid server cookie?
3883 */
3884 if (msg->cc_ok && optlen >= 16)
3885 ADD_STRING(target, " (good)");
3886 /*
3887 * Server cookie is not valid but
3888 * we had our cookie echoed back.
3889 */
3890 if (msg->cc_ok && optlen < 16)
3891 ADD_STRING(target, " (echoed)");
3892 /*
3893 * We didn't get our cookie echoed
3894 * back.
3895 */
3896 if (msg->cc_bad)
3897 ADD_STRING(target, " (bad)");
3898 ADD_STRING(target, "\n");
3899 continue;
3900 }
3901
3902 if (optcode == DNS_OPT_CLIENT_SUBNET) {
3903 ADD_STRING(target, "\n");
3904 continue;
3905 }
3906
3907 /*
3908 * For non-COOKIE options, add a printable
3909 * version
3910 */
3911 ADD_STRING(target, "(\"");
3912 if (isc_buffer_availablelength(target) < optlen)
3913 return (ISC_R_NOSPACE);
3914 for (i = 0; i < optlen; i++) {
3915 if (isprint(optdata[i]))
3916 isc_buffer_putmem(target,
3917 &optdata[i],
3918 1);
3919 else
3920 isc_buffer_putstr(target, ".");
3921 }
3922 ADD_STRING(target, "\")");
3923 }
3924 ADD_STRING(target, "\n");
3925 }
3926 return (ISC_R_SUCCESS);
3927 case DNS_PSEUDOSECTION_TSIG:
3928 ps = dns_message_gettsig(msg, &name);
3929 if (ps == NULL)
3930 return (ISC_R_SUCCESS);
3931 INDENT(style);
3932 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3933 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3934 result = dns_master_rdatasettotext(name, ps, style, target);
3935 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3936 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3937 ADD_STRING(target, "\n");
3938 return (result);
3939 case DNS_PSEUDOSECTION_SIG0:
3940 ps = dns_message_getsig0(msg, &name);
3941 if (ps == NULL)
3942 return (ISC_R_SUCCESS);
3943 INDENT(style);
3944 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3945 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3946 result = dns_master_rdatasettotext(name, ps, style, target);
3947 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3948 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3949 ADD_STRING(target, "\n");
3950 return (result);
3951 }
3952 result = ISC_R_UNEXPECTED;
3953 cleanup:
3954 return (result);
3955 }
3956
3957 isc_result_t
3958 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3959 dns_messagetextflag_t flags, isc_buffer_t *target)
3960 {
3961 char buf[sizeof("1234567890")];
3962 isc_result_t result;
3963
3964 REQUIRE(DNS_MESSAGE_VALID(msg));
3965 REQUIRE(target != NULL);
3966
3967 if (((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) &&
3968 (dns_master_styleflags(style) & DNS_STYLEFLAG_YAML))
3969 {
3970 INDENT(style);
3971 ADD_STRING(target, "opcode: ");
3972 ADD_STRING(target, opcodetext[msg->opcode]);
3973 ADD_STRING(target, "\n");
3974 INDENT(style);
3975 ADD_STRING(target, "status: ");
3976 result = dns_rcode_totext(msg->rcode, target);
3977 if (result != ISC_R_SUCCESS)
3978 return (result);
3979 ADD_STRING(target, "\n");
3980 INDENT(style);
3981 ADD_STRING(target, "id: ");
3982 snprintf(buf, sizeof(buf), "%6u", msg->id);
3983 ADD_STRING(target, buf);
3984 ADD_STRING(target, "\n");
3985 INDENT(style);
3986 ADD_STRING(target, "flags:");
3987 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3988 ADD_STRING(target, " qr");
3989 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3990 ADD_STRING(target, " aa");
3991 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3992 ADD_STRING(target, " tc");
3993 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3994 ADD_STRING(target, " rd");
3995 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3996 ADD_STRING(target, " ra");
3997 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3998 ADD_STRING(target, " ad");
3999 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
4000 ADD_STRING(target, " cd");
4001 ADD_STRING(target, "\n");
4002 /*
4003 * The final unnamed flag must be zero.
4004 */
4005 if ((msg->flags & 0x0040U) != 0) {
4006 INDENT(style);
4007 ADD_STRING(target, "MBZ: 0x4");
4008 ADD_STRING(target, "\n");
4009 }
4010 if (msg->opcode != dns_opcode_update) {
4011 INDENT(style);
4012 ADD_STRING(target, "QUESTION: ");
4013 } else {
4014 ADD_STRING(target, "ZONE: ");
4015 }
4016 snprintf(buf, sizeof(buf), "%1u",
4017 msg->counts[DNS_SECTION_QUESTION]);
4018 ADD_STRING(target, buf);
4019 ADD_STRING(target, "\n");
4020 if (msg->opcode != dns_opcode_update) {
4021 INDENT(style);
4022 ADD_STRING(target, "ANSWER: ");
4023 } else {
4024 INDENT(style);
4025 ADD_STRING(target, "PREREQ: ");
4026 }
4027 snprintf(buf, sizeof(buf), "%1u",
4028 msg->counts[DNS_SECTION_ANSWER]);
4029 ADD_STRING(target, buf);
4030 ADD_STRING(target, "\n");
4031 if (msg->opcode != dns_opcode_update) {
4032 INDENT(style);
4033 ADD_STRING(target, "AUTHORITY: ");
4034 } else {
4035 INDENT(style);
4036 ADD_STRING(target, "UPDATE: ");
4037 }
4038 snprintf(buf, sizeof(buf), "%1u",
4039 msg->counts[DNS_SECTION_AUTHORITY]);
4040 ADD_STRING(target, buf);
4041 ADD_STRING(target, "\n");
4042 INDENT(style);
4043 ADD_STRING(target, "ADDITIONAL: ");
4044 snprintf(buf, sizeof(buf), "%1u",
4045 msg->counts[DNS_SECTION_ADDITIONAL]);
4046 ADD_STRING(target, buf);
4047 ADD_STRING(target, "\n");
4048 } else if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
4049 INDENT(style);
4050 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
4051 ADD_STRING(target, opcodetext[msg->opcode]);
4052 ADD_STRING(target, ", status: ");
4053 result = dns_rcode_totext(msg->rcode, target);
4054 if (result != ISC_R_SUCCESS)
4055 return (result);
4056 ADD_STRING(target, ", id: ");
4057 snprintf(buf, sizeof(buf), "%6u", msg->id);
4058 ADD_STRING(target, buf);
4059 ADD_STRING(target, "\n");
4060 INDENT(style);
4061 ADD_STRING(target, ";; flags:");
4062 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
4063 ADD_STRING(target, " qr");
4064 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
4065 ADD_STRING(target, " aa");
4066 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
4067 ADD_STRING(target, " tc");
4068 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
4069 ADD_STRING(target, " rd");
4070 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
4071 ADD_STRING(target, " ra");
4072 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
4073 ADD_STRING(target, " ad");
4074 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
4075 ADD_STRING(target, " cd");
4076 /*
4077 * The final unnamed flag must be zero.
4078 */
4079 if ((msg->flags & 0x0040U) != 0) {
4080 INDENT(style);
4081 ADD_STRING(target, "; MBZ: 0x4");
4082 }
4083 if (msg->opcode != dns_opcode_update) {
4084 INDENT(style);
4085 ADD_STRING(target, "; QUESTION: ");
4086 } else {
4087 INDENT(style);
4088 ADD_STRING(target, "; ZONE: ");
4089 }
4090 snprintf(buf, sizeof(buf), "%1u",
4091 msg->counts[DNS_SECTION_QUESTION]);
4092 ADD_STRING(target, buf);
4093 if (msg->opcode != dns_opcode_update) {
4094 ADD_STRING(target, ", ANSWER: ");
4095 } else {
4096 ADD_STRING(target, ", PREREQ: ");
4097 }
4098 snprintf(buf, sizeof(buf), "%1u",
4099 msg->counts[DNS_SECTION_ANSWER]);
4100 ADD_STRING(target, buf);
4101 if (msg->opcode != dns_opcode_update) {
4102 ADD_STRING(target, ", AUTHORITY: ");
4103 } else {
4104 ADD_STRING(target, ", UPDATE: ");
4105 }
4106 snprintf(buf, sizeof(buf), "%1u",
4107 msg->counts[DNS_SECTION_AUTHORITY]);
4108 ADD_STRING(target, buf);
4109 ADD_STRING(target, ", ADDITIONAL: ");
4110 snprintf(buf, sizeof(buf), "%1u",
4111 msg->counts[DNS_SECTION_ADDITIONAL]);
4112 ADD_STRING(target, buf);
4113 ADD_STRING(target, "\n");
4114 }
4115 result = dns_message_pseudosectiontotext(msg,
4116 DNS_PSEUDOSECTION_OPT,
4117 style, flags, target);
4118 if (result != ISC_R_SUCCESS)
4119 return (result);
4120
4121 result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
4122 style, flags, target);
4123 if (result != ISC_R_SUCCESS)
4124 return (result);
4125 result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
4126 style, flags, target);
4127 if (result != ISC_R_SUCCESS)
4128 return (result);
4129 result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
4130 style, flags, target);
4131 if (result != ISC_R_SUCCESS)
4132 return (result);
4133 result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
4134 style, flags, target);
4135 if (result != ISC_R_SUCCESS)
4136 return (result);
4137
4138 result = dns_message_pseudosectiontotext(msg,
4139 DNS_PSEUDOSECTION_TSIG,
4140 style, flags, target);
4141 if (result != ISC_R_SUCCESS)
4142 return (result);
4143
4144 result = dns_message_pseudosectiontotext(msg,
4145 DNS_PSEUDOSECTION_SIG0,
4146 style, flags, target);
4147 if (result != ISC_R_SUCCESS)
4148 return (result);
4149
4150 cleanup:
4151 return (result);
4152 }
4153
4154 isc_region_t *
4155 dns_message_getrawmessage(dns_message_t *msg) {
4156 REQUIRE(DNS_MESSAGE_VALID(msg));
4157 return (&msg->saved);
4158 }
4159
4160 void
4161 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
4162 dns_aclenv_t *env, const dns_acl_t *acl,
4163 const dns_aclelement_t *elem)
4164 {
4165 REQUIRE(DNS_MESSAGE_VALID(msg));
4166 REQUIRE((order == NULL) == (env == NULL));
4167 REQUIRE(env == NULL || (acl != NULL || elem != NULL));
4168
4169 msg->order = order;
4170 msg->order_arg.env = env;
4171 msg->order_arg.acl = acl;
4172 msg->order_arg.element = elem;
4173 }
4174
4175 void
4176 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
4177 REQUIRE(DNS_MESSAGE_VALID(msg));
4178 msg->timeadjust = timeadjust;
4179 }
4180
4181 int
4182 dns_message_gettimeadjust(dns_message_t *msg) {
4183 REQUIRE(DNS_MESSAGE_VALID(msg));
4184 return (msg->timeadjust);
4185 }
4186
4187 isc_result_t
4188 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
4189
4190 REQUIRE(opcode < 16);
4191
4192 if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
4193 return (ISC_R_NOSPACE);
4194 isc_buffer_putstr(target, opcodetext[opcode]);
4195 return (ISC_R_SUCCESS);
4196 }
4197
4198 void
4199 dns_message_logpacket(dns_message_t *message,
4200 const char *description, const isc_sockaddr_t *address,
4201 isc_logcategory_t *category, isc_logmodule_t *module,
4202 int level, isc_mem_t *mctx)
4203 {
4204 REQUIRE(address != NULL);
4205
4206 logfmtpacket(message, description, address, category, module,
4207 &dns_master_style_debug, level, mctx);
4208 }
4209
4210 void
4211 dns_message_logfmtpacket(dns_message_t *message,
4212 const char *description,
4213 const isc_sockaddr_t *address,
4214 isc_logcategory_t *category, isc_logmodule_t *module,
4215 const dns_master_style_t *style, int level,
4216 isc_mem_t *mctx)
4217 {
4218 REQUIRE(address != NULL);
4219
4220 logfmtpacket(message, description, address, category, module, style,
4221 level, mctx);
4222 }
4223
4224 static void
4225 logfmtpacket(dns_message_t *message, const char *description,
4226 const isc_sockaddr_t *address, isc_logcategory_t *category,
4227 isc_logmodule_t *module, const dns_master_style_t *style,
4228 int level, isc_mem_t *mctx)
4229 {
4230 char addrbuf[ISC_SOCKADDR_FORMATSIZE] = { 0 };
4231 const char *newline = "\n";
4232 const char *space = " ";
4233 isc_buffer_t buffer;
4234 char *buf = NULL;
4235 int len = 1024;
4236 isc_result_t result;
4237
4238 if (! isc_log_wouldlog(dns_lctx, level))
4239 return;
4240
4241 /*
4242 * Note that these are multiline debug messages. We want a newline
4243 * to appear in the log after each message.
4244 */
4245
4246 if (address != NULL)
4247 isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
4248 else
4249 newline = space = "";
4250
4251 do {
4252 buf = isc_mem_get(mctx, len);
4253 if (buf == NULL)
4254 break;
4255 isc_buffer_init(&buffer, buf, len);
4256 result = dns_message_totext(message, style, 0, &buffer);
4257 if (result == ISC_R_NOSPACE) {
4258 isc_mem_put(mctx, buf, len);
4259 len += 1024;
4260 } else if (result == ISC_R_SUCCESS)
4261 isc_log_write(dns_lctx, category, module, level,
4262 "%s%s%s%s%.*s", description, space,
4263 addrbuf, newline,
4264 (int)isc_buffer_usedlength(&buffer),
4265 buf);
4266 } while (result == ISC_R_NOSPACE);
4267
4268 if (buf != NULL)
4269 isc_mem_put(mctx, buf, len);
4270 }
4271
4272 isc_result_t
4273 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
4274 unsigned int version, uint16_t udpsize,
4275 unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
4276 {
4277 dns_rdataset_t *rdataset = NULL;
4278 dns_rdatalist_t *rdatalist = NULL;
4279 dns_rdata_t *rdata = NULL;
4280 isc_result_t result;
4281 unsigned int len = 0, i;
4282
4283 REQUIRE(DNS_MESSAGE_VALID(message));
4284 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
4285
4286 result = dns_message_gettemprdatalist(message, &rdatalist);
4287 if (result != ISC_R_SUCCESS)
4288 return (result);
4289 result = dns_message_gettemprdata(message, &rdata);
4290 if (result != ISC_R_SUCCESS)
4291 goto cleanup;
4292 result = dns_message_gettemprdataset(message, &rdataset);
4293 if (result != ISC_R_SUCCESS)
4294 goto cleanup;
4295
4296 rdatalist->type = dns_rdatatype_opt;
4297
4298 /*
4299 * Set Maximum UDP buffer size.
4300 */
4301 rdatalist->rdclass = udpsize;
4302
4303 /*
4304 * Set EXTENDED-RCODE and Z to 0.
4305 */
4306 rdatalist->ttl = (version << 16);
4307 rdatalist->ttl |= (flags & 0xffff);
4308
4309 /*
4310 * Set EDNS options if applicable
4311 */
4312 if (count != 0U) {
4313 isc_buffer_t *buf = NULL;
4314 bool seenpad = false;
4315 for (i = 0; i < count; i++)
4316 len += ednsopts[i].length + 4;
4317
4318 if (len > 0xffffU) {
4319 result = ISC_R_NOSPACE;
4320 goto cleanup;
4321 }
4322
4323 result = isc_buffer_allocate(message->mctx, &buf, len);
4324 if (result != ISC_R_SUCCESS)
4325 goto cleanup;
4326
4327 for (i = 0; i < count; i++) {
4328 if (ednsopts[i].code == DNS_OPT_PAD &&
4329 ednsopts[i].length == 0U && !seenpad)
4330 {
4331 seenpad = true;
4332 continue;
4333 }
4334 isc_buffer_putuint16(buf, ednsopts[i].code);
4335 isc_buffer_putuint16(buf, ednsopts[i].length);
4336 if (ednsopts[i].length != 0) {
4337 isc_buffer_putmem(buf, ednsopts[i].value,
4338 ednsopts[i].length);
4339 }
4340 }
4341
4342 /* Padding must be the final option */
4343 if (seenpad) {
4344 isc_buffer_putuint16(buf, DNS_OPT_PAD);
4345 isc_buffer_putuint16(buf, 0);
4346 }
4347 rdata->data = isc_buffer_base(buf);
4348 rdata->length = len;
4349 dns_message_takebuffer(message, &buf);
4350 if (seenpad)
4351 message->padding_off = len;
4352 } else {
4353 rdata->data = NULL;
4354 rdata->length = 0;
4355 }
4356
4357 rdata->rdclass = rdatalist->rdclass;
4358 rdata->type = rdatalist->type;
4359 rdata->flags = 0;
4360
4361 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
4362 result = dns_rdatalist_tordataset(rdatalist, rdataset);
4363 RUNTIME_CHECK(result == ISC_R_SUCCESS);
4364
4365 *rdatasetp = rdataset;
4366 return (ISC_R_SUCCESS);
4367
4368 cleanup:
4369 if (rdata != NULL)
4370 dns_message_puttemprdata(message, &rdata);
4371 if (rdataset != NULL)
4372 dns_message_puttemprdataset(message, &rdataset);
4373 if (rdatalist != NULL)
4374 dns_message_puttemprdatalist(message, &rdatalist);
4375 return (result);
4376 }
4377
4378 void
4379 dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
4380
4381 REQUIRE(DNS_MESSAGE_VALID(msg));
4382 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
4383 REQUIRE(msg->state == DNS_SECTION_ANY);
4384 REQUIRE(msg->rdclass_set == 0);
4385
4386 msg->rdclass = rdclass;
4387 msg->rdclass_set = 1;
4388 }
4389
4390 void
4391 dns_message_setpadding(dns_message_t *msg, uint16_t padding) {
4392 REQUIRE(DNS_MESSAGE_VALID(msg));
4393
4394 /* Avoid silly large padding */
4395 if (padding > 512)
4396 padding = 512;
4397 msg->padding = padding;
4398 }
4399