Coverage Report

Created: 2026-10-17 06:52

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