Coverage Report

Created: 2026-07-30 06:31

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