Coverage Report

Created: 2025-07-18 07:02

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