Coverage Report

Created: 2025-12-12 06:31

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