Coverage Report

Created: 2025-08-03 06:33

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