Coverage Report

Created: 2026-09-01 06:32

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
19.1M
  do {                                               \
57
19.1M
    isc_result_t _r = (x);                     \
58
19.1M
    if (_r != ISC_R_SUCCESS) {                 \
59
9.69k
      isc_lex_ungettoken(lexer, &token); \
60
9.69k
      return (_r);                       \
61
9.69k
    }                                          \
62
19.1M
  } while (0)
63
64
#define CHECKTOK(op)                                       \
65
614
  do {                                               \
66
614
    result = (op);                             \
67
614
    if (result != ISC_R_SUCCESS) {             \
68
614
      isc_lex_ungettoken(lexer, &token); \
69
614
      goto cleanup;                      \
70
614
    }                                          \
71
614
  } while (0)
72
73
12.3M
#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
1.09M
#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
24.4k
#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
40.0k
#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
3.14k
#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
229
#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
3.70k
#define NS_INT16SZ 2
325
/*% IPv6 Address Size */
326
3.76k
#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
985
locator_pton(const char *src, unsigned char *dst) {
344
985
  unsigned char tmp[NS_LOCATORSZ];
345
985
  unsigned char *tp = tmp, *endp;
346
985
  int ch, seen_xdigits;
347
985
  unsigned int val, hexval;
348
349
985
  memset(tp, '\0', NS_LOCATORSZ);
350
985
  endp = tp + NS_LOCATORSZ;
351
985
  seen_xdigits = 0;
352
985
  val = 0;
353
8.96k
  while ((ch = *src++) != '\0') {
354
8.01k
    hexval = isc_hex_char(ch);
355
8.01k
    if (hexval != 0) {
356
5.08k
      val <<= 4;
357
5.08k
      val |= (ch - hexval);
358
5.08k
      if (++seen_xdigits > 4) {
359
4
        return 0;
360
4
      }
361
5.07k
      continue;
362
5.08k
    }
363
2.92k
    if (ch == ':') {
364
2.90k
      if (!seen_xdigits) {
365
4
        return 0;
366
4
      }
367
2.90k
      if (tp + NS_INT16SZ > endp) {
368
4
        return 0;
369
4
      }
370
2.90k
      *tp++ = (unsigned char)(val >> 8) & 0xff;
371
2.90k
      *tp++ = (unsigned char)val & 0xff;
372
2.90k
      seen_xdigits = 0;
373
2.90k
      val = 0;
374
2.90k
      continue;
375
2.90k
    }
376
21
    return 0;
377
2.92k
  }
378
952
  if (seen_xdigits) {
379
801
    if (tp + NS_INT16SZ > endp) {
380
4
      return 0;
381
4
    }
382
797
    *tp++ = (unsigned char)(val >> 8) & 0xff;
383
797
    *tp++ = (unsigned char)val & 0xff;
384
797
  }
385
948
  if (tp != endp) {
386
52
    return 0;
387
52
  }
388
896
  memmove(dst, tmp, NS_LOCATORSZ);
389
896
  return 1;
390
948
}
391
392
static void
393
2.10k
name_duporclone(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
394
2.10k
  if (mctx != NULL) {
395
0
    dns_name_dup(source, mctx, target);
396
2.10k
  } else {
397
2.10k
    dns_name_clone(source, target);
398
2.10k
  }
399
2.10k
}
400
401
static void *
402
3.10k
mem_maybedup(isc_mem_t *mctx, void *source, size_t length) {
403
3.10k
  void *copy = NULL;
404
405
3.10k
  REQUIRE(source != NULL);
406
407
3.10k
  if (mctx == NULL) {
408
3.10k
    return source;
409
3.10k
  }
410
411
0
  copy = isc_mem_allocate(mctx, length);
412
0
  memmove(copy, source, length);
413
414
0
  return copy;
415
3.10k
}
416
417
static isc_result_t
418
214k
typemap_fromtext(isc_lex_t *lexer, isc_buffer_t *target, bool allow_empty) {
419
214k
  isc_token_t token;
420
214k
  unsigned char bm[8 * 1024]; /* 64k bits */
421
214k
  dns_rdatatype_t covered, max_used;
422
214k
  int octet;
423
214k
  unsigned int max_octet, newend, end;
424
214k
  int window;
425
214k
  bool first = true;
426
427
214k
  max_used = 0;
428
214k
  bm[0] = 0;
429
214k
  end = 0;
430
431
455k
  do {
432
455k
    RETERR(isc_lex_getmastertoken(lexer, &token,
433
455k
                isc_tokentype_string, true));
434
455k
    if (token.type != isc_tokentype_string) {
435
214k
      break;
436
214k
    }
437
241k
    RETTOK(dns_rdatatype_fromtext(&covered,
438
241k
                &token.value.as_textregion));
439
240k
    if (covered > max_used) {
440
160k
      newend = covered / 8;
441
160k
      if (newend > end) {
442
80.2k
        memset(&bm[end + 1], 0, newend - end);
443
80.2k
        end = newend;
444
80.2k
      }
445
160k
      max_used = covered;
446
160k
    }
447
240k
    bm[covered / 8] |= (0x80 >> (covered % 8));
448
240k
    first = false;
449
240k
  } while (1);
450
214k
  isc_lex_ungettoken(lexer, &token);
451
214k
  if (!allow_empty && first) {
452
10
    return DNS_R_FORMERR;
453
10
  }
454
455
6.79M
  for (window = 0; window < 256; window++) {
456
6.79M
    if (max_used < window * 256) {
457
212k
      break;
458
212k
    }
459
460
6.58M
    max_octet = max_used - (window * 256);
461
6.58M
    if (max_octet >= 256) {
462
6.36M
      max_octet = 31;
463
6.36M
    } else {
464
214k
      max_octet /= 8;
465
214k
    }
466
467
    /*
468
     * Find if we have a type in this window.
469
     */
470
210M
    for (octet = max_octet; octet >= 0; octet--) {
471
204M
      if (bm[window * 32 + octet] != 0) {
472
210k
        break;
473
210k
      }
474
204M
    }
475
6.58M
    if (octet < 0) {
476
6.37M
      continue;
477
6.37M
    }
478
210k
    RETERR(uint8_tobuffer(window, target));
479
210k
    RETERR(uint8_tobuffer(octet + 1, target));
480
210k
    RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1));
481
210k
  }
482
214k
  return ISC_R_SUCCESS;
483
214k
}
484
485
static isc_result_t
486
typemap_totext(isc_region_t *sr, dns_rdata_textctx_t *tctx,
487
6.21k
         isc_buffer_t *target) {
488
6.21k
  unsigned int i, j, k;
489
6.21k
  unsigned int window, len;
490
6.21k
  bool first = true;
491
492
10.9k
  for (i = 0; i < sr->length; i += len) {
493
4.77k
    if (tctx != NULL &&
494
1.57k
        (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
495
136
    {
496
136
      RETERR(str_totext(tctx->linebreak, target));
497
136
      first = true;
498
136
    }
499
4.77k
    INSIST(i + 2 <= sr->length);
500
4.77k
    window = sr->base[i];
501
4.77k
    len = sr->base[i + 1];
502
4.77k
    INSIST(len > 0 && len <= 32);
503
4.77k
    i += 2;
504
4.77k
    INSIST(i + len <= sr->length);
505
34.3k
    for (j = 0; j < len; j++) {
506
29.5k
      dns_rdatatype_t t;
507
29.5k
      if (sr->base[i + j] == 0) {
508
6.45k
        continue;
509
6.45k
      }
510
207k
      for (k = 0; k < 8; k++) {
511
184k
        if ((sr->base[i + j] & (0x80 >> k)) == 0) {
512
103k
          continue;
513
103k
        }
514
81.1k
        t = window * 256 + j * 8 + k;
515
81.1k
        if (!first) {
516
77.8k
          RETERR(str_totext(" ", target));
517
77.8k
        }
518
81.1k
        first = false;
519
81.1k
        if (dns_rdatatype_isknown(t)) {
520
23.9k
          RETERR(dns_rdatatype_totext(t, target));
521
57.2k
        } else {
522
57.2k
          char buf[sizeof("TYPE65535")];
523
57.2k
          snprintf(buf, sizeof(buf), "TYPE%u", t);
524
57.2k
          RETERR(str_totext(buf, target));
525
57.2k
        }
526
81.1k
      }
527
23.0k
    }
528
4.77k
  }
529
6.21k
  return ISC_R_SUCCESS;
530
6.21k
}
531
532
static isc_result_t
533
8.25k
typemap_test(isc_region_t *sr, bool allow_empty) {
534
8.25k
  unsigned int window, lastwindow = 0;
535
8.25k
  unsigned int len;
536
8.25k
  bool first = true;
537
8.25k
  unsigned int i;
538
539
14.4k
  for (i = 0; i < sr->length; i += len) {
540
    /*
541
     * Check for overflow.
542
     */
543
6.58k
    if (i + 2 > sr->length) {
544
18
      RETERR(DNS_R_FORMERR);
545
0
    }
546
6.56k
    window = sr->base[i];
547
6.56k
    len = sr->base[i + 1];
548
6.56k
    i += 2;
549
    /*
550
     * Check that bitmap windows are in the correct order.
551
     */
552
6.56k
    if (!first && window <= lastwindow) {
553
89
      RETERR(DNS_R_FORMERR);
554
0
    }
555
    /*
556
     * Check for legal lengths.
557
     */
558
6.47k
    if (len < 1 || len > 32) {
559
164
      RETERR(DNS_R_FORMERR);
560
0
    }
561
    /*
562
     * Check for overflow.
563
     */
564
6.31k
    if (i + len > sr->length) {
565
83
      RETERR(DNS_R_FORMERR);
566
0
    }
567
    /*
568
     * The last octet of the bitmap must be non zero.
569
     */
570
6.23k
    if (sr->base[i + len - 1] == 0) {
571
15
      RETERR(DNS_R_FORMERR);
572
0
    }
573
6.21k
    lastwindow = window;
574
6.21k
    first = false;
575
6.21k
  }
576
7.88k
  if (i != sr->length) {
577
0
    return DNS_R_EXTRADATA;
578
0
  }
579
7.88k
  if (!allow_empty && first) {
580
4
    RETERR(DNS_R_FORMERR);
581
0
  }
582
7.87k
  return ISC_R_SUCCESS;
583
7.88k
}
584
585
static isc_result_t
586
2.10k
check_private(isc_buffer_t *source, dns_secalg_t alg) {
587
2.10k
  isc_region_t sr;
588
2.10k
  if (alg == DNS_KEYALG_PRIVATEDNS) {
589
1.23k
    dns_fixedname_t fixed;
590
591
1.23k
    RETERR(dns_name_fromwire(dns_fixedname_initname(&fixed), source,
592
1.23k
           DNS_DECOMPRESS_NEVER, NULL));
593
1.21k
  } 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
874
    const unsigned char *in = NULL;
600
874
    ASN1_OBJECT *obj = NULL;
601
602
874
    isc_buffer_activeregion(source, &sr);
603
874
    if (sr.length < 1 || (unsigned int)*sr.base + 1 > sr.length) {
604
33
      RETERR(DNS_R_FORMERR);
605
0
    }
606
841
    in = sr.base + 1;
607
841
    obj = d2i_ASN1_OBJECT(NULL, &in, *sr.base);
608
841
    if (obj == NULL) {
609
89
      ERR_clear_error();
610
89
      RETERR(DNS_R_FORMERR);
611
0
    }
612
752
    ASN1_OBJECT_free(obj);
613
752
    if ((in - sr.base) != (*sr.base + 1)) {
614
19
      RETERR(DNS_R_FORMERR);
615
0
    }
616
752
  }
617
1.94k
  return ISC_R_SUCCESS;
618
2.10k
}
619
620
/*
621
 * A relative URI template that has a "dns" variable.
622
 */
623
static bool
624
3.88k
validate_dohpath(isc_region_t *region) {
625
3.88k
  const unsigned char *p;
626
3.88k
  const unsigned char *v = NULL;
627
3.88k
  const unsigned char *n = NULL;
628
3.88k
  unsigned char c;
629
3.88k
  bool dns = false;
630
3.88k
  bool wasop = false;
631
3.88k
  enum {
632
3.88k
    path,
633
3.88k
    variable,
634
3.88k
    percent1,
635
3.88k
    percent2,
636
3.88k
    variable_percent1,
637
3.88k
    variable_percent2,
638
3.88k
    prefix,
639
3.88k
    explode
640
3.88k
  } state = path;
641
642
3.88k
  if (region->length == 0 || *region->base != '/' ||
643
3.85k
      !isc_utf8_valid(region->base, region->length))
644
224
  {
645
224
    return false;
646
224
  }
647
648
  /*
649
   * RFC 6570 URI Template check + "dns" variable.
650
   */
651
3.66k
  p = region->base;
652
216k
  while (p < region->base + region->length) {
653
212k
    switch (state) {
654
69.7k
    case path:
655
69.7k
      switch (*p++) {
656
9.66k
      case '{': /*}*/
657
9.66k
        state = variable;
658
9.66k
        wasop = false;
659
9.66k
        v = p;
660
9.66k
        break;
661
979
      case '%':
662
979
        state = percent1;
663
979
        break;
664
59.0k
      default:
665
59.0k
        break;
666
69.7k
      }
667
69.7k
      break;
668
108k
    case variable:
669
108k
      c = *p++;
670
108k
      switch (c) {
671
2.33k
      case '+':
672
3.21k
      case '#':
673
6.50k
      case '.':
674
9.09k
      case '/':
675
9.74k
      case ';':
676
11.2k
      case '?':
677
12.4k
      case '&':
678
        /* Operators. */
679
12.4k
        if (p != v + 1 || wasop) {
680
106
          return false;
681
106
        }
682
12.3k
        wasop = true;
683
12.3k
        v = p;
684
12.3k
        break;
685
7
      case '=':
686
11
      case '!':
687
17
      case '@':
688
22
      case '|':
689
        /* Reserved operators. */
690
22
        return false;
691
2.42k
      case '*':
692
6.16k
      case ':':
693
11.5k
      case '}':
694
21.0k
      case ',':
695
        /* Found the end of the variable name. */
696
21.0k
        if (p == (v + 1)) {
697
38
          return false;
698
38
        }
699
        /* 'p' has been incremented so 4 not 3 */
700
21.0k
        if ((p - v) == 4 && memcmp(v, "dns", 3) == 0) {
701
3.92k
          dns = true;
702
3.92k
        }
703
21.0k
        switch (c) {
704
3.73k
        case ':':
705
3.73k
          state = prefix;
706
3.73k
          n = p;
707
3.73k
          break;
708
5.42k
        case /*{*/ '}':
709
5.42k
          state = path;
710
5.42k
          break;
711
2.41k
        case '*':
712
2.41k
          state = explode;
713
2.41k
          break;
714
9.45k
        case ',':
715
9.45k
          wasop = false;
716
9.45k
          v = p;
717
9.45k
          break;
718
21.0k
        }
719
21.0k
        break;
720
21.0k
      case '%':
721
        /* Percent encoded variable name. */
722
791
        state = variable_percent1;
723
791
        break;
724
74.1k
      default:
725
        /* Valid variable name character? */
726
74.1k
        if (c != '_' && !isalnum(c)) {
727
37
          return false;
728
37
        }
729
74.0k
        break;
730
108k
      }
731
108k
      break;
732
108k
    case explode:
733
2.40k
      switch (*p++) {
734
1.09k
      case ',':
735
1.09k
        state = variable;
736
1.09k
        wasop = false;
737
1.09k
        v = p;
738
1.09k
        break;
739
1.30k
      case /*}*/ '}':
740
1.30k
        state = path;
741
1.30k
        break;
742
6
      default:
743
6
        return false;
744
2.40k
      }
745
2.39k
      break;
746
    /* Check % encoding */
747
2.39k
    case percent1:
748
1.90k
    case percent2:
749
2.68k
    case variable_percent1:
750
3.45k
    case variable_percent2:
751
      /* bad percent encoding? */
752
3.45k
      if (!isxdigit(*p++)) {
753
20
        return false;
754
20
      }
755
3.43k
      if (state == percent1) {
756
958
        state = percent2;
757
2.47k
      } else if (state == percent2) {
758
934
        state = path;
759
1.53k
      } else if (state == variable_percent1) {
760
778
        state = variable_percent2;
761
778
      } else {
762
760
        state = variable;
763
760
      }
764
3.43k
      break;
765
28.6k
    case prefix:
766
28.6k
      c = *p++;
767
28.6k
      if (!isdigit(c)) {
768
        /* valid number range [1..9999] */
769
3.68k
        if ((p == n + 1) || (p - n) > 5 || *n == '0') {
770
29
          return false;
771
29
        }
772
3.65k
        switch (c) {
773
1.29k
        case ',':
774
1.29k
          state = variable;
775
1.29k
          wasop = false;
776
1.29k
          break;
777
2.35k
        case /*{*/ '}':
778
2.35k
          state = path;
779
2.35k
          break;
780
6
        default:
781
6
          return false;
782
3.65k
        }
783
3.65k
      }
784
28.5k
      break;
785
212k
    }
786
212k
  }
787
3.39k
  return state == path && dns;
788
3.66k
}
789
790
#include "code.h"
791
792
#define META   0x0001
793
#define RESERVED 0x0002
794
795
/***
796
 *** Initialization
797
 ***/
798
799
void
800
140M
dns_rdata_init(dns_rdata_t *rdata) {
801
140M
  REQUIRE(rdata != NULL);
802
803
140M
  rdata->data = NULL;
804
140M
  rdata->length = 0;
805
140M
  rdata->rdclass = 0;
806
140M
  rdata->type = dns_rdatatype_none;
807
140M
  rdata->flags = 0;
808
140M
  ISC_LINK_INIT(rdata, link);
809
  /* ISC_LIST_INIT(rdata->list); */
810
140M
}
811
812
void
813
10.1M
dns_rdata_reset(dns_rdata_t *rdata) {
814
10.1M
  REQUIRE(rdata != NULL);
815
816
10.1M
  REQUIRE(!ISC_LINK_LINKED(rdata, link));
817
10.1M
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
818
819
10.1M
  rdata->data = NULL;
820
10.1M
  rdata->length = 0;
821
10.1M
  rdata->rdclass = 0;
822
10.1M
  rdata->type = dns_rdatatype_none;
823
10.1M
  rdata->flags = 0;
824
10.1M
}
825
826
/***
827
 ***
828
 ***/
829
830
void
831
10.5M
dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) {
832
10.5M
  REQUIRE(src != NULL);
833
10.5M
  REQUIRE(target != NULL);
834
835
10.5M
  REQUIRE(DNS_RDATA_INITIALIZED(target));
836
837
10.5M
  REQUIRE(DNS_RDATA_VALIDFLAGS(src));
838
10.5M
  REQUIRE(DNS_RDATA_VALIDFLAGS(target));
839
840
10.5M
  target->data = src->data;
841
10.5M
  target->length = src->length;
842
10.5M
  target->rdclass = src->rdclass;
843
10.5M
  target->type = src->type;
844
10.5M
  target->flags = src->flags;
845
10.5M
}
846
847
/***
848
 *** Comparisons
849
 ***/
850
851
int
852
253M
dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
853
253M
  int result = 0;
854
253M
  bool use_default = false;
855
856
253M
  REQUIRE(rdata1 != NULL);
857
253M
  REQUIRE(rdata2 != NULL);
858
253M
  REQUIRE(rdata1->length == 0 || rdata1->data != NULL);
859
253M
  REQUIRE(rdata2->length == 0 || rdata2->data != NULL);
860
253M
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
861
253M
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
862
863
253M
  if (rdata1->rdclass != rdata2->rdclass) {
864
0
    return rdata1->rdclass < rdata2->rdclass ? -1 : 1;
865
0
  }
866
867
253M
  if (rdata1->type != rdata2->type) {
868
0
    return rdata1->type < rdata2->type ? -1 : 1;
869
0
  }
870
871
253M
  COMPARESWITCH
872
873
253M
  if (use_default) {
874
5.74k
    isc_region_t r1;
875
5.74k
    isc_region_t r2;
876
877
5.74k
    dns_rdata_toregion(rdata1, &r1);
878
5.74k
    dns_rdata_toregion(rdata2, &r2);
879
5.74k
    result = isc_region_compare(&r1, &r2);
880
5.74k
  }
881
253M
  return result;
882
253M
}
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
139M
         dns_rdatatype_t type, isc_region_t *r) {
924
139M
  REQUIRE(rdata != NULL);
925
139M
  REQUIRE(DNS_RDATA_INITIALIZED(rdata));
926
139M
  REQUIRE(r != NULL);
927
928
139M
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
929
930
139M
  rdata->data = r->base;
931
139M
  rdata->length = r->length;
932
139M
  rdata->rdclass = rdclass;
933
139M
  rdata->type = type;
934
139M
  rdata->flags = 0;
935
139M
}
936
937
void
938
465M
dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) {
939
465M
  REQUIRE(rdata != NULL);
940
465M
  REQUIRE(r != NULL);
941
465M
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
942
943
465M
  r->base = rdata->data;
944
465M
  r->length = rdata->length;
945
465M
}
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
723k
       dns_decompress_t dctx, isc_buffer_t *target) {
951
723k
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
952
723k
  isc_region_t region;
953
723k
  isc_buffer_t ss;
954
723k
  isc_buffer_t st;
955
723k
  bool use_default = false;
956
723k
  uint32_t activelength;
957
723k
  unsigned int length;
958
959
723k
  if (rdata != NULL) {
960
327k
    REQUIRE(DNS_RDATA_INITIALIZED(rdata));
961
327k
    REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
962
327k
  }
963
723k
  REQUIRE(source != NULL);
964
723k
  REQUIRE(target != NULL);
965
966
723k
  if (type == dns_rdatatype_none) {
967
9
    return DNS_R_FORMERR;
968
9
  }
969
970
723k
  ss = *source;
971
723k
  st = *target;
972
973
723k
  activelength = isc_buffer_activelength(source);
974
723k
  INSIST(activelength < 65536);
975
976
723k
  FROMWIRESWITCH
977
978
723k
  if (use_default) {
979
93.4k
    if (activelength > isc_buffer_availablelength(target)) {
980
549
      result = ISC_R_NOSPACE;
981
92.8k
    } else {
982
92.8k
      isc_buffer_putmem(target, isc_buffer_current(source),
983
92.8k
            activelength);
984
92.8k
      isc_buffer_forward(source, activelength);
985
92.8k
      result = ISC_R_SUCCESS;
986
92.8k
    }
987
93.4k
  }
988
989
  /*
990
   * Reject any rdata that expands out to more than DNS_RDATA_MAXLENGTH
991
   * as we cannot transmit it.
992
   */
993
723k
  length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
994
723k
  if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
995
8
    result = DNS_R_FORMERR;
996
8
  }
997
998
  /*
999
   * We should have consumed all of our buffer.
1000
   */
1001
723k
  if (result == ISC_R_SUCCESS && !buffer_empty(source)) {
1002
462
    result = DNS_R_EXTRADATA;
1003
462
  }
1004
1005
723k
  if (rdata != NULL && result == ISC_R_SUCCESS) {
1006
275k
    region.base = isc_buffer_used(&st);
1007
275k
    region.length = length;
1008
275k
    dns_rdata_fromregion(rdata, rdclass, type, &region);
1009
275k
  }
1010
1011
723k
  if (result != ISC_R_SUCCESS) {
1012
53.8k
    *source = ss;
1013
53.8k
    *target = st;
1014
53.8k
  }
1015
723k
  return result;
1016
723k
}
1017
1018
isc_result_t
1019
dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx,
1020
122k
     isc_buffer_t *target) {
1021
122k
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1022
122k
  bool use_default = false;
1023
122k
  isc_region_t tr;
1024
122k
  isc_buffer_t st;
1025
1026
122k
  REQUIRE(rdata != NULL);
1027
122k
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1028
1029
  /*
1030
   * Some DynDNS meta-RRs have empty rdata.
1031
   */
1032
122k
  if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
1033
1.22k
    INSIST(rdata->length == 0);
1034
1.22k
    return ISC_R_SUCCESS;
1035
1.22k
  }
1036
1037
121k
  st = *target;
1038
1039
121k
  TOWIRESWITCH
1040
1041
121k
  if (use_default) {
1042
44.1k
    isc_buffer_availableregion(target, &tr);
1043
44.1k
    if (tr.length < rdata->length) {
1044
1
      return ISC_R_NOSPACE;
1045
1
    }
1046
44.1k
    memmove(tr.base, rdata->data, rdata->length);
1047
44.1k
    isc_buffer_add(target, rdata->length);
1048
44.1k
    return ISC_R_SUCCESS;
1049
44.1k
  }
1050
77.1k
  if (result != ISC_R_SUCCESS) {
1051
131
    *target = st;
1052
131
    dns_compress_rollback(cctx, target->used);
1053
131
  }
1054
77.1k
  return result;
1055
121k
}
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
395k
         dns_rdatatype_t type) {
1065
395k
  isc_result_t result;
1066
1067
395k
  isc_buffer_setactive(src, isc_buffer_usedlength(src));
1068
395k
  result = dns_rdata_fromwire(NULL, rdclass, type, src,
1069
395k
            DNS_DECOMPRESS_NEVER, dest);
1070
1071
395k
  return result;
1072
395k
}
1073
1074
static isc_result_t
1075
unknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type,
1076
400k
     isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target) {
1077
400k
  isc_result_t result;
1078
400k
  isc_buffer_t *buf = NULL;
1079
400k
  isc_token_t token;
1080
1081
400k
  if (type == dns_rdatatype_none || dns_rdatatype_ismeta(type)) {
1082
20
    return DNS_R_METATYPE;
1083
20
  }
1084
1085
400k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
1086
400k
              false));
1087
400k
  if (token.value.as_ulong > 65535U) {
1088
29
    return ISC_R_RANGE;
1089
29
  }
1090
400k
  isc_buffer_allocate(mctx, &buf, token.value.as_ulong);
1091
1092
400k
  if (token.value.as_ulong != 0U) {
1093
396k
    CHECK(isc_hex_tobuffer(lexer, buf,
1094
396k
               (unsigned int)token.value.as_ulong));
1095
396k
    if (isc_buffer_usedlength(buf) != token.value.as_ulong) {
1096
0
      CLEANUP(ISC_R_UNEXPECTEDEND);
1097
0
    }
1098
396k
  }
1099
1100
400k
  if (dns_rdatatype_isknown(type)) {
1101
395k
    result = rdata_validate(buf, target, rdclass, type);
1102
395k
  } else {
1103
4.40k
    isc_region_t r;
1104
4.40k
    isc_buffer_usedregion(buf, &r);
1105
4.40k
    result = isc_buffer_copyregion(target, &r);
1106
4.40k
  }
1107
400k
  CHECK(result);
1108
1109
399k
  isc_buffer_free(&buf);
1110
399k
  return ISC_R_SUCCESS;
1111
1112
1.36k
cleanup:
1113
1.36k
  isc_buffer_free(&buf);
1114
1.36k
  return result;
1115
400k
}
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
10.3M
       dns_rdatacallbacks_t *callbacks) {
1123
10.3M
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1124
10.3M
  isc_region_t region;
1125
10.3M
  isc_buffer_t st;
1126
10.3M
  isc_token_t token;
1127
10.3M
  unsigned int lexoptions = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
1128
10.3M
          ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
1129
10.3M
  char *name;
1130
10.3M
  unsigned long line;
1131
10.3M
  void (*callback)(dns_rdatacallbacks_t *, const char *, ...);
1132
10.3M
  isc_result_t tresult;
1133
10.3M
  unsigned int length;
1134
10.3M
  bool unknown;
1135
1136
10.3M
  REQUIRE(origin == NULL || dns_name_isabsolute(origin));
1137
10.3M
  if (rdata != NULL) {
1138
10.3M
    REQUIRE(DNS_RDATA_INITIALIZED(rdata));
1139
10.3M
    REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1140
10.3M
  }
1141
10.3M
  if (callbacks != NULL) {
1142
10.3M
    REQUIRE(callbacks->warn != NULL);
1143
10.3M
    REQUIRE(callbacks->error != NULL);
1144
10.3M
  }
1145
1146
10.3M
  st = *target;
1147
1148
10.3M
  if (callbacks != NULL) {
1149
10.3M
    callback = callbacks->error;
1150
10.3M
  } else {
1151
12.0k
    callback = default_fromtext_callback;
1152
12.0k
  }
1153
1154
10.3M
  result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
1155
10.3M
          true);
1156
10.3M
  if (result != ISC_R_SUCCESS) {
1157
91
    name = isc_lex_getsourcename(lexer);
1158
91
    line = isc_lex_getsourceline(lexer);
1159
91
    fromtext_error(callback, callbacks, name, line, NULL, result);
1160
91
    return result;
1161
91
  }
1162
1163
10.3M
  unknown = false;
1164
10.3M
  if (token.type == isc_tokentype_string &&
1165
10.2M
      strcmp(DNS_AS_STR(token), "\\#") == 0)
1166
414k
  {
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
414k
    if (type == dns_rdatatype_txt) {
1173
14.6k
      result = isc_lex_getmastertoken(
1174
14.6k
        lexer, &token, isc_tokentype_number, false);
1175
14.6k
      if (result == ISC_R_SUCCESS) {
1176
353
        isc_lex_ungettoken(lexer, &token);
1177
353
      }
1178
14.6k
    }
1179
1180
414k
    if (result == ISC_R_SUCCESS) {
1181
400k
      unknown = true;
1182
400k
      result = unknown_fromtext(rdclass, type, lexer, mctx,
1183
400k
              target);
1184
400k
    } else {
1185
14.3k
      options |= DNS_RDATA_UNKNOWNESCAPE;
1186
14.3k
    }
1187
9.90M
  } else {
1188
9.90M
    isc_lex_ungettoken(lexer, &token);
1189
9.90M
  }
1190
1191
10.3M
  if (!unknown) {
1192
9.92M
    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
9.92M
  }
1200
14.7M
  do {
1201
14.7M
    name = isc_lex_getsourcename(lexer);
1202
14.7M
    line = isc_lex_getsourceline(lexer);
1203
14.7M
    tresult = isc_lex_gettoken(lexer, lexoptions, &token);
1204
14.7M
    if (tresult != ISC_R_SUCCESS) {
1205
4.66k
      if (result == ISC_R_SUCCESS) {
1206
406
        result = tresult;
1207
406
      }
1208
4.66k
      if (callback != NULL) {
1209
1.08k
        fromtext_error(callback, callbacks, name, line,
1210
1.08k
                 NULL, result);
1211
1.08k
      }
1212
4.66k
      break;
1213
14.7M
    } else if (token.type != isc_tokentype_eol &&
1214
14.3M
         token.type != isc_tokentype_eof)
1215
4.47M
    {
1216
4.47M
      if (result == ISC_R_SUCCESS) {
1217
141
        result = DNS_R_EXTRATOKEN;
1218
141
      }
1219
4.47M
      if (callback != NULL) {
1220
11.2k
        fromtext_error(callback, callbacks, name, line,
1221
11.2k
                 &token, result);
1222
11.2k
        callback = NULL;
1223
11.2k
      }
1224
10.3M
    } else if (result != ISC_R_SUCCESS && callback != NULL) {
1225
5.84k
      fromtext_error(callback, callbacks, name, line, &token,
1226
5.84k
               result);
1227
5.84k
      break;
1228
10.3M
    } else {
1229
10.3M
      if (token.type == isc_tokentype_eof) {
1230
9.88M
        fromtext_warneof(lexer, callbacks);
1231
9.88M
      }
1232
10.3M
      break;
1233
10.3M
    }
1234
14.7M
  } while (1);
1235
1236
10.3M
  length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
1237
10.3M
  if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
1238
3
    result = ISC_R_NOSPACE;
1239
3
  }
1240
1241
10.3M
  if (rdata != NULL && result == ISC_R_SUCCESS) {
1242
10.3M
    region.base = isc_buffer_used(&st);
1243
10.3M
    region.length = length;
1244
10.3M
    dns_rdata_fromregion(rdata, rdclass, type, &region);
1245
10.3M
  }
1246
10.3M
  if (result != ISC_R_SUCCESS) {
1247
18.1k
    *target = st;
1248
18.1k
  }
1249
10.3M
  return result;
1250
10.3M
}
1251
1252
static isc_result_t
1253
unknown_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
1254
96.5k
         isc_buffer_t *target) {
1255
96.5k
  isc_result_t result = ISC_R_SUCCESS;
1256
96.5k
  char buf[sizeof("65535")];
1257
96.5k
  isc_region_t sr;
1258
1259
96.5k
  strlcpy(buf, "\\# ", sizeof(buf));
1260
96.5k
  RETERR(str_totext(buf, target));
1261
1262
96.5k
  dns_rdata_toregion(rdata, &sr);
1263
96.5k
  INSIST(sr.length < 65536);
1264
96.5k
  snprintf(buf, sizeof(buf), "%u", sr.length);
1265
96.5k
  RETERR(str_totext(buf, target));
1266
1267
96.5k
  if (sr.length != 0U) {
1268
48.4k
    if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
1269
172
      RETERR(str_totext(" ( ", target));
1270
48.2k
    } else {
1271
48.2k
      RETERR(str_totext(" ", target));
1272
48.2k
    }
1273
1274
48.4k
    if (tctx->width == 0) { /* No splitting */
1275
0
      result = isc_hex_totext(&sr, 0, "", target);
1276
48.4k
    } else {
1277
48.4k
      result = isc_hex_totext(&sr, tctx->width - 2,
1278
48.4k
            tctx->linebreak, target);
1279
48.4k
    }
1280
48.4k
    if (result == ISC_R_SUCCESS &&
1281
48.4k
        (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
1282
172
    {
1283
172
      result = str_totext(" )", target);
1284
172
    }
1285
48.4k
  }
1286
96.5k
  return result;
1287
96.5k
}
1288
1289
static isc_result_t
1290
rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
1291
237k
       isc_buffer_t *target) {
1292
237k
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1293
237k
  bool use_default = false;
1294
237k
  unsigned int cur;
1295
1296
237k
  REQUIRE(rdata != NULL);
1297
237k
  REQUIRE(tctx->origin == NULL || dns_name_isabsolute(tctx->origin));
1298
1299
  /*
1300
   * Some DynDNS meta-RRs have empty rdata.
1301
   */
1302
237k
  if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
1303
2.32k
    INSIST(rdata->length == 0);
1304
2.32k
    return ISC_R_SUCCESS;
1305
2.32k
  }
1306
1307
235k
  if ((tctx->flags & DNS_STYLEFLAG_UNKNOWNFORMAT) != 0) {
1308
0
    return unknown_totext(rdata, tctx, target);
1309
0
  }
1310
1311
235k
  cur = isc_buffer_usedlength(target);
1312
1313
235k
  TOTEXTSWITCH
1314
1315
235k
  if (use_default || (result == ISC_R_NOTIMPLEMENTED)) {
1316
92.0k
    unsigned int u = isc_buffer_usedlength(target);
1317
1318
92.0k
    INSIST(u >= cur);
1319
92.0k
    isc_buffer_subtract(target, u - cur);
1320
92.0k
    result = unknown_totext(rdata, tctx, target);
1321
92.0k
  }
1322
1323
235k
  return result;
1324
235k
}
1325
1326
isc_result_t
1327
dns_rdata_totext(dns_rdata_t *rdata, const dns_name_t *origin,
1328
3.71k
     isc_buffer_t *target) {
1329
3.71k
  dns_rdata_textctx_t tctx;
1330
1331
3.71k
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1332
1333
  /*
1334
   * Set up formatting options for single-line output.
1335
   */
1336
3.71k
  tctx.origin = origin;
1337
3.71k
  tctx.flags = 0;
1338
3.71k
  tctx.width = 60;
1339
3.71k
  tctx.linebreak = " ";
1340
3.71k
  return rdata_totext(rdata, &tctx, target);
1341
3.71k
}
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
233k
        isc_buffer_t *target) {
1348
233k
  dns_rdata_textctx_t tctx;
1349
1350
233k
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1351
1352
  /*
1353
   * Set up formatting options for formatted output.
1354
   */
1355
233k
  tctx.origin = origin;
1356
233k
  tctx.flags = flags;
1357
233k
  if (split_width == 0xffffffff) {
1358
230k
    tctx.width = width;
1359
230k
  } else {
1360
3.71k
    tctx.width = split_width;
1361
3.71k
  }
1362
1363
233k
  if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) {
1364
3.71k
    tctx.linebreak = linebreak;
1365
230k
  } else {
1366
230k
    if (split_width == 0xffffffff) {
1367
230k
      tctx.width = 60; /* Used for hex word length only. */
1368
230k
    }
1369
230k
    tctx.linebreak = " ";
1370
230k
  }
1371
233k
  return rdata_totext(rdata, &tctx, target);
1372
233k
}
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
2.35k
dns_rdata_tostruct(const dns_rdata_t *rdata, void *target, isc_mem_t *mctx) {
1415
2.35k
  isc_result_t result = ISC_R_NOTIMPLEMENTED;
1416
2.35k
  bool use_default = false;
1417
1418
2.35k
  REQUIRE(rdata != NULL);
1419
2.35k
  REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1420
2.35k
  REQUIRE((rdata->flags & DNS_RDATA_UPDATE) == 0);
1421
1422
2.35k
  TOSTRUCTSWITCH
1423
1424
2.35k
  if (use_default) {
1425
0
    (void)NULL;
1426
0
  }
1427
1428
2.35k
  return result;
1429
2.35k
}
1430
1431
void
1432
535
dns_rdata_freestruct(void *source) {
1433
535
  dns_rdatacommon_t *common = source;
1434
535
  REQUIRE(common != NULL);
1435
1436
535
  FREESTRUCTSWITCH
1437
535
}
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
4.34k
         dns_rdatatype_t type, bool wildcard) {
1491
4.34k
  bool result;
1492
1493
4.34k
  CHECKOWNERSWITCH
1494
4.34k
  return result;
1495
4.34k
}
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
421M
dns_rdatatype_attributes(dns_rdatatype_t type) {
1508
421M
  RDATATYPE_ATTRIBUTE_SW
1509
418M
  if (type >= (dns_rdatatype_t)128 && type <= (dns_rdatatype_t)255) {
1510
781k
    return DNS_RDATATYPEATTR_UNKNOWN | DNS_RDATATYPEATTR_META;
1511
781k
  }
1512
418M
  return DNS_RDATATYPEATTR_UNKNOWN;
1513
418M
}
1514
1515
isc_result_t
1516
1.77M
dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) {
1517
1.77M
  unsigned int hash;
1518
1.77M
  unsigned int n;
1519
1.77M
  unsigned char a, b;
1520
1521
1.77M
  n = source->length;
1522
1523
1.77M
  if (n == 0) {
1524
0
    return DNS_R_UNKNOWN;
1525
0
  }
1526
1527
1.77M
  a = isc_ascii_tolower(source->base[0]);
1528
1.77M
  b = isc_ascii_tolower(source->base[n - 1]);
1529
1530
1.77M
  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
1.77M
  RDATATYPE_FROMTEXT_SW(hash, source->base, n, typep);
1538
1539
1.59M
  if (source->length > 4 && source->length < (4 + sizeof("65000")) &&
1540
472k
      strncasecmp("type", source->base, 4) == 0)
1541
389k
  {
1542
389k
    char buf[sizeof("65000")];
1543
389k
    char *endp;
1544
389k
    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
389k
    snprintf(buf, sizeof(buf), "%.*s", (int)(source->length - 4),
1551
389k
       source->base + 4);
1552
389k
    val = strtoul(buf, &endp, 10);
1553
389k
    if (*endp == '\0' && val <= 0xffff) {
1554
389k
      *typep = (dns_rdatatype_t)val;
1555
389k
      return ISC_R_SUCCESS;
1556
389k
    }
1557
389k
  }
1558
1559
1.20M
  return DNS_R_UNKNOWN;
1560
1.59M
}
1561
1562
isc_result_t
1563
418M
dns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target) {
1564
418M
  RDATATYPE_TOTEXT_SW
1565
1566
418M
  return dns_rdatatype_tounknowntext(type, target);
1567
418M
}
1568
1569
isc_result_t
1570
418M
dns_rdatatype_tounknowntext(dns_rdatatype_t type, isc_buffer_t *target) {
1571
418M
  char buf[sizeof("TYPE65535")];
1572
1573
418M
  snprintf(buf, sizeof(buf), "TYPE%u", type);
1574
418M
  return str_totext(buf, target);
1575
418M
}
1576
1577
void
1578
418M
dns_rdatatype_format(dns_rdatatype_t rdtype, char *array, unsigned int size) {
1579
418M
  isc_result_t result;
1580
418M
  isc_buffer_t buf;
1581
1582
418M
  if (size == 0U) {
1583
0
    return;
1584
0
  }
1585
1586
418M
  isc_buffer_init(&buf, array, size);
1587
418M
  result = dns_rdatatype_totext(rdtype, &buf);
1588
  /*
1589
   * Null terminate.
1590
   */
1591
418M
  if (result == ISC_R_SUCCESS) {
1592
418M
    if (isc_buffer_availablelength(&buf) >= 1) {
1593
418M
      isc_buffer_putuint8(&buf, 0);
1594
418M
    } else {
1595
0
      result = ISC_R_NOSPACE;
1596
0
    }
1597
418M
  }
1598
418M
  if (result != ISC_R_SUCCESS) {
1599
0
    strlcpy(array, "<unknown>", size);
1600
0
  }
1601
418M
}
1602
1603
/*
1604
 * Private function.
1605
 */
1606
1607
static unsigned int
1608
384k
name_length(const dns_name_t *name) {
1609
384k
  return name->length;
1610
384k
}
1611
1612
static isc_result_t
1613
commatxt_totext(isc_region_t *source, bool quote, bool comma,
1614
82.4k
    isc_buffer_t *target) {
1615
82.4k
  unsigned int tl;
1616
82.4k
  unsigned int n;
1617
82.4k
  unsigned char *sp;
1618
82.4k
  char *tp;
1619
82.4k
  isc_region_t region;
1620
1621
82.4k
  isc_buffer_availableregion(target, &region);
1622
82.4k
  sp = source->base;
1623
82.4k
  tp = (char *)region.base;
1624
82.4k
  tl = region.length;
1625
1626
82.4k
  n = *sp++;
1627
1628
82.4k
  REQUIRE(n + 1 <= source->length);
1629
82.4k
  if (n == 0U) {
1630
55.6k
    REQUIRE(quote);
1631
55.6k
  }
1632
1633
82.4k
  if (quote) {
1634
79.7k
    if (tl < 1) {
1635
0
      return ISC_R_NOSPACE;
1636
0
    }
1637
79.7k
    *tp++ = '"';
1638
79.7k
    tl--;
1639
79.7k
  }
1640
1.08M
  while (n--) {
1641
    /*
1642
     * \DDD space (0x20) if not quoting.
1643
     */
1644
999k
    if (*sp < (quote ? ' ' : '!') || *sp >= 0x7f) {
1645
560k
      if (tl < 4) {
1646
0
        return ISC_R_NOSPACE;
1647
0
      }
1648
560k
      *tp++ = '\\';
1649
560k
      *tp++ = '0' + ((*sp / 100) % 10);
1650
560k
      *tp++ = '0' + ((*sp / 10) % 10);
1651
560k
      *tp++ = '0' + (*sp % 10);
1652
560k
      sp++;
1653
560k
      tl -= 4;
1654
560k
      continue;
1655
560k
    }
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
438k
    if (*sp == '"' || *sp == '\\' || (comma && *sp == ',') ||
1663
405k
        (!comma && !quote && (*sp == '@' || *sp == ';')))
1664
33.6k
    {
1665
33.6k
      if (tl < 2) {
1666
0
        return ISC_R_NOSPACE;
1667
0
      }
1668
33.6k
      *tp++ = '\\';
1669
33.6k
      tl--;
1670
      /*
1671
       * Perform comma escape processing.
1672
       * ',' => '\\,'
1673
       * '\' => '\\\\'
1674
       */
1675
33.6k
      if (comma && (*sp == ',' || *sp == '\\')) {
1676
2.57k
        if (tl < ((*sp == '\\') ? 3 : 2)) {
1677
0
          return ISC_R_NOSPACE;
1678
0
        }
1679
2.57k
        *tp++ = '\\';
1680
2.57k
        tl--;
1681
2.57k
        if (*sp == '\\') {
1682
1.78k
          *tp++ = '\\';
1683
1.78k
          tl--;
1684
1.78k
        }
1685
2.57k
      }
1686
33.6k
    }
1687
438k
    if (tl < 1) {
1688
0
      return ISC_R_NOSPACE;
1689
0
    }
1690
438k
    *tp++ = *sp++;
1691
438k
    tl--;
1692
438k
  }
1693
82.4k
  if (quote) {
1694
79.7k
    if (tl < 1) {
1695
0
      return ISC_R_NOSPACE;
1696
0
    }
1697
79.7k
    *tp++ = '"';
1698
79.7k
    tl--;
1699
79.7k
    POST(tl);
1700
79.7k
  }
1701
82.4k
  isc_buffer_add(target, (unsigned int)(tp - (char *)region.base));
1702
82.4k
  isc_region_consume(source, *source->base + 1);
1703
82.4k
  return ISC_R_SUCCESS;
1704
82.4k
}
1705
1706
static isc_result_t
1707
80.9k
txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target) {
1708
80.9k
  return commatxt_totext(source, quote, false, target);
1709
80.9k
}
1710
1711
static isc_result_t
1712
2.21M
commatxt_fromtext(isc_textregion_t *source, bool comma, isc_buffer_t *target) {
1713
2.21M
  isc_region_t tregion;
1714
2.21M
  bool escape = false, comma_escape = false, seen_comma = false;
1715
2.21M
  unsigned int n, nrem;
1716
2.21M
  char *s;
1717
2.21M
  unsigned char *t;
1718
2.21M
  int d;
1719
2.21M
  int c;
1720
1721
2.21M
  isc_buffer_availableregion(target, &tregion);
1722
2.21M
  s = source->base;
1723
2.21M
  n = source->length;
1724
2.21M
  t = tregion.base;
1725
2.21M
  nrem = tregion.length;
1726
2.21M
  if (nrem < 1) {
1727
4
    return ISC_R_NOSPACE;
1728
4
  }
1729
  /*
1730
   * Length byte.
1731
   */
1732
2.21M
  nrem--;
1733
2.21M
  t++;
1734
  /*
1735
   * Maximum text string length.
1736
   */
1737
2.21M
  if (nrem > 255) {
1738
2.21M
    nrem = 255;
1739
2.21M
  }
1740
57.7M
  while (n-- != 0) {
1741
55.8M
    c = (*s++) & 0xff;
1742
55.8M
    if (escape && (d = decvalue((char)c)) != -1) {
1743
41.7k
      c = d;
1744
41.7k
      if (n == 0) {
1745
26
        return DNS_R_SYNTAX;
1746
26
      }
1747
41.6k
      n--;
1748
41.6k
      if ((d = decvalue(*s++)) != -1) {
1749
41.6k
        c = c * 10 + d;
1750
41.6k
      } else {
1751
7
        return DNS_R_SYNTAX;
1752
7
      }
1753
41.6k
      if (n == 0) {
1754
16
        return DNS_R_SYNTAX;
1755
16
      }
1756
41.6k
      n--;
1757
41.6k
      if ((d = decvalue(*s++)) != -1) {
1758
41.6k
        c = c * 10 + d;
1759
41.6k
      } else {
1760
15
        return DNS_R_SYNTAX;
1761
15
      }
1762
41.6k
      if (c > 255) {
1763
12
        return DNS_R_SYNTAX;
1764
12
      }
1765
55.8M
    } else if (!escape && c == '\\') {
1766
515k
      escape = true;
1767
515k
      continue;
1768
515k
    }
1769
55.3M
    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
55.3M
    if (comma && !comma_escape && c == ',') {
1781
305k
      seen_comma = true;
1782
305k
      break;
1783
305k
    }
1784
55.0M
    if (comma && !comma_escape && c == '\\') {
1785
4.95k
      comma_escape = true;
1786
4.95k
      continue;
1787
4.95k
    }
1788
55.0M
    comma_escape = false;
1789
55.0M
    if (nrem == 0) {
1790
78
      return (tregion.length <= 256U) ? ISC_R_NOSPACE
1791
78
              : DNS_R_SYNTAX;
1792
78
    }
1793
55.0M
    *t++ = c;
1794
55.0M
    nrem--;
1795
55.0M
  }
1796
1797
  /*
1798
   * Incomplete escape processing?
1799
   */
1800
2.21M
  if (escape || (comma && comma_escape)) {
1801
9
    return DNS_R_SYNTAX;
1802
9
  }
1803
1804
2.21M
  if (comma) {
1805
    /*
1806
     * Disallow empty ALPN at start (",h1" or "\,h1") or
1807
     * in the middle ("h1,,h2" or "h1\,\,h2").
1808
     */
1809
317k
    if ((t - tregion.base - 1) == 0) {
1810
21
      return DNS_R_SYNTAX;
1811
21
    }
1812
1813
    /*
1814
     * Consume this ALPN and possible ending comma.
1815
     */
1816
317k
    isc_textregion_consume(source, s - source->base);
1817
1818
    /*
1819
     * Disallow empty ALPN at end ("h1," or "h1\,").
1820
     */
1821
317k
    if (seen_comma && source->length == 0) {
1822
2
      return DNS_R_SYNTAX;
1823
2
    }
1824
317k
  }
1825
1826
2.21M
  *tregion.base = (unsigned char)(t - tregion.base - 1);
1827
2.21M
  isc_buffer_add(target, *tregion.base + 1);
1828
2.21M
  return ISC_R_SUCCESS;
1829
2.21M
}
1830
1831
static isc_result_t
1832
1.89M
txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
1833
1.89M
  return commatxt_fromtext(source, false, target);
1834
1.89M
}
1835
1836
static isc_result_t
1837
118k
txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) {
1838
118k
  unsigned int n;
1839
118k
  isc_region_t sregion;
1840
118k
  isc_region_t tregion;
1841
1842
118k
  isc_buffer_activeregion(source, &sregion);
1843
118k
  if (sregion.length == 0) {
1844
90
    return ISC_R_UNEXPECTEDEND;
1845
90
  }
1846
118k
  n = *sregion.base + 1;
1847
118k
  if (n > sregion.length) {
1848
121
    return ISC_R_UNEXPECTEDEND;
1849
121
  }
1850
1851
118k
  isc_buffer_availableregion(target, &tregion);
1852
118k
  if (n > tregion.length) {
1853
2.30k
    return ISC_R_NOSPACE;
1854
2.30k
  }
1855
1856
116k
  if (tregion.base != sregion.base) {
1857
116k
    memmove(tregion.base, sregion.base, n);
1858
116k
  }
1859
116k
  isc_buffer_forward(source, n);
1860
116k
  isc_buffer_add(target, n);
1861
116k
  return ISC_R_SUCCESS;
1862
118k
}
1863
1864
/*
1865
 * Conversion of TXT-like rdata fields without length limits.
1866
 */
1867
static isc_result_t
1868
6.10k
multitxt_totext(isc_region_t *source, isc_buffer_t *target) {
1869
6.10k
  unsigned int tl;
1870
6.10k
  unsigned int n0, n;
1871
6.10k
  unsigned char *sp;
1872
6.10k
  char *tp;
1873
6.10k
  isc_region_t region;
1874
1875
6.10k
  isc_buffer_availableregion(target, &region);
1876
6.10k
  sp = source->base;
1877
6.10k
  tp = (char *)region.base;
1878
6.10k
  tl = region.length;
1879
1880
6.10k
  if (tl < 1) {
1881
0
    return ISC_R_NOSPACE;
1882
0
  }
1883
6.10k
  *tp++ = '"';
1884
6.10k
  tl--;
1885
6.10k
  do {
1886
6.10k
    n = source->length;
1887
6.10k
    n0 = source->length - 1;
1888
1889
645k
    while (n--) {
1890
639k
      if (*sp < ' ' || *sp >= 0x7f) {
1891
490k
        if (tl < 4) {
1892
0
          return ISC_R_NOSPACE;
1893
0
        }
1894
490k
        *tp++ = '\\';
1895
490k
        *tp++ = '0' + ((*sp / 100) % 10);
1896
490k
        *tp++ = '0' + ((*sp / 10) % 10);
1897
490k
        *tp++ = '0' + (*sp % 10);
1898
490k
        sp++;
1899
490k
        tl -= 4;
1900
490k
        continue;
1901
490k
      }
1902
      /* double quote, backslash */
1903
148k
      if (*sp == '"' || *sp == '\\') {
1904
5.29k
        if (tl < 2) {
1905
0
          return ISC_R_NOSPACE;
1906
0
        }
1907
5.29k
        *tp++ = '\\';
1908
5.29k
        tl--;
1909
5.29k
      }
1910
148k
      if (tl < 1) {
1911
0
        return ISC_R_NOSPACE;
1912
0
      }
1913
148k
      *tp++ = *sp++;
1914
148k
      tl--;
1915
148k
    }
1916
6.10k
    isc_region_consume(source, n0 + 1);
1917
6.10k
  } while (source->length != 0);
1918
6.10k
  if (tl < 1) {
1919
0
    return ISC_R_NOSPACE;
1920
0
  }
1921
6.10k
  *tp++ = '"';
1922
6.10k
  tl--;
1923
6.10k
  POST(tl);
1924
6.10k
  isc_buffer_add(target, (unsigned int)(tp - (char *)region.base));
1925
6.10k
  return ISC_R_SUCCESS;
1926
6.10k
}
1927
1928
static isc_result_t
1929
32.6k
multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
1930
32.6k
  isc_region_t tregion;
1931
32.6k
  bool escape;
1932
32.6k
  unsigned int n, nrem;
1933
32.6k
  char *s;
1934
32.6k
  unsigned char *t0, *t;
1935
32.6k
  int d;
1936
32.6k
  int c;
1937
1938
32.6k
  s = source->base;
1939
32.6k
  n = source->length;
1940
32.6k
  escape = false;
1941
1942
32.6k
  do {
1943
32.6k
    isc_buffer_availableregion(target, &tregion);
1944
32.6k
    t0 = t = tregion.base;
1945
32.6k
    nrem = tregion.length;
1946
32.6k
    if (nrem < 1) {
1947
32
      return ISC_R_NOSPACE;
1948
32
    }
1949
1950
12.0M
    while (n != 0) {
1951
11.9M
      --n;
1952
11.9M
      c = (*s++) & 0xff;
1953
11.9M
      if (escape && (d = decvalue((char)c)) != -1) {
1954
45.5k
        c = d;
1955
45.5k
        if (n == 0) {
1956
14
          return DNS_R_SYNTAX;
1957
14
        }
1958
45.5k
        n--;
1959
45.5k
        if ((d = decvalue(*s++)) != -1) {
1960
45.5k
          c = c * 10 + d;
1961
45.5k
        } else {
1962
18
          return DNS_R_SYNTAX;
1963
18
        }
1964
45.5k
        if (n == 0) {
1965
10
          return DNS_R_SYNTAX;
1966
10
        }
1967
45.5k
        n--;
1968
45.5k
        if ((d = decvalue(*s++)) != -1) {
1969
45.4k
          c = c * 10 + d;
1970
45.4k
        } else {
1971
10
          return DNS_R_SYNTAX;
1972
10
        }
1973
45.4k
        if (c > 255) {
1974
7
          return DNS_R_SYNTAX;
1975
7
        }
1976
11.9M
      } else if (!escape && c == '\\') {
1977
54.7k
        escape = true;
1978
54.7k
        continue;
1979
54.7k
      }
1980
11.9M
      escape = false;
1981
11.9M
      *t++ = c;
1982
11.9M
      nrem--;
1983
11.9M
      if (nrem == 0) {
1984
37
        break;
1985
37
      }
1986
11.9M
    }
1987
32.5k
    if (escape) {
1988
4
      return DNS_R_SYNTAX;
1989
4
    }
1990
1991
32.5k
    isc_buffer_add(target, (unsigned int)(t - t0));
1992
32.5k
  } while (n != 0);
1993
32.5k
  return ISC_R_SUCCESS;
1994
32.6k
}
1995
1996
static bool
1997
64.7k
name_prefix(dns_name_t *name, const dns_name_t *origin, dns_name_t *target) {
1998
64.7k
  int l1, l2;
1999
2000
64.7k
  if (origin == NULL) {
2001
63.1k
    goto return_false;
2002
63.1k
  }
2003
2004
1.58k
  if (dns_name_isroot(origin)) {
2005
1.58k
    goto return_false;
2006
1.58k
  }
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
64.7k
return_false:
2029
64.7k
  *target = *name;
2030
64.7k
  return false;
2031
0
}
2032
2033
static isc_result_t
2034
421M
str_totext(const char *source, isc_buffer_t *target) {
2035
421M
  unsigned int l;
2036
421M
  isc_region_t region;
2037
2038
421M
  isc_buffer_availableregion(target, &region);
2039
421M
  l = strlen(source);
2040
2041
421M
  if (l > region.length) {
2042
2
    return ISC_R_NOSPACE;
2043
2
  }
2044
2045
421M
  memmove(region.base, source, l);
2046
421M
  isc_buffer_add(target, l);
2047
421M
  return ISC_R_SUCCESS;
2048
421M
}
2049
2050
static isc_result_t
2051
16.1k
inet_totext(int af, uint32_t flags, isc_region_t *src, isc_buffer_t *target) {
2052
16.1k
  char tmpbuf[64];
2053
2054
  /* Note - inet_ntop doesn't do size checking on its input. */
2055
16.1k
  if (inet_ntop(af, src->base, tmpbuf, sizeof(tmpbuf)) == NULL) {
2056
0
    return ISC_R_NOSPACE;
2057
0
  }
2058
16.1k
  if (strlen(tmpbuf) > isc_buffer_availablelength(target)) {
2059
0
    return ISC_R_NOSPACE;
2060
0
  }
2061
16.1k
  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
16.1k
  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
16.1k
  return ISC_R_SUCCESS;
2080
16.1k
}
2081
2082
static bool
2083
733k
buffer_empty(isc_buffer_t *source) {
2084
733k
  return (source->current == source->active) ? true : false;
2085
733k
}
2086
2087
static void
2088
8.96M
buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region) {
2089
8.96M
  isc_buffer_init(buffer, region->base, region->length);
2090
8.96M
  isc_buffer_add(buffer, region->length);
2091
8.96M
  isc_buffer_setactive(buffer, region->length);
2092
8.96M
}
2093
2094
static isc_result_t
2095
43.4k
uint32_tobuffer(uint32_t value, isc_buffer_t *target) {
2096
43.4k
  isc_region_t region;
2097
2098
43.4k
  isc_buffer_availableregion(target, &region);
2099
43.4k
  if (region.length < 4) {
2100
0
    return ISC_R_NOSPACE;
2101
0
  }
2102
43.4k
  isc_buffer_putuint32(target, value);
2103
43.4k
  return ISC_R_SUCCESS;
2104
43.4k
}
2105
2106
static isc_result_t
2107
3.28M
uint16_tobuffer(uint32_t value, isc_buffer_t *target) {
2108
3.28M
  isc_region_t region;
2109
2110
3.28M
  if (value > 0xffff) {
2111
53
    return ISC_R_RANGE;
2112
53
  }
2113
3.28M
  isc_buffer_availableregion(target, &region);
2114
3.28M
  if (region.length < 2) {
2115
12
    return ISC_R_NOSPACE;
2116
12
  }
2117
3.28M
  isc_buffer_putuint16(target, (uint16_t)value);
2118
3.28M
  return ISC_R_SUCCESS;
2119
3.28M
}
2120
2121
static isc_result_t
2122
1.91M
uint8_tobuffer(uint32_t value, isc_buffer_t *target) {
2123
1.91M
  isc_region_t region;
2124
2125
1.91M
  if (value > 0xff) {
2126
103
    return ISC_R_RANGE;
2127
103
  }
2128
1.91M
  isc_buffer_availableregion(target, &region);
2129
1.91M
  if (region.length < 1) {
2130
0
    return ISC_R_NOSPACE;
2131
0
  }
2132
1.91M
  isc_buffer_putuint8(target, (uint8_t)value);
2133
1.91M
  return ISC_R_SUCCESS;
2134
1.91M
}
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
76.3k
uint32_fromregion(isc_region_t *region) {
2145
76.3k
  uint32_t value;
2146
2147
76.3k
  REQUIRE(region->length >= 4);
2148
76.3k
  value = (uint32_t)region->base[0] << 24;
2149
76.3k
  value |= (uint32_t)region->base[1] << 16;
2150
76.3k
  value |= (uint32_t)region->base[2] << 8;
2151
76.3k
  value |= (uint32_t)region->base[3];
2152
76.3k
  return value;
2153
76.3k
}
2154
2155
static uint16_t
2156
19
uint16_consume_fromregion(isc_region_t *region) {
2157
19
  uint16_t r = uint16_fromregion(region);
2158
2159
19
  isc_region_consume(region, 2);
2160
19
  return r;
2161
19
}
2162
2163
static uint16_t
2164
1.91M
uint16_fromregion(isc_region_t *region) {
2165
1.91M
  REQUIRE(region->length >= 2);
2166
2167
1.91M
  return (region->base[0] << 8) | region->base[1];
2168
1.91M
}
2169
2170
static uint8_t
2171
174k
uint8_fromregion(isc_region_t *region) {
2172
174k
  REQUIRE(region->length >= 1);
2173
2174
174k
  return region->base[0];
2175
174k
}
2176
2177
static uint8_t
2178
1.24k
uint8_consume_fromregion(isc_region_t *region) {
2179
1.24k
  uint8_t r = uint8_fromregion(region);
2180
2181
1.24k
  isc_region_consume(region, 1);
2182
1.24k
  return r;
2183
1.24k
}
2184
2185
static isc_result_t
2186
3.57M
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
2187
3.57M
  isc_region_t tr;
2188
2189
3.57M
  if (length == 0U) {
2190
84.9k
    return ISC_R_SUCCESS;
2191
84.9k
  }
2192
2193
3.48M
  isc_buffer_availableregion(target, &tr);
2194
3.48M
  if (length > tr.length) {
2195
14.0k
    return ISC_R_NOSPACE;
2196
14.0k
  }
2197
3.47M
  if (tr.base != base) {
2198
3.47M
    memmove(tr.base, base, length);
2199
3.47M
  }
2200
3.47M
  isc_buffer_add(target, length);
2201
3.47M
  return ISC_R_SUCCESS;
2202
3.48M
}
2203
2204
static int
2205
2.14M
hexvalue(char value) {
2206
2.14M
  int hexval = isc_hex_char(value);
2207
2.14M
  if (hexval == 0) {
2208
110
    return -1;
2209
2.14M
  } else {
2210
2.14M
    return value - hexval;
2211
2.14M
  }
2212
2.14M
}
2213
2214
static int
2215
751k
decvalue(char value) {
2216
751k
  if (isdigit((unsigned char)value)) {
2217
268k
    return value - '0';
2218
483k
  } else {
2219
483k
    return -1;
2220
483k
  }
2221
751k
}
2222
2223
static void
2224
default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *fmt,
2225
10.6k
        ...) {
2226
10.6k
  va_list ap;
2227
2228
10.6k
  UNUSED(callbacks);
2229
2230
10.6k
  va_start(ap, fmt);
2231
10.6k
  vfprintf(stderr, fmt, ap);
2232
10.6k
  va_end(ap);
2233
10.6k
  fprintf(stderr, "\n");
2234
10.6k
}
2235
2236
static void
2237
9.88M
fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) {
2238
9.88M
  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
9.88M
}
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
18.2k
         unsigned long line, isc_token_t *token, isc_result_t result) {
2285
18.2k
  if (name == NULL) {
2286
0
    name = "UNKNOWN";
2287
0
  }
2288
2289
18.2k
  if (token != NULL) {
2290
17.0k
    switch (token->type) {
2291
231
    case isc_tokentype_eol:
2292
231
      (*callback)(callbacks, "%s: %s:%lu: near eol: %s",
2293
231
            "dns_rdata_fromtext", name, line,
2294
231
            isc_result_totext(result));
2295
231
      break;
2296
5.61k
    case isc_tokentype_eof:
2297
5.61k
      (*callback)(callbacks, "%s: %s:%lu: near eof: %s",
2298
5.61k
            "dns_rdata_fromtext", name, line,
2299
5.61k
            isc_result_totext(result));
2300
5.61k
      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
10.7k
    case isc_tokentype_string:
2308
10.7k
    case isc_tokentype_qstring:
2309
10.7k
      (*callback)(callbacks, "%s: %s:%lu: near '%s': %s",
2310
10.7k
            "dns_rdata_fromtext", name, line,
2311
10.7k
            DNS_AS_STR(*token),
2312
10.7k
            isc_result_totext(result));
2313
10.7k
      break;
2314
452
    default:
2315
452
      (*callback)(callbacks, "%s: %s:%lu: %s",
2316
452
            "dns_rdata_fromtext", name, line,
2317
452
            isc_result_totext(result));
2318
452
      break;
2319
17.0k
    }
2320
17.0k
  } else {
2321
1.17k
    (*callback)(callbacks, "dns_rdata_fromtext: %s:%lu: %s", name,
2322
1.17k
          line, isc_result_totext(result));
2323
1.17k
  }
2324
18.2k
}
2325
2326
dns_rdatatype_t
2327
13.2k
dns_rdata_covers(dns_rdata_t *rdata) {
2328
13.2k
  if (rdata->type == dns_rdatatype_rrsig) {
2329
8.79k
    return covers_rrsig(rdata);
2330
8.79k
  }
2331
4.47k
  return covers_sig(rdata);
2332
13.2k
}
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
}