Coverage Report

Created: 2025-08-26 06:58

/src/bind9/lib/dns/name.c
Line
Count
Source (jump to first uncovered line)
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
#include <stdlib.h>
20
#include <unistd.h>
21
22
#include <isc/ascii.h>
23
#include <isc/attributes.h>
24
#include <isc/buffer.h>
25
#include <isc/hash.h>
26
#include <isc/hex.h>
27
#include <isc/mem.h>
28
#include <isc/once.h>
29
#include <isc/random.h>
30
#include <isc/result.h>
31
#include <isc/string.h>
32
#include <isc/thread.h>
33
#include <isc/util.h>
34
35
#include <dns/compress.h>
36
#include <dns/fixedname.h>
37
#include <dns/name.h>
38
39
typedef enum {
40
  ft_init = 0,
41
  ft_start,
42
  ft_ordinary,
43
  ft_initialescape,
44
  ft_escape,
45
  ft_escdecimal,
46
  ft_at
47
} ft_state;
48
49
/*%
50
 * Note that the name data must be a char array, not a string
51
 * literal, to avoid compiler warnings about discarding
52
 * the const attribute of a string.
53
 */
54
static unsigned char root_ndata[] = { "" };
55
static dns_name_t root = DNS_NAME_INITABSOLUTE(root_ndata);
56
const dns_name_t *dns_rootname = &root;
57
58
static unsigned char wild_ndata[] = { "\001*" };
59
60
static dns_name_t const wild = DNS_NAME_INITNONABSOLUTE(wild_ndata);
61
const dns_name_t *dns_wildcardname = &wild;
62
63
/*
64
 * dns_name_t to text post-conversion procedure.
65
 */
66
static thread_local dns_name_totextfilter_t *totext_filter_proc = NULL;
67
68
bool
69
0
dns_name_isvalid(const dns_name_t *name) {
70
0
  unsigned char *ndata;
71
0
  unsigned int offset, count, length, nlabels;
72
73
0
  if (!DNS_NAME_VALID(name)) {
74
0
    return false;
75
0
  }
76
77
0
  ndata = name->ndata;
78
0
  length = name->length;
79
0
  offset = 0;
80
0
  nlabels = 0;
81
82
0
  while (offset != length) {
83
0
    count = *ndata;
84
0
    if (count > DNS_NAME_LABELLEN) {
85
0
      return false;
86
0
    }
87
88
0
    nlabels++;
89
0
    offset += count + 1;
90
0
    ndata += count + 1;
91
0
    if (offset > length) {
92
0
      return false;
93
0
    }
94
95
0
    if (count == 0) {
96
0
      break;
97
0
    }
98
0
  }
99
100
0
  if (nlabels > DNS_NAME_MAXLABELS || offset != name->length) {
101
0
    return false;
102
0
  }
103
104
0
  return true;
105
0
}
106
107
bool
108
0
dns_name_hasbuffer(const dns_name_t *name) {
109
  /*
110
   * Does 'name' have a dedicated buffer?
111
   */
112
113
0
  REQUIRE(DNS_NAME_VALID(name));
114
115
0
  if (name->buffer != NULL) {
116
0
    return true;
117
0
  }
118
119
0
  return false;
120
0
}
121
122
bool
123
0
dns_name_isabsolute(const dns_name_t *name) {
124
  /*
125
   * Does 'name' end in the root label?
126
   */
127
128
0
  REQUIRE(DNS_NAME_VALID(name));
129
130
0
  return name->attributes.absolute;
131
0
}
132
133
0
#define hyphenchar(c) ((c) == 0x2d)
134
#define asterchar(c)  ((c) == 0x2a)
135
#define alphachar(c) \
136
0
  (((c) >= 0x41 && (c) <= 0x5a) || ((c) >= 0x61 && (c) <= 0x7a))
137
0
#define digitchar(c)  ((c) >= 0x30 && (c) <= 0x39)
138
0
#define borderchar(c) (alphachar(c) || digitchar(c))
139
0
#define middlechar(c) (borderchar(c) || hyphenchar(c))
140
0
#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
141
142
bool
143
0
dns_name_ismailbox(const dns_name_t *name) {
144
0
  unsigned char *ndata, ch;
145
0
  unsigned int n;
146
0
  bool first;
147
148
0
  REQUIRE(DNS_NAME_VALID(name));
149
0
  REQUIRE(name->length > 0);
150
0
  REQUIRE(name->attributes.absolute);
151
152
  /*
153
   * Root label.
154
   */
155
0
  if (name->length == 1) {
156
0
    return true;
157
0
  }
158
159
0
  ndata = name->ndata;
160
0
  n = *ndata++;
161
0
  INSIST(n <= DNS_NAME_LABELLEN);
162
0
  while (n--) {
163
0
    ch = *ndata++;
164
0
    if (!domainchar(ch)) {
165
0
      return false;
166
0
    }
167
0
  }
168
169
0
  if (ndata == name->ndata + name->length) {
170
0
    return false;
171
0
  }
172
173
  /*
174
   * RFC952/RFC1123 hostname.
175
   */
176
0
  while (ndata < (name->ndata + name->length)) {
177
0
    n = *ndata++;
178
0
    INSIST(n <= DNS_NAME_LABELLEN);
179
0
    first = true;
180
0
    while (n--) {
181
0
      ch = *ndata++;
182
0
      if (first || n == 0) {
183
0
        if (!borderchar(ch)) {
184
0
          return false;
185
0
        }
186
0
      } else {
187
0
        if (!middlechar(ch)) {
188
0
          return false;
189
0
        }
190
0
      }
191
0
      first = false;
192
0
    }
193
0
  }
194
0
  return true;
195
0
}
196
197
bool
198
0
dns_name_ishostname(const dns_name_t *name, bool wildcard) {
199
0
  unsigned char *ndata, ch;
200
0
  unsigned int n;
201
0
  bool first;
202
203
0
  REQUIRE(DNS_NAME_VALID(name));
204
0
  REQUIRE(name->length > 0);
205
0
  REQUIRE(name->attributes.absolute);
206
207
  /*
208
   * Root label.
209
   */
210
0
  if (name->length == 1) {
211
0
    return true;
212
0
  }
213
214
  /*
215
   * Skip wildcard if this is a ownername.
216
   */
217
0
  ndata = name->ndata;
218
0
  if (wildcard && ndata[0] == 1 && ndata[1] == '*') {
219
0
    ndata += 2;
220
0
  }
221
222
  /*
223
   * RFC952/RFC1123 hostname.
224
   */
225
0
  while (ndata < (name->ndata + name->length)) {
226
0
    n = *ndata++;
227
0
    INSIST(n <= DNS_NAME_LABELLEN);
228
0
    first = true;
229
0
    while (n--) {
230
0
      ch = *ndata++;
231
0
      if (first || n == 0) {
232
0
        if (!borderchar(ch)) {
233
0
          return false;
234
0
        }
235
0
      } else {
236
0
        if (!middlechar(ch)) {
237
0
          return false;
238
0
        }
239
0
      }
240
0
      first = false;
241
0
    }
242
0
  }
243
0
  return true;
244
0
}
245
246
bool
247
0
dns_name_iswildcard(const dns_name_t *name) {
248
0
  unsigned char *ndata;
249
250
  /*
251
   * Is 'name' a wildcard name?
252
   */
253
254
0
  REQUIRE(DNS_NAME_VALID(name));
255
0
  REQUIRE(name->length > 0);
256
257
0
  if (name->length >= 2) {
258
0
    ndata = name->ndata;
259
0
    if (ndata[0] == 1 && ndata[1] == '*') {
260
0
      return true;
261
0
    }
262
0
  }
263
264
0
  return false;
265
0
}
266
267
bool
268
0
dns_name_internalwildcard(const dns_name_t *name) {
269
0
  unsigned char *ndata;
270
0
  unsigned int count;
271
0
  unsigned int label;
272
273
  /*
274
   * Does 'name' contain a internal wildcard?
275
   */
276
277
0
  REQUIRE(DNS_NAME_VALID(name));
278
279
  /*
280
   * Skip first label.
281
   */
282
0
  ndata = name->ndata;
283
0
  count = *ndata++;
284
0
  INSIST(count <= DNS_NAME_LABELLEN);
285
0
  ndata += count;
286
0
  label = 1;
287
288
0
  uint8_t labels = dns_name_countlabels(name);
289
0
  while (label + 1 < labels) {
290
0
    count = *ndata++;
291
0
    INSIST(count <= DNS_NAME_LABELLEN);
292
293
0
    if (count == 1 && *ndata == '*') {
294
0
      return true;
295
0
    }
296
0
    ndata += count;
297
0
    label++;
298
0
  }
299
0
  return false;
300
0
}
301
302
uint32_t
303
0
dns_name_hash(const dns_name_t *name) {
304
0
  REQUIRE(DNS_NAME_VALID(name));
305
306
0
  return isc_hash32(name->ndata, name->length, false);
307
0
}
308
309
dns_namereln_t
310
dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
311
0
         int *orderp, unsigned int *nlabelsp) {
312
0
  unsigned int l1, l2, l, count1, count2, count, nlabels;
313
0
  int cdiff, ldiff, diff;
314
0
  unsigned char *label1, *label2;
315
0
  dns_offsets_t offsets1, offsets2;
316
0
  dns_namereln_t namereln = dns_namereln_none;
317
318
  /*
319
   * Determine the relative ordering under the DNSSEC order relation of
320
   * 'name1' and 'name2', and also determine the hierarchical
321
   * relationship of the names.
322
   *
323
   * Note: It makes no sense for one of the names to be relative and the
324
   * other absolute.  If both names are relative, then to be meaningfully
325
   * compared the caller must ensure that they are both relative to the
326
   * same domain.
327
   */
328
329
0
  REQUIRE(DNS_NAME_VALID(name1));
330
0
  REQUIRE(DNS_NAME_VALID(name2));
331
0
  REQUIRE(orderp != NULL);
332
0
  REQUIRE(nlabelsp != NULL);
333
  /*
334
   * Either name1 is absolute and name2 is absolute, or neither is.
335
   */
336
0
  REQUIRE((name1->attributes.absolute) == (name2->attributes.absolute));
337
338
0
  if (name1 == name2) {
339
0
    *orderp = 0;
340
0
    *nlabelsp = dns_name_countlabels(name1);
341
342
0
    return dns_namereln_equal;
343
0
  }
344
345
0
  l1 = dns_name_offsets(name1, offsets1);
346
0
  l2 = dns_name_offsets(name2, offsets2);
347
348
0
  nlabels = 0;
349
0
  if (l2 > l1) {
350
0
    l = l1;
351
0
    ldiff = 0 - (l2 - l1);
352
0
  } else {
353
0
    l = l2;
354
0
    ldiff = l1 - l2;
355
0
  }
356
357
0
  while (l-- > 0) {
358
0
    l1--;
359
0
    l2--;
360
0
    label1 = &name1->ndata[offsets1[l1]];
361
0
    label2 = &name2->ndata[offsets2[l2]];
362
0
    count1 = *label1++;
363
0
    count2 = *label2++;
364
365
0
    cdiff = (int)count1 - (int)count2;
366
0
    if (cdiff < 0) {
367
0
      count = count1;
368
0
    } else {
369
0
      count = count2;
370
0
    }
371
372
0
    diff = isc_ascii_lowercmp(label1, label2, count);
373
0
    if (diff != 0) {
374
0
      *orderp = diff;
375
0
      goto done;
376
0
    }
377
378
0
    if (cdiff != 0) {
379
0
      *orderp = cdiff;
380
0
      goto done;
381
0
    }
382
0
    nlabels++;
383
0
  }
384
385
0
  *orderp = ldiff;
386
0
  if (ldiff < 0) {
387
0
    namereln = dns_namereln_contains;
388
0
  } else if (ldiff > 0) {
389
0
    namereln = dns_namereln_subdomain;
390
0
  } else {
391
0
    namereln = dns_namereln_equal;
392
0
  }
393
0
  *nlabelsp = nlabels;
394
0
  return namereln;
395
396
0
done:
397
0
  *nlabelsp = nlabels;
398
0
  if (nlabels > 0) {
399
0
    namereln = dns_namereln_commonancestor;
400
0
  }
401
402
0
  return namereln;
403
0
}
404
405
int
406
0
dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
407
0
  int order;
408
0
  unsigned int nlabels;
409
410
  /*
411
   * Determine the relative ordering under the DNSSEC order relation of
412
   * 'name1' and 'name2'.
413
   *
414
   * Note: It makes no sense for one of the names to be relative and the
415
   * other absolute.  If both names are relative, then to be meaningfully
416
   * compared the caller must ensure that they are both relative to the
417
   * same domain.
418
   */
419
420
0
  (void)dns_name_fullcompare(name1, name2, &order, &nlabels);
421
422
0
  return order;
423
0
}
424
425
bool
426
0
dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
427
0
  unsigned int length;
428
429
  /*
430
   * Are 'name1' and 'name2' equal?
431
   *
432
   * Note: It makes no sense for one of the names to be relative and the
433
   * other absolute.  If both names are relative, then to be meaningfully
434
   * compared the caller must ensure that they are both relative to the
435
   * same domain.
436
   */
437
438
0
  REQUIRE(DNS_NAME_VALID(name1));
439
0
  REQUIRE(DNS_NAME_VALID(name2));
440
  /*
441
   * Either name1 is absolute and name2 is absolute, or neither is.
442
   */
443
0
  REQUIRE((name1->attributes.absolute) == (name2->attributes.absolute));
444
445
0
  if (name1 == name2) {
446
0
    return true;
447
0
  }
448
449
0
  length = name1->length;
450
0
  if (length != name2->length) {
451
0
    return false;
452
0
  }
453
454
  /* label lengths are < 64 so tolower() does not affect them */
455
0
  return isc_ascii_lowerequal(name1->ndata, name2->ndata, length);
456
0
}
457
458
bool
459
0
dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
460
  /*
461
   * Are 'name1' and 'name2' equal?
462
   *
463
   * Note: It makes no sense for one of the names to be relative and the
464
   * other absolute.  If both names are relative, then to be meaningfully
465
   * compared the caller must ensure that they are both relative to the
466
   * same domain.
467
   */
468
469
0
  REQUIRE(DNS_NAME_VALID(name1));
470
0
  REQUIRE(DNS_NAME_VALID(name2));
471
  /*
472
   * Either name1 is absolute and name2 is absolute, or neither is.
473
   */
474
0
  REQUIRE((name1->attributes.absolute) == (name2->attributes.absolute));
475
476
0
  if (name1->length != name2->length) {
477
0
    return false;
478
0
  }
479
480
0
  if (memcmp(name1->ndata, name2->ndata, name1->length) != 0) {
481
0
    return false;
482
0
  }
483
484
0
  return true;
485
0
}
486
487
int
488
0
dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) {
489
  /*
490
   * Compare two absolute names as rdata.
491
   */
492
493
0
  REQUIRE(DNS_NAME_VALID(name1));
494
0
  REQUIRE(name1->length > 0);
495
0
  REQUIRE(name1->attributes.absolute);
496
0
  REQUIRE(DNS_NAME_VALID(name2));
497
0
  REQUIRE(name2->length > 0);
498
0
  REQUIRE(name2->attributes.absolute);
499
500
  /* label lengths are < 64 so tolower() does not affect them */
501
0
  return isc_ascii_lowercmp(name1->ndata, name2->ndata,
502
0
          ISC_MIN(name1->length, name2->length));
503
0
}
504
505
bool
506
0
dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
507
0
  int order;
508
0
  unsigned int nlabels;
509
0
  dns_namereln_t namereln;
510
511
  /*
512
   * Is 'name1' a subdomain of 'name2'?
513
   *
514
   * Note: It makes no sense for one of the names to be relative and the
515
   * other absolute.  If both names are relative, then to be meaningfully
516
   * compared the caller must ensure that they are both relative to the
517
   * same domain.
518
   */
519
520
0
  namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
521
0
  if (namereln == dns_namereln_subdomain ||
522
0
      namereln == dns_namereln_equal)
523
0
  {
524
0
    return true;
525
0
  }
526
527
0
  return false;
528
0
}
529
530
bool
531
0
dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) {
532
0
  int order;
533
0
  unsigned int nlabels, labels;
534
0
  dns_name_t tname;
535
536
0
  REQUIRE(DNS_NAME_VALID(name));
537
0
  REQUIRE(name->length > 0);
538
0
  REQUIRE(DNS_NAME_VALID(wname));
539
0
  labels = dns_name_countlabels(wname);
540
0
  REQUIRE(labels > 0);
541
0
  REQUIRE(dns_name_iswildcard(wname));
542
543
0
  dns_name_init(&tname);
544
0
  dns_name_getlabelsequence(wname, 1, labels - 1, &tname);
545
0
  if (dns_name_fullcompare(name, &tname, &order, &nlabels) ==
546
0
      dns_namereln_subdomain)
547
0
  {
548
0
    return true;
549
0
  }
550
0
  return false;
551
0
}
552
553
void
554
0
dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
555
0
  dns_offsets_t offsets;
556
557
  /*
558
   * Make 'label' refer to the 'n'th least significant label of 'name'.
559
   */
560
561
0
  REQUIRE(DNS_NAME_VALID(name));
562
0
  REQUIRE(label != NULL);
563
564
0
  uint8_t labels = dns_name_offsets(name, offsets);
565
566
0
  REQUIRE(labels > 0);
567
0
  REQUIRE(n < labels);
568
569
0
  label->base = &name->ndata[offsets[n]];
570
0
  if (n == (unsigned int)labels - 1) {
571
0
    label->length = name->length - offsets[n];
572
0
  } else {
573
0
    label->length = offsets[n + 1] - offsets[n];
574
0
  }
575
0
}
576
577
void
578
dns_name_getlabelsequence(const dns_name_t *source, unsigned int first,
579
0
        unsigned int n, dns_name_t *target) {
580
0
  unsigned char *p, l;
581
0
  unsigned int firstoffset, endoffset;
582
0
  unsigned int i;
583
584
  /*
585
   * Make 'target' refer to the 'n' labels including and following
586
   * 'first' in 'source'.
587
   */
588
589
0
  REQUIRE(DNS_NAME_VALID(source));
590
0
  REQUIRE(DNS_NAME_VALID(target));
591
0
  REQUIRE(DNS_NAME_BINDABLE(target));
592
593
0
  uint8_t labels = dns_name_countlabels(source);
594
0
  REQUIRE(first <= labels && n <= labels - first);
595
596
0
  p = source->ndata;
597
0
  if (first == labels) {
598
0
    firstoffset = source->length;
599
0
  } else {
600
0
    for (i = 0; i < first; i++) {
601
0
      l = *p;
602
0
      p += l + 1;
603
0
    }
604
0
    firstoffset = (unsigned int)(p - source->ndata);
605
0
  }
606
607
0
  if (first + n == labels) {
608
0
    endoffset = source->length;
609
0
  } else {
610
0
    for (i = 0; i < n; i++) {
611
0
      l = *p;
612
0
      p += l + 1;
613
0
    }
614
0
    endoffset = (unsigned int)(p - source->ndata);
615
0
  }
616
617
0
  target->ndata = &source->ndata[firstoffset];
618
0
  target->length = endoffset - firstoffset;
619
620
0
  if (first + n == labels && n > 0 && source->attributes.absolute) {
621
0
    target->attributes.absolute = true;
622
0
  } else {
623
0
    target->attributes.absolute = false;
624
0
  }
625
0
}
626
627
void
628
0
dns_name_clone(const dns_name_t *source, dns_name_t *target) {
629
  /*
630
   * Make 'target' refer to the same name as 'source'.
631
   */
632
633
0
  REQUIRE(DNS_NAME_VALID(source));
634
0
  REQUIRE(DNS_NAME_VALID(target));
635
0
  REQUIRE(DNS_NAME_BINDABLE(target));
636
637
0
  target->ndata = source->ndata;
638
0
  target->length = source->length;
639
0
  target->attributes = source->attributes;
640
0
  target->attributes.readonly = false;
641
0
  target->attributes.dynamic = false;
642
0
}
643
644
void
645
0
dns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
646
0
  size_t length;
647
0
  isc_region_t r2 = { .base = NULL, .length = 0 };
648
649
  /*
650
   * Make 'name' refer to region 'r'.
651
   */
652
653
0
  REQUIRE(DNS_NAME_VALID(name));
654
0
  REQUIRE(r != NULL);
655
0
  REQUIRE(DNS_NAME_BINDABLE(name));
656
657
0
  name->ndata = r->base;
658
0
  if (name->buffer != NULL) {
659
0
    isc_buffer_clear(name->buffer);
660
0
    isc_buffer_availableregion(name->buffer, &r2);
661
0
    length = (r->length < r2.length) ? r->length : r2.length;
662
0
    if (length > DNS_NAME_MAXWIRE) {
663
0
      length = DNS_NAME_MAXWIRE;
664
0
    }
665
0
  } else {
666
0
    length = (r->length <= DNS_NAME_MAXWIRE) ? r->length
667
0
               : DNS_NAME_MAXWIRE;
668
0
  }
669
670
0
  name->attributes.absolute = false;
671
672
0
  if (length > 0) {
673
0
    size_t offset = 0;
674
0
    uint8_t nlabels = 0;
675
0
    while (offset != length) {
676
0
      uint8_t count;
677
678
0
      INSIST(nlabels < DNS_NAME_MAXLABELS);
679
0
      nlabels++;
680
681
0
      count = name->ndata[offset];
682
0
      INSIST(count <= DNS_NAME_LABELLEN);
683
684
0
      offset += count + 1;
685
0
      INSIST(offset <= length);
686
687
0
      if (count == 0) {
688
0
        name->attributes.absolute = true;
689
0
        break;
690
0
      }
691
0
    }
692
0
    name->length = offset;
693
0
  }
694
695
0
  if (name->buffer != NULL) {
696
    /*
697
     * name->length has been updated by set_offsets to the actual
698
     * length of the name data so we can now copy the actual name
699
     * data and not anything after it.
700
     */
701
0
    if (name->length > 0) {
702
0
      memmove(r2.base, r->base, name->length);
703
0
    }
704
0
    name->ndata = r2.base;
705
0
    isc_buffer_add(name->buffer, name->length);
706
0
  }
707
0
}
708
709
static isc_result_t
710
convert_text(isc_buffer_t *source, const dns_name_t *origin,
711
0
       unsigned int options, dns_name_t *name, isc_buffer_t *target) {
712
0
  unsigned char *ndata = NULL, *label = NULL;
713
0
  char *tdata = NULL;
714
0
  char c;
715
0
  ft_state state;
716
0
  unsigned int value = 0, count = 0;
717
0
  unsigned int n1 = 0, n2 = 0;
718
0
  unsigned int tlen, nrem, nused, digits = 0, labels, tused;
719
0
  bool done;
720
0
  bool downcase;
721
722
0
  REQUIRE(DNS_NAME_VALID(name));
723
0
  REQUIRE(ISC_BUFFER_VALID(source));
724
0
  REQUIRE(ISC_BUFFER_VALID(target));
725
726
0
  downcase = ((options & DNS_NAME_DOWNCASE) != 0);
727
728
0
  if (target == NULL && name->buffer != NULL) {
729
0
    target = name->buffer;
730
0
    isc_buffer_clear(target);
731
0
  }
732
733
0
  REQUIRE(DNS_NAME_BINDABLE(name));
734
735
  /*
736
   * Set up the state machine.
737
   */
738
0
  tdata = (char *)source->base + source->current;
739
0
  tlen = isc_buffer_remaininglength(source);
740
0
  tused = 0;
741
0
  ndata = isc_buffer_used(target);
742
0
  nrem = isc_buffer_availablelength(target);
743
0
  if (nrem > DNS_NAME_MAXWIRE) {
744
0
    nrem = DNS_NAME_MAXWIRE;
745
0
  }
746
0
  nused = 0;
747
0
  labels = 0;
748
0
  done = false;
749
0
  state = ft_init;
750
751
0
  while (nrem > 0 && tlen > 0 && !done) {
752
0
    c = *tdata++;
753
0
    tlen--;
754
0
    tused++;
755
756
0
    switch (state) {
757
0
    case ft_init:
758
      /*
759
       * Is this the root name?
760
       */
761
0
      if (c == '.') {
762
0
        if (tlen != 0) {
763
0
          return DNS_R_EMPTYLABEL;
764
0
        }
765
0
        labels++;
766
0
        *ndata++ = 0;
767
0
        nrem--;
768
0
        nused++;
769
0
        done = true;
770
0
        break;
771
0
      }
772
0
      if (c == '@' && tlen == 0) {
773
0
        state = ft_at;
774
0
        break;
775
0
      }
776
777
0
      FALLTHROUGH;
778
0
    case ft_start:
779
0
      label = ndata;
780
0
      ndata++;
781
0
      nrem--;
782
0
      nused++;
783
0
      count = 0;
784
0
      if (c == '\\') {
785
0
        state = ft_initialescape;
786
0
        break;
787
0
      }
788
0
      state = ft_ordinary;
789
0
      if (nrem == 0) {
790
0
        return ISC_R_NOSPACE;
791
0
      }
792
0
      FALLTHROUGH;
793
0
    case ft_ordinary:
794
0
      if (c == '.') {
795
0
        if (count == 0) {
796
0
          return DNS_R_EMPTYLABEL;
797
0
        }
798
0
        *label = count;
799
0
        labels++;
800
0
        INSIST(labels < DNS_NAME_MAXLABELS);
801
0
        if (tlen == 0) {
802
0
          labels++;
803
0
          *ndata++ = 0;
804
0
          nrem--;
805
0
          nused++;
806
0
          done = true;
807
0
        }
808
0
        state = ft_start;
809
0
      } else if (c == '\\') {
810
0
        state = ft_escape;
811
0
      } else {
812
0
        if (count >= DNS_NAME_LABELLEN) {
813
0
          return DNS_R_LABELTOOLONG;
814
0
        }
815
0
        count++;
816
0
        if (downcase) {
817
0
          c = isc_ascii_tolower(c);
818
0
        }
819
0
        *ndata++ = c;
820
0
        nrem--;
821
0
        nused++;
822
0
      }
823
0
      break;
824
0
    case ft_initialescape:
825
0
      if (c == '[') {
826
        /*
827
         * This looks like a bitstring label, which
828
         * was deprecated.  Intentionally drop it.
829
         */
830
0
        return DNS_R_BADLABELTYPE;
831
0
      }
832
0
      state = ft_escape;
833
0
      POST(state);
834
0
      FALLTHROUGH;
835
0
    case ft_escape:
836
0
      if (!isdigit((unsigned char)c)) {
837
0
        if (count >= DNS_NAME_LABELLEN) {
838
0
          return DNS_R_LABELTOOLONG;
839
0
        }
840
0
        count++;
841
0
        if (downcase) {
842
0
          c = isc_ascii_tolower(c);
843
0
        }
844
0
        *ndata++ = c;
845
0
        nrem--;
846
0
        nused++;
847
0
        state = ft_ordinary;
848
0
        break;
849
0
      }
850
0
      digits = 0;
851
0
      value = 0;
852
0
      state = ft_escdecimal;
853
0
      FALLTHROUGH;
854
0
    case ft_escdecimal:
855
0
      if (!isdigit((unsigned char)c)) {
856
0
        return DNS_R_BADESCAPE;
857
0
      }
858
0
      value = 10 * value + c - '0';
859
0
      digits++;
860
0
      if (digits == 3) {
861
0
        if (value > 255) {
862
0
          return DNS_R_BADESCAPE;
863
0
        }
864
0
        if (count >= DNS_NAME_LABELLEN) {
865
0
          return DNS_R_LABELTOOLONG;
866
0
        }
867
0
        count++;
868
0
        if (downcase) {
869
0
          value = isc_ascii_tolower(value);
870
0
        }
871
0
        *ndata++ = value;
872
0
        nrem--;
873
0
        nused++;
874
0
        state = ft_ordinary;
875
0
      }
876
0
      break;
877
0
    default:
878
0
      FATAL_ERROR("Unexpected state %d", state);
879
      /* Does not return. */
880
0
    }
881
0
  }
882
883
0
  if (!done) {
884
0
    if (nrem == 0) {
885
0
      return ISC_R_NOSPACE;
886
0
    }
887
0
    INSIST(tlen == 0);
888
0
    if (state != ft_ordinary && state != ft_at) {
889
0
      return ISC_R_UNEXPECTEDEND;
890
0
    }
891
0
    if (state == ft_ordinary) {
892
0
      INSIST(count != 0);
893
0
      INSIST(label != NULL);
894
0
      *label = count;
895
0
      labels++;
896
0
      INSIST(labels < DNS_NAME_MAXLABELS);
897
0
    }
898
0
    if (origin != NULL) {
899
0
      if (nrem < origin->length) {
900
0
        return ISC_R_NOSPACE;
901
0
      }
902
0
      label = origin->ndata;
903
0
      n1 = origin->length;
904
0
      nrem -= n1;
905
0
      POST(nrem);
906
0
      while (n1 > 0) {
907
0
        n2 = *label++;
908
0
        INSIST(n2 <= DNS_NAME_LABELLEN);
909
0
        *ndata++ = n2;
910
0
        n1 -= n2 + 1;
911
0
        nused += n2 + 1;
912
0
        while (n2 > 0) {
913
0
          c = *label++;
914
0
          if (downcase) {
915
0
            c = isc_ascii_tolower(c);
916
0
          }
917
0
          *ndata++ = c;
918
0
          n2--;
919
0
        }
920
0
        labels++;
921
0
        if (n1 > 0) {
922
0
          INSIST(labels < DNS_NAME_MAXLABELS);
923
0
        }
924
0
      }
925
0
      if (origin->attributes.absolute) {
926
0
        name->attributes.absolute = true;
927
0
      }
928
0
    }
929
0
  } else {
930
0
    name->attributes.absolute = true;
931
0
  }
932
933
0
  name->ndata = (unsigned char *)target->base + target->used;
934
0
  name->length = nused;
935
936
0
  isc_buffer_forward(source, tused);
937
0
  isc_buffer_add(target, name->length);
938
939
0
  return ISC_R_SUCCESS;
940
0
}
941
942
isc_result_t
943
dns_name_wirefromtext(isc_buffer_t *source, const dns_name_t *origin,
944
0
          unsigned int options, isc_buffer_t *target) {
945
0
  dns_name_t name;
946
947
0
  REQUIRE(ISC_BUFFER_VALID(target));
948
949
0
  dns_name_init(&name);
950
0
  return convert_text(source, origin, options, &name, target);
951
0
}
952
953
isc_result_t
954
dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
955
0
      const dns_name_t *origin, unsigned int options) {
956
0
  REQUIRE(DNS_NAME_VALID(name));
957
0
  REQUIRE(ISC_BUFFER_VALID(name->buffer));
958
959
0
  isc_buffer_clear(name->buffer);
960
0
  return convert_text(source, origin, options, name, name->buffer);
961
0
}
962
963
isc_result_t
964
dns_name_totext(const dns_name_t *name, unsigned int options,
965
0
    isc_buffer_t *target) {
966
0
  unsigned char *ndata;
967
0
  char *tdata;
968
0
  unsigned int nlen, tlen;
969
0
  unsigned char c;
970
0
  unsigned int trem, count;
971
0
  unsigned int labels;
972
0
  bool saw_root = false;
973
0
  unsigned int oused;
974
0
  bool omit_final_dot = ((options & DNS_NAME_OMITFINALDOT) != 0);
975
976
  /*
977
   * This function assumes the name is in proper uncompressed
978
   * wire format.
979
   */
980
0
  REQUIRE(DNS_NAME_VALID(name));
981
0
  REQUIRE(ISC_BUFFER_VALID(target));
982
983
0
  oused = target->used;
984
985
0
  ndata = name->ndata;
986
0
  nlen = name->length;
987
0
  labels = dns_name_countlabels(name);
988
0
  tdata = isc_buffer_used(target);
989
0
  tlen = isc_buffer_availablelength(target);
990
991
0
  trem = tlen;
992
993
0
  if (labels == 0 && nlen == 0) {
994
    /*
995
     * Special handling for an empty name.
996
     */
997
0
    if (trem == 0) {
998
0
      return ISC_R_NOSPACE;
999
0
    }
1000
1001
    /*
1002
     * The names of these booleans are misleading in this case.
1003
     * This empty name is not necessarily from the root node of
1004
     * the DNS root zone, nor is a final dot going to be included.
1005
     * They need to be set this way, though, to keep the "@"
1006
     * from being trounced.
1007
     */
1008
0
    saw_root = true;
1009
0
    omit_final_dot = false;
1010
0
    *tdata++ = '@';
1011
0
    trem--;
1012
1013
    /*
1014
     * Skip the while() loop.
1015
     */
1016
0
    nlen = 0;
1017
0
  } else if (nlen == 1 && labels == 1 && *ndata == '\0') {
1018
    /*
1019
     * Special handling for the root label.
1020
     */
1021
0
    if (trem == 0) {
1022
0
      return ISC_R_NOSPACE;
1023
0
    }
1024
1025
0
    saw_root = true;
1026
0
    omit_final_dot = false;
1027
0
    *tdata++ = '.';
1028
0
    trem--;
1029
1030
    /*
1031
     * Skip the while() loop.
1032
     */
1033
0
    nlen = 0;
1034
0
  }
1035
1036
0
  while (labels > 0 && nlen > 0 && trem > 0) {
1037
0
    labels--;
1038
0
    count = *ndata++;
1039
0
    nlen--;
1040
0
    if (count == 0) {
1041
0
      saw_root = true;
1042
0
      break;
1043
0
    }
1044
0
    if (count <= DNS_NAME_LABELLEN) {
1045
0
      INSIST(nlen >= count);
1046
0
      while (count > 0) {
1047
0
        c = *ndata;
1048
0
        switch (c) {
1049
        /* Special modifiers in zone files. */
1050
0
        case 0x40: /* '@' */
1051
0
        case 0x24: /* '$' */
1052
0
          if ((options & DNS_NAME_PRINCIPAL) != 0)
1053
0
          {
1054
0
            goto no_escape;
1055
0
          }
1056
0
          FALLTHROUGH;
1057
0
        case 0x22: /* '"' */
1058
0
        case 0x28: /* '(' */
1059
0
        case 0x29: /* ')' */
1060
0
        case 0x2E: /* '.' */
1061
0
        case 0x3B: /* ';' */
1062
0
        case 0x5C: /* '\\' */
1063
0
          if (trem < 2) {
1064
0
            return ISC_R_NOSPACE;
1065
0
          }
1066
0
          *tdata++ = '\\';
1067
0
          *tdata++ = c;
1068
0
          ndata++;
1069
0
          trem -= 2;
1070
0
          nlen--;
1071
0
          break;
1072
0
        no_escape:
1073
0
        default:
1074
0
          if (c > 0x20 && c < 0x7f) {
1075
0
            if (trem == 0) {
1076
0
              return ISC_R_NOSPACE;
1077
0
            }
1078
0
            *tdata++ = c;
1079
0
            ndata++;
1080
0
            trem--;
1081
0
            nlen--;
1082
0
          } else {
1083
0
            if (trem < 4) {
1084
0
              return ISC_R_NOSPACE;
1085
0
            }
1086
0
            *tdata++ = 0x5c;
1087
0
            *tdata++ = 0x30 +
1088
0
                 ((c / 100) % 10);
1089
0
            *tdata++ = 0x30 +
1090
0
                 ((c / 10) % 10);
1091
0
            *tdata++ = 0x30 + (c % 10);
1092
0
            trem -= 4;
1093
0
            ndata++;
1094
0
            nlen--;
1095
0
          }
1096
0
        }
1097
0
        count--;
1098
0
      }
1099
0
    } else {
1100
0
      FATAL_ERROR("Unexpected label type %02x", count);
1101
0
      UNREACHABLE();
1102
0
    }
1103
1104
    /*
1105
     * The following assumes names are absolute.  If not, we
1106
     * fix things up later.  Note that this means that in some
1107
     * cases one more byte of text buffer is required than is
1108
     * needed in the final output.
1109
     */
1110
0
    if (trem == 0) {
1111
0
      return ISC_R_NOSPACE;
1112
0
    }
1113
0
    *tdata++ = '.';
1114
0
    trem--;
1115
0
  }
1116
1117
0
  if (nlen != 0 && trem == 0) {
1118
0
    return ISC_R_NOSPACE;
1119
0
  }
1120
1121
0
  if (!saw_root || omit_final_dot) {
1122
0
    trem++;
1123
0
    tdata--;
1124
0
  }
1125
0
  if (trem > 0) {
1126
0
    *tdata = 0;
1127
0
  }
1128
0
  isc_buffer_add(target, tlen - trem);
1129
1130
0
  if (totext_filter_proc != NULL) {
1131
0
    return (totext_filter_proc)(target, oused);
1132
0
  }
1133
1134
0
  return ISC_R_SUCCESS;
1135
0
}
1136
1137
isc_result_t
1138
dns_name_tofilenametext(const dns_name_t *name, bool omit_final_dot,
1139
0
      isc_buffer_t *target) {
1140
0
  unsigned char *ndata;
1141
0
  char *tdata;
1142
0
  unsigned int nlen, tlen;
1143
0
  unsigned char c;
1144
0
  unsigned int trem, count;
1145
0
  unsigned int labels;
1146
1147
  /*
1148
   * This function assumes the name is in proper uncompressed
1149
   * wire format.
1150
   */
1151
0
  REQUIRE(DNS_NAME_VALID(name));
1152
0
  REQUIRE(name->attributes.absolute);
1153
0
  REQUIRE(ISC_BUFFER_VALID(target));
1154
1155
0
  ndata = name->ndata;
1156
0
  nlen = name->length;
1157
0
  labels = dns_name_countlabels(name);
1158
0
  tdata = isc_buffer_used(target);
1159
0
  tlen = isc_buffer_availablelength(target);
1160
1161
0
  trem = tlen;
1162
1163
0
  if (nlen == 1 && labels == 1 && *ndata == '\0') {
1164
    /*
1165
     * Special handling for the root label.
1166
     */
1167
0
    if (trem == 0) {
1168
0
      return ISC_R_NOSPACE;
1169
0
    }
1170
1171
0
    omit_final_dot = false;
1172
0
    *tdata++ = '.';
1173
0
    trem--;
1174
1175
    /*
1176
     * Skip the while() loop.
1177
     */
1178
0
    nlen = 0;
1179
0
  }
1180
1181
0
  while (labels > 0 && nlen > 0 && trem > 0) {
1182
0
    labels--;
1183
0
    count = *ndata++;
1184
0
    nlen--;
1185
0
    if (count == 0) {
1186
0
      break;
1187
0
    }
1188
0
    if (count <= DNS_NAME_LABELLEN) {
1189
0
      INSIST(nlen >= count);
1190
0
      while (count > 0) {
1191
0
        c = *ndata;
1192
0
        if ((c >= 0x30 && c <= 0x39) || /* digit */
1193
0
            (c >= 0x41 && c <= 0x5A) || /* uppercase */
1194
0
            (c >= 0x61 && c <= 0x7A) || /* lowercase */
1195
0
            c == 0x2D ||   /* hyphen */
1196
0
            c == 0x5F)     /* underscore */
1197
0
        {
1198
0
          if (trem == 0) {
1199
0
            return ISC_R_NOSPACE;
1200
0
          }
1201
          /* downcase */
1202
0
          if (c >= 0x41 && c <= 0x5A) {
1203
0
            c += 0x20;
1204
0
          }
1205
0
          *tdata++ = c;
1206
0
          ndata++;
1207
0
          trem--;
1208
0
          nlen--;
1209
0
        } else {
1210
0
          if (trem < 4) {
1211
0
            return ISC_R_NOSPACE;
1212
0
          }
1213
0
          snprintf(tdata, trem, "%%%02X", c);
1214
0
          tdata += 3;
1215
0
          trem -= 3;
1216
0
          ndata++;
1217
0
          nlen--;
1218
0
        }
1219
0
        count--;
1220
0
      }
1221
0
    } else {
1222
0
      FATAL_ERROR("Unexpected label type %02x", count);
1223
0
      UNREACHABLE();
1224
0
    }
1225
1226
    /*
1227
     * The following assumes names are absolute.  If not, we
1228
     * fix things up later.  Note that this means that in some
1229
     * cases one more byte of text buffer is required than is
1230
     * needed in the final output.
1231
     */
1232
0
    if (trem == 0) {
1233
0
      return ISC_R_NOSPACE;
1234
0
    }
1235
0
    *tdata++ = '.';
1236
0
    trem--;
1237
0
  }
1238
1239
0
  if (nlen != 0 && trem == 0) {
1240
0
    return ISC_R_NOSPACE;
1241
0
  }
1242
1243
0
  if (omit_final_dot) {
1244
0
    trem++;
1245
0
  }
1246
1247
0
  isc_buffer_add(target, tlen - trem);
1248
1249
0
  return ISC_R_SUCCESS;
1250
0
}
1251
1252
isc_result_t
1253
0
dns_name_downcase(const dns_name_t *source, dns_name_t *name) {
1254
  /*
1255
   * Downcase 'source'.
1256
   */
1257
1258
0
  REQUIRE(DNS_NAME_VALID(source));
1259
0
  REQUIRE(DNS_NAME_VALID(name));
1260
1261
0
  if (source == name) {
1262
0
    REQUIRE(!name->attributes.readonly);
1263
0
    isc_ascii_lowercopy(name->ndata, source->ndata, source->length);
1264
0
    return ISC_R_SUCCESS;
1265
0
  }
1266
1267
0
  REQUIRE(DNS_NAME_BINDABLE(name));
1268
0
  REQUIRE(ISC_BUFFER_VALID(name->buffer));
1269
1270
0
  isc_buffer_clear(name->buffer);
1271
0
  name->ndata = (uint8_t *)name->buffer->base + name->buffer->used;
1272
1273
  /* label lengths are < 64 so tolower() does not affect them */
1274
0
  isc_ascii_lowercopy(name->ndata, source->ndata, source->length);
1275
1276
0
  name->length = source->length;
1277
0
  name->attributes = (struct dns_name_attrs){
1278
0
    .absolute = source->attributes.absolute
1279
0
  };
1280
0
  isc_buffer_add(name->buffer, name->length);
1281
1282
0
  return ISC_R_SUCCESS;
1283
0
}
1284
1285
isc_result_t
1286
dns_name_fromwire(dns_name_t *const name, isc_buffer_t *const source,
1287
0
      const dns_decompress_t dctx, isc_buffer_t *target) {
1288
  /*
1289
   * Copy the name at source into target, decompressing it.
1290
   *
1291
   *  *** WARNING ***
1292
   *
1293
   * dns_name_fromwire() deals with raw network data. An error in this
1294
   * routine could result in the failure or hijacking of the server.
1295
   *
1296
   * The description of name compression in RFC 1035 section 4.1.4 is
1297
   * subtle wrt certain edge cases. The first important sentence is:
1298
   *
1299
   * > In this scheme, an entire domain name or a list of labels at the
1300
   * > end of a domain name is replaced with a pointer to a prior
1301
   * > occurance of the same name.
1302
   *
1303
   * The key word is "prior". This says that compression pointers must
1304
   * point strictly earlier in the message (before our "marker" variable),
1305
   * which is enough to prevent DoS attacks due to compression loops.
1306
   *
1307
   * The next important sentence is:
1308
   *
1309
   * > If a domain name is contained in a part of the message subject to a
1310
   * > length field (such as the RDATA section of an RR), and compression
1311
   * > is used, the length of the compressed name is used in the length
1312
   * > calculation, rather than the length of the expanded name.
1313
   *
1314
   * When decompressing, this means that the amount of the source buffer
1315
   * that we consumed (which is checked wrt the container's length field)
1316
   * is the length of the compressed name. A compressed name is defined as
1317
   * a sequence of labels ending with the root label or a compression
1318
   * pointer, that is, the segment of the name that dns_name_fromwire()
1319
   * examines first.
1320
   *
1321
   * This matters when handling names that play dirty tricks, like:
1322
   *
1323
   *  +---+---+---+---+---+---+
1324
   *  | 4 | 1 |'a'|192| 0 | 0 |
1325
   *  +---+---+---+---+---+---+
1326
   *
1327
   * We start at octet 1. There is an ordinary single character label "a",
1328
   * followed by a compression pointer that refers back to octet zero.
1329
   * Here there is a label of length 4, which weirdly re-uses the octets
1330
   * we already examined as the data for the label. It is followed by the
1331
   * root label,
1332
   *
1333
   * The specification says that the compressed name ends after the first
1334
   * zero octet (after the compression pointer) not the second zero octet,
1335
   * even though the second octet is later in the message. This shows the
1336
   * correct way to set our "consumed" variable.
1337
   */
1338
1339
0
  REQUIRE(DNS_NAME_VALID(name));
1340
0
  REQUIRE(DNS_NAME_BINDABLE(name));
1341
0
  REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1342
0
    (target == NULL && ISC_BUFFER_VALID(name->buffer)));
1343
1344
0
  if (target == NULL && name->buffer != NULL) {
1345
0
    target = name->buffer;
1346
0
    isc_buffer_clear(target);
1347
0
  }
1348
1349
0
  uint8_t *const name_buf = isc_buffer_used(target);
1350
0
  const uint32_t name_max = ISC_MIN(DNS_NAME_MAXWIRE,
1351
0
            isc_buffer_availablelength(target));
1352
0
  uint32_t name_len = 0;
1353
1354
  /*
1355
   * After chasing a compression pointer, these variables refer to the
1356
   * source buffer as follows:
1357
   *
1358
   * sb --- mr --- cr --- st --- cd --- sm
1359
   *
1360
   * sb = source_buf (const)
1361
   * mr = marker
1362
   * cr = cursor
1363
   * st = start (const)
1364
   * cd = consumed
1365
   * sm = source_max (const)
1366
   *
1367
   * The marker hops backwards for each pointer.
1368
   * The cursor steps forwards for each label.
1369
   * The amount of the source we consumed is set once.
1370
   */
1371
0
  const uint8_t *const source_buf = isc_buffer_base(source);
1372
0
  const uint8_t *const source_max = isc_buffer_used(source);
1373
0
  const uint8_t *const start = isc_buffer_current(source);
1374
0
  const uint8_t *marker = start;
1375
0
  const uint8_t *cursor = start;
1376
0
  const uint8_t *consumed = NULL;
1377
1378
  /*
1379
   * One iteration per label.
1380
   */
1381
0
  while (cursor < source_max) {
1382
0
    const uint8_t label_len = *cursor++;
1383
0
    if (label_len <= DNS_NAME_LABELLEN) {
1384
      /*
1385
       * Normal label: record its offset, and check bounds on
1386
       * the name length, which also ensures we don't overrun
1387
       * the offsets array. Don't touch any source bytes yet!
1388
       * The source bounds check will happen when we loop.
1389
       */
1390
      /* and then a step to the ri-i-i-i-i-ight */
1391
0
      cursor += label_len;
1392
0
      name_len += label_len + 1;
1393
0
      if (name_len > name_max) {
1394
0
        return name_max == DNS_NAME_MAXWIRE
1395
0
                 ? DNS_R_NAMETOOLONG
1396
0
                 : ISC_R_NOSPACE;
1397
0
      } else if (label_len == 0) {
1398
0
        goto root_label;
1399
0
      }
1400
0
    } else if (label_len < 192) {
1401
0
      return DNS_R_BADLABELTYPE;
1402
0
    } else if (!dns_decompress_getpermitted(dctx)) {
1403
0
      return DNS_R_DISALLOWED;
1404
0
    } else if (cursor < source_max) {
1405
      /*
1406
       * Compression pointer. Ensure it does not loop.
1407
       *
1408
       * Copy multiple labels in one go, to make the most of
1409
       * memmove() performance. Start at the marker and finish
1410
       * just before the pointer's hi+lo bytes, before the
1411
       * cursor. Bounds were already checked.
1412
       */
1413
0
      const uint32_t hi = label_len & 0x3F;
1414
0
      const uint32_t lo = *cursor++;
1415
0
      const uint8_t *pointer = source_buf + (256 * hi + lo);
1416
0
      if (pointer >= marker) {
1417
0
        return DNS_R_BADPOINTER;
1418
0
      }
1419
0
      const uint32_t copy_len = (cursor - 2) - marker;
1420
0
      uint8_t *const dest = name_buf + name_len - copy_len;
1421
0
      memmove(dest, marker, copy_len);
1422
0
      consumed = consumed != NULL ? consumed : cursor;
1423
      /* it's just a jump to the left */
1424
0
      cursor = marker = pointer;
1425
0
    }
1426
0
  }
1427
0
  return ISC_R_UNEXPECTEDEND;
1428
0
root_label:;
1429
  /*
1430
   * Copy labels almost like we do for compression pointers,
1431
   * from the marker up to and including the root label.
1432
   */
1433
0
  const uint32_t copy_len = cursor - marker;
1434
0
  memmove(name_buf + name_len - copy_len, marker, copy_len);
1435
0
  consumed = consumed != NULL ? consumed : cursor;
1436
0
  isc_buffer_forward(source, consumed - start);
1437
1438
0
  name->attributes.absolute = true;
1439
0
  name->ndata = name_buf;
1440
0
  name->length = name_len;
1441
0
  isc_buffer_add(target, name_len);
1442
1443
0
  return ISC_R_SUCCESS;
1444
0
}
1445
1446
isc_result_t
1447
dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
1448
0
    isc_buffer_t *target) {
1449
0
  bool compress, multi;
1450
0
  unsigned int here;
1451
0
  unsigned int prefix_length;
1452
0
  unsigned int suffix_coff;
1453
1454
  /*
1455
   * Convert 'name' into wire format, compressing it as specified by the
1456
   * compression context 'cctx' (or without compressing if 'cctx'
1457
   * is NULL), and storing the result in 'target'.
1458
   */
1459
1460
0
  REQUIRE(DNS_NAME_VALID(name));
1461
0
  REQUIRE(ISC_BUFFER_VALID(target));
1462
1463
0
  if (cctx == NULL) {
1464
0
    if (isc_buffer_availablelength(target) < name->length) {
1465
0
      return ISC_R_NOSPACE;
1466
0
    }
1467
0
    memmove(isc_buffer_used(target), name->ndata, name->length);
1468
0
    isc_buffer_add(target, name->length);
1469
0
    return ISC_R_SUCCESS;
1470
0
  }
1471
1472
0
  compress = !name->attributes.nocompress &&
1473
0
       dns_compress_getpermitted(cctx);
1474
0
  multi = compress && dns_compress_getmultiuse(cctx);
1475
1476
  /*
1477
   * Write a compression pointer directly if the caller passed us
1478
   * a pointer to this name's offset that we saved previously.
1479
   */
1480
0
  if (multi && cctx->coff < 0x4000) {
1481
0
    if (isc_buffer_availablelength(target) < 2) {
1482
0
      return ISC_R_NOSPACE;
1483
0
    }
1484
0
    isc_buffer_putuint16(target, cctx->coff | 0xc000);
1485
0
    return ISC_R_SUCCESS;
1486
0
  }
1487
1488
  /*
1489
   * Always add the name to the compression context; if compression
1490
   * is off, reset the return values before writing the name.
1491
   */
1492
0
  prefix_length = name->length;
1493
0
  suffix_coff = 0;
1494
0
  dns_compress_name(cctx, target, name, &prefix_length, &suffix_coff);
1495
0
  if (!compress) {
1496
0
    prefix_length = name->length;
1497
0
    suffix_coff = 0;
1498
0
  }
1499
1500
  /*
1501
   * Return this name's compression offset for use next time, provided
1502
   * it isn't too short for compression to help (i.e. it's the root)
1503
   */
1504
0
  here = isc_buffer_usedlength(target);
1505
0
  if (multi && here < 0x4000 && prefix_length > 1) {
1506
0
    cctx->coff = (uint16_t)here;
1507
0
  }
1508
1509
0
  if (prefix_length > 0) {
1510
0
    if (isc_buffer_availablelength(target) < prefix_length) {
1511
0
      return ISC_R_NOSPACE;
1512
0
    }
1513
0
    memmove(isc_buffer_used(target), name->ndata, prefix_length);
1514
0
    isc_buffer_add(target, prefix_length);
1515
0
  }
1516
1517
0
  if (suffix_coff > 0) {
1518
0
    if (multi && prefix_length == 0) {
1519
0
      cctx->coff = suffix_coff;
1520
0
    }
1521
0
    if (isc_buffer_availablelength(target) < 2) {
1522
0
      return ISC_R_NOSPACE;
1523
0
    }
1524
0
    isc_buffer_putuint16(target, suffix_coff | 0xc000);
1525
0
  }
1526
1527
0
  return ISC_R_SUCCESS;
1528
0
}
1529
1530
isc_result_t
1531
dns_name_concatenate(const dns_name_t *prefix, const dns_name_t *suffix,
1532
0
         dns_name_t *name) {
1533
0
  unsigned char *ndata = NULL;
1534
0
  unsigned int nrem, prefix_length, length;
1535
0
  bool copy_prefix = true;
1536
0
  bool copy_suffix = true;
1537
0
  bool absolute = false;
1538
0
  dns_name_t tmp_name;
1539
0
  isc_buffer_t *target = NULL;
1540
1541
  /*
1542
   * Concatenate 'prefix' and 'suffix'.
1543
   */
1544
1545
0
  REQUIRE(prefix == NULL || DNS_NAME_VALID(prefix));
1546
0
  REQUIRE(suffix == NULL || DNS_NAME_VALID(suffix));
1547
0
  REQUIRE(DNS_NAME_VALID(name) && ISC_BUFFER_VALID(name->buffer));
1548
0
  REQUIRE(DNS_NAME_BINDABLE(name));
1549
1550
0
  if (prefix == NULL || prefix->length == 0) {
1551
0
    copy_prefix = false;
1552
0
  }
1553
0
  if (suffix == NULL || suffix->length == 0) {
1554
0
    copy_suffix = false;
1555
0
  }
1556
0
  if (copy_prefix && prefix->attributes.absolute) {
1557
0
    absolute = true;
1558
0
    REQUIRE(!copy_suffix);
1559
0
  }
1560
0
  if (name == NULL) {
1561
0
    dns_name_init(&tmp_name);
1562
0
    name = &tmp_name;
1563
0
  }
1564
1565
0
  target = name->buffer;
1566
0
  isc_buffer_clear(target);
1567
1568
  /*
1569
   * Set up.
1570
   */
1571
0
  nrem = target->length - target->used;
1572
0
  ndata = (unsigned char *)target->base + target->used;
1573
0
  if (nrem > DNS_NAME_MAXWIRE) {
1574
0
    nrem = DNS_NAME_MAXWIRE;
1575
0
  }
1576
0
  length = 0;
1577
0
  prefix_length = 0;
1578
0
  if (copy_prefix) {
1579
0
    prefix_length = prefix->length;
1580
0
    length += prefix_length;
1581
0
  }
1582
0
  if (copy_suffix) {
1583
0
    length += suffix->length;
1584
0
  }
1585
0
  if (length > DNS_NAME_MAXWIRE) {
1586
0
    return DNS_R_NAMETOOLONG;
1587
0
  }
1588
0
  if (length > nrem) {
1589
0
    return ISC_R_NOSPACE;
1590
0
  }
1591
1592
0
  if (copy_suffix) {
1593
0
    if (suffix->attributes.absolute) {
1594
0
      absolute = true;
1595
0
    }
1596
0
    memmove(ndata + prefix_length, suffix->ndata, suffix->length);
1597
0
  }
1598
1599
  /*
1600
   * If 'prefix' and 'name' are the same object, we don't have to
1601
   * copy anything.
1602
   */
1603
0
  if (copy_prefix && (prefix != name || prefix->buffer != target)) {
1604
0
    memmove(ndata, prefix->ndata, prefix_length);
1605
0
  }
1606
1607
0
  name->ndata = ndata;
1608
0
  name->length = length;
1609
0
  name->attributes.absolute = absolute;
1610
1611
0
  isc_buffer_add(target, name->length);
1612
1613
0
  return ISC_R_SUCCESS;
1614
0
}
1615
1616
void
1617
0
dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
1618
  /*
1619
   * Make 'target' a dynamically allocated copy of 'source'.
1620
   */
1621
1622
0
  REQUIRE(DNS_NAME_VALID(source));
1623
0
  REQUIRE(source->length > 0);
1624
0
  REQUIRE(DNS_NAME_VALID(target));
1625
0
  REQUIRE(DNS_NAME_BINDABLE(target));
1626
1627
0
  target->ndata = isc_mem_get(mctx, source->length);
1628
1629
0
  memmove(target->ndata, source->ndata, source->length);
1630
1631
0
  target->length = source->length;
1632
0
  target->attributes = (struct dns_name_attrs){ .dynamic = true };
1633
0
  target->attributes.absolute = source->attributes.absolute;
1634
0
}
1635
1636
void
1637
0
dns_name_free(dns_name_t *name, isc_mem_t *mctx) {
1638
0
  size_t size;
1639
1640
  /*
1641
   * Free 'name'.
1642
   */
1643
1644
0
  REQUIRE(DNS_NAME_VALID(name));
1645
0
  REQUIRE(name->attributes.dynamic);
1646
1647
0
  size = name->length;
1648
0
  isc_mem_put(mctx, name->ndata, size);
1649
0
  dns_name_invalidate(name);
1650
0
}
1651
1652
size_t
1653
0
dns_name_size(const dns_name_t *name) {
1654
0
  size_t size;
1655
1656
0
  REQUIRE(DNS_NAME_VALID(name));
1657
1658
0
  if (!name->attributes.dynamic) {
1659
0
    return 0;
1660
0
  }
1661
1662
0
  size = name->length;
1663
1664
0
  return size;
1665
0
}
1666
1667
isc_result_t
1668
0
dns_name_digest(const dns_name_t *name, dns_digestfunc_t digest, void *arg) {
1669
  /*
1670
   * Send 'name' in DNSSEC canonical form to 'digest'.
1671
   */
1672
1673
0
  REQUIRE(DNS_NAME_VALID(name));
1674
0
  REQUIRE(digest != NULL);
1675
1676
0
  unsigned char ndata[DNS_NAME_MAXWIRE];
1677
0
  isc_ascii_lowercopy(ndata, name->ndata, name->length);
1678
1679
0
  isc_region_t r = {
1680
0
    .base = ndata,
1681
0
    .length = name->length,
1682
0
  };
1683
0
  return (digest)(arg, &r);
1684
0
}
1685
1686
bool
1687
0
dns_name_dynamic(const dns_name_t *name) {
1688
0
  REQUIRE(DNS_NAME_VALID(name));
1689
1690
  /*
1691
   * Returns whether there is dynamic memory associated with this name.
1692
   */
1693
1694
0
  return name->attributes.dynamic;
1695
0
}
1696
1697
isc_result_t
1698
0
dns_name_print(const dns_name_t *name, FILE *stream) {
1699
0
  isc_result_t result;
1700
0
  isc_buffer_t b;
1701
0
  isc_region_t r;
1702
0
  char t[1024];
1703
1704
  /*
1705
   * Print 'name' on 'stream'.
1706
   */
1707
1708
0
  REQUIRE(DNS_NAME_VALID(name));
1709
1710
0
  isc_buffer_init(&b, t, sizeof(t));
1711
0
  result = dns_name_totext(name, 0, &b);
1712
0
  if (result != ISC_R_SUCCESS) {
1713
0
    return result;
1714
0
  }
1715
0
  isc_buffer_usedregion(&b, &r);
1716
0
  fprintf(stream, "%.*s", (int)r.length, (char *)r.base);
1717
1718
0
  return ISC_R_SUCCESS;
1719
0
}
1720
1721
isc_result_t
1722
0
dns_name_settotextfilter(dns_name_totextfilter_t *proc) {
1723
  /*
1724
   * If we already have been here set / clear as appropriate.
1725
   */
1726
0
  if (totext_filter_proc != NULL && proc != NULL) {
1727
0
    if (totext_filter_proc == proc) {
1728
0
      return ISC_R_SUCCESS;
1729
0
    }
1730
0
  }
1731
0
  if (proc == NULL && totext_filter_proc != NULL) {
1732
0
    totext_filter_proc = NULL;
1733
0
    return ISC_R_SUCCESS;
1734
0
  }
1735
1736
0
  totext_filter_proc = proc;
1737
1738
0
  return ISC_R_SUCCESS;
1739
0
}
1740
1741
void
1742
0
dns_name_format(const dns_name_t *name, char *cp, unsigned int size) {
1743
0
  isc_result_t result;
1744
0
  isc_buffer_t buf;
1745
1746
0
  REQUIRE(size > 0);
1747
1748
  /*
1749
   * Leave room for null termination after buffer.
1750
   */
1751
0
  isc_buffer_init(&buf, cp, size - 1);
1752
0
  result = dns_name_totext(name, DNS_NAME_OMITFINALDOT, &buf);
1753
0
  if (result == ISC_R_SUCCESS) {
1754
0
    isc_buffer_putuint8(&buf, (uint8_t)'\0');
1755
0
  } else {
1756
0
    snprintf(cp, size, "<unknown>");
1757
0
  }
1758
0
}
1759
1760
/*
1761
 * dns_name_tostring() -- similar to dns_name_format() but allocates its own
1762
 * memory.
1763
 */
1764
isc_result_t
1765
0
dns_name_tostring(const dns_name_t *name, char **target, isc_mem_t *mctx) {
1766
0
  isc_result_t result;
1767
0
  isc_buffer_t buf;
1768
0
  isc_region_t reg;
1769
0
  char *p, txt[DNS_NAME_FORMATSIZE];
1770
1771
0
  REQUIRE(DNS_NAME_VALID(name));
1772
0
  REQUIRE(target != NULL && *target == NULL);
1773
1774
0
  isc_buffer_init(&buf, txt, sizeof(txt));
1775
0
  result = dns_name_totext(name, 0, &buf);
1776
0
  if (result != ISC_R_SUCCESS) {
1777
0
    return result;
1778
0
  }
1779
1780
0
  isc_buffer_usedregion(&buf, &reg);
1781
0
  p = isc_mem_allocate(mctx, reg.length + 1);
1782
0
  memmove(p, (char *)reg.base, (int)reg.length);
1783
0
  p[reg.length] = '\0';
1784
1785
0
  *target = p;
1786
0
  return ISC_R_SUCCESS;
1787
0
}
1788
1789
isc_result_t
1790
dns_name_fromstring(dns_name_t *target, const char *src,
1791
        const dns_name_t *origin, unsigned int options,
1792
0
        isc_mem_t *mctx) {
1793
0
  isc_result_t result;
1794
0
  isc_buffer_t buf;
1795
0
  dns_fixedname_t fn;
1796
0
  dns_name_t *name;
1797
1798
0
  REQUIRE(src != NULL);
1799
1800
0
  isc_buffer_constinit(&buf, src, strlen(src));
1801
0
  isc_buffer_add(&buf, strlen(src));
1802
0
  if (DNS_NAME_BINDABLE(target) && target->buffer != NULL) {
1803
0
    name = target;
1804
0
  } else {
1805
0
    name = dns_fixedname_initname(&fn);
1806
0
  }
1807
1808
0
  result = dns_name_fromtext(name, &buf, origin, options);
1809
0
  if (result != ISC_R_SUCCESS) {
1810
0
    return result;
1811
0
  }
1812
1813
0
  if (name != target) {
1814
0
    dns_name_dup(name, mctx, target);
1815
0
  }
1816
0
  return result;
1817
0
}
1818
1819
void
1820
0
dns_name_copy(const dns_name_t *source, dns_name_t *dest) {
1821
0
  isc_buffer_t *target = NULL;
1822
0
  unsigned char *ndata = NULL;
1823
1824
0
  REQUIRE(DNS_NAME_VALID(source));
1825
0
  REQUIRE(DNS_NAME_VALID(dest));
1826
0
  REQUIRE(DNS_NAME_BINDABLE(dest));
1827
1828
0
  target = dest->buffer;
1829
1830
0
  REQUIRE(target != NULL);
1831
0
  REQUIRE(target->length >= source->length);
1832
1833
0
  isc_buffer_clear(target);
1834
1835
0
  ndata = (unsigned char *)target->base;
1836
0
  dest->ndata = target->base;
1837
1838
0
  if (source->length != 0) {
1839
0
    memmove(ndata, source->ndata, source->length);
1840
0
  }
1841
1842
0
  dest->ndata = ndata;
1843
0
  dest->length = source->length;
1844
0
  dest->attributes.absolute = source->attributes.absolute;
1845
1846
0
  isc_buffer_add(target, dest->length);
1847
0
}
1848
1849
/*
1850
 * Service Discovery Prefixes RFC 6763.
1851
 */
1852
static unsigned char b_dns_sd_udp_data[] = "\001b\007_dns-sd\004_udp";
1853
static unsigned char db_dns_sd_udp_data[] = "\002db\007_dns-sd\004_udp";
1854
static unsigned char r_dns_sd_udp_data[] = "\001r\007_dns-sd\004_udp";
1855
static unsigned char dr_dns_sd_udp_data[] = "\002dr\007_dns-sd\004_udp";
1856
static unsigned char lb_dns_sd_udp_data[] = "\002lb\007_dns-sd\004_udp";
1857
1858
static dns_name_t const dns_sd[] = {
1859
  DNS_NAME_INITNONABSOLUTE(b_dns_sd_udp_data),
1860
  DNS_NAME_INITNONABSOLUTE(db_dns_sd_udp_data),
1861
  DNS_NAME_INITNONABSOLUTE(r_dns_sd_udp_data),
1862
  DNS_NAME_INITNONABSOLUTE(dr_dns_sd_udp_data),
1863
  DNS_NAME_INITNONABSOLUTE(lb_dns_sd_udp_data)
1864
};
1865
1866
bool
1867
0
dns_name_isdnssd(const dns_name_t *name) {
1868
0
  size_t i;
1869
0
  dns_name_t prefix;
1870
1871
0
  if (dns_name_countlabels(name) > 3U) {
1872
0
    dns_name_init(&prefix);
1873
0
    dns_name_getlabelsequence(name, 0, 3, &prefix);
1874
0
    for (i = 0; i < (sizeof(dns_sd) / sizeof(dns_sd[0])); i++) {
1875
0
      if (dns_name_equal(&prefix, &dns_sd[i])) {
1876
0
        return true;
1877
0
      }
1878
0
    }
1879
0
  }
1880
1881
0
  return false;
1882
0
}
1883
1884
static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
1885
1886
static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
1887
static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
1888
static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
1889
static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
1890
static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
1891
static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
1892
static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
1893
static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
1894
static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
1895
static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
1896
static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
1897
static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
1898
static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
1899
static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
1900
static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
1901
static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
1902
1903
static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
1904
1905
static dns_name_t const rfc1918names[] = {
1906
  DNS_NAME_INITABSOLUTE(inaddr10),    DNS_NAME_INITABSOLUTE(inaddr16172),
1907
  DNS_NAME_INITABSOLUTE(inaddr17172), DNS_NAME_INITABSOLUTE(inaddr18172),
1908
  DNS_NAME_INITABSOLUTE(inaddr19172), DNS_NAME_INITABSOLUTE(inaddr20172),
1909
  DNS_NAME_INITABSOLUTE(inaddr21172), DNS_NAME_INITABSOLUTE(inaddr22172),
1910
  DNS_NAME_INITABSOLUTE(inaddr23172), DNS_NAME_INITABSOLUTE(inaddr24172),
1911
  DNS_NAME_INITABSOLUTE(inaddr25172), DNS_NAME_INITABSOLUTE(inaddr26172),
1912
  DNS_NAME_INITABSOLUTE(inaddr27172), DNS_NAME_INITABSOLUTE(inaddr28172),
1913
  DNS_NAME_INITABSOLUTE(inaddr29172), DNS_NAME_INITABSOLUTE(inaddr30172),
1914
  DNS_NAME_INITABSOLUTE(inaddr31172), DNS_NAME_INITABSOLUTE(inaddr168192)
1915
};
1916
1917
bool
1918
0
dns_name_isrfc1918(const dns_name_t *name) {
1919
0
  size_t i;
1920
1921
0
  for (i = 0; i < (sizeof(rfc1918names) / sizeof(*rfc1918names)); i++) {
1922
0
    if (dns_name_issubdomain(name, &rfc1918names[i])) {
1923
0
      return true;
1924
0
    }
1925
0
  }
1926
0
  return false;
1927
0
}
1928
1929
static unsigned char ip6fc[] = "\001c\001f\003ip6\004ARPA";
1930
static unsigned char ip6fd[] = "\001d\001f\003ip6\004ARPA";
1931
1932
static dns_name_t const ulanames[] = { DNS_NAME_INITABSOLUTE(ip6fc),
1933
               DNS_NAME_INITABSOLUTE(ip6fd) };
1934
1935
bool
1936
0
dns_name_isula(const dns_name_t *name) {
1937
0
  size_t i;
1938
1939
0
  for (i = 0; i < (sizeof(ulanames) / sizeof(*ulanames)); i++) {
1940
0
    if (dns_name_issubdomain(name, &ulanames[i])) {
1941
0
      return true;
1942
0
    }
1943
0
  }
1944
0
  return false;
1945
0
}
1946
1947
bool
1948
0
dns_name_istat(const dns_name_t *name) {
1949
0
  unsigned char len;
1950
0
  const unsigned char *ndata;
1951
1952
0
  REQUIRE(DNS_NAME_VALID(name));
1953
1954
0
  if (name->length == 0) {
1955
0
    return false;
1956
0
  }
1957
1958
0
  ndata = name->ndata;
1959
0
  len = ndata[0];
1960
0
  INSIST(len <= name->length);
1961
0
  ndata++;
1962
1963
  /*
1964
   * Is there at least one trust anchor reported and is the
1965
   * label length consistent with a trust-anchor-telemetry label.
1966
   */
1967
0
  if ((len < 8) || (len - 3) % 5 != 0) {
1968
0
    return false;
1969
0
  }
1970
1971
0
  if (ndata[0] != '_' || isc_ascii_tolower(ndata[1]) != 't' ||
1972
0
      isc_ascii_tolower(ndata[2]) != 'a')
1973
0
  {
1974
0
    return false;
1975
0
  }
1976
0
  ndata += 3;
1977
0
  len -= 3;
1978
1979
0
  while (len > 0) {
1980
0
    INSIST(len >= 5);
1981
0
    if (ndata[0] != '-' || !isc_hex_char(ndata[1]) ||
1982
0
        !isc_hex_char(ndata[2]) || !isc_hex_char(ndata[3]) ||
1983
0
        !isc_hex_char(ndata[4]))
1984
0
    {
1985
0
      return false;
1986
0
    }
1987
0
    ndata += 5;
1988
0
    len -= 5;
1989
0
  }
1990
0
  return true;
1991
0
}
1992
1993
bool
1994
0
dns_name_isdnssvcb(const dns_name_t *name) {
1995
0
  unsigned char len, len1;
1996
0
  const unsigned char *ndata;
1997
1998
0
  REQUIRE(DNS_NAME_VALID(name));
1999
2000
0
  if (name->length < 5) {
2001
0
    return false;
2002
0
  }
2003
2004
0
  ndata = name->ndata;
2005
0
  len = len1 = ndata[0];
2006
0
  INSIST(len <= name->length);
2007
0
  ndata++;
2008
2009
0
  if (len < 2 || ndata[0] != '_') {
2010
0
    return false;
2011
0
  }
2012
0
  if (isdigit(ndata[1]) && name->length > len + 1) {
2013
0
    char buf[sizeof("65000")];
2014
0
    long port;
2015
0
    char *endp;
2016
2017
    /*
2018
     * Do we have a valid _port label?
2019
     */
2020
0
    if (len > 6U || (ndata[1] == '0' && len != 2)) {
2021
0
      return false;
2022
0
    }
2023
0
    memcpy(buf, ndata + 1, len - 1);
2024
0
    buf[len - 1] = 0;
2025
0
    port = strtol(buf, &endp, 10);
2026
0
    if (*endp != 0 || port < 0 || port > 0xffff) {
2027
0
      return false;
2028
0
    }
2029
2030
    /*
2031
     * Move to next label.
2032
     */
2033
0
    ndata += len;
2034
0
    INSIST(len1 + 1U < name->length);
2035
0
    len = *ndata;
2036
0
    INSIST(len + len1 + 1U <= name->length);
2037
0
    ndata++;
2038
0
  }
2039
2040
0
  if (len == 4U && strncasecmp((const char *)ndata, "_dns", 4) == 0) {
2041
0
    return true;
2042
0
  }
2043
2044
0
  return false;
2045
0
}
2046
2047
bool
2048
0
dns_name_israd(const dns_name_t *name, const dns_name_t *rad) {
2049
0
  dns_name_t suffix;
2050
0
  char labelbuf[64];
2051
0
  unsigned long v, last = ULONG_MAX;
2052
0
  char *end, *l;
2053
2054
0
  REQUIRE(DNS_NAME_VALID(name));
2055
0
  REQUIRE(DNS_NAME_VALID(rad));
2056
2057
0
  uint8_t name_labels = dns_name_countlabels(name);
2058
0
  uint8_t rad_labels = dns_name_countlabels(rad);
2059
2060
0
  if (name_labels < rad_labels + 4U || name->length < 4U) {
2061
0
    return false;
2062
0
  }
2063
2064
0
  if (name->ndata[0] != 3 || name->ndata[1] != '_' ||
2065
0
      tolower(name->ndata[2]) != 'e' || tolower(name->ndata[3]) != 'r')
2066
0
  {
2067
0
    return false;
2068
0
  }
2069
2070
0
  dns_name_init(&suffix);
2071
0
  dns_name_split(name, rad_labels + 1, NULL, &suffix);
2072
2073
0
  if (suffix.ndata[0] != 3 || suffix.ndata[1] != '_' ||
2074
0
      tolower(suffix.ndata[2]) != 'e' || tolower(suffix.ndata[3]) != 'r')
2075
0
  {
2076
0
    return false;
2077
0
  }
2078
2079
  /* type list */
2080
0
  dns_name_split(name, name_labels - 1, NULL, &suffix);
2081
0
  INSIST(*suffix.ndata < sizeof(labelbuf));
2082
0
  memmove(labelbuf, suffix.ndata + 1, *suffix.ndata);
2083
0
  labelbuf[*suffix.ndata] = 0;
2084
0
  if (strlen(labelbuf) != *suffix.ndata) {
2085
0
    return false;
2086
0
  }
2087
0
  l = labelbuf;
2088
0
  do {
2089
0
    v = strtoul(l, &end, 10);
2090
0
    if (v > 0xffff || (*end != 0 && *end != '-') || end == l) {
2091
0
      return false;
2092
0
    }
2093
0
    if (last != ULONG_MAX && v <= last) {
2094
0
      return false;
2095
0
    }
2096
0
    last = v;
2097
0
    if (*end == '-') {
2098
0
      l = end + 1;
2099
0
    }
2100
0
  } while (*end != 0);
2101
2102
  /* extended error code */
2103
0
  dns_name_split(name, rad_labels + 2, NULL, &suffix);
2104
0
  INSIST(*suffix.ndata < sizeof(labelbuf));
2105
0
  memmove(labelbuf, suffix.ndata + 1, *suffix.ndata);
2106
0
  labelbuf[*suffix.ndata] = 0;
2107
0
  if (strlen(labelbuf) != *suffix.ndata) {
2108
0
    return false;
2109
0
  }
2110
0
  v = strtoul(labelbuf, &end, 10);
2111
0
  if (v > 0xfff || *end != 0) {
2112
0
    return false;
2113
0
  }
2114
2115
0
  return dns_name_issubdomain(name, rad);
2116
0
}
2117
2118
uint8_t
2119
0
dns_name_offsets(const dns_name_t *name, dns_offsets_t offsets) {
2120
0
  REQUIRE(DNS_NAME_VALID(name));
2121
0
  unsigned int offset, count, length, nlabels;
2122
0
  unsigned char *ndata;
2123
2124
0
  ndata = name->ndata;
2125
0
  length = name->length;
2126
0
  offset = 0;
2127
0
  nlabels = 0;
2128
0
  while (offset != length) {
2129
0
    INSIST(nlabels < DNS_NAME_MAXLABELS);
2130
0
    if (offsets != NULL) {
2131
0
      offsets[nlabels] = offset;
2132
0
    }
2133
0
    nlabels++;
2134
0
    count = *ndata;
2135
0
    INSIST(count <= DNS_NAME_LABELLEN);
2136
0
    offset += count + 1;
2137
0
    ndata += count + 1;
2138
0
    INSIST(offset <= length);
2139
0
    if (count == 0) {
2140
      /* Final root label */
2141
0
      break;
2142
0
    }
2143
0
  }
2144
0
  INSIST(offset == name->length);
2145
2146
0
  return nlabels;
2147
0
}