Coverage Report

Created: 2025-12-12 06:30

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