Coverage Report

Created: 2026-06-07 06:21

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