Coverage Report

Created: 2026-07-16 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/rdata.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
#include <ctype.h>
17
#include <inttypes.h>
18
#include <stdbool.h>
19
20
#include <openssl/err.h>
21
#include <openssl/objects.h>
22
23
#include <isc/ascii.h>
24
#include <isc/base64.h>
25
#include <isc/hex.h>
26
#include <isc/lex.h>
27
#include <isc/mem.h>
28
#include <isc/parseint.h>
29
#include <isc/result.h>
30
#include <isc/string.h>
31
#include <isc/utf8.h>
32
#include <isc/util.h>
33
34
#include <dns/callbacks.h>
35
#include <dns/cert.h>
36
#include <dns/compress.h>
37
#include <dns/db.h>
38
#include <dns/dsdigest.h>
39
#include <dns/enumtype.h>
40
#include <dns/fixedname.h>
41
#include <dns/keyflags.h>
42
#include <dns/keyvalues.h>
43
#include <dns/message.h>
44
#include <dns/rcode.h>
45
#include <dns/rdata.h>
46
#include <dns/rdataclass.h>
47
#include <dns/rdataset.h>
48
#include <dns/rdatastruct.h>
49
#include <dns/rdatatype.h>
50
#include <dns/secalg.h>
51
#include <dns/secproto.h>
52
#include <dns/time.h>
53
#include <dns/ttl.h>
54
55
#define RETTOK(x)                                          \
56
0
  do {                                               \
57
0
    isc_result_t _r = (x);                     \
58
0
    if (_r != ISC_R_SUCCESS) {                 \
59
0
      isc_lex_ungettoken(lexer, &token); \
60
0
      return (_r);                       \
61
0
    }                                          \
62
0
  } while (0)
63
64
#define CHECKTOK(op)                                       \
65
0
  do {                                               \
66
0
    result = (op);                             \
67
0
    if (result != ISC_R_SUCCESS) {             \
68
0
      isc_lex_ungettoken(lexer, &token); \
69
0
      goto cleanup;                      \
70
0
    }                                          \
71
0
  } while (0)
72
73
0
#define DNS_AS_STR(t) ((t).value.as_textregion.base)
74
75
#define ARGS_FROMTEXT                                           \
76
  int rdclass, dns_rdatatype_t type, isc_lex_t *lexer,    \
77
    const dns_name_t *origin, unsigned int options, \
78
    isc_buffer_t *target, dns_rdatacallbacks_t *callbacks
79
80
0
#define CALL_FROMTEXT rdclass, type, lexer, origin, options, target, callbacks
81
82
#define ARGS_TOTEXT \
83
  dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, isc_buffer_t *target
84
85
0
#define CALL_TOTEXT rdata, tctx, target
86
87
#define ARGS_FROMWIRE                                            \
88
  int rdclass, dns_rdatatype_t type, isc_buffer_t *source, \
89
    dns_decompress_t dctx, isc_buffer_t *target
90
91
0
#define CALL_FROMWIRE rdclass, type, source, dctx, target
92
93
#define ARGS_TOWIRE \
94
  dns_rdata_t *rdata, dns_compress_t *cctx, isc_buffer_t *target
95
96
0
#define CALL_TOWIRE rdata, cctx, target
97
98
#define ARGS_COMPARE const dns_rdata_t *rdata1, const dns_rdata_t *rdata2
99
100
#define CALL_COMPARE rdata1, rdata2
101
102
#define ARGS_FROMSTRUCT \
103
  int rdclass, dns_rdatatype_t type, void *source, isc_buffer_t *target
104
105
0
#define CALL_FROMSTRUCT rdclass, type, source, target
106
107
#define ARGS_TOSTRUCT const dns_rdata_t *rdata, void *target, isc_mem_t *mctx
108
109
0
#define CALL_TOSTRUCT rdata, target, mctx
110
111
#define ARGS_FREESTRUCT void *source
112
113
0
#define CALL_FREESTRUCT source
114
115
#define ARGS_ADDLDATA                                \
116
  dns_rdata_t *rdata, const dns_name_t *owner, \
117
    dns_additionaldatafunc_t add, void *arg
118
119
0
#define CALL_ADDLDATA rdata, owner, add, arg
120
121
#define ARGS_DIGEST dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg
122
123
#define CALL_DIGEST rdata, digest, arg
124
125
#define ARGS_CHECKOWNER                                   \
126
  const dns_name_t *name, dns_rdataclass_t rdclass, \
127
    dns_rdatatype_t type, bool wildcard
128
129
#define CALL_CHECKOWNER name, rdclass, type, wildcard
130
131
#define ARGS_CHECKNAMES \
132
  dns_rdata_t *rdata, const dns_name_t *owner, dns_name_t *bad
133
134
0
#define CALL_CHECKNAMES rdata, owner, bad
135
136
/*%
137
 * Context structure for the totext_ functions.
138
 * Contains formatting options for rdata-to-text
139
 * conversion.
140
 */
141
typedef struct dns_rdata_textctx {
142
  const dns_name_t *origin;      /*%< Current origin, or NULL. */
143
  dns_masterstyle_flags_t flags; /*%< DNS_STYLEFLAG_*  */
144
  unsigned int width;        /*%< Width of rdata column. */
145
  const char *linebreak;         /*%< Line break string. */
146
} dns_rdata_textctx_t;
147
148
static isc_result_t
149
txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target);
150
151
static isc_result_t
152
txt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
153
154
static isc_result_t
155
txt_fromwire(isc_buffer_t *source, isc_buffer_t *target);
156
157
static isc_result_t
158
commatxt_fromtext(isc_textregion_t *source, bool comma, isc_buffer_t *target);
159
160
static isc_result_t
161
commatxt_totext(isc_region_t *source, bool quote, bool comma,
162
    isc_buffer_t *target);
163
164
static isc_result_t
165
multitxt_totext(isc_region_t *source, isc_buffer_t *target);
166
167
static isc_result_t
168
multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
169
170
static bool
171
name_prefix(dns_name_t *name, const dns_name_t *origin, dns_name_t *target);
172
173
static unsigned int
174
name_length(const dns_name_t *name);
175
176
static isc_result_t
177
str_totext(const char *source, isc_buffer_t *target);
178
179
static isc_result_t
180
inet_totext(int af, uint32_t flags, isc_region_t *src, isc_buffer_t *target);
181
182
static bool
183
buffer_empty(isc_buffer_t *source);
184
185
static void
186
buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region);
187
188
static isc_result_t
189
uint32_tobuffer(uint32_t, isc_buffer_t *target);
190
191
static isc_result_t
192
uint16_tobuffer(uint32_t, isc_buffer_t *target);
193
194
static isc_result_t
195
uint8_tobuffer(uint32_t, isc_buffer_t *target);
196
197
static isc_result_t
198
name_tobuffer(const dns_name_t *name, isc_buffer_t *target);
199
200
static uint32_t
201
uint32_fromregion(isc_region_t *region);
202
203
static uint16_t
204
uint16_fromregion(isc_region_t *region);
205
206
static uint8_t
207
uint8_fromregion(isc_region_t *region);
208
209
static uint8_t
210
uint8_consume_fromregion(isc_region_t *region);
211
212
static isc_result_t
213
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
214
215
static int
216
hexvalue(char value);
217
218
static int
219
decvalue(char value);
220
221
static void
222
default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *, ...)
223
  ISC_FORMAT_PRINTF(2, 3);
224
225
static void
226
fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
227
         dns_rdatacallbacks_t *callbacks, const char *name,
228
         unsigned long line, isc_token_t *token, isc_result_t result);
229
230
static void
231
fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks);
232
233
static isc_result_t
234
rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
235
       isc_buffer_t *target);
236
237
static void
238
warn_badname(const dns_name_t *name, isc_lex_t *lexer,
239
       dns_rdatacallbacks_t *callbacks);
240
241
static void
242
warn_badmx(isc_token_t *token, isc_lex_t *lexer,
243
     dns_rdatacallbacks_t *callbacks);
244
245
static uint16_t
246
uint16_consume_fromregion(isc_region_t *region);
247
248
static isc_result_t
249
unknown_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
250
         isc_buffer_t *target);
251
252
static isc_result_t generic_fromtext_key(ARGS_FROMTEXT);
253
254
static isc_result_t generic_totext_key(ARGS_TOTEXT);
255
256
static isc_result_t generic_fromwire_key(ARGS_FROMWIRE);
257
258
static isc_result_t generic_fromstruct_key(ARGS_FROMSTRUCT);
259
260
static isc_result_t generic_tostruct_key(ARGS_TOSTRUCT);
261
262
static void generic_freestruct_key(ARGS_FREESTRUCT);
263
264
static isc_result_t generic_fromtext_txt(ARGS_FROMTEXT);
265
266
static isc_result_t generic_totext_txt(ARGS_TOTEXT);
267
268
static isc_result_t generic_fromwire_txt(ARGS_FROMWIRE);
269
270
static isc_result_t generic_fromstruct_txt(ARGS_FROMSTRUCT);
271
272
static isc_result_t generic_tostruct_txt(ARGS_TOSTRUCT);
273
274
static void generic_freestruct_txt(ARGS_FREESTRUCT);
275
276
static isc_result_t
277
generic_txt_first(dns_rdata_txt_t *txt);
278
279
static isc_result_t
280
generic_txt_next(dns_rdata_txt_t *txt);
281
282
static isc_result_t
283
generic_txt_current(dns_rdata_txt_t *txt, dns_rdata_txt_string_t *string);
284
285
static isc_result_t generic_totext_ds(ARGS_TOTEXT);
286
287
static isc_result_t generic_tostruct_ds(ARGS_TOSTRUCT);
288
289
static isc_result_t generic_fromtext_ds(ARGS_FROMTEXT);
290
291
static isc_result_t generic_fromwire_ds(ARGS_FROMWIRE);
292
293
static isc_result_t generic_fromstruct_ds(ARGS_FROMSTRUCT);
294
295
static isc_result_t generic_fromtext_tlsa(ARGS_FROMTEXT);
296
297
static isc_result_t generic_totext_tlsa(ARGS_TOTEXT);
298
299
static isc_result_t generic_fromwire_tlsa(ARGS_FROMWIRE);
300
301
static isc_result_t generic_fromstruct_tlsa(ARGS_FROMSTRUCT);
302
303
static isc_result_t generic_tostruct_tlsa(ARGS_TOSTRUCT);
304
305
static void generic_freestruct_tlsa(ARGS_FREESTRUCT);
306
307
static isc_result_t generic_fromtext_in_svcb(ARGS_FROMTEXT);
308
static isc_result_t generic_totext_in_svcb(ARGS_TOTEXT);
309
static isc_result_t generic_fromwire_in_svcb(ARGS_FROMWIRE);
310
static isc_result_t generic_towire_in_svcb(ARGS_TOWIRE);
311
static isc_result_t generic_fromstruct_in_svcb(ARGS_FROMSTRUCT);
312
static isc_result_t generic_tostruct_in_svcb(ARGS_TOSTRUCT);
313
static void generic_freestruct_in_svcb(ARGS_FREESTRUCT);
314
static isc_result_t generic_additionaldata_in_svcb(ARGS_ADDLDATA);
315
static bool generic_checknames_in_svcb(ARGS_CHECKNAMES);
316
static isc_result_t
317
generic_rdata_in_svcb_first(dns_rdata_in_svcb_t *);
318
static isc_result_t
319
generic_rdata_in_svcb_next(dns_rdata_in_svcb_t *);
320
static void
321
generic_rdata_in_svcb_current(dns_rdata_in_svcb_t *, isc_region_t *);
322
323
/*% INT16 Size */
324
0
#define NS_INT16SZ 2
325
/*% IPv6 Address Size */
326
0
#define NS_LOCATORSZ 8
327
328
/*
329
 * Active Directory gc._msdcs.<forest> prefix.
330
 */
331
static unsigned char gc_msdcs_data[] = "\002gc\006_msdcs";
332
333
static dns_name_t const gc_msdcs = DNS_NAME_INITNONABSOLUTE(gc_msdcs_data);
334
335
/*%
336
 *  convert presentation level address to network order binary form.
337
 * \return
338
 *  1 if `src' is a valid [RFC1884 2.2] address, else 0.
339
 * \note
340
 *  (1) does not touch `dst' unless it's returning 1.
341
 */
342
static int
343
0
locator_pton(const char *src, unsigned char *dst) {
344
0
  unsigned char tmp[NS_LOCATORSZ];
345
0
  unsigned char *tp = tmp, *endp;
346
0
  int ch, seen_xdigits;
347
0
  unsigned int val, hexval;
348
349
0
  memset(tp, '\0', NS_LOCATORSZ);
350
0
  endp = tp + NS_LOCATORSZ;
351
0
  seen_xdigits = 0;
352
0
  val = 0;
353
0
  while ((ch = *src++) != '\0') {
354
0
    hexval = isc_hex_char(ch);
355
0
    if (hexval != 0) {
356
0
      val <<= 4;
357
0
      val |= (ch - hexval);
358
0
      if (++seen_xdigits > 4) {
359
0
        return 0;
360
0
      }
361
0
      continue;
362
0
    }
363
0
    if (ch == ':') {
364
0
      if (!seen_xdigits) {
365
0
        return 0;
366
0
      }
367
0
      if (tp + NS_INT16SZ > endp) {
368
0
        return 0;
369
0
      }
370
0
      *tp++ = (unsigned char)(val >> 8) & 0xff;
371
0
      *tp++ = (unsigned char)val & 0xff;
372
0
      seen_xdigits = 0;
373
0
      val = 0;
374
0
      continue;
375
0
    }
376
0
    return 0;
377
0
  }
378
0
  if (seen_xdigits) {
379
0
    if (tp + NS_INT16SZ > endp) {
380
0
      return 0;
381
0
    }
382
0
    *tp++ = (unsigned char)(val >> 8) & 0xff;
383
0
    *tp++ = (unsigned char)val & 0xff;
384
0
  }
385
0
  if (tp != endp) {
386
0
    return 0;
387
0
  }
388
0
  memmove(dst, tmp, NS_LOCATORSZ);
389
0
  return 1;
390
0
}
391
392
static void
393
0
name_duporclone(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
394
0
  if (mctx != NULL) {
395
0
    dns_name_dup(source, mctx, target);
396
0
  } else {
397
0
    dns_name_clone(source, target);
398
0
  }
399
0
}
400
401
static void *
402
0
mem_maybedup(isc_mem_t *mctx, void *source, size_t length) {
403
0
  void *copy = NULL;
404
405
0
  REQUIRE(source != NULL);
406
407
0
  if (mctx == NULL) {
408
0
    return source;
409
0
  }
410
411
0
  copy = isc_mem_allocate(mctx, length);
412
0
  memmove(copy, source, length);
413
414
0
  return copy;
415
0
}
416
417
static isc_result_t
418
0
typemap_fromtext(isc_lex_t *lexer, isc_buffer_t *target, bool allow_empty) {
419
0
  isc_token_t token;
420
0
  unsigned char bm[8 * 1024]; /* 64k bits */
421
0
  dns_rdatatype_t covered, max_used;
422
0
  int octet;
423
0
  unsigned int max_octet, newend, end;
424
0
  int window;
425
0
  bool first = true;
426
427
0
  max_used = 0;
428
0
  bm[0] = 0;
429
0
  end = 0;
430
431
0
  do {
432
0
    RETERR(isc_lex_getmastertoken(lexer, &token,
433
0
                isc_tokentype_string, true));
434
0
    if (token.type != isc_tokentype_string) {
435
0
      break;
436
0
    }
437
0
    RETTOK(dns_rdatatype_fromtext(&covered,
438
0
                &token.value.as_textregion));
439
0
    if (covered > max_used) {
440
0
      newend = covered / 8;
441
0
      if (newend > end) {
442
0
        memset(&bm[end + 1], 0, newend - end);
443
0
        end = newend;
444
0
      }
445
0
      max_used = covered;
446
0
    }
447
0
    bm[covered / 8] |= (0x80 >> (covered % 8));
448
0
    first = false;
449
0
  } while (1);
450
0
  isc_lex_ungettoken(lexer, &token);
451
0
  if (!allow_empty && first) {
452
0
    return DNS_R_FORMERR;
453
0
  }
454
455
0
  for (window = 0; window < 256; window++) {
456
0
    if (max_used < window * 256) {
457
0
      break;
458
0
    }
459
460
0
    max_octet = max_used - (window * 256);
461
0
    if (max_octet >= 256) {
462
0
      max_octet = 31;
463
0
    } else {
464
0
      max_octet /= 8;
465
0
    }
466
467
    /*
468
     * Find if we have a type in this window.
469
     */
470
0
    for (octet = max_octet; octet >= 0; octet--) {
471
0
      if (bm[window * 32 + octet] != 0) {
472
0
        break;
473
0
      }
474
0
    }
475
0
    if (octet < 0) {
476
0
      continue;
477
0
    }
478
0
    RETERR(uint8_tobuffer(window, target));
479
0
    RETERR(uint8_tobuffer(octet + 1, target));
480
0
    RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1));
481
0
  }
482
0
  return ISC_R_SUCCESS;
483
0
}
484
485
static isc_result_t
486
typemap_totext(isc_region_t *sr, dns_rdata_textctx_t *tctx,
487
0
         isc_buffer_t *target) {
488
0
  unsigned int i, j, k;
489
0
  unsigned int window, len;
490
0
  bool first = true;
491
492
0
  for (i = 0; i < sr->length; i += len) {
493
0
    if (tctx != NULL &&
494
0
        (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
495
0
    {
496
0
      RETERR(str_totext(tctx->linebreak, target));
497
0
      first = true;
498
0
    }
499
0
    INSIST(i + 2 <= sr->length);
500
0
    window = sr->base[i];
501
0
    len = sr->base[i + 1];
502
0
    INSIST(len > 0 && len <= 32);
503
0
    i += 2;
504
0
    INSIST(i + len <= sr->length);
505
0
    for (j = 0; j < len; j++) {
506
0
      dns_rdatatype_t t;
507
0
      if (sr->base[i + j] == 0) {
508
0
        continue;
509
0
      }
510
0
      for (k = 0; k < 8; k++) {
511
0
        if ((sr->base[i + j] & (0x80 >> k)) == 0) {
512
0
          continue;
513
0
        }
514
0
        t = window * 256 + j * 8 + k;
515
0
        if (!first) {
516
0
          RETERR(str_totext(" ", target));
517
0
        }
518
0
        first = false;
519
0
        if (dns_rdatatype_isknown(t)) {
520
0
          RETERR(dns_rdatatype_totext(t, target));
521
0
        } else {
522
0
          char buf[sizeof("TYPE65535")];
523
0
          snprintf(buf, sizeof(buf), "TYPE%u", t);
524
0
          RETERR(str_totext(buf, target));
525
0
        }
526
0
      }
527
0
    }
528
0
  }
529
0
  return ISC_R_SUCCESS;
530
0
}
531
532
static isc_result_t
533
0
typemap_test(isc_region_t *sr, bool allow_empty) {
534
0
  unsigned int window, lastwindow = 0;
535
0
  unsigned int len;
536
0
  bool first = true;
537
0
  unsigned int i;
538
539
0
  for (i = 0; i < sr->length; i += len) {
540
    /*
541
     * Check for overflow.
542
     */
543
0
    if (i + 2 > sr->length) {
544
0
      RETERR(DNS_R_FORMERR);
545
0
    }
546
0
    window = sr->base[i];
547
0
    len = sr->base[i + 1];
548
0
    i += 2;
549
    /*
550
     * Check that bitmap windows are in the correct order.
551
     */
552
0
    if (!first && window <= lastwindow) {
553
0
      RETERR(DNS_R_FORMERR);
554
0
    }
555
    /*
556
     * Check for legal lengths.
557
     */
558
0
    if (len < 1 || len > 32) {
559
0
      RETERR(DNS_R_FORMERR);
560
0
    }
561
    /*
562
     * Check for overflow.
563
     */
564
0
    if (i + len > sr->length) {
565
0
      RETERR(DNS_R_FORMERR);
566
0
    }
567
    /*
568
     * The last octet of the bitmap must be non zero.
569
     */
570
0
    if (sr->base[i + len - 1] == 0) {
571
0
      RETERR(DNS_R_FORMERR);
572
0
    }
573
0
    lastwindow = window;
574
0
    first = false;
575
0
  }
576
0
  if (i != sr->length) {
577
0
    return DNS_R_EXTRADATA;
578
0
  }
579
0
  if (!allow_empty && first) {
580
0
    RETERR(DNS_R_FORMERR);
581
0
  }
582
0
  return ISC_R_SUCCESS;
583
0
}
584
585
static isc_result_t
586
0
check_private(isc_buffer_t *source, dns_secalg_t alg) {
587
0
  isc_region_t sr;
588
0
  if (alg == DNS_KEYALG_PRIVATEDNS) {
589
0
    dns_fixedname_t fixed;
590
591
0
    RETERR(dns_name_fromwire(dns_fixedname_initname(&fixed), source,
592
0
           DNS_DECOMPRESS_DEFAULT, NULL));
593
0
  } else if (alg == DNS_KEYALG_PRIVATEOID) {
594
    /*
595
     * Check that we can extract the OID from the start of the
596
     * key data. We have a length byte followed by the OID BER
597
     * encoded.
598
     */
599
0
    const unsigned char *in = NULL;
600
0
    ASN1_OBJECT *obj = NULL;
601
602
0
    isc_buffer_activeregion(source, &sr);
603
0
    if (sr.length < 1 || (unsigned int)*sr.base + 1 > sr.length) {
604
0
      RETERR(DNS_R_FORMERR);
605
0
    }
606
0
    in = sr.base + 1;
607
0
    obj = d2i_ASN1_OBJECT(NULL, &in, *sr.base);
608
0
    if (obj == NULL) {
609
0
      ERR_clear_error();
610
0
      RETERR(DNS_R_FORMERR);
611
0
    }
612
0
    ASN1_OBJECT_free(obj);
613
0
    if ((in - sr.base) != (*sr.base + 1)) {
614
0
      RETERR(DNS_R_FORMERR);
615
0
    }
616
0
  }
617
0
  return ISC_R_SUCCESS;
618
0
}
619
620
/*
621
 * A relative URI template that has a "dns" variable.
622
 */
623
static bool
624
0
validate_dohpath(isc_region_t *region) {
625
0
  const unsigned char *p;
626
0
  const unsigned char *v = NULL;
627
0
  const unsigned char *n = NULL;
628
0
  unsigned char c;
629
0
  bool dns = false;
630
0
  bool wasop = false;
631
0
  enum {
632
0
    path,
633
0
    variable,
634
0
    percent1,
635
0
    percent2,
636
0
    variable_percent1,
637
0
    variable_percent2,
638
0
    prefix,
639
0
    explode
640
0
  } state = path;
641
642
0
  if (region->length == 0 || *region->base != '/' ||
643
0
      !isc_utf8_valid(region->base, region->length))
644
0
  {
645
0
    return false;
646
0
  }
647
648
  /*
649
   * RFC 6570 URI Template check + "dns" variable.
650
   */
651
0
  p = region->base;
652
0
  while (p < region->base + region->length) {
653
0
    switch (state) {
654
0
    case path:
655
0
      switch (*p++) {
656
0
      case '{': /*}*/
657
0
        state = variable;
658
0
        wasop = false;
659
0
        v = p;
660
0
        break;
661
0
      case '%':
662
0
        state = percent1;
663
0
        break;
664
0
      default:
665
0
        break;
666
0
      }
667
0
      break;
668
0
    case variable:
669
0
      c = *p++;
670
0
      switch (c) {
671
0
      case '+':
672
0
      case '#':
673
0
      case '.':
674
0
      case '/':
675
0
      case ';':
676
0
      case '?':
677
0
      case '&':
678
        /* Operators. */
679
0
        if (p != v + 1 || wasop) {
680
0
          return false;
681
0
        }
682
0
        wasop = true;
683
0
        v = p;
684
0
        break;
685
0
      case '=':
686
0
      case '!':
687
0
      case '@':
688
0
      case '|':
689
        /* Reserved operators. */
690
0
        return false;
691
0
      case '*':
692
0
      case ':':
693
0
      case '}':
694
0
      case ',':
695
        /* Found the end of the variable name. */
696
0
        if (p == (v + 1)) {
697
0
          return false;
698
0
        }
699
        /* 'p' has been incremented so 4 not 3 */
700
0
        if ((p - v) == 4 && memcmp(v, "dns", 3) == 0) {
701
0
          dns = true;
702
0
        }
703
0
        switch (c) {
704
0
        case ':':
705
0
          state = prefix;
706
0
          n = p;
707
0
          break;
708
0
        case /*{*/ '}':
709
0
          state = path;
710
0
          break;
711
0
        case '*':
712
0
          state = explode;
713
0
          break;
714
0
        case ',':
715
0
          wasop = false;
716
0
          v = p;
717
0
          break;
718
0
        }
719
0
        break;
720
0
      case '%':
721
        /* Percent encoded variable name. */
722
0
        state = variable_percent1;
723
0
        break;
724
0
      default:
725
        /* Valid variable name character? */
726
0
        if (c != '_' && !isalnum(c)) {
727
0
          return false;
728
0
        }
729
0
        break;
730
0
      }
731
0
      break;
732
0
    case explode:
733
0
      switch (*p++) {
734
0
      case ',':
735
0
        state = variable;
736
0
        wasop = false;
737
0
        v = p;
738
0
        break;
739
0
      case /*}*/ '}':
740
0
        state = path;
741
0
        break;
742
0
      default:
743
0
        return false;
744
0
      }
745
0
      break;
746
    /* Check % encoding */
747
0
    case percent1:
748
0
    case percent2:
749
0
    case variable_percent1:
750
0
    case variable_percent2:
751
      /* bad percent encoding? */
752
0
      if (!isxdigit(*p++)) {
753
0
        return false;
754
0
      }
755
0
      if (state == percent1) {
756
0
        state = percent2;
757
0
      } else if (state == percent2) {
758
0
        state = path;
759
0
      } else if (state == variable_percent1) {
760
0
        state = variable_percent2;
761
0
      } else {
762
0
        state = variable;
763
0
      }
764
0
      break;
765
0
    case prefix:
766
0
      c = *p++;
767
0
      if (!isdigit(c)) {
768
        /* valid number range [1..9999] */
769
0
        if ((p == n + 1) || (p - n) > 5 || *n == '0') {
770
0
          return false;
771
0
        }
772
0
        switch (c) {
773
0
        case ',':
774
0
          state = variable;
775
0
          wasop = false;
776
0
          break;
777
0
        case /*{*/ '}':
778
0
          state = path;
779
0
          break;
780
0
        default:
781
0
          return false;
782
0
        }
783
0
      }
784
0
      break;
785
0
    }
786
0
  }
787
0
  return state == path && dns;
788
0
}
789
790
#include "code.h"
791
792
#define META   0x0001
793
#define RESERVED 0x0002
794
795
/***
796
 *** Initialization
797
 ***/
798
799
void
800
0
dns_rdata_init(dns_rdata_t *rdata) {
801
0
  REQUIRE(rdata != NULL);
802
803
0
  rdata->data = NULL;
804
0
  rdata->length = 0;
805
0
  rdata->rdclass = 0;
806
0
  rdata->type = dns_rdatatype_none;
807
0
  rdata->flags = 0;
808
0
  ISC_LINK_INIT(rdata, link);
809
  /* ISC_LIST_INIT(rdata->list); */
810
0
}
811
812
void
813
0
dns_rdata_reset(dns_rdata_t *rdata) {
814
0
  REQUIRE(rdata != NULL);
815
816
0
  REQUIRE(!ISC_LINK_LINKED(rdata, link));
817
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
818
819
0
  rdata->data = NULL;
820
0
  rdata->length = 0;
821
0
  rdata->rdclass = 0;
822
0
  rdata->type = dns_rdatatype_none;
823
0
  rdata->flags = 0;
824
0
}
825
826
/***
827
 ***
828
 ***/
829
830
void
831
0
dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) {
832
0
  REQUIRE(src != NULL);
833
0
  REQUIRE(target != NULL);
834
835
0
  REQUIRE(DNS_RDATA_INITIALIZED(target));
836
837
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(src));
838
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(target));
839
840
0
  target->data = src->data;
841
0
  target->length = src->length;
842
0
  target->rdclass = src->rdclass;
843
0
  target->type = src->type;
844
0
  target->flags = src->flags;
845
0
}
846
847
/***
848
 *** Comparisons
849
 ***/
850
851
int
852
0
dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
853
0
  int result = 0;
854
0
  bool use_default = false;
855
856
0
  REQUIRE(rdata1 != NULL);
857
0
  REQUIRE(rdata2 != NULL);
858
0
  REQUIRE(rdata1->length == 0 || rdata1->data != NULL);
859
0
  REQUIRE(rdata2->length == 0 || rdata2->data != NULL);
860
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
861
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
862
863
0
  if (rdata1->rdclass != rdata2->rdclass) {
864
0
    return rdata1->rdclass < rdata2->rdclass ? -1 : 1;
865
0
  }
866
867
0
  if (rdata1->type != rdata2->type) {
868
0
    return rdata1->type < rdata2->type ? -1 : 1;
869
0
  }
870
871
0
  COMPARESWITCH
872
873
0
  if (use_default) {
874
0
    isc_region_t r1;
875
0
    isc_region_t r2;
876
877
0
    dns_rdata_toregion(rdata1, &r1);
878
0
    dns_rdata_toregion(rdata2, &r2);
879
0
    result = isc_region_compare(&r1, &r2);
880
0
  }
881
0
  return result;
882
0
}
883
884
int
885
0
dns_rdata_casecompare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
886
0
  int result = 0;
887
0
  bool use_default = false;
888
889
0
  REQUIRE(rdata1 != NULL);
890
0
  REQUIRE(rdata2 != NULL);
891
0
  REQUIRE(rdata1->length == 0 || rdata1->data != NULL);
892
0
  REQUIRE(rdata2->length == 0 || rdata2->data != NULL);
893
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
894
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
895
896
0
  if (rdata1->rdclass != rdata2->rdclass) {
897
0
    return rdata1->rdclass < rdata2->rdclass ? -1 : 1;
898
0
  }
899
900
0
  if (rdata1->type != rdata2->type) {
901
0
    return rdata1->type < rdata2->type ? -1 : 1;
902
0
  }
903
904
0
  CASECOMPARESWITCH
905
906
0
  if (use_default) {
907
0
    isc_region_t r1;
908
0
    isc_region_t r2;
909
910
0
    dns_rdata_toregion(rdata1, &r1);
911
0
    dns_rdata_toregion(rdata2, &r2);
912
0
    result = isc_region_compare(&r1, &r2);
913
0
  }
914
0
  return result;
915
0
}
916
917
/***
918
 *** Conversions
919
 ***/
920
921
void
922
dns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
923
0
         dns_rdatatype_t type, isc_region_t *r) {
924
0
  REQUIRE(rdata != NULL);
925
0
  REQUIRE(DNS_RDATA_INITIALIZED(rdata));
926
0
  REQUIRE(r != NULL);
927
928
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
929
930
0
  rdata->data = r->base;
931
0
  rdata->length = r->length;
932
0
  rdata->rdclass = rdclass;
933
0
  rdata->type = type;
934
0
  rdata->flags = 0;
935
0
}
936
937
void
938
0
dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) {
939
0
  REQUIRE(rdata != NULL);
940
0
  REQUIRE(r != NULL);
941
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
942
943
0
  r->base = rdata->data;
944
0
  r->length = rdata->length;
945
0
}
946
947
isc_result_t
948
dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
949
       dns_rdatatype_t type, isc_buffer_t *source,
950
0
       dns_decompress_t dctx, isc_buffer_t *target) {
951
0
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
952
0
  isc_region_t region;
953
0
  isc_buffer_t ss;
954
0
  isc_buffer_t st;
955
0
  bool use_default = false;
956
0
  uint32_t activelength;
957
0
  unsigned int length;
958
959
0
  if (rdata != NULL) {
960
0
    REQUIRE(DNS_RDATA_INITIALIZED(rdata));
961
0
    REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
962
0
  }
963
0
  REQUIRE(source != NULL);
964
0
  REQUIRE(target != NULL);
965
966
0
  if (type == dns_rdatatype_none) {
967
0
    return DNS_R_FORMERR;
968
0
  }
969
970
0
  ss = *source;
971
0
  st = *target;
972
973
0
  activelength = isc_buffer_activelength(source);
974
0
  INSIST(activelength < 65536);
975
976
0
  FROMWIRESWITCH
977
978
0
  if (use_default) {
979
0
    if (activelength > isc_buffer_availablelength(target)) {
980
0
      result = ISC_R_NOSPACE;
981
0
    } else {
982
0
      isc_buffer_putmem(target, isc_buffer_current(source),
983
0
            activelength);
984
0
      isc_buffer_forward(source, activelength);
985
0
      result = ISC_R_SUCCESS;
986
0
    }
987
0
  }
988
989
  /*
990
   * Reject any rdata that expands out to more than DNS_RDATA_MAXLENGTH
991
   * as we cannot transmit it.
992
   */
993
0
  length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
994
0
  if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
995
0
    result = DNS_R_FORMERR;
996
0
  }
997
998
  /*
999
   * We should have consumed all of our buffer.
1000
   */
1001
0
  if (result == ISC_R_SUCCESS && !buffer_empty(source)) {
1002
0
    result = DNS_R_EXTRADATA;
1003
0
  }
1004
1005
0
  if (rdata != NULL && result == ISC_R_SUCCESS) {
1006
0
    region.base = isc_buffer_used(&st);
1007
0
    region.length = length;
1008
0
    dns_rdata_fromregion(rdata, rdclass, type, &region);
1009
0
  }
1010
1011
0
  if (result != ISC_R_SUCCESS) {
1012
0
    *source = ss;
1013
0
    *target = st;
1014
0
  }
1015
0
  return result;
1016
0
}
1017
1018
isc_result_t
1019
dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx,
1020
0
     isc_buffer_t *target) {
1021
0
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1022
0
  bool use_default = false;
1023
0
  isc_region_t tr;
1024
0
  isc_buffer_t st;
1025
1026
0
  REQUIRE(rdata != NULL);
1027
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1028
1029
  /*
1030
   * Some DynDNS meta-RRs have empty rdata.
1031
   */
1032
0
  if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
1033
0
    INSIST(rdata->length == 0);
1034
0
    return ISC_R_SUCCESS;
1035
0
  }
1036
1037
0
  st = *target;
1038
1039
0
  TOWIRESWITCH
1040
1041
0
  if (use_default) {
1042
0
    isc_buffer_availableregion(target, &tr);
1043
0
    if (tr.length < rdata->length) {
1044
0
      return ISC_R_NOSPACE;
1045
0
    }
1046
0
    memmove(tr.base, rdata->data, rdata->length);
1047
0
    isc_buffer_add(target, rdata->length);
1048
0
    return ISC_R_SUCCESS;
1049
0
  }
1050
0
  if (result != ISC_R_SUCCESS) {
1051
0
    *target = st;
1052
0
    dns_compress_rollback(cctx, target->used);
1053
0
  }
1054
0
  return result;
1055
0
}
1056
1057
/*
1058
 * If the binary data in 'src' is valid uncompressed wire format
1059
 * rdata of class 'rdclass' and type 'type', return ISC_R_SUCCESS
1060
 * and copy the validated rdata to 'dest'.  Otherwise return an error.
1061
 */
1062
static isc_result_t
1063
rdata_validate(isc_buffer_t *src, isc_buffer_t *dest, dns_rdataclass_t rdclass,
1064
0
         dns_rdatatype_t type) {
1065
0
  isc_result_t result;
1066
1067
0
  isc_buffer_setactive(src, isc_buffer_usedlength(src));
1068
0
  result = dns_rdata_fromwire(NULL, rdclass, type, src,
1069
0
            DNS_DECOMPRESS_NEVER, dest);
1070
1071
0
  return result;
1072
0
}
1073
1074
static isc_result_t
1075
unknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type,
1076
0
     isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target) {
1077
0
  isc_result_t result;
1078
0
  isc_buffer_t *buf = NULL;
1079
0
  isc_token_t token;
1080
1081
0
  if (type == dns_rdatatype_none || dns_rdatatype_ismeta(type)) {
1082
0
    return DNS_R_METATYPE;
1083
0
  }
1084
1085
0
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
1086
0
              false));
1087
0
  if (token.value.as_ulong > 65535U) {
1088
0
    return ISC_R_RANGE;
1089
0
  }
1090
0
  isc_buffer_allocate(mctx, &buf, token.value.as_ulong);
1091
1092
0
  if (token.value.as_ulong != 0U) {
1093
0
    CHECK(isc_hex_tobuffer(lexer, buf,
1094
0
               (unsigned int)token.value.as_ulong));
1095
0
    if (isc_buffer_usedlength(buf) != token.value.as_ulong) {
1096
0
      CLEANUP(ISC_R_UNEXPECTEDEND);
1097
0
    }
1098
0
  }
1099
1100
0
  if (dns_rdatatype_isknown(type)) {
1101
0
    result = rdata_validate(buf, target, rdclass, type);
1102
0
  } else {
1103
0
    isc_region_t r;
1104
0
    isc_buffer_usedregion(buf, &r);
1105
0
    result = isc_buffer_copyregion(target, &r);
1106
0
  }
1107
0
  CHECK(result);
1108
1109
0
  isc_buffer_free(&buf);
1110
0
  return ISC_R_SUCCESS;
1111
1112
0
cleanup:
1113
0
  isc_buffer_free(&buf);
1114
0
  return result;
1115
0
}
1116
1117
isc_result_t
1118
dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
1119
       dns_rdatatype_t type, isc_lex_t *lexer,
1120
       const dns_name_t *origin, unsigned int options,
1121
       isc_mem_t *mctx, isc_buffer_t *target,
1122
0
       dns_rdatacallbacks_t *callbacks) {
1123
0
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1124
0
  isc_region_t region;
1125
0
  isc_buffer_t st;
1126
0
  isc_token_t token;
1127
0
  unsigned int lexoptions = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
1128
0
          ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
1129
0
  char *name;
1130
0
  unsigned long line;
1131
0
  void (*callback)(dns_rdatacallbacks_t *, const char *, ...);
1132
0
  isc_result_t tresult;
1133
0
  unsigned int length;
1134
0
  bool unknown;
1135
1136
0
  REQUIRE(origin == NULL || dns_name_isabsolute(origin));
1137
0
  if (rdata != NULL) {
1138
0
    REQUIRE(DNS_RDATA_INITIALIZED(rdata));
1139
0
    REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1140
0
  }
1141
0
  if (callbacks != NULL) {
1142
0
    REQUIRE(callbacks->warn != NULL);
1143
0
    REQUIRE(callbacks->error != NULL);
1144
0
  }
1145
1146
0
  st = *target;
1147
1148
0
  if (callbacks != NULL) {
1149
0
    callback = callbacks->error;
1150
0
  } else {
1151
0
    callback = default_fromtext_callback;
1152
0
  }
1153
1154
0
  result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
1155
0
          true);
1156
0
  if (result != ISC_R_SUCCESS) {
1157
0
    name = isc_lex_getsourcename(lexer);
1158
0
    line = isc_lex_getsourceline(lexer);
1159
0
    fromtext_error(callback, callbacks, name, line, NULL, result);
1160
0
    return result;
1161
0
  }
1162
1163
0
  unknown = false;
1164
0
  if (token.type == isc_tokentype_string &&
1165
0
      strcmp(DNS_AS_STR(token), "\\#") == 0)
1166
0
  {
1167
    /*
1168
     * If this is a TXT record '\#' could be a escaped '#'.
1169
     * Look to see if the next token is a number and if so
1170
     * treat it as a unknown record format.
1171
     */
1172
0
    if (type == dns_rdatatype_txt) {
1173
0
      result = isc_lex_getmastertoken(
1174
0
        lexer, &token, isc_tokentype_number, false);
1175
0
      if (result == ISC_R_SUCCESS) {
1176
0
        isc_lex_ungettoken(lexer, &token);
1177
0
      }
1178
0
    }
1179
1180
0
    if (result == ISC_R_SUCCESS) {
1181
0
      unknown = true;
1182
0
      result = unknown_fromtext(rdclass, type, lexer, mctx,
1183
0
              target);
1184
0
    } else {
1185
0
      options |= DNS_RDATA_UNKNOWNESCAPE;
1186
0
    }
1187
0
  } else {
1188
0
    isc_lex_ungettoken(lexer, &token);
1189
0
  }
1190
1191
0
  if (!unknown) {
1192
0
    FROMTEXTSWITCH
1193
1194
    /*
1195
     * Consume to end of line / file.
1196
     * If not at end of line initially set error code.
1197
     * Call callback via fromtext_error once if there was an error.
1198
     */
1199
0
  }
1200
0
  do {
1201
0
    name = isc_lex_getsourcename(lexer);
1202
0
    line = isc_lex_getsourceline(lexer);
1203
0
    tresult = isc_lex_gettoken(lexer, lexoptions, &token);
1204
0
    if (tresult != ISC_R_SUCCESS) {
1205
0
      if (result == ISC_R_SUCCESS) {
1206
0
        result = tresult;
1207
0
      }
1208
0
      if (callback != NULL) {
1209
0
        fromtext_error(callback, callbacks, name, line,
1210
0
                 NULL, result);
1211
0
      }
1212
0
      break;
1213
0
    } else if (token.type != isc_tokentype_eol &&
1214
0
         token.type != isc_tokentype_eof)
1215
0
    {
1216
0
      if (result == ISC_R_SUCCESS) {
1217
0
        result = DNS_R_EXTRATOKEN;
1218
0
      }
1219
0
      if (callback != NULL) {
1220
0
        fromtext_error(callback, callbacks, name, line,
1221
0
                 &token, result);
1222
0
        callback = NULL;
1223
0
      }
1224
0
    } else if (result != ISC_R_SUCCESS && callback != NULL) {
1225
0
      fromtext_error(callback, callbacks, name, line, &token,
1226
0
               result);
1227
0
      break;
1228
0
    } else {
1229
0
      if (token.type == isc_tokentype_eof) {
1230
0
        fromtext_warneof(lexer, callbacks);
1231
0
      }
1232
0
      break;
1233
0
    }
1234
0
  } while (1);
1235
1236
0
  length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
1237
0
  if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
1238
0
    result = ISC_R_NOSPACE;
1239
0
  }
1240
1241
0
  if (rdata != NULL && result == ISC_R_SUCCESS) {
1242
0
    region.base = isc_buffer_used(&st);
1243
0
    region.length = length;
1244
0
    dns_rdata_fromregion(rdata, rdclass, type, &region);
1245
0
  }
1246
0
  if (result != ISC_R_SUCCESS) {
1247
0
    *target = st;
1248
0
  }
1249
0
  return result;
1250
0
}
1251
1252
static isc_result_t
1253
unknown_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
1254
0
         isc_buffer_t *target) {
1255
0
  isc_result_t result = ISC_R_SUCCESS;
1256
0
  char buf[sizeof("65535")];
1257
0
  isc_region_t sr;
1258
1259
0
  strlcpy(buf, "\\# ", sizeof(buf));
1260
0
  RETERR(str_totext(buf, target));
1261
1262
0
  dns_rdata_toregion(rdata, &sr);
1263
0
  INSIST(sr.length < 65536);
1264
0
  snprintf(buf, sizeof(buf), "%u", sr.length);
1265
0
  RETERR(str_totext(buf, target));
1266
1267
0
  if (sr.length != 0U) {
1268
0
    if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
1269
0
      RETERR(str_totext(" ( ", target));
1270
0
    } else {
1271
0
      RETERR(str_totext(" ", target));
1272
0
    }
1273
1274
0
    if (tctx->width == 0) { /* No splitting */
1275
0
      result = isc_hex_totext(&sr, 0, "", target);
1276
0
    } else {
1277
0
      result = isc_hex_totext(&sr, tctx->width - 2,
1278
0
            tctx->linebreak, target);
1279
0
    }
1280
0
    if (result == ISC_R_SUCCESS &&
1281
0
        (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
1282
0
    {
1283
0
      result = str_totext(" )", target);
1284
0
    }
1285
0
  }
1286
0
  return result;
1287
0
}
1288
1289
static isc_result_t
1290
rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
1291
0
       isc_buffer_t *target) {
1292
0
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1293
0
  bool use_default = false;
1294
0
  unsigned int cur;
1295
1296
0
  REQUIRE(rdata != NULL);
1297
0
  REQUIRE(tctx->origin == NULL || dns_name_isabsolute(tctx->origin));
1298
1299
  /*
1300
   * Some DynDNS meta-RRs have empty rdata.
1301
   */
1302
0
  if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
1303
0
    INSIST(rdata->length == 0);
1304
0
    return ISC_R_SUCCESS;
1305
0
  }
1306
1307
0
  if ((tctx->flags & DNS_STYLEFLAG_UNKNOWNFORMAT) != 0) {
1308
0
    return unknown_totext(rdata, tctx, target);
1309
0
  }
1310
1311
0
  cur = isc_buffer_usedlength(target);
1312
1313
0
  TOTEXTSWITCH
1314
1315
0
  if (use_default || (result == ISC_R_NOTIMPLEMENTED)) {
1316
0
    unsigned int u = isc_buffer_usedlength(target);
1317
1318
0
    INSIST(u >= cur);
1319
0
    isc_buffer_subtract(target, u - cur);
1320
0
    result = unknown_totext(rdata, tctx, target);
1321
0
  }
1322
1323
0
  return result;
1324
0
}
1325
1326
isc_result_t
1327
dns_rdata_totext(dns_rdata_t *rdata, const dns_name_t *origin,
1328
0
     isc_buffer_t *target) {
1329
0
  dns_rdata_textctx_t tctx;
1330
1331
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1332
1333
  /*
1334
   * Set up formatting options for single-line output.
1335
   */
1336
0
  tctx.origin = origin;
1337
0
  tctx.flags = 0;
1338
0
  tctx.width = 60;
1339
0
  tctx.linebreak = " ";
1340
0
  return rdata_totext(rdata, &tctx, target);
1341
0
}
1342
1343
isc_result_t
1344
dns_rdata_tofmttext(dns_rdata_t *rdata, const dns_name_t *origin,
1345
        dns_masterstyle_flags_t flags, unsigned int width,
1346
        unsigned int split_width, const char *linebreak,
1347
0
        isc_buffer_t *target) {
1348
0
  dns_rdata_textctx_t tctx;
1349
1350
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1351
1352
  /*
1353
   * Set up formatting options for formatted output.
1354
   */
1355
0
  tctx.origin = origin;
1356
0
  tctx.flags = flags;
1357
0
  if (split_width == 0xffffffff) {
1358
0
    tctx.width = width;
1359
0
  } else {
1360
0
    tctx.width = split_width;
1361
0
  }
1362
1363
0
  if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) {
1364
0
    tctx.linebreak = linebreak;
1365
0
  } else {
1366
0
    if (split_width == 0xffffffff) {
1367
0
      tctx.width = 60; /* Used for hex word length only. */
1368
0
    }
1369
0
    tctx.linebreak = " ";
1370
0
  }
1371
0
  return rdata_totext(rdata, &tctx, target);
1372
0
}
1373
1374
isc_result_t
1375
dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
1376
0
         dns_rdatatype_t type, void *source, isc_buffer_t *target) {
1377
0
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1378
0
  isc_buffer_t st;
1379
0
  isc_region_t region;
1380
0
  bool use_default = false;
1381
0
  unsigned int length;
1382
1383
0
  REQUIRE(source != NULL);
1384
0
  if (rdata != NULL) {
1385
0
    REQUIRE(DNS_RDATA_INITIALIZED(rdata));
1386
0
    REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1387
0
  }
1388
1389
0
  st = *target;
1390
1391
0
  FROMSTRUCTSWITCH
1392
1393
0
  if (use_default) {
1394
0
    (void)NULL;
1395
0
  }
1396
1397
0
  length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
1398
0
  if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
1399
0
    result = ISC_R_NOSPACE;
1400
0
  }
1401
1402
0
  if (rdata != NULL && result == ISC_R_SUCCESS) {
1403
0
    region.base = isc_buffer_used(&st);
1404
0
    region.length = length;
1405
0
    dns_rdata_fromregion(rdata, rdclass, type, &region);
1406
0
  }
1407
0
  if (result != ISC_R_SUCCESS) {
1408
0
    *target = st;
1409
0
  }
1410
0
  return result;
1411
0
}
1412
1413
isc_result_t
1414
0
dns_rdata_tostruct(const dns_rdata_t *rdata, void *target, isc_mem_t *mctx) {
1415
0
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1416
0
  bool use_default = false;
1417
1418
0
  REQUIRE(rdata != NULL);
1419
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1420
0
  REQUIRE((rdata->flags & DNS_RDATA_UPDATE) == 0);
1421
1422
0
  TOSTRUCTSWITCH
1423
1424
0
  if (use_default) {
1425
0
    (void)NULL;
1426
0
  }
1427
1428
0
  return result;
1429
0
}
1430
1431
void
1432
0
dns_rdata_freestruct(void *source) {
1433
0
  dns_rdatacommon_t *common = source;
1434
0
  REQUIRE(common != NULL);
1435
1436
0
  FREESTRUCTSWITCH
1437
0
}
1438
1439
isc_result_t
1440
dns_rdata_additionaldata(dns_rdata_t *rdata, const dns_name_t *owner,
1441
0
       dns_additionaldatafunc_t add, void *arg) {
1442
0
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1443
0
  bool use_default = false;
1444
1445
  /*
1446
   * Call 'add' for each name and type from 'rdata' which is subject to
1447
   * additional section processing.
1448
   */
1449
1450
0
  REQUIRE(rdata != NULL);
1451
0
  REQUIRE(add != NULL);
1452
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1453
1454
0
  ADDITIONALDATASWITCH
1455
1456
  /* No additional processing for unknown types */
1457
0
  if (use_default) {
1458
0
    result = ISC_R_SUCCESS;
1459
0
  }
1460
1461
0
  return result;
1462
0
}
1463
1464
isc_result_t
1465
0
dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg) {
1466
0
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1467
0
  bool use_default = false;
1468
0
  isc_region_t r;
1469
1470
  /*
1471
   * Send 'rdata' in DNSSEC canonical form to 'digest'.
1472
   */
1473
1474
0
  REQUIRE(rdata != NULL);
1475
0
  REQUIRE(digest != NULL);
1476
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1477
1478
0
  DIGESTSWITCH
1479
1480
0
  if (use_default) {
1481
0
    dns_rdata_toregion(rdata, &r);
1482
0
    result = (digest)(arg, &r);
1483
0
  }
1484
1485
0
  return result;
1486
0
}
1487
1488
bool
1489
dns_rdata_checkowner(const dns_name_t *name, dns_rdataclass_t rdclass,
1490
0
         dns_rdatatype_t type, bool wildcard) {
1491
0
  bool result;
1492
1493
0
  CHECKOWNERSWITCH
1494
0
  return result;
1495
0
}
1496
1497
bool
1498
dns_rdata_checknames(dns_rdata_t *rdata, const dns_name_t *owner,
1499
0
         dns_name_t *bad) {
1500
0
  bool result;
1501
1502
0
  CHECKNAMESSWITCH
1503
0
  return result;
1504
0
}
1505
1506
unsigned int
1507
0
dns_rdatatype_attributes(dns_rdatatype_t type) {
1508
0
  RDATATYPE_ATTRIBUTE_SW
1509
0
  if (type >= (dns_rdatatype_t)128 && type <= (dns_rdatatype_t)255) {
1510
0
    return DNS_RDATATYPEATTR_UNKNOWN | DNS_RDATATYPEATTR_META;
1511
0
  }
1512
0
  return DNS_RDATATYPEATTR_UNKNOWN;
1513
0
}
1514
1515
isc_result_t
1516
0
dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) {
1517
0
  unsigned int hash;
1518
0
  unsigned int n;
1519
0
  unsigned char a, b;
1520
1521
0
  n = source->length;
1522
1523
0
  if (n == 0) {
1524
0
    return DNS_R_UNKNOWN;
1525
0
  }
1526
1527
0
  a = isc_ascii_tolower(source->base[0]);
1528
0
  b = isc_ascii_tolower(source->base[n - 1]);
1529
1530
0
  hash = ((a + n) * b) % 256;
1531
1532
  /*
1533
   * This switch block is inlined via \#define, and will use "return"
1534
   * to return a result to the caller if it is a valid (known)
1535
   * rdatatype name.
1536
   */
1537
0
  RDATATYPE_FROMTEXT_SW(hash, source->base, n, typep);
1538
1539
0
  if (source->length > 4 && source->length < (4 + sizeof("65000")) &&
1540
0
      strncasecmp("type", source->base, 4) == 0)
1541
0
  {
1542
0
    char buf[sizeof("65000")];
1543
0
    char *endp;
1544
0
    unsigned int val;
1545
1546
    /*
1547
     * source->base is not required to be NUL terminated.
1548
     * Copy up to remaining bytes and NUL terminate.
1549
     */
1550
0
    snprintf(buf, sizeof(buf), "%.*s", (int)(source->length - 4),
1551
0
       source->base + 4);
1552
0
    val = strtoul(buf, &endp, 10);
1553
0
    if (*endp == '\0' && val <= 0xffff) {
1554
0
      *typep = (dns_rdatatype_t)val;
1555
0
      return ISC_R_SUCCESS;
1556
0
    }
1557
0
  }
1558
1559
0
  return DNS_R_UNKNOWN;
1560
0
}
1561
1562
isc_result_t
1563
0
dns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target) {
1564
0
  RDATATYPE_TOTEXT_SW
1565
1566
0
  return dns_rdatatype_tounknowntext(type, target);
1567
0
}
1568
1569
isc_result_t
1570
0
dns_rdatatype_tounknowntext(dns_rdatatype_t type, isc_buffer_t *target) {
1571
0
  char buf[sizeof("TYPE65535")];
1572
1573
0
  snprintf(buf, sizeof(buf), "TYPE%u", type);
1574
0
  return str_totext(buf, target);
1575
0
}
1576
1577
void
1578
0
dns_rdatatype_format(dns_rdatatype_t rdtype, char *array, unsigned int size) {
1579
0
  isc_result_t result;
1580
0
  isc_buffer_t buf;
1581
1582
0
  if (size == 0U) {
1583
0
    return;
1584
0
  }
1585
1586
0
  isc_buffer_init(&buf, array, size);
1587
0
  result = dns_rdatatype_totext(rdtype, &buf);
1588
  /*
1589
   * Null terminate.
1590
   */
1591
0
  if (result == ISC_R_SUCCESS) {
1592
0
    if (isc_buffer_availablelength(&buf) >= 1) {
1593
0
      isc_buffer_putuint8(&buf, 0);
1594
0
    } else {
1595
0
      result = ISC_R_NOSPACE;
1596
0
    }
1597
0
  }
1598
0
  if (result != ISC_R_SUCCESS) {
1599
0
    strlcpy(array, "<unknown>", size);
1600
0
  }
1601
0
}
1602
1603
/*
1604
 * Private function.
1605
 */
1606
1607
static unsigned int
1608
0
name_length(const dns_name_t *name) {
1609
0
  return name->length;
1610
0
}
1611
1612
static isc_result_t
1613
commatxt_totext(isc_region_t *source, bool quote, bool comma,
1614
0
    isc_buffer_t *target) {
1615
0
  unsigned int tl;
1616
0
  unsigned int n;
1617
0
  unsigned char *sp;
1618
0
  char *tp;
1619
0
  isc_region_t region;
1620
1621
0
  isc_buffer_availableregion(target, &region);
1622
0
  sp = source->base;
1623
0
  tp = (char *)region.base;
1624
0
  tl = region.length;
1625
1626
0
  n = *sp++;
1627
1628
0
  REQUIRE(n + 1 <= source->length);
1629
0
  if (n == 0U) {
1630
0
    REQUIRE(quote);
1631
0
  }
1632
1633
0
  if (quote) {
1634
0
    if (tl < 1) {
1635
0
      return ISC_R_NOSPACE;
1636
0
    }
1637
0
    *tp++ = '"';
1638
0
    tl--;
1639
0
  }
1640
0
  while (n--) {
1641
    /*
1642
     * \DDD space (0x20) if not quoting.
1643
     */
1644
0
    if (*sp < (quote ? ' ' : '!') || *sp >= 0x7f) {
1645
0
      if (tl < 4) {
1646
0
        return ISC_R_NOSPACE;
1647
0
      }
1648
0
      *tp++ = '\\';
1649
0
      *tp++ = '0' + ((*sp / 100) % 10);
1650
0
      *tp++ = '0' + ((*sp / 10) % 10);
1651
0
      *tp++ = '0' + (*sp % 10);
1652
0
      sp++;
1653
0
      tl -= 4;
1654
0
      continue;
1655
0
    }
1656
    /*
1657
     * Escape double quote and backslash.  If we are not
1658
     * enclosing the string in double quotes, also escape
1659
     * at sign (@) and semicolon (;) unless comma is set.
1660
     * If comma is set, then only escape commas (,).
1661
     */
1662
0
    if (*sp == '"' || *sp == '\\' || (comma && *sp == ',') ||
1663
0
        (!comma && !quote && (*sp == '@' || *sp == ';')))
1664
0
    {
1665
0
      if (tl < 2) {
1666
0
        return ISC_R_NOSPACE;
1667
0
      }
1668
0
      *tp++ = '\\';
1669
0
      tl--;
1670
      /*
1671
       * Perform comma escape processing.
1672
       * ',' => '\\,'
1673
       * '\' => '\\\\'
1674
       */
1675
0
      if (comma && (*sp == ',' || *sp == '\\')) {
1676
0
        if (tl < ((*sp == '\\') ? 3 : 2)) {
1677
0
          return ISC_R_NOSPACE;
1678
0
        }
1679
0
        *tp++ = '\\';
1680
0
        tl--;
1681
0
        if (*sp == '\\') {
1682
0
          *tp++ = '\\';
1683
0
          tl--;
1684
0
        }
1685
0
      }
1686
0
    }
1687
0
    if (tl < 1) {
1688
0
      return ISC_R_NOSPACE;
1689
0
    }
1690
0
    *tp++ = *sp++;
1691
0
    tl--;
1692
0
  }
1693
0
  if (quote) {
1694
0
    if (tl < 1) {
1695
0
      return ISC_R_NOSPACE;
1696
0
    }
1697
0
    *tp++ = '"';
1698
0
    tl--;
1699
0
    POST(tl);
1700
0
  }
1701
0
  isc_buffer_add(target, (unsigned int)(tp - (char *)region.base));
1702
0
  isc_region_consume(source, *source->base + 1);
1703
0
  return ISC_R_SUCCESS;
1704
0
}
1705
1706
static isc_result_t
1707
0
txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target) {
1708
0
  return commatxt_totext(source, quote, false, target);
1709
0
}
1710
1711
static isc_result_t
1712
0
commatxt_fromtext(isc_textregion_t *source, bool comma, isc_buffer_t *target) {
1713
0
  isc_region_t tregion;
1714
0
  bool escape = false, comma_escape = false, seen_comma = false;
1715
0
  unsigned int n, nrem;
1716
0
  char *s;
1717
0
  unsigned char *t;
1718
0
  int d;
1719
0
  int c;
1720
1721
0
  isc_buffer_availableregion(target, &tregion);
1722
0
  s = source->base;
1723
0
  n = source->length;
1724
0
  t = tregion.base;
1725
0
  nrem = tregion.length;
1726
0
  if (nrem < 1) {
1727
0
    return ISC_R_NOSPACE;
1728
0
  }
1729
  /*
1730
   * Length byte.
1731
   */
1732
0
  nrem--;
1733
0
  t++;
1734
  /*
1735
   * Maximum text string length.
1736
   */
1737
0
  if (nrem > 255) {
1738
0
    nrem = 255;
1739
0
  }
1740
0
  while (n-- != 0) {
1741
0
    c = (*s++) & 0xff;
1742
0
    if (escape && (d = decvalue((char)c)) != -1) {
1743
0
      c = d;
1744
0
      if (n == 0) {
1745
0
        return DNS_R_SYNTAX;
1746
0
      }
1747
0
      n--;
1748
0
      if ((d = decvalue(*s++)) != -1) {
1749
0
        c = c * 10 + d;
1750
0
      } else {
1751
0
        return DNS_R_SYNTAX;
1752
0
      }
1753
0
      if (n == 0) {
1754
0
        return DNS_R_SYNTAX;
1755
0
      }
1756
0
      n--;
1757
0
      if ((d = decvalue(*s++)) != -1) {
1758
0
        c = c * 10 + d;
1759
0
      } else {
1760
0
        return DNS_R_SYNTAX;
1761
0
      }
1762
0
      if (c > 255) {
1763
0
        return DNS_R_SYNTAX;
1764
0
      }
1765
0
    } else if (!escape && c == '\\') {
1766
0
      escape = true;
1767
0
      continue;
1768
0
    }
1769
0
    escape = false;
1770
    /*
1771
     * Level 1 escape processing complete.
1772
     * If comma is set perform comma escape processing.
1773
     *
1774
     * Level 1  Level 2   ALPN's
1775
     * h1\,h2   =>  h1,h2   =>  h1 and h2
1776
     * h1\\,h2  =>  h1\,h2  =>  h1,h2
1777
     * h1\\h2   =>  h1\h2   =>  h1h2
1778
     * h1\\\\h2 =>  h1\\h2  =>  h1\h2
1779
     */
1780
0
    if (comma && !comma_escape && c == ',') {
1781
0
      seen_comma = true;
1782
0
      break;
1783
0
    }
1784
0
    if (comma && !comma_escape && c == '\\') {
1785
0
      comma_escape = true;
1786
0
      continue;
1787
0
    }
1788
0
    comma_escape = false;
1789
0
    if (nrem == 0) {
1790
0
      return (tregion.length <= 256U) ? ISC_R_NOSPACE
1791
0
              : DNS_R_SYNTAX;
1792
0
    }
1793
0
    *t++ = c;
1794
0
    nrem--;
1795
0
  }
1796
1797
  /*
1798
   * Incomplete escape processing?
1799
   */
1800
0
  if (escape || (comma && comma_escape)) {
1801
0
    return DNS_R_SYNTAX;
1802
0
  }
1803
1804
0
  if (comma) {
1805
    /*
1806
     * Disallow empty ALPN at start (",h1" or "\,h1") or
1807
     * in the middle ("h1,,h2" or "h1\,\,h2").
1808
     */
1809
0
    if ((t - tregion.base - 1) == 0) {
1810
0
      return DNS_R_SYNTAX;
1811
0
    }
1812
1813
    /*
1814
     * Consume this ALPN and possible ending comma.
1815
     */
1816
0
    isc_textregion_consume(source, s - source->base);
1817
1818
    /*
1819
     * Disallow empty ALPN at end ("h1," or "h1\,").
1820
     */
1821
0
    if (seen_comma && source->length == 0) {
1822
0
      return DNS_R_SYNTAX;
1823
0
    }
1824
0
  }
1825
1826
0
  *tregion.base = (unsigned char)(t - tregion.base - 1);
1827
0
  isc_buffer_add(target, *tregion.base + 1);
1828
0
  return ISC_R_SUCCESS;
1829
0
}
1830
1831
static isc_result_t
1832
0
txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
1833
0
  return commatxt_fromtext(source, false, target);
1834
0
}
1835
1836
static isc_result_t
1837
0
txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) {
1838
0
  unsigned int n;
1839
0
  isc_region_t sregion;
1840
0
  isc_region_t tregion;
1841
1842
0
  isc_buffer_activeregion(source, &sregion);
1843
0
  if (sregion.length == 0) {
1844
0
    return ISC_R_UNEXPECTEDEND;
1845
0
  }
1846
0
  n = *sregion.base + 1;
1847
0
  if (n > sregion.length) {
1848
0
    return ISC_R_UNEXPECTEDEND;
1849
0
  }
1850
1851
0
  isc_buffer_availableregion(target, &tregion);
1852
0
  if (n > tregion.length) {
1853
0
    return ISC_R_NOSPACE;
1854
0
  }
1855
1856
0
  if (tregion.base != sregion.base) {
1857
0
    memmove(tregion.base, sregion.base, n);
1858
0
  }
1859
0
  isc_buffer_forward(source, n);
1860
0
  isc_buffer_add(target, n);
1861
0
  return ISC_R_SUCCESS;
1862
0
}
1863
1864
/*
1865
 * Conversion of TXT-like rdata fields without length limits.
1866
 */
1867
static isc_result_t
1868
0
multitxt_totext(isc_region_t *source, isc_buffer_t *target) {
1869
0
  unsigned int tl;
1870
0
  unsigned int n0, n;
1871
0
  unsigned char *sp;
1872
0
  char *tp;
1873
0
  isc_region_t region;
1874
1875
0
  isc_buffer_availableregion(target, &region);
1876
0
  sp = source->base;
1877
0
  tp = (char *)region.base;
1878
0
  tl = region.length;
1879
1880
0
  if (tl < 1) {
1881
0
    return ISC_R_NOSPACE;
1882
0
  }
1883
0
  *tp++ = '"';
1884
0
  tl--;
1885
0
  do {
1886
0
    n = source->length;
1887
0
    n0 = source->length - 1;
1888
1889
0
    while (n--) {
1890
0
      if (*sp < ' ' || *sp >= 0x7f) {
1891
0
        if (tl < 4) {
1892
0
          return ISC_R_NOSPACE;
1893
0
        }
1894
0
        *tp++ = '\\';
1895
0
        *tp++ = '0' + ((*sp / 100) % 10);
1896
0
        *tp++ = '0' + ((*sp / 10) % 10);
1897
0
        *tp++ = '0' + (*sp % 10);
1898
0
        sp++;
1899
0
        tl -= 4;
1900
0
        continue;
1901
0
      }
1902
      /* double quote, backslash */
1903
0
      if (*sp == '"' || *sp == '\\') {
1904
0
        if (tl < 2) {
1905
0
          return ISC_R_NOSPACE;
1906
0
        }
1907
0
        *tp++ = '\\';
1908
0
        tl--;
1909
0
      }
1910
0
      if (tl < 1) {
1911
0
        return ISC_R_NOSPACE;
1912
0
      }
1913
0
      *tp++ = *sp++;
1914
0
      tl--;
1915
0
    }
1916
0
    isc_region_consume(source, n0 + 1);
1917
0
  } while (source->length != 0);
1918
0
  if (tl < 1) {
1919
0
    return ISC_R_NOSPACE;
1920
0
  }
1921
0
  *tp++ = '"';
1922
0
  tl--;
1923
0
  POST(tl);
1924
0
  isc_buffer_add(target, (unsigned int)(tp - (char *)region.base));
1925
0
  return ISC_R_SUCCESS;
1926
0
}
1927
1928
static isc_result_t
1929
0
multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
1930
0
  isc_region_t tregion;
1931
0
  bool escape;
1932
0
  unsigned int n, nrem;
1933
0
  char *s;
1934
0
  unsigned char *t0, *t;
1935
0
  int d;
1936
0
  int c;
1937
1938
0
  s = source->base;
1939
0
  n = source->length;
1940
0
  escape = false;
1941
1942
0
  do {
1943
0
    isc_buffer_availableregion(target, &tregion);
1944
0
    t0 = t = tregion.base;
1945
0
    nrem = tregion.length;
1946
0
    if (nrem < 1) {
1947
0
      return ISC_R_NOSPACE;
1948
0
    }
1949
1950
0
    while (n != 0) {
1951
0
      --n;
1952
0
      c = (*s++) & 0xff;
1953
0
      if (escape && (d = decvalue((char)c)) != -1) {
1954
0
        c = d;
1955
0
        if (n == 0) {
1956
0
          return DNS_R_SYNTAX;
1957
0
        }
1958
0
        n--;
1959
0
        if ((d = decvalue(*s++)) != -1) {
1960
0
          c = c * 10 + d;
1961
0
        } else {
1962
0
          return DNS_R_SYNTAX;
1963
0
        }
1964
0
        if (n == 0) {
1965
0
          return DNS_R_SYNTAX;
1966
0
        }
1967
0
        n--;
1968
0
        if ((d = decvalue(*s++)) != -1) {
1969
0
          c = c * 10 + d;
1970
0
        } else {
1971
0
          return DNS_R_SYNTAX;
1972
0
        }
1973
0
        if (c > 255) {
1974
0
          return DNS_R_SYNTAX;
1975
0
        }
1976
0
      } else if (!escape && c == '\\') {
1977
0
        escape = true;
1978
0
        continue;
1979
0
      }
1980
0
      escape = false;
1981
0
      *t++ = c;
1982
0
      nrem--;
1983
0
      if (nrem == 0) {
1984
0
        break;
1985
0
      }
1986
0
    }
1987
0
    if (escape) {
1988
0
      return DNS_R_SYNTAX;
1989
0
    }
1990
1991
0
    isc_buffer_add(target, (unsigned int)(t - t0));
1992
0
  } while (n != 0);
1993
0
  return ISC_R_SUCCESS;
1994
0
}
1995
1996
static bool
1997
0
name_prefix(dns_name_t *name, const dns_name_t *origin, dns_name_t *target) {
1998
0
  int l1, l2;
1999
2000
0
  if (origin == NULL) {
2001
0
    goto return_false;
2002
0
  }
2003
2004
0
  if (dns_name_compare(origin, dns_rootname) == 0) {
2005
0
    goto return_false;
2006
0
  }
2007
2008
0
  if (!dns_name_issubdomain(name, origin)) {
2009
0
    goto return_false;
2010
0
  }
2011
2012
0
  l1 = dns_name_countlabels(name);
2013
0
  l2 = dns_name_countlabels(origin);
2014
2015
0
  if (l1 == l2) {
2016
0
    goto return_false;
2017
0
  }
2018
2019
  /* Master files should be case preserving. */
2020
0
  dns_name_getlabelsequence(name, l1 - l2, l2, target);
2021
0
  if (!dns_name_caseequal(origin, target)) {
2022
0
    goto return_false;
2023
0
  }
2024
2025
0
  dns_name_getlabelsequence(name, 0, l1 - l2, target);
2026
0
  return true;
2027
2028
0
return_false:
2029
0
  *target = *name;
2030
0
  return false;
2031
0
}
2032
2033
static isc_result_t
2034
0
str_totext(const char *source, isc_buffer_t *target) {
2035
0
  unsigned int l;
2036
0
  isc_region_t region;
2037
2038
0
  isc_buffer_availableregion(target, &region);
2039
0
  l = strlen(source);
2040
2041
0
  if (l > region.length) {
2042
0
    return ISC_R_NOSPACE;
2043
0
  }
2044
2045
0
  memmove(region.base, source, l);
2046
0
  isc_buffer_add(target, l);
2047
0
  return ISC_R_SUCCESS;
2048
0
}
2049
2050
static isc_result_t
2051
0
inet_totext(int af, uint32_t flags, isc_region_t *src, isc_buffer_t *target) {
2052
0
  char tmpbuf[64];
2053
2054
  /* Note - inet_ntop doesn't do size checking on its input. */
2055
0
  if (inet_ntop(af, src->base, tmpbuf, sizeof(tmpbuf)) == NULL) {
2056
0
    return ISC_R_NOSPACE;
2057
0
  }
2058
0
  if (strlen(tmpbuf) > isc_buffer_availablelength(target)) {
2059
0
    return ISC_R_NOSPACE;
2060
0
  }
2061
0
  isc_buffer_putstr(target, tmpbuf);
2062
2063
  /*
2064
   * An IPv6 address ending in "::" breaks YAML
2065
   * parsing, so append 0 in that case.
2066
   */
2067
0
  if (af == AF_INET6 && (flags & DNS_STYLEFLAG_YAML) != 0) {
2068
0
    isc_region_t r;
2069
0
    isc_buffer_usedregion(target, &r);
2070
0
    if (r.length > 0 && r.base[r.length - 1] == ':') {
2071
0
      if (isc_buffer_availablelength(target) == 0) {
2072
0
        return ISC_R_NOSPACE;
2073
0
      }
2074
0
      isc_buffer_putmem(target, (const unsigned char *)"0",
2075
0
            1);
2076
0
    }
2077
0
  }
2078
2079
0
  return ISC_R_SUCCESS;
2080
0
}
2081
2082
static bool
2083
0
buffer_empty(isc_buffer_t *source) {
2084
0
  return (source->current == source->active) ? true : false;
2085
0
}
2086
2087
static void
2088
0
buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region) {
2089
0
  isc_buffer_init(buffer, region->base, region->length);
2090
0
  isc_buffer_add(buffer, region->length);
2091
0
  isc_buffer_setactive(buffer, region->length);
2092
0
}
2093
2094
static isc_result_t
2095
0
uint32_tobuffer(uint32_t value, isc_buffer_t *target) {
2096
0
  isc_region_t region;
2097
2098
0
  isc_buffer_availableregion(target, &region);
2099
0
  if (region.length < 4) {
2100
0
    return ISC_R_NOSPACE;
2101
0
  }
2102
0
  isc_buffer_putuint32(target, value);
2103
0
  return ISC_R_SUCCESS;
2104
0
}
2105
2106
static isc_result_t
2107
0
uint16_tobuffer(uint32_t value, isc_buffer_t *target) {
2108
0
  isc_region_t region;
2109
2110
0
  if (value > 0xffff) {
2111
0
    return ISC_R_RANGE;
2112
0
  }
2113
0
  isc_buffer_availableregion(target, &region);
2114
0
  if (region.length < 2) {
2115
0
    return ISC_R_NOSPACE;
2116
0
  }
2117
0
  isc_buffer_putuint16(target, (uint16_t)value);
2118
0
  return ISC_R_SUCCESS;
2119
0
}
2120
2121
static isc_result_t
2122
0
uint8_tobuffer(uint32_t value, isc_buffer_t *target) {
2123
0
  isc_region_t region;
2124
2125
0
  if (value > 0xff) {
2126
0
    return ISC_R_RANGE;
2127
0
  }
2128
0
  isc_buffer_availableregion(target, &region);
2129
0
  if (region.length < 1) {
2130
0
    return ISC_R_NOSPACE;
2131
0
  }
2132
0
  isc_buffer_putuint8(target, (uint8_t)value);
2133
0
  return ISC_R_SUCCESS;
2134
0
}
2135
2136
static isc_result_t
2137
0
name_tobuffer(const dns_name_t *name, isc_buffer_t *target) {
2138
0
  isc_region_t r;
2139
0
  dns_name_toregion(name, &r);
2140
0
  return isc_buffer_copyregion(target, &r);
2141
0
}
2142
2143
static uint32_t
2144
0
uint32_fromregion(isc_region_t *region) {
2145
0
  uint32_t value;
2146
2147
0
  REQUIRE(region->length >= 4);
2148
0
  value = (uint32_t)region->base[0] << 24;
2149
0
  value |= (uint32_t)region->base[1] << 16;
2150
0
  value |= (uint32_t)region->base[2] << 8;
2151
0
  value |= (uint32_t)region->base[3];
2152
0
  return value;
2153
0
}
2154
2155
static uint16_t
2156
0
uint16_consume_fromregion(isc_region_t *region) {
2157
0
  uint16_t r = uint16_fromregion(region);
2158
2159
0
  isc_region_consume(region, 2);
2160
0
  return r;
2161
0
}
2162
2163
static uint16_t
2164
0
uint16_fromregion(isc_region_t *region) {
2165
0
  REQUIRE(region->length >= 2);
2166
2167
0
  return (region->base[0] << 8) | region->base[1];
2168
0
}
2169
2170
static uint8_t
2171
0
uint8_fromregion(isc_region_t *region) {
2172
0
  REQUIRE(region->length >= 1);
2173
2174
0
  return region->base[0];
2175
0
}
2176
2177
static uint8_t
2178
0
uint8_consume_fromregion(isc_region_t *region) {
2179
0
  uint8_t r = uint8_fromregion(region);
2180
2181
0
  isc_region_consume(region, 1);
2182
0
  return r;
2183
0
}
2184
2185
static isc_result_t
2186
0
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
2187
0
  isc_region_t tr;
2188
2189
0
  if (length == 0U) {
2190
0
    return ISC_R_SUCCESS;
2191
0
  }
2192
2193
0
  isc_buffer_availableregion(target, &tr);
2194
0
  if (length > tr.length) {
2195
0
    return ISC_R_NOSPACE;
2196
0
  }
2197
0
  if (tr.base != base) {
2198
0
    memmove(tr.base, base, length);
2199
0
  }
2200
0
  isc_buffer_add(target, length);
2201
0
  return ISC_R_SUCCESS;
2202
0
}
2203
2204
static int
2205
0
hexvalue(char value) {
2206
0
  int hexval = isc_hex_char(value);
2207
0
  if (hexval == 0) {
2208
0
    return -1;
2209
0
  } else {
2210
0
    return value - hexval;
2211
0
  }
2212
0
}
2213
2214
static int
2215
0
decvalue(char value) {
2216
0
  if (isdigit((unsigned char)value)) {
2217
0
    return value - '0';
2218
0
  } else {
2219
0
    return -1;
2220
0
  }
2221
0
}
2222
2223
static void
2224
default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *fmt,
2225
0
        ...) {
2226
0
  va_list ap;
2227
2228
0
  UNUSED(callbacks);
2229
2230
0
  va_start(ap, fmt);
2231
0
  vfprintf(stderr, fmt, ap);
2232
0
  va_end(ap);
2233
0
  fprintf(stderr, "\n");
2234
0
}
2235
2236
static void
2237
0
fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) {
2238
0
  if (isc_lex_isfile(lexer) && callbacks != NULL) {
2239
0
    const char *name = isc_lex_getsourcename(lexer);
2240
0
    if (name == NULL) {
2241
0
      name = "UNKNOWN";
2242
0
    }
2243
0
    (*callbacks->warn)(callbacks,
2244
0
           "%s:%lu: file does not end with newline",
2245
0
           name, isc_lex_getsourceline(lexer));
2246
0
  }
2247
0
}
2248
2249
static void
2250
warn_badmx(isc_token_t *token, isc_lex_t *lexer,
2251
0
     dns_rdatacallbacks_t *callbacks) {
2252
0
  const char *file;
2253
0
  unsigned long line;
2254
2255
0
  if (lexer != NULL) {
2256
0
    file = isc_lex_getsourcename(lexer);
2257
0
    line = isc_lex_getsourceline(lexer);
2258
0
    (*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s", file,
2259
0
           line, DNS_AS_STR(*token),
2260
0
           isc_result_totext(DNS_R_MXISADDRESS));
2261
0
  }
2262
0
}
2263
2264
static void
2265
warn_badname(const dns_name_t *name, isc_lex_t *lexer,
2266
0
       dns_rdatacallbacks_t *callbacks) {
2267
0
  const char *file;
2268
0
  unsigned long line;
2269
0
  char namebuf[DNS_NAME_FORMATSIZE];
2270
2271
0
  if (lexer != NULL) {
2272
0
    file = isc_lex_getsourcename(lexer);
2273
0
    line = isc_lex_getsourceline(lexer);
2274
0
    dns_name_format(name, namebuf, sizeof(namebuf));
2275
0
    (*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s", file,
2276
0
           line, namebuf,
2277
0
           isc_result_totext(DNS_R_BADNAME));
2278
0
  }
2279
0
}
2280
2281
static void
2282
fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
2283
         dns_rdatacallbacks_t *callbacks, const char *name,
2284
0
         unsigned long line, isc_token_t *token, isc_result_t result) {
2285
0
  if (name == NULL) {
2286
0
    name = "UNKNOWN";
2287
0
  }
2288
2289
0
  if (token != NULL) {
2290
0
    switch (token->type) {
2291
0
    case isc_tokentype_eol:
2292
0
      (*callback)(callbacks, "%s: %s:%lu: near eol: %s",
2293
0
            "dns_rdata_fromtext", name, line,
2294
0
            isc_result_totext(result));
2295
0
      break;
2296
0
    case isc_tokentype_eof:
2297
0
      (*callback)(callbacks, "%s: %s:%lu: near eof: %s",
2298
0
            "dns_rdata_fromtext", name, line,
2299
0
            isc_result_totext(result));
2300
0
      break;
2301
0
    case isc_tokentype_number:
2302
0
      (*callback)(callbacks, "%s: %s:%lu: near %lu: %s",
2303
0
            "dns_rdata_fromtext", name, line,
2304
0
            token->value.as_ulong,
2305
0
            isc_result_totext(result));
2306
0
      break;
2307
0
    case isc_tokentype_string:
2308
0
    case isc_tokentype_qstring:
2309
0
      (*callback)(callbacks, "%s: %s:%lu: near '%s': %s",
2310
0
            "dns_rdata_fromtext", name, line,
2311
0
            DNS_AS_STR(*token),
2312
0
            isc_result_totext(result));
2313
0
      break;
2314
0
    default:
2315
0
      (*callback)(callbacks, "%s: %s:%lu: %s",
2316
0
            "dns_rdata_fromtext", name, line,
2317
0
            isc_result_totext(result));
2318
0
      break;
2319
0
    }
2320
0
  } else {
2321
0
    (*callback)(callbacks, "dns_rdata_fromtext: %s:%lu: %s", name,
2322
0
          line, isc_result_totext(result));
2323
0
  }
2324
0
}
2325
2326
dns_rdatatype_t
2327
0
dns_rdata_covers(dns_rdata_t *rdata) {
2328
0
  if (rdata->type == dns_rdatatype_rrsig) {
2329
0
    return covers_rrsig(rdata);
2330
0
  }
2331
0
  return covers_sig(rdata);
2332
0
}
2333
2334
void
2335
0
dns_rdata_exists(dns_rdata_t *rdata, dns_rdatatype_t type) {
2336
0
  REQUIRE(rdata != NULL);
2337
0
  REQUIRE(DNS_RDATA_INITIALIZED(rdata));
2338
2339
0
  rdata->data = NULL;
2340
0
  rdata->length = 0;
2341
0
  rdata->flags = DNS_RDATA_UPDATE;
2342
0
  rdata->type = type;
2343
0
  rdata->rdclass = dns_rdataclass_any;
2344
0
}
2345
2346
void
2347
0
dns_rdata_notexist(dns_rdata_t *rdata, dns_rdatatype_t type) {
2348
0
  REQUIRE(rdata != NULL);
2349
0
  REQUIRE(DNS_RDATA_INITIALIZED(rdata));
2350
2351
0
  rdata->data = NULL;
2352
0
  rdata->length = 0;
2353
0
  rdata->flags = DNS_RDATA_UPDATE;
2354
0
  rdata->type = type;
2355
0
  rdata->rdclass = dns_rdataclass_none;
2356
0
}
2357
2358
void
2359
0
dns_rdata_deleterrset(dns_rdata_t *rdata, dns_rdatatype_t type) {
2360
0
  REQUIRE(rdata != NULL);
2361
0
  REQUIRE(DNS_RDATA_INITIALIZED(rdata));
2362
2363
0
  rdata->data = NULL;
2364
0
  rdata->length = 0;
2365
0
  rdata->flags = DNS_RDATA_UPDATE;
2366
0
  rdata->type = type;
2367
0
  rdata->rdclass = dns_rdataclass_any;
2368
0
}
2369
2370
void
2371
0
dns_rdata_makedelete(dns_rdata_t *rdata) {
2372
0
  REQUIRE(rdata != NULL);
2373
2374
0
  rdata->rdclass = dns_rdataclass_none;
2375
0
}
2376
2377
const char *
2378
0
dns_rdata_updateop(dns_rdata_t *rdata, dns_section_t section) {
2379
0
  REQUIRE(rdata != NULL);
2380
0
  REQUIRE(DNS_RDATA_INITIALIZED(rdata));
2381
2382
0
  switch (section) {
2383
0
  case DNS_SECTION_PREREQUISITE:
2384
0
    switch (rdata->rdclass) {
2385
0
    case dns_rdataclass_none:
2386
0
      switch (rdata->type) {
2387
0
      case dns_rdatatype_any:
2388
0
        return "domain doesn't exist";
2389
0
      default:
2390
0
        return "rrset doesn't exist";
2391
0
      }
2392
0
    case dns_rdataclass_any:
2393
0
      switch (rdata->type) {
2394
0
      case dns_rdatatype_any:
2395
0
        return "domain exists";
2396
0
      default:
2397
0
        return "rrset exists (value independent)";
2398
0
      }
2399
0
    default:
2400
0
      return "rrset exists (value dependent)";
2401
0
    }
2402
0
  case DNS_SECTION_UPDATE:
2403
0
    switch (rdata->rdclass) {
2404
0
    case dns_rdataclass_none:
2405
0
      return "delete";
2406
0
    case dns_rdataclass_any:
2407
0
      switch (rdata->type) {
2408
0
      case dns_rdatatype_any:
2409
0
        return "delete all rrsets";
2410
0
      default:
2411
0
        return "delete rrset";
2412
0
      }
2413
0
    default:
2414
0
      return "add";
2415
0
    }
2416
0
  default:
2417
0
    break;
2418
0
  }
2419
0
  return "invalid";
2420
0
}
2421
2422
static bool
2423
0
svcb_ishttp(const char *s, size_t len) {
2424
  /*
2425
   * HTTP entries from:
2426
   *
2427
   * https://www.iana.org/assignments/tls-extensiontype-values/\
2428
   * tls-extensiontype-values.xhtml#alpn-protocol-ids
2429
   */
2430
0
  struct {
2431
0
    size_t len;
2432
0
    const char *value;
2433
0
  } http[] = { { 8, "http/0.9" }, { 8, "http/1.0" }, { 8, "http/1.1" },
2434
0
         { 2, "h2" }, { 3, "h2c" },    { 2, "h3" } };
2435
2436
0
  for (size_t i = 0; i < ARRAY_SIZE(http); i++) {
2437
0
    if (len == http[i].len && memcmp(s, http[i].value, len) == 0) {
2438
0
      return true;
2439
0
    }
2440
0
  }
2441
0
  return false;
2442
0
}
2443
2444
static bool
2445
0
svcb_hashttp(isc_textregion_t *alpn) {
2446
0
  while (alpn->length > 0) {
2447
0
    char c, *s;
2448
0
    unsigned char len = *alpn->base;
2449
2450
0
    isc_textregion_consume(alpn, 1);
2451
2452
    /*
2453
     * This has to detect "http/1.1", "h2" and "h3", etc.
2454
     * in a comma list.
2455
     */
2456
0
    s = alpn->base;
2457
0
    while (len-- > 0) {
2458
0
      c = *alpn->base;
2459
0
      isc_textregion_consume(alpn, 1);
2460
0
      if (c == ',') {
2461
0
        if (svcb_ishttp(s, (alpn->base - s) - 1)) {
2462
0
          return true;
2463
0
        }
2464
0
        s = alpn->base;
2465
0
      }
2466
0
    }
2467
0
    if (svcb_ishttp(s, alpn->base - s)) {
2468
0
      return true;
2469
0
    }
2470
0
  }
2471
0
  return false;
2472
0
}
2473
2474
isc_result_t
2475
0
dns_rdata_checksvcb(const dns_name_t *owner, const dns_rdata_t *rdata) {
2476
0
  dns_rdata_in_svcb_t svcb;
2477
0
  isc_result_t result;
2478
2479
0
  REQUIRE(owner != NULL);
2480
0
  REQUIRE(rdata != NULL);
2481
0
  REQUIRE(rdata->type == dns_rdatatype_svcb);
2482
0
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
2483
2484
0
  result = dns_rdata_tostruct(rdata, &svcb, NULL);
2485
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
2486
2487
  /*
2488
   * Check that Alias Mode records don't have SvcParamKeys.
2489
   */
2490
0
  if (svcb.priority == 0 && svcb.svclen != 0) {
2491
0
    return DNS_R_HAVEPARMKEYS;
2492
0
  }
2493
2494
0
  if (dns_name_isdnssvcb(owner)) {
2495
0
    isc_region_t r = { .base = svcb.svc, .length = svcb.svclen };
2496
0
    isc_textregion_t alpn;
2497
0
    uint16_t key = 0, len = 0;
2498
2499
    /* Check for ALPN (key1) */
2500
0
    while (r.length > 0) {
2501
0
      key = uint16_fromregion(&r);
2502
0
      isc_region_consume(&r, 2);
2503
0
      len = uint16_fromregion(&r);
2504
0
      isc_region_consume(&r, 2);
2505
0
      if (key >= SVCB_ALPN_KEY) {
2506
0
        break;
2507
0
      }
2508
0
      isc_region_consume(&r, len);
2509
0
    }
2510
0
    if (key != SVCB_ALPN_KEY) {
2511
0
      return DNS_R_NOALPN;
2512
0
    }
2513
0
    alpn = (isc_textregion_t){ .base = (char *)r.base,
2514
0
             .length = len };
2515
0
    isc_region_consume(&r, len);
2516
0
    if (svcb_hashttp(&alpn)) {
2517
      /* Check for DOHPATH (key7) */
2518
0
      while (r.length > 0) {
2519
0
        key = uint16_fromregion(&r);
2520
0
        isc_region_consume(&r, 2);
2521
0
        len = uint16_fromregion(&r);
2522
0
        isc_region_consume(&r, 2);
2523
0
        if (key >= SVCB_DOHPATH_KEY) {
2524
0
          break;
2525
0
        }
2526
0
        isc_region_consume(&r, len);
2527
0
      }
2528
0
      if (key != SVCB_DOHPATH_KEY) {
2529
0
        return DNS_R_NODOHPATH;
2530
0
      }
2531
0
    }
2532
0
  }
2533
0
  return ISC_R_SUCCESS;
2534
0
}