xref: /openbsd-src/usr.sbin/nsd/dname.c (revision bf87c3c07c3ad89262e2b8cae09f17e70aa9e1ee)
162ac0c33Sjakob /*
262ac0c33Sjakob  * dname.c -- Domain name handling.
362ac0c33Sjakob  *
4dd5b221eSsthen  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
1062ac0c33Sjakob 
11d11a62c8Ssthen #include "config.h"
1262ac0c33Sjakob 
1362ac0c33Sjakob #include <sys/types.h>
1462ac0c33Sjakob 
1562ac0c33Sjakob #include <assert.h>
1662ac0c33Sjakob #include <ctype.h>
1762ac0c33Sjakob #include <limits.h>
1862ac0c33Sjakob #include <stdio.h>
1962ac0c33Sjakob #include <string.h>
2062ac0c33Sjakob 
2162ac0c33Sjakob #include "dns.h"
2262ac0c33Sjakob #include "dname.h"
2362ac0c33Sjakob #include "query.h"
2462ac0c33Sjakob 
2562ac0c33Sjakob const dname_type *
dname_make(region_type * region,const uint8_t * name,int normalize)2662ac0c33Sjakob dname_make(region_type *region, const uint8_t *name, int normalize)
2762ac0c33Sjakob {
2862ac0c33Sjakob 	size_t name_size = 0;
2962ac0c33Sjakob 	uint8_t label_offsets[MAXDOMAINLEN];
3062ac0c33Sjakob 	uint8_t label_count = 0;
3162ac0c33Sjakob 	const uint8_t *label = name;
3262ac0c33Sjakob 	dname_type *result;
3362ac0c33Sjakob 	ssize_t i;
3462ac0c33Sjakob 
3562ac0c33Sjakob 	assert(name);
3662ac0c33Sjakob 
3762ac0c33Sjakob 	while (1) {
3862ac0c33Sjakob 		if (label_is_pointer(label))
3962ac0c33Sjakob 			return NULL;
4062ac0c33Sjakob 
4162ac0c33Sjakob 		label_offsets[label_count] = (uint8_t) (label - name);
4262ac0c33Sjakob 		++label_count;
4362ac0c33Sjakob 		name_size += label_length(label) + 1;
4462ac0c33Sjakob 
4562ac0c33Sjakob 		if (label_is_root(label))
4662ac0c33Sjakob 			break;
4762ac0c33Sjakob 
4862ac0c33Sjakob 		label = label_next(label);
4962ac0c33Sjakob 	}
5062ac0c33Sjakob 
5162ac0c33Sjakob 	if (name_size > MAXDOMAINLEN)
5262ac0c33Sjakob 		return NULL;
5362ac0c33Sjakob 
5462ac0c33Sjakob 	assert(label_count <= MAXDOMAINLEN / 2 + 1);
5562ac0c33Sjakob 
5662ac0c33Sjakob 	/* Reverse label offsets.  */
5762ac0c33Sjakob 	for (i = 0; i < label_count / 2; ++i) {
5862ac0c33Sjakob 		uint8_t tmp = label_offsets[i];
5962ac0c33Sjakob 		label_offsets[i] = label_offsets[label_count - i - 1];
6062ac0c33Sjakob 		label_offsets[label_count - i - 1] = tmp;
6162ac0c33Sjakob 	}
6262ac0c33Sjakob 
6362ac0c33Sjakob 	result = (dname_type *) region_alloc(
6462ac0c33Sjakob 		region,
6562ac0c33Sjakob 		(sizeof(dname_type)
668d8f1862Ssthen 		 + (((size_t)label_count) + ((size_t)name_size)) * sizeof(uint8_t)));
6762ac0c33Sjakob 	result->name_size = name_size;
6862ac0c33Sjakob 	result->label_count = label_count;
6962ac0c33Sjakob 	memcpy((uint8_t *) dname_label_offsets(result),
7062ac0c33Sjakob 	       label_offsets,
7162ac0c33Sjakob 	       label_count * sizeof(uint8_t));
7262ac0c33Sjakob 	if (normalize) {
7362ac0c33Sjakob 		uint8_t *dst = (uint8_t *) dname_name(result);
7462ac0c33Sjakob 		const uint8_t *src = name;
7562ac0c33Sjakob 		while (!label_is_root(src)) {
7662ac0c33Sjakob 			ssize_t len = label_length(src);
7762ac0c33Sjakob 			*dst++ = *src++;
7862ac0c33Sjakob 			for (i = 0; i < len; ++i) {
79c1404d4fSbrad 				*dst++ = DNAME_NORMALIZE((unsigned char)*src++);
8062ac0c33Sjakob 			}
8162ac0c33Sjakob 		}
8262ac0c33Sjakob 		*dst = *src;
8362ac0c33Sjakob 	} else {
8462ac0c33Sjakob 		memcpy((uint8_t *) dname_name(result),
8562ac0c33Sjakob 		       name,
8662ac0c33Sjakob 		       name_size * sizeof(uint8_t));
8762ac0c33Sjakob 	}
8862ac0c33Sjakob 	return result;
8962ac0c33Sjakob }
9062ac0c33Sjakob 
9162ac0c33Sjakob 
9262ac0c33Sjakob const dname_type *
dname_make_from_packet(region_type * region,buffer_type * packet,int allow_pointers,int normalize)9362ac0c33Sjakob dname_make_from_packet(region_type *region, buffer_type *packet,
9462ac0c33Sjakob 		       int allow_pointers, int normalize)
9562ac0c33Sjakob {
9662ac0c33Sjakob 	uint8_t buf[MAXDOMAINLEN + 1];
9762ac0c33Sjakob 	if(!dname_make_wire_from_packet(buf, packet, allow_pointers))
9862ac0c33Sjakob 		return 0;
9962ac0c33Sjakob 	return dname_make(region, buf, normalize);
10062ac0c33Sjakob }
10162ac0c33Sjakob 
10262ac0c33Sjakob int
dname_make_wire_from_packet(uint8_t * buf,buffer_type * packet,int allow_pointers)10362ac0c33Sjakob dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet,
10462ac0c33Sjakob                        int allow_pointers)
10562ac0c33Sjakob {
10662ac0c33Sjakob 	int done = 0;
10762ac0c33Sjakob 	uint8_t visited[(MAX_PACKET_SIZE+7)/8];
10862ac0c33Sjakob 	size_t dname_length = 0;
10962ac0c33Sjakob 	const uint8_t *label;
11062ac0c33Sjakob 	ssize_t mark = -1;
11162ac0c33Sjakob 
112977db6e5Sflorian 	if(sizeof(visited)<(buffer_limit(packet)+7)/8)
113977db6e5Sflorian 		memset(visited, 0, sizeof(visited));
114977db6e5Sflorian 	else	memset(visited, 0, (buffer_limit(packet)+7)/8);
11562ac0c33Sjakob 
11662ac0c33Sjakob 	while (!done) {
11762ac0c33Sjakob 		if (!buffer_available(packet, 1)) {
11862ac0c33Sjakob /* 			error("dname out of bounds"); */
11962ac0c33Sjakob 			return 0;
12062ac0c33Sjakob 		}
12162ac0c33Sjakob 
12262ac0c33Sjakob 		if (get_bit(visited, buffer_position(packet))) {
12362ac0c33Sjakob /* 			error("dname loops"); */
12462ac0c33Sjakob 			return 0;
12562ac0c33Sjakob 		}
12662ac0c33Sjakob 		set_bit(visited, buffer_position(packet));
12762ac0c33Sjakob 
12862ac0c33Sjakob 		label = buffer_current(packet);
12962ac0c33Sjakob 		if (label_is_pointer(label)) {
13062ac0c33Sjakob 			size_t pointer;
13162ac0c33Sjakob 			if (!allow_pointers) {
13262ac0c33Sjakob 				return 0;
13362ac0c33Sjakob 			}
13462ac0c33Sjakob 			if (!buffer_available(packet, 2)) {
13562ac0c33Sjakob /* 				error("dname pointer out of bounds"); */
13662ac0c33Sjakob 				return 0;
13762ac0c33Sjakob 			}
13862ac0c33Sjakob 			pointer = label_pointer_location(label);
13962ac0c33Sjakob 			if (pointer >= buffer_limit(packet)) {
14062ac0c33Sjakob /* 				error("dname pointer points outside packet"); */
14162ac0c33Sjakob 				return 0;
14262ac0c33Sjakob 			}
14362ac0c33Sjakob 			buffer_skip(packet, 2);
14462ac0c33Sjakob 			if (mark == -1) {
14562ac0c33Sjakob 				mark = buffer_position(packet);
14662ac0c33Sjakob 			}
14762ac0c33Sjakob 			buffer_set_position(packet, pointer);
14862ac0c33Sjakob 		} else if (label_is_normal(label)) {
14962ac0c33Sjakob 			size_t length = label_length(label) + 1;
15062ac0c33Sjakob 			done = label_is_root(label);
15162ac0c33Sjakob 			if (!buffer_available(packet, length)) {
15262ac0c33Sjakob /* 				error("dname label out of bounds"); */
15362ac0c33Sjakob 				return 0;
15462ac0c33Sjakob 			}
15562ac0c33Sjakob 			if (dname_length + length >= MAXDOMAINLEN+1) {
15662ac0c33Sjakob /* 				error("dname too large"); */
15762ac0c33Sjakob 				return 0;
15862ac0c33Sjakob 			}
15962ac0c33Sjakob 			buffer_read(packet, buf + dname_length, length);
16062ac0c33Sjakob 			dname_length += length;
16162ac0c33Sjakob 		} else {
16262ac0c33Sjakob /* 			error("bad label type"); */
16362ac0c33Sjakob 			return 0;
16462ac0c33Sjakob 		}
16562ac0c33Sjakob 	}
16662ac0c33Sjakob 
16762ac0c33Sjakob 	if (mark != -1) {
16862ac0c33Sjakob 		buffer_set_position(packet, mark);
16962ac0c33Sjakob 	}
17062ac0c33Sjakob 
17162ac0c33Sjakob 	return dname_length;
17262ac0c33Sjakob }
17362ac0c33Sjakob 
17462ac0c33Sjakob const dname_type *
dname_parse(region_type * region,const char * name)17562ac0c33Sjakob dname_parse(region_type *region, const char *name)
17662ac0c33Sjakob {
17762ac0c33Sjakob 	uint8_t dname[MAXDOMAINLEN];
17862ac0c33Sjakob 	if(!dname_parse_wire(dname, name))
17962ac0c33Sjakob 		return 0;
18062ac0c33Sjakob 	return dname_make(region, dname, 1);
18162ac0c33Sjakob }
18262ac0c33Sjakob 
dname_parse_wire(uint8_t * dname,const char * name)18362ac0c33Sjakob int dname_parse_wire(uint8_t* dname, const char* name)
18462ac0c33Sjakob {
18562ac0c33Sjakob 	const uint8_t *s = (const uint8_t *) name;
18662ac0c33Sjakob 	uint8_t *h;
18762ac0c33Sjakob 	uint8_t *p;
18862ac0c33Sjakob 	uint8_t *d = dname;
18962ac0c33Sjakob 	size_t label_length;
19062ac0c33Sjakob 
19162ac0c33Sjakob 	if (strcmp(name, ".") == 0) {
19262ac0c33Sjakob 		/* Root domain.  */
19362ac0c33Sjakob 		dname[0] = 0;
19462ac0c33Sjakob 		return 1;
19562ac0c33Sjakob 	}
19662ac0c33Sjakob 
19762ac0c33Sjakob 	for (h = d, p = h + 1; *s; ++s, ++p) {
19862ac0c33Sjakob 		if (p - dname >= MAXDOMAINLEN) {
19962ac0c33Sjakob 			return 0;
20062ac0c33Sjakob 		}
20162ac0c33Sjakob 
20262ac0c33Sjakob 		switch (*s) {
20362ac0c33Sjakob 		case '.':
20462ac0c33Sjakob 			if (p == h + 1) {
20562ac0c33Sjakob 				/* Empty label.  */
20662ac0c33Sjakob 				return 0;
20762ac0c33Sjakob 			} else {
20862ac0c33Sjakob 				label_length = p - h - 1;
20962ac0c33Sjakob 				if (label_length > MAXLABELLEN) {
21062ac0c33Sjakob 					return 0;
21162ac0c33Sjakob 				}
21262ac0c33Sjakob 				*h = label_length;
21362ac0c33Sjakob 				h = p;
21462ac0c33Sjakob 			}
21562ac0c33Sjakob 			break;
21662ac0c33Sjakob 		case '\\':
21762ac0c33Sjakob 			/* Handle escaped characters (RFC1035 5.1) */
218c1404d4fSbrad 			if (isdigit((unsigned char)s[1]) && isdigit((unsigned char)s[2]) && isdigit((unsigned char)s[3])) {
21962ac0c33Sjakob 				int val = (hexdigit_to_int(s[1]) * 100 +
22062ac0c33Sjakob 					   hexdigit_to_int(s[2]) * 10 +
22162ac0c33Sjakob 					   hexdigit_to_int(s[3]));
22262ac0c33Sjakob 				if (0 <= val && val <= 255) {
22362ac0c33Sjakob 					s += 3;
22462ac0c33Sjakob 					*p = val;
22562ac0c33Sjakob 				} else {
22662ac0c33Sjakob 					*p = *++s;
22762ac0c33Sjakob 				}
22862ac0c33Sjakob 			} else if (s[1] != '\0') {
22962ac0c33Sjakob 				*p = *++s;
23062ac0c33Sjakob 			}
23162ac0c33Sjakob 			break;
23262ac0c33Sjakob 		default:
23362ac0c33Sjakob 			*p = *s;
23462ac0c33Sjakob 			break;
23562ac0c33Sjakob 		}
23662ac0c33Sjakob 	}
23762ac0c33Sjakob 
23862ac0c33Sjakob 	if (p != h + 1) {
23962ac0c33Sjakob 		/* Terminate last label.  */
24062ac0c33Sjakob 		label_length = p - h - 1;
24162ac0c33Sjakob 		if (label_length > MAXLABELLEN) {
24262ac0c33Sjakob 			return 0;
24362ac0c33Sjakob 		}
24462ac0c33Sjakob 		*h = label_length;
24562ac0c33Sjakob 		h = p;
246a904e103Sflorian 		p++;
24762ac0c33Sjakob 	}
24862ac0c33Sjakob 
24962ac0c33Sjakob 	/* Add root label.  */
2508d8f1862Ssthen 	if (h - dname >= MAXDOMAINLEN) {
2518d8f1862Ssthen 		return 0;
2528d8f1862Ssthen 	}
25362ac0c33Sjakob 	*h = 0;
25462ac0c33Sjakob 
25562ac0c33Sjakob 	return p-dname;
25662ac0c33Sjakob }
25762ac0c33Sjakob 
25862ac0c33Sjakob 
25962ac0c33Sjakob const dname_type *
dname_copy(region_type * region,const dname_type * dname)26062ac0c33Sjakob dname_copy(region_type *region, const dname_type *dname)
26162ac0c33Sjakob {
26262ac0c33Sjakob 	return (dname_type *) region_alloc_init(
26362ac0c33Sjakob 		region, dname, dname_total_size(dname));
26462ac0c33Sjakob }
26562ac0c33Sjakob 
26662ac0c33Sjakob 
26762ac0c33Sjakob const dname_type *
dname_partial_copy(region_type * region,const dname_type * dname,uint8_t label_count)26862ac0c33Sjakob dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count)
26962ac0c33Sjakob {
27062ac0c33Sjakob 	if (!dname)
27162ac0c33Sjakob 		return NULL;
27262ac0c33Sjakob 
27362ac0c33Sjakob 	if (label_count == 0) {
27462ac0c33Sjakob 		/* Always copy the root label.  */
27562ac0c33Sjakob 		label_count = 1;
27662ac0c33Sjakob 	}
27762ac0c33Sjakob 
27862ac0c33Sjakob 	assert(label_count <= dname->label_count);
27962ac0c33Sjakob 
28062ac0c33Sjakob 	return dname_make(region, dname_label(dname, label_count - 1), 0);
28162ac0c33Sjakob }
28262ac0c33Sjakob 
28362ac0c33Sjakob 
28462ac0c33Sjakob const dname_type *
dname_origin(region_type * region,const dname_type * dname)28562ac0c33Sjakob dname_origin(region_type *region, const dname_type *dname)
28662ac0c33Sjakob {
28762ac0c33Sjakob 	return dname_partial_copy(region, dname, dname->label_count - 1);
28862ac0c33Sjakob }
28962ac0c33Sjakob 
29062ac0c33Sjakob 
29162ac0c33Sjakob int
dname_is_subdomain(const dname_type * left,const dname_type * right)29262ac0c33Sjakob dname_is_subdomain(const dname_type *left, const dname_type *right)
29362ac0c33Sjakob {
29462ac0c33Sjakob 	uint8_t i;
29562ac0c33Sjakob 
29662ac0c33Sjakob 	if (left->label_count < right->label_count)
29762ac0c33Sjakob 		return 0;
29862ac0c33Sjakob 
29962ac0c33Sjakob 	for (i = 1; i < right->label_count; ++i) {
30062ac0c33Sjakob 		if (label_compare(dname_label(left, i),
30162ac0c33Sjakob 				  dname_label(right, i)) != 0)
30262ac0c33Sjakob 			return 0;
30362ac0c33Sjakob 	}
30462ac0c33Sjakob 
30562ac0c33Sjakob 	return 1;
30662ac0c33Sjakob }
30762ac0c33Sjakob 
30862ac0c33Sjakob 
30962ac0c33Sjakob int
dname_compare(const dname_type * left,const dname_type * right)310dd5b221eSsthen dname_compare(const dname_type *left, const dname_type *right)
31162ac0c33Sjakob {
31262ac0c33Sjakob 	int result;
31362ac0c33Sjakob 	uint8_t label_count;
31462ac0c33Sjakob 	uint8_t i;
31562ac0c33Sjakob 
31662ac0c33Sjakob 	assert(left);
31762ac0c33Sjakob 	assert(right);
31862ac0c33Sjakob 
31962ac0c33Sjakob 	if (left == right) {
32062ac0c33Sjakob 		return 0;
32162ac0c33Sjakob 	}
32262ac0c33Sjakob 
32362ac0c33Sjakob 	label_count = (left->label_count <= right->label_count
32462ac0c33Sjakob 		       ? left->label_count
32562ac0c33Sjakob 		       : right->label_count);
32662ac0c33Sjakob 
32762ac0c33Sjakob 	/* Skip the root label by starting at label 1.  */
32862ac0c33Sjakob 	for (i = 1; i < label_count; ++i) {
32962ac0c33Sjakob 		result = label_compare(dname_label(left, i),
33062ac0c33Sjakob 				       dname_label(right, i));
33162ac0c33Sjakob 		if (result) {
33262ac0c33Sjakob 			return result;
33362ac0c33Sjakob 		}
33462ac0c33Sjakob 	}
33562ac0c33Sjakob 
33662ac0c33Sjakob 	/* Dname with the fewest labels is "first".  */
337c1404d4fSbrad 	/* the subtraction works because the size of int is much larger than
338c1404d4fSbrad 	 * the label count and the values won't wrap around */
33962ac0c33Sjakob 	return (int) left->label_count - (int) right->label_count;
34062ac0c33Sjakob }
34162ac0c33Sjakob 
34262ac0c33Sjakob 
34362ac0c33Sjakob int
label_compare(const uint8_t * left,const uint8_t * right)34462ac0c33Sjakob label_compare(const uint8_t *left, const uint8_t *right)
34562ac0c33Sjakob {
34662ac0c33Sjakob 	int left_length;
34762ac0c33Sjakob 	int right_length;
34862ac0c33Sjakob 	size_t size;
34962ac0c33Sjakob 	int result;
35062ac0c33Sjakob 
35162ac0c33Sjakob 	assert(left);
35262ac0c33Sjakob 	assert(right);
35362ac0c33Sjakob 
35462ac0c33Sjakob 	assert(label_is_normal(left));
35562ac0c33Sjakob 	assert(label_is_normal(right));
35662ac0c33Sjakob 
35762ac0c33Sjakob 	left_length = label_length(left);
35862ac0c33Sjakob 	right_length = label_length(right);
35962ac0c33Sjakob 	size = left_length < right_length ? left_length : right_length;
36062ac0c33Sjakob 
36162ac0c33Sjakob 	result = memcmp(label_data(left), label_data(right), size);
36262ac0c33Sjakob 	if (result) {
36362ac0c33Sjakob 		return result;
36462ac0c33Sjakob 	} else {
365c1404d4fSbrad 		/* the subtraction works because the size of int is much
366c1404d4fSbrad 		 * larger than the lengths and the values won't wrap around */
36762ac0c33Sjakob 		return (int) left_length - (int) right_length;
36862ac0c33Sjakob 	}
36962ac0c33Sjakob }
37062ac0c33Sjakob 
37162ac0c33Sjakob 
37262ac0c33Sjakob uint8_t
dname_label_match_count(const dname_type * left,const dname_type * right)37362ac0c33Sjakob dname_label_match_count(const dname_type *left, const dname_type *right)
37462ac0c33Sjakob {
37562ac0c33Sjakob 	uint8_t i;
37662ac0c33Sjakob 
37762ac0c33Sjakob 	assert(left);
37862ac0c33Sjakob 	assert(right);
37962ac0c33Sjakob 
38062ac0c33Sjakob 	for (i = 1; i < left->label_count && i < right->label_count; ++i) {
38162ac0c33Sjakob 		if (label_compare(dname_label(left, i),
38262ac0c33Sjakob 				  dname_label(right, i)) != 0)
38362ac0c33Sjakob 		{
38462ac0c33Sjakob 			return i;
38562ac0c33Sjakob 		}
38662ac0c33Sjakob 	}
38762ac0c33Sjakob 
38862ac0c33Sjakob 	return i;
38962ac0c33Sjakob }
39062ac0c33Sjakob 
39162ac0c33Sjakob const char *
dname_to_string(const dname_type * dname,const dname_type * origin)39262ac0c33Sjakob dname_to_string(const dname_type *dname, const dname_type *origin)
39362ac0c33Sjakob {
39462ac0c33Sjakob 	static char buf[MAXDOMAINLEN * 5];
395*bf87c3c0Sflorian 	return dname_to_string_buf(dname, origin, buf);
396*bf87c3c0Sflorian }
397*bf87c3c0Sflorian 
398*bf87c3c0Sflorian const char *
dname_to_string_buf(const dname_type * dname,const dname_type * origin,char buf[MAXDOMAINLEN * 5])399*bf87c3c0Sflorian dname_to_string_buf(const dname_type *dname, const dname_type *origin, char buf[MAXDOMAINLEN * 5])
400*bf87c3c0Sflorian {
40162ac0c33Sjakob 	size_t i;
402dd5b221eSsthen 	size_t labels_to_convert = dname->label_count - 1;
40362ac0c33Sjakob 	int absolute = 1;
40462ac0c33Sjakob 	char *dst;
40562ac0c33Sjakob 	const uint8_t *src;
406dd5b221eSsthen 
40762ac0c33Sjakob 	if (dname->label_count == 1) {
408*bf87c3c0Sflorian 		strlcpy(buf, ".", MAXDOMAINLEN * 5);
40962ac0c33Sjakob 		return buf;
41062ac0c33Sjakob 	}
41162ac0c33Sjakob 
41262ac0c33Sjakob 	if (origin && dname_is_subdomain(dname, origin)) {
41362ac0c33Sjakob 		int common_labels = dname_label_match_count(dname, origin);
41462ac0c33Sjakob 		labels_to_convert = dname->label_count - common_labels;
41562ac0c33Sjakob 		absolute = 0;
41662ac0c33Sjakob 	}
41762ac0c33Sjakob 
418dd5b221eSsthen 	dst = buf;
41962ac0c33Sjakob 	src = dname_name(dname);
42062ac0c33Sjakob 	for (i = 0; i < labels_to_convert; ++i) {
42162ac0c33Sjakob 		size_t len = label_length(src);
42262ac0c33Sjakob 		size_t j;
42362ac0c33Sjakob 		++src;
42462ac0c33Sjakob 		for (j = 0; j < len; ++j) {
42562ac0c33Sjakob 			uint8_t ch = *src++;
4268d298c9fSsthen 			if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
42762ac0c33Sjakob 				*dst++ = ch;
42862ac0c33Sjakob 			} else if (ch == '.' || ch == '\\') {
42962ac0c33Sjakob 				*dst++ = '\\';
43062ac0c33Sjakob 				*dst++ = ch;
43162ac0c33Sjakob 			} else {
43262ac0c33Sjakob 				snprintf(dst, 5, "\\%03u", (unsigned int)ch);
43362ac0c33Sjakob 				dst += 4;
43462ac0c33Sjakob 			}
43562ac0c33Sjakob 		}
43662ac0c33Sjakob 		*dst++ = '.';
43762ac0c33Sjakob 	}
43862ac0c33Sjakob 	if (absolute) {
43962ac0c33Sjakob 		*dst = '\0';
44062ac0c33Sjakob 	} else {
44162ac0c33Sjakob 		*--dst = '\0';
44262ac0c33Sjakob 	}
44362ac0c33Sjakob 	return buf;
44462ac0c33Sjakob }
44562ac0c33Sjakob 
44662ac0c33Sjakob 
44762ac0c33Sjakob const dname_type *
dname_make_from_label(region_type * region,const uint8_t * label,const size_t length)44862ac0c33Sjakob dname_make_from_label(region_type *region,
44962ac0c33Sjakob 		      const uint8_t *label, const size_t length)
45062ac0c33Sjakob {
45162ac0c33Sjakob 	uint8_t temp[MAXLABELLEN + 2];
45262ac0c33Sjakob 
45362ac0c33Sjakob 	assert(length > 0 && length <= MAXLABELLEN);
45462ac0c33Sjakob 
45562ac0c33Sjakob 	temp[0] = length;
45662ac0c33Sjakob 	memcpy(temp + 1, label, length * sizeof(uint8_t));
45762ac0c33Sjakob 	temp[length + 1] = '\000';
45862ac0c33Sjakob 
45962ac0c33Sjakob 	return dname_make(region, temp, 1);
46062ac0c33Sjakob }
46162ac0c33Sjakob 
46262ac0c33Sjakob 
46362ac0c33Sjakob const dname_type *
dname_concatenate(region_type * region,const dname_type * left,const dname_type * right)46462ac0c33Sjakob dname_concatenate(region_type *region,
46562ac0c33Sjakob 		  const dname_type *left,
46662ac0c33Sjakob 		  const dname_type *right)
46762ac0c33Sjakob {
46862ac0c33Sjakob 	uint8_t temp[MAXDOMAINLEN];
46962ac0c33Sjakob 
47062ac0c33Sjakob 	assert(left->name_size + right->name_size - 1 <= MAXDOMAINLEN);
47162ac0c33Sjakob 
47262ac0c33Sjakob 	memcpy(temp, dname_name(left), left->name_size - 1);
47362ac0c33Sjakob 	memcpy(temp + left->name_size - 1, dname_name(right), right->name_size);
47462ac0c33Sjakob 
47562ac0c33Sjakob 	return dname_make(region, temp, 0);
47662ac0c33Sjakob }
47762ac0c33Sjakob 
47862ac0c33Sjakob 
47962ac0c33Sjakob const dname_type *
dname_replace(region_type * region,const dname_type * name,const dname_type * src,const dname_type * dest)48062ac0c33Sjakob dname_replace(region_type* region,
48162ac0c33Sjakob 		const dname_type* name,
48262ac0c33Sjakob 		const dname_type* src,
48362ac0c33Sjakob 		const dname_type* dest)
48462ac0c33Sjakob {
48562ac0c33Sjakob 	/* nomenclature: name is said to be <x>.<src>. x can be null. */
48662ac0c33Sjakob 	dname_type* res;
48762ac0c33Sjakob 	int x_labels = name->label_count - src->label_count;
48862ac0c33Sjakob 	int x_len = name->name_size - src->name_size;
48962ac0c33Sjakob 	int i;
49062ac0c33Sjakob 	assert(dname_is_subdomain(name, src));
49162ac0c33Sjakob 
49262ac0c33Sjakob 	/* check if final size is acceptable */
49362ac0c33Sjakob 	if(x_len+dest->name_size > MAXDOMAINLEN)
49462ac0c33Sjakob 		return NULL;
49562ac0c33Sjakob 
49662ac0c33Sjakob 	res = (dname_type*)region_alloc(region, sizeof(dname_type) +
4978d8f1862Ssthen 		(x_labels+((int)dest->label_count) + x_len+((int)dest->name_size))
49862ac0c33Sjakob 		*sizeof(uint8_t));
49962ac0c33Sjakob 	res->name_size = x_len+dest->name_size;
50062ac0c33Sjakob 	res->label_count = x_labels+dest->label_count;
50162ac0c33Sjakob 	for(i=0; i<dest->label_count; i++)
50262ac0c33Sjakob 		((uint8_t*)dname_label_offsets(res))[i] =
50362ac0c33Sjakob 			dname_label_offsets(dest)[i] + x_len;
50462ac0c33Sjakob 	for(i=dest->label_count; i<res->label_count; i++)
50562ac0c33Sjakob 		((uint8_t*)dname_label_offsets(res))[i] =
50662ac0c33Sjakob 			dname_label_offsets(name)[i - dest->label_count +
50762ac0c33Sjakob 				src->label_count];
50862ac0c33Sjakob 	memcpy((uint8_t*)dname_name(res), dname_name(name), x_len);
50962ac0c33Sjakob 	memcpy((uint8_t*)dname_name(res)+x_len, dname_name(dest), dest->name_size);
51062ac0c33Sjakob 	assert(dname_is_subdomain(res, dest));
51162ac0c33Sjakob 	return res;
51262ac0c33Sjakob }
51362ac0c33Sjakob 
wirelabel2str(const uint8_t * label)514dd5b221eSsthen char* wirelabel2str(const uint8_t* label)
5155bcb494bSjakob {
516dd5b221eSsthen 	static char buf[MAXDOMAINLEN*5+3];
517dd5b221eSsthen 	char* p = buf;
518dd5b221eSsthen 	uint8_t lablen;
519dd5b221eSsthen 	lablen = *label++;
520dd5b221eSsthen 	while(lablen--) {
521dd5b221eSsthen 		uint8_t ch = *label++;
5228d298c9fSsthen 		if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
523dd5b221eSsthen 			*p++ = ch;
524dd5b221eSsthen 		} else if (ch == '.' || ch == '\\') {
525dd5b221eSsthen 			*p++ = '\\';
526dd5b221eSsthen 			*p++ = ch;
527dd5b221eSsthen 		} else {
528dd5b221eSsthen 			snprintf(p, 5, "\\%03u", (unsigned int)ch);
529dd5b221eSsthen 			p += 4;
5305bcb494bSjakob 		}
531dd5b221eSsthen 	}
532dd5b221eSsthen 	*p++ = 0;
533dd5b221eSsthen 	return buf;
5345bcb494bSjakob }
5355bcb494bSjakob 
wiredname2str(const uint8_t * dname)536dd5b221eSsthen char* wiredname2str(const uint8_t* dname)
537dd5b221eSsthen {
538dd5b221eSsthen 	static char buf[MAXDOMAINLEN*5+3];
539dd5b221eSsthen 	char* p = buf;
540dd5b221eSsthen 	uint8_t lablen;
541dd5b221eSsthen 	if(*dname == 0) {
542dd5b221eSsthen 		strlcpy(buf, ".", sizeof(buf));
543dd5b221eSsthen 		return buf;
5445bcb494bSjakob 	}
545dd5b221eSsthen 	lablen = *dname++;
546dd5b221eSsthen 	while(lablen) {
547dd5b221eSsthen 		while(lablen--) {
548dd5b221eSsthen 			uint8_t ch = *dname++;
549c1404d4fSbrad 			if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') {
550dd5b221eSsthen 				*p++ = ch;
551dd5b221eSsthen 			} else if (ch == '.' || ch == '\\') {
552dd5b221eSsthen 				*p++ = '\\';
553dd5b221eSsthen 				*p++ = ch;
554dd5b221eSsthen 			} else {
555dd5b221eSsthen 				snprintf(p, 5, "\\%03u", (unsigned int)ch);
556dd5b221eSsthen 				p += 4;
5575bcb494bSjakob 			}
558dd5b221eSsthen 		}
559dd5b221eSsthen 		lablen = *dname++;
560dd5b221eSsthen 		*p++ = '.';
561dd5b221eSsthen 	}
562dd5b221eSsthen 	*p++ = 0;
563dd5b221eSsthen 	return buf;
564dd5b221eSsthen }
5655bcb494bSjakob 
dname_equal_nocase(uint8_t * a,uint8_t * b,uint16_t len)566dd5b221eSsthen int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len)
567dd5b221eSsthen {
568dd5b221eSsthen 	uint8_t i, lablen;
569dd5b221eSsthen 	while(len > 0) {
570dd5b221eSsthen 		/* check labellen */
571dd5b221eSsthen 		if(*a != *b)
572dd5b221eSsthen 			return 0;
573dd5b221eSsthen 		lablen = *a++;
574dd5b221eSsthen 		b++;
575dd5b221eSsthen 		len--;
576dd5b221eSsthen 		/* malformed or compression ptr; we stop scanning */
577dd5b221eSsthen 		if((lablen & 0xc0) || len < lablen)
578dd5b221eSsthen 			return (memcmp(a, b, len) == 0);
579dd5b221eSsthen 		/* check the label, lowercased */
580dd5b221eSsthen 		for(i=0; i<lablen; i++) {
581c1404d4fSbrad 			if(DNAME_NORMALIZE((unsigned char)*a++) != DNAME_NORMALIZE((unsigned char)*b++))
5825bcb494bSjakob 				return 0;
5835bcb494bSjakob 		}
584dd5b221eSsthen 		len -= lablen;
585dd5b221eSsthen 	}
586dd5b221eSsthen 	return 1;
587dd5b221eSsthen }
588