]>
git.saurik.com Git - apple/network_cmds.git/blob - unbound/util/data/dname.c
2 * util/data/dname.h - domain name handling
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
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.
39 * This file contains domain name handling functions.
44 #include "util/data/dname.h"
45 #include "util/data/msgparse.h"
47 #include "util/storage/lookup3.h"
48 #include "ldns/sbuffer.h"
50 /* determine length of a dname in buffer, no compression pointers allowed */
52 query_dname_len(sldns_buffer
* query
)
57 if(sldns_buffer_remaining(query
) < 1)
58 return 0; /* parse error, need label len */
59 labellen
= sldns_buffer_read_u8(query
);
61 return 0; /* no compression allowed in queries */
63 if(len
> LDNS_MAX_DOMAINLEN
)
64 return 0; /* too long */
67 if(sldns_buffer_remaining(query
) < labellen
)
68 return 0; /* parse error, need content */
69 sldns_buffer_skip(query
, (ssize_t
)labellen
);
74 dname_valid(uint8_t* dname
, size_t maxlen
)
81 return 0; /* no compression ptrs allowed */
83 if(len
>= LDNS_MAX_DOMAINLEN
)
84 return 0; /* too long */
86 return 0; /* does not fit in memory allocation */
92 return 0; /* does not fit in memory allocation */
96 /** compare uncompressed, noncanonical, registers are hints for speed */
98 query_dname_compare(register uint8_t* d1
, register uint8_t* d2
)
100 register uint8_t lab1
, lab2
;
101 log_assert(d1
&& d2
);
104 while( lab1
!= 0 || lab2
!= 0 ) {
105 /* compare label length */
106 /* if one dname ends, it has labellength 0 */
112 log_assert(lab1
== lab2
&& lab1
!= 0);
113 /* compare lowercased labels. */
115 /* compare bytes first for speed */
117 tolower((unsigned char)*d1
) != tolower((unsigned char)*d2
)) {
118 if(tolower((unsigned char)*d1
) < tolower((unsigned char)*d2
))
125 /* next pair of labels. */
133 query_dname_tolower(uint8_t* dname
)
135 /* the dname is stored uncompressed */
141 *dname
= (uint8_t)tolower((unsigned char)*dname
);
149 pkt_dname_tolower(sldns_buffer
* pkt
, uint8_t* dname
)
153 if(dname
>= sldns_buffer_end(pkt
))
157 if(LABEL_IS_PTR(lablen
)) {
158 if((size_t)PTR_OFFSET(lablen
, *dname
)
159 >= sldns_buffer_limit(pkt
))
161 dname
= sldns_buffer_at(pkt
, PTR_OFFSET(lablen
, *dname
));
163 if(count
++ > MAX_COMPRESS_PTRS
)
167 if(dname
+lablen
>= sldns_buffer_end(pkt
))
170 *dname
= (uint8_t)tolower((unsigned char)*dname
);
173 if(dname
>= sldns_buffer_end(pkt
))
181 pkt_dname_len(sldns_buffer
* pkt
)
188 /* read dname and determine length */
189 /* check compression pointers, loops, out of bounds */
191 /* read next label */
192 if(sldns_buffer_remaining(pkt
) < 1)
194 labellen
= sldns_buffer_read_u8(pkt
);
195 if(LABEL_IS_PTR(labellen
)) {
196 /* compression ptr */
198 if(sldns_buffer_remaining(pkt
) < 1)
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! */
206 endpos
= sldns_buffer_position(pkt
);
207 sldns_buffer_set_position(pkt
, ptr
);
211 return 0; /* label too long */
213 if(len
> LDNS_MAX_DOMAINLEN
)
219 if(sldns_buffer_remaining(pkt
) < labellen
)
221 sldns_buffer_skip(pkt
, (ssize_t
)labellen
);
225 sldns_buffer_set_position(pkt
, endpos
);
231 dname_pkt_compare(sldns_buffer
* pkt
, uint8_t* d1
, uint8_t* d2
)
234 log_assert(pkt
&& d1
&& d2
);
237 while( len1
!= 0 || len2
!= 0 ) {
239 if(LABEL_IS_PTR(len1
)) {
240 d1
= sldns_buffer_at(pkt
, PTR_OFFSET(len1
, *d1
));
244 if(LABEL_IS_PTR(len2
)) {
245 d2
= sldns_buffer_at(pkt
, PTR_OFFSET(len2
, *d2
));
249 /* check label length */
250 log_assert(len1
<= LDNS_MAX_LABELLEN
);
251 log_assert(len2
<= LDNS_MAX_LABELLEN
);
253 if(len1
< len2
) return -1;
256 log_assert(len1
== len2
&& len1
!= 0);
259 if(tolower((unsigned char)*d1
++) != tolower((unsigned char)*d2
++)) {
260 if(tolower((unsigned char)d1
[-1]) < tolower((unsigned char)d2
[-1]))
272 dname_query_hash(uint8_t* dname
, hashvalue_t h
)
274 uint8_t labuf
[LDNS_MAX_LABELLEN
+1];
278 /* preserve case of query, make hash label by label */
281 log_assert(lablen
<= LDNS_MAX_LABELLEN
);
285 labuf
[++i
] = (uint8_t)tolower((unsigned char)*dname
++);
286 h
= hashlittle(labuf
, labuf
[0] + 1, h
);
294 dname_pkt_hash(sldns_buffer
* pkt
, uint8_t* dname
, hashvalue_t h
)
296 uint8_t labuf
[LDNS_MAX_LABELLEN
+1];
300 /* preserve case of query, make hash label by label */
303 if(LABEL_IS_PTR(lablen
)) {
305 dname
= sldns_buffer_at(pkt
, PTR_OFFSET(lablen
, *dname
));
309 log_assert(lablen
<= LDNS_MAX_LABELLEN
);
313 labuf
[++i
] = (uint8_t)tolower((unsigned char)*dname
++);
314 h
= hashlittle(labuf
, labuf
[0] + 1, h
);
321 void dname_pkt_copy(sldns_buffer
* pkt
, uint8_t* to
, uint8_t* dname
)
323 /* copy over the dname and decompress it at the same time */
328 if(LABEL_IS_PTR(lablen
)) {
330 dname
= sldns_buffer_at(pkt
, PTR_OFFSET(lablen
, *dname
));
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");
342 memmove(to
, dname
, lablen
);
351 void dname_print(FILE* out
, struct sldns_buffer
* pkt
, uint8_t* dname
)
354 if(!out
) out
= stdout
;
361 if(LABEL_IS_PTR(lablen
)) {
364 fputs("??compressionptr??", out
);
367 dname
= sldns_buffer_at(pkt
, PTR_OFFSET(lablen
, *dname
));
371 if(lablen
> LDNS_MAX_LABELLEN
) {
372 fputs("??extendedlabel??", out
);
376 fputc((int)*dname
++, out
);
383 dname_count_labels(uint8_t* dname
)
398 dname_count_size_labels(uint8_t* dname
, size_t* size
)
416 * Compare labels in memory, lowercase while comparing.
419 * @param len: number of bytes to compare.
420 * @return: 0, -1, +1 comparison result.
423 memlowercmp(uint8_t* p1
, uint8_t* p2
, uint8_t len
)
426 if(*p1
!= *p2
&& tolower((unsigned char)*p1
) != tolower((unsigned char)*p2
)) {
427 if(tolower((unsigned char)*p1
) < tolower((unsigned char)*p2
))
438 dname_lab_cmp(uint8_t* d1
, int labs1
, uint8_t* d2
, int labs2
, int* mlabs
)
444 /* first skip so that we compare same label. */
446 while(atlabel
> labs2
) {
451 log_assert(atlabel
== labs2
);
452 } else if(labs1
< labs2
) {
454 while(atlabel
> labs1
) {
459 log_assert(atlabel
== labs1
);
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) */
470 log_assert(len1
!= 0 && len2
!= 0);
478 /* memlowercmp is inlined here; or just like
479 * if((c=memlowercmp(d1, d2, len1)) != 0) {
481 * lastmlabs = atlabel; } apart from d1++,d2++ */
483 if(*d1
!= *d2
&& tolower((unsigned char)*d1
)
484 != tolower((unsigned char)*d2
)) {
485 if(tolower((unsigned char)*d1
) <
486 tolower((unsigned char)*d2
)) {
497 break; /* out of memlowercmp */
506 /* last difference atlabel number, so number of labels matching,
507 * at the right side, is one less. */
508 *mlabs
= lastmlabs
-1;
510 /* all labels compared were equal, check if one has more
511 * labels, so that example.com. > com. */
514 else if(labs1
< labs2
)
521 dname_buffer_write(sldns_buffer
* pkt
, uint8_t* dname
)
525 if(sldns_buffer_remaining(pkt
) < 1)
528 sldns_buffer_write_u8(pkt
, lablen
);
530 if(sldns_buffer_remaining(pkt
) < (size_t)lablen
+1)
532 sldns_buffer_write(pkt
, dname
, lablen
);
535 sldns_buffer_write_u8(pkt
, lablen
);
540 void dname_str(uint8_t* dname
, char* str
)
545 if(!dname
|| !*dname
) {
552 if(lablen
> LDNS_MAX_LABELLEN
) {
558 if(len
>= LDNS_MAX_DOMAINLEN
-1) {
564 if(isalnum((unsigned char)*dname
)
565 || *dname
== '-' || *dname
== '_'
567 *s
++ = *(char*)dname
++;
580 dname_strict_subdomain(uint8_t* d1
, int labs1
, uint8_t* d2
, int labs2
)
583 /* check subdomain: d1: www.example.com. and d2: example.com. */
586 if(dname_lab_cmp(d1
, labs1
, d2
, labs2
, &m
) > 0) {
587 /* subdomain if all labels match */
594 dname_strict_subdomain_c(uint8_t* d1
, uint8_t* d2
)
596 return dname_strict_subdomain(d1
, dname_count_labels(d1
), d2
,
597 dname_count_labels(d2
));
601 dname_subdomain_c(uint8_t* d1
, uint8_t* d2
)
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
);
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 */
619 dname_is_root(uint8_t* dname
)
624 log_assert(!LABEL_IS_PTR(len
));
629 dname_remove_label(uint8_t** dname
, size_t* len
)
632 log_assert(dname
&& *dname
&& len
);
633 lablen
= (*dname
)[0];
634 log_assert(!LABEL_IS_PTR(lablen
));
635 log_assert(*len
> lablen
);
637 return; /* do not modify root label */
643 dname_remove_labels(uint8_t** dname
, size_t* len
, int n
)
647 dname_remove_label(dname
, len
);
651 dname_signame_label_count(uint8_t* dname
)
657 if(dname
[0] == 1 && dname
[1] == '*')
670 dname_is_wild(uint8_t* dname
)
672 return (dname
[0] == 1 && dname
[1] == '*');
676 * Compare labels in memory, lowercase while comparing.
677 * Returns canonical order for labels. If all is equal, the
681 * @param len1: length of label 1.
683 * @param len2: length of label 2.
684 * @return: 0, -1, +1 comparison result.
687 memcanoncmp(uint8_t* p1
, uint8_t len1
, uint8_t* p2
, uint8_t len2
)
689 uint8_t min
= (len1
<len2
)?len1
:len2
;
690 int c
= memlowercmp(p1
, p2
, min
);
693 /* equal, see who is shortest */
703 dname_canon_lab_cmp(uint8_t* d1
, int labs1
, uint8_t* d2
, int labs2
, int* mlabs
)
705 /* like dname_lab_cmp, but with different label comparison,
706 * empty character sorts before \000.
707 * So ylyly is before z. */
713 /* first skip so that we compare same label. */
715 while(atlabel
> labs2
) {
720 log_assert(atlabel
== labs2
);
721 } else if(labs1
< labs2
) {
723 while(atlabel
> labs1
) {
728 log_assert(atlabel
== labs1
);
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) */
739 if((c
=memcanoncmp(d1
, len1
, d2
, len2
)) != 0) {
750 /* last difference atlabel number, so number of labels matching,
751 * at the right side, is one less. */
752 *mlabs
= lastmlabs
-1;
754 /* all labels compared were equal, check if one has more
755 * labels, so that example.com. > com. */
758 else if(labs1
< labs2
)
765 dname_canonical_compare(uint8_t* d1
, uint8_t* d2
)
768 labs1
= dname_count_labels(d1
);
769 labs2
= dname_count_labels(d2
);
770 return dname_canon_lab_cmp(d1
, labs1
, d2
, labs2
, &m
);
773 uint8_t* dname_get_shared_topdomain(uint8_t* d1
, uint8_t* d2
)
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
);