Coverage Report

Created: 2025-11-24 06:17

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