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 return 0;
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 return 0;
202 ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
203 if(ptrcount++ > MAX_COMPRESS_PTRS)
204 return 0; /* loop! */
205 if(sldns_buffer_limit(pkt) <= ptr)
206 return 0; /* 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 return 0; /* label too long */
214 len += 1 + labellen;
215 if(len > LDNS_MAX_DOMAINLEN)
216 return 0;
217 if(labellen == 0) {
218 /* end of dname */
219 break;
220 }
221 if(sldns_buffer_remaining(pkt) < labellen)
222 return 0;
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 }
231
232 int
dname_pkt_compare(sldns_buffer * pkt,uint8_t * d1,uint8_t * d2)233 dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
234 {
235 uint8_t len1, len2;
236 int count1 = 0, count2 = 0;
237 log_assert(pkt && d1 && d2);
238 len1 = *d1++;
239 len2 = *d2++;
240 while( len1 != 0 || len2 != 0 ) {
241 /* resolve ptrs */
242 if(LABEL_IS_PTR(len1)) {
243 if((size_t)PTR_OFFSET(len1, *d1)
244 >= sldns_buffer_limit(pkt))
245 return -1;
246 if(count1++ > MAX_COMPRESS_PTRS)
247 return -1;
248 d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
249 len1 = *d1++;
250 continue;
251 }
252 if(LABEL_IS_PTR(len2)) {
253 if((size_t)PTR_OFFSET(len2, *d2)
254 >= sldns_buffer_limit(pkt))
255 return 1;
256 if(count2++ > MAX_COMPRESS_PTRS)
257 return 1;
258 d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
259 len2 = *d2++;
260 continue;
261 }
262 /* check label length */
263 log_assert(len1 <= LDNS_MAX_LABELLEN);
264 log_assert(len2 <= LDNS_MAX_LABELLEN);
265 if(len1 != len2) {
266 if(len1 < len2) return -1;
267 return 1;
268 }
269 log_assert(len1 == len2 && len1 != 0);
270 /* compare labels */
271 while(len1--) {
272 if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
273 if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
274 return -1;
275 return 1;
276 }
277 d1++;
278 d2++;
279 }
280 len1 = *d1++;
281 len2 = *d2++;
282 }
283 return 0;
284 }
285
286 hashvalue_type
dname_query_hash(uint8_t * dname,hashvalue_type h)287 dname_query_hash(uint8_t* dname, hashvalue_type h)
288 {
289 uint8_t labuf[LDNS_MAX_LABELLEN+1];
290 uint8_t lablen;
291 int i;
292
293 /* preserve case of query, make hash label by label */
294 lablen = *dname++;
295 while(lablen) {
296 log_assert(lablen <= LDNS_MAX_LABELLEN);
297 labuf[0] = lablen;
298 i=0;
299 while(lablen--) {
300 labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
301 dname++;
302 }
303 h = hashlittle(labuf, labuf[0] + 1, h);
304 lablen = *dname++;
305 }
306
307 return h;
308 }
309
310 hashvalue_type
dname_pkt_hash(sldns_buffer * pkt,uint8_t * dname,hashvalue_type h)311 dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
312 {
313 uint8_t labuf[LDNS_MAX_LABELLEN+1];
314 uint8_t lablen;
315 int i;
316 int count = 0;
317
318 /* preserve case of query, make hash label by label */
319 lablen = *dname++;
320 while(lablen) {
321 if(LABEL_IS_PTR(lablen)) {
322 /* follow pointer */
323 if((size_t)PTR_OFFSET(lablen, *dname)
324 >= sldns_buffer_limit(pkt))
325 return h;
326 if(count++ > MAX_COMPRESS_PTRS)
327 return h;
328 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
329 lablen = *dname++;
330 continue;
331 }
332 log_assert(lablen <= LDNS_MAX_LABELLEN);
333 labuf[0] = lablen;
334 i=0;
335 while(lablen--) {
336 labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
337 dname++;
338 }
339 h = hashlittle(labuf, labuf[0] + 1, h);
340 lablen = *dname++;
341 }
342
343 return h;
344 }
345
dname_pkt_copy(sldns_buffer * pkt,uint8_t * to,uint8_t * dname)346 void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
347 {
348 /* copy over the dname and decompress it at the same time */
349 size_t comprcount = 0;
350 size_t len = 0;
351 uint8_t lablen;
352 lablen = *dname++;
353 while(lablen) {
354 if(LABEL_IS_PTR(lablen)) {
355 if(comprcount++ > MAX_COMPRESS_PTRS) {
356 /* too many compression pointers */
357 *to = 0; /* end the result prematurely */
358 return;
359 }
360 /* follow pointer */
361 if((size_t)PTR_OFFSET(lablen, *dname)
362 >= sldns_buffer_limit(pkt))
363 return;
364 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
365 lablen = *dname++;
366 continue;
367 }
368 if(lablen > LDNS_MAX_LABELLEN) {
369 *to = 0; /* end the result prematurely */
370 return;
371 }
372 log_assert(lablen <= LDNS_MAX_LABELLEN);
373 len += (size_t)lablen+1;
374 if(len >= LDNS_MAX_DOMAINLEN) {
375 *to = 0; /* end the result prematurely */
376 log_err("bad dname in dname_pkt_copy");
377 return;
378 }
379 *to++ = lablen;
380 memmove(to, dname, lablen);
381 dname += lablen;
382 to += lablen;
383 lablen = *dname++;
384 }
385 /* copy last \0 */
386 *to = 0;
387 }
388
dname_print(FILE * out,struct sldns_buffer * pkt,uint8_t * dname)389 void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
390 {
391 uint8_t lablen;
392 int count = 0;
393 if(!out) out = stdout;
394 if(!dname) return;
395
396 lablen = *dname++;
397 if(!lablen)
398 fputc('.', out);
399 while(lablen) {
400 if(LABEL_IS_PTR(lablen)) {
401 /* follow pointer */
402 if(!pkt) {
403 fputs("??compressionptr??", out);
404 return;
405 }
406 if((size_t)PTR_OFFSET(lablen, *dname)
407 >= sldns_buffer_limit(pkt)) {
408 fputs("??compressionptr??", out);
409 return;
410 }
411 if(count++ > MAX_COMPRESS_PTRS) {
412 fputs("??compressionptr??", out);
413 return;
414 }
415 dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
416 lablen = *dname++;
417 continue;
418 }
419 if(lablen > LDNS_MAX_LABELLEN) {
420 fputs("??extendedlabel??", out);
421 return;
422 }
423 while(lablen--)
424 fputc((int)*dname++, out);
425 fputc('.', out);
426 lablen = *dname++;
427 }
428 }
429
430 int
dname_count_labels(uint8_t * dname)431 dname_count_labels(uint8_t* dname)
432 {
433 uint8_t lablen;
434 int labs = 1;
435
436 lablen = *dname++;
437 while(lablen) {
438 labs++;
439 dname += lablen;
440 lablen = *dname++;
441 }
442 return labs;
443 }
444
445 int
dname_count_size_labels(uint8_t * dname,size_t * size)446 dname_count_size_labels(uint8_t* dname, size_t* size)
447 {
448 uint8_t lablen;
449 int labs = 1;
450 size_t sz = 1;
451
452 lablen = *dname++;
453 while(lablen) {
454 labs++;
455 sz += lablen+1;
456 dname += lablen;
457 lablen = *dname++;
458 }
459 *size = sz;
460 return labs;
461 }
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
memlowercmp(uint8_t * p1,uint8_t * p2,uint8_t len)471 memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
472 {
473 while(len--) {
474 if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) {
475 if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2))
476 return -1;
477 return 1;
478 }
479 p1++;
480 p2++;
481 }
482 return 0;
483 }
484
485 int
dname_lab_cmp(uint8_t * d1,int labs1,uint8_t * d2,int labs2,int * mlabs)486 dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
487 {
488 uint8_t len1, len2;
489 int atlabel = labs1;
490 int lastmlabs;
491 int lastdiff = 0;
492 /* first skip so that we compare same label. */
493 if(labs1 > labs2) {
494 while(atlabel > labs2) {
495 len1 = *d1++;
496 d1 += len1;
497 atlabel--;
498 }
499 log_assert(atlabel == labs2);
500 } else if(labs1 < labs2) {
501 atlabel = labs2;
502 while(atlabel > labs1) {
503 len2 = *d2++;
504 d2 += len2;
505 atlabel--;
506 }
507 log_assert(atlabel == labs1);
508 }
509 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 while(atlabel > 1) {
515 len1 = *d1++;
516 len2 = *d2++;
517 if(len1 != len2) {
518 log_assert(len1 != 0 && len2 != 0);
519 if(len1<len2)
520 lastdiff = -1;
521 else lastdiff = 1;
522 lastmlabs = atlabel;
523 d1 += len1;
524 d2 += len2;
525 } 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 while(len1) {
531 if(*d1 != *d2 && tolower((unsigned char)*d1)
532 != tolower((unsigned char)*d2)) {
533 if(tolower((unsigned char)*d1) <
534 tolower((unsigned char)*d2)) {
535 lastdiff = -1;
536 lastmlabs = atlabel;
537 d1 += len1;
538 d2 += len1;
539 break;
540 }
541 lastdiff = 1;
542 lastmlabs = atlabel;
543 d1 += len1;
544 d2 += len1;
545 break; /* out of memlowercmp */
546 }
547 d1++;
548 d2++;
549 len1--;
550 }
551 }
552 atlabel--;
553 }
554 /* last difference atlabel number, so number of labels matching,
555 * at the right side, is one less. */
556 *mlabs = lastmlabs-1;
557 if(lastdiff == 0) {
558 /* all labels compared were equal, check if one has more
559 * labels, so that example.com. > com. */
560 if(labs1 > labs2)
561 return 1;
562 else if(labs1 < labs2)
563 return -1;
564 }
565 return lastdiff;
566 }
567
568 int
dname_lab_startswith(uint8_t * label,char * prefix,char ** endptr)569 dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
570 {
571 size_t plen = strlen(prefix);
572 size_t orig_plen = plen;
573 size_t lablen = (size_t)*label;
574 if(plen > lablen)
575 return 0;
576 label++;
577 while(plen--) {
578 if(*prefix != tolower((unsigned char)*label)) {
579 return 0;
580 }
581 prefix++; label++;
582 }
583 if(orig_plen < lablen)
584 *endptr = (char *)label;
585 else
586 /* prefix length == label length */
587 *endptr = NULL;
588 return 1;
589 }
590
591 int
dname_has_label(uint8_t * dname,size_t dnamelen,uint8_t * label)592 dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label)
593 {
594 size_t len;
595
596 /* 1 byte needed for the label length */
597 if(dnamelen < 1)
598 return 0;
599
600 len = *dname;
601 while(len <= dnamelen) {
602 if(!(*dname)) {
603 if(*dname == *label)
604 return 1; /* empty label match */
605 /* termination label found, stop iterating */
606 return 0;
607 }
608 if(*dname == *label && *label &&
609 memlowercmp(dname+1, label+1, *dname) == 0)
610 return 1;
611 len += *dname;
612 dname += *dname;
613 dname++;
614 len++;
615 }
616 return 0;
617 }
618
619 int
dname_buffer_write(sldns_buffer * pkt,uint8_t * dname)620 dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
621 {
622 uint8_t lablen;
623
624 if(sldns_buffer_remaining(pkt) < 1)
625 return 0;
626 lablen = *dname++;
627 sldns_buffer_write_u8(pkt, lablen);
628 while(lablen) {
629 if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
630 return 0;
631 sldns_buffer_write(pkt, dname, lablen);
632 dname += lablen;
633 lablen = *dname++;
634 sldns_buffer_write_u8(pkt, lablen);
635 }
636 return 1;
637 }
638
dname_str(uint8_t * dname,char * str)639 void dname_str(uint8_t* dname, char* str)
640 {
641 size_t len = 0;
642 uint8_t lablen = 0;
643 char* s = str;
644 if(!dname || !*dname) {
645 *s++ = '.';
646 *s = 0;
647 return;
648 }
649 lablen = *dname++;
650 while(lablen) {
651 len += lablen+1;
652 if(len >= LDNS_MAX_DOMAINLEN) {
653 if ((s-str) >= (LDNS_MAX_DOMAINLEN-1))
654 s = str + LDNS_MAX_DOMAINLEN - 2;
655 *s++ = '&';
656 *s = 0;
657 return;
658 }
659 if(lablen > LDNS_MAX_LABELLEN) {
660 *s++ = '#';
661 *s = 0;
662 return;
663 }
664 while(lablen--) {
665 if(isalnum((unsigned char)*dname)
666 || *dname == '-' || *dname == '_'
667 || *dname == '*')
668 *s++ = *(char*)dname++;
669 else {
670 *s++ = '?';
671 dname++;
672 }
673 }
674 *s++ = '.';
675 lablen = *dname++;
676 }
677 *s = 0;
678 }
679
680 int
dname_strict_subdomain(uint8_t * d1,int labs1,uint8_t * d2,int labs2)681 dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
682 {
683 int m;
684 /* check subdomain: d1: www.example.com. and d2: example.com. */
685 if(labs2 >= labs1)
686 return 0;
687 if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
688 /* subdomain if all labels match */
689 return (m == labs2);
690 }
691 return 0;
692 }
693
694 int
dname_strict_subdomain_c(uint8_t * d1,uint8_t * d2)695 dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
696 {
697 return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
698 dname_count_labels(d2));
699 }
700
701 int
dname_subdomain_c(uint8_t * d1,uint8_t * d2)702 dname_subdomain_c(uint8_t* d1, uint8_t* d2)
703 {
704 int m;
705 /* check subdomain: d1: www.example.com. and d2: example.com. */
706 /* or d1: example.com. and d2: example.com. */
707 int labs1 = dname_count_labels(d1);
708 int labs2 = dname_count_labels(d2);
709 if(labs2 > labs1)
710 return 0;
711 if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
712 /* must have been example.com , www.example.com - wrong */
713 /* or otherwise different dnames */
714 return 0;
715 }
716 return (m == labs2);
717 }
718
719 int
dname_is_root(uint8_t * dname)720 dname_is_root(uint8_t* dname)
721 {
722 uint8_t len;
723 log_assert(dname);
724 len = dname[0];
725 log_assert(!LABEL_IS_PTR(len));
726 return (len == 0);
727 }
728
729 void
dname_remove_label(uint8_t ** dname,size_t * len)730 dname_remove_label(uint8_t** dname, size_t* len)
731 {
732 size_t lablen;
733 log_assert(dname && *dname && len);
734 lablen = (*dname)[0];
735 log_assert(!LABEL_IS_PTR(lablen));
736 log_assert(*len > lablen);
737 if(lablen == 0)
738 return; /* do not modify root label */
739 *len -= lablen+1;
740 *dname += lablen+1;
741 }
742
743 int
dname_remove_label_limit_len(uint8_t ** dname,size_t * len,size_t lenlimit)744 dname_remove_label_limit_len(uint8_t** dname, size_t* len, size_t lenlimit)
745 {
746 size_t lablen;
747 log_assert(dname && *dname && len);
748 lablen = (*dname)[0];
749 log_assert(!LABEL_IS_PTR(lablen));
750 log_assert(*len > lablen);
751 if(lablen == 0)
752 return 0; /* do not modify root label */
753 if(*len - (lablen + 1) < lenlimit) return 0;
754 *len -= lablen+1;
755 *dname += lablen+1;
756 return 1;
757 }
758
759 void
dname_remove_labels(uint8_t ** dname,size_t * len,int n)760 dname_remove_labels(uint8_t** dname, size_t* len, int n)
761 {
762 int i;
763 for(i=0; i<n; i++)
764 dname_remove_label(dname, len);
765 }
766
767 int
dname_signame_label_count(uint8_t * dname)768 dname_signame_label_count(uint8_t* dname)
769 {
770 uint8_t lablen;
771 int count = 0;
772 if(!*dname)
773 return 0;
774 if(dname[0] == 1 && dname[1] == '*')
775 dname += 2;
776 lablen = dname[0];
777 while(lablen) {
778 count++;
779 dname += lablen;
780 dname += 1;
781 lablen = dname[0];
782 }
783 return count;
784 }
785
786 int
dname_is_wild(uint8_t * dname)787 dname_is_wild(uint8_t* dname)
788 {
789 return (dname[0] == 1 && dname[1] == '*');
790 }
791
792 /**
793 * Compare labels in memory, lowercase while comparing.
794 * Returns canonical order for labels. If all is equal, the
795 * shortest is first.
796 *
797 * @param p1: label 1
798 * @param len1: length of label 1.
799 * @param p2: label 2
800 * @param len2: length of label 2.
801 * @return: 0, -1, +1 comparison result.
802 */
803 static int
memcanoncmp(uint8_t * p1,uint8_t len1,uint8_t * p2,uint8_t len2)804 memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
805 {
806 uint8_t min = (len1<len2)?len1:len2;
807 int c = memlowercmp(p1, p2, min);
808 if(c != 0)
809 return c;
810 /* equal, see who is shortest */
811 if(len1 < len2)
812 return -1;
813 if(len1 > len2)
814 return 1;
815 return 0;
816 }
817
818
819 int
dname_canon_lab_cmp(uint8_t * d1,int labs1,uint8_t * d2,int labs2,int * mlabs)820 dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
821 {
822 /* like dname_lab_cmp, but with different label comparison,
823 * empty character sorts before \000.
824 * So ylyly is before z. */
825 uint8_t len1, len2;
826 int atlabel = labs1;
827 int lastmlabs;
828 int lastdiff = 0;
829 int c;
830 /* first skip so that we compare same label. */
831 if(labs1 > labs2) {
832 while(atlabel > labs2) {
833 len1 = *d1++;
834 d1 += len1;
835 atlabel--;
836 }
837 log_assert(atlabel == labs2);
838 } else if(labs1 < labs2) {
839 atlabel = labs2;
840 while(atlabel > labs1) {
841 len2 = *d2++;
842 d2 += len2;
843 atlabel--;
844 }
845 log_assert(atlabel == labs1);
846 }
847 lastmlabs = atlabel+1;
848 /* now at same label in d1 and d2, atlabel */
849 /* www.example.com. */
850 /* 4 3 2 1 atlabel number */
851 /* repeat until at root label (which is always the same) */
852 while(atlabel > 1) {
853 len1 = *d1++;
854 len2 = *d2++;
855
856 if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
857 if(c<0)
858 lastdiff = -1;
859 else lastdiff = 1;
860 lastmlabs = atlabel;
861 }
862
863 d1 += len1;
864 d2 += len2;
865 atlabel--;
866 }
867 /* last difference atlabel number, so number of labels matching,
868 * at the right side, is one less. */
869 *mlabs = lastmlabs-1;
870 if(lastdiff == 0) {
871 /* all labels compared were equal, check if one has more
872 * labels, so that example.com. > com. */
873 if(labs1 > labs2)
874 return 1;
875 else if(labs1 < labs2)
876 return -1;
877 }
878 return lastdiff;
879 }
880
881 int
dname_canonical_compare(uint8_t * d1,uint8_t * d2)882 dname_canonical_compare(uint8_t* d1, uint8_t* d2)
883 {
884 int labs1, labs2, m;
885 labs1 = dname_count_labels(d1);
886 labs2 = dname_count_labels(d2);
887 return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
888 }
889
dname_get_shared_topdomain(uint8_t * d1,uint8_t * d2)890 uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
891 {
892 int labs1, labs2, m;
893 size_t len = LDNS_MAX_DOMAINLEN;
894 labs1 = dname_count_labels(d1);
895 labs2 = dname_count_labels(d2);
896 (void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
897 dname_remove_labels(&d1, &len, labs1-m);
898 return d1;
899 }
900