Coverage Report

Created: 2025-07-18 07:00

/src/unbound/util/data/dname.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * util/data/dname.h - domain name handling
3
 *
4
 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5
 *
6
 * This software is open source.
7
 * 
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 
12
 * Redistributions of source code must retain the above copyright notice,
13
 * this list of conditions and the following disclaimer.
14
 * 
15
 * Redistributions in binary form must reproduce the above copyright notice,
16
 * this list of conditions and the following disclaimer in the documentation
17
 * and/or other materials provided with the distribution.
18
 * 
19
 * Neither the name of the NLNET LABS nor the names of its contributors may
20
 * be used to endorse or promote products derived from this software without
21
 * specific prior written permission.
22
 * 
23
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
 */
35
36
/**
37
 * \file
38
 *
39
 * This file contains domain name handling functions.
40
 */
41
42
#include "config.h"
43
#include <ctype.h>
44
#include "util/data/dname.h"
45
#include "util/data/msgparse.h"
46
#include "util/log.h"
47
#include "util/storage/lookup3.h"
48
#include "sldns/sbuffer.h"
49
50
/* determine length of a dname in buffer, no compression pointers allowed */
51
size_t
52
query_dname_len(sldns_buffer* query)
53
0
{
54
0
  size_t len = 0;
55
0
  size_t labellen;
56
0
  while(1) {
57
0
    if(sldns_buffer_remaining(query) < 1)
58
0
      return 0; /* parse error, need label len */
59
0
    labellen = sldns_buffer_read_u8(query);
60
0
    if((labellen&0xc0))
61
0
      return 0; /* no compression allowed in queries */
62
0
    len += labellen + 1;
63
0
    if(len > LDNS_MAX_DOMAINLEN)
64
0
      return 0; /* too long */
65
0
    if(labellen == 0)
66
0
      return len;
67
0
    if(sldns_buffer_remaining(query) < labellen)
68
0
      return 0; /* parse error, need content */
69
0
    sldns_buffer_skip(query, (ssize_t)labellen);
70
0
  }
71
0
}
72
73
size_t 
74
dname_valid(uint8_t* dname, size_t maxlen)
75
0
{
76
0
  size_t len = 0;
77
0
  size_t labellen;
78
0
  if(maxlen == 0)
79
0
    return 0; /* too short, shortest is '0' root label */
80
0
  labellen = *dname++;
81
0
  while(labellen) {
82
0
    if((labellen&0xc0))
83
0
      return 0; /* no compression ptrs allowed */
84
0
    len += labellen + 1;
85
0
    if(len >= LDNS_MAX_DOMAINLEN)
86
0
      return 0; /* too long */
87
0
    if(len > maxlen)
88
0
      return 0; /* does not fit in memory allocation */
89
0
    dname += labellen;
90
0
    labellen = *dname++;
91
0
  }
92
0
  len += 1;
93
0
  if(len > maxlen)
94
0
    return 0; /* does not fit in memory allocation */
95
0
  return len;
96
0
}
97
98
/** compare uncompressed, noncanonical, registers are hints for speed */
99
int 
100
query_dname_compare(register uint8_t* d1, register uint8_t* d2)
101
0
{
102
0
  register uint8_t lab1, lab2;
103
0
  log_assert(d1 && d2);
104
0
  lab1 = *d1++;
105
0
  lab2 = *d2++;
106
0
  while( lab1 != 0 || lab2 != 0 ) {
107
    /* compare label length */
108
    /* if one dname ends, it has labellength 0 */
109
0
    if(lab1 != lab2) {
110
0
      if(lab1 < lab2)
111
0
        return -1;
112
0
      return 1;
113
0
    }
114
0
    log_assert(lab1 == lab2 && lab1 != 0);
115
    /* compare lowercased labels. */
116
0
    while(lab1--) {
117
      /* compare bytes first for speed */
118
0
      if(*d1 != *d2 && 
119
0
        tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
120
0
        if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
121
0
          return -1;
122
0
        return 1;
123
0
      }
124
0
      d1++;
125
0
      d2++;
126
0
    }
127
    /* next pair of labels. */
128
0
    lab1 = *d1++;
129
0
    lab2 = *d2++;
130
0
  }
131
0
  return 0;
132
0
}
133
134
void 
135
query_dname_tolower(uint8_t* dname)
136
0
{
137
  /* the dname is stored uncompressed */
138
0
  uint8_t labellen;
139
0
  labellen = *dname;
140
0
  while(labellen) {
141
0
    dname++;
142
0
    while(labellen--) {
143
0
      *dname = (uint8_t)tolower((unsigned char)*dname);
144
0
      dname++;
145
0
    }
146
0
    labellen = *dname;
147
0
  }
148
0
}
149
150
void 
151
pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname)
152
0
{
153
0
  uint8_t lablen;
154
0
  int count = 0;
155
0
  if(dname >= sldns_buffer_end(pkt))
156
0
    return;
157
0
  lablen = *dname++;
158
0
  while(lablen) {
159
0
    if(LABEL_IS_PTR(lablen)) {
160
0
      if((size_t)PTR_OFFSET(lablen, *dname) 
161
0
        >= sldns_buffer_limit(pkt))
162
0
        return;
163
0
      dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
164
0
      lablen = *dname++;
165
0
      if(count++ > MAX_COMPRESS_PTRS)
166
0
        return;
167
0
      continue;
168
0
    }
169
0
    if(dname+lablen >= sldns_buffer_end(pkt))
170
0
      return;
171
0
    while(lablen--) {
172
0
      *dname = (uint8_t)tolower((unsigned char)*dname);
173
0
      dname++;
174
0
    }
175
0
    if(dname >= sldns_buffer_end(pkt))
176
0
      return;
177
0
    lablen = *dname++;
178
0
  }
179
0
}
180
181
182
size_t
183
pkt_dname_len(sldns_buffer* pkt)
184
455k
{
185
455k
  size_t len = 0;
186
455k
  int ptrcount = 0;
187
455k
  uint8_t labellen;
188
455k
  size_t endpos = 0;
189
190
  /* read dname and determine length */
191
  /* check compression pointers, loops, out of bounds */
192
614k
  while(1) {
193
    /* read next label */
194
614k
    if(sldns_buffer_remaining(pkt) < 1)
195
861
      return 0;
196
613k
    labellen = sldns_buffer_read_u8(pkt);
197
613k
    if(LABEL_IS_PTR(labellen)) {
198
      /* compression ptr */
199
103k
      uint16_t ptr;
200
103k
      if(sldns_buffer_remaining(pkt) < 1)
201
235
        return 0;
202
103k
      ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
203
103k
      if(ptrcount++ > MAX_COMPRESS_PTRS)
204
200
        return 0; /* loop! */
205
103k
      if(sldns_buffer_limit(pkt) <= ptr)
206
296
        return 0; /* out of bounds! */
207
102k
      if(!endpos)
208
32.0k
        endpos = sldns_buffer_position(pkt);
209
102k
      sldns_buffer_set_position(pkt, ptr);
210
510k
    } else {
211
      /* label contents */
212
510k
      if(labellen > 0x3f)
213
892
        return 0; /* label too long */
214
509k
      len += 1 + labellen;
215
509k
      if(len > LDNS_MAX_DOMAINLEN)
216
247
        return 0;
217
509k
      if(labellen == 0) {
218
        /* end of dname */
219
451k
        break;
220
451k
      }
221
57.1k
      if(sldns_buffer_remaining(pkt) < labellen)
222
455
        return 0;
223
56.6k
      sldns_buffer_skip(pkt, (ssize_t)labellen);
224
56.6k
    }
225
613k
  }
226
451k
  if(endpos)
227
30.7k
    sldns_buffer_set_position(pkt, endpos);
228
229
451k
  return len;
230
455k
}
231
232
int 
233
dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
234
420k
{
235
420k
  uint8_t len1, len2;
236
420k
  int count1 = 0, count2 = 0;
237
420k
  log_assert(pkt && d1 && d2);
238
420k
  len1 = *d1++;
239
420k
  len2 = *d2++;
240
519k
  while( len1 != 0 || len2 != 0 ) {
241
    /* resolve ptrs */
242
105k
    if(LABEL_IS_PTR(len1)) {
243
37.8k
      if((size_t)PTR_OFFSET(len1, *d1)
244
37.8k
        >= sldns_buffer_limit(pkt))
245
0
        return -1;
246
37.8k
      if(count1++ > MAX_COMPRESS_PTRS)
247
0
        return -1;
248
37.8k
      d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
249
37.8k
      len1 = *d1++;
250
37.8k
      continue;
251
37.8k
    }
252
67.5k
    if(LABEL_IS_PTR(len2)) {
253
32.8k
      if((size_t)PTR_OFFSET(len2, *d2)
254
32.8k
        >= sldns_buffer_limit(pkt))
255
0
        return 1;
256
32.8k
      if(count2++ > MAX_COMPRESS_PTRS)
257
0
        return 1;
258
32.8k
      d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
259
32.8k
      len2 = *d2++;
260
32.8k
      continue;
261
32.8k
    }
262
    /* check label length */
263
34.6k
    log_assert(len1 <= LDNS_MAX_LABELLEN);
264
34.6k
    log_assert(len2 <= LDNS_MAX_LABELLEN);
265
34.6k
    if(len1 != len2) {
266
3.67k
      if(len1 < len2) return -1;
267
2.15k
      return 1;
268
3.67k
    }
269
31.0k
    log_assert(len1 == len2 && len1 != 0);
270
    /* compare labels */
271
415k
    while(len1--) {
272
386k
      if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
273
2.26k
        if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
274
1.04k
          return -1;
275
1.21k
        return 1;
276
2.26k
      }
277
384k
      d1++;
278
384k
      d2++;
279
384k
    }
280
28.7k
    len1 = *d1++;
281
28.7k
    len2 = *d2++;
282
28.7k
  }
283
414k
  return 0;
284
420k
}
285
286
hashvalue_type
287
dname_query_hash(uint8_t* dname, hashvalue_type h)
288
0
{
289
0
  uint8_t labuf[LDNS_MAX_LABELLEN+1];
290
0
  uint8_t lablen;
291
0
  int i;
292
293
  /* preserve case of query, make hash label by label */
294
0
  lablen = *dname++;
295
0
  while(lablen) {
296
0
    log_assert(lablen <= LDNS_MAX_LABELLEN);
297
0
    labuf[0] = lablen;
298
0
    i=0;
299
0
    while(lablen--) {
300
0
      labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
301
0
      dname++;
302
0
    }
303
0
    h = hashlittle(labuf, labuf[0] + 1, h);
304
0
    lablen = *dname++;
305
0
  }
306
307
0
  return h;
308
0
}
309
310
hashvalue_type
311
dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
312
420k
{
313
420k
  uint8_t labuf[LDNS_MAX_LABELLEN+1];
314
420k
  uint8_t lablen;
315
420k
  int i;
316
420k
  int count = 0;
317
318
  /* preserve case of query, make hash label by label */
319
420k
  lablen = *dname++;
320
499k
  while(lablen) {
321
78.7k
    if(LABEL_IS_PTR(lablen)) {
322
      /* follow pointer */
323
36.7k
      if((size_t)PTR_OFFSET(lablen, *dname)
324
36.7k
        >= sldns_buffer_limit(pkt))
325
0
        return h;
326
36.7k
      if(count++ > MAX_COMPRESS_PTRS)
327
0
        return h;
328
36.7k
      dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
329
36.7k
      lablen = *dname++;
330
36.7k
      continue;
331
36.7k
    }
332
42.0k
    log_assert(lablen <= LDNS_MAX_LABELLEN);
333
42.0k
    labuf[0] = lablen;
334
42.0k
    i=0;
335
599k
    while(lablen--) {
336
557k
      labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
337
557k
      dname++;
338
557k
    }
339
42.0k
    h = hashlittle(labuf, labuf[0] + 1, h);
340
42.0k
    lablen = *dname++;
341
42.0k
  }
342
343
420k
  return h;
344
420k
}
345
346
void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
347
0
{
348
  /* copy over the dname and decompress it at the same time */
349
0
  size_t comprcount = 0;
350
0
  size_t len = 0;
351
0
  uint8_t lablen;
352
0
  lablen = *dname++;
353
0
  while(lablen) {
354
0
    if(LABEL_IS_PTR(lablen)) {
355
0
      if(comprcount++ > MAX_COMPRESS_PTRS) {
356
        /* too many compression pointers */
357
0
        *to = 0; /* end the result prematurely */
358
0
        return;
359
0
      }
360
      /* follow pointer */
361
0
      if((size_t)PTR_OFFSET(lablen, *dname)
362
0
        >= sldns_buffer_limit(pkt))
363
0
        return;
364
0
      dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
365
0
      lablen = *dname++;
366
0
      continue;
367
0
    }
368
0
    if(lablen > LDNS_MAX_LABELLEN) {
369
0
      *to = 0; /* end the result prematurely */
370
0
      return;
371
0
    }
372
0
    log_assert(lablen <= LDNS_MAX_LABELLEN);
373
0
    len += (size_t)lablen+1;
374
0
    if(len >= LDNS_MAX_DOMAINLEN) {
375
0
      *to = 0; /* end the result prematurely */
376
0
      log_err("bad dname in dname_pkt_copy");
377
0
      return;
378
0
    }
379
0
    *to++ = lablen;
380
0
    memmove(to, dname, lablen);
381
0
    dname += lablen;
382
0
    to += lablen;
383
0
    lablen = *dname++;
384
0
  }
385
  /* copy last \0 */
386
0
  *to = 0;
387
0
}
388
389
void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
390
0
{
391
0
  uint8_t lablen;
392
0
  int count = 0;
393
0
  if(!out) out = stdout;
394
0
  if(!dname) return;
395
396
0
  lablen = *dname++;
397
0
  if(!lablen) 
398
0
    fputc('.', out);
399
0
  while(lablen) {
400
0
    if(LABEL_IS_PTR(lablen)) {
401
      /* follow pointer */
402
0
      if(!pkt) {
403
0
        fputs("??compressionptr??", out);
404
0
        return;
405
0
      }
406
0
      if((size_t)PTR_OFFSET(lablen, *dname)
407
0
        >= sldns_buffer_limit(pkt)) {
408
0
        fputs("??compressionptr??", out);
409
0
        return;
410
0
      }
411
0
      if(count++ > MAX_COMPRESS_PTRS) {
412
0
        fputs("??compressionptr??", out);
413
0
        return;
414
0
      }
415
0
      dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
416
0
      lablen = *dname++;
417
0
      continue;
418
0
    }
419
0
    if(lablen > LDNS_MAX_LABELLEN) {
420
0
      fputs("??extendedlabel??", out);
421
0
      return;
422
0
    }
423
0
    while(lablen--)
424
0
      fputc((int)*dname++, out);
425
0
    fputc('.', out);
426
0
    lablen = *dname++;
427
0
  }
428
0
}
429
430
int 
431
dname_count_labels(uint8_t* dname)
432
0
{
433
0
  uint8_t lablen;
434
0
  int labs = 1;
435
436
0
  lablen = *dname++;
437
0
  while(lablen) {
438
0
    labs++;
439
0
    dname += lablen;
440
0
    lablen = *dname++;
441
0
  }
442
0
  return labs;
443
0
}
444
445
int 
446
dname_count_size_labels(uint8_t* dname, size_t* size)
447
0
{ 
448
0
  uint8_t lablen;
449
0
  int labs = 1;
450
0
  size_t sz = 1;
451
452
0
  lablen = *dname++;
453
0
  while(lablen) {
454
0
    labs++;
455
0
    sz += lablen+1;
456
0
    dname += lablen;
457
0
    lablen = *dname++;
458
0
  }
459
0
  *size = sz;
460
0
  return labs;
461
0
}
462
463
/**
464
 * Compare labels in memory, lowercase while comparing.
465
 * @param p1: label 1
466
 * @param p2: label 2
467
 * @param len: number of bytes to compare.
468
 * @return: 0, -1, +1 comparison result.
469
 */
470
static int
471
memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
472
0
{
473
0
  while(len--) {
474
0
    if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) {
475
0
      if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2))
476
0
        return -1;
477
0
      return 1;
478
0
    }
479
0
    p1++;
480
0
    p2++;
481
0
  }
482
0
  return 0;
483
0
}
484
485
int 
486
dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
487
0
{
488
0
  uint8_t len1, len2;
489
0
  int atlabel = labs1;
490
0
  int lastmlabs;
491
0
  int lastdiff = 0;
492
  /* first skip so that we compare same label. */
493
0
  if(labs1 > labs2) {
494
0
    while(atlabel > labs2) {
495
0
      len1 = *d1++;
496
0
      d1 += len1;
497
0
      atlabel--;
498
0
    }
499
0
    log_assert(atlabel == labs2);
500
0
  } else if(labs1 < labs2) {
501
0
    atlabel = labs2;
502
0
    while(atlabel > labs1) {
503
0
      len2 = *d2++;
504
0
      d2 += len2;
505
0
      atlabel--;
506
0
    }
507
0
    log_assert(atlabel == labs1);
508
0
  }
509
0
  lastmlabs = atlabel+1;
510
  /* now at same label in d1 and d2, atlabel */
511
  /* www.example.com.                  */
512
  /* 4   3       2  1   atlabel number */
513
  /* repeat until at root label (which is always the same) */
514
0
  while(atlabel > 1) {
515
0
    len1 = *d1++;
516
0
    len2 = *d2++;
517
0
    if(len1 != len2) {
518
0
      log_assert(len1 != 0 && len2 != 0);
519
0
      if(len1<len2)
520
0
        lastdiff = -1;
521
0
      else  lastdiff = 1;
522
0
      lastmlabs = atlabel;
523
0
      d1 += len1;
524
0
      d2 += len2;
525
0
    } else {
526
      /* memlowercmp is inlined here; or just like
527
       * if((c=memlowercmp(d1, d2, len1)) != 0) { 
528
       *  lastdiff = c;
529
       *  lastmlabs = atlabel; } apart from d1++,d2++ */
530
0
      while(len1) {
531
0
        if(*d1 != *d2 && tolower((unsigned char)*d1) 
532
0
          != tolower((unsigned char)*d2)) {
533
0
          if(tolower((unsigned char)*d1) < 
534
0
            tolower((unsigned char)*d2)) {
535
0
            lastdiff = -1;
536
0
            lastmlabs = atlabel;
537
0
            d1 += len1;
538
0
            d2 += len1;
539
0
            break;
540
0
          }
541
0
          lastdiff = 1;
542
0
          lastmlabs = atlabel;
543
0
          d1 += len1;
544
0
          d2 += len1;
545
0
          break; /* out of memlowercmp */
546
0
        }
547
0
        d1++;
548
0
        d2++;
549
0
        len1--;
550
0
      }
551
0
    }
552
0
    atlabel--;
553
0
  }
554
  /* last difference atlabel number, so number of labels matching,
555
   * at the right side, is one less. */
556
0
  *mlabs = lastmlabs-1;
557
0
  if(lastdiff == 0) {
558
    /* all labels compared were equal, check if one has more
559
     * labels, so that example.com. > com. */
560
0
    if(labs1 > labs2)
561
0
      return 1;
562
0
    else if(labs1 < labs2)
563
0
      return -1;
564
0
  }
565
0
  return lastdiff;
566
0
}
567
568
int
569
dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
570
0
{
571
0
  size_t plen = strlen(prefix);
572
0
  size_t orig_plen = plen;
573
0
  size_t lablen = (size_t)*label;
574
0
  if(plen > lablen)
575
0
    return 0;
576
0
  label++;
577
0
  while(plen--) {
578
0
    if(*prefix != tolower((unsigned char)*label)) {
579
0
      return 0;
580
0
    }
581
0
    prefix++; label++;
582
0
  }
583
0
  if(orig_plen < lablen)
584
0
    *endptr = (char *)label;
585
0
  else
586
    /* prefix length == label length */
587
0
    *endptr = NULL;
588
0
  return 1;
589
0
}
590
591
int
592
dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label)
593
0
{
594
0
  size_t len;
595
596
  /* 1 byte needed for the label length */
597
0
  if(dnamelen < 1)
598
0
    return 0;
599
600
0
  len = *dname;
601
0
  while(len <= dnamelen) {
602
0
    if(!(*dname)) {
603
0
      if(*dname == *label)
604
0
        return 1; /* empty label match */
605
      /* termination label found, stop iterating */
606
0
      return 0;
607
0
    }
608
0
    if(*dname == *label && *label &&
609
0
      memlowercmp(dname+1, label+1, *dname) == 0)
610
0
      return 1;
611
0
    len += *dname;
612
0
    dname += *dname;
613
0
    dname++;
614
0
    len++;
615
0
  }
616
0
  return 0;
617
0
}
618
619
int 
620
dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
621
0
{
622
0
  uint8_t lablen;
623
624
0
  if(sldns_buffer_remaining(pkt) < 1)
625
0
    return 0;
626
0
  lablen = *dname++;
627
0
  sldns_buffer_write_u8(pkt, lablen);
628
0
  while(lablen) {
629
0
    if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
630
0
      return 0;
631
0
    sldns_buffer_write(pkt, dname, lablen);
632
0
    dname += lablen;
633
0
    lablen = *dname++;
634
0
    sldns_buffer_write_u8(pkt, lablen);
635
0
  }
636
0
  return 1;
637
0
}
638
639
void dname_str(uint8_t* dname, char* str)
640
0
{
641
0
  size_t len = 0;
642
0
  uint8_t lablen = 0;
643
0
  char* s = str;
644
0
  if(!dname || !*dname) {
645
0
    *s++ = '.';
646
0
    *s = 0;
647
0
    goto out;
648
0
  }
649
0
  lablen = *dname++;
650
0
  while(lablen) {
651
0
    if(lablen > LDNS_MAX_LABELLEN) {
652
0
      *s++ = '#';
653
0
      *s = 0;
654
0
      goto out;
655
0
    }
656
0
    len += lablen+1;
657
0
    if(len >= LDNS_MAX_DOMAINLEN) {
658
0
      *s++ = '&';
659
0
      *s = 0;
660
0
      goto out;
661
0
    }
662
0
    while(lablen--) {
663
0
      if(isalnum((unsigned char)*dname)
664
0
        || *dname == '-' || *dname == '_'
665
0
        || *dname == '*')
666
0
        *s++ = *(char*)dname++;
667
0
      else  {
668
0
        *s++ = '?';
669
0
        dname++;
670
0
      }
671
0
    }
672
0
    *s++ = '.';
673
0
    lablen = *dname++;
674
0
  }
675
0
  *s = 0;
676
677
0
out:
678
0
  log_assert(s - str < LDNS_MAX_DOMAINLEN);
679
0
  return;
680
0
}
681
682
int 
683
dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
684
0
{
685
0
  int m;
686
  /* check subdomain: d1: www.example.com. and d2: example.com. */
687
0
  if(labs2 >= labs1) 
688
0
    return 0;
689
0
  if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
690
    /* subdomain if all labels match */
691
0
    return (m == labs2);
692
0
  }
693
0
  return 0;
694
0
}
695
696
int 
697
dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
698
0
{
699
0
  return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
700
0
    dname_count_labels(d2));
701
0
}
702
703
int 
704
dname_subdomain_c(uint8_t* d1, uint8_t* d2)
705
0
{
706
0
  int m;
707
  /* check subdomain: d1: www.example.com. and d2: example.com. */
708
  /*    or      d1: example.com. and d2: example.com. */
709
0
  int labs1 = dname_count_labels(d1);
710
0
  int labs2 = dname_count_labels(d2);
711
0
  if(labs2 > labs1) 
712
0
    return 0;
713
0
  if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
714
    /* must have been example.com , www.example.com - wrong */
715
    /* or otherwise different dnames */
716
0
    return 0;
717
0
  }
718
0
  return (m == labs2);
719
0
}
720
721
int 
722
dname_is_root(uint8_t* dname)
723
0
{
724
0
  uint8_t len;
725
0
  log_assert(dname);
726
0
  len = dname[0];
727
0
  log_assert(!LABEL_IS_PTR(len));
728
0
  return (len == 0);
729
0
}
730
731
void
732
dname_remove_label(uint8_t** dname, size_t* len)
733
0
{
734
0
  size_t lablen;
735
0
  log_assert(dname && *dname && len);
736
0
  lablen = (*dname)[0];
737
0
  log_assert(!LABEL_IS_PTR(lablen));
738
0
  log_assert(*len > lablen);
739
0
  if(lablen == 0)
740
0
    return; /* do not modify root label */
741
0
  *len -= lablen+1;
742
0
  *dname += lablen+1;
743
0
}
744
745
int
746
dname_remove_label_limit_len(uint8_t** dname, size_t* len, size_t lenlimit)
747
0
{
748
0
  size_t lablen;
749
0
  log_assert(dname && *dname && len);
750
0
  lablen = (*dname)[0];
751
0
  log_assert(!LABEL_IS_PTR(lablen));
752
0
  log_assert(*len > lablen);
753
0
  if(lablen == 0)
754
0
    return 0; /* do not modify root label */
755
0
  if(*len - (lablen + 1) < lenlimit) return 0;
756
0
  *len -= lablen+1;
757
0
  *dname += lablen+1;
758
0
  return 1;
759
0
}
760
761
void
762
dname_remove_labels(uint8_t** dname, size_t* len, int n)
763
0
{
764
0
  int i;
765
0
  for(i=0; i<n; i++)
766
0
    dname_remove_label(dname, len);
767
0
}
768
769
int 
770
dname_signame_label_count(uint8_t* dname)
771
0
{
772
0
  uint8_t lablen;
773
0
  int count = 0;
774
0
  if(!*dname)
775
0
    return 0;
776
0
  if(dname[0] == 1 && dname[1] == '*')
777
0
    dname += 2;
778
0
  lablen = dname[0];
779
0
  while(lablen) {
780
0
    count++;
781
0
    dname += lablen;
782
0
    dname += 1;
783
0
    lablen = dname[0];
784
0
  }
785
0
  return count;
786
0
}
787
788
int 
789
dname_is_wild(uint8_t* dname)
790
0
{
791
0
  return (dname[0] == 1 && dname[1] == '*');
792
0
}
793
794
/**
795
 * Compare labels in memory, lowercase while comparing.
796
 * Returns canonical order for labels. If all is equal, the
797
 * shortest is first.
798
 *
799
 * @param p1: label 1
800
 * @param len1: length of label 1.
801
 * @param p2: label 2
802
 * @param len2: length of label 2.
803
 * @return: 0, -1, +1 comparison result.
804
 */
805
static int
806
memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
807
0
{
808
0
  uint8_t min = (len1<len2)?len1:len2;
809
0
  int c = memlowercmp(p1, p2, min);
810
0
  if(c != 0)
811
0
    return c;
812
  /* equal, see who is shortest */
813
0
  if(len1 < len2)
814
0
    return -1;
815
0
  if(len1 > len2)
816
0
    return 1;
817
0
  return 0;
818
0
}
819
820
821
int 
822
dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
823
0
{
824
  /* like dname_lab_cmp, but with different label comparison,
825
   * empty character sorts before \000.
826
   * So   ylyly is before z. */
827
0
  uint8_t len1, len2;
828
0
  int atlabel = labs1;
829
0
  int lastmlabs;
830
0
  int lastdiff = 0;
831
0
  int c;
832
  /* first skip so that we compare same label. */
833
0
  if(labs1 > labs2) {
834
0
    while(atlabel > labs2) {
835
0
      len1 = *d1++;
836
0
      d1 += len1;
837
0
      atlabel--;
838
0
    }
839
0
    log_assert(atlabel == labs2);
840
0
  } else if(labs1 < labs2) {
841
0
    atlabel = labs2;
842
0
    while(atlabel > labs1) {
843
0
      len2 = *d2++;
844
0
      d2 += len2;
845
0
      atlabel--;
846
0
    }
847
0
    log_assert(atlabel == labs1);
848
0
  }
849
0
  lastmlabs = atlabel+1;
850
  /* now at same label in d1 and d2, atlabel */
851
  /* www.example.com.                  */
852
  /* 4   3       2  1   atlabel number */
853
  /* repeat until at root label (which is always the same) */
854
0
  while(atlabel > 1) {
855
0
    len1 = *d1++;
856
0
    len2 = *d2++;
857
858
0
    if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
859
0
      if(c<0)
860
0
        lastdiff = -1;
861
0
      else  lastdiff = 1;
862
0
      lastmlabs = atlabel;
863
0
    }
864
865
0
    d1 += len1;
866
0
    d2 += len2;
867
0
    atlabel--;
868
0
  }
869
  /* last difference atlabel number, so number of labels matching,
870
   * at the right side, is one less. */
871
0
  *mlabs = lastmlabs-1;
872
0
  if(lastdiff == 0) {
873
    /* all labels compared were equal, check if one has more
874
     * labels, so that example.com. > com. */
875
0
    if(labs1 > labs2)
876
0
      return 1;
877
0
    else if(labs1 < labs2)
878
0
      return -1;
879
0
  }
880
0
  return lastdiff;
881
0
}
882
883
int
884
dname_canonical_compare(uint8_t* d1, uint8_t* d2)
885
0
{
886
0
  int labs1, labs2, m;
887
0
  labs1 = dname_count_labels(d1);
888
0
  labs2 = dname_count_labels(d2);
889
0
  return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
890
0
}
891
892
uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
893
0
{
894
0
  int labs1, labs2, m;
895
0
  size_t len = LDNS_MAX_DOMAINLEN;
896
0
  labs1 = dname_count_labels(d1);
897
0
  labs2 = dname_count_labels(d2);
898
0
  (void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
899
0
  dname_remove_labels(&d1, &len, labs1-m);
900
0
  return d1;
901
0
}