1 /*
2 * dname.c -- Domain name handling.
3 *
4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5 *
6 * See LICENSE for the license.
7 *
8 */
9
10
11 #include "config.h"
12
13 #include <sys/types.h>
14
15 #include <assert.h>
16 #include <ctype.h>
17 #include <limits.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #include "dns.h"
22 #include "dname.h"
23 #include "query.h"
24
25 const dname_type *
dname_make(region_type * region,const uint8_t * name,int normalize)26 dname_make(region_type *region, const uint8_t *name, int normalize)
27 {
28 size_t name_size = 0;
29 uint8_t label_offsets[MAXDOMAINLEN];
30 uint8_t label_count = 0;
31 const uint8_t *label = name;
32 dname_type *result;
33 ssize_t i;
34
35 assert(name);
36
37 while (1) {
38 if (label_is_pointer(label))
39 return NULL;
40
41 label_offsets[label_count] = (uint8_t) (label - name);
42 ++label_count;
43 name_size += label_length(label) + 1;
44
45 if (label_is_root(label))
46 break;
47
48 label = label_next(label);
49 }
50
51 if (name_size > MAXDOMAINLEN)
52 return NULL;
53
54 assert(label_count <= MAXDOMAINLEN / 2 + 1);
55
56 /* Reverse label offsets. */
57 for (i = 0; i < label_count / 2; ++i) {
58 uint8_t tmp = label_offsets[i];
59 label_offsets[i] = label_offsets[label_count - i - 1];
60 label_offsets[label_count - i - 1] = tmp;
61 }
62
63 result = (dname_type *) region_alloc(
64 region,
65 (sizeof(dname_type)
66 + (((size_t)label_count) + ((size_t)name_size)) * sizeof(uint8_t)));
67 result->name_size = name_size;
68 result->label_count = label_count;
69 memcpy((uint8_t *) dname_label_offsets(result),
70 label_offsets,
71 label_count * sizeof(uint8_t));
72 if (normalize) {
73 uint8_t *dst = (uint8_t *) dname_name(result);
74 const uint8_t *src = name;
75 while (!label_is_root(src)) {
76 ssize_t len = label_length(src);
77 *dst++ = *src++;
78 for (i = 0; i < len; ++i) {
79 *dst++ = DNAME_NORMALIZE((unsigned char)*src++);
80 }
81 }
82 *dst = *src;
83 } else {
84 memcpy((uint8_t *) dname_name(result),
85 name,
86 name_size * sizeof(uint8_t));
87 }
88 return result;
89 }
90
91
92 const dname_type *
dname_make_from_packet(region_type * region,buffer_type * packet,int allow_pointers,int normalize)93 dname_make_from_packet(region_type *region, buffer_type *packet,
94 int allow_pointers, int normalize)
95 {
96 uint8_t buf[MAXDOMAINLEN + 1];
97 if(!dname_make_wire_from_packet(buf, packet, allow_pointers))
98 return 0;
99 return dname_make(region, buf, normalize);
100 }
101
102 int
dname_make_wire_from_packet(uint8_t * buf,buffer_type * packet,int allow_pointers)103 dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet,
104 int allow_pointers)
105 {
106 int done = 0;
107 uint8_t visited[(MAX_PACKET_SIZE+7)/8];
108 size_t dname_length = 0;
109 const uint8_t *label;
110 ssize_t mark = -1;
111
112 if(sizeof(visited)<(buffer_limit(packet)+7)/8)
113 memset(visited, 0, sizeof(visited));
114 else memset(visited, 0, (buffer_limit(packet)+7)/8);
115
116 while (!done) {
117 if (!buffer_available(packet, 1)) {
118 /* error("dname out of bounds"); */
119 return 0;
120 }
121
122 if (get_bit(visited, buffer_position(packet))) {
123 /* error("dname loops"); */
124 return 0;
125 }
126 set_bit(visited, buffer_position(packet));
127
128 label = buffer_current(packet);
129 if (label_is_pointer(label)) {
130 size_t pointer;
131 if (!allow_pointers) {
132 return 0;
133 }
134 if (!buffer_available(packet, 2)) {
135 /* error("dname pointer out of bounds"); */
136 return 0;
137 }
138 pointer = label_pointer_location(label);
139 if (pointer >= buffer_limit(packet)) {
140 /* error("dname pointer points outside packet"); */
141 return 0;
142 }
143 buffer_skip(packet, 2);
144 if (mark == -1) {
145 mark = buffer_position(packet);
146 }
147 buffer_set_position(packet, pointer);
148 } else if (label_is_normal(label)) {
149 size_t length = label_length(label) + 1;
150 done = label_is_root(label);
151 if (!buffer_available(packet, length)) {
152 /* error("dname label out of bounds"); */
153 return 0;
154 }
155 if (dname_length + length >= MAXDOMAINLEN+1) {
156 /* error("dname too large"); */
157 return 0;
158 }
159 buffer_read(packet, buf + dname_length, length);
160 dname_length += length;
161 } else {
162 /* error("bad label type"); */
163 return 0;
164 }
165 }
166
167 if (mark != -1) {
168 buffer_set_position(packet, mark);
169 }
170
171 return dname_length;
172 }
173
174 const dname_type *
dname_parse(region_type * region,const char * name)175 dname_parse(region_type *region, const char *name)
176 {
177 uint8_t dname[MAXDOMAINLEN];
178 if(!dname_parse_wire(dname, name))
179 return 0;
180 return dname_make(region, dname, 1);
181 }
182
dname_parse_wire(uint8_t * dname,const char * name)183 int dname_parse_wire(uint8_t* dname, const char* name)
184 {
185 const uint8_t *s = (const uint8_t *) name;
186 uint8_t *h;
187 uint8_t *p;
188 uint8_t *d = dname;
189 size_t label_length;
190
191 if (strcmp(name, ".") == 0) {
192 /* Root domain. */
193 dname[0] = 0;
194 return 1;
195 }
196
197 for (h = d, p = h + 1; *s; ++s, ++p) {
198 if (p - dname >= MAXDOMAINLEN) {
199 return 0;
200 }
201
202 switch (*s) {
203 case '.':
204 if (p == h + 1) {
205 /* Empty label. */
206 return 0;
207 } else {
208 label_length = p - h - 1;
209 if (label_length > MAXLABELLEN) {
210 return 0;
211 }
212 *h = label_length;
213 h = p;
214 }
215 break;
216 case '\\':
217 /* Handle escaped characters (RFC1035 5.1) */
218 if (isdigit((unsigned char)s[1]) && isdigit((unsigned char)s[2]) && isdigit((unsigned char)s[3])) {
219 int val = (hexdigit_to_int(s[1]) * 100 +
220 hexdigit_to_int(s[2]) * 10 +
221 hexdigit_to_int(s[3]));
222 if (0 <= val && val <= 255) {
223 s += 3;
224 *p = val;
225 } else {
226 *p = *++s;
227 }
228 } else if (s[1] != '\0') {
229 *p = *++s;
230 }
231 break;
232 default:
233 *p = *s;
234 break;
235 }
236 }
237
238 if (p != h + 1) {
239 /* Terminate last label. */
240 label_length = p - h - 1;
241 if (label_length > MAXLABELLEN) {
242 return 0;
243 }
244 *h = label_length;
245 h = p;
246 p++;
247 }
248
249 /* Add root label. */
250 if (h - dname >= MAXDOMAINLEN) {
251 return 0;
252 }
253 *h = 0;
254
255 return p-dname;
256 }
257
258
259 const dname_type *
dname_copy(region_type * region,const dname_type * dname)260 dname_copy(region_type *region, const dname_type *dname)
261 {
262 return (dname_type *) region_alloc_init(
263 region, dname, dname_total_size(dname));
264 }
265
266
267 const dname_type *
dname_partial_copy(region_type * region,const dname_type * dname,uint8_t label_count)268 dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count)
269 {
270 if (!dname)
271 return NULL;
272
273 if (label_count == 0) {
274 /* Always copy the root label. */
275 label_count = 1;
276 }
277
278 assert(label_count <= dname->label_count);
279
280 return dname_make(region, dname_label(dname, label_count - 1), 0);
281 }
282
283
284 const dname_type *
dname_origin(region_type * region,const dname_type * dname)285 dname_origin(region_type *region, const dname_type *dname)
286 {
287 return dname_partial_copy(region, dname, dname->label_count - 1);
288 }
289
290
291 int
dname_is_subdomain(const dname_type * left,const dname_type * right)292 dname_is_subdomain(const dname_type *left, const dname_type *right)
293 {
294 uint8_t i;
295
296 if (left->label_count < right->label_count)
297 return 0;
298
299 for (i = 1; i < right->label_count; ++i) {
300 if (label_compare(dname_label(left, i),
301 dname_label(right, i)) != 0)
302 return 0;
303 }
304
305 return 1;
306 }
307
308
309 int
dname_compare(const dname_type * left,const dname_type * right)310 dname_compare(const dname_type *left, const dname_type *right)
311 {
312 int result;
313 uint8_t label_count;
314 uint8_t i;
315
316 assert(left);
317 assert(right);
318
319 if (left == right) {
320 return 0;
321 }
322
323 label_count = (left->label_count <= right->label_count
324 ? left->label_count
325 : right->label_count);
326
327 /* Skip the root label by starting at label 1. */
328 for (i = 1; i < label_count; ++i) {
329 result = label_compare(dname_label(left, i),
330 dname_label(right, i));
331 if (result) {
332 return result;
333 }
334 }
335
336 /* Dname with the fewest labels is "first". */
337 /* the subtraction works because the size of int is much larger than
338 * the label count and the values won't wrap around */
339 return (int) left->label_count - (int) right->label_count;
340 }
341
342
343 int
label_compare(const uint8_t * left,const uint8_t * right)344 label_compare(const uint8_t *left, const uint8_t *right)
345 {
346 int left_length;
347 int right_length;
348 size_t size;
349 int result;
350
351 assert(left);
352 assert(right);
353
354 assert(label_is_normal(left));
355 assert(label_is_normal(right));
356
357 left_length = label_length(left);
358 right_length = label_length(right);
359 size = left_length < right_length ? left_length : right_length;
360
361 result = memcmp(label_data(left), label_data(right), size);
362 if (result) {
363 return result;
364 } else {
365 /* the subtraction works because the size of int is much
366 * larger than the lengths and the values won't wrap around */
367 return (int) left_length - (int) right_length;
368 }
369 }
370
371
372 uint8_t
dname_label_match_count(const dname_type * left,const dname_type * right)373 dname_label_match_count(const dname_type *left, const dname_type *right)
374 {
375 uint8_t i;
376
377 assert(left);
378 assert(right);
379
380 for (i = 1; i < left->label_count && i < right->label_count; ++i) {
381 if (label_compare(dname_label(left, i),
382 dname_label(right, i)) != 0)
383 {
384 return i;
385 }
386 }
387
388 return i;
389 }
390
391 const char *
dname_to_string(const dname_type * dname,const dname_type * origin)392 dname_to_string(const dname_type *dname, const dname_type *origin)
393 {
394 static char buf[MAXDOMAINLEN * 5];
395 size_t i;
396 size_t labels_to_convert = dname->label_count - 1;
397 int absolute = 1;
398 char *dst;
399 const uint8_t *src;
400
401 if (dname->label_count == 1) {
402 strlcpy(buf, ".", sizeof(buf));
403 return buf;
404 }
405
406 if (origin && dname_is_subdomain(dname, origin)) {
407 int common_labels = dname_label_match_count(dname, origin);
408 labels_to_convert = dname->label_count - common_labels;
409 absolute = 0;
410 }
411
412 dst = buf;
413 src = dname_name(dname);
414 for (i = 0; i < labels_to_convert; ++i) {
415 size_t len = label_length(src);
416 size_t j;
417 ++src;
418 for (j = 0; j < len; ++j) {
419 uint8_t ch = *src++;
420 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
421 *dst++ = ch;
422 } else if (ch == '.' || ch == '\\') {
423 *dst++ = '\\';
424 *dst++ = ch;
425 } else {
426 snprintf(dst, 5, "\\%03u", (unsigned int)ch);
427 dst += 4;
428 }
429 }
430 *dst++ = '.';
431 }
432 if (absolute) {
433 *dst = '\0';
434 } else {
435 *--dst = '\0';
436 }
437 return buf;
438 }
439
440
441 const dname_type *
dname_make_from_label(region_type * region,const uint8_t * label,const size_t length)442 dname_make_from_label(region_type *region,
443 const uint8_t *label, const size_t length)
444 {
445 uint8_t temp[MAXLABELLEN + 2];
446
447 assert(length > 0 && length <= MAXLABELLEN);
448
449 temp[0] = length;
450 memcpy(temp + 1, label, length * sizeof(uint8_t));
451 temp[length + 1] = '\000';
452
453 return dname_make(region, temp, 1);
454 }
455
456
457 const dname_type *
dname_concatenate(region_type * region,const dname_type * left,const dname_type * right)458 dname_concatenate(region_type *region,
459 const dname_type *left,
460 const dname_type *right)
461 {
462 uint8_t temp[MAXDOMAINLEN];
463
464 assert(left->name_size + right->name_size - 1 <= MAXDOMAINLEN);
465
466 memcpy(temp, dname_name(left), left->name_size - 1);
467 memcpy(temp + left->name_size - 1, dname_name(right), right->name_size);
468
469 return dname_make(region, temp, 0);
470 }
471
472
473 const dname_type *
dname_replace(region_type * region,const dname_type * name,const dname_type * src,const dname_type * dest)474 dname_replace(region_type* region,
475 const dname_type* name,
476 const dname_type* src,
477 const dname_type* dest)
478 {
479 /* nomenclature: name is said to be <x>.<src>. x can be null. */
480 dname_type* res;
481 int x_labels = name->label_count - src->label_count;
482 int x_len = name->name_size - src->name_size;
483 int i;
484 assert(dname_is_subdomain(name, src));
485
486 /* check if final size is acceptable */
487 if(x_len+dest->name_size > MAXDOMAINLEN)
488 return NULL;
489
490 res = (dname_type*)region_alloc(region, sizeof(dname_type) +
491 (x_labels+((int)dest->label_count) + x_len+((int)dest->name_size))
492 *sizeof(uint8_t));
493 res->name_size = x_len+dest->name_size;
494 res->label_count = x_labels+dest->label_count;
495 for(i=0; i<dest->label_count; i++)
496 ((uint8_t*)dname_label_offsets(res))[i] =
497 dname_label_offsets(dest)[i] + x_len;
498 for(i=dest->label_count; i<res->label_count; i++)
499 ((uint8_t*)dname_label_offsets(res))[i] =
500 dname_label_offsets(name)[i - dest->label_count +
501 src->label_count];
502 memcpy((uint8_t*)dname_name(res), dname_name(name), x_len);
503 memcpy((uint8_t*)dname_name(res)+x_len, dname_name(dest), dest->name_size);
504 assert(dname_is_subdomain(res, dest));
505 return res;
506 }
507
wirelabel2str(const uint8_t * label)508 char* wirelabel2str(const uint8_t* label)
509 {
510 static char buf[MAXDOMAINLEN*5+3];
511 char* p = buf;
512 uint8_t lablen;
513 lablen = *label++;
514 while(lablen--) {
515 uint8_t ch = *label++;
516 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
517 *p++ = ch;
518 } else if (ch == '.' || ch == '\\') {
519 *p++ = '\\';
520 *p++ = ch;
521 } else {
522 snprintf(p, 5, "\\%03u", (unsigned int)ch);
523 p += 4;
524 }
525 }
526 *p++ = 0;
527 return buf;
528 }
529
wiredname2str(const uint8_t * dname)530 char* wiredname2str(const uint8_t* dname)
531 {
532 static char buf[MAXDOMAINLEN*5+3];
533 char* p = buf;
534 uint8_t lablen;
535 if(*dname == 0) {
536 strlcpy(buf, ".", sizeof(buf));
537 return buf;
538 }
539 lablen = *dname++;
540 while(lablen) {
541 while(lablen--) {
542 uint8_t ch = *dname++;
543 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
544 *p++ = ch;
545 } else if (ch == '.' || ch == '\\') {
546 *p++ = '\\';
547 *p++ = ch;
548 } else {
549 snprintf(p, 5, "\\%03u", (unsigned int)ch);
550 p += 4;
551 }
552 }
553 lablen = *dname++;
554 *p++ = '.';
555 }
556 *p++ = 0;
557 return buf;
558 }
559
dname_equal_nocase(uint8_t * a,uint8_t * b,uint16_t len)560 int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len)
561 {
562 uint8_t i, lablen;
563 while(len > 0) {
564 /* check labellen */
565 if(*a != *b)
566 return 0;
567 lablen = *a++;
568 b++;
569 len--;
570 /* malformed or compression ptr; we stop scanning */
571 if((lablen & 0xc0) || len < lablen)
572 return (memcmp(a, b, len) == 0);
573 /* check the label, lowercased */
574 for(i=0; i<lablen; i++) {
575 if(DNAME_NORMALIZE((unsigned char)*a++) != DNAME_NORMALIZE((unsigned char)*b++))
576 return 0;
577 }
578 len -= lablen;
579 }
580 return 1;
581 }
582