xref: /openbsd-src/usr.bin/dig/lib/dns/name.c (revision 1fb015a8af3a7e9b85db2510147a155826ef04d9)
15185a700Sflorian /*
25185a700Sflorian  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian  *
45185a700Sflorian  * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian  * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian  * copyright notice and this permission notice appear in all copies.
75185a700Sflorian  *
85185a700Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian  * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian  */
165185a700Sflorian 
17*1fb015a8Sflorian /* $Id: name.c,v 1.14 2020/09/14 08:40:43 florian Exp $ */
185185a700Sflorian 
195185a700Sflorian /*! \file */
205185a700Sflorian #include <ctype.h>
215185a700Sflorian #include <stdlib.h>
225185a700Sflorian #include <isc/buffer.h>
235185a700Sflorian #include <isc/hash.h>
245185a700Sflorian 
255185a700Sflorian #include <string.h>
265185a700Sflorian #include <isc/util.h>
275185a700Sflorian 
285185a700Sflorian #include <dns/compress.h>
295185a700Sflorian #include <dns/fixedname.h>
305185a700Sflorian #include <dns/name.h>
315185a700Sflorian #include <dns/result.h>
325185a700Sflorian 
335185a700Sflorian typedef enum {
345185a700Sflorian 	ft_init = 0,
355185a700Sflorian 	ft_start,
365185a700Sflorian 	ft_ordinary,
375185a700Sflorian 	ft_initialescape,
385185a700Sflorian 	ft_escape,
395185a700Sflorian 	ft_escdecimal,
405185a700Sflorian 	ft_at
415185a700Sflorian } ft_state;
425185a700Sflorian 
435185a700Sflorian typedef enum {
445185a700Sflorian 	fw_start = 0,
455185a700Sflorian 	fw_ordinary,
465185a700Sflorian 	fw_newcurrent
475185a700Sflorian } fw_state;
485185a700Sflorian 
495185a700Sflorian static char digitvalue[256] = {
505185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	/*16*/
515185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
525185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
535185a700Sflorian 	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
545185a700Sflorian 	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
555185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
565185a700Sflorian 	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
575185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
585185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
595185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
605185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
615185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
625185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
635185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
645185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
655185a700Sflorian 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
665185a700Sflorian };
675185a700Sflorian 
685185a700Sflorian static unsigned char maptolower[] = {
695185a700Sflorian 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
705185a700Sflorian 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
715185a700Sflorian 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
725185a700Sflorian 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
735185a700Sflorian 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
745185a700Sflorian 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
755185a700Sflorian 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
765185a700Sflorian 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
775185a700Sflorian 	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
785185a700Sflorian 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
795185a700Sflorian 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
805185a700Sflorian 	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
815185a700Sflorian 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
825185a700Sflorian 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
835185a700Sflorian 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
845185a700Sflorian 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
855185a700Sflorian 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
865185a700Sflorian 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
875185a700Sflorian 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
885185a700Sflorian 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
895185a700Sflorian 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
905185a700Sflorian 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
915185a700Sflorian 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
925185a700Sflorian 	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
935185a700Sflorian 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
945185a700Sflorian 	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
955185a700Sflorian 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
965185a700Sflorian 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
975185a700Sflorian 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
985185a700Sflorian 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
995185a700Sflorian 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
1005185a700Sflorian 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1015185a700Sflorian };
1025185a700Sflorian 
1035185a700Sflorian #define CONVERTTOASCII(c)
1045185a700Sflorian #define CONVERTFROMASCII(c)
1055185a700Sflorian 
1065185a700Sflorian #define INIT_OFFSETS(name, var, default_offsets) \
1075185a700Sflorian 	if ((name)->offsets != NULL)		 \
1085185a700Sflorian 		var = (name)->offsets;		 \
1095185a700Sflorian 	else \
1105185a700Sflorian 		var = (default_offsets);
1115185a700Sflorian 
1125185a700Sflorian #define SETUP_OFFSETS(name, var, default_offsets) \
1135185a700Sflorian 	if ((name)->offsets != NULL)		  \
1145185a700Sflorian 		var = (name)->offsets;		  \
1155185a700Sflorian 	else { \
1165185a700Sflorian 		var = (default_offsets);      \
1175185a700Sflorian 		set_offsets(name, var, NULL); \
1185185a700Sflorian 	}
1195185a700Sflorian 
1205185a700Sflorian /*%
1215185a700Sflorian  * Note:  If additional attributes are added that should not be set for
1225185a700Sflorian  *	  empty names, MAKE_EMPTY() must be changed so it clears them.
1235185a700Sflorian  */
1245185a700Sflorian #define MAKE_EMPTY(name) \
1255185a700Sflorian do { \
1265185a700Sflorian 	name->ndata = NULL; \
1275185a700Sflorian 	name->length = 0; \
1285185a700Sflorian 	name->labels = 0; \
1295185a700Sflorian 	name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
1305185a700Sflorian } while (0);
1315185a700Sflorian 
1325185a700Sflorian /*%
1335185a700Sflorian  * A name is "bindable" if it can be set to point to a new value, i.e.
1345185a700Sflorian  * name->ndata and name->length may be changed.
1355185a700Sflorian  */
1365185a700Sflorian #define BINDABLE(name) \
1375185a700Sflorian 	((name->attributes & (DNS_NAMEATTR_READONLY|DNS_NAMEATTR_DYNAMIC)) \
1385185a700Sflorian 	 == 0)
1395185a700Sflorian 
1405185a700Sflorian /*%
1415185a700Sflorian  * Note that the name data must be a char array, not a string
1425185a700Sflorian  * literal, to avoid compiler warnings about discarding
1435185a700Sflorian  * the const attribute of a string.
1445185a700Sflorian  */
1455185a700Sflorian static unsigned char root_ndata[] = { "" };
1465185a700Sflorian static unsigned char root_offsets[] = { 0 };
1475185a700Sflorian 
1485185a700Sflorian static dns_name_t root = DNS_NAME_INITABSOLUTE(root_ndata, root_offsets);
1495185a700Sflorian 
1505185a700Sflorian /* XXXDCL make const? */
1515185a700Sflorian dns_name_t *dns_rootname = &root;
1525185a700Sflorian 
1535185a700Sflorian static void
1545185a700Sflorian set_offsets(const dns_name_t *name, unsigned char *offsets,
1555185a700Sflorian 	    dns_name_t *set_name);
1565185a700Sflorian 
1575185a700Sflorian void
dns_name_init(dns_name_t * name,unsigned char * offsets)1585185a700Sflorian dns_name_init(dns_name_t *name, unsigned char *offsets) {
1595185a700Sflorian 	/*
1605185a700Sflorian 	 * Initialize 'name'.
1615185a700Sflorian 	 */
162f1dacf25Sflorian 	name->ndata = NULL;
163f1dacf25Sflorian 	name->length = 0;
164f1dacf25Sflorian 	name->labels = 0;
165f1dacf25Sflorian 	name->attributes = 0;
166f1dacf25Sflorian 	name->offsets = offsets;
167f1dacf25Sflorian 	name->buffer = NULL;
168f1dacf25Sflorian 	ISC_LINK_INIT(name, link);
169f1dacf25Sflorian 	ISC_LIST_INIT(name->list);
170f1dacf25Sflorian 
1715185a700Sflorian }
1725185a700Sflorian 
1735185a700Sflorian void
dns_name_reset(dns_name_t * name)1745185a700Sflorian dns_name_reset(dns_name_t *name) {
1755185a700Sflorian 	REQUIRE(BINDABLE(name));
1765185a700Sflorian 
177f1dacf25Sflorian 	name->ndata = NULL;
178f1dacf25Sflorian 	name->length = 0;
179f1dacf25Sflorian 	name->labels = 0;
180f1dacf25Sflorian 	name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
181f1dacf25Sflorian 	if (name->buffer != NULL)
182f1dacf25Sflorian 		isc_buffer_clear(name->buffer);
1835185a700Sflorian }
1845185a700Sflorian 
1855185a700Sflorian void
dns_name_invalidate(dns_name_t * name)1865185a700Sflorian dns_name_invalidate(dns_name_t *name) {
1875185a700Sflorian 	/*
1885185a700Sflorian 	 * Make 'name' invalid.
1895185a700Sflorian 	 */
1905185a700Sflorian 
1915185a700Sflorian 	name->ndata = NULL;
1925185a700Sflorian 	name->length = 0;
1935185a700Sflorian 	name->labels = 0;
1945185a700Sflorian 	name->attributes = 0;
1955185a700Sflorian 	name->offsets = NULL;
1965185a700Sflorian 	name->buffer = NULL;
1975185a700Sflorian 	ISC_LINK_INIT(name, link);
1985185a700Sflorian }
1995185a700Sflorian 
2005185a700Sflorian void
dns_name_setbuffer(dns_name_t * name,isc_buffer_t * buffer)2015185a700Sflorian dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
2025185a700Sflorian 	/*
2035185a700Sflorian 	 * Dedicate a buffer for use with 'name'.
2045185a700Sflorian 	 */
2055185a700Sflorian 
2065185a700Sflorian 	REQUIRE((buffer != NULL && name->buffer == NULL) ||
2075185a700Sflorian 		(buffer == NULL));
2085185a700Sflorian 
2095185a700Sflorian 	name->buffer = buffer;
2105185a700Sflorian }
2115185a700Sflorian 
212*1fb015a8Sflorian int
dns_name_isabsolute(const dns_name_t * name)2135185a700Sflorian dns_name_isabsolute(const dns_name_t *name) {
2145185a700Sflorian 
2155185a700Sflorian 	/*
2165185a700Sflorian 	 * Does 'name' end in the root label?
2175185a700Sflorian 	 */
2185185a700Sflorian 
2195185a700Sflorian 	if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
220*1fb015a8Sflorian 		return (1);
221*1fb015a8Sflorian 	return (0);
2225185a700Sflorian }
2235185a700Sflorian 
2245185a700Sflorian unsigned int
dns_name_hash(dns_name_t * name,int case_sensitive)225*1fb015a8Sflorian dns_name_hash(dns_name_t *name, int case_sensitive) {
2265185a700Sflorian 	unsigned int length;
2275185a700Sflorian 
2285185a700Sflorian 	/*
2295185a700Sflorian 	 * Provide a hash value for 'name'.
2305185a700Sflorian 	 */
2315185a700Sflorian 
2325185a700Sflorian 	if (name->labels == 0)
2335185a700Sflorian 		return (0);
2345185a700Sflorian 
2355185a700Sflorian 	length = name->length;
2365185a700Sflorian 	if (length > 16)
2375185a700Sflorian 		length = 16;
2385185a700Sflorian 
2395185a700Sflorian 	return (isc_hash_function_reverse(name->ndata, length,
2405185a700Sflorian 					  case_sensitive, NULL));
2415185a700Sflorian }
2425185a700Sflorian 
2435185a700Sflorian dns_namereln_t
dns_name_fullcompare(const dns_name_t * name1,const dns_name_t * name2,int * orderp,unsigned int * nlabelsp)2445185a700Sflorian dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
2455185a700Sflorian 		     int *orderp, unsigned int *nlabelsp)
2465185a700Sflorian {
2475185a700Sflorian 	unsigned int l1, l2, l, count1, count2, count, nlabels;
2485185a700Sflorian 	int cdiff, ldiff, chdiff;
2495185a700Sflorian 	unsigned char *label1, *label2;
2505185a700Sflorian 	unsigned char *offsets1, *offsets2;
2515185a700Sflorian 	dns_offsets_t odata1, odata2;
2525185a700Sflorian 	dns_namereln_t namereln = dns_namereln_none;
2535185a700Sflorian 
2545185a700Sflorian 	/*
2555185a700Sflorian 	 * Determine the relative ordering under the DNSSEC order relation of
2565185a700Sflorian 	 * 'name1' and 'name2', and also determine the hierarchical
2575185a700Sflorian 	 * relationship of the names.
2585185a700Sflorian 	 *
2595185a700Sflorian 	 * Note: It makes no sense for one of the names to be relative and the
2605185a700Sflorian 	 * other absolute.  If both names are relative, then to be meaningfully
2615185a700Sflorian 	 * compared the caller must ensure that they are both relative to the
2625185a700Sflorian 	 * same domain.
2635185a700Sflorian 	 */
2645185a700Sflorian 
2655185a700Sflorian 	REQUIRE(orderp != NULL);
2665185a700Sflorian 	REQUIRE(nlabelsp != NULL);
2675185a700Sflorian 	/*
2685185a700Sflorian 	 * Either name1 is absolute and name2 is absolute, or neither is.
2695185a700Sflorian 	 */
2705185a700Sflorian 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
2715185a700Sflorian 		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
2725185a700Sflorian 
2735185a700Sflorian 	if (name1 == name2) {
2745185a700Sflorian 		*orderp = 0;
2755185a700Sflorian 		*nlabelsp = name1->labels;
2765185a700Sflorian 		return (dns_namereln_equal);
2775185a700Sflorian 	}
2785185a700Sflorian 
2795185a700Sflorian 	SETUP_OFFSETS(name1, offsets1, odata1);
2805185a700Sflorian 	SETUP_OFFSETS(name2, offsets2, odata2);
2815185a700Sflorian 
2825185a700Sflorian 	nlabels = 0;
2835185a700Sflorian 	l1 = name1->labels;
2845185a700Sflorian 	l2 = name2->labels;
2855185a700Sflorian 	if (l2 > l1) {
2865185a700Sflorian 		l = l1;
2875185a700Sflorian 		ldiff = 0 - (l2 - l1);
2885185a700Sflorian 	} else {
2895185a700Sflorian 		l = l2;
2905185a700Sflorian 		ldiff = l1 - l2;
2915185a700Sflorian 	}
2925185a700Sflorian 
2935185a700Sflorian 	offsets1 += l1;
2945185a700Sflorian 	offsets2 += l2;
2955185a700Sflorian 
2965185a700Sflorian 	while (l > 0) {
2975185a700Sflorian 		l--;
2985185a700Sflorian 		offsets1--;
2995185a700Sflorian 		offsets2--;
3005185a700Sflorian 		label1 = &name1->ndata[*offsets1];
3015185a700Sflorian 		label2 = &name2->ndata[*offsets2];
3025185a700Sflorian 		count1 = *label1++;
3035185a700Sflorian 		count2 = *label2++;
3045185a700Sflorian 
3055185a700Sflorian 		/*
3065185a700Sflorian 		 * We dropped bitstring labels, and we don't support any
3075185a700Sflorian 		 * other extended label types.
3085185a700Sflorian 		 */
3095185a700Sflorian 		INSIST(count1 <= 63 && count2 <= 63);
3105185a700Sflorian 
3115185a700Sflorian 		cdiff = (int)count1 - (int)count2;
3125185a700Sflorian 		if (cdiff < 0)
3135185a700Sflorian 			count = count1;
3145185a700Sflorian 		else
3155185a700Sflorian 			count = count2;
3165185a700Sflorian 
3175185a700Sflorian 		/* Loop unrolled for performance */
3185185a700Sflorian 		while (count > 3) {
3195185a700Sflorian 			chdiff = (int)maptolower[label1[0]] -
3205185a700Sflorian 				 (int)maptolower[label2[0]];
3215185a700Sflorian 			if (chdiff != 0) {
3225185a700Sflorian 				*orderp = chdiff;
3235185a700Sflorian 				goto done;
3245185a700Sflorian 			}
3255185a700Sflorian 			chdiff = (int)maptolower[label1[1]] -
3265185a700Sflorian 				 (int)maptolower[label2[1]];
3275185a700Sflorian 			if (chdiff != 0) {
3285185a700Sflorian 				*orderp = chdiff;
3295185a700Sflorian 				goto done;
3305185a700Sflorian 			}
3315185a700Sflorian 			chdiff = (int)maptolower[label1[2]] -
3325185a700Sflorian 				 (int)maptolower[label2[2]];
3335185a700Sflorian 			if (chdiff != 0) {
3345185a700Sflorian 				*orderp = chdiff;
3355185a700Sflorian 				goto done;
3365185a700Sflorian 			}
3375185a700Sflorian 			chdiff = (int)maptolower[label1[3]] -
3385185a700Sflorian 				 (int)maptolower[label2[3]];
3395185a700Sflorian 			if (chdiff != 0) {
3405185a700Sflorian 				*orderp = chdiff;
3415185a700Sflorian 				goto done;
3425185a700Sflorian 			}
3435185a700Sflorian 			count -= 4;
3445185a700Sflorian 			label1 += 4;
3455185a700Sflorian 			label2 += 4;
3465185a700Sflorian 		}
3475185a700Sflorian 		while (count-- > 0) {
3485185a700Sflorian 			chdiff = (int)maptolower[*label1++] -
3495185a700Sflorian 				 (int)maptolower[*label2++];
3505185a700Sflorian 			if (chdiff != 0) {
3515185a700Sflorian 				*orderp = chdiff;
3525185a700Sflorian 				goto done;
3535185a700Sflorian 			}
3545185a700Sflorian 		}
3555185a700Sflorian 		if (cdiff != 0) {
3565185a700Sflorian 			*orderp = cdiff;
3575185a700Sflorian 			goto done;
3585185a700Sflorian 		}
3595185a700Sflorian 		nlabels++;
3605185a700Sflorian 	}
3615185a700Sflorian 
3625185a700Sflorian 	*orderp = ldiff;
3635185a700Sflorian 	if (ldiff < 0)
3645185a700Sflorian 		namereln = dns_namereln_contains;
3655185a700Sflorian 	else if (ldiff > 0)
3665185a700Sflorian 		namereln = dns_namereln_subdomain;
3675185a700Sflorian 	else
3685185a700Sflorian 		namereln = dns_namereln_equal;
3695185a700Sflorian 	*nlabelsp = nlabels;
3705185a700Sflorian 	return (namereln);
3715185a700Sflorian 
3725185a700Sflorian  done:
3735185a700Sflorian 	*nlabelsp = nlabels;
3745185a700Sflorian 	if (nlabels > 0)
3755185a700Sflorian 		namereln = dns_namereln_commonancestor;
3765185a700Sflorian 
3775185a700Sflorian 	return (namereln);
3785185a700Sflorian }
3795185a700Sflorian 
3805185a700Sflorian int
dns_name_compare(const dns_name_t * name1,const dns_name_t * name2)3815185a700Sflorian dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
3825185a700Sflorian 	int order;
3835185a700Sflorian 	unsigned int nlabels;
3845185a700Sflorian 
3855185a700Sflorian 	/*
3865185a700Sflorian 	 * Determine the relative ordering under the DNSSEC order relation of
3875185a700Sflorian 	 * 'name1' and 'name2'.
3885185a700Sflorian 	 *
3895185a700Sflorian 	 * Note: It makes no sense for one of the names to be relative and the
3905185a700Sflorian 	 * other absolute.  If both names are relative, then to be meaningfully
3915185a700Sflorian 	 * compared the caller must ensure that they are both relative to the
3925185a700Sflorian 	 * same domain.
3935185a700Sflorian 	 */
3945185a700Sflorian 
3955185a700Sflorian 	(void)dns_name_fullcompare(name1, name2, &order, &nlabels);
3965185a700Sflorian 
3975185a700Sflorian 	return (order);
3985185a700Sflorian }
3995185a700Sflorian 
400*1fb015a8Sflorian int
dns_name_equal(const dns_name_t * name1,const dns_name_t * name2)4015185a700Sflorian dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
4025185a700Sflorian 	unsigned int l, count;
4035185a700Sflorian 	unsigned char c;
4045185a700Sflorian 	unsigned char *label1, *label2;
4055185a700Sflorian 
4065185a700Sflorian 	/*
4075185a700Sflorian 	 * Are 'name1' and 'name2' equal?
4085185a700Sflorian 	 *
4095185a700Sflorian 	 * Note: It makes no sense for one of the names to be relative and the
4105185a700Sflorian 	 * other absolute.  If both names are relative, then to be meaningfully
4115185a700Sflorian 	 * compared the caller must ensure that they are both relative to the
4125185a700Sflorian 	 * same domain.
4135185a700Sflorian 	 */
4145185a700Sflorian 
4155185a700Sflorian 	/*
4165185a700Sflorian 	 * Either name1 is absolute and name2 is absolute, or neither is.
4175185a700Sflorian 	 */
4185185a700Sflorian 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
4195185a700Sflorian 		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
4205185a700Sflorian 
4215185a700Sflorian 	if (name1 == name2)
422*1fb015a8Sflorian 		return (1);
4235185a700Sflorian 
4245185a700Sflorian 	if (name1->length != name2->length)
425*1fb015a8Sflorian 		return (0);
4265185a700Sflorian 
4275185a700Sflorian 	l = name1->labels;
4285185a700Sflorian 
4295185a700Sflorian 	if (l != name2->labels)
430*1fb015a8Sflorian 		return (0);
4315185a700Sflorian 
4325185a700Sflorian 	label1 = name1->ndata;
4335185a700Sflorian 	label2 = name2->ndata;
4345185a700Sflorian 	while (l-- > 0) {
4355185a700Sflorian 		count = *label1++;
4365185a700Sflorian 		if (count != *label2++)
437*1fb015a8Sflorian 			return (0);
4385185a700Sflorian 
4395185a700Sflorian 		INSIST(count <= 63); /* no bitstring support */
4405185a700Sflorian 
4415185a700Sflorian 		/* Loop unrolled for performance */
4425185a700Sflorian 		while (count > 3) {
4435185a700Sflorian 			c = maptolower[label1[0]];
4445185a700Sflorian 			if (c != maptolower[label2[0]])
445*1fb015a8Sflorian 				return (0);
4465185a700Sflorian 			c = maptolower[label1[1]];
4475185a700Sflorian 			if (c != maptolower[label2[1]])
448*1fb015a8Sflorian 				return (0);
4495185a700Sflorian 			c = maptolower[label1[2]];
4505185a700Sflorian 			if (c != maptolower[label2[2]])
451*1fb015a8Sflorian 				return (0);
4525185a700Sflorian 			c = maptolower[label1[3]];
4535185a700Sflorian 			if (c != maptolower[label2[3]])
454*1fb015a8Sflorian 				return (0);
4555185a700Sflorian 			count -= 4;
4565185a700Sflorian 			label1 += 4;
4575185a700Sflorian 			label2 += 4;
4585185a700Sflorian 		}
4595185a700Sflorian 		while (count-- > 0) {
4605185a700Sflorian 			c = maptolower[*label1++];
4615185a700Sflorian 			if (c != maptolower[*label2++])
462*1fb015a8Sflorian 				return (0);
4635185a700Sflorian 		}
4645185a700Sflorian 	}
4655185a700Sflorian 
466*1fb015a8Sflorian 	return (1);
4675185a700Sflorian }
4685185a700Sflorian 
469*1fb015a8Sflorian int
dns_name_caseequal(const dns_name_t * name1,const dns_name_t * name2)4705185a700Sflorian dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
4715185a700Sflorian 
4725185a700Sflorian 	/*
4735185a700Sflorian 	 * Are 'name1' and 'name2' equal?
4745185a700Sflorian 	 *
4755185a700Sflorian 	 * Note: It makes no sense for one of the names to be relative and the
4765185a700Sflorian 	 * other absolute.  If both names are relative, then to be meaningfully
4775185a700Sflorian 	 * compared the caller must ensure that they are both relative to the
4785185a700Sflorian 	 * same domain.
4795185a700Sflorian 	 */
4805185a700Sflorian 
4815185a700Sflorian 	/*
4825185a700Sflorian 	 * Either name1 is absolute and name2 is absolute, or neither is.
4835185a700Sflorian 	 */
4845185a700Sflorian 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
4855185a700Sflorian 		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
4865185a700Sflorian 
4875185a700Sflorian 	if (name1->length != name2->length)
488*1fb015a8Sflorian 		return (0);
4895185a700Sflorian 
4905185a700Sflorian 	if (memcmp(name1->ndata, name2->ndata, name1->length) != 0)
491*1fb015a8Sflorian 		return (0);
4925185a700Sflorian 
493*1fb015a8Sflorian 	return (1);
4945185a700Sflorian }
4955185a700Sflorian 
496*1fb015a8Sflorian int
dns_name_issubdomain(const dns_name_t * name1,const dns_name_t * name2)4975185a700Sflorian dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
4985185a700Sflorian 	int order;
4995185a700Sflorian 	unsigned int nlabels;
5005185a700Sflorian 	dns_namereln_t namereln;
5015185a700Sflorian 
5025185a700Sflorian 	/*
5035185a700Sflorian 	 * Is 'name1' a subdomain of 'name2'?
5045185a700Sflorian 	 *
5055185a700Sflorian 	 * Note: It makes no sense for one of the names to be relative and the
5065185a700Sflorian 	 * other absolute.  If both names are relative, then to be meaningfully
5075185a700Sflorian 	 * compared the caller must ensure that they are both relative to the
5085185a700Sflorian 	 * same domain.
5095185a700Sflorian 	 */
5105185a700Sflorian 
5115185a700Sflorian 	namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
5125185a700Sflorian 	if (namereln == dns_namereln_subdomain ||
5135185a700Sflorian 	    namereln == dns_namereln_equal)
514*1fb015a8Sflorian 		return (1);
5155185a700Sflorian 
516*1fb015a8Sflorian 	return (0);
5175185a700Sflorian }
5185185a700Sflorian 
5195185a700Sflorian unsigned int
dns_name_countlabels(const dns_name_t * name)5205185a700Sflorian dns_name_countlabels(const dns_name_t *name) {
5215185a700Sflorian 	/*
5225185a700Sflorian 	 * How many labels does 'name' have?
5235185a700Sflorian 	 */
5245185a700Sflorian 
5255185a700Sflorian 	ENSURE(name->labels <= 128);
5265185a700Sflorian 
5275185a700Sflorian 	return (name->labels);
5285185a700Sflorian }
5295185a700Sflorian 
5305185a700Sflorian void
dns_name_getlabel(const dns_name_t * name,unsigned int n,dns_label_t * label)5315185a700Sflorian dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
5325185a700Sflorian 	unsigned char *offsets;
5335185a700Sflorian 	dns_offsets_t odata;
5345185a700Sflorian 
5355185a700Sflorian 	/*
5365185a700Sflorian 	 * Make 'label' refer to the 'n'th least significant label of 'name'.
5375185a700Sflorian 	 */
5385185a700Sflorian 
5395185a700Sflorian 	REQUIRE(name->labels > 0);
5405185a700Sflorian 	REQUIRE(n < name->labels);
5415185a700Sflorian 	REQUIRE(label != NULL);
5425185a700Sflorian 
5435185a700Sflorian 	SETUP_OFFSETS(name, offsets, odata);
5445185a700Sflorian 
5455185a700Sflorian 	label->base = &name->ndata[offsets[n]];
5465185a700Sflorian 	if (n == name->labels - 1)
5475185a700Sflorian 		label->length = name->length - offsets[n];
5485185a700Sflorian 	else
5495185a700Sflorian 		label->length = offsets[n + 1] - offsets[n];
5505185a700Sflorian }
5515185a700Sflorian 
5525185a700Sflorian void
dns_name_getlabelsequence(const dns_name_t * source,unsigned int first,unsigned int n,dns_name_t * target)5535185a700Sflorian dns_name_getlabelsequence(const dns_name_t *source,
5545185a700Sflorian 			  unsigned int first, unsigned int n,
5555185a700Sflorian 			  dns_name_t *target)
5565185a700Sflorian {
5575185a700Sflorian 	unsigned char *offsets;
5585185a700Sflorian 	dns_offsets_t odata;
5595185a700Sflorian 	unsigned int firstoffset, endoffset;
5605185a700Sflorian 
5615185a700Sflorian 	/*
5625185a700Sflorian 	 * Make 'target' refer to the 'n' labels including and following
5635185a700Sflorian 	 * 'first' in 'source'.
5645185a700Sflorian 	 */
5655185a700Sflorian 
5665185a700Sflorian 	REQUIRE(first <= source->labels);
5675185a700Sflorian 	REQUIRE(n <= source->labels - first); /* note first+n could overflow */
5685185a700Sflorian 	REQUIRE(BINDABLE(target));
5695185a700Sflorian 
5705185a700Sflorian 	SETUP_OFFSETS(source, offsets, odata);
5715185a700Sflorian 
5725185a700Sflorian 	if (first == source->labels)
5735185a700Sflorian 		firstoffset = source->length;
5745185a700Sflorian 	else
5755185a700Sflorian 		firstoffset = offsets[first];
5765185a700Sflorian 
5775185a700Sflorian 	if (first + n == source->labels)
5785185a700Sflorian 		endoffset = source->length;
5795185a700Sflorian 	else
5805185a700Sflorian 		endoffset = offsets[first + n];
5815185a700Sflorian 
5825185a700Sflorian 	target->ndata = &source->ndata[firstoffset];
5835185a700Sflorian 	target->length = endoffset - firstoffset;
5845185a700Sflorian 
5855185a700Sflorian 	if (first + n == source->labels && n > 0 &&
5865185a700Sflorian 	    (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
5875185a700Sflorian 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
5885185a700Sflorian 	else
5895185a700Sflorian 		target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
5905185a700Sflorian 
5915185a700Sflorian 	target->labels = n;
5925185a700Sflorian 
5935185a700Sflorian 	/*
5945185a700Sflorian 	 * If source and target are the same, and we're making target
5955185a700Sflorian 	 * a prefix of source, the offsets table is correct already
5965185a700Sflorian 	 * so we don't need to call set_offsets().
5975185a700Sflorian 	 */
5985185a700Sflorian 	if (target->offsets != NULL &&
5995185a700Sflorian 	    (target != source || first != 0))
6005185a700Sflorian 		set_offsets(target, target->offsets, NULL);
6015185a700Sflorian }
6025185a700Sflorian 
6035185a700Sflorian void
dns_name_clone(const dns_name_t * source,dns_name_t * target)6045185a700Sflorian dns_name_clone(const dns_name_t *source, dns_name_t *target) {
6055185a700Sflorian 
6065185a700Sflorian 	/*
6075185a700Sflorian 	 * Make 'target' refer to the same name as 'source'.
6085185a700Sflorian 	 */
6095185a700Sflorian 
6105185a700Sflorian 	REQUIRE(BINDABLE(target));
6115185a700Sflorian 
6125185a700Sflorian 	target->ndata = source->ndata;
6135185a700Sflorian 	target->length = source->length;
6145185a700Sflorian 	target->labels = source->labels;
6155185a700Sflorian 	target->attributes = source->attributes &
6165185a700Sflorian 		(unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC |
6175185a700Sflorian 				DNS_NAMEATTR_DYNOFFSETS);
6185185a700Sflorian 	if (target->offsets != NULL && source->labels > 0) {
6195185a700Sflorian 		if (source->offsets != NULL)
6205185a700Sflorian 			memmove(target->offsets, source->offsets,
6215185a700Sflorian 				source->labels);
6225185a700Sflorian 		else
6235185a700Sflorian 			set_offsets(target, target->offsets, NULL);
6245185a700Sflorian 	}
6255185a700Sflorian }
6265185a700Sflorian 
6275185a700Sflorian void
dns_name_fromregion(dns_name_t * name,const isc_region_t * r)6285185a700Sflorian dns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
6295185a700Sflorian 	unsigned char *offsets;
6305185a700Sflorian 	dns_offsets_t odata;
6315185a700Sflorian 	unsigned int len;
6325185a700Sflorian 	isc_region_t r2;
6335185a700Sflorian 
6345185a700Sflorian 	/*
6355185a700Sflorian 	 * Make 'name' refer to region 'r'.
6365185a700Sflorian 	 */
6375185a700Sflorian 
6385185a700Sflorian 	REQUIRE(r != NULL);
6395185a700Sflorian 	REQUIRE(BINDABLE(name));
6405185a700Sflorian 
6415185a700Sflorian 	INIT_OFFSETS(name, offsets, odata);
6425185a700Sflorian 
6435185a700Sflorian 	if (name->buffer != NULL) {
6445185a700Sflorian 		isc_buffer_clear(name->buffer);
6455185a700Sflorian 		isc_buffer_availableregion(name->buffer, &r2);
6465185a700Sflorian 		len = (r->length < r2.length) ? r->length : r2.length;
6475185a700Sflorian 		if (len > DNS_NAME_MAXWIRE)
6485185a700Sflorian 			len = DNS_NAME_MAXWIRE;
6495185a700Sflorian 		if (len != 0)
6505185a700Sflorian 			memmove(r2.base, r->base, len);
6515185a700Sflorian 		name->ndata = r2.base;
6525185a700Sflorian 		name->length = len;
6535185a700Sflorian 	} else {
6545185a700Sflorian 		name->ndata = r->base;
6555185a700Sflorian 		name->length = (r->length <= DNS_NAME_MAXWIRE) ?
6565185a700Sflorian 			r->length : DNS_NAME_MAXWIRE;
6575185a700Sflorian 	}
6585185a700Sflorian 
6595185a700Sflorian 	if (r->length > 0)
6605185a700Sflorian 		set_offsets(name, offsets, name);
6615185a700Sflorian 	else {
6625185a700Sflorian 		name->labels = 0;
6635185a700Sflorian 		name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
6645185a700Sflorian 	}
6655185a700Sflorian 
6665185a700Sflorian 	if (name->buffer != NULL)
6675185a700Sflorian 		isc_buffer_add(name->buffer, name->length);
6685185a700Sflorian }
6695185a700Sflorian 
6705185a700Sflorian void
dns_name_toregion(dns_name_t * name,isc_region_t * r)6715185a700Sflorian dns_name_toregion(dns_name_t *name, isc_region_t *r) {
6725185a700Sflorian 	/*
6735185a700Sflorian 	 * Make 'r' refer to 'name'.
6745185a700Sflorian 	 */
6755185a700Sflorian 
6765185a700Sflorian 	REQUIRE(r != NULL);
6775185a700Sflorian 
678f1dacf25Sflorian 	r->base = name->ndata;
679f1dacf25Sflorian 	r->length = name->length;
6805185a700Sflorian }
6815185a700Sflorian 
6825185a700Sflorian isc_result_t
dns_name_fromtext(dns_name_t * name,isc_buffer_t * source,const dns_name_t * origin,unsigned int options,isc_buffer_t * target)6835185a700Sflorian dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
6845185a700Sflorian 		  const dns_name_t *origin, unsigned int options,
6855185a700Sflorian 		  isc_buffer_t *target)
6865185a700Sflorian {
6875185a700Sflorian 	unsigned char *ndata, *label = NULL;
6885185a700Sflorian 	char *tdata;
6895185a700Sflorian 	char c;
6905185a700Sflorian 	ft_state state;
6915185a700Sflorian 	unsigned int value = 0, count = 0;
6925185a700Sflorian 	unsigned int n1 = 0, n2 = 0;
6935185a700Sflorian 	unsigned int tlen, nrem, nused, digits = 0, labels, tused;
694*1fb015a8Sflorian 	int done;
6955185a700Sflorian 	unsigned char *offsets;
6965185a700Sflorian 	dns_offsets_t odata;
697*1fb015a8Sflorian 	int downcase;
6985185a700Sflorian 
6995185a700Sflorian 	/*
7005185a700Sflorian 	 * Convert the textual representation of a DNS name at source
7015185a700Sflorian 	 * into uncompressed wire form stored in target.
7025185a700Sflorian 	 *
7035185a700Sflorian 	 * Notes:
7045185a700Sflorian 	 *	Relative domain names will have 'origin' appended to them
7055185a700Sflorian 	 *	unless 'origin' is NULL, in which case relative domain names
7065185a700Sflorian 	 *	will remain relative.
7075185a700Sflorian 	 */
7085185a700Sflorian 
709*1fb015a8Sflorian 	downcase = (options & DNS_NAME_DOWNCASE) != 0;
7105185a700Sflorian 
7115185a700Sflorian 	if (target == NULL && name->buffer != NULL) {
7125185a700Sflorian 		target = name->buffer;
7135185a700Sflorian 		isc_buffer_clear(target);
7145185a700Sflorian 	}
7155185a700Sflorian 
7165185a700Sflorian 	REQUIRE(BINDABLE(name));
7175185a700Sflorian 
7185185a700Sflorian 	INIT_OFFSETS(name, offsets, odata);
7195185a700Sflorian 	offsets[0] = 0;
7205185a700Sflorian 
7215185a700Sflorian 	/*
7225185a700Sflorian 	 * Make 'name' empty in case of failure.
7235185a700Sflorian 	 */
7245185a700Sflorian 	MAKE_EMPTY(name);
7255185a700Sflorian 
7265185a700Sflorian 	/*
7275185a700Sflorian 	 * Set up the state machine.
7285185a700Sflorian 	 */
7295185a700Sflorian 	tdata = (char *)source->base + source->current;
7305185a700Sflorian 	tlen = isc_buffer_remaininglength(source);
7315185a700Sflorian 	tused = 0;
7325185a700Sflorian 	ndata = isc_buffer_used(target);
7335185a700Sflorian 	nrem = isc_buffer_availablelength(target);
7345185a700Sflorian 	if (nrem > 255)
7355185a700Sflorian 		nrem = 255;
7365185a700Sflorian 	nused = 0;
7375185a700Sflorian 	labels = 0;
738*1fb015a8Sflorian 	done = 0;
7395185a700Sflorian 	state = ft_init;
7405185a700Sflorian 
7415185a700Sflorian 	while (nrem > 0 && tlen > 0 && !done) {
7425185a700Sflorian 		c = *tdata++;
7435185a700Sflorian 		tlen--;
7445185a700Sflorian 		tused++;
7455185a700Sflorian 
7465185a700Sflorian 		switch (state) {
7475185a700Sflorian 		case ft_init:
7485185a700Sflorian 			/*
7495185a700Sflorian 			 * Is this the root name?
7505185a700Sflorian 			 */
7515185a700Sflorian 			if (c == '.') {
7525185a700Sflorian 				if (tlen != 0)
7535185a700Sflorian 					return (DNS_R_EMPTYLABEL);
7545185a700Sflorian 				labels++;
7555185a700Sflorian 				*ndata++ = 0;
7565185a700Sflorian 				nrem--;
7575185a700Sflorian 				nused++;
758*1fb015a8Sflorian 				done = 1;
7595185a700Sflorian 				break;
7605185a700Sflorian 			}
7615185a700Sflorian 			if (c == '@' && tlen == 0) {
7625185a700Sflorian 				state = ft_at;
7635185a700Sflorian 				break;
7645185a700Sflorian 			}
7655185a700Sflorian 
7665185a700Sflorian 			/* FALLTHROUGH */
7675185a700Sflorian 		case ft_start:
7685185a700Sflorian 			label = ndata;
7695185a700Sflorian 			ndata++;
7705185a700Sflorian 			nrem--;
7715185a700Sflorian 			nused++;
7725185a700Sflorian 			count = 0;
7735185a700Sflorian 			if (c == '\\') {
7745185a700Sflorian 				state = ft_initialescape;
7755185a700Sflorian 				break;
7765185a700Sflorian 			}
7775185a700Sflorian 			state = ft_ordinary;
7785185a700Sflorian 			if (nrem == 0)
7795185a700Sflorian 				return (ISC_R_NOSPACE);
7805185a700Sflorian 			/* FALLTHROUGH */
7815185a700Sflorian 		case ft_ordinary:
7825185a700Sflorian 			if (c == '.') {
7835185a700Sflorian 				if (count == 0)
7845185a700Sflorian 					return (DNS_R_EMPTYLABEL);
7855185a700Sflorian 				*label = count;
7865185a700Sflorian 				labels++;
7875185a700Sflorian 				INSIST(labels <= 127);
7885185a700Sflorian 				offsets[labels] = nused;
7895185a700Sflorian 				if (tlen == 0) {
7905185a700Sflorian 					labels++;
7915185a700Sflorian 					*ndata++ = 0;
7925185a700Sflorian 					nrem--;
7935185a700Sflorian 					nused++;
794*1fb015a8Sflorian 					done = 1;
7955185a700Sflorian 				}
7965185a700Sflorian 				state = ft_start;
7975185a700Sflorian 			} else if (c == '\\') {
7985185a700Sflorian 				state = ft_escape;
7995185a700Sflorian 			} else {
8005185a700Sflorian 				if (count >= 63)
8015185a700Sflorian 					return (DNS_R_LABELTOOLONG);
8025185a700Sflorian 				count++;
8035185a700Sflorian 				CONVERTTOASCII(c);
8045185a700Sflorian 				if (downcase)
8055185a700Sflorian 					c = maptolower[c & 0xff];
8065185a700Sflorian 				*ndata++ = c;
8075185a700Sflorian 				nrem--;
8085185a700Sflorian 				nused++;
8095185a700Sflorian 			}
8105185a700Sflorian 			break;
8115185a700Sflorian 		case ft_initialescape:
8125185a700Sflorian 			if (c == '[') {
8135185a700Sflorian 				/*
8145185a700Sflorian 				 * This looks like a bitstring label, which
8155185a700Sflorian 				 * was deprecated.  Intentionally drop it.
8165185a700Sflorian 				 */
8175185a700Sflorian 				return (DNS_R_BADLABELTYPE);
8185185a700Sflorian 			}
8195185a700Sflorian 			state = ft_escape;
8205185a700Sflorian 			POST(state);
8215185a700Sflorian 			/* FALLTHROUGH */
8225185a700Sflorian 		case ft_escape:
8235185a700Sflorian 			if (!isdigit(c & 0xff)) {
8245185a700Sflorian 				if (count >= 63)
8255185a700Sflorian 					return (DNS_R_LABELTOOLONG);
8265185a700Sflorian 				count++;
8275185a700Sflorian 				CONVERTTOASCII(c);
8285185a700Sflorian 				if (downcase)
8295185a700Sflorian 					c = maptolower[c & 0xff];
8305185a700Sflorian 				*ndata++ = c;
8315185a700Sflorian 				nrem--;
8325185a700Sflorian 				nused++;
8335185a700Sflorian 				state = ft_ordinary;
8345185a700Sflorian 				break;
8355185a700Sflorian 			}
8365185a700Sflorian 			digits = 0;
8375185a700Sflorian 			value = 0;
8385185a700Sflorian 			state = ft_escdecimal;
8395185a700Sflorian 			/* FALLTHROUGH */
8405185a700Sflorian 		case ft_escdecimal:
8415185a700Sflorian 			if (!isdigit(c & 0xff))
8425185a700Sflorian 				return (DNS_R_BADESCAPE);
8435185a700Sflorian 			value *= 10;
8445185a700Sflorian 			value += digitvalue[c & 0xff];
8455185a700Sflorian 			digits++;
8465185a700Sflorian 			if (digits == 3) {
8475185a700Sflorian 				if (value > 255)
8485185a700Sflorian 					return (DNS_R_BADESCAPE);
8495185a700Sflorian 				if (count >= 63)
8505185a700Sflorian 					return (DNS_R_LABELTOOLONG);
8515185a700Sflorian 				count++;
8525185a700Sflorian 				if (downcase)
8535185a700Sflorian 					value = maptolower[value];
8545185a700Sflorian 				*ndata++ = value;
8555185a700Sflorian 				nrem--;
8565185a700Sflorian 				nused++;
8575185a700Sflorian 				state = ft_ordinary;
8585185a700Sflorian 			}
8595185a700Sflorian 			break;
8605185a700Sflorian 		default:
8615185a700Sflorian 			FATAL_ERROR(__FILE__, __LINE__,
8625185a700Sflorian 				    "Unexpected state %d", state);
8635185a700Sflorian 			/* Does not return. */
8645185a700Sflorian 		}
8655185a700Sflorian 	}
8665185a700Sflorian 
8675185a700Sflorian 	if (!done) {
8685185a700Sflorian 		if (nrem == 0)
8695185a700Sflorian 			return (ISC_R_NOSPACE);
8705185a700Sflorian 		INSIST(tlen == 0);
8715185a700Sflorian 		if (state != ft_ordinary && state != ft_at)
8725185a700Sflorian 			return (ISC_R_UNEXPECTEDEND);
8735185a700Sflorian 		if (state == ft_ordinary) {
8745185a700Sflorian 			INSIST(count != 0);
8755185a700Sflorian 			*label = count;
8765185a700Sflorian 			labels++;
8775185a700Sflorian 			INSIST(labels <= 127);
8785185a700Sflorian 			offsets[labels] = nused;
8795185a700Sflorian 		}
8805185a700Sflorian 		if (origin != NULL) {
8815185a700Sflorian 			if (nrem < origin->length)
8825185a700Sflorian 				return (ISC_R_NOSPACE);
8835185a700Sflorian 			label = origin->ndata;
8845185a700Sflorian 			n1 = origin->length;
8855185a700Sflorian 			nrem -= n1;
8865185a700Sflorian 			POST(nrem);
8875185a700Sflorian 			while (n1 > 0) {
8885185a700Sflorian 				n2 = *label++;
8895185a700Sflorian 				INSIST(n2 <= 63); /* no bitstring support */
8905185a700Sflorian 				*ndata++ = n2;
8915185a700Sflorian 				n1 -= n2 + 1;
8925185a700Sflorian 				nused += n2 + 1;
8935185a700Sflorian 				while (n2 > 0) {
8945185a700Sflorian 					c = *label++;
8955185a700Sflorian 					if (downcase)
8965185a700Sflorian 						c = maptolower[c & 0xff];
8975185a700Sflorian 					*ndata++ = c;
8985185a700Sflorian 					n2--;
8995185a700Sflorian 				}
9005185a700Sflorian 				labels++;
9015185a700Sflorian 				if (n1 > 0) {
9025185a700Sflorian 					INSIST(labels <= 127);
9035185a700Sflorian 					offsets[labels] = nused;
9045185a700Sflorian 				}
9055185a700Sflorian 			}
9065185a700Sflorian 			if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
9075185a700Sflorian 				name->attributes |= DNS_NAMEATTR_ABSOLUTE;
9085185a700Sflorian 		}
9095185a700Sflorian 	} else
9105185a700Sflorian 		name->attributes |= DNS_NAMEATTR_ABSOLUTE;
9115185a700Sflorian 
9125185a700Sflorian 	name->ndata = (unsigned char *)target->base + target->used;
9135185a700Sflorian 	name->labels = labels;
9145185a700Sflorian 	name->length = nused;
9155185a700Sflorian 
9165185a700Sflorian 	isc_buffer_forward(source, tused);
9175185a700Sflorian 	isc_buffer_add(target, name->length);
9185185a700Sflorian 
9195185a700Sflorian 	return (ISC_R_SUCCESS);
9205185a700Sflorian }
9215185a700Sflorian 
9225185a700Sflorian isc_result_t
dns_name_totext(dns_name_t * name,int omit_final_dot,isc_buffer_t * target)923*1fb015a8Sflorian dns_name_totext(dns_name_t *name, int omit_final_dot,
9245185a700Sflorian 		isc_buffer_t *target)
9255185a700Sflorian {
9265185a700Sflorian 	unsigned int options = DNS_NAME_MASTERFILE;
9275185a700Sflorian 
9285185a700Sflorian 	if (omit_final_dot)
9295185a700Sflorian 		options |= DNS_NAME_OMITFINALDOT;
9305185a700Sflorian 	return (dns_name_totext2(name, options, target));
9315185a700Sflorian }
9325185a700Sflorian 
9335185a700Sflorian isc_result_t
dns_name_totext2(dns_name_t * name,unsigned int options,isc_buffer_t * target)9345185a700Sflorian dns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target)
9355185a700Sflorian {
9365185a700Sflorian 	unsigned char *ndata;
9375185a700Sflorian 	char *tdata;
9385185a700Sflorian 	unsigned int nlen, tlen;
9395185a700Sflorian 	unsigned char c;
9405185a700Sflorian 	unsigned int trem, count;
9415185a700Sflorian 	unsigned int labels;
942*1fb015a8Sflorian 	int saw_root = 0;
943*1fb015a8Sflorian 	int omit_final_dot = options & DNS_NAME_OMITFINALDOT;
9445185a700Sflorian 
9455185a700Sflorian 	/*
9465185a700Sflorian 	 * This function assumes the name is in proper uncompressed
9475185a700Sflorian 	 * wire format.
9485185a700Sflorian 	 */
9495185a700Sflorian 
9505185a700Sflorian 	ndata = name->ndata;
9515185a700Sflorian 	nlen = name->length;
9525185a700Sflorian 	labels = name->labels;
9535185a700Sflorian 	tdata = isc_buffer_used(target);
9545185a700Sflorian 	tlen = isc_buffer_availablelength(target);
9555185a700Sflorian 
9565185a700Sflorian 	trem = tlen;
9575185a700Sflorian 
9585185a700Sflorian 	if (labels == 0 && nlen == 0) {
9595185a700Sflorian 		/*
9605185a700Sflorian 		 * Special handling for an empty name.
9615185a700Sflorian 		 */
9625185a700Sflorian 		if (trem == 0)
9635185a700Sflorian 			return (ISC_R_NOSPACE);
9645185a700Sflorian 
9655185a700Sflorian 		/*
9665185a700Sflorian 		 * The names of these booleans are misleading in this case.
9675185a700Sflorian 		 * This empty name is not necessarily from the root node of
9685185a700Sflorian 		 * the DNS root zone, nor is a final dot going to be included.
9695185a700Sflorian 		 * They need to be set this way, though, to keep the "@"
9705185a700Sflorian 		 * from being trounced.
9715185a700Sflorian 		 */
972*1fb015a8Sflorian 		saw_root = 1;
973*1fb015a8Sflorian 		omit_final_dot = 0;
9745185a700Sflorian 		*tdata++ = '@';
9755185a700Sflorian 		trem--;
9765185a700Sflorian 
9775185a700Sflorian 		/*
9785185a700Sflorian 		 * Skip the while() loop.
9795185a700Sflorian 		 */
9805185a700Sflorian 		nlen = 0;
9815185a700Sflorian 	} else if (nlen == 1 && labels == 1 && *ndata == '\0') {
9825185a700Sflorian 		/*
9835185a700Sflorian 		 * Special handling for the root label.
9845185a700Sflorian 		 */
9855185a700Sflorian 		if (trem == 0)
9865185a700Sflorian 			return (ISC_R_NOSPACE);
9875185a700Sflorian 
988*1fb015a8Sflorian 		saw_root = 1;
989*1fb015a8Sflorian 		omit_final_dot = 0;
9905185a700Sflorian 		*tdata++ = '.';
9915185a700Sflorian 		trem--;
9925185a700Sflorian 
9935185a700Sflorian 		/*
9945185a700Sflorian 		 * Skip the while() loop.
9955185a700Sflorian 		 */
9965185a700Sflorian 		nlen = 0;
9975185a700Sflorian 	}
9985185a700Sflorian 
9995185a700Sflorian 	while (labels > 0 && nlen > 0 && trem > 0) {
10005185a700Sflorian 		labels--;
10015185a700Sflorian 		count = *ndata++;
10025185a700Sflorian 		nlen--;
10035185a700Sflorian 		if (count == 0) {
1004*1fb015a8Sflorian 			saw_root = 1;
10055185a700Sflorian 			break;
10065185a700Sflorian 		}
10075185a700Sflorian 		if (count < 64) {
10085185a700Sflorian 			INSIST(nlen >= count);
10095185a700Sflorian 			while (count > 0) {
10105185a700Sflorian 				c = *ndata;
10115185a700Sflorian 				switch (c) {
10125185a700Sflorian 				/* Special modifiers in zone files. */
10135185a700Sflorian 				case 0x40: /* '@' */
10145185a700Sflorian 				case 0x24: /* '$' */
10155185a700Sflorian 					if ((options & DNS_NAME_MASTERFILE) == 0)
10165185a700Sflorian 						goto no_escape;
10175185a700Sflorian 					/* FALLTHROUGH */
10185185a700Sflorian 				case 0x22: /* '"' */
10195185a700Sflorian 				case 0x28: /* '(' */
10205185a700Sflorian 				case 0x29: /* ')' */
10215185a700Sflorian 				case 0x2E: /* '.' */
10225185a700Sflorian 				case 0x3B: /* ';' */
10235185a700Sflorian 				case 0x5C: /* '\\' */
10245185a700Sflorian 					if (trem < 2)
10255185a700Sflorian 						return (ISC_R_NOSPACE);
10265185a700Sflorian 					*tdata++ = '\\';
10275185a700Sflorian 					CONVERTFROMASCII(c);
10285185a700Sflorian 					*tdata++ = c;
10295185a700Sflorian 					ndata++;
10305185a700Sflorian 					trem -= 2;
10315185a700Sflorian 					nlen--;
10325185a700Sflorian 					break;
10335185a700Sflorian 				no_escape:
10345185a700Sflorian 				default:
10355185a700Sflorian 					if (c > 0x20 && c < 0x7f) {
10365185a700Sflorian 						if (trem == 0)
10375185a700Sflorian 							return (ISC_R_NOSPACE);
10385185a700Sflorian 						CONVERTFROMASCII(c);
10395185a700Sflorian 						*tdata++ = c;
10405185a700Sflorian 						ndata++;
10415185a700Sflorian 						trem--;
10425185a700Sflorian 						nlen--;
10435185a700Sflorian 					} else {
10445185a700Sflorian 						if (trem < 4)
10455185a700Sflorian 							return (ISC_R_NOSPACE);
10465185a700Sflorian 						*tdata++ = 0x5c;
10475185a700Sflorian 						*tdata++ = 0x30 +
10485185a700Sflorian 							   ((c / 100) % 10);
10495185a700Sflorian 						*tdata++ = 0x30 +
10505185a700Sflorian 							   ((c / 10) % 10);
10515185a700Sflorian 						*tdata++ = 0x30 + (c % 10);
10525185a700Sflorian 						trem -= 4;
10535185a700Sflorian 						ndata++;
10545185a700Sflorian 						nlen--;
10555185a700Sflorian 					}
10565185a700Sflorian 				}
10575185a700Sflorian 				count--;
10585185a700Sflorian 			}
10595185a700Sflorian 		} else {
10605185a700Sflorian 			FATAL_ERROR(__FILE__, __LINE__,
10615185a700Sflorian 				    "Unexpected label type %02x", count);
10625185a700Sflorian 			/* NOTREACHED */
10635185a700Sflorian 		}
10645185a700Sflorian 
10655185a700Sflorian 		/*
10665185a700Sflorian 		 * The following assumes names are absolute.  If not, we
10675185a700Sflorian 		 * fix things up later.  Note that this means that in some
10685185a700Sflorian 		 * cases one more byte of text buffer is required than is
10695185a700Sflorian 		 * needed in the final output.
10705185a700Sflorian 		 */
10715185a700Sflorian 		if (trem == 0)
10725185a700Sflorian 			return (ISC_R_NOSPACE);
10735185a700Sflorian 		*tdata++ = '.';
10745185a700Sflorian 		trem--;
10755185a700Sflorian 	}
10765185a700Sflorian 
10775185a700Sflorian 	if (nlen != 0 && trem == 0)
10785185a700Sflorian 		return (ISC_R_NOSPACE);
10795185a700Sflorian 
10805185a700Sflorian 	if (!saw_root || omit_final_dot)
10815185a700Sflorian 		trem++;
10825185a700Sflorian 
10835185a700Sflorian 	isc_buffer_add(target, tlen - trem);
10845185a700Sflorian 
10855185a700Sflorian 	return (ISC_R_SUCCESS);
10865185a700Sflorian }
10875185a700Sflorian 
10885185a700Sflorian isc_result_t
dns_name_downcase(dns_name_t * source,dns_name_t * name,isc_buffer_t * target)10895185a700Sflorian dns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) {
10905185a700Sflorian 	unsigned char *sndata, *ndata;
10915185a700Sflorian 	unsigned int nlen, count, labels;
10925185a700Sflorian 	isc_buffer_t buffer;
10935185a700Sflorian 
10945185a700Sflorian 	/*
10955185a700Sflorian 	 * Downcase 'source'.
10965185a700Sflorian 	 */
10975185a700Sflorian 
10985185a700Sflorian 	if (source == name) {
10995185a700Sflorian 		REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
11005185a700Sflorian 		isc_buffer_init(&buffer, source->ndata, source->length);
11015185a700Sflorian 		target = &buffer;
11025185a700Sflorian 		ndata = source->ndata;
11035185a700Sflorian 	} else {
11045185a700Sflorian 		REQUIRE(BINDABLE(name));
11055185a700Sflorian 		if (target == NULL) {
11065185a700Sflorian 			target = name->buffer;
11075185a700Sflorian 			isc_buffer_clear(name->buffer);
11085185a700Sflorian 		}
11095185a700Sflorian 		ndata = (unsigned char *)target->base + target->used;
11105185a700Sflorian 		name->ndata = ndata;
11115185a700Sflorian 	}
11125185a700Sflorian 
11135185a700Sflorian 	sndata = source->ndata;
11145185a700Sflorian 	nlen = source->length;
11155185a700Sflorian 	labels = source->labels;
11165185a700Sflorian 
11175185a700Sflorian 	if (nlen > (target->length - target->used)) {
11185185a700Sflorian 		MAKE_EMPTY(name);
11195185a700Sflorian 		return (ISC_R_NOSPACE);
11205185a700Sflorian 	}
11215185a700Sflorian 
11225185a700Sflorian 	while (labels > 0 && nlen > 0) {
11235185a700Sflorian 		labels--;
11245185a700Sflorian 		count = *sndata++;
11255185a700Sflorian 		*ndata++ = count;
11265185a700Sflorian 		nlen--;
11275185a700Sflorian 		if (count < 64) {
11285185a700Sflorian 			INSIST(nlen >= count);
11295185a700Sflorian 			while (count > 0) {
11305185a700Sflorian 				*ndata++ = maptolower[(*sndata++)];
11315185a700Sflorian 				nlen--;
11325185a700Sflorian 				count--;
11335185a700Sflorian 			}
11345185a700Sflorian 		} else {
11355185a700Sflorian 			FATAL_ERROR(__FILE__, __LINE__,
11365185a700Sflorian 				    "Unexpected label type %02x", count);
11375185a700Sflorian 			/* Does not return. */
11385185a700Sflorian 		}
11395185a700Sflorian 	}
11405185a700Sflorian 
11415185a700Sflorian 	if (source != name) {
11425185a700Sflorian 		name->labels = source->labels;
11435185a700Sflorian 		name->length = source->length;
11445185a700Sflorian 		if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
11455185a700Sflorian 			name->attributes = DNS_NAMEATTR_ABSOLUTE;
11465185a700Sflorian 		else
11475185a700Sflorian 			name->attributes = 0;
11485185a700Sflorian 		if (name->labels > 0 && name->offsets != NULL)
11495185a700Sflorian 			set_offsets(name, name->offsets, NULL);
11505185a700Sflorian 	}
11515185a700Sflorian 
11525185a700Sflorian 	isc_buffer_add(target, name->length);
11535185a700Sflorian 
11545185a700Sflorian 	return (ISC_R_SUCCESS);
11555185a700Sflorian }
11565185a700Sflorian 
11575185a700Sflorian static void
set_offsets(const dns_name_t * name,unsigned char * offsets,dns_name_t * set_name)11585185a700Sflorian set_offsets(const dns_name_t *name, unsigned char *offsets,
11595185a700Sflorian 	    dns_name_t *set_name)
11605185a700Sflorian {
11615185a700Sflorian 	unsigned int offset, count, length, nlabels;
11625185a700Sflorian 	unsigned char *ndata;
1163*1fb015a8Sflorian 	int absolute;
11645185a700Sflorian 
11655185a700Sflorian 	ndata = name->ndata;
11665185a700Sflorian 	length = name->length;
11675185a700Sflorian 	offset = 0;
11685185a700Sflorian 	nlabels = 0;
1169*1fb015a8Sflorian 	absolute = 0;
11705185a700Sflorian 	while (offset != length) {
11715185a700Sflorian 		INSIST(nlabels < 128);
11725185a700Sflorian 		offsets[nlabels++] = offset;
11735185a700Sflorian 		count = *ndata++;
11745185a700Sflorian 		offset++;
11755185a700Sflorian 		INSIST(count <= 63);
11765185a700Sflorian 		offset += count;
11775185a700Sflorian 		ndata += count;
11785185a700Sflorian 		INSIST(offset <= length);
11795185a700Sflorian 		if (count == 0) {
1180*1fb015a8Sflorian 			absolute = 1;
11815185a700Sflorian 			break;
11825185a700Sflorian 		}
11835185a700Sflorian 	}
11845185a700Sflorian 	if (set_name != NULL) {
11855185a700Sflorian 		INSIST(set_name == name);
11865185a700Sflorian 
11875185a700Sflorian 		set_name->labels = nlabels;
11885185a700Sflorian 		set_name->length = offset;
11895185a700Sflorian 		if (absolute)
11905185a700Sflorian 			set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
11915185a700Sflorian 		else
11925185a700Sflorian 			set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
11935185a700Sflorian 	}
11945185a700Sflorian 	INSIST(nlabels == name->labels);
11955185a700Sflorian 	INSIST(offset == name->length);
11965185a700Sflorian }
11975185a700Sflorian 
11985185a700Sflorian isc_result_t
dns_name_fromwire(dns_name_t * name,isc_buffer_t * source,dns_decompress_t * dctx,unsigned int options,isc_buffer_t * target)11995185a700Sflorian dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
12005185a700Sflorian 		  dns_decompress_t *dctx, unsigned int options,
12015185a700Sflorian 		  isc_buffer_t *target)
12025185a700Sflorian {
12035185a700Sflorian 	unsigned char *cdata, *ndata;
12045185a700Sflorian 	unsigned int cused; /* Bytes of compressed name data used */
12055185a700Sflorian 	unsigned int nused, labels, n, nmax;
12065185a700Sflorian 	unsigned int current, new_current, biggest_pointer;
1207*1fb015a8Sflorian 	int done;
12085185a700Sflorian 	fw_state state = fw_start;
12095185a700Sflorian 	unsigned int c;
12105185a700Sflorian 	unsigned char *offsets;
12115185a700Sflorian 	dns_offsets_t odata;
1212*1fb015a8Sflorian 	int downcase;
1213*1fb015a8Sflorian 	int seen_pointer;
12145185a700Sflorian 
12155185a700Sflorian 	/*
12165185a700Sflorian 	 * Copy the possibly-compressed name at source into target,
12175185a700Sflorian 	 * decompressing it.  Loop prevention is performed by checking
12185185a700Sflorian 	 * the new pointer against biggest_pointer.
12195185a700Sflorian 	 */
12205185a700Sflorian 
1221*1fb015a8Sflorian 	downcase = (options & DNS_NAME_DOWNCASE) != 0;
12225185a700Sflorian 
12235185a700Sflorian 	if (target == NULL && name->buffer != NULL) {
12245185a700Sflorian 		target = name->buffer;
12255185a700Sflorian 		isc_buffer_clear(target);
12265185a700Sflorian 	}
12275185a700Sflorian 
12285185a700Sflorian 	REQUIRE(dctx != NULL);
12295185a700Sflorian 	REQUIRE(BINDABLE(name));
12305185a700Sflorian 
12315185a700Sflorian 	INIT_OFFSETS(name, offsets, odata);
12325185a700Sflorian 
12335185a700Sflorian 	/*
12345185a700Sflorian 	 * Make 'name' empty in case of failure.
12355185a700Sflorian 	 */
12365185a700Sflorian 	MAKE_EMPTY(name);
12375185a700Sflorian 
12385185a700Sflorian 	/*
12395185a700Sflorian 	 * Initialize things to make the compiler happy; they're not required.
12405185a700Sflorian 	 */
12415185a700Sflorian 	n = 0;
12425185a700Sflorian 	new_current = 0;
12435185a700Sflorian 
12445185a700Sflorian 	/*
12455185a700Sflorian 	 * Set up.
12465185a700Sflorian 	 */
12475185a700Sflorian 	labels = 0;
1248*1fb015a8Sflorian 	done = 0;
12495185a700Sflorian 
12505185a700Sflorian 	ndata = isc_buffer_used(target);
12515185a700Sflorian 	nused = 0;
1252*1fb015a8Sflorian 	seen_pointer = 0;
12535185a700Sflorian 
12545185a700Sflorian 	/*
12555185a700Sflorian 	 * Find the maximum number of uncompressed target name
12565185a700Sflorian 	 * bytes we are willing to generate.  This is the smaller
12575185a700Sflorian 	 * of the available target buffer length and the
12585185a700Sflorian 	 * maximum legal domain name length (255).
12595185a700Sflorian 	 */
12605185a700Sflorian 	nmax = isc_buffer_availablelength(target);
12615185a700Sflorian 	if (nmax > DNS_NAME_MAXWIRE)
12625185a700Sflorian 		nmax = DNS_NAME_MAXWIRE;
12635185a700Sflorian 
12645185a700Sflorian 	cdata = isc_buffer_current(source);
12655185a700Sflorian 	cused = 0;
12665185a700Sflorian 
12675185a700Sflorian 	current = source->current;
12685185a700Sflorian 	biggest_pointer = current;
12695185a700Sflorian 
12705185a700Sflorian 	/*
12715185a700Sflorian 	 * Note:  The following code is not optimized for speed, but
12725185a700Sflorian 	 * rather for correctness.  Speed will be addressed in the future.
12735185a700Sflorian 	 */
12745185a700Sflorian 
12755185a700Sflorian 	while (current < source->active && !done) {
12765185a700Sflorian 		c = *cdata++;
12775185a700Sflorian 		current++;
12785185a700Sflorian 		if (!seen_pointer)
12795185a700Sflorian 			cused++;
12805185a700Sflorian 
12815185a700Sflorian 		switch (state) {
12825185a700Sflorian 		case fw_start:
12835185a700Sflorian 			if (c < 64) {
12845185a700Sflorian 				offsets[labels] = nused;
12855185a700Sflorian 				labels++;
12865185a700Sflorian 				if (nused + c + 1 > nmax)
12875185a700Sflorian 					goto full;
12885185a700Sflorian 				nused += c + 1;
12895185a700Sflorian 				*ndata++ = c;
12905185a700Sflorian 				if (c == 0)
1291*1fb015a8Sflorian 					done = 1;
12925185a700Sflorian 				n = c;
12935185a700Sflorian 				state = fw_ordinary;
12945185a700Sflorian 			} else if (c >= 128 && c < 192) {
12955185a700Sflorian 				/*
12965185a700Sflorian 				 * 14 bit local compression pointer.
12975185a700Sflorian 				 * Local compression is no longer an
12985185a700Sflorian 				 * IETF draft.
12995185a700Sflorian 				 */
13005185a700Sflorian 				return (DNS_R_BADLABELTYPE);
13015185a700Sflorian 			} else if (c >= 192) {
13025185a700Sflorian 				/*
13035185a700Sflorian 				 * Ordinary 14-bit pointer.
13045185a700Sflorian 				 */
13055185a700Sflorian 				if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
13065185a700Sflorian 				    0)
13075185a700Sflorian 					return (DNS_R_DISALLOWED);
13085185a700Sflorian 				new_current = c & 0x3F;
13095185a700Sflorian 				state = fw_newcurrent;
13105185a700Sflorian 			} else
13115185a700Sflorian 				return (DNS_R_BADLABELTYPE);
13125185a700Sflorian 			break;
13135185a700Sflorian 		case fw_ordinary:
13145185a700Sflorian 			if (downcase)
13155185a700Sflorian 				c = maptolower[c];
13165185a700Sflorian 			*ndata++ = c;
13175185a700Sflorian 			n--;
13185185a700Sflorian 			if (n == 0)
13195185a700Sflorian 				state = fw_start;
13205185a700Sflorian 			break;
13215185a700Sflorian 		case fw_newcurrent:
13225185a700Sflorian 			new_current *= 256;
13235185a700Sflorian 			new_current += c;
13245185a700Sflorian 			if (new_current >= biggest_pointer)
13255185a700Sflorian 				return (DNS_R_BADPOINTER);
13265185a700Sflorian 			biggest_pointer = new_current;
13275185a700Sflorian 			current = new_current;
13285185a700Sflorian 			cdata = (unsigned char *)source->base + current;
1329*1fb015a8Sflorian 			seen_pointer = 1;
13305185a700Sflorian 			state = fw_start;
13315185a700Sflorian 			break;
13325185a700Sflorian 		default:
13335185a700Sflorian 			FATAL_ERROR(__FILE__, __LINE__,
13345185a700Sflorian 				    "Unknown state %d", state);
13355185a700Sflorian 			/* Does not return. */
13365185a700Sflorian 		}
13375185a700Sflorian 	}
13385185a700Sflorian 
13395185a700Sflorian 	if (!done)
13405185a700Sflorian 		return (ISC_R_UNEXPECTEDEND);
13415185a700Sflorian 
13425185a700Sflorian 	name->ndata = (unsigned char *)target->base + target->used;
13435185a700Sflorian 	name->labels = labels;
13445185a700Sflorian 	name->length = nused;
13455185a700Sflorian 	name->attributes |= DNS_NAMEATTR_ABSOLUTE;
13465185a700Sflorian 
13475185a700Sflorian 	isc_buffer_forward(source, cused);
13485185a700Sflorian 	isc_buffer_add(target, name->length);
13495185a700Sflorian 
13505185a700Sflorian 	return (ISC_R_SUCCESS);
13515185a700Sflorian 
13525185a700Sflorian  full:
13535185a700Sflorian 	if (nmax == DNS_NAME_MAXWIRE)
13545185a700Sflorian 		/*
13555185a700Sflorian 		 * The name did not fit even though we had a buffer
13565185a700Sflorian 		 * big enough to fit a maximum-length name.
13575185a700Sflorian 		 */
13585185a700Sflorian 		return (DNS_R_NAMETOOLONG);
13595185a700Sflorian 	else
13605185a700Sflorian 		/*
13615185a700Sflorian 		 * The name might fit if only the caller could give us a
13625185a700Sflorian 		 * big enough buffer.
13635185a700Sflorian 		 */
13645185a700Sflorian 		return (ISC_R_NOSPACE);
13655185a700Sflorian }
13665185a700Sflorian 
13675185a700Sflorian isc_result_t
dns_name_towire(const dns_name_t * name,dns_compress_t * cctx,isc_buffer_t * target)13685185a700Sflorian dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
13695185a700Sflorian 		isc_buffer_t *target)
13705185a700Sflorian {
13715185a700Sflorian 	unsigned int methods;
13725185a700Sflorian 	uint16_t offset;
13735185a700Sflorian 	dns_name_t gp;	/* Global compression prefix */
1374*1fb015a8Sflorian 	int gf;	/* Global compression target found */
13755185a700Sflorian 	uint16_t go;	/* Global compression offset */
13765185a700Sflorian 	dns_offsets_t clo;
13775185a700Sflorian 	dns_name_t clname;
13785185a700Sflorian 
13795185a700Sflorian 	/*
13805185a700Sflorian 	 * Convert 'name' into wire format, compressing it as specified by the
13815185a700Sflorian 	 * compression context 'cctx', and storing the result in 'target'.
13825185a700Sflorian 	 */
13835185a700Sflorian 
13845185a700Sflorian 	REQUIRE(cctx != NULL);
13855185a700Sflorian 
13865185a700Sflorian 	/*
13875185a700Sflorian 	 * If 'name' doesn't have an offsets table, make a clone which
13885185a700Sflorian 	 * has one.
13895185a700Sflorian 	 */
13905185a700Sflorian 	if (name->offsets == NULL) {
1391f1dacf25Sflorian 		dns_name_init(&clname, clo);
13925185a700Sflorian 		dns_name_clone(name, &clname);
13935185a700Sflorian 		name = &clname;
13945185a700Sflorian 	}
1395f1dacf25Sflorian 	dns_name_init(&gp, NULL);
13965185a700Sflorian 
13975185a700Sflorian 	offset = target->used;	/*XXX*/
13985185a700Sflorian 
13995185a700Sflorian 	methods = dns_compress_getmethods(cctx);
14005185a700Sflorian 
14015185a700Sflorian 	if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
14025185a700Sflorian 	    (methods & DNS_COMPRESS_GLOBAL14) != 0)
14035185a700Sflorian 		gf = dns_compress_findglobal(cctx, name, &gp, &go);
14045185a700Sflorian 	else
1405*1fb015a8Sflorian 		gf = 0;
14065185a700Sflorian 
14075185a700Sflorian 	/*
14085185a700Sflorian 	 * If the offset is too high for 14 bit global compression, we're
14095185a700Sflorian 	 * out of luck.
14105185a700Sflorian 	 */
14115185a700Sflorian 	if (gf && go >= 0x4000)
1412*1fb015a8Sflorian 		gf = 0;
14135185a700Sflorian 
14145185a700Sflorian 	/*
14155185a700Sflorian 	 * Will the compression pointer reduce the message size?
14165185a700Sflorian 	 */
14175185a700Sflorian 	if (gf && (gp.length + 2) >= name->length)
1418*1fb015a8Sflorian 		gf = 0;
14195185a700Sflorian 
14205185a700Sflorian 	if (gf) {
14215185a700Sflorian 		if (target->length - target->used < gp.length)
14225185a700Sflorian 			return (ISC_R_NOSPACE);
14235185a700Sflorian 		if (gp.length != 0) {
14245185a700Sflorian 			unsigned char *base = target->base;
14255185a700Sflorian 			(void)memmove(base + target->used, gp.ndata,
14265185a700Sflorian 				      (size_t)gp.length);
14275185a700Sflorian 		}
14285185a700Sflorian 		isc_buffer_add(target, gp.length);
14295185a700Sflorian 		go |= 0xc000;
14305185a700Sflorian 		if (target->length - target->used < 2)
14315185a700Sflorian 			return (ISC_R_NOSPACE);
14325185a700Sflorian 		isc_buffer_putuint16(target, go);
14335185a700Sflorian 		if (gp.length != 0)
14345185a700Sflorian 			dns_compress_add(cctx, name, &gp, offset);
14355185a700Sflorian 	} else {
14365185a700Sflorian 		if (target->length - target->used < name->length)
14375185a700Sflorian 			return (ISC_R_NOSPACE);
14385185a700Sflorian 		if (name->length != 0) {
14395185a700Sflorian 			unsigned char *base = target->base;
14405185a700Sflorian 			(void)memmove(base + target->used, name->ndata,
14415185a700Sflorian 				      (size_t)name->length);
14425185a700Sflorian 		}
14435185a700Sflorian 		isc_buffer_add(target, name->length);
14445185a700Sflorian 		dns_compress_add(cctx, name, name, offset);
14455185a700Sflorian 	}
14465185a700Sflorian 	return (ISC_R_SUCCESS);
14475185a700Sflorian }
14485185a700Sflorian 
14495185a700Sflorian isc_result_t
dns_name_concatenate(dns_name_t * prefix,dns_name_t * suffix,dns_name_t * name,isc_buffer_t * target)14505185a700Sflorian dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name,
14515185a700Sflorian 		     isc_buffer_t *target)
14525185a700Sflorian {
14535185a700Sflorian 	unsigned char *ndata, *offsets;
14545185a700Sflorian 	unsigned int nrem, labels, prefix_length, length;
1455*1fb015a8Sflorian 	int copy_prefix = 1;
1456*1fb015a8Sflorian 	int copy_suffix = 1;
1457*1fb015a8Sflorian 	int absolute = 0;
14585185a700Sflorian 	dns_name_t tmp_name;
14595185a700Sflorian 	dns_offsets_t odata;
14605185a700Sflorian 
14615185a700Sflorian 	/*
14625185a700Sflorian 	 * Concatenate 'prefix' and 'suffix'.
14635185a700Sflorian 	 */
14645185a700Sflorian 
14655185a700Sflorian 	if (prefix == NULL || prefix->labels == 0)
1466*1fb015a8Sflorian 		copy_prefix = 0;
14675185a700Sflorian 	if (suffix == NULL || suffix->labels == 0)
1468*1fb015a8Sflorian 		copy_suffix = 0;
14695185a700Sflorian 	if (copy_prefix &&
14705185a700Sflorian 	    (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
1471*1fb015a8Sflorian 		absolute = 1;
14725185a700Sflorian 		REQUIRE(!copy_suffix);
14735185a700Sflorian 	}
14745185a700Sflorian 	if (name == NULL) {
1475f1dacf25Sflorian 		dns_name_init(&tmp_name, odata);
14765185a700Sflorian 		name = &tmp_name;
14775185a700Sflorian 	}
14785185a700Sflorian 	if (target == NULL) {
14795185a700Sflorian 		INSIST(name->buffer != NULL);
14805185a700Sflorian 		target = name->buffer;
14815185a700Sflorian 		isc_buffer_clear(name->buffer);
14825185a700Sflorian 	}
14835185a700Sflorian 
14845185a700Sflorian 	REQUIRE(BINDABLE(name));
14855185a700Sflorian 
14865185a700Sflorian 	/*
14875185a700Sflorian 	 * Set up.
14885185a700Sflorian 	 */
14895185a700Sflorian 	nrem = target->length - target->used;
14905185a700Sflorian 	ndata = (unsigned char *)target->base + target->used;
14915185a700Sflorian 	if (nrem > DNS_NAME_MAXWIRE)
14925185a700Sflorian 		nrem = DNS_NAME_MAXWIRE;
14935185a700Sflorian 	length = 0;
14945185a700Sflorian 	prefix_length = 0;
14955185a700Sflorian 	labels = 0;
14965185a700Sflorian 	if (copy_prefix) {
14975185a700Sflorian 		prefix_length = prefix->length;
14985185a700Sflorian 		length += prefix_length;
14995185a700Sflorian 		labels += prefix->labels;
15005185a700Sflorian 	}
15015185a700Sflorian 	if (copy_suffix) {
15025185a700Sflorian 		length += suffix->length;
15035185a700Sflorian 		labels += suffix->labels;
15045185a700Sflorian 	}
15055185a700Sflorian 	if (length > DNS_NAME_MAXWIRE) {
15065185a700Sflorian 		MAKE_EMPTY(name);
15075185a700Sflorian 		return (DNS_R_NAMETOOLONG);
15085185a700Sflorian 	}
15095185a700Sflorian 	if (length > nrem) {
15105185a700Sflorian 		MAKE_EMPTY(name);
15115185a700Sflorian 		return (ISC_R_NOSPACE);
15125185a700Sflorian 	}
15135185a700Sflorian 
15145185a700Sflorian 	if (copy_suffix) {
15155185a700Sflorian 		if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1516*1fb015a8Sflorian 			absolute = 1;
15175185a700Sflorian 		memmove(ndata + prefix_length, suffix->ndata, suffix->length);
15185185a700Sflorian 	}
15195185a700Sflorian 
15205185a700Sflorian 	/*
15215185a700Sflorian 	 * If 'prefix' and 'name' are the same object, and the object has
15225185a700Sflorian 	 * a dedicated buffer, and we're using it, then we don't have to
15235185a700Sflorian 	 * copy anything.
15245185a700Sflorian 	 */
15255185a700Sflorian 	if (copy_prefix && (prefix != name || prefix->buffer != target))
15265185a700Sflorian 		memmove(ndata, prefix->ndata, prefix_length);
15275185a700Sflorian 
15285185a700Sflorian 	name->ndata = ndata;
15295185a700Sflorian 	name->labels = labels;
15305185a700Sflorian 	name->length = length;
15315185a700Sflorian 	if (absolute)
15325185a700Sflorian 		name->attributes = DNS_NAMEATTR_ABSOLUTE;
15335185a700Sflorian 	else
15345185a700Sflorian 		name->attributes = 0;
15355185a700Sflorian 
15365185a700Sflorian 	if (name->labels > 0 && name->offsets != NULL) {
15375185a700Sflorian 		INIT_OFFSETS(name, offsets, odata);
15385185a700Sflorian 		set_offsets(name, offsets, NULL);
15395185a700Sflorian 	}
15405185a700Sflorian 
15415185a700Sflorian 	isc_buffer_add(target, name->length);
15425185a700Sflorian 
15435185a700Sflorian 	return (ISC_R_SUCCESS);
15445185a700Sflorian }
15455185a700Sflorian 
15465185a700Sflorian isc_result_t
dns_name_dup(const dns_name_t * source,dns_name_t * target)15475185a700Sflorian dns_name_dup(const dns_name_t *source,
15485185a700Sflorian 	     dns_name_t *target)
15495185a700Sflorian {
15505185a700Sflorian 	/*
15515185a700Sflorian 	 * Make 'target' a dynamically allocated copy of 'source'.
15525185a700Sflorian 	 */
15535185a700Sflorian 
15545185a700Sflorian 	REQUIRE(source->length > 0);
15555185a700Sflorian 	REQUIRE(BINDABLE(target));
15565185a700Sflorian 
15575185a700Sflorian 	/*
15585185a700Sflorian 	 * Make 'target' empty in case of failure.
15595185a700Sflorian 	 */
15605185a700Sflorian 	MAKE_EMPTY(target);
15615185a700Sflorian 
15625185a700Sflorian 	target->ndata = malloc(source->length);
15635185a700Sflorian 	if (target->ndata == NULL)
15645185a700Sflorian 		return (ISC_R_NOMEMORY);
15655185a700Sflorian 
15665185a700Sflorian 	memmove(target->ndata, source->ndata, source->length);
15675185a700Sflorian 
15685185a700Sflorian 	target->length = source->length;
15695185a700Sflorian 	target->labels = source->labels;
15705185a700Sflorian 	target->attributes = DNS_NAMEATTR_DYNAMIC;
15715185a700Sflorian 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
15725185a700Sflorian 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
15735185a700Sflorian 	if (target->offsets != NULL) {
15745185a700Sflorian 		if (source->offsets != NULL)
15755185a700Sflorian 			memmove(target->offsets, source->offsets,
15765185a700Sflorian 				source->labels);
15775185a700Sflorian 		else
15785185a700Sflorian 			set_offsets(target, target->offsets, NULL);
15795185a700Sflorian 	}
15805185a700Sflorian 
15815185a700Sflorian 	return (ISC_R_SUCCESS);
15825185a700Sflorian }
15835185a700Sflorian 
15845185a700Sflorian isc_result_t
dns_name_dupwithoffsets(dns_name_t * source,dns_name_t * target)15855185a700Sflorian dns_name_dupwithoffsets(dns_name_t *source,
15865185a700Sflorian 			dns_name_t *target)
15875185a700Sflorian {
15885185a700Sflorian 	/*
15895185a700Sflorian 	 * Make 'target' a read-only dynamically allocated copy of 'source'.
15905185a700Sflorian 	 * 'target' will also have a dynamically allocated offsets table.
15915185a700Sflorian 	 */
15925185a700Sflorian 
15935185a700Sflorian 	REQUIRE(source->length > 0);
15945185a700Sflorian 	REQUIRE(BINDABLE(target));
15955185a700Sflorian 	REQUIRE(target->offsets == NULL);
15965185a700Sflorian 
15975185a700Sflorian 	/*
15985185a700Sflorian 	 * Make 'target' empty in case of failure.
15995185a700Sflorian 	 */
16005185a700Sflorian 	MAKE_EMPTY(target);
16015185a700Sflorian 
16025185a700Sflorian 	target->ndata = malloc(source->length + source->labels);
16035185a700Sflorian 	if (target->ndata == NULL)
16045185a700Sflorian 		return (ISC_R_NOMEMORY);
16055185a700Sflorian 
16065185a700Sflorian 	memmove(target->ndata, source->ndata, source->length);
16075185a700Sflorian 
16085185a700Sflorian 	target->length = source->length;
16095185a700Sflorian 	target->labels = source->labels;
16105185a700Sflorian 	target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
16115185a700Sflorian 		DNS_NAMEATTR_READONLY;
16125185a700Sflorian 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
16135185a700Sflorian 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
16145185a700Sflorian 	target->offsets = target->ndata + source->length;
16155185a700Sflorian 	if (source->offsets != NULL)
16165185a700Sflorian 		memmove(target->offsets, source->offsets, source->labels);
16175185a700Sflorian 	else
16185185a700Sflorian 		set_offsets(target, target->offsets, NULL);
16195185a700Sflorian 
16205185a700Sflorian 	return (ISC_R_SUCCESS);
16215185a700Sflorian }
16225185a700Sflorian 
16235185a700Sflorian void
dns_name_free(dns_name_t * name)16245185a700Sflorian dns_name_free(dns_name_t *name) {
16255185a700Sflorian 	/*
16265185a700Sflorian 	 * Free 'name'.
16275185a700Sflorian 	 */
16285185a700Sflorian 
16295185a700Sflorian 	REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
16305185a700Sflorian 
16315185a700Sflorian 	free(name->ndata);
16325185a700Sflorian 	dns_name_invalidate(name);
16335185a700Sflorian }
16345185a700Sflorian 
1635*1fb015a8Sflorian int
dns_name_dynamic(dns_name_t * name)16365185a700Sflorian dns_name_dynamic(dns_name_t *name) {
16375185a700Sflorian 
16385185a700Sflorian 	/*
16395185a700Sflorian 	 * Returns whether there is dynamic memory associated with this name.
16405185a700Sflorian 	 */
16415185a700Sflorian 
16425185a700Sflorian 	return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ?
1643*1fb015a8Sflorian 		1 : 0);
16445185a700Sflorian }
16455185a700Sflorian 
16465185a700Sflorian void
dns_name_format(dns_name_t * name,char * cp,unsigned int size)16475185a700Sflorian dns_name_format(dns_name_t *name, char *cp, unsigned int size) {
16485185a700Sflorian 	isc_result_t result;
16495185a700Sflorian 	isc_buffer_t buf;
16505185a700Sflorian 
16515185a700Sflorian 	REQUIRE(size > 0);
16525185a700Sflorian 
16535185a700Sflorian 	/*
16545185a700Sflorian 	 * Leave room for null termination after buffer.
16555185a700Sflorian 	 */
16565185a700Sflorian 	isc_buffer_init(&buf, cp, size - 1);
1657*1fb015a8Sflorian 	result = dns_name_totext(name, 1, &buf);
16585185a700Sflorian 	if (result == ISC_R_SUCCESS) {
16595185a700Sflorian 		/*
16605185a700Sflorian 		 * Null terminate.
16615185a700Sflorian 		 */
16625185a700Sflorian 		isc_region_t r;
16635185a700Sflorian 		isc_buffer_usedregion(&buf, &r);
16645185a700Sflorian 		((char *) r.base)[r.length] = '\0';
16655185a700Sflorian 
16665185a700Sflorian 	} else
16675185a700Sflorian 		snprintf(cp, size, "<unknown>");
16685185a700Sflorian }
16695185a700Sflorian 
16705185a700Sflorian /*
16715185a700Sflorian  * dns_name_fromstring() -- convert directly from a string to a name,
16725185a700Sflorian  * allocating memory as needed
16735185a700Sflorian  */
16745185a700Sflorian isc_result_t
dns_name_fromstring2(dns_name_t * target,const char * src,const dns_name_t * origin,unsigned int options)16755185a700Sflorian dns_name_fromstring2(dns_name_t *target, const char *src,
16765185a700Sflorian 		     const dns_name_t *origin, unsigned int options)
16775185a700Sflorian {
16785185a700Sflorian 	isc_result_t result;
16795185a700Sflorian 	isc_buffer_t buf;
16805185a700Sflorian 	dns_fixedname_t fn;
16815185a700Sflorian 	dns_name_t *name;
16825185a700Sflorian 
16835185a700Sflorian 	REQUIRE(src != NULL);
16845185a700Sflorian 
168538a45998Sflorian 	isc_buffer_init(&buf, (void *)src, strlen(src));
16865185a700Sflorian 	isc_buffer_add(&buf, strlen(src));
16875185a700Sflorian 	if (BINDABLE(target) && target->buffer != NULL)
16885185a700Sflorian 		name = target;
16895185a700Sflorian 	else {
16905185a700Sflorian 		dns_fixedname_init(&fn);
16915185a700Sflorian 		name = dns_fixedname_name(&fn);
16925185a700Sflorian 	}
16935185a700Sflorian 
16945185a700Sflorian 	result = dns_name_fromtext(name, &buf, origin, options, NULL);
16955185a700Sflorian 	if (result != ISC_R_SUCCESS)
16965185a700Sflorian 		return (result);
16975185a700Sflorian 
16985185a700Sflorian 	if (name != target)
16995185a700Sflorian 		result = dns_name_dupwithoffsets(name, target);
17005185a700Sflorian 	return (result);
17015185a700Sflorian }
17025185a700Sflorian 
17035185a700Sflorian isc_result_t
dns_name_copy(dns_name_t * source,dns_name_t * dest,isc_buffer_t * target)17045185a700Sflorian dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
17055185a700Sflorian 	unsigned char *ndata;
17065185a700Sflorian 
17075185a700Sflorian 	/*
17085185a700Sflorian 	 * Make dest a copy of source.
17095185a700Sflorian 	 */
17105185a700Sflorian 
17115185a700Sflorian 	REQUIRE(target != NULL || dest->buffer != NULL);
17125185a700Sflorian 
17135185a700Sflorian 	if (target == NULL) {
17145185a700Sflorian 		target = dest->buffer;
17155185a700Sflorian 		isc_buffer_clear(dest->buffer);
17165185a700Sflorian 	}
17175185a700Sflorian 
17185185a700Sflorian 	REQUIRE(BINDABLE(dest));
17195185a700Sflorian 
17205185a700Sflorian 	/*
17215185a700Sflorian 	 * Set up.
17225185a700Sflorian 	 */
17235185a700Sflorian 	if (target->length - target->used < source->length)
17245185a700Sflorian 		return (ISC_R_NOSPACE);
17255185a700Sflorian 
17265185a700Sflorian 	ndata = (unsigned char *)target->base + target->used;
17275185a700Sflorian 	dest->ndata = target->base;
17285185a700Sflorian 
17295185a700Sflorian 	if (source->length != 0)
17305185a700Sflorian 		memmove(ndata, source->ndata, source->length);
17315185a700Sflorian 
17325185a700Sflorian 	dest->ndata = ndata;
17335185a700Sflorian 	dest->labels = source->labels;
17345185a700Sflorian 	dest->length = source->length;
17355185a700Sflorian 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
17365185a700Sflorian 		dest->attributes = DNS_NAMEATTR_ABSOLUTE;
17375185a700Sflorian 	else
17385185a700Sflorian 		dest->attributes = 0;
17395185a700Sflorian 
17405185a700Sflorian 	if (dest->labels > 0 && dest->offsets != NULL) {
17415185a700Sflorian 		if (source->offsets != NULL)
17425185a700Sflorian 			memmove(dest->offsets, source->offsets, source->labels);
17435185a700Sflorian 		else
17445185a700Sflorian 			set_offsets(dest, dest->offsets, NULL);
17455185a700Sflorian 	}
17465185a700Sflorian 
17475185a700Sflorian 	isc_buffer_add(target, dest->length);
17485185a700Sflorian 
17495185a700Sflorian 	return (ISC_R_SUCCESS);
17505185a700Sflorian }
1751