]> git.saurik.com Git - apple/network_cmds.git/blame - unbound/util/data/dname.c
network_cmds-596.100.2.tar.gz
[apple/network_cmds.git] / unbound / util / data / dname.c
CommitLineData
89c4ed63
A
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 */
51size_t
52query_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
73size_t
74dname_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 */
97int
98query_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
132void
133query_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
148void
149pkt_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
180size_t
181pkt_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
230int
231dname_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
271hashvalue_t
272dname_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
293hashvalue_t
294dname_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
321void 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
351void 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
382int
383dname_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
397int
398dname_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 */
422static int
423memlowercmp(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
437int
438dname_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
520int
521dname_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
540void 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
579int
580dname_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
593int
594dname_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
600int
601dname_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
618int
619dname_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
628void
629dname_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
642void
643dname_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
650int
651dname_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
669int
670dname_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 */
686static int
687memcanoncmp(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
702int
703dname_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
764int
765dname_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
773uint8_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}