1eaad808eSchristos /*
2eaad808eSchristos * util/data/dname.h - domain name handling
3eaad808eSchristos *
4eaad808eSchristos * Copyright (c) 2007, NLnet Labs. All rights reserved.
5eaad808eSchristos *
6eaad808eSchristos * This software is open source.
7eaad808eSchristos *
8eaad808eSchristos * Redistribution and use in source and binary forms, with or without
9eaad808eSchristos * modification, are permitted provided that the following conditions
10eaad808eSchristos * are met:
11eaad808eSchristos *
12eaad808eSchristos * Redistributions of source code must retain the above copyright notice,
13eaad808eSchristos * this list of conditions and the following disclaimer.
14eaad808eSchristos *
15eaad808eSchristos * Redistributions in binary form must reproduce the above copyright notice,
16eaad808eSchristos * this list of conditions and the following disclaimer in the documentation
17eaad808eSchristos * and/or other materials provided with the distribution.
18eaad808eSchristos *
19eaad808eSchristos * Neither the name of the NLNET LABS nor the names of its contributors may
20eaad808eSchristos * be used to endorse or promote products derived from this software without
21eaad808eSchristos * specific prior written permission.
22eaad808eSchristos *
23eaad808eSchristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24eaad808eSchristos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25eaad808eSchristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26eaad808eSchristos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27eaad808eSchristos * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28eaad808eSchristos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29eaad808eSchristos * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30eaad808eSchristos * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31eaad808eSchristos * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32eaad808eSchristos * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33eaad808eSchristos * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34eaad808eSchristos */
35eaad808eSchristos
36eaad808eSchristos /**
37eaad808eSchristos * \file
38eaad808eSchristos *
39eaad808eSchristos * This file contains domain name handling functions.
40eaad808eSchristos */
41eaad808eSchristos
42eaad808eSchristos #include "config.h"
43eaad808eSchristos #include <ctype.h>
44eaad808eSchristos #include "util/data/dname.h"
45eaad808eSchristos #include "util/data/msgparse.h"
46eaad808eSchristos #include "util/log.h"
47eaad808eSchristos #include "util/storage/lookup3.h"
48eaad808eSchristos #include "sldns/sbuffer.h"
49eaad808eSchristos
50eaad808eSchristos /* determine length of a dname in buffer, no compression pointers allowed */
51eaad808eSchristos size_t
query_dname_len(sldns_buffer * query)52eaad808eSchristos query_dname_len(sldns_buffer* query)
53eaad808eSchristos {
54eaad808eSchristos size_t len = 0;
55eaad808eSchristos size_t labellen;
56eaad808eSchristos while(1) {
57eaad808eSchristos if(sldns_buffer_remaining(query) < 1)
58eaad808eSchristos return 0; /* parse error, need label len */
59eaad808eSchristos labellen = sldns_buffer_read_u8(query);
60eaad808eSchristos if(labellen&0xc0)
61eaad808eSchristos return 0; /* no compression allowed in queries */
62eaad808eSchristos len += labellen + 1;
63eaad808eSchristos if(len > LDNS_MAX_DOMAINLEN)
64eaad808eSchristos return 0; /* too long */
65eaad808eSchristos if(labellen == 0)
66eaad808eSchristos return len;
67eaad808eSchristos if(sldns_buffer_remaining(query) < labellen)
68eaad808eSchristos return 0; /* parse error, need content */
69eaad808eSchristos sldns_buffer_skip(query, (ssize_t)labellen);
70eaad808eSchristos }
71eaad808eSchristos }
72eaad808eSchristos
73eaad808eSchristos size_t
dname_valid(uint8_t * dname,size_t maxlen)74eaad808eSchristos dname_valid(uint8_t* dname, size_t maxlen)
75eaad808eSchristos {
76eaad808eSchristos size_t len = 0;
77eaad808eSchristos size_t labellen;
78f337475aSchristos if(maxlen == 0)
79f337475aSchristos return 0; /* too short, shortest is '0' root label */
80eaad808eSchristos labellen = *dname++;
81eaad808eSchristos while(labellen) {
82eaad808eSchristos if(labellen&0xc0)
83eaad808eSchristos return 0; /* no compression ptrs allowed */
84eaad808eSchristos len += labellen + 1;
85eaad808eSchristos if(len >= LDNS_MAX_DOMAINLEN)
86eaad808eSchristos return 0; /* too long */
87eaad808eSchristos if(len > maxlen)
88eaad808eSchristos return 0; /* does not fit in memory allocation */
89eaad808eSchristos dname += labellen;
90eaad808eSchristos labellen = *dname++;
91eaad808eSchristos }
92eaad808eSchristos len += 1;
93eaad808eSchristos if(len > maxlen)
94eaad808eSchristos return 0; /* does not fit in memory allocation */
95eaad808eSchristos return len;
96eaad808eSchristos }
97eaad808eSchristos
98eaad808eSchristos /** compare uncompressed, noncanonical, registers are hints for speed */
99eaad808eSchristos int
query_dname_compare(register uint8_t * d1,register uint8_t * d2)100eaad808eSchristos query_dname_compare(register uint8_t* d1, register uint8_t* d2)
101eaad808eSchristos {
102eaad808eSchristos register uint8_t lab1, lab2;
103eaad808eSchristos log_assert(d1 && d2);
104eaad808eSchristos lab1 = *d1++;
105eaad808eSchristos lab2 = *d2++;
106eaad808eSchristos while( lab1 != 0 || lab2 != 0 ) {
107eaad808eSchristos /* compare label length */
108eaad808eSchristos /* if one dname ends, it has labellength 0 */
109eaad808eSchristos if(lab1 != lab2) {
110eaad808eSchristos if(lab1 < lab2)
111eaad808eSchristos return -1;
112eaad808eSchristos return 1;
113eaad808eSchristos }
114eaad808eSchristos log_assert(lab1 == lab2 && lab1 != 0);
115eaad808eSchristos /* compare lowercased labels. */
116eaad808eSchristos while(lab1--) {
117eaad808eSchristos /* compare bytes first for speed */
118eaad808eSchristos if(*d1 != *d2 &&
119eaad808eSchristos tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
120eaad808eSchristos if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
121eaad808eSchristos return -1;
122eaad808eSchristos return 1;
123eaad808eSchristos }
124eaad808eSchristos d1++;
125eaad808eSchristos d2++;
126eaad808eSchristos }
127eaad808eSchristos /* next pair of labels. */
128eaad808eSchristos lab1 = *d1++;
129eaad808eSchristos lab2 = *d2++;
130eaad808eSchristos }
131eaad808eSchristos return 0;
132eaad808eSchristos }
133eaad808eSchristos
134eaad808eSchristos void
query_dname_tolower(uint8_t * dname)135eaad808eSchristos query_dname_tolower(uint8_t* dname)
136eaad808eSchristos {
137eaad808eSchristos /* the dname is stored uncompressed */
138eaad808eSchristos uint8_t labellen;
139eaad808eSchristos labellen = *dname;
140eaad808eSchristos while(labellen) {
141eaad808eSchristos dname++;
142eaad808eSchristos while(labellen--) {
143eaad808eSchristos *dname = (uint8_t)tolower((unsigned char)*dname);
144eaad808eSchristos dname++;
145eaad808eSchristos }
146eaad808eSchristos labellen = *dname;
147eaad808eSchristos }
148eaad808eSchristos }
149eaad808eSchristos
150eaad808eSchristos void
pkt_dname_tolower(sldns_buffer * pkt,uint8_t * dname)151eaad808eSchristos pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname)
152eaad808eSchristos {
153eaad808eSchristos uint8_t lablen;
154eaad808eSchristos int count = 0;
155eaad808eSchristos if(dname >= sldns_buffer_end(pkt))
156eaad808eSchristos return;
157eaad808eSchristos lablen = *dname++;
158eaad808eSchristos while(lablen) {
159eaad808eSchristos if(LABEL_IS_PTR(lablen)) {
160eaad808eSchristos if((size_t)PTR_OFFSET(lablen, *dname)
161eaad808eSchristos >= sldns_buffer_limit(pkt))
162eaad808eSchristos return;
163eaad808eSchristos dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
164eaad808eSchristos lablen = *dname++;
165eaad808eSchristos if(count++ > MAX_COMPRESS_PTRS)
166eaad808eSchristos return;
167eaad808eSchristos continue;
168eaad808eSchristos }
169eaad808eSchristos if(dname+lablen >= sldns_buffer_end(pkt))
170eaad808eSchristos return;
171eaad808eSchristos while(lablen--) {
172eaad808eSchristos *dname = (uint8_t)tolower((unsigned char)*dname);
173eaad808eSchristos dname++;
174eaad808eSchristos }
175eaad808eSchristos if(dname >= sldns_buffer_end(pkt))
176eaad808eSchristos return;
177eaad808eSchristos lablen = *dname++;
178eaad808eSchristos }
179eaad808eSchristos }
180eaad808eSchristos
181eaad808eSchristos
182eaad808eSchristos size_t
pkt_dname_len(sldns_buffer * pkt)183eaad808eSchristos pkt_dname_len(sldns_buffer* pkt)
184eaad808eSchristos {
185eaad808eSchristos size_t len = 0;
186eaad808eSchristos int ptrcount = 0;
187eaad808eSchristos uint8_t labellen;
188eaad808eSchristos size_t endpos = 0;
189eaad808eSchristos
190eaad808eSchristos /* read dname and determine length */
191eaad808eSchristos /* check compression pointers, loops, out of bounds */
192eaad808eSchristos while(1) {
193eaad808eSchristos /* read next label */
194eaad808eSchristos if(sldns_buffer_remaining(pkt) < 1)
195eaad808eSchristos return 0;
196eaad808eSchristos labellen = sldns_buffer_read_u8(pkt);
197eaad808eSchristos if(LABEL_IS_PTR(labellen)) {
198eaad808eSchristos /* compression ptr */
199eaad808eSchristos uint16_t ptr;
200eaad808eSchristos if(sldns_buffer_remaining(pkt) < 1)
201eaad808eSchristos return 0;
202eaad808eSchristos ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
203eaad808eSchristos if(ptrcount++ > MAX_COMPRESS_PTRS)
204eaad808eSchristos return 0; /* loop! */
205eaad808eSchristos if(sldns_buffer_limit(pkt) <= ptr)
206eaad808eSchristos return 0; /* out of bounds! */
207eaad808eSchristos if(!endpos)
208eaad808eSchristos endpos = sldns_buffer_position(pkt);
209eaad808eSchristos sldns_buffer_set_position(pkt, ptr);
210eaad808eSchristos } else {
211eaad808eSchristos /* label contents */
212eaad808eSchristos if(labellen > 0x3f)
213eaad808eSchristos return 0; /* label too long */
214eaad808eSchristos len += 1 + labellen;
215eaad808eSchristos if(len > LDNS_MAX_DOMAINLEN)
216eaad808eSchristos return 0;
217eaad808eSchristos if(labellen == 0) {
218eaad808eSchristos /* end of dname */
219eaad808eSchristos break;
220eaad808eSchristos }
221eaad808eSchristos if(sldns_buffer_remaining(pkt) < labellen)
222eaad808eSchristos return 0;
223eaad808eSchristos sldns_buffer_skip(pkt, (ssize_t)labellen);
224eaad808eSchristos }
225eaad808eSchristos }
226eaad808eSchristos if(endpos)
227eaad808eSchristos sldns_buffer_set_position(pkt, endpos);
228eaad808eSchristos
229eaad808eSchristos return len;
230eaad808eSchristos }
231eaad808eSchristos
232eaad808eSchristos int
dname_pkt_compare(sldns_buffer * pkt,uint8_t * d1,uint8_t * d2)233eaad808eSchristos dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
234eaad808eSchristos {
235eaad808eSchristos uint8_t len1, len2;
236*561252a2Schristos int count1 = 0, count2 = 0;
237eaad808eSchristos log_assert(pkt && d1 && d2);
238eaad808eSchristos len1 = *d1++;
239eaad808eSchristos len2 = *d2++;
240eaad808eSchristos while( len1 != 0 || len2 != 0 ) {
241eaad808eSchristos /* resolve ptrs */
242eaad808eSchristos if(LABEL_IS_PTR(len1)) {
243*561252a2Schristos if((size_t)PTR_OFFSET(len1, *d1)
244*561252a2Schristos >= sldns_buffer_limit(pkt))
245*561252a2Schristos return -1;
246*561252a2Schristos if(count1++ > MAX_COMPRESS_PTRS)
247*561252a2Schristos return -1;
248eaad808eSchristos d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
249eaad808eSchristos len1 = *d1++;
250eaad808eSchristos continue;
251eaad808eSchristos }
252eaad808eSchristos if(LABEL_IS_PTR(len2)) {
253*561252a2Schristos if((size_t)PTR_OFFSET(len2, *d2)
254*561252a2Schristos >= sldns_buffer_limit(pkt))
255*561252a2Schristos return 1;
256*561252a2Schristos if(count2++ > MAX_COMPRESS_PTRS)
257*561252a2Schristos return 1;
258eaad808eSchristos d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
259eaad808eSchristos len2 = *d2++;
260eaad808eSchristos continue;
261eaad808eSchristos }
262eaad808eSchristos /* check label length */
263eaad808eSchristos log_assert(len1 <= LDNS_MAX_LABELLEN);
264eaad808eSchristos log_assert(len2 <= LDNS_MAX_LABELLEN);
265eaad808eSchristos if(len1 != len2) {
266eaad808eSchristos if(len1 < len2) return -1;
267eaad808eSchristos return 1;
268eaad808eSchristos }
269eaad808eSchristos log_assert(len1 == len2 && len1 != 0);
270eaad808eSchristos /* compare labels */
271eaad808eSchristos while(len1--) {
272eaad808eSchristos if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
273eaad808eSchristos if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
274eaad808eSchristos return -1;
275eaad808eSchristos return 1;
276eaad808eSchristos }
277eaad808eSchristos d1++;
278eaad808eSchristos d2++;
279eaad808eSchristos }
280eaad808eSchristos len1 = *d1++;
281eaad808eSchristos len2 = *d2++;
282eaad808eSchristos }
283eaad808eSchristos return 0;
284eaad808eSchristos }
285eaad808eSchristos
286762909a6Schristos hashvalue_type
dname_query_hash(uint8_t * dname,hashvalue_type h)287762909a6Schristos dname_query_hash(uint8_t* dname, hashvalue_type h)
288eaad808eSchristos {
289eaad808eSchristos uint8_t labuf[LDNS_MAX_LABELLEN+1];
290eaad808eSchristos uint8_t lablen;
291eaad808eSchristos int i;
292eaad808eSchristos
293eaad808eSchristos /* preserve case of query, make hash label by label */
294eaad808eSchristos lablen = *dname++;
295eaad808eSchristos while(lablen) {
296eaad808eSchristos log_assert(lablen <= LDNS_MAX_LABELLEN);
297eaad808eSchristos labuf[0] = lablen;
298eaad808eSchristos i=0;
299eaad808eSchristos while(lablen--) {
300eaad808eSchristos labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
301eaad808eSchristos dname++;
302eaad808eSchristos }
303eaad808eSchristos h = hashlittle(labuf, labuf[0] + 1, h);
304eaad808eSchristos lablen = *dname++;
305eaad808eSchristos }
306eaad808eSchristos
307eaad808eSchristos return h;
308eaad808eSchristos }
309eaad808eSchristos
310762909a6Schristos hashvalue_type
dname_pkt_hash(sldns_buffer * pkt,uint8_t * dname,hashvalue_type h)311762909a6Schristos dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
312eaad808eSchristos {
313eaad808eSchristos uint8_t labuf[LDNS_MAX_LABELLEN+1];
314eaad808eSchristos uint8_t lablen;
315eaad808eSchristos int i;
316*561252a2Schristos int count = 0;
317eaad808eSchristos
318eaad808eSchristos /* preserve case of query, make hash label by label */
319eaad808eSchristos lablen = *dname++;
320eaad808eSchristos while(lablen) {
321eaad808eSchristos if(LABEL_IS_PTR(lablen)) {
322eaad808eSchristos /* follow pointer */
323*561252a2Schristos if((size_t)PTR_OFFSET(lablen, *dname)
324*561252a2Schristos >= sldns_buffer_limit(pkt))
325*561252a2Schristos return h;
326*561252a2Schristos if(count++ > MAX_COMPRESS_PTRS)
327*561252a2Schristos return h;
328eaad808eSchristos dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
329eaad808eSchristos lablen = *dname++;
330eaad808eSchristos continue;
331eaad808eSchristos }
332eaad808eSchristos log_assert(lablen <= LDNS_MAX_LABELLEN);
333eaad808eSchristos labuf[0] = lablen;
334eaad808eSchristos i=0;
335eaad808eSchristos while(lablen--) {
336eaad808eSchristos labuf[++i] = (uint8_t)tolower((unsigned char)*dname);
337eaad808eSchristos dname++;
338eaad808eSchristos }
339eaad808eSchristos h = hashlittle(labuf, labuf[0] + 1, h);
340eaad808eSchristos lablen = *dname++;
341eaad808eSchristos }
342eaad808eSchristos
343eaad808eSchristos return h;
344eaad808eSchristos }
345eaad808eSchristos
dname_pkt_copy(sldns_buffer * pkt,uint8_t * to,uint8_t * dname)346eaad808eSchristos void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
347eaad808eSchristos {
348eaad808eSchristos /* copy over the dname and decompress it at the same time */
349f337475aSchristos size_t comprcount = 0;
350eaad808eSchristos size_t len = 0;
351eaad808eSchristos uint8_t lablen;
352eaad808eSchristos lablen = *dname++;
353eaad808eSchristos while(lablen) {
354eaad808eSchristos if(LABEL_IS_PTR(lablen)) {
355f337475aSchristos if(comprcount++ > MAX_COMPRESS_PTRS) {
356f337475aSchristos /* too many compression pointers */
357f337475aSchristos *to = 0; /* end the result prematurely */
358f337475aSchristos return;
359f337475aSchristos }
360eaad808eSchristos /* follow pointer */
361*561252a2Schristos if((size_t)PTR_OFFSET(lablen, *dname)
362*561252a2Schristos >= sldns_buffer_limit(pkt))
363*561252a2Schristos return;
364eaad808eSchristos dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
365eaad808eSchristos lablen = *dname++;
366eaad808eSchristos continue;
367eaad808eSchristos }
368f337475aSchristos if(lablen > LDNS_MAX_LABELLEN) {
369f337475aSchristos *to = 0; /* end the result prematurely */
370f337475aSchristos return;
371f337475aSchristos }
372eaad808eSchristos log_assert(lablen <= LDNS_MAX_LABELLEN);
373eaad808eSchristos len += (size_t)lablen+1;
374eaad808eSchristos if(len >= LDNS_MAX_DOMAINLEN) {
375eaad808eSchristos *to = 0; /* end the result prematurely */
376eaad808eSchristos log_err("bad dname in dname_pkt_copy");
377eaad808eSchristos return;
378eaad808eSchristos }
379eaad808eSchristos *to++ = lablen;
380eaad808eSchristos memmove(to, dname, lablen);
381eaad808eSchristos dname += lablen;
382eaad808eSchristos to += lablen;
383eaad808eSchristos lablen = *dname++;
384eaad808eSchristos }
385eaad808eSchristos /* copy last \0 */
386eaad808eSchristos *to = 0;
387eaad808eSchristos }
388eaad808eSchristos
dname_print(FILE * out,struct sldns_buffer * pkt,uint8_t * dname)389eaad808eSchristos void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
390eaad808eSchristos {
391eaad808eSchristos uint8_t lablen;
392*561252a2Schristos int count = 0;
393eaad808eSchristos if(!out) out = stdout;
394eaad808eSchristos if(!dname) return;
395eaad808eSchristos
396eaad808eSchristos lablen = *dname++;
397eaad808eSchristos if(!lablen)
398eaad808eSchristos fputc('.', out);
399eaad808eSchristos while(lablen) {
400eaad808eSchristos if(LABEL_IS_PTR(lablen)) {
401eaad808eSchristos /* follow pointer */
402eaad808eSchristos if(!pkt) {
403eaad808eSchristos fputs("??compressionptr??", out);
404eaad808eSchristos return;
405eaad808eSchristos }
406*561252a2Schristos if((size_t)PTR_OFFSET(lablen, *dname)
407*561252a2Schristos >= sldns_buffer_limit(pkt)) {
408*561252a2Schristos fputs("??compressionptr??", out);
409*561252a2Schristos return;
410*561252a2Schristos }
411*561252a2Schristos if(count++ > MAX_COMPRESS_PTRS) {
412*561252a2Schristos fputs("??compressionptr??", out);
413*561252a2Schristos return;
414*561252a2Schristos }
415eaad808eSchristos dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
416eaad808eSchristos lablen = *dname++;
417eaad808eSchristos continue;
418eaad808eSchristos }
419eaad808eSchristos if(lablen > LDNS_MAX_LABELLEN) {
420eaad808eSchristos fputs("??extendedlabel??", out);
421eaad808eSchristos return;
422eaad808eSchristos }
423eaad808eSchristos while(lablen--)
424eaad808eSchristos fputc((int)*dname++, out);
425eaad808eSchristos fputc('.', out);
426eaad808eSchristos lablen = *dname++;
427eaad808eSchristos }
428eaad808eSchristos }
429eaad808eSchristos
430eaad808eSchristos int
dname_count_labels(uint8_t * dname)431eaad808eSchristos dname_count_labels(uint8_t* dname)
432eaad808eSchristos {
433eaad808eSchristos uint8_t lablen;
434eaad808eSchristos int labs = 1;
435eaad808eSchristos
436eaad808eSchristos lablen = *dname++;
437eaad808eSchristos while(lablen) {
438eaad808eSchristos labs++;
439eaad808eSchristos dname += lablen;
440eaad808eSchristos lablen = *dname++;
441eaad808eSchristos }
442eaad808eSchristos return labs;
443eaad808eSchristos }
444eaad808eSchristos
445eaad808eSchristos int
dname_count_size_labels(uint8_t * dname,size_t * size)446eaad808eSchristos dname_count_size_labels(uint8_t* dname, size_t* size)
447eaad808eSchristos {
448eaad808eSchristos uint8_t lablen;
449eaad808eSchristos int labs = 1;
450eaad808eSchristos size_t sz = 1;
451eaad808eSchristos
452eaad808eSchristos lablen = *dname++;
453eaad808eSchristos while(lablen) {
454eaad808eSchristos labs++;
455eaad808eSchristos sz += lablen+1;
456eaad808eSchristos dname += lablen;
457eaad808eSchristos lablen = *dname++;
458eaad808eSchristos }
459eaad808eSchristos *size = sz;
460eaad808eSchristos return labs;
461eaad808eSchristos }
462eaad808eSchristos
463eaad808eSchristos /**
464eaad808eSchristos * Compare labels in memory, lowercase while comparing.
465eaad808eSchristos * @param p1: label 1
466eaad808eSchristos * @param p2: label 2
467eaad808eSchristos * @param len: number of bytes to compare.
468eaad808eSchristos * @return: 0, -1, +1 comparison result.
469eaad808eSchristos */
470eaad808eSchristos static int
memlowercmp(uint8_t * p1,uint8_t * p2,uint8_t len)471eaad808eSchristos memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
472eaad808eSchristos {
473eaad808eSchristos while(len--) {
474eaad808eSchristos if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) {
475eaad808eSchristos if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2))
476eaad808eSchristos return -1;
477eaad808eSchristos return 1;
478eaad808eSchristos }
479eaad808eSchristos p1++;
480eaad808eSchristos p2++;
481eaad808eSchristos }
482eaad808eSchristos return 0;
483eaad808eSchristos }
484eaad808eSchristos
485eaad808eSchristos int
dname_lab_cmp(uint8_t * d1,int labs1,uint8_t * d2,int labs2,int * mlabs)486eaad808eSchristos dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
487eaad808eSchristos {
488eaad808eSchristos uint8_t len1, len2;
489eaad808eSchristos int atlabel = labs1;
490eaad808eSchristos int lastmlabs;
491eaad808eSchristos int lastdiff = 0;
492eaad808eSchristos /* first skip so that we compare same label. */
493eaad808eSchristos if(labs1 > labs2) {
494eaad808eSchristos while(atlabel > labs2) {
495eaad808eSchristos len1 = *d1++;
496eaad808eSchristos d1 += len1;
497eaad808eSchristos atlabel--;
498eaad808eSchristos }
499eaad808eSchristos log_assert(atlabel == labs2);
500eaad808eSchristos } else if(labs1 < labs2) {
501eaad808eSchristos atlabel = labs2;
502eaad808eSchristos while(atlabel > labs1) {
503eaad808eSchristos len2 = *d2++;
504eaad808eSchristos d2 += len2;
505eaad808eSchristos atlabel--;
506eaad808eSchristos }
507eaad808eSchristos log_assert(atlabel == labs1);
508eaad808eSchristos }
509eaad808eSchristos lastmlabs = atlabel+1;
510eaad808eSchristos /* now at same label in d1 and d2, atlabel */
511eaad808eSchristos /* www.example.com. */
512eaad808eSchristos /* 4 3 2 1 atlabel number */
513eaad808eSchristos /* repeat until at root label (which is always the same) */
514eaad808eSchristos while(atlabel > 1) {
515eaad808eSchristos len1 = *d1++;
516eaad808eSchristos len2 = *d2++;
517eaad808eSchristos if(len1 != len2) {
518eaad808eSchristos log_assert(len1 != 0 && len2 != 0);
519eaad808eSchristos if(len1<len2)
520eaad808eSchristos lastdiff = -1;
521eaad808eSchristos else lastdiff = 1;
522eaad808eSchristos lastmlabs = atlabel;
523eaad808eSchristos d1 += len1;
524eaad808eSchristos d2 += len2;
525eaad808eSchristos } else {
526eaad808eSchristos /* memlowercmp is inlined here; or just like
527eaad808eSchristos * if((c=memlowercmp(d1, d2, len1)) != 0) {
528eaad808eSchristos * lastdiff = c;
529eaad808eSchristos * lastmlabs = atlabel; } apart from d1++,d2++ */
530eaad808eSchristos while(len1) {
531eaad808eSchristos if(*d1 != *d2 && tolower((unsigned char)*d1)
532eaad808eSchristos != tolower((unsigned char)*d2)) {
533eaad808eSchristos if(tolower((unsigned char)*d1) <
534eaad808eSchristos tolower((unsigned char)*d2)) {
535eaad808eSchristos lastdiff = -1;
536eaad808eSchristos lastmlabs = atlabel;
537eaad808eSchristos d1 += len1;
538eaad808eSchristos d2 += len1;
539eaad808eSchristos break;
540eaad808eSchristos }
541eaad808eSchristos lastdiff = 1;
542eaad808eSchristos lastmlabs = atlabel;
543eaad808eSchristos d1 += len1;
544eaad808eSchristos d2 += len1;
545eaad808eSchristos break; /* out of memlowercmp */
546eaad808eSchristos }
547eaad808eSchristos d1++;
548eaad808eSchristos d2++;
549eaad808eSchristos len1--;
550eaad808eSchristos }
551eaad808eSchristos }
552eaad808eSchristos atlabel--;
553eaad808eSchristos }
554eaad808eSchristos /* last difference atlabel number, so number of labels matching,
555eaad808eSchristos * at the right side, is one less. */
556eaad808eSchristos *mlabs = lastmlabs-1;
557eaad808eSchristos if(lastdiff == 0) {
558eaad808eSchristos /* all labels compared were equal, check if one has more
559eaad808eSchristos * labels, so that example.com. > com. */
560eaad808eSchristos if(labs1 > labs2)
561eaad808eSchristos return 1;
562eaad808eSchristos else if(labs1 < labs2)
563eaad808eSchristos return -1;
564eaad808eSchristos }
565eaad808eSchristos return lastdiff;
566eaad808eSchristos }
567eaad808eSchristos
568eaad808eSchristos int
dname_lab_startswith(uint8_t * label,char * prefix,char ** endptr)569d6959bcfSchristos dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
570d6959bcfSchristos {
571d6959bcfSchristos size_t plen = strlen(prefix);
572d6959bcfSchristos size_t orig_plen = plen;
573d6959bcfSchristos size_t lablen = (size_t)*label;
574d6959bcfSchristos if(plen > lablen)
575d6959bcfSchristos return 0;
576d6959bcfSchristos label++;
577d6959bcfSchristos while(plen--) {
578d6959bcfSchristos if(*prefix != tolower((unsigned char)*label)) {
579d6959bcfSchristos return 0;
580d6959bcfSchristos }
581d6959bcfSchristos prefix++; label++;
582d6959bcfSchristos }
583d6959bcfSchristos if(orig_plen < lablen)
584d6959bcfSchristos *endptr = (char *)label;
585d6959bcfSchristos else
586d6959bcfSchristos /* prefix length == label length */
587d6959bcfSchristos *endptr = NULL;
588d6959bcfSchristos return 1;
589d6959bcfSchristos }
590d6959bcfSchristos
591d6959bcfSchristos int
dname_has_label(uint8_t * dname,size_t dnamelen,uint8_t * label)592*561252a2Schristos dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label)
593*561252a2Schristos {
594*561252a2Schristos size_t len;
595*561252a2Schristos
596*561252a2Schristos /* 1 byte needed for the label length */
597*561252a2Schristos if(dnamelen < 1)
598*561252a2Schristos return 0;
599*561252a2Schristos
600*561252a2Schristos len = *dname;
601*561252a2Schristos while(len <= dnamelen) {
602*561252a2Schristos if(!(*dname)) {
603*561252a2Schristos if(*dname == *label)
604*561252a2Schristos return 1; /* empty label match */
605*561252a2Schristos /* termination label found, stop iterating */
606*561252a2Schristos return 0;
607*561252a2Schristos }
608*561252a2Schristos if(*dname == *label && *label &&
609*561252a2Schristos memlowercmp(dname+1, label+1, *dname) == 0)
610*561252a2Schristos return 1;
611*561252a2Schristos len += *dname;
612*561252a2Schristos dname += *dname;
613*561252a2Schristos dname++;
614*561252a2Schristos len++;
615*561252a2Schristos }
616*561252a2Schristos return 0;
617*561252a2Schristos }
618*561252a2Schristos
619*561252a2Schristos int
dname_buffer_write(sldns_buffer * pkt,uint8_t * dname)620eaad808eSchristos dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
621eaad808eSchristos {
622eaad808eSchristos uint8_t lablen;
623eaad808eSchristos
624eaad808eSchristos if(sldns_buffer_remaining(pkt) < 1)
625eaad808eSchristos return 0;
626eaad808eSchristos lablen = *dname++;
627eaad808eSchristos sldns_buffer_write_u8(pkt, lablen);
628eaad808eSchristos while(lablen) {
629eaad808eSchristos if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
630eaad808eSchristos return 0;
631eaad808eSchristos sldns_buffer_write(pkt, dname, lablen);
632eaad808eSchristos dname += lablen;
633eaad808eSchristos lablen = *dname++;
634eaad808eSchristos sldns_buffer_write_u8(pkt, lablen);
635eaad808eSchristos }
636eaad808eSchristos return 1;
637eaad808eSchristos }
638eaad808eSchristos
dname_str(uint8_t * dname,char * str)639eaad808eSchristos void dname_str(uint8_t* dname, char* str)
640eaad808eSchristos {
641eaad808eSchristos size_t len = 0;
642eaad808eSchristos uint8_t lablen = 0;
643eaad808eSchristos char* s = str;
644eaad808eSchristos if(!dname || !*dname) {
645eaad808eSchristos *s++ = '.';
646eaad808eSchristos *s = 0;
647eaad808eSchristos return;
648eaad808eSchristos }
649eaad808eSchristos lablen = *dname++;
650eaad808eSchristos while(lablen) {
651eaad808eSchristos if(lablen > LDNS_MAX_LABELLEN) {
652eaad808eSchristos *s++ = '#';
653eaad808eSchristos *s = 0;
654eaad808eSchristos return;
655eaad808eSchristos }
656eaad808eSchristos len += lablen+1;
657eaad808eSchristos if(len >= LDNS_MAX_DOMAINLEN-1) {
658eaad808eSchristos *s++ = '&';
659eaad808eSchristos *s = 0;
660eaad808eSchristos return;
661eaad808eSchristos }
662eaad808eSchristos while(lablen--) {
663eaad808eSchristos if(isalnum((unsigned char)*dname)
664eaad808eSchristos || *dname == '-' || *dname == '_'
665eaad808eSchristos || *dname == '*')
666eaad808eSchristos *s++ = *(char*)dname++;
667eaad808eSchristos else {
668eaad808eSchristos *s++ = '?';
669eaad808eSchristos dname++;
670eaad808eSchristos }
671eaad808eSchristos }
672eaad808eSchristos *s++ = '.';
673eaad808eSchristos lablen = *dname++;
674eaad808eSchristos }
675eaad808eSchristos *s = 0;
676eaad808eSchristos }
677eaad808eSchristos
678eaad808eSchristos int
dname_strict_subdomain(uint8_t * d1,int labs1,uint8_t * d2,int labs2)679eaad808eSchristos dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
680eaad808eSchristos {
681eaad808eSchristos int m;
682eaad808eSchristos /* check subdomain: d1: www.example.com. and d2: example.com. */
683eaad808eSchristos if(labs2 >= labs1)
684eaad808eSchristos return 0;
685eaad808eSchristos if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
686eaad808eSchristos /* subdomain if all labels match */
687eaad808eSchristos return (m == labs2);
688eaad808eSchristos }
689eaad808eSchristos return 0;
690eaad808eSchristos }
691eaad808eSchristos
692eaad808eSchristos int
dname_strict_subdomain_c(uint8_t * d1,uint8_t * d2)693eaad808eSchristos dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
694eaad808eSchristos {
695eaad808eSchristos return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
696eaad808eSchristos dname_count_labels(d2));
697eaad808eSchristos }
698eaad808eSchristos
699eaad808eSchristos int
dname_subdomain_c(uint8_t * d1,uint8_t * d2)700eaad808eSchristos dname_subdomain_c(uint8_t* d1, uint8_t* d2)
701eaad808eSchristos {
702eaad808eSchristos int m;
703eaad808eSchristos /* check subdomain: d1: www.example.com. and d2: example.com. */
704eaad808eSchristos /* or d1: example.com. and d2: example.com. */
705eaad808eSchristos int labs1 = dname_count_labels(d1);
706eaad808eSchristos int labs2 = dname_count_labels(d2);
707eaad808eSchristos if(labs2 > labs1)
708eaad808eSchristos return 0;
709eaad808eSchristos if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
710eaad808eSchristos /* must have been example.com , www.example.com - wrong */
711eaad808eSchristos /* or otherwise different dnames */
712eaad808eSchristos return 0;
713eaad808eSchristos }
714eaad808eSchristos return (m == labs2);
715eaad808eSchristos }
716eaad808eSchristos
717eaad808eSchristos int
dname_is_root(uint8_t * dname)718eaad808eSchristos dname_is_root(uint8_t* dname)
719eaad808eSchristos {
720eaad808eSchristos uint8_t len;
721eaad808eSchristos log_assert(dname);
722eaad808eSchristos len = dname[0];
723eaad808eSchristos log_assert(!LABEL_IS_PTR(len));
724eaad808eSchristos return (len == 0);
725eaad808eSchristos }
726eaad808eSchristos
727eaad808eSchristos void
dname_remove_label(uint8_t ** dname,size_t * len)728eaad808eSchristos dname_remove_label(uint8_t** dname, size_t* len)
729eaad808eSchristos {
730eaad808eSchristos size_t lablen;
731eaad808eSchristos log_assert(dname && *dname && len);
732eaad808eSchristos lablen = (*dname)[0];
733eaad808eSchristos log_assert(!LABEL_IS_PTR(lablen));
734eaad808eSchristos log_assert(*len > lablen);
735eaad808eSchristos if(lablen == 0)
736eaad808eSchristos return; /* do not modify root label */
737eaad808eSchristos *len -= lablen+1;
738eaad808eSchristos *dname += lablen+1;
739eaad808eSchristos }
740eaad808eSchristos
741eaad808eSchristos void
dname_remove_labels(uint8_t ** dname,size_t * len,int n)742eaad808eSchristos dname_remove_labels(uint8_t** dname, size_t* len, int n)
743eaad808eSchristos {
744eaad808eSchristos int i;
745eaad808eSchristos for(i=0; i<n; i++)
746eaad808eSchristos dname_remove_label(dname, len);
747eaad808eSchristos }
748eaad808eSchristos
749eaad808eSchristos int
dname_signame_label_count(uint8_t * dname)750eaad808eSchristos dname_signame_label_count(uint8_t* dname)
751eaad808eSchristos {
752eaad808eSchristos uint8_t lablen;
753eaad808eSchristos int count = 0;
754eaad808eSchristos if(!*dname)
755eaad808eSchristos return 0;
756eaad808eSchristos if(dname[0] == 1 && dname[1] == '*')
757eaad808eSchristos dname += 2;
758eaad808eSchristos lablen = dname[0];
759eaad808eSchristos while(lablen) {
760eaad808eSchristos count++;
761eaad808eSchristos dname += lablen;
762eaad808eSchristos dname += 1;
763eaad808eSchristos lablen = dname[0];
764eaad808eSchristos }
765eaad808eSchristos return count;
766eaad808eSchristos }
767eaad808eSchristos
768eaad808eSchristos int
dname_is_wild(uint8_t * dname)769eaad808eSchristos dname_is_wild(uint8_t* dname)
770eaad808eSchristos {
771eaad808eSchristos return (dname[0] == 1 && dname[1] == '*');
772eaad808eSchristos }
773eaad808eSchristos
774eaad808eSchristos /**
775eaad808eSchristos * Compare labels in memory, lowercase while comparing.
776eaad808eSchristos * Returns canonical order for labels. If all is equal, the
777eaad808eSchristos * shortest is first.
778eaad808eSchristos *
779eaad808eSchristos * @param p1: label 1
780eaad808eSchristos * @param len1: length of label 1.
781eaad808eSchristos * @param p2: label 2
782eaad808eSchristos * @param len2: length of label 2.
783eaad808eSchristos * @return: 0, -1, +1 comparison result.
784eaad808eSchristos */
785eaad808eSchristos static int
memcanoncmp(uint8_t * p1,uint8_t len1,uint8_t * p2,uint8_t len2)786eaad808eSchristos memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
787eaad808eSchristos {
788eaad808eSchristos uint8_t min = (len1<len2)?len1:len2;
789eaad808eSchristos int c = memlowercmp(p1, p2, min);
790eaad808eSchristos if(c != 0)
791eaad808eSchristos return c;
792eaad808eSchristos /* equal, see who is shortest */
793eaad808eSchristos if(len1 < len2)
794eaad808eSchristos return -1;
795eaad808eSchristos if(len1 > len2)
796eaad808eSchristos return 1;
797eaad808eSchristos return 0;
798eaad808eSchristos }
799eaad808eSchristos
800eaad808eSchristos
801eaad808eSchristos int
dname_canon_lab_cmp(uint8_t * d1,int labs1,uint8_t * d2,int labs2,int * mlabs)802eaad808eSchristos dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
803eaad808eSchristos {
804eaad808eSchristos /* like dname_lab_cmp, but with different label comparison,
805eaad808eSchristos * empty character sorts before \000.
806eaad808eSchristos * So ylyly is before z. */
807eaad808eSchristos uint8_t len1, len2;
808eaad808eSchristos int atlabel = labs1;
809eaad808eSchristos int lastmlabs;
810eaad808eSchristos int lastdiff = 0;
811eaad808eSchristos int c;
812eaad808eSchristos /* first skip so that we compare same label. */
813eaad808eSchristos if(labs1 > labs2) {
814eaad808eSchristos while(atlabel > labs2) {
815eaad808eSchristos len1 = *d1++;
816eaad808eSchristos d1 += len1;
817eaad808eSchristos atlabel--;
818eaad808eSchristos }
819eaad808eSchristos log_assert(atlabel == labs2);
820eaad808eSchristos } else if(labs1 < labs2) {
821eaad808eSchristos atlabel = labs2;
822eaad808eSchristos while(atlabel > labs1) {
823eaad808eSchristos len2 = *d2++;
824eaad808eSchristos d2 += len2;
825eaad808eSchristos atlabel--;
826eaad808eSchristos }
827eaad808eSchristos log_assert(atlabel == labs1);
828eaad808eSchristos }
829eaad808eSchristos lastmlabs = atlabel+1;
830eaad808eSchristos /* now at same label in d1 and d2, atlabel */
831eaad808eSchristos /* www.example.com. */
832eaad808eSchristos /* 4 3 2 1 atlabel number */
833eaad808eSchristos /* repeat until at root label (which is always the same) */
834eaad808eSchristos while(atlabel > 1) {
835eaad808eSchristos len1 = *d1++;
836eaad808eSchristos len2 = *d2++;
837eaad808eSchristos
838eaad808eSchristos if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
839eaad808eSchristos if(c<0)
840eaad808eSchristos lastdiff = -1;
841eaad808eSchristos else lastdiff = 1;
842eaad808eSchristos lastmlabs = atlabel;
843eaad808eSchristos }
844eaad808eSchristos
845eaad808eSchristos d1 += len1;
846eaad808eSchristos d2 += len2;
847eaad808eSchristos atlabel--;
848eaad808eSchristos }
849eaad808eSchristos /* last difference atlabel number, so number of labels matching,
850eaad808eSchristos * at the right side, is one less. */
851eaad808eSchristos *mlabs = lastmlabs-1;
852eaad808eSchristos if(lastdiff == 0) {
853eaad808eSchristos /* all labels compared were equal, check if one has more
854eaad808eSchristos * labels, so that example.com. > com. */
855eaad808eSchristos if(labs1 > labs2)
856eaad808eSchristos return 1;
857eaad808eSchristos else if(labs1 < labs2)
858eaad808eSchristos return -1;
859eaad808eSchristos }
860eaad808eSchristos return lastdiff;
861eaad808eSchristos }
862eaad808eSchristos
863eaad808eSchristos int
dname_canonical_compare(uint8_t * d1,uint8_t * d2)864eaad808eSchristos dname_canonical_compare(uint8_t* d1, uint8_t* d2)
865eaad808eSchristos {
866eaad808eSchristos int labs1, labs2, m;
867eaad808eSchristos labs1 = dname_count_labels(d1);
868eaad808eSchristos labs2 = dname_count_labels(d2);
869eaad808eSchristos return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
870eaad808eSchristos }
871eaad808eSchristos
dname_get_shared_topdomain(uint8_t * d1,uint8_t * d2)872eaad808eSchristos uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
873eaad808eSchristos {
874eaad808eSchristos int labs1, labs2, m;
875eaad808eSchristos size_t len = LDNS_MAX_DOMAINLEN;
876eaad808eSchristos labs1 = dname_count_labels(d1);
877eaad808eSchristos labs2 = dname_count_labels(d2);
878eaad808eSchristos (void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
879eaad808eSchristos dname_remove_labels(&d1, &len, labs1-m);
880eaad808eSchristos return d1;
881eaad808eSchristos }
882