Home | History | Annotate | Line # | Download | only in dist
      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 *
     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/2+1];
     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_normal(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 (name_size > MAXDOMAINLEN)
     46 			return NULL;
     47 		if (label_is_root(label))
     48 			break;
     49 
     50 		label = label_next(label);
     51 	}
     52 
     53 	assert(label_count <= MAXDOMAINLEN / 2 + 1);
     54 
     55 	/* Reverse label offsets.  */
     56 	for (i = 0; i < label_count / 2; ++i) {
     57 		uint8_t tmp = label_offsets[i];
     58 		label_offsets[i] = label_offsets[label_count - i - 1];
     59 		label_offsets[label_count - i - 1] = tmp;
     60 	}
     61 
     62 	result = (dname_type *) region_alloc(
     63 		region,
     64 		(sizeof(dname_type)
     65 		 + (((size_t)label_count) + ((size_t)name_size)) * sizeof(uint8_t)));
     66 	result->name_size = name_size;
     67 	result->label_count = label_count;
     68 	memcpy((uint8_t *) dname_label_offsets(result),
     69 	       label_offsets,
     70 	       label_count * sizeof(uint8_t));
     71 	if (normalize) {
     72 		uint8_t *dst = (uint8_t *) dname_name(result);
     73 		const uint8_t *src = name;
     74 		while (!label_is_root(src)) {
     75 			ssize_t len = label_length(src);
     76 			*dst++ = *src++;
     77 			for (i = 0; i < len; ++i) {
     78 				*dst++ = DNAME_NORMALIZE((unsigned char)*src++);
     79 			}
     80 		}
     81 		*dst = *src;
     82 	} else {
     83 		memcpy((uint8_t *) dname_name(result),
     84 		       name,
     85 		       name_size * sizeof(uint8_t));
     86 	}
     87 	return result;
     88 }
     89 
     90 
     91 const dname_type *
     92 dname_make_from_packet(region_type *region, buffer_type *packet,
     93 		       int allow_pointers, int normalize)
     94 {
     95 	uint8_t buf[MAXDOMAINLEN + 1];
     96 	if(!dname_make_wire_from_packet(buf, packet, allow_pointers))
     97 		return 0;
     98 	return dname_make(region, buf, normalize);
     99 }
    100 
    101 int
    102 dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet,
    103                        int allow_pointers)
    104 {
    105 	int done = 0;
    106 	uint8_t visited[(MAX_PACKET_SIZE+7)/8];
    107 	size_t dname_length = 0;
    108 	const uint8_t *label;
    109 	ssize_t mark = -1;
    110 
    111 	if(sizeof(visited)<(buffer_limit(packet)+7)/8)
    112 		memset(visited, 0, sizeof(visited));
    113 	else	memset(visited, 0, (buffer_limit(packet)+7)/8);
    114 
    115 	while (!done) {
    116 		if (!buffer_available(packet, 1)) {
    117 /* 			error("dname out of bounds"); */
    118 			return 0;
    119 		}
    120 
    121 		if (get_bit(visited, buffer_position(packet))) {
    122 /* 			error("dname loops"); */
    123 			return 0;
    124 		}
    125 		set_bit(visited, buffer_position(packet));
    126 
    127 		label = buffer_current(packet);
    128 		if (label_is_pointer(label)) {
    129 			size_t pointer;
    130 			if (!allow_pointers) {
    131 				return 0;
    132 			}
    133 			if (!buffer_available(packet, 2)) {
    134 /* 				error("dname pointer out of bounds"); */
    135 				return 0;
    136 			}
    137 			pointer = label_pointer_location(label);
    138 			if (pointer >= buffer_limit(packet)) {
    139 /* 				error("dname pointer points outside packet"); */
    140 				return 0;
    141 			}
    142 			buffer_skip(packet, 2);
    143 			if (mark == -1) {
    144 				mark = buffer_position(packet);
    145 			}
    146 			buffer_set_position(packet, pointer);
    147 		} else if (label_is_normal(label)) {
    148 			size_t length = label_length(label) + 1;
    149 			done = label_is_root(label);
    150 			if (!buffer_available(packet, length)) {
    151 /* 				error("dname label out of bounds"); */
    152 				return 0;
    153 			}
    154 			if (dname_length + length >= MAXDOMAINLEN+1) {
    155 /* 				error("dname too large"); */
    156 				return 0;
    157 			}
    158 			buffer_read(packet, buf + dname_length, length);
    159 			dname_length += length;
    160 		} else {
    161 /* 			error("bad label type"); */
    162 			return 0;
    163 		}
    164 	}
    165 
    166 	if (mark != -1) {
    167 		buffer_set_position(packet, mark);
    168 	}
    169 
    170 	return dname_length;
    171 }
    172 
    173 const dname_type *
    174 dname_parse(region_type *region, const char *name)
    175 {
    176 	uint8_t dname[MAXDOMAINLEN];
    177 	if(!dname_parse_wire(dname, name))
    178 		return 0;
    179 	return dname_make(region, dname, 1);
    180 }
    181 
    182 int dname_parse_wire(uint8_t* dname, const char* name)
    183 {
    184 	const uint8_t *s = (const uint8_t *) name;
    185 	uint8_t *h;
    186 	uint8_t *p;
    187 	uint8_t *d = dname;
    188 	size_t label_length;
    189 
    190 	if (strcmp(name, ".") == 0) {
    191 		/* Root domain.  */
    192 		dname[0] = 0;
    193 		return 1;
    194 	}
    195 
    196 	for (h = d, p = h + 1; *s; ++s, ++p) {
    197 		if (p - dname >= MAXDOMAINLEN) {
    198 			return 0;
    199 		}
    200 
    201 		switch (*s) {
    202 		case '.':
    203 			if (p == h + 1) {
    204 				/* Empty label.  */
    205 				return 0;
    206 			} else {
    207 				label_length = p - h - 1;
    208 				if (label_length > MAXLABELLEN) {
    209 					return 0;
    210 				}
    211 				*h = label_length;
    212 				h = p;
    213 			}
    214 			break;
    215 		case '\\':
    216 			/* Handle escaped characters (RFC1035 5.1) */
    217 			if (isdigit((unsigned char)s[1]) && isdigit((unsigned char)s[2]) && isdigit((unsigned char)s[3])) {
    218 				int val = (hexdigit_to_int(s[1]) * 100 +
    219 					   hexdigit_to_int(s[2]) * 10 +
    220 					   hexdigit_to_int(s[3]));
    221 				if (0 <= val && val <= 255) {
    222 					s += 3;
    223 					*p = val;
    224 				} else {
    225 					*p = *++s;
    226 				}
    227 			} else if (s[1] != '\0') {
    228 				*p = *++s;
    229 			}
    230 			break;
    231 		default:
    232 			*p = *s;
    233 			break;
    234 		}
    235 	}
    236 
    237 	if (p != h + 1) {
    238 		/* Terminate last label.  */
    239 		label_length = p - h - 1;
    240 		if (label_length > MAXLABELLEN) {
    241 			return 0;
    242 		}
    243 		*h = label_length;
    244 		h = p;
    245 		p++;
    246 	}
    247 
    248 	/* Add root label.  */
    249 	if (h - dname >= MAXDOMAINLEN) {
    250 		return 0;
    251 	}
    252 	*h = 0;
    253 
    254 	return p-dname;
    255 }
    256 
    257 
    258 const dname_type *
    259 dname_copy(region_type *region, const dname_type *dname)
    260 {
    261 	return (dname_type *) region_alloc_init(
    262 		region, dname, dname_total_size(dname));
    263 }
    264 
    265 
    266 const dname_type *
    267 dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count)
    268 {
    269 	if (!dname)
    270 		return NULL;
    271 
    272 	if (label_count == 0) {
    273 		/* Always copy the root label.  */
    274 		label_count = 1;
    275 	}
    276 
    277 	assert(label_count <= dname->label_count);
    278 
    279 	return dname_make(region, dname_label(dname, label_count - 1), 0);
    280 }
    281 
    282 
    283 const dname_type *
    284 dname_origin(region_type *region, const dname_type *dname)
    285 {
    286 	return dname_partial_copy(region, dname, dname->label_count - 1);
    287 }
    288 
    289 
    290 int
    291 dname_is_subdomain(const dname_type *left, const dname_type *right)
    292 {
    293 	uint8_t i;
    294 
    295 	if (left->label_count < right->label_count)
    296 		return 0;
    297 
    298 	for (i = 1; i < right->label_count; ++i) {
    299 		if (label_compare(dname_label(left, i),
    300 				  dname_label(right, i)) != 0)
    301 			return 0;
    302 	}
    303 
    304 	return 1;
    305 }
    306 
    307 
    308 int
    309 dname_compare(const void *a, const void *b)
    310 {
    311 	int result;
    312 	uint8_t label_count;
    313 	uint8_t i;
    314 	const dname_type *left, *right;
    315 
    316 	left = a;
    317 	right = b;
    318 
    319 	assert(left);
    320 	assert(right);
    321 
    322 	if (left == right) {
    323 		return 0;
    324 	}
    325 
    326 	label_count = (left->label_count <= right->label_count
    327 		       ? left->label_count
    328 		       : right->label_count);
    329 
    330 	/* Skip the root label by starting at label 1.  */
    331 	for (i = 1; i < label_count; ++i) {
    332 		result = label_compare(dname_label(left, i),
    333 				       dname_label(right, i));
    334 		if (result) {
    335 			return result;
    336 		}
    337 	}
    338 
    339 	/* Dname with the fewest labels is "first".  */
    340 	/* the subtraction works because the size of int is much larger than
    341 	 * the label count and the values won't wrap around */
    342 	return (int) left->label_count - (int) right->label_count;
    343 }
    344 
    345 
    346 int
    347 label_compare(const uint8_t *left, const uint8_t *right)
    348 {
    349 	int left_length;
    350 	int right_length;
    351 	size_t size;
    352 	int result;
    353 
    354 	assert(left);
    355 	assert(right);
    356 
    357 	assert(label_is_normal(left));
    358 	assert(label_is_normal(right));
    359 
    360 	left_length = label_length(left);
    361 	right_length = label_length(right);
    362 	size = left_length < right_length ? left_length : right_length;
    363 
    364 	result = memcmp(label_data(left), label_data(right), size);
    365 	if (result) {
    366 		return result;
    367 	} else {
    368 		/* the subtraction works because the size of int is much
    369 		 * larger than the lengths and the values won't wrap around */
    370 		return (int) left_length - (int) right_length;
    371 	}
    372 }
    373 
    374 
    375 uint8_t
    376 dname_label_match_count(const dname_type *left, const dname_type *right)
    377 {
    378 	uint8_t i;
    379 
    380 	assert(left);
    381 	assert(right);
    382 
    383 	for (i = 1; i < left->label_count && i < right->label_count; ++i) {
    384 		if (label_compare(dname_label(left, i),
    385 				  dname_label(right, i)) != 0)
    386 		{
    387 			return i;
    388 		}
    389 	}
    390 
    391 	return i;
    392 }
    393 
    394 const char *
    395 dname_to_string(const dname_type *dname, const dname_type *origin)
    396 {
    397 	static char buf[MAXDOMAINLEN * 5];
    398 	return dname_to_string_buf(dname, origin, buf);
    399 }
    400 
    401 const char *
    402 dname_to_string_buf(const dname_type *dname, const dname_type *origin, char buf[MAXDOMAINLEN * 5])
    403 {
    404 	size_t i;
    405 	size_t labels_to_convert = dname->label_count - 1;
    406 	int absolute = 1;
    407 	char *dst;
    408 	const uint8_t *src;
    409 
    410 	if (dname->label_count == 1) {
    411 		strlcpy(buf, ".", MAXDOMAINLEN * 5);
    412 		return buf;
    413 	}
    414 
    415 	if (origin && dname_is_subdomain(dname, origin)) {
    416 		int common_labels = dname_label_match_count(dname, origin);
    417 		labels_to_convert = dname->label_count - common_labels;
    418 		absolute = 0;
    419 	}
    420 
    421 	dst = buf;
    422 	src = dname_name(dname);
    423 	for (i = 0; i < labels_to_convert; ++i) {
    424 		size_t len = label_length(src);
    425 		size_t j;
    426 		++src;
    427 		for (j = 0; j < len; ++j) {
    428 			uint8_t ch = *src++;
    429 			if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
    430 				*dst++ = ch;
    431 			} else if (ch == '.' || ch == '\\') {
    432 				*dst++ = '\\';
    433 				*dst++ = ch;
    434 			} else {
    435 				snprintf(dst, 5, "\\%03u", (unsigned int)ch);
    436 				dst += 4;
    437 			}
    438 		}
    439 		*dst++ = '.';
    440 	}
    441 	if (absolute) {
    442 		*dst = '\0';
    443 	} else {
    444 		*--dst = '\0';
    445 	}
    446 	return buf;
    447 }
    448 
    449 
    450 const dname_type *
    451 dname_make_from_label(region_type *region,
    452 		      const uint8_t *label, const size_t length)
    453 {
    454 	uint8_t temp[MAXLABELLEN + 2];
    455 
    456 	assert(length > 0 && length <= MAXLABELLEN);
    457 
    458 	temp[0] = length;
    459 	memcpy(temp + 1, label, length * sizeof(uint8_t));
    460 	temp[length + 1] = '\000';
    461 
    462 	return dname_make(region, temp, 1);
    463 }
    464 
    465 
    466 const dname_type *
    467 dname_concatenate(region_type *region,
    468 		  const dname_type *left,
    469 		  const dname_type *right)
    470 {
    471 	uint8_t temp[MAXDOMAINLEN];
    472 
    473 	assert(left->name_size + right->name_size - 1 <= MAXDOMAINLEN);
    474 
    475 	memcpy(temp, dname_name(left), left->name_size - 1);
    476 	memcpy(temp + left->name_size - 1, dname_name(right), right->name_size);
    477 
    478 	return dname_make(region, temp, 0);
    479 }
    480 
    481 
    482 const dname_type *
    483 dname_replace(region_type* region,
    484 		const dname_type* name,
    485 		const dname_type* src,
    486 		const dname_type* dest)
    487 {
    488 	/* nomenclature: name is said to be <x>.<src>. x can be null. */
    489 	dname_type* res;
    490 	int x_labels = name->label_count - src->label_count;
    491 	int x_len = name->name_size - src->name_size;
    492 	int i;
    493 	assert(dname_is_subdomain(name, src));
    494 
    495 	/* check if final size is acceptable */
    496 	if(x_len+dest->name_size > MAXDOMAINLEN)
    497 		return NULL;
    498 
    499 	res = (dname_type*)region_alloc(region, sizeof(dname_type) +
    500 		(x_labels+((int)dest->label_count) + x_len+((int)dest->name_size))
    501 		*sizeof(uint8_t));
    502 	res->name_size = x_len+dest->name_size;
    503 	res->label_count = x_labels+dest->label_count;
    504 	for(i=0; i<dest->label_count; i++)
    505 		((uint8_t*)dname_label_offsets(res))[i] =
    506 			dname_label_offsets(dest)[i] + x_len;
    507 	for(i=dest->label_count; i<res->label_count; i++)
    508 		((uint8_t*)dname_label_offsets(res))[i] =
    509 			dname_label_offsets(name)[i - dest->label_count +
    510 				src->label_count];
    511 	memcpy((uint8_t*)dname_name(res), dname_name(name), x_len);
    512 	memcpy((uint8_t*)dname_name(res)+x_len, dname_name(dest), dest->name_size);
    513 	assert(dname_is_subdomain(res, dest));
    514 	return res;
    515 }
    516 
    517 char* wirelabel2str(const uint8_t* label)
    518 {
    519 	static char buf[MAXDOMAINLEN*5+3];
    520 	char* p = buf;
    521 	uint8_t lablen;
    522 	lablen = *label++;
    523 	while(lablen--) {
    524 		uint8_t ch = *label++;
    525 		if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
    526 			*p++ = ch;
    527 		} else if (ch == '.' || ch == '\\') {
    528 			*p++ = '\\';
    529 			*p++ = ch;
    530 		} else {
    531 			snprintf(p, 5, "\\%03u", (unsigned int)ch);
    532 			p += 4;
    533 		}
    534 	}
    535 	*p++ = 0;
    536 	return buf;
    537 }
    538 
    539 char* wiredname2str(const uint8_t* dname)
    540 {
    541 	static char buf[MAXDOMAINLEN*5+3];
    542 	char* p = buf;
    543 	uint8_t lablen;
    544 	if(*dname == 0) {
    545 		strlcpy(buf, ".", sizeof(buf));
    546 		return buf;
    547 	}
    548 	lablen = *dname++;
    549 	while(lablen) {
    550 		while(lablen--) {
    551 			uint8_t ch = *dname++;
    552 			if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
    553 				*p++ = ch;
    554 			} else if (ch == '.' || ch == '\\') {
    555 				*p++ = '\\';
    556 				*p++ = ch;
    557 			} else {
    558 				snprintf(p, 5, "\\%03u", (unsigned int)ch);
    559 				p += 4;
    560 			}
    561 		}
    562 		lablen = *dname++;
    563 		*p++ = '.';
    564 	}
    565 	*p++ = 0;
    566 	return buf;
    567 }
    568 
    569 int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len)
    570 {
    571 	uint8_t i, lablen;
    572 	while(len > 0) {
    573 		/* check labellen */
    574 		if(*a != *b)
    575 			return 0;
    576 		lablen = *a++;
    577 		b++;
    578 		len--;
    579 		/* malformed or compression ptr; we stop scanning */
    580 		if((lablen & 0xc0) || len < lablen)
    581 			return (memcmp(a, b, len) == 0);
    582 		/* check the label, lowercased */
    583 		for(i=0; i<lablen; i++) {
    584 			if(DNAME_NORMALIZE((unsigned char)*a++) != DNAME_NORMALIZE((unsigned char)*b++))
    585 				return 0;
    586 		}
    587 		len -= lablen;
    588 	}
    589 	return 1;
    590 }
    591 
    592 int
    593 is_dname_subdomain_of_case(const uint8_t* d, unsigned int len,
    594 	const uint8_t* d2, unsigned int len2)
    595 {
    596 	unsigned int i;
    597 	if(len < len2)
    598 		return 0;
    599 	if(len == len2) {
    600 		if(memcmp(d, d2, len) == 0)
    601 			return 1;
    602 		return 0;
    603 	}
    604 	/* so len > len2, for d=a.example.com. and d2=example.com. */
    605 	/* trailing portion must be exactly name d2. */
    606 	if(memcmp(d+len-len2, d2, len2) != 0)
    607 		return 0;
    608 	/* that must also be a label point */
    609 	i=0;
    610 	while(i < len) {
    611 		if(i == len-len2)
    612 			return 1;
    613 		i += d[i];
    614 		i += 1;
    615 	}
    616 
    617 	/* The trailing portion is not at a label point. */
    618 	return 0;
    619 }
    620 
    621 size_t
    622 buf_dname_length(const uint8_t* buf, size_t len)
    623 {
    624 	size_t l = 0;
    625 	if(!buf || len == 0)
    626 		return l;
    627 	while(len > 0 && buf[0] != 0) {
    628 		size_t lablen = (size_t)(buf[0]);
    629 		if( (lablen&0xc0) )
    630 			return 0; /* the name should be uncompressed */
    631 		if(lablen+1 > len)
    632 			return 0; /* should fit in the buffer */
    633 		l += lablen+1;
    634 		len -= lablen+1;
    635 		buf += lablen+1;
    636 		if(l > MAXDOMAINLEN)
    637 			return 0;
    638 	}
    639 	if(len == 0)
    640 		return 0; /* end label should fit in buffer */
    641 	if(buf[0] != 0)
    642 		return 0; /* must end in root label */
    643 	l += 1; /* for the end root label */
    644 	if(l > MAXDOMAINLEN)
    645 		return 0;
    646 	return l;
    647 }
    648 
    649 int
    650 dname_make_buffered(struct dname_buffer* dname, uint8_t *name, int normalize)
    651 {
    652 	size_t name_size = 0;
    653 	uint8_t label_offsets[MAXDOMAINLEN/2+1];
    654 	uint8_t label_count = 0;
    655 	const uint8_t *label = name;
    656 	ssize_t i;
    657 
    658 	assert(name);
    659 
    660 	while (1) {
    661 		if(!label_is_normal(label))
    662 			return 0;
    663 
    664 		label_offsets[label_count] = (uint8_t) (label - name);
    665 		++label_count;
    666 		name_size += label_length(label) + 1;
    667 
    668 		if (name_size > MAXDOMAINLEN)
    669 			return 0;
    670 		if (label_is_root(label))
    671 			break;
    672 
    673 		label = label_next(label);
    674 	}
    675 
    676 	assert(label_count <= MAXDOMAINLEN / 2 + 1);
    677 
    678 	/* Reverse label offsets.  */
    679 	for (i = 0; i < label_count / 2; ++i) {
    680 		uint8_t tmp = label_offsets[i];
    681 		label_offsets[i] = label_offsets[label_count - i - 1];
    682 		label_offsets[label_count - i - 1] = tmp;
    683 	}
    684 
    685 	/* Move the name to the correct part of the result */
    686 	memmove( ((char*)dname)+sizeof(struct dname)+
    687 		label_count*sizeof(uint8_t), name, name_size);
    688 	dname->dname.name_size = name_size;
    689 	dname->dname.label_count = label_count;
    690 	memcpy((uint8_t *) dname_label_offsets((void*)dname),
    691 		label_offsets, label_count * sizeof(uint8_t));
    692 	if (normalize) {
    693 		uint8_t *src = (uint8_t *) dname_name((void*)dname);
    694 		while (!label_is_root(src)) {
    695 			ssize_t len = label_length(src);
    696 			src++;
    697 			for (i = 0; i < len; ++i) {
    698 				*src = DNAME_NORMALIZE((unsigned char)*src);
    699 				src++;
    700 			}
    701 		}
    702 	}
    703 	return 1;
    704 }
    705 
    706 int
    707 dname_make_from_packet_buffered(struct dname_buffer* dname,
    708 	buffer_type *packet, int allow_pointers, int normalize)
    709 {
    710 	int wirelen = dname_make_wire_from_packet(dname->storage,
    711 		packet, allow_pointers);
    712 	if(wirelen == 0)
    713 		return 0;
    714 	if(!dname_make_buffered(dname, dname->storage, normalize))
    715 		return 0;
    716 	assert(wirelen == dname->dname.name_size);
    717 	return wirelen;
    718 }
    719