]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/unbound/util/data/dname.c
Fix multiple vulnerabilities in unbound.
[FreeBSD/FreeBSD.git] / contrib / unbound / util / data / dname.c
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 {
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 
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 
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 
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 
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
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 
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
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
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
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
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 
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 
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
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 
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
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
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 
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
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                 if(lablen > LDNS_MAX_LABELLEN) {
652                         *s++ = '#';
653                         *s = 0;
654                         return;
655                 }
656                 len += lablen+1;
657                 if(len >= LDNS_MAX_DOMAINLEN-1) {
658                         *s++ = '&';
659                         *s = 0;
660                         return;
661                 }
662                 while(lablen--) {
663                         if(isalnum((unsigned char)*dname) 
664                                 || *dname == '-' || *dname == '_' 
665                                 || *dname == '*')
666                                 *s++ = *(char*)dname++;
667                         else    {
668                                 *s++ = '?';
669                                 dname++;
670                         }
671                 }
672                 *s++ = '.';
673                 lablen = *dname++;
674         }
675         *s = 0;
676 }
677
678 int 
679 dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
680 {
681         int m;
682         /* check subdomain: d1: www.example.com. and d2: example.com. */
683         if(labs2 >= labs1) 
684                 return 0;
685         if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
686                 /* subdomain if all labels match */
687                 return (m == labs2);
688         }
689         return 0;
690 }
691
692 int 
693 dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
694 {
695         return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
696                 dname_count_labels(d2));
697 }
698
699 int 
700 dname_subdomain_c(uint8_t* d1, uint8_t* d2)
701 {
702         int m;
703         /* check subdomain: d1: www.example.com. and d2: example.com. */
704         /*      or          d1: example.com. and d2: example.com. */
705         int labs1 = dname_count_labels(d1);
706         int labs2 = dname_count_labels(d2);
707         if(labs2 > labs1) 
708                 return 0;
709         if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
710                 /* must have been example.com , www.example.com - wrong */
711                 /* or otherwise different dnames */
712                 return 0;
713         }
714         return (m == labs2);
715 }
716
717 int 
718 dname_is_root(uint8_t* dname)
719 {
720         uint8_t len;
721         log_assert(dname);
722         len = dname[0];
723         log_assert(!LABEL_IS_PTR(len));
724         return (len == 0);
725 }
726
727 void 
728 dname_remove_label(uint8_t** dname, size_t* len)
729 {
730         size_t lablen;
731         log_assert(dname && *dname && len);
732         lablen = (*dname)[0];
733         log_assert(!LABEL_IS_PTR(lablen));
734         log_assert(*len > lablen);
735         if(lablen == 0)
736                 return; /* do not modify root label */
737         *len -= lablen+1;
738         *dname += lablen+1;
739 }
740
741 void 
742 dname_remove_labels(uint8_t** dname, size_t* len, int n)
743 {
744         int i;
745         for(i=0; i<n; i++)
746                 dname_remove_label(dname, len);
747 }
748
749 int 
750 dname_signame_label_count(uint8_t* dname)
751 {
752         uint8_t lablen;
753         int count = 0;
754         if(!*dname)
755                 return 0;
756         if(dname[0] == 1 && dname[1] == '*')
757                 dname += 2;
758         lablen = dname[0];
759         while(lablen) {
760                 count++;
761                 dname += lablen;
762                 dname += 1;
763                 lablen = dname[0];
764         }
765         return count;
766 }
767
768 int 
769 dname_is_wild(uint8_t* dname)
770 {
771         return (dname[0] == 1 && dname[1] == '*');
772 }
773
774 /**
775  * Compare labels in memory, lowercase while comparing.
776  * Returns canonical order for labels. If all is equal, the
777  * shortest is first.
778  *
779  * @param p1: label 1
780  * @param len1: length of label 1.
781  * @param p2: label 2
782  * @param len2: length of label 2.
783  * @return: 0, -1, +1 comparison result.
784  */
785 static int
786 memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
787 {
788         uint8_t min = (len1<len2)?len1:len2;
789         int c = memlowercmp(p1, p2, min);
790         if(c != 0)
791                 return c;
792         /* equal, see who is shortest */
793         if(len1 < len2)
794                 return -1;
795         if(len1 > len2)
796                 return 1;
797         return 0;
798 }
799
800
801 int 
802 dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
803 {
804         /* like dname_lab_cmp, but with different label comparison,
805          * empty character sorts before \000.
806          * So   ylyly is before z. */
807         uint8_t len1, len2;
808         int atlabel = labs1;
809         int lastmlabs;
810         int lastdiff = 0;
811         int c;
812         /* first skip so that we compare same label. */
813         if(labs1 > labs2) {
814                 while(atlabel > labs2) {
815                         len1 = *d1++;
816                         d1 += len1;
817                         atlabel--;
818                 }
819                 log_assert(atlabel == labs2);
820         } else if(labs1 < labs2) {
821                 atlabel = labs2;
822                 while(atlabel > labs1) {
823                         len2 = *d2++;
824                         d2 += len2;
825                         atlabel--;
826                 }
827                 log_assert(atlabel == labs1);
828         }
829         lastmlabs = atlabel+1;
830         /* now at same label in d1 and d2, atlabel */
831         /* www.example.com.                  */
832         /* 4   3       2  1   atlabel number */
833         /* repeat until at root label (which is always the same) */
834         while(atlabel > 1) {
835                 len1 = *d1++;
836                 len2 = *d2++;
837
838                 if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
839                         if(c<0)
840                                 lastdiff = -1;
841                         else    lastdiff = 1;
842                         lastmlabs = atlabel;
843                 }
844
845                 d1 += len1;
846                 d2 += len2;
847                 atlabel--;
848         }
849         /* last difference atlabel number, so number of labels matching,
850          * at the right side, is one less. */
851         *mlabs = lastmlabs-1;
852         if(lastdiff == 0) {
853                 /* all labels compared were equal, check if one has more
854                  * labels, so that example.com. > com. */
855                 if(labs1 > labs2)
856                         return 1;
857                 else if(labs1 < labs2)
858                         return -1;
859         }
860         return lastdiff;
861 }
862
863 int
864 dname_canonical_compare(uint8_t* d1, uint8_t* d2)
865 {
866         int labs1, labs2, m;
867         labs1 = dname_count_labels(d1);
868         labs2 = dname_count_labels(d2);
869         return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
870 }
871
872 uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
873 {
874         int labs1, labs2, m;
875         size_t len = LDNS_MAX_DOMAINLEN;
876         labs1 = dname_count_labels(d1);
877         labs2 = dname_count_labels(d2);
878         (void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
879         dname_remove_labels(&d1, &len, labs1-m);
880         return d1;
881 }