Coverage Report

Created: 2026-07-16 07:05

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.3k
#define DNS_MESSAGE_OPCODE_MASK       0x7800U
85
32.3k
#define DNS_MESSAGE_OPCODE_SHIFT      11
86
41.1k
#define DNS_MESSAGE_RCODE_MASK        0x000fU
87
32.3k
#define DNS_MESSAGE_FLAG_MASK       0x8ff0U
88
8.48k
#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
537M
  {                                                         \
98
537M
    if (strlen(s) >= isc_buffer_availablelength(b)) { \
99
3
      result = ISC_R_NOSPACE;                   \
100
3
      goto cleanup;                             \
101
3
    } else                                            \
102
537M
      isc_buffer_putstr(b, s);                  \
103
537M
  }
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
154k
#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
121k
#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
53.6k
#define RDATA_COUNT    8
128
67.7k
#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
853k
  ((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
121k
      unsigned int count) {
238
121k
  dns_msgblock_t *block;
239
121k
  unsigned int length;
240
241
121k
  length = sizeof(dns_msgblock_t) + (sizeof_type * count);
242
243
121k
  block = isc_mem_get(mctx, length);
244
245
121k
  block->count = count;
246
121k
  block->remaining = count;
247
248
121k
  ISC_LINK_INIT(block, link);
249
250
121k
  return block;
251
121k
}
252
253
/*
254
 * Return an element from the msgblock.  If no more are available, return
255
 * NULL.
256
 */
257
static void *
258
853k
msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
259
853k
  void *ptr;
260
261
853k
  if (block == NULL || block->remaining == 0) {
262
121k
    return NULL;
263
121k
  }
264
265
732k
  block->remaining--;
266
267
732k
  ptr = (((unsigned char *)block) + sizeof(dns_msgblock_t) +
268
732k
         (sizeof_type * block->remaining));
269
270
732k
  return ptr;
271
853k
}
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
121k
        unsigned int sizeof_type) {
284
121k
  unsigned int length;
285
286
121k
  length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
287
288
121k
  isc_mem_put(mctx, block, length);
289
121k
}
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
70.5k
newbuffer(dns_message_t *msg, unsigned int size) {
298
70.5k
  isc_buffer_t *dynbuf = NULL;
299
300
70.5k
  isc_buffer_allocate(msg->mctx, &dynbuf, size);
301
302
70.5k
  ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
303
70.5k
}
304
305
static isc_buffer_t *
306
804k
currentbuffer(dns_message_t *msg) {
307
804k
  isc_buffer_t *dynbuf;
308
309
804k
  dynbuf = ISC_LIST_TAIL(msg->scratchpad);
310
804k
  INSIST(dynbuf != NULL);
311
312
804k
  return dynbuf;
313
804k
}
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
306k
newrdata(dns_message_t *msg) {
322
306k
  dns_msgblock_t *msgblock;
323
306k
  dns_rdata_t *rdata;
324
325
306k
  rdata = ISC_LIST_HEAD(msg->freerdata);
326
306k
  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
306k
  msgblock = ISC_LIST_TAIL(msg->rdatas);
333
306k
  rdata = msgblock_get(msgblock, dns_rdata_t);
334
306k
  if (rdata == NULL) {
335
53.6k
    msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
336
53.6k
               RDATA_COUNT);
337
53.6k
    ISC_LIST_APPEND(msg->rdatas, msgblock, link);
338
339
53.6k
    rdata = msgblock_get(msgblock, dns_rdata_t);
340
53.6k
  }
341
342
306k
  dns_rdata_init(rdata);
343
306k
  return rdata;
344
306k
}
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
425k
newrdatalist(dns_message_t *msg) {
353
425k
  dns_msgblock_t *msgblock;
354
425k
  dns_rdatalist_t *rdatalist;
355
356
425k
  rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
357
425k
  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
425k
  msgblock = ISC_LIST_TAIL(msg->rdatalists);
364
425k
  rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
365
425k
  if (rdatalist == NULL) {
366
67.7k
    msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdatalist_t),
367
67.7k
               RDATALIST_COUNT);
368
67.7k
    ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
369
370
67.7k
    rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
371
67.7k
  }
372
425k
out:
373
425k
  dns_rdatalist_init(rdatalist);
374
425k
  return rdatalist;
375
425k
}
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
201k
msgresetname(dns_message_t *msg, dns_name_t *name) {
452
254k
  ISC_LIST_FOREACH(name->list, rds, link) {
453
254k
    ISC_LIST_UNLINK(name->list, rds, link);
454
254k
    dns__message_putassociatedrdataset(msg, &rds);
455
254k
  }
456
201k
}
457
458
static void
459
24.9k
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
201k
    ISC_LIST_FOREACH(msg->sections[i], name, link) {
463
201k
      ISC_LIST_UNLINK(msg->sections[i], name, link);
464
201k
      msgresetname(msg, name);
465
201k
      dns_message_puttempname(msg, &name);
466
201k
    }
467
98.4k
  }
468
24.9k
}
469
470
static void
471
23.6k
msgresetopt(dns_message_t *msg) {
472
23.6k
  if (msg->opt != NULL) {
473
4.25k
    if (msg->opt_reserved > 0) {
474
0
      dns_message_renderrelease(msg, msg->opt_reserved);
475
0
      msg->opt_reserved = 0;
476
0
    }
477
4.25k
    dns__message_putassociatedrdataset(msg, &msg->opt);
478
4.25k
    msg->opt = NULL;
479
4.25k
    msg->cc_ok = 0;
480
4.25k
    msg->cc_bad = 0;
481
4.25k
  }
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
625
    INSIST(dns_rdataset_isassociated(msg->tsig));
492
625
    INSIST(msg->namepool != NULL);
493
625
    if (replying) {
494
0
      INSIST(msg->querytsig == NULL);
495
0
      msg->querytsig = msg->tsig;
496
625
    } else {
497
625
      dns__message_putassociatedrdataset(msg, &msg->tsig);
498
625
      if (msg->querytsig != NULL) {
499
171
        dns__message_putassociatedrdataset(
500
171
          msg, &msg->querytsig);
501
171
      }
502
625
    }
503
625
    dns_message_puttempname(msg, &msg->tsigname);
504
625
    msg->tsig = NULL;
505
23.0k
  } else if (msg->querytsig != NULL && !replying) {
506
60
    dns__message_putassociatedrdataset(msg, &msg->querytsig);
507
60
    msg->querytsig = NULL;
508
60
  }
509
23.6k
  if (msg->sig0 != NULL) {
510
496
    dns__message_putassociatedrdataset(msg, &msg->sig0);
511
496
    msg->sig0 = NULL;
512
496
  }
513
23.6k
  if (msg->sig0name != NULL) {
514
496
    dns_message_puttempname(msg, &msg->sig0name);
515
496
  }
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
117k
  while (dynbuf != NULL) {
572
94.2k
    next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
573
94.2k
    ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
574
94.2k
    isc_buffer_free(&dynbuf);
575
94.2k
    dynbuf = next_dynbuf;
576
94.2k
  }
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
77.3k
  while (msgblock != NULL) {
584
53.6k
    next_msgblock = ISC_LIST_NEXT(msgblock, link);
585
53.6k
    ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
586
53.6k
    msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
587
53.6k
    msgblock = next_msgblock;
588
53.6k
  }
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
91.3k
  while (msgblock != NULL) {
600
67.7k
    next_msgblock = ISC_LIST_NEXT(msgblock, link);
601
67.7k
    ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
602
67.7k
    msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
603
67.7k
    msgblock = next_msgblock;
604
67.7k
  }
605
606
23.6k
  if (msg->tsigkey != NULL) {
607
614
    dns_tsigkey_detach(&msg->tsigkey);
608
614
    msg->tsigkey = NULL;
609
614
  }
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
231
    next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
639
231
    ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
640
231
    isc_buffer_free(&dynbuf);
641
231
    dynbuf = next_dynbuf;
642
231
  }
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
218k
name_match(void *node, const void *key) {
772
218k
  return dns_name_equal(node, key);
773
218k
}
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
235k
rds_hash(dns_rdataset_t *rds) {
790
235k
  isc_hash32_t state;
791
792
235k
  isc_hash32_init(&state);
793
235k
  isc_hash32_hash(&state, &rds->rdclass, sizeof(rds->rdclass), true);
794
235k
  isc_hash32_hash(&state, &rds->type, sizeof(rds->type), true);
795
235k
  isc_hash32_hash(&state, &rds->covers, sizeof(rds->covers), true);
796
797
235k
  return isc_hash32_finalize(&state);
798
235k
}
799
800
static bool
801
165k
rds_match(void *node, const void *key0) {
802
165k
  const dns_rdataset_t *rds = node;
803
165k
  const dns_rdataset_t *key = key0;
804
805
165k
  return rds->rdclass == key->rdclass && rds->type == key->type &&
806
165k
         rds->covers == key->covers;
807
165k
}
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
430k
  dns_decompress_t dctx) {
831
430k
  isc_buffer_t *scratch;
832
430k
  isc_result_t result;
833
430k
  unsigned int tries;
834
835
430k
  scratch = currentbuffer(msg);
836
837
  /*
838
   * First try:  use current buffer.
839
   * Second try:  allocate a new buffer and use that.
840
   */
841
430k
  tries = 0;
842
451k
  while (tries < 2) {
843
451k
    result = dns_name_fromwire(name, source, dctx, scratch);
844
845
451k
    if (result == ISC_R_NOSPACE) {
846
21.6k
      tries++;
847
848
21.6k
      newbuffer(msg, SCRATCHPAD_SIZE);
849
21.6k
      scratch = currentbuffer(msg);
850
21.6k
      dns_name_reset(name);
851
430k
    } else {
852
430k
      return result;
853
430k
    }
854
451k
  }
855
856
430k
  UNREACHABLE();
857
430k
}
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
304k
   unsigned int rdatalen, dns_rdata_t *rdata) {
863
304k
  isc_buffer_t *scratch;
864
304k
  isc_result_t result;
865
304k
  unsigned int tries;
866
304k
  unsigned int trysize;
867
868
304k
  scratch = currentbuffer(msg);
869
870
304k
  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
304k
  tries = 0;
880
304k
  trysize = 0;
881
  /* XXX possibly change this to a while (tries < 2) loop */
882
352k
  for (;;) {
883
352k
    result = dns_rdata_fromwire(rdata, rdclass, rdtype, source,
884
352k
              dctx, scratch);
885
886
352k
    if (result == ISC_R_NOSPACE) {
887
48.9k
      if (tries == 0) {
888
39.5k
        trysize = 2 * rdatalen;
889
39.5k
        if (trysize < SCRATCHPAD_SIZE) {
890
36.6k
          trysize = SCRATCHPAD_SIZE;
891
36.6k
        }
892
39.5k
      } else {
893
9.37k
        INSIST(trysize != 0);
894
9.37k
        if (trysize >= 65535) {
895
1
          return ISC_R_NOSPACE;
896
1
        }
897
        /* XXX DNS_R_RRTOOLONG? */
898
9.37k
        trysize *= 2;
899
9.37k
      }
900
48.9k
      tries++;
901
48.9k
      newbuffer(msg, trysize);
902
903
48.9k
      scratch = currentbuffer(msg);
904
304k
    } else {
905
304k
      return result;
906
304k
    }
907
352k
  }
908
304k
}
909
910
#define DO_ERROR(r)                          \
911
326k
  do {                                 \
912
326k
    if (best_effort) {           \
913
326k
      seen_problem = true; \
914
326k
    } else {                     \
915
0
      result = r;          \
916
0
      goto cleanup;        \
917
0
    }                            \
918
326k
  } while (0)
919
920
static void
921
8.34k
cleanup_name_hashmaps(dns_namelist_t *section) {
922
34.1k
  ISC_LIST_FOREACH(*section, name, link) {
923
34.1k
    if (name->hashmap != NULL) {
924
17.2k
      isc_hashmap_destroy(&name->hashmap);
925
17.2k
    }
926
34.1k
  }
927
8.34k
}
928
929
static isc_result_t
930
getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
931
23.5k
       unsigned int options) {
932
23.5k
  isc_region_t r;
933
23.5k
  unsigned int count;
934
23.5k
  dns_name_t *name = NULL;
935
23.5k
  dns_rdataset_t *rdataset = NULL;
936
23.5k
  dns_rdatalist_t *rdatalist = NULL;
937
23.5k
  isc_result_t result = ISC_R_SUCCESS;
938
23.5k
  dns_rdatatype_t rdtype;
939
23.5k
  dns_rdataclass_t rdclass;
940
23.5k
  dns_namelist_t *section = &msg->sections[DNS_SECTION_QUESTION];
941
23.5k
  bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
942
23.5k
  bool seen_problem = false;
943
23.5k
  bool free_name = false;
944
945
23.5k
  REQUIRE(msg->counts[DNS_SECTION_QUESTION] <= 1 || best_effort);
946
947
145k
  for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
948
121k
    name = NULL;
949
121k
    dns_message_gettempname(msg, &name);
950
121k
    free_name = true;
951
952
    /*
953
     * Parse the name out of this packet.
954
     */
955
121k
    isc_buffer_remainingregion(source, &r);
956
121k
    isc_buffer_setactive(source, r.length);
957
121k
    CHECK(getname(name, source, msg, dctx));
958
959
121k
    ISC_LIST_APPEND(*section, name, link);
960
961
121k
    free_name = false;
962
963
    /*
964
     * Get type and class.
965
     */
966
121k
    isc_buffer_remainingregion(source, &r);
967
121k
    if (r.length < 4) {
968
15
      CLEANUP(ISC_R_UNEXPECTEDEND);
969
0
    }
970
121k
    rdtype = isc_buffer_getuint16(source);
971
121k
    rdclass = isc_buffer_getuint16(source);
972
973
    /*
974
     * Notify and update messages need to specify the data class.
975
     */
976
121k
    if ((msg->opcode == dns_opcode_update ||
977
117k
         msg->opcode == dns_opcode_notify) &&
978
7.52k
        (rdclass == dns_rdataclass_none ||
979
7.28k
         rdclass == dns_rdataclass_any))
980
477
    {
981
477
      DO_ERROR(DNS_R_FORMERR);
982
477
    }
983
984
    /*
985
     * If this class is different than the one we already read,
986
     * this is an error.
987
     */
988
121k
    if (msg->rdclass_set == 0) {
989
5.55k
      msg->rdclass = rdclass;
990
5.55k
      msg->rdclass_set = 1;
991
116k
    } else if (msg->rdclass != rdclass) {
992
109k
      DO_ERROR(DNS_R_FORMERR);
993
109k
    }
994
995
    /*
996
     * Is this a TKEY query?
997
     */
998
121k
    if (rdtype == dns_rdatatype_tkey) {
999
307
      msg->tkey = 1;
1000
307
    }
1001
1002
    /*
1003
     * Allocate a new rdatalist.
1004
     */
1005
121k
    rdatalist = newrdatalist(msg);
1006
121k
    rdatalist->type = rdtype;
1007
121k
    rdatalist->rdclass = rdclass;
1008
121k
    rdatalist->covers = dns_rdatatype_none;
1009
1010
    /*
1011
     * Convert rdatalist to rdataset, and attach the latter to
1012
     * the name.
1013
     */
1014
121k
    dns_message_gettemprdataset(msg, &rdataset);
1015
121k
    dns_rdatalist_tordataset(rdatalist, rdataset);
1016
1017
121k
    rdataset->attributes.question = true;
1018
1019
121k
    ISC_LIST_APPEND(name->list, rdataset, link);
1020
1021
121k
    rdataset = NULL;
1022
121k
  }
1023
1024
23.4k
  if (seen_problem) {
1025
    /* XXX test coverage */
1026
2.20k
    result = DNS_R_RECOVERABLE;
1027
2.20k
  }
1028
1029
23.5k
cleanup:
1030
23.5k
  if (rdataset != NULL) {
1031
0
    dns_rdataset_cleanup(rdataset);
1032
0
    dns_message_puttemprdataset(msg, &rdataset);
1033
0
  }
1034
1035
23.5k
  if (free_name) {
1036
101
    dns_message_puttempname(msg, &name);
1037
101
  }
1038
1039
23.5k
  return result;
1040
23.4k
}
1041
1042
static bool
1043
36.5k
update(dns_section_t section, dns_rdataclass_t rdclass) {
1044
36.5k
  if (section == DNS_SECTION_PREREQUISITE) {
1045
8.05k
    return rdclass == dns_rdataclass_any ||
1046
6.94k
           rdclass == dns_rdataclass_none;
1047
8.05k
  }
1048
28.5k
  if (section == DNS_SECTION_UPDATE) {
1049
11.3k
    return rdclass == dns_rdataclass_any;
1050
11.3k
  }
1051
17.1k
  return false;
1052
28.5k
}
1053
1054
static isc_result_t
1055
getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
1056
64.6k
     dns_section_t sectionid, unsigned int options) {
1057
64.6k
  isc_region_t r;
1058
64.6k
  unsigned int count, rdatalen;
1059
64.6k
  dns_name_t *name = NULL;
1060
64.6k
  dns_name_t *found_name = NULL;
1061
64.6k
  dns_rdataset_t *rdataset = NULL;
1062
64.6k
  dns_rdataset_t *found_rdataset = NULL;
1063
64.6k
  dns_rdatalist_t *rdatalist = NULL;
1064
64.6k
  isc_result_t result = ISC_R_SUCCESS;
1065
64.6k
  dns_rdatatype_t rdtype, covers;
1066
64.6k
  dns_rdataclass_t rdclass;
1067
64.6k
  dns_rdata_t *rdata = NULL;
1068
64.6k
  dns_ttl_t ttl;
1069
64.6k
  dns_namelist_t *section = &msg->sections[sectionid];
1070
64.6k
  bool free_name = false, seen_problem = false;
1071
64.6k
  bool free_hashmaps = false;
1072
64.6k
  bool preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0);
1073
64.6k
  bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
1074
64.6k
  bool isedns, issigzero, istsig;
1075
64.6k
  isc_hashmap_t *name_map = NULL;
1076
1077
64.6k
  if (msg->counts[sectionid] > 1) {
1078
13.3k
    isc_hashmap_create(msg->mctx, 1, &name_map);
1079
13.3k
  }
1080
1081
368k
  for (count = 0; count < msg->counts[sectionid]; count++) {
1082
308k
    int recstart = source->current;
1083
308k
    bool skip_name_search, skip_type_search;
1084
1085
308k
    skip_name_search = false;
1086
308k
    skip_type_search = false;
1087
308k
    isedns = false;
1088
308k
    issigzero = false;
1089
308k
    istsig = false;
1090
308k
    found_rdataset = NULL;
1091
1092
308k
    name = NULL;
1093
308k
    dns_message_gettempname(msg, &name);
1094
308k
    free_name = true;
1095
1096
    /*
1097
     * Parse the name out of this packet.
1098
     */
1099
308k
    isc_buffer_remainingregion(source, &r);
1100
308k
    isc_buffer_setactive(source, r.length);
1101
308k
    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
306k
    isc_buffer_remainingregion(source, &r);
1109
306k
    if (r.length < 2 + 2 + 4 + 2) {
1110
175
      CLEANUP(ISC_R_UNEXPECTEDEND);
1111
0
    }
1112
306k
    rdtype = isc_buffer_getuint16(source);
1113
306k
    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
306k
    if (msg->rdclass_set == 0 &&
1120
21.1k
        rdtype != dns_rdatatype_opt &&  /* class is UDP SIZE */
1121
15.8k
        rdtype != dns_rdatatype_tsig && /* class is ANY */
1122
15.0k
        rdtype != dns_rdatatype_tkey)   /* class is undefined */
1123
14.5k
    {
1124
14.5k
      msg->rdclass = rdclass;
1125
14.5k
      msg->rdclass_set = 1;
1126
14.5k
    }
1127
1128
    /*
1129
     * If this class is different than the one in the question
1130
     * section, bail.
1131
     */
1132
306k
    if (msg->opcode != dns_opcode_update &&
1133
269k
        rdtype != dns_rdatatype_tsig &&
1134
264k
        rdtype != dns_rdatatype_opt &&
1135
255k
        rdtype != dns_rdatatype_key &&  /* in a TKEY query */
1136
254k
        rdtype != dns_rdatatype_sig &&  /* SIG(0) */
1137
249k
        rdtype != dns_rdatatype_tkey && /* Win2000 TKEY */
1138
246k
        msg->rdclass != dns_rdataclass_any &&
1139
242k
        msg->rdclass != rdclass)
1140
189k
    {
1141
189k
      DO_ERROR(DNS_R_FORMERR);
1142
189k
    }
1143
1144
    /*
1145
     * If this is not a TKEY query/response then the KEY
1146
     * record's class needs to match.
1147
     */
1148
306k
    if (msg->opcode != dns_opcode_update && !msg->tkey &&
1149
269k
        rdtype == dns_rdatatype_key &&
1150
1.45k
        msg->rdclass != dns_rdataclass_any &&
1151
1.24k
        msg->rdclass != rdclass)
1152
614
    {
1153
614
      DO_ERROR(DNS_R_FORMERR);
1154
614
    }
1155
1156
    /*
1157
     * Special type handling for TSIG, OPT, and TKEY.
1158
     */
1159
306k
    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.71k
      if (sectionid != DNS_SECTION_ADDITIONAL ||
1165
3.78k
          rdclass != dns_rdataclass_any ||
1166
2.40k
          count != msg->counts[sectionid] - 1)
1167
5.68k
      {
1168
5.68k
        DO_ERROR(DNS_R_BADTSIG);
1169
5.68k
      } else {
1170
1.02k
        skip_name_search = true;
1171
1.02k
        skip_type_search = true;
1172
1.02k
        istsig = true;
1173
1.02k
      }
1174
299k
    } 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
9.85k
      if (!dns_name_equal(dns_rootname, name) ||
1181
9.23k
          sectionid != DNS_SECTION_ADDITIONAL ||
1182
5.28k
          msg->opt != NULL)
1183
5.52k
      {
1184
5.52k
        DO_ERROR(DNS_R_FORMERR);
1185
5.52k
      } else {
1186
4.33k
        skip_name_search = true;
1187
4.33k
        skip_type_search = true;
1188
4.33k
        isedns = true;
1189
4.33k
      }
1190
289k
    } 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
2.94k
      dns_section_t tkeysection;
1199
1200
2.94k
      if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0) {
1201
1.99k
        tkeysection = DNS_SECTION_ADDITIONAL;
1202
1.99k
      } else {
1203
957
        tkeysection = DNS_SECTION_ANSWER;
1204
957
      }
1205
2.94k
      if (sectionid != tkeysection &&
1206
2.04k
          sectionid != DNS_SECTION_ANSWER)
1207
1.17k
      {
1208
1.17k
        DO_ERROR(DNS_R_FORMERR);
1209
1.17k
      }
1210
2.94k
    }
1211
1212
    /*
1213
     * ... now get ttl and rdatalen, and check buffer.
1214
     */
1215
306k
    ttl = isc_buffer_getuint32(source);
1216
306k
    rdatalen = isc_buffer_getuint16(source);
1217
306k
    r.length -= (2 + 2 + 4 + 2);
1218
306k
    if (r.length < rdatalen) {
1219
196
      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
306k
    rdata = newrdata(msg);
1229
306k
    if (msg->opcode == dns_opcode_update &&
1230
36.5k
        update(sectionid, rdclass))
1231
2.30k
    {
1232
2.30k
      if (rdatalen != 0) {
1233
3
        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.29k
      rdata->data = (unsigned char *)1;
1243
2.29k
      rdata->length = 0;
1244
2.29k
      rdata->rdclass = rdclass;
1245
2.29k
      rdata->type = rdtype;
1246
2.29k
      rdata->flags = DNS_RDATA_UPDATE;
1247
2.29k
      result = ISC_R_SUCCESS;
1248
304k
    } else if (rdclass == dns_rdataclass_none &&
1249
5.19k
         msg->opcode == dns_opcode_update &&
1250
994
         sectionid == DNS_SECTION_UPDATE)
1251
472
    {
1252
472
      result = getrdata(source, msg, dctx, msg->rdclass,
1253
472
            rdtype, rdatalen, rdata);
1254
303k
    } else {
1255
303k
      result = getrdata(source, msg, dctx, rdclass, rdtype,
1256
303k
            rdatalen, rdata);
1257
303k
    }
1258
306k
    if (result != ISC_R_SUCCESS) {
1259
2.79k
      goto cleanup;
1260
2.79k
    }
1261
303k
    rdata->rdclass = rdclass;
1262
303k
    if (rdtype == dns_rdatatype_rrsig && rdata->flags == 0) {
1263
4.86k
      covers = dns_rdata_covers(rdata);
1264
      /* A signature can only cover a real rdata type */
1265
4.86k
      if (covers == dns_rdatatype_none ||
1266
4.04k
          dns_rdatatype_ismeta(covers) ||
1267
3.67k
          dns_rdatatype_issig(covers))
1268
1.37k
      {
1269
1.37k
        DO_ERROR(DNS_R_FORMERR);
1270
1.37k
      }
1271
298k
    } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1272
5.51k
         rdata->flags == 0)
1273
5.28k
    {
1274
5.28k
      covers = dns_rdata_covers(rdata);
1275
5.28k
      if (covers == dns_rdatatype_none) {
1276
1.77k
        if (sectionid != DNS_SECTION_ADDITIONAL ||
1277
1.22k
            count != msg->counts[sectionid] - 1 ||
1278
517
            !dns_name_equal(name, dns_rootname))
1279
1.27k
        {
1280
1.27k
          DO_ERROR(DNS_R_BADSIG0);
1281
1.27k
        } else {
1282
500
          skip_name_search = true;
1283
500
          skip_type_search = true;
1284
500
          issigzero = true;
1285
500
        }
1286
3.50k
      } else {
1287
3.50k
        covers = dns_rdatatype_none;
1288
3.50k
      }
1289
293k
    } else {
1290
293k
      covers = dns_rdatatype_none;
1291
293k
    }
1292
1293
    /*
1294
     * Check the ownername of NSEC3 records
1295
     */
1296
303k
    if (rdtype == dns_rdatatype_nsec3 &&
1297
5.66k
        !dns_rdata_checkowner(name, msg->rdclass, rdtype, false))
1298
18
    {
1299
18
      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
303k
    if (preserve_order || msg->opcode == dns_opcode_update ||
1308
267k
        skip_name_search)
1309
40.9k
    {
1310
40.9k
      if (!isedns && !istsig && !issigzero) {
1311
35.5k
        ISC_LIST_APPEND(*section, name, link);
1312
35.5k
        free_name = false;
1313
35.5k
      }
1314
262k
    } else {
1315
262k
      if (name_map == NULL) {
1316
7.16k
        result = ISC_R_SUCCESS;
1317
7.16k
        goto skip_name_check;
1318
7.16k
      }
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
255k
      result = isc_hashmap_add(name_map, dns_name_hash(name),
1327
255k
             name_match, name, name,
1328
255k
             (void **)&found_name);
1329
1330
      /*
1331
       * If it is a new name, append to the section.
1332
       */
1333
262k
    skip_name_check:
1334
262k
      switch (result) {
1335
44.1k
      case ISC_R_SUCCESS:
1336
44.1k
        ISC_LIST_APPEND(*section, name, link);
1337
44.1k
        break;
1338
218k
      case ISC_R_EXISTS:
1339
218k
        dns_message_puttempname(msg, &name);
1340
218k
        name = found_name;
1341
218k
        found_name = NULL;
1342
218k
        break;
1343
0
      default:
1344
0
        UNREACHABLE();
1345
262k
      }
1346
262k
      free_name = false;
1347
262k
    }
1348
1349
303k
    rdatalist = newrdatalist(msg);
1350
303k
    rdatalist->type = rdtype;
1351
303k
    rdatalist->covers = covers;
1352
303k
    rdatalist->rdclass = rdclass;
1353
303k
    rdatalist->ttl = ttl;
1354
1355
303k
    dns_message_gettemprdataset(msg, &rdataset);
1356
303k
    dns_rdatalist_tordataset(rdatalist, rdataset);
1357
303k
    dns_rdataset_setownercase(rdataset, name);
1358
303k
    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
303k
    if (isedns || istsig || issigzero) {
1365
      /* Skip adding the rdataset to the tables */
1366
298k
    } else if (preserve_order || msg->opcode == dns_opcode_update ||
1367
262k
         skip_type_search)
1368
35.5k
    {
1369
35.5k
      result = ISC_R_SUCCESS;
1370
1371
35.5k
      ISC_LIST_APPEND(name->list, rdataset, link);
1372
262k
    } else {
1373
      /*
1374
       * If this is a type that can only occur in
1375
       * the question section, fail.
1376
       */
1377
262k
      if (dns_rdatatype_questiononly(rdtype)) {
1378
5.27k
        DO_ERROR(DNS_R_FORMERR);
1379
5.27k
      }
1380
1381
262k
      if (ISC_LIST_EMPTY(name->list)) {
1382
44.1k
        result = ISC_R_SUCCESS;
1383
44.1k
        goto skip_rds_check;
1384
44.1k
      }
1385
1386
218k
      if (name->hashmap == NULL) {
1387
17.2k
        isc_hashmap_create(msg->mctx, 1,
1388
17.2k
               &name->hashmap);
1389
17.2k
        free_hashmaps = true;
1390
1391
17.2k
        INSIST(ISC_LIST_HEAD(name->list) ==
1392
17.2k
               ISC_LIST_TAIL(name->list));
1393
1394
17.2k
        dns_rdataset_t *old_rdataset =
1395
17.2k
          ISC_LIST_HEAD(name->list);
1396
1397
17.2k
        result = isc_hashmap_add(
1398
17.2k
          name->hashmap, rds_hash(old_rdataset),
1399
17.2k
          rds_match, old_rdataset, old_rdataset,
1400
17.2k
          NULL);
1401
1402
17.2k
        INSIST(result == ISC_R_SUCCESS);
1403
17.2k
      }
1404
1405
218k
      result = isc_hashmap_add(
1406
218k
        name->hashmap, rds_hash(rdataset), rds_match,
1407
218k
        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
262k
    skip_rds_check:
1423
262k
      switch (result) {
1424
165k
      case ISC_R_EXISTS:
1425
        /* Free the rdataset we used as the key */
1426
165k
        dns__message_putassociatedrdataset(msg,
1427
165k
                   &rdataset);
1428
165k
        result = ISC_R_SUCCESS;
1429
165k
        rdataset = found_rdataset;
1430
1431
165k
        if (!dns_rdatatype_issingleton(rdtype)) {
1432
153k
          break;
1433
153k
        }
1434
1435
12.1k
        dns_rdatalist_fromrdataset(rdataset,
1436
12.1k
                 &rdatalist);
1437
12.1k
        dns_rdata_t *first =
1438
12.1k
          ISC_LIST_HEAD(rdatalist->rdata);
1439
12.1k
        INSIST(first != NULL);
1440
12.1k
        if (dns_rdata_compare(rdata, first) != 0) {
1441
6.03k
          DO_ERROR(DNS_R_FORMERR);
1442
6.03k
        }
1443
12.1k
        break;
1444
96.7k
      case ISC_R_SUCCESS:
1445
96.7k
        ISC_LIST_APPEND(name->list, rdataset, link);
1446
96.7k
        break;
1447
0
      default:
1448
0
        UNREACHABLE();
1449
262k
      }
1450
262k
    }
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
303k
    if (ttl != rdataset->ttl) {
1461
40.7k
      rdataset->attributes.ttladjusted = true;
1462
40.7k
      if (ttl < rdataset->ttl) {
1463
4.35k
        rdataset->ttl = ttl;
1464
4.35k
      }
1465
40.7k
    }
1466
1467
    /* Append this rdata to the rdataset. */
1468
303k
    dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1469
303k
    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
303k
    if (isedns) {
1480
4.25k
      dns_rcode_t ercode;
1481
1482
4.25k
      msg->opt = rdataset;
1483
4.25k
      ercode = (dns_rcode_t)((msg->opt->ttl &
1484
4.25k
            DNS_MESSAGE_EDNSRCODE_MASK) >>
1485
4.25k
                 20);
1486
4.25k
      msg->rcode |= ercode;
1487
4.25k
      dns_message_puttempname(msg, &name);
1488
4.25k
      free_name = false;
1489
299k
    } else if (issigzero) {
1490
500
      msg->sig0 = rdataset;
1491
500
      msg->sig0name = name;
1492
500
      msg->sigstart = recstart;
1493
500
      free_name = false;
1494
298k
    } else if (istsig) {
1495
627
      msg->tsig = rdataset;
1496
627
      msg->tsigname = name;
1497
627
      msg->sigstart = recstart;
1498
      /*
1499
       * Windows doesn't like TSIG names to be compressed.
1500
       */
1501
627
      msg->tsigname->attributes.nocompress = true;
1502
627
      free_name = false;
1503
298k
    } else if (rdtype == dns_rdatatype_dname &&
1504
3.53k
         sectionid == DNS_SECTION_ANSWER &&
1505
1.85k
         msg->opcode == dns_opcode_query)
1506
531
    {
1507
531
      msg->has_dname = 1;
1508
531
    }
1509
303k
    rdataset = NULL;
1510
1511
303k
    if (seen_problem) {
1512
247k
      if (free_name) {
1513
        /* XXX test coverage */
1514
0
        dns_message_puttempname(msg, &name);
1515
0
      }
1516
247k
      free_name = false;
1517
247k
    }
1518
303k
    INSIST(!free_name);
1519
303k
  }
1520
1521
59.9k
  if (seen_problem) {
1522
9.31k
    result = DNS_R_RECOVERABLE;
1523
9.31k
  }
1524
1525
64.6k
cleanup:
1526
64.6k
  if (rdataset != NULL && rdataset != found_rdataset) {
1527
0
    dns__message_putassociatedrdataset(msg, &rdataset);
1528
0
  }
1529
64.6k
  if (free_name) {
1530
4.73k
    dns_message_puttempname(msg, &name);
1531
4.73k
  }
1532
1533
64.6k
  if (free_hashmaps) {
1534
8.34k
    cleanup_name_hashmaps(section);
1535
8.34k
  }
1536
1537
64.6k
  if (name_map != NULL) {
1538
13.3k
    isc_hashmap_destroy(&name_map);
1539
13.3k
  }
1540
1541
64.6k
  return result;
1542
59.9k
}
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.30k
    return DNS_R_NOTIMP;
1555
16.3k
  } else if (many_questions) {
1556
1.39k
    return DNS_R_FORMERR;
1557
14.9k
  } else if (no_questions && (msg->opcode != dns_opcode_query) &&
1558
6.14k
       (msg->opcode != dns_opcode_status))
1559
5.32k
  {
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
5.32k
    return DNS_R_FORMERR;
1568
9.59k
  } else if (msg->opcode == dns_opcode_notify &&
1569
501
       ((is_query_response && has_answer) || has_auth))
1570
93
  {
1571
93
    return DNS_R_FORMERR;
1572
93
  }
1573
9.50k
  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
14
    return early_check_ret;
1634
14
  }
1635
1636
23.5k
  result = getquestions(source, msg, dctx, options);
1637
1638
23.5k
  if (result == ISC_R_UNEXPECTEDEND && ignore_tc) {
1639
0
    goto truncated;
1640
0
  }
1641
23.5k
  if (result == DNS_R_RECOVERABLE) {
1642
2.20k
    seen_problem = true;
1643
2.20k
    result = ISC_R_SUCCESS;
1644
2.20k
  }
1645
23.5k
  if (result != ISC_R_SUCCESS) {
1646
116
    return result;
1647
116
  }
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.38k
    seen_problem = true;
1656
2.38k
    result = ISC_R_SUCCESS;
1657
2.38k
  }
1658
23.4k
  if (result != ISC_R_SUCCESS) {
1659
2.37k
    return result;
1660
2.37k
  }
1661
1662
21.1k
  result = getsection(source, msg, dctx, DNS_SECTION_AUTHORITY, options);
1663
21.1k
  if (result == ISC_R_UNEXPECTEDEND && ignore_tc) {
1664
0
    goto truncated;
1665
0
  }
1666
21.1k
  if (result == DNS_R_RECOVERABLE) {
1667
3.15k
    seen_problem = true;
1668
3.15k
    result = ISC_R_SUCCESS;
1669
3.15k
  }
1670
21.1k
  if (result != ISC_R_SUCCESS) {
1671
1.04k
    return result;
1672
1.04k
  }
1673
1674
20.0k
  result = getsection(source, msg, dctx, DNS_SECTION_ADDITIONAL, options);
1675
20.0k
  if (result == ISC_R_UNEXPECTEDEND && ignore_tc) {
1676
0
    goto truncated;
1677
0
  }
1678
20.0k
  if (result == DNS_R_RECOVERABLE) {
1679
3.78k
    seen_problem = true;
1680
3.78k
    result = ISC_R_SUCCESS;
1681
3.78k
  }
1682
20.0k
  if (result != ISC_R_SUCCESS) {
1683
1.32k
    return result;
1684
1.32k
  }
1685
1686
18.7k
  isc_buffer_remainingregion(source, &r);
1687
18.7k
  if (r.length != 0) {
1688
2.23k
    isc_log_write(ISC_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MESSAGE,
1689
2.23k
            ISC_LOG_DEBUG(3),
1690
2.23k
            "message has %u byte(s) of trailing garbage",
1691
2.23k
            r.length);
1692
2.23k
  }
1693
1694
18.7k
truncated:
1695
1696
18.7k
  if (result == ISC_R_UNEXPECTEDEND && ignore_tc) {
1697
0
    return DNS_R_RECOVERABLE;
1698
0
  }
1699
18.7k
  if (seen_problem) {
1700
8.16k
    return DNS_R_RECOVERABLE;
1701
8.16k
  }
1702
10.5k
  return ISC_R_SUCCESS;
1703
18.7k
}
1704
1705
isc_result_t
1706
dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1707
8.91k
      isc_buffer_t *buffer) {
1708
8.91k
  isc_region_t r;
1709
1710
8.91k
  REQUIRE(DNS_MESSAGE_VALID(msg));
1711
8.91k
  REQUIRE(buffer != NULL);
1712
8.91k
  REQUIRE(isc_buffer_length(buffer) < 65536);
1713
8.91k
  REQUIRE(msg->buffer == NULL);
1714
8.91k
  REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1715
1716
8.91k
  msg->cctx = cctx;
1717
1718
  /*
1719
   * Erase the contents of this buffer.
1720
   */
1721
8.91k
  isc_buffer_clear(buffer);
1722
1723
  /*
1724
   * Make certain there is enough for at least the header in this
1725
   * buffer.
1726
   */
1727
8.91k
  isc_buffer_availableregion(buffer, &r);
1728
8.91k
  if (r.length < DNS_MESSAGE_HEADERLEN) {
1729
0
    return ISC_R_NOSPACE;
1730
0
  }
1731
1732
8.91k
  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.91k
  isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1740
1741
8.91k
  msg->buffer = buffer;
1742
1743
8.91k
  return ISC_R_SUCCESS;
1744
8.91k
}
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.11k
dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1777
2.11k
  REQUIRE(DNS_MESSAGE_VALID(msg));
1778
2.11k
  REQUIRE(space <= msg->reserved);
1779
1780
2.11k
  msg->reserved -= space;
1781
2.11k
}
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
33.1k
wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1803
33.1k
  int pass_needed;
1804
1805
  /*
1806
   * If we are not rendering class IN, this ordering is bogus.
1807
   */
1808
33.1k
  if (rds->rdclass != dns_rdataclass_in) {
1809
21.1k
    return false;
1810
21.1k
  }
1811
1812
12.0k
  switch (rds->type) {
1813
421
  case dns_rdatatype_a:
1814
679
  case dns_rdatatype_aaaa:
1815
679
    if (preferred_glue == rds->type) {
1816
0
      pass_needed = 4;
1817
679
    } else {
1818
679
      pass_needed = 3;
1819
679
    }
1820
679
    break;
1821
498
  case dns_rdatatype_rrsig:
1822
1.02k
  case dns_rdatatype_dnskey:
1823
1.02k
    pass_needed = 2;
1824
1.02k
    break;
1825
10.3k
  default:
1826
10.3k
    pass_needed = 1;
1827
12.0k
  }
1828
1829
12.0k
  if (pass_needed >= pass) {
1830
4.63k
    return false;
1831
4.63k
  }
1832
1833
7.41k
  return true;
1834
12.0k
}
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.11k
    unsigned int options, unsigned int *countp) {
1840
2.11k
  isc_result_t result;
1841
1842
  /*
1843
   * Shrink the space in the buffer by the reserved amount.
1844
   */
1845
2.11k
  if (target->length - target->used < reserved) {
1846
0
    return ISC_R_NOSPACE;
1847
0
  }
1848
1849
2.11k
  target->length -= reserved;
1850
2.11k
  result = dns_rdataset_towire(rdataset, owner_name, id, cctx, target,
1851
2.11k
             false, options, countp);
1852
2.11k
  target->length += reserved;
1853
1854
2.11k
  return result;
1855
2.11k
}
1856
1857
static void
1858
154
maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) {
1859
154
  if (msg->counts[sectionid] == 0 &&
1860
77
      (sectionid == DNS_SECTION_ANSWER ||
1861
76
       (sectionid == DNS_SECTION_AUTHORITY &&
1862
27
        msg->counts[DNS_SECTION_ANSWER] == 0)))
1863
2
  {
1864
2
    msg->flags &= ~DNS_MESSAGEFLAG_AD;
1865
2
  }
1866
154
}
1867
1868
static void
1869
update_min_section_ttl(dns_message_t *restrict msg,
1870
           const dns_section_t sectionid,
1871
154k
           dns_rdataset_t *restrict rdataset) {
1872
154k
  if (!msg->minttl[sectionid].is_set ||
1873
144k
      rdataset->ttl < msg->minttl[sectionid].ttl)
1874
16.0k
  {
1875
16.0k
    msg->minttl[sectionid].is_set = true;
1876
16.0k
    msg->minttl[sectionid].ttl = rdataset->ttl;
1877
16.0k
  }
1878
154k
}
1879
1880
isc_result_t
1881
dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1882
36.8k
        unsigned int options) {
1883
36.8k
  dns_namelist_t *section = NULL;
1884
36.8k
  dns_name_t *name = NULL;
1885
36.8k
  dns_rdataset_t *rdataset = NULL;
1886
36.8k
  unsigned int count, total;
1887
36.8k
  isc_result_t result;
1888
36.8k
  isc_buffer_t st; /* for rollbacks */
1889
36.8k
  int pass;
1890
36.8k
  bool partial = false;
1891
36.8k
  unsigned int rd_options;
1892
36.8k
  dns_rdatatype_t preferred_glue = 0;
1893
1894
36.8k
  REQUIRE(DNS_MESSAGE_VALID(msg));
1895
36.8k
  REQUIRE(msg->buffer != NULL);
1896
36.8k
  REQUIRE(VALID_NAMED_SECTION(sectionid));
1897
1898
36.8k
  section = &msg->sections[sectionid];
1899
1900
36.8k
  if ((sectionid == DNS_SECTION_ADDITIONAL) &&
1901
8.83k
      (options & DNS_MESSAGERENDER_ORDERED) == 0)
1902
8.83k
  {
1903
8.83k
    if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1904
0
      preferred_glue = dns_rdatatype_a;
1905
0
      pass = 4;
1906
8.83k
    } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1907
0
      preferred_glue = dns_rdatatype_aaaa;
1908
0
      pass = 4;
1909
8.83k
    } else {
1910
8.83k
      pass = 3;
1911
8.83k
    }
1912
28.0k
  } else {
1913
28.0k
    pass = 1;
1914
28.0k
  }
1915
1916
36.8k
  if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0) {
1917
36.8k
    rd_options = 0;
1918
36.8k
  } 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.8k
  if (msg->buffer->length - msg->buffer->used < msg->reserved) {
1926
0
    return ISC_R_NOSPACE;
1927
0
  }
1928
36.8k
  msg->buffer->length -= msg->reserved;
1929
1930
36.8k
  total = 0;
1931
36.8k
  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.8k
  name = ISC_LIST_HEAD(*section);
1939
36.8k
  if (name != NULL) {
1940
11.3k
    rdataset = ISC_LIST_HEAD(name->list);
1941
11.3k
    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
11.3k
  }
1972
1973
44.7k
  do {
1974
44.7k
    name = ISC_LIST_HEAD(*section);
1975
44.7k
    if (name == NULL) {
1976
25.5k
      msg->buffer->length += msg->reserved;
1977
25.5k
      msg->counts[sectionid] += total;
1978
25.5k
      return ISC_R_SUCCESS;
1979
25.5k
    }
1980
1981
162k
    ISC_LIST_FOREACH(*section, n, link) {
1982
206k
      ISC_LIST_FOREACH(n->list, rds, link) {
1983
206k
        if (rds->attributes.rendered) {
1984
43.4k
          continue;
1985
43.4k
        }
1986
1987
162k
        if (((options & DNS_MESSAGERENDER_ORDERED) ==
1988
162k
             0) &&
1989
162k
            (sectionid == DNS_SECTION_ADDITIONAL) &&
1990
33.1k
            wrong_priority(rds, pass, preferred_glue))
1991
7.41k
        {
1992
7.41k
          continue;
1993
7.41k
        }
1994
1995
155k
        st = *(msg->buffer);
1996
1997
155k
        count = 0;
1998
155k
        result = dns_rdataset_towire(
1999
155k
          rds, n, msg->id, msg->cctx, msg->buffer,
2000
155k
          partial, rd_options, &count);
2001
2002
155k
        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
155k
        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
155k
        if (result != ISC_R_SUCCESS) {
2023
154
          INSIST(st.used < 65536);
2024
154
          dns_compress_rollback(
2025
154
            msg->cctx, (uint16_t)st.used);
2026
154
          *(msg->buffer) = st; /* rollback */
2027
154
          msg->buffer->length += msg->reserved;
2028
154
          msg->counts[sectionid] += total;
2029
154
          maybe_clear_ad(msg, sectionid);
2030
154
          return result;
2031
154
        }
2032
2033
        /*
2034
         * If we have rendered non-validated data,
2035
         * ensure that the AD bit is not set.
2036
         */
2037
154k
        if (rds->trust != dns_trust_secure &&
2038
154k
            (sectionid == DNS_SECTION_ANSWER ||
2039
137k
             sectionid == DNS_SECTION_AUTHORITY))
2040
35.1k
        {
2041
35.1k
          msg->flags &= ~DNS_MESSAGEFLAG_AD;
2042
35.1k
        }
2043
154k
        if (OPTOUT(rds)) {
2044
0
          msg->flags &= ~DNS_MESSAGEFLAG_AD;
2045
0
        }
2046
2047
154k
        update_min_section_ttl(msg, sectionid, rds);
2048
2049
154k
        rds->attributes.rendered = true;
2050
154k
      }
2051
162k
    }
2052
19.1k
  } while (--pass != 0);
2053
2054
11.1k
  msg->buffer->length += msg->reserved;
2055
11.1k
  msg->counts[sectionid] += total;
2056
2057
11.1k
  return ISC_R_SUCCESS;
2058
36.8k
}
2059
2060
void
2061
8.76k
dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2062
8.76k
  uint16_t tmp;
2063
8.76k
  isc_region_t r;
2064
2065
8.76k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2066
8.76k
  REQUIRE(msg->buffer != NULL);
2067
8.76k
  REQUIRE(target != NULL);
2068
2069
8.76k
  isc_buffer_availableregion(target, &r);
2070
8.76k
  REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2071
2072
8.76k
  isc_buffer_putuint16(target, msg->id);
2073
2074
8.76k
  tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT) &
2075
8.76k
         DNS_MESSAGE_OPCODE_MASK);
2076
8.76k
  tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2077
8.76k
  tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2078
2079
8.76k
  INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
2080
8.76k
         msg->counts[DNS_SECTION_ANSWER] < 65536 &&
2081
8.76k
         msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2082
8.76k
         msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2083
2084
8.76k
  isc_buffer_putuint16(target, tmp);
2085
8.76k
  isc_buffer_putuint16(target,
2086
8.76k
           (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2087
8.76k
  isc_buffer_putuint16(target, (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2088
8.76k
  isc_buffer_putuint16(target,
2089
8.76k
           (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2090
8.76k
  isc_buffer_putuint16(target,
2091
8.76k
           (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2092
8.76k
}
2093
2094
isc_result_t
2095
8.76k
dns_message_renderend(dns_message_t *msg) {
2096
8.76k
  isc_buffer_t tmpbuf;
2097
8.76k
  isc_region_t r;
2098
8.76k
  int result;
2099
8.76k
  unsigned int count;
2100
2101
8.76k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2102
8.76k
  REQUIRE(msg->buffer != NULL);
2103
2104
8.76k
  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.76k
  if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
2118
2.11k
      (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2119
1.31k
  {
2120
1.31k
    isc_buffer_t *buf;
2121
2122
1.31k
    msgresetnames(msg, DNS_SECTION_ANSWER);
2123
1.31k
    buf = msg->buffer;
2124
1.31k
    dns_message_renderreset(msg);
2125
1.31k
    msg->buffer = buf;
2126
1.31k
    isc_buffer_clear(msg->buffer);
2127
1.31k
    isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2128
1.31k
    dns_compress_rollback(msg->cctx, 0);
2129
1.31k
    result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2130
1.31k
               0);
2131
1.31k
    if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) {
2132
0
      return result;
2133
0
    }
2134
1.31k
  }
2135
2136
  /*
2137
   * If we've got an OPT record, render it.
2138
   */
2139
8.76k
  if (msg->opt != NULL) {
2140
2.11k
    dns_message_renderrelease(msg, msg->opt_reserved);
2141
2.11k
    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.11k
    msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2147
2.11k
    msg->opt->ttl |= (((dns_ttl_t)(msg->rcode) << 20) &
2148
2.11k
          DNS_MESSAGE_EDNSRCODE_MASK);
2149
    /*
2150
     * Render.
2151
     */
2152
2.11k
    count = 0;
2153
2.11k
    result = renderset(msg->opt, dns_rootname, msg->id, msg->cctx,
2154
2.11k
           msg->buffer, msg->reserved, 0, &count);
2155
2.11k
    msg->counts[DNS_SECTION_ADDITIONAL] += count;
2156
2.11k
    if (result != ISC_R_SUCCESS) {
2157
3
      return result;
2158
3
    }
2159
2.11k
  }
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.76k
  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.76k
  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.76k
  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.76k
  isc_buffer_usedregion(msg->buffer, &r);
2249
8.76k
  isc_buffer_init(&tmpbuf, r.base, r.length);
2250
2251
8.76k
  dns_message_renderheader(msg, &tmpbuf);
2252
2253
8.76k
  msg->buffer = NULL; /* forget about this buffer only on success XXX */
2254
2255
8.76k
  return ISC_R_SUCCESS;
2256
8.76k
}
2257
2258
void
2259
1.31k
dns_message_renderreset(dns_message_t *msg) {
2260
  /*
2261
   * Reset the message so that it may be rendered again.
2262
   */
2263
2264
1.31k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2265
1.31k
  REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2266
2267
1.31k
  msg->buffer = NULL;
2268
2269
6.59k
  for (size_t i = 0; i < DNS_SECTION_MAX; i++) {
2270
5.27k
    msg->cursors[i] = NULL;
2271
5.27k
    msg->counts[i] = 0;
2272
5.27k
    MSG_SECTION_FOREACH(msg, i, name) {
2273
1.25k
      ISC_LIST_FOREACH(name->list, rds, link) {
2274
1.25k
        rds->attributes.rendered = false;
2275
1.25k
      }
2276
1.25k
    }
2277
5.27k
  }
2278
1.31k
  if (msg->tsigname != NULL) {
2279
2
    dns_message_puttempname(msg, &msg->tsigname);
2280
2
  }
2281
1.31k
  if (msg->tsig != NULL) {
2282
2
    dns__message_putassociatedrdataset(msg, &msg->tsig);
2283
2
  }
2284
1.31k
  if (msg->sig0name != NULL) {
2285
4
    dns_message_puttempname(msg, &msg->sig0name);
2286
4
  }
2287
1.31k
  if (msg->sig0 != NULL) {
2288
4
    dns__message_putassociatedrdataset(msg, &msg->sig0);
2289
4
  }
2290
1.31k
}
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
430k
dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2406
430k
  dns_fixedname_t *fn = NULL;
2407
2408
430k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2409
430k
  REQUIRE(item != NULL && *item == NULL);
2410
2411
430k
  fn = isc_mempool_get(msg->namepool);
2412
430k
  *item = dns_fixedname_initname(fn);
2413
430k
}
2414
2415
void
2416
231
dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2417
231
  REQUIRE(DNS_MESSAGE_VALID(msg));
2418
231
  REQUIRE(item != NULL && *item == NULL);
2419
2420
231
  *item = newrdata(msg);
2421
231
}
2422
2423
void
2424
425k
dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2425
425k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2426
425k
  REQUIRE(item != NULL && *item == NULL);
2427
2428
425k
  *item = isc_mempool_get(msg->rdspool);
2429
425k
  dns_rdataset_init(*item);
2430
425k
}
2431
2432
void
2433
231
dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2434
231
  REQUIRE(DNS_MESSAGE_VALID(msg));
2435
231
  REQUIRE(item != NULL && *item == NULL);
2436
2437
231
  *item = newrdatalist(msg);
2438
231
}
2439
2440
void
2441
430k
dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) {
2442
430k
  dns_name_t *item = NULL;
2443
2444
430k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2445
430k
  REQUIRE(itemp != NULL && *itemp != NULL);
2446
2447
430k
  item = *itemp;
2448
430k
  *itemp = NULL;
2449
2450
430k
  REQUIRE(!ISC_LINK_LINKED(item, link));
2451
430k
  REQUIRE(ISC_LIST_HEAD(item->list) == NULL);
2452
2453
430k
  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
430k
  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
430k
  isc_mempool_put(msg->namepool, item);
2470
430k
}
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
425k
dns__message_putassociatedrdataset(dns_message_t *msg, dns_rdataset_t **item) {
2483
425k
  dns_rdataset_disassociate(*item);
2484
425k
  dns_message_puttemprdataset(msg, item);
2485
425k
}
2486
2487
void
2488
425k
dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2489
425k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2490
425k
  REQUIRE(item != NULL && *item != NULL);
2491
2492
425k
  REQUIRE(!dns_rdataset_isassociated(*item));
2493
425k
  isc_mempool_put(msg->rdspool, *item);
2494
425k
}
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.6k
dns_message_getopt(dns_message_t *msg) {
2605
  /*
2606
   * Get the OPT record for 'msg'.
2607
   */
2608
2609
17.6k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2610
2611
17.6k
  return msg->opt;
2612
17.6k
}
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.5k
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.5k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2671
17.5k
  REQUIRE(owner == NULL || *owner == NULL);
2672
2673
17.5k
  SET_IF_NOT_NULL(owner, msg->tsigname);
2674
17.5k
  return msg->tsig;
2675
17.5k
}
2676
2677
isc_result_t
2678
270
dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2679
270
  isc_result_t result;
2680
2681
  /*
2682
   * Set the TSIG key for 'msg'
2683
   */
2684
2685
270
  REQUIRE(DNS_MESSAGE_VALID(msg));
2686
2687
270
  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
270
  if (key != NULL) {
2695
270
    REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2696
270
    dns_tsigkey_attach(key, &msg->tsigkey);
2697
270
    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
270
  }
2708
270
  return ISC_R_SUCCESS;
2709
270
}
2710
2711
dns_tsigkey_t *
2712
615
dns_message_gettsigkey(dns_message_t *msg) {
2713
  /*
2714
   * Get the TSIG key for 'msg'
2715
   */
2716
2717
615
  REQUIRE(DNS_MESSAGE_VALID(msg));
2718
2719
615
  return msg->tsigkey;
2720
615
}
2721
2722
void
2723
231
dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2724
231
  dns_rdata_t *rdata = NULL;
2725
231
  dns_rdatalist_t *list = NULL;
2726
231
  dns_rdataset_t *set = NULL;
2727
231
  isc_buffer_t *buf = NULL;
2728
231
  isc_region_t r;
2729
2730
231
  REQUIRE(DNS_MESSAGE_VALID(msg));
2731
231
  REQUIRE(msg->querytsig == NULL);
2732
2733
231
  if (querytsig == NULL) {
2734
0
    return;
2735
0
  }
2736
2737
231
  dns_message_gettemprdata(msg, &rdata);
2738
2739
231
  dns_message_gettemprdatalist(msg, &list);
2740
231
  dns_message_gettemprdataset(msg, &set);
2741
2742
231
  isc_buffer_usedregion(querytsig, &r);
2743
231
  isc_buffer_allocate(msg->mctx, &buf, r.length);
2744
231
  isc_buffer_putmem(buf, r.base, r.length);
2745
231
  isc_buffer_usedregion(buf, &r);
2746
231
  dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2747
231
  dns_message_takebuffer(msg, &buf);
2748
231
  ISC_LIST_APPEND(list->rdata, rdata, link);
2749
231
  dns_rdatalist_tordataset(list, set);
2750
2751
231
  msg->querytsig = set;
2752
231
}
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.5k
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.5k
  REQUIRE(DNS_MESSAGE_VALID(msg));
2784
17.5k
  REQUIRE(owner == NULL || *owner == NULL);
2785
2786
17.5k
  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
67
    if (msg->sig0name == NULL) {
2792
0
      *owner = dns_rootname;
2793
67
    } else {
2794
67
      *owner = msg->sig0name;
2795
67
    }
2796
67
  }
2797
17.5k
  return msg->sig0;
2798
17.5k
}
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
231
dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2865
231
  REQUIRE(DNS_MESSAGE_VALID(msg));
2866
231
  REQUIRE(buffer != NULL);
2867
231
  REQUIRE(ISC_BUFFER_VALID(*buffer));
2868
2869
231
  ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2870
231
  *buffer = NULL;
2871
231
}
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.14k
dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3051
1.14k
  isc_buffer_t msgb;
3052
3053
1.14k
  REQUIRE(DNS_MESSAGE_VALID(msg));
3054
3055
1.14k
  if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL) {
3056
99
    return ISC_R_SUCCESS;
3057
99
  }
3058
3059
1.04k
  INSIST(msg->saved.base != NULL);
3060
1.04k
  isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3061
1.04k
  isc_buffer_add(&msgb, msg->saved.length);
3062
1.04k
  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
615
    if (view != NULL) {
3067
434
      return dns_view_checksig(view, &msgb, msg);
3068
434
    } else {
3069
181
      return dns_tsig_verify(&msgb, msg, NULL, NULL);
3070
181
    }
3071
615
  } 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
73
      result = DNS_R_KEYUNAUTHORIZED;
3098
73
      goto freesig;
3099
73
    }
3100
359
    result = dns_view_simplefind(view, &sig.signer,
3101
359
               dns_rdatatype_key /* SIG(0) */, 0,
3102
359
               0, false, &keyset, NULL);
3103
3104
359
    if (result != ISC_R_SUCCESS) {
3105
242
      result = DNS_R_KEYUNAUTHORIZED;
3106
242
      goto freesig;
3107
242
    } else if (keyset.trust < dns_trust_ultimate) {
3108
0
      result = DNS_R_KEYUNAUTHORIZED;
3109
0
      goto freesig;
3110
0
    }
3111
117
    result = dns_rdataset_first(&keyset);
3112
117
    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
117
    const uint32_t max_key_checks =
3121
117
      view->sig0key_checks_limit > 0
3122
117
        ? view->sig0key_checks_limit
3123
117
        : UINT32_MAX;
3124
117
    const uint32_t max_message_checks =
3125
117
      view->sig0message_checks_limit > 0
3126
117
        ? view->sig0message_checks_limit
3127
117
        : UINT32_MAX;
3128
3129
117
    for (key_checks = 0, message_checks = 0;
3130
233
         result == ISC_R_SUCCESS && key_checks < max_key_checks &&
3131
117
         message_checks < max_message_checks;
3132
117
         key_checks++, result = dns_rdataset_next(&keyset))
3133
117
    {
3134
117
      dns_rdata_t keyrdata = DNS_RDATA_INIT;
3135
117
      dns_rdata_key_t ks;
3136
117
      dst_key_t *key = NULL;
3137
117
      isc_region_t r;
3138
3139
117
      dns_rdataset_current(&keyset, &keyrdata);
3140
117
      dns_rdata_tostruct(&keyrdata, &ks, NULL);
3141
3142
117
      if (sig.algorithm != ks.algorithm ||
3143
105
          (ks.protocol != DNS_KEYPROTO_DNSSEC &&
3144
0
           ks.protocol != DNS_KEYPROTO_ANY))
3145
12
      {
3146
12
        continue;
3147
12
      }
3148
3149
105
      dns_rdata_toregion(&keyrdata, &r);
3150
105
      if (dst_region_computeid(&r) != sig.keyid) {
3151
26
        continue;
3152
26
      }
3153
3154
79
      result = dns_dnssec_keyfromrdata(&sig.signer, &keyrdata,
3155
79
               view->mctx, &key);
3156
79
      if (result != ISC_R_SUCCESS) {
3157
0
        continue;
3158
0
      }
3159
3160
79
      result = dns_dnssec_verifymessage(&msgb, msg, key);
3161
79
      dst_key_free(&key);
3162
79
      if (result == ISC_R_SUCCESS) {
3163
1
        break;
3164
1
      }
3165
78
      message_checks++;
3166
78
    }
3167
117
    if (result == ISC_R_NOMORE) {
3168
116
      result = DNS_R_KEYUNAUTHORIZED;
3169
116
    } 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
117
  }
3188
1.04k
}
3189
3190
#define INDENT(sp)                                                           \
3191
734k
  do {                                                                 \
3192
734k
    unsigned int __i;                                            \
3193
734k
    dns_masterstyle_flags_t __flags = dns_master_styleflags(sp); \
3194
734k
    if ((__flags & DNS_STYLEFLAG_INDENT) == 0ULL &&              \
3195
734k
        (__flags & DNS_STYLEFLAG_YAML) == 0ULL)                  \
3196
734k
    {                                                            \
3197
734k
      break;                                               \
3198
734k
    }                                                            \
3199
734k
    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.4k
        dns_messagetextflag_t flags, isc_buffer_t *target) {
3208
70.4k
  dns_name_t empty_name;
3209
70.4k
  isc_result_t result = ISC_R_SUCCESS;
3210
70.4k
  bool seensoa = false;
3211
70.4k
  size_t saved_count;
3212
70.4k
  dns_masterstyle_flags_t sflags;
3213
3214
70.4k
  REQUIRE(DNS_MESSAGE_VALID(msg));
3215
70.4k
  REQUIRE(target != NULL);
3216
70.4k
  REQUIRE(VALID_NAMED_SECTION(section));
3217
3218
70.4k
  saved_count = msg->indent.count;
3219
3220
70.4k
  if (ISC_LIST_EMPTY(msg->sections[section])) {
3221
49.5k
    goto cleanup;
3222
49.5k
  }
3223
3224
20.8k
  sflags = dns_master_styleflags(style);
3225
3226
20.8k
  INDENT(style);
3227
20.8k
  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.8k
  } else if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3235
20.8k
    ADD_STRING(target, ";; ");
3236
20.8k
    if (msg->opcode != dns_opcode_update) {
3237
17.9k
      ADD_STRING(target, sectiontext[section]);
3238
17.9k
    } else {
3239
2.84k
      ADD_STRING(target, updsectiontext[section]);
3240
2.84k
    }
3241
20.8k
    ADD_STRING(target, " SECTION:\n");
3242
20.8k
  }
3243
3244
20.8k
  dns_name_init(&empty_name);
3245
20.8k
  if (ISC_LIST_EMPTY(msg->sections[section])) {
3246
0
    goto cleanup;
3247
0
  }
3248
20.8k
  bool has_yaml = (sflags & DNS_STYLEFLAG_YAML) != 0;
3249
20.8k
  msg->indent.count += has_yaml;
3250
3251
190k
  MSG_SECTION_FOREACH(msg, section, name) {
3252
239k
    ISC_LIST_FOREACH(name->list, rds, link) {
3253
239k
      if (section == DNS_SECTION_ANSWER &&
3254
34.3k
          rds->type == dns_rdatatype_soa)
3255
804
      {
3256
804
        if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3257
0
        {
3258
0
          continue;
3259
0
        }
3260
804
        if (seensoa &&
3261
678
            (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3262
0
        {
3263
0
          continue;
3264
0
        }
3265
804
        seensoa = true;
3266
804
      }
3267
239k
      if (section == DNS_SECTION_QUESTION) {
3268
118k
        INDENT(style);
3269
118k
        if ((sflags & DNS_STYLEFLAG_YAML) == 0) {
3270
118k
          ADD_STRING(target, ";");
3271
118k
        }
3272
118k
        result = dns_master_questiontotext(
3273
118k
          name, rds, style, target);
3274
120k
      } else {
3275
120k
        result = dns_master_rdatasettotext(
3276
120k
          name, rds, style, &msg->indent, target);
3277
120k
      }
3278
239k
      if (result != ISC_R_SUCCESS) {
3279
11
        goto cleanup;
3280
11
      }
3281
239k
    }
3282
190k
  }
3283
20.8k
  msg->indent.count -= has_yaml;
3284
3285
20.8k
  if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3286
20.8k
      (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0 &&
3287
20.8k
      (sflags & DNS_STYLEFLAG_YAML) == 0)
3288
20.8k
  {
3289
20.8k
    INDENT(style);
3290
20.8k
    ADD_STRING(target, "\n");
3291
20.8k
  }
3292
3293
70.4k
cleanup:
3294
70.4k
  msg->indent.count = saved_count;
3295
70.4k
  return result;
3296
20.8k
}
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
21.3k
  for (i = 0; i < addrbytes; i++) {
3327
9.24k
    addr[i] = isc_buffer_getuint8(ecsbuf);
3328
9.24k
  }
3329
3330
12.1k
  switch (family) {
3331
4.58k
  case 0:
3332
4.58k
    if (addrlen != 0U || scopelen != 0U) {
3333
0
      return DNS_R_OPTERR;
3334
0
    }
3335
4.58k
    strlcpy(addr_text, "0", sizeof(addr_text));
3336
4.58k
    break;
3337
2.20k
  case 1:
3338
2.20k
    if (addrlen > 32 || scopelen > 32) {
3339
0
      return DNS_R_OPTERR;
3340
0
    }
3341
2.20k
    inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
3342
2.20k
    break;
3343
5.35k
  case 2:
3344
5.35k
    if (addrlen > 128 || scopelen > 128) {
3345
0
      return DNS_R_OPTERR;
3346
0
    }
3347
5.35k
    inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
3348
5.35k
    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.30k
     const dns_master_style_t *style, isc_buffer_t *target) {
3367
3.30k
  char buf[sizeof("18446744073709551615")]; /* 2^64-1 */
3368
3.30k
  isc_result_t result = ISC_R_SUCCESS;
3369
3.30k
  uint32_t u;
3370
3.30k
  uint64_t q;
3371
3.30k
  const char *sep1 = " ", *sep2 = ", ";
3372
3.30k
  size_t count = msg->indent.count;
3373
3.30k
  bool yaml = false;
3374
3375
3.30k
  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.30k
  u = isc_buffer_getuint16(optbuf);
3382
3.30k
  ADD_STRING(target, sep1);
3383
3.30k
  INDENT(style);
3384
3.30k
  if (yaml) {
3385
0
    ADD_STRING(target, "LLQ-VERSION: ");
3386
3.30k
  } else {
3387
3.30k
    ADD_STRING(target, "Version: ");
3388
3.30k
  }
3389
3.30k
  snprintf(buf, sizeof(buf), "%u", u);
3390
3.30k
  ADD_STRING(target, buf);
3391
3392
3.30k
  u = isc_buffer_getuint16(optbuf);
3393
3.30k
  ADD_STRING(target, sep2);
3394
3.30k
  INDENT(style);
3395
3.30k
  if (yaml) {
3396
0
    ADD_STRING(target, "LLQ-OPCODE: ");
3397
3.30k
  } else {
3398
3.30k
    ADD_STRING(target, "Opcode: ");
3399
3.30k
  }
3400
3.30k
  snprintf(buf, sizeof(buf), "%u", u);
3401
3.30k
  ADD_STRING(target, buf);
3402
3403
3.30k
  u = isc_buffer_getuint16(optbuf);
3404
3.30k
  ADD_STRING(target, sep2);
3405
3.30k
  INDENT(style);
3406
3.30k
  if (yaml) {
3407
0
    ADD_STRING(target, "LLQ-ERROR: ");
3408
3.30k
  } else {
3409
3.30k
    ADD_STRING(target, "Error: ");
3410
3.30k
  }
3411
3.30k
  snprintf(buf, sizeof(buf), "%u", u);
3412
3.30k
  ADD_STRING(target, buf);
3413
3414
3.30k
  q = isc_buffer_getuint32(optbuf);
3415
3.30k
  q <<= 32;
3416
3.30k
  q |= isc_buffer_getuint32(optbuf);
3417
3.30k
  ADD_STRING(target, sep2);
3418
3.30k
  INDENT(style);
3419
3.30k
  if (yaml) {
3420
0
    ADD_STRING(target, "LLQ-ID: ");
3421
3.30k
  } else {
3422
3.30k
    ADD_STRING(target, "Identifier: ");
3423
3.30k
  }
3424
3.30k
  snprintf(buf, sizeof(buf), "%" PRIu64, q);
3425
3.30k
  ADD_STRING(target, buf);
3426
3427
3.30k
  u = isc_buffer_getuint32(optbuf);
3428
3.30k
  ADD_STRING(target, sep2);
3429
3.30k
  INDENT(style);
3430
3.30k
  if (yaml) {
3431
0
    ADD_STRING(target, "LLQ-LEASE: ");
3432
3.30k
  } else {
3433
3.30k
    ADD_STRING(target, "Lifetime: ");
3434
3.30k
  }
3435
3.30k
  snprintf(buf, sizeof(buf), "%u", u);
3436
3.30k
  ADD_STRING(target, buf);
3437
3438
3.30k
cleanup:
3439
3.30k
  msg->indent.count = count;
3440
3.30k
  return result;
3441
3.30k
}
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.73k
render_nameopt(isc_buffer_t *optbuf, bool yaml, isc_buffer_t *target) {
3467
2.73k
  dns_decompress_t dctx = DNS_DECOMPRESS_NEVER;
3468
2.73k
  dns_fixedname_t fixed;
3469
2.73k
  dns_name_t *name = dns_fixedname_initname(&fixed);
3470
2.73k
  char namebuf[DNS_NAME_FORMATSIZE];
3471
2.73k
  isc_result_t result;
3472
3473
2.73k
  result = dns_name_fromwire(name, optbuf, dctx, NULL);
3474
2.73k
  if (result == ISC_R_SUCCESS && isc_buffer_activelength(optbuf) == 0) {
3475
1.73k
    dns_name_format(name, namebuf, sizeof(namebuf));
3476
1.73k
    ADD_STRING(target, " \"");
3477
1.73k
    if (yaml) {
3478
0
      PUT_YAMLSTR(target, (unsigned char *)namebuf,
3479
0
            strlen(namebuf), false);
3480
1.73k
    } else {
3481
1.73k
      ADD_STRING(target, namebuf);
3482
1.73k
    }
3483
1.73k
    ADD_STRING(target, "\"");
3484
1.73k
    return result;
3485
1.73k
  }
3486
1.00k
  result = ISC_R_FAILURE;
3487
1.00k
cleanup:
3488
1.00k
  return result;
3489
1.00k
}
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
31.8k
       const dns_master_style_t *style, isc_buffer_t *target) {
3515
31.8k
  isc_result_t result = ISC_R_SUCCESS;
3516
31.8k
  unsigned int labels = isc_buffer_getuint8(optbuf);
3517
31.8k
  unsigned int type = isc_buffer_getuint8(optbuf);
3518
31.8k
  char buf[sizeof("4000000000")];
3519
31.8k
  char namebuf[DNS_NAME_FORMATSIZE];
3520
31.8k
  dns_name_t *name = ISC_LIST_HEAD(msg->sections[DNS_SECTION_QUESTION]);
3521
31.8k
  dns_name_t suffix = DNS_NAME_INITEMPTY;
3522
31.8k
  bool yaml = false, rawmode = false;
3523
31.8k
  const char *sep1 = " ", *sep2 = ", ";
3524
3525
31.8k
  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
31.8k
  ADD_STRING(target, sep1);
3532
3533
31.8k
  if (msg->counts[DNS_SECTION_QUESTION] != 1 || name == NULL ||
3534
2.94k
      dns_name_countlabels(name) < labels + 1)
3535
31.0k
  {
3536
31.0k
    rawmode = true;
3537
31.0k
    INDENT(style);
3538
31.0k
    ADD_STRING(target, "LABELS: ");
3539
31.0k
    snprintf(buf, sizeof(buf), "%u", labels);
3540
31.0k
    ADD_STRING(target, buf);
3541
31.0k
  } else {
3542
762
    dns_name_split(name, labels + 1, NULL, &suffix);
3543
762
    dns_name_format(&suffix, namebuf, sizeof(namebuf));
3544
3545
762
    INDENT(style);
3546
762
    ADD_STRING(target, "ZONE: ");
3547
762
    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
762
    } else {
3553
762
      ADD_STRING(target, namebuf);
3554
762
    }
3555
762
  }
3556
31.8k
  ADD_STRING(target, sep2);
3557
3558
31.8k
  if (!rawmode && type == 0 && isc_buffer_remaininglength(optbuf) == 4) {
3559
92
    uint32_t serial = isc_buffer_getuint32(optbuf);
3560
92
    INDENT(style);
3561
92
    ADD_STRING(target, "SOA-SERIAL: ");
3562
92
    snprintf(buf, sizeof(buf), "%u", serial);
3563
92
    ADD_STRING(target, buf);
3564
31.7k
  } else {
3565
31.7k
    size_t len = isc_buffer_remaininglength(optbuf);
3566
31.7k
    unsigned char *data = isc_buffer_current(optbuf);
3567
31.7k
    INDENT(style);
3568
31.7k
    ADD_STRING(target, "TYPE: ");
3569
31.7k
    snprintf(buf, sizeof(buf), "%u", type);
3570
31.7k
    ADD_STRING(target, buf);
3571
31.7k
    ADD_STRING(target, sep2);
3572
31.7k
    INDENT(style);
3573
31.7k
    ADD_STRING(target, "VALUE: ");
3574
276M
    for (size_t i = 0; i < len; i++) {
3575
276M
      snprintf(buf, sizeof(buf), "%02x", data[i]);
3576
276M
      ADD_STRING(target, buf);
3577
276M
    }
3578
31.7k
    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
31.7k
    } else {
3585
31.7k
      ADD_STRING(target, " (\"");
3586
276M
      for (size_t i = 0; i < len; i++) {
3587
276M
        if (isprint(data[i])) {
3588
21.2M
          if (isc_buffer_availablelength(target) <
3589
21.2M
              1)
3590
0
          {
3591
0
            CLEANUP(ISC_R_NOSPACE);
3592
0
          }
3593
21.2M
          isc_buffer_putmem(target, &data[i], 1);
3594
255M
        } else {
3595
255M
          ADD_STRING(target, ".");
3596
255M
        }
3597
276M
      }
3598
31.7k
      ADD_STRING(target, "\")");
3599
31.7k
    }
3600
31.7k
    isc_buffer_forward(optbuf, len);
3601
31.7k
  }
3602
31.8k
cleanup:
3603
31.8k
  return result;
3604
31.8k
}
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.8k
        isc_buffer_t *target) {
4046
52.8k
  dns_rdataset_t *ps = NULL;
4047
52.8k
  const dns_name_t *name = NULL;
4048
52.8k
  isc_result_t result;
4049
52.8k
  char buf[sizeof(" (65000 bytes)")];
4050
52.8k
  uint32_t mbz;
4051
52.8k
  dns_rdata_t rdata;
4052
52.8k
  isc_buffer_t optbuf;
4053
52.8k
  uint16_t optcode, optlen;
4054
52.8k
  unsigned char *optdata = NULL;
4055
52.8k
  isc_buffer_t ecsbuf;
4056
4057
52.8k
  REQUIRE(DNS_MESSAGE_VALID(msg));
4058
52.8k
  REQUIRE(target != NULL);
4059
52.8k
  REQUIRE(VALID_NAMED_PSEUDOSECTION(section));
4060
4061
52.8k
  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.8k
  switch (section) {
4067
17.6k
  case DNS_PSEUDOSECTION_OPT:
4068
17.6k
    ps = dns_message_getopt(msg);
4069
17.6k
    if (ps == NULL) {
4070
13.3k
      return ISC_R_SUCCESS;
4071
13.3k
    }
4072
4.23k
    if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
4073
4.23k
      INDENT(style);
4074
4.23k
      ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
4075
4.23k
    }
4076
4077
4.23k
    INDENT(style);
4078
4.23k
    ADD_STRING(target, "; EDNS: version: ");
4079
4.23k
    snprintf(buf, sizeof(buf), "%u",
4080
4.23k
       (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
4081
4.23k
    ADD_STRING(target, buf);
4082
4.23k
    ADD_STRING(target, ", flags:");
4083
4.23k
    if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0) {
4084
1.04k
      ADD_STRING(target, " do");
4085
1.04k
    }
4086
4.23k
    if ((ps->ttl & DNS_MESSAGEEXTFLAG_CO) != 0) {
4087
1.06k
      ADD_STRING(target, " co");
4088
1.06k
    }
4089
4.23k
    mbz = ps->ttl & 0xffff;
4090
    /* Exclude Known Flags. */
4091
4.23k
    mbz &= ~(DNS_MESSAGEEXTFLAG_DO | DNS_MESSAGEEXTFLAG_CO);
4092
4.23k
    if (mbz != 0) {
4093
3.36k
      ADD_STRING(target, "; MBZ: ");
4094
3.36k
      snprintf(buf, sizeof(buf), "0x%.4x", mbz);
4095
3.36k
      ADD_STRING(target, buf);
4096
3.36k
      ADD_STRING(target, ", udp: ");
4097
3.36k
    } else {
4098
869
      ADD_STRING(target, "; udp: ");
4099
869
    }
4100
4.23k
    snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
4101
4.23k
    ADD_STRING(target, buf);
4102
4103
4.23k
    result = dns_rdataset_first(ps);
4104
4.23k
    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.23k
    dns_rdata_init(&rdata);
4116
4.23k
    dns_rdataset_current(ps, &rdata);
4117
4118
4.23k
    isc_buffer_init(&optbuf, rdata.data, rdata.length);
4119
4.23k
    isc_buffer_add(&optbuf, rdata.length);
4120
399k
    while (isc_buffer_remaininglength(&optbuf) != 0) {
4121
395k
      const char *option_name = NULL;
4122
4123
395k
      INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
4124
395k
      optcode = isc_buffer_getuint16(&optbuf);
4125
395k
      optlen = isc_buffer_getuint16(&optbuf);
4126
4127
395k
      INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
4128
4129
395k
      INDENT(style);
4130
395k
      ADD_STRING(target, "; ");
4131
395k
      if (optcode < ARRAY_SIZE(option_names)) {
4132
315k
        option_name = option_names[optcode];
4133
315k
      }
4134
395k
      if (option_name != NULL) {
4135
110k
        ADD_STRING(target, option_names[optcode])
4136
284k
      } else {
4137
284k
        snprintf(buf, sizeof(buf), "OPT=%u", optcode);
4138
284k
        ADD_STRING(target, buf);
4139
284k
      }
4140
395k
      ADD_STRING(target, ":");
4141
4142
395k
      switch (optcode) {
4143
3.30k
      case DNS_OPT_LLQ:
4144
3.30k
        if (optlen == 18U) {
4145
3.30k
          RETERR(render_llq(&optbuf, msg, style,
4146
3.30k
                target));
4147
3.30k
          ADD_STRING(target, "\n");
4148
3.30k
          continue;
4149
3.30k
        }
4150
0
        break;
4151
10.6k
      case DNS_OPT_UL:
4152
10.6k
        if (optlen == 4U || optlen == 8U) {
4153
10.6k
          uint32_t secs, key = 0;
4154
10.6k
          secs = isc_buffer_getuint32(&optbuf);
4155
10.6k
          snprintf(buf, sizeof(buf), " %u", secs);
4156
10.6k
          ADD_STRING(target, buf);
4157
10.6k
          if (optlen == 8U) {
4158
5.22k
            key = isc_buffer_getuint32(
4159
5.22k
              &optbuf);
4160
5.22k
            snprintf(buf, sizeof(buf),
4161
5.22k
               "/%u", key);
4162
5.22k
            ADD_STRING(target, buf);
4163
5.22k
          }
4164
10.6k
          ADD_STRING(target, " (");
4165
10.6k
          CHECK(dns_ttl_totext(secs, true, true,
4166
10.6k
                   target));
4167
10.6k
          if (optlen == 8U) {
4168
5.22k
            ADD_STRING(target, "/");
4169
5.22k
            CHECK(dns_ttl_totext(key, true,
4170
5.22k
                     true,
4171
5.22k
                     target));
4172
5.22k
          }
4173
10.6k
          ADD_STRING(target, ")\n");
4174
10.6k
          continue;
4175
10.6k
        }
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.9k
      case DNS_OPT_EXPIRE:
4193
15.9k
        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
5.00k
        break;
4205
5.00k
      case DNS_OPT_TCP_KEEPALIVE:
4206
2.87k
        if (optlen == 2) {
4207
2.00k
          unsigned int dsecs;
4208
2.00k
          dsecs = isc_buffer_getuint16(&optbuf);
4209
2.00k
          snprintf(buf, sizeof(buf), " %u.%u",
4210
2.00k
             dsecs / 10U, dsecs % 10U);
4211
2.00k
          ADD_STRING(target, buf);
4212
2.00k
          ADD_STRING(target, " secs\n");
4213
2.00k
          continue;
4214
2.00k
        }
4215
873
        break;
4216
7.93k
      case DNS_OPT_PAD:
4217
7.93k
        if (optlen > 0U) {
4218
2.39k
          snprintf(buf, sizeof(buf),
4219
2.39k
             " (%u bytes)", optlen);
4220
2.39k
          ADD_STRING(target, buf);
4221
2.39k
          isc_buffer_forward(&optbuf, optlen);
4222
2.39k
        }
4223
7.93k
        ADD_STRING(target, "\n");
4224
7.93k
        continue;
4225
2.50k
      case DNS_OPT_CHAIN:
4226
4.02k
      case DNS_OPT_REPORT_CHANNEL:
4227
4.02k
        if (optlen > 0U) {
4228
2.73k
          isc_buffer_t sb = optbuf;
4229
2.73k
          isc_buffer_setactive(&optbuf, optlen);
4230
2.73k
          result = render_nameopt(&optbuf, false,
4231
2.73k
                target);
4232
2.73k
          if (result == ISC_R_SUCCESS) {
4233
1.73k
            ADD_STRING(target, "\n");
4234
1.73k
            continue;
4235
1.73k
          }
4236
1.00k
          optbuf = sb;
4237
1.00k
        }
4238
2.29k
        ADD_STRING(target, "\n");
4239
2.29k
        break;
4240
1.60k
      case DNS_OPT_KEY_TAG:
4241
1.60k
        if (optlen > 0U && (optlen % 2U) == 0U) {
4242
1.60k
          const char *sep = "";
4243
15.7k
          while (optlen > 0U) {
4244
14.1k
            uint16_t id =
4245
14.1k
              isc_buffer_getuint16(
4246
14.1k
                &optbuf);
4247
14.1k
            snprintf(buf, sizeof(buf),
4248
14.1k
               "%s %u", sep, id);
4249
14.1k
            ADD_STRING(target, buf);
4250
14.1k
            sep = ",";
4251
14.1k
            optlen -= 2;
4252
14.1k
          }
4253
1.60k
          ADD_STRING(target, "\n");
4254
1.60k
          continue;
4255
1.60k
        }
4256
0
        break;
4257
6.63k
      case DNS_OPT_EDE:
4258
6.63k
        if (optlen >= 2U) {
4259
6.63k
          uint16_t ede;
4260
6.63k
          ede = isc_buffer_getuint16(&optbuf);
4261
6.63k
          snprintf(buf, sizeof(buf), " %u", ede);
4262
6.63k
          ADD_STRING(target, buf);
4263
6.63k
          if (ede < ARRAY_SIZE(edetext)) {
4264
2.09k
            ADD_STRING(target, " (");
4265
2.09k
            ADD_STRING(target,
4266
2.09k
                 edetext[ede]);
4267
2.09k
            ADD_STRING(target, ")");
4268
2.09k
          }
4269
6.63k
          optlen -= 2;
4270
6.63k
          if (optlen != 0) {
4271
4.55k
            ADD_STRING(target, ":");
4272
4.55k
          }
4273
6.63k
        } 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
6.63k
        break;
4286
6.63k
      case DNS_OPT_CLIENT_TAG:
4287
1.12k
      case DNS_OPT_SERVER_TAG:
4288
1.12k
        if (optlen == 2U) {
4289
1.12k
          uint16_t id =
4290
1.12k
            isc_buffer_getuint16(&optbuf);
4291
1.12k
          snprintf(buf, sizeof(buf), " %u\n", id);
4292
1.12k
          ADD_STRING(target, buf);
4293
1.12k
          continue;
4294
1.12k
        }
4295
0
        break;
4296
39.1k
      case DNS_OPT_ZONEVERSION:
4297
39.1k
        if (optlen >= 2U) {
4298
31.8k
          isc_buffer_t zonebuf = optbuf;
4299
31.8k
          isc_buffer_setactive(&zonebuf, optlen);
4300
31.8k
          CHECK(render_zoneversion(
4301
31.8k
            msg, &zonebuf, style, target));
4302
31.8k
          ADD_STRING(target, "\n");
4303
31.8k
          isc_buffer_forward(&optbuf, optlen);
4304
31.8k
          continue;
4305
31.8k
        }
4306
7.31k
        break;
4307
290k
      default:
4308
290k
        break;
4309
395k
      }
4310
4311
312k
      if (optlen != 0) {
4312
50.6k
        int i;
4313
50.6k
        bool utf8ok = false;
4314
4315
50.6k
        ADD_STRING(target, " ");
4316
4317
50.6k
        optdata = isc_buffer_current(&optbuf);
4318
50.6k
        if (optcode == DNS_OPT_EDE) {
4319
4.55k
          utf8ok = isc_utf8_valid(optdata,
4320
4.55k
                optlen);
4321
4.55k
        }
4322
50.6k
        if (!utf8ok) {
4323
2.17M
          for (i = 0; i < optlen; i++) {
4324
2.13M
            const char *sep;
4325
2.13M
            switch (optcode) {
4326
10.4k
            case DNS_OPT_COOKIE:
4327
10.4k
              sep = "";
4328
10.4k
              break;
4329
2.12M
            default:
4330
2.12M
              sep = " ";
4331
2.12M
              break;
4332
2.13M
            }
4333
2.13M
            snprintf(buf, sizeof(buf),
4334
2.13M
               "%02x%s", optdata[i],
4335
2.13M
               sep);
4336
2.13M
            ADD_STRING(target, buf);
4337
2.13M
          }
4338
46.1k
        }
4339
4340
50.6k
        isc_buffer_forward(&optbuf, optlen);
4341
4342
50.6k
        if (optcode == DNS_OPT_COOKIE) {
4343
          /*
4344
           * Valid server cookie?
4345
           */
4346
899
          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
899
          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
899
          if (msg->cc_bad) {
4361
0
            ADD_STRING(target, " (bad)");
4362
0
          }
4363
899
          ADD_STRING(target, "\n");
4364
899
          continue;
4365
899
        }
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
45.2k
          ADD_STRING(target, "(\"");
4378
45.2k
        } else {
4379
4.55k
          ADD_STRING(target, "(");
4380
4.55k
        }
4381
49.7k
        if (isc_buffer_availablelength(target) < optlen)
4382
0
        {
4383
0
          return ISC_R_NOSPACE;
4384
0
        }
4385
2.19M
        for (i = 0; i < optlen; i++) {
4386
2.14M
          if (isprint(optdata[i]) ||
4387
1.97M
              (utf8ok && optdata[i] > 127))
4388
176k
          {
4389
176k
            isc_buffer_putmem(
4390
176k
              target, &optdata[i], 1);
4391
1.96M
          } else {
4392
1.96M
            isc_buffer_putstr(target, ".");
4393
1.96M
          }
4394
2.14M
        }
4395
49.7k
        if (optcode != DNS_OPT_EDE) {
4396
45.2k
          ADD_STRING(target, "\")");
4397
45.2k
        } else {
4398
4.55k
          ADD_STRING(target, ")");
4399
4.55k
        }
4400
49.7k
      }
4401
311k
      ADD_STRING(target, "\n");
4402
311k
    }
4403
4.23k
    return ISC_R_SUCCESS;
4404
17.5k
  case DNS_PSEUDOSECTION_TSIG:
4405
17.5k
    ps = dns_message_gettsig(msg, &name);
4406
17.5k
    if (ps == NULL) {
4407
17.5k
      return ISC_R_SUCCESS;
4408
17.5k
    }
4409
43
    INDENT(style);
4410
43
    if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
4411
43
      ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
4412
43
    }
4413
43
    result = dns_master_rdatasettotext(name, ps, style,
4414
43
               &msg->indent, target);
4415
43
    if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
4416
43
        (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4417
43
    {
4418
43
      ADD_STRING(target, "\n");
4419
43
    }
4420
43
    return result;
4421
17.5k
  case DNS_PSEUDOSECTION_SIG0:
4422
17.5k
    ps = dns_message_getsig0(msg, &name);
4423
17.5k
    if (ps == NULL) {
4424
17.5k
      return ISC_R_SUCCESS;
4425
17.5k
    }
4426
67
    INDENT(style);
4427
67
    if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
4428
67
      ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
4429
67
    }
4430
67
    result = dns_master_rdatasettotext(name, ps, style,
4431
67
               &msg->indent, target);
4432
67
    if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
4433
67
        (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
4434
67
    {
4435
67
      ADD_STRING(target, "\n");
4436
67
    }
4437
67
    return result;
4438
0
  default:
4439
0
    break;
4440
52.8k
  }
4441
0
  result = ISC_R_UNEXPECTED;
4442
1
cleanup:
4443
1
  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.6k
       dns_messagetextflag_t flags, isc_buffer_t *target) {
4449
17.6k
  char buf[sizeof("1234567890")];
4450
17.6k
  isc_result_t result = ISC_R_SUCCESS;
4451
4452
17.6k
  REQUIRE(DNS_MESSAGE_VALID(msg));
4453
17.6k
  REQUIRE(target != NULL);
4454
4455
17.6k
  if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) != 0) {
4456
0
    return ISC_R_SUCCESS;
4457
0
  }
4458
4459
17.6k
  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.6k
  } else {
4545
17.6k
    INDENT(style);
4546
17.6k
    ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
4547
17.6k
    ADD_STRING(target, opcodetext[msg->opcode]);
4548
17.6k
    ADD_STRING(target, ", status: ");
4549
17.6k
    RETERR(dns_rcode_totext(msg->rcode, target));
4550
17.6k
    ADD_STRING(target, ", id: ");
4551
17.6k
    snprintf(buf, sizeof(buf), "%6u", msg->id);
4552
17.6k
    ADD_STRING(target, buf);
4553
17.6k
    ADD_STRING(target, "\n");
4554
17.6k
    INDENT(style);
4555
17.6k
    ADD_STRING(target, ";; flags:");
4556
17.6k
    if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
4557
5.84k
      ADD_STRING(target, " qr");
4558
5.84k
    }
4559
17.6k
    if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
4560
6.97k
      ADD_STRING(target, " aa");
4561
6.97k
    }
4562
17.6k
    if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
4563
8.76k
      ADD_STRING(target, " tc");
4564
8.76k
    }
4565
17.6k
    if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
4566
7.16k
      ADD_STRING(target, " rd");
4567
7.16k
    }
4568
17.6k
    if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
4569
3.47k
      ADD_STRING(target, " ra");
4570
3.47k
    }
4571
17.6k
    if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
4572
4.74k
      ADD_STRING(target, " ad");
4573
4.74k
    }
4574
17.6k
    if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
4575
6.56k
      ADD_STRING(target, " cd");
4576
6.56k
    }
4577
    /*
4578
     * The final unnamed flag must be zero.
4579
     */
4580
17.6k
    if ((msg->flags & 0x0040U) != 0) {
4581
4.51k
      INDENT(style);
4582
4.51k
      ADD_STRING(target, "; MBZ: 0x4");
4583
4.51k
    }
4584
17.6k
    if (msg->opcode != dns_opcode_update) {
4585
15.3k
      INDENT(style);
4586
15.3k
      ADD_STRING(target, "; QUESTION: ");
4587
15.3k
    } else {
4588
2.24k
      INDENT(style);
4589
2.24k
      ADD_STRING(target, "; ZONE: ");
4590
2.24k
    }
4591
17.6k
    snprintf(buf, sizeof(buf), "%1u",
4592
17.6k
       msg->counts[DNS_SECTION_QUESTION]);
4593
17.6k
    ADD_STRING(target, buf);
4594
17.6k
    if (msg->opcode != dns_opcode_update) {
4595
15.3k
      ADD_STRING(target, ", ANSWER: ");
4596
15.3k
    } else {
4597
2.24k
      ADD_STRING(target, ", PREREQ: ");
4598
2.24k
    }
4599
17.6k
    snprintf(buf, sizeof(buf), "%1u",
4600
17.6k
       msg->counts[DNS_SECTION_ANSWER]);
4601
17.6k
    ADD_STRING(target, buf);
4602
17.6k
    if (msg->opcode != dns_opcode_update) {
4603
15.3k
      ADD_STRING(target, ", AUTHORITY: ");
4604
15.3k
    } else {
4605
2.24k
      ADD_STRING(target, ", UPDATE: ");
4606
2.24k
    }
4607
17.6k
    snprintf(buf, sizeof(buf), "%1u",
4608
17.6k
       msg->counts[DNS_SECTION_AUTHORITY]);
4609
17.6k
    ADD_STRING(target, buf);
4610
17.6k
    ADD_STRING(target, ", ADDITIONAL: ");
4611
17.6k
    snprintf(buf, sizeof(buf), "%1u",
4612
17.6k
       msg->counts[DNS_SECTION_ADDITIONAL]);
4613
17.6k
    ADD_STRING(target, buf);
4614
17.6k
    ADD_STRING(target, "\n");
4615
17.6k
  }
4616
4617
17.6k
cleanup:
4618
17.6k
  return result;
4619
17.6k
}
4620
4621
isc_result_t
4622
dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
4623
17.6k
       dns_messagetextflag_t flags, isc_buffer_t *target) {
4624
17.6k
  REQUIRE(DNS_MESSAGE_VALID(msg));
4625
17.6k
  REQUIRE(target != NULL);
4626
4627
17.6k
  RETERR(dns_message_headertotext(msg, style, flags, target));
4628
17.6k
  RETERR(dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_OPT,
4629
17.6k
                 style, flags, target));
4630
17.6k
  RETERR(dns_message_sectiontotext(msg, DNS_SECTION_QUESTION, style,
4631
17.6k
           flags, target));
4632
17.6k
  RETERR(dns_message_sectiontotext(msg, DNS_SECTION_ANSWER, style, flags,
4633
17.6k
           target));
4634
17.6k
  RETERR(dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY, style,
4635
17.6k
           flags, target));
4636
17.6k
  RETERR(dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL, style,
4637
17.6k
           flags, target));
4638
17.5k
  RETERR(dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_TSIG,
4639
17.5k
                 style, flags, target));
4640
17.5k
  return dns_message_pseudosectiontotext(msg, DNS_PSEUDOSECTION_SIG0,
4641
17.5k
                 style, flags, target);
4642
17.5k
}
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
}