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