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