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