1135446Strhodes/*
2262706Serwin * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1998-2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id$ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <ctype.h>
25170222Sdougb#include <stdlib.h>
26135446Strhodes
27135446Strhodes#include <isc/buffer.h>
28135446Strhodes#include <isc/hash.h>
29135446Strhodes#include <isc/mem.h>
30170222Sdougb#include <isc/once.h>
31135446Strhodes#include <isc/print.h>
32135446Strhodes#include <isc/string.h>
33170222Sdougb#include <isc/thread.h>
34135446Strhodes#include <isc/util.h>
35135446Strhodes
36135446Strhodes#include <dns/compress.h>
37224092Sdougb#include <dns/fixedname.h>
38135446Strhodes#include <dns/name.h>
39135446Strhodes#include <dns/result.h>
40135446Strhodes
41135446Strhodes#define VALID_NAME(n)	ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
42135446Strhodes
43135446Strhodestypedef enum {
44135446Strhodes	ft_init = 0,
45135446Strhodes	ft_start,
46135446Strhodes	ft_ordinary,
47135446Strhodes	ft_initialescape,
48135446Strhodes	ft_escape,
49135446Strhodes	ft_escdecimal,
50135446Strhodes	ft_at
51135446Strhodes} ft_state;
52135446Strhodes
53135446Strhodestypedef enum {
54135446Strhodes	fw_start = 0,
55135446Strhodes	fw_ordinary,
56135446Strhodes	fw_copy,
57135446Strhodes	fw_newcurrent
58135446Strhodes} fw_state;
59135446Strhodes
60135446Strhodesstatic char digitvalue[256] = {
61135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	/*16*/
62135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
63135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
64135446Strhodes	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
65135446Strhodes	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
66135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
67135446Strhodes	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
68135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
69135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
70135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
71135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
72135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
73135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
74135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
75135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
76135446Strhodes	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
77135446Strhodes};
78135446Strhodes
79135446Strhodesstatic unsigned char maptolower[] = {
80135446Strhodes	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
81135446Strhodes	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
82135446Strhodes	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
83135446Strhodes	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
84135446Strhodes	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
85135446Strhodes	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
86135446Strhodes	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
87135446Strhodes	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
88135446Strhodes	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
89135446Strhodes	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
90135446Strhodes	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
91135446Strhodes	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
92135446Strhodes	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
93135446Strhodes	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
94135446Strhodes	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
95135446Strhodes	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
96135446Strhodes	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
97135446Strhodes	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
98135446Strhodes	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
99135446Strhodes	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
100135446Strhodes	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
101135446Strhodes	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
102135446Strhodes	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
103135446Strhodes	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
104135446Strhodes	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
105135446Strhodes	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
106135446Strhodes	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
107135446Strhodes	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
108135446Strhodes	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
109135446Strhodes	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
110135446Strhodes	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
111135446Strhodes	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
112135446Strhodes};
113135446Strhodes
114135446Strhodes#define CONVERTTOASCII(c)
115135446Strhodes#define CONVERTFROMASCII(c)
116135446Strhodes
117135446Strhodes#define INIT_OFFSETS(name, var, default) \
118135446Strhodes	if (name->offsets != NULL) \
119135446Strhodes		var = name->offsets; \
120135446Strhodes	else \
121135446Strhodes		var = default;
122135446Strhodes
123135446Strhodes#define SETUP_OFFSETS(name, var, default) \
124135446Strhodes	if (name->offsets != NULL) \
125135446Strhodes		var = name->offsets; \
126135446Strhodes	else { \
127135446Strhodes		var = default; \
128135446Strhodes		set_offsets(name, var, NULL); \
129135446Strhodes	}
130135446Strhodes
131170222Sdougb/*%
132135446Strhodes * Note:  If additional attributes are added that should not be set for
133135446Strhodes *	  empty names, MAKE_EMPTY() must be changed so it clears them.
134135446Strhodes */
135135446Strhodes#define MAKE_EMPTY(name) \
136135446Strhodesdo { \
137135446Strhodes	name->ndata = NULL; \
138135446Strhodes	name->length = 0; \
139135446Strhodes	name->labels = 0; \
140135446Strhodes	name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
141135446Strhodes} while (0);
142135446Strhodes
143170222Sdougb/*%
144135446Strhodes * A name is "bindable" if it can be set to point to a new value, i.e.
145135446Strhodes * name->ndata and name->length may be changed.
146135446Strhodes */
147135446Strhodes#define BINDABLE(name) \
148135446Strhodes	((name->attributes & (DNS_NAMEATTR_READONLY|DNS_NAMEATTR_DYNAMIC)) \
149135446Strhodes	 == 0)
150135446Strhodes
151170222Sdougb/*%
152135446Strhodes * Note that the name data must be a char array, not a string
153135446Strhodes * literal, to avoid compiler warnings about discarding
154135446Strhodes * the const attribute of a string.
155135446Strhodes */
156135446Strhodesstatic unsigned char root_ndata[] = { '\0' };
157135446Strhodesstatic unsigned char root_offsets[] = { 0 };
158135446Strhodes
159193149Sdougbstatic dns_name_t root =
160135446Strhodes{
161135446Strhodes	DNS_NAME_MAGIC,
162135446Strhodes	root_ndata, 1, 1,
163135446Strhodes	DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
164135446Strhodes	root_offsets, NULL,
165135446Strhodes	{(void *)-1, (void *)-1},
166135446Strhodes	{NULL, NULL}
167135446Strhodes};
168135446Strhodes
169135446Strhodes/* XXXDCL make const? */
170135446StrhodesLIBDNS_EXTERNAL_DATA dns_name_t *dns_rootname = &root;
171135446Strhodes
172135446Strhodesstatic unsigned char wild_ndata[] = { '\001', '*' };
173135446Strhodesstatic unsigned char wild_offsets[] = { 0 };
174135446Strhodes
175135446Strhodesstatic dns_name_t wild =
176135446Strhodes{
177135446Strhodes	DNS_NAME_MAGIC,
178135446Strhodes	wild_ndata, 2, 1,
179135446Strhodes	DNS_NAMEATTR_READONLY,
180135446Strhodes	wild_offsets, NULL,
181135446Strhodes	{(void *)-1, (void *)-1},
182135446Strhodes	{NULL, NULL}
183135446Strhodes};
184135446Strhodes
185135446Strhodes/* XXXDCL make const? */
186135446StrhodesLIBDNS_EXTERNAL_DATA dns_name_t *dns_wildcardname = &wild;
187135446Strhodes
188135446Strhodesunsigned int
189135446Strhodesdns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive);
190135446Strhodes
191170222Sdougb/*
192170222Sdougb * dns_name_t to text post-conversion procedure.
193170222Sdougb */
194170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
195170222Sdougbstatic int thread_key_initialized = 0;
196170222Sdougbstatic isc_mutex_t thread_key_mutex;
197170222Sdougbstatic isc_mem_t *thread_key_mctx = NULL;
198170222Sdougbstatic isc_thread_key_t totext_filter_proc_key;
199170222Sdougbstatic isc_once_t once = ISC_ONCE_INIT;
200170222Sdougb#else
201170222Sdougbstatic dns_name_totextfilter_t totext_filter_proc = NULL;
202170222Sdougb#endif
203170222Sdougb
204135446Strhodesstatic void
205135446Strhodesset_offsets(const dns_name_t *name, unsigned char *offsets,
206135446Strhodes	    dns_name_t *set_name);
207135446Strhodes
208135446Strhodesvoid
209135446Strhodesdns_name_init(dns_name_t *name, unsigned char *offsets) {
210135446Strhodes	/*
211135446Strhodes	 * Initialize 'name'.
212135446Strhodes	 */
213135446Strhodes	DNS_NAME_INIT(name, offsets);
214135446Strhodes}
215135446Strhodes
216135446Strhodesvoid
217135446Strhodesdns_name_reset(dns_name_t *name) {
218135446Strhodes	REQUIRE(VALID_NAME(name));
219135446Strhodes	REQUIRE(BINDABLE(name));
220135446Strhodes
221135446Strhodes	DNS_NAME_RESET(name);
222135446Strhodes}
223135446Strhodes
224135446Strhodesvoid
225135446Strhodesdns_name_invalidate(dns_name_t *name) {
226135446Strhodes	/*
227135446Strhodes	 * Make 'name' invalid.
228135446Strhodes	 */
229135446Strhodes
230135446Strhodes	REQUIRE(VALID_NAME(name));
231135446Strhodes
232135446Strhodes	name->magic = 0;
233135446Strhodes	name->ndata = NULL;
234135446Strhodes	name->length = 0;
235135446Strhodes	name->labels = 0;
236135446Strhodes	name->attributes = 0;
237135446Strhodes	name->offsets = NULL;
238135446Strhodes	name->buffer = NULL;
239135446Strhodes	ISC_LINK_INIT(name, link);
240135446Strhodes}
241135446Strhodes
242135446Strhodesvoid
243135446Strhodesdns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
244135446Strhodes	/*
245135446Strhodes	 * Dedicate a buffer for use with 'name'.
246135446Strhodes	 */
247135446Strhodes
248135446Strhodes	REQUIRE(VALID_NAME(name));
249135446Strhodes	REQUIRE((buffer != NULL && name->buffer == NULL) ||
250135446Strhodes		(buffer == NULL));
251135446Strhodes
252135446Strhodes	name->buffer = buffer;
253135446Strhodes}
254135446Strhodes
255135446Strhodesisc_boolean_t
256135446Strhodesdns_name_hasbuffer(const dns_name_t *name) {
257135446Strhodes	/*
258135446Strhodes	 * Does 'name' have a dedicated buffer?
259135446Strhodes	 */
260135446Strhodes
261135446Strhodes	REQUIRE(VALID_NAME(name));
262135446Strhodes
263135446Strhodes	if (name->buffer != NULL)
264135446Strhodes		return (ISC_TRUE);
265135446Strhodes
266135446Strhodes	return (ISC_FALSE);
267135446Strhodes}
268135446Strhodes
269135446Strhodesisc_boolean_t
270135446Strhodesdns_name_isabsolute(const dns_name_t *name) {
271135446Strhodes
272135446Strhodes	/*
273135446Strhodes	 * Does 'name' end in the root label?
274135446Strhodes	 */
275135446Strhodes
276135446Strhodes	REQUIRE(VALID_NAME(name));
277135446Strhodes
278135446Strhodes	if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
279135446Strhodes		return (ISC_TRUE);
280135446Strhodes	return (ISC_FALSE);
281135446Strhodes}
282135446Strhodes
283135446Strhodes#define hyphenchar(c) ((c) == 0x2d)
284135446Strhodes#define asterchar(c) ((c) == 0x2a)
285135446Strhodes#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
286135446Strhodes		      || ((c) >= 0x61 && (c) <= 0x7a))
287135446Strhodes#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
288135446Strhodes#define borderchar(c) (alphachar(c) || digitchar(c))
289135446Strhodes#define middlechar(c) (borderchar(c) || hyphenchar(c))
290135446Strhodes#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
291135446Strhodes
292135446Strhodesisc_boolean_t
293135446Strhodesdns_name_ismailbox(const dns_name_t *name) {
294135446Strhodes	unsigned char *ndata, ch;
295135446Strhodes	unsigned int n;
296135446Strhodes	isc_boolean_t first;
297135446Strhodes
298135446Strhodes	REQUIRE(VALID_NAME(name));
299135446Strhodes	REQUIRE(name->labels > 0);
300135446Strhodes	REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
301135446Strhodes
302193149Sdougb	/*
303135446Strhodes	 * Root label.
304135446Strhodes	 */
305135446Strhodes	if (name->length == 1)
306135446Strhodes		return (ISC_TRUE);
307135446Strhodes
308135446Strhodes	ndata = name->ndata;
309135446Strhodes	n = *ndata++;
310135446Strhodes	INSIST(n <= 63);
311135446Strhodes	while (n--) {
312135446Strhodes		ch = *ndata++;
313135446Strhodes		if (!domainchar(ch))
314135446Strhodes			return (ISC_FALSE);
315135446Strhodes	}
316193149Sdougb
317135446Strhodes	if (ndata == name->ndata + name->length)
318135446Strhodes		return (ISC_FALSE);
319135446Strhodes
320135446Strhodes	/*
321135446Strhodes	 * RFC292/RFC1123 hostname.
322135446Strhodes	 */
323135446Strhodes	while (ndata < (name->ndata + name->length)) {
324135446Strhodes		n = *ndata++;
325135446Strhodes		INSIST(n <= 63);
326135446Strhodes		first = ISC_TRUE;
327135446Strhodes		while (n--) {
328135446Strhodes			ch = *ndata++;
329135446Strhodes			if (first || n == 0) {
330135446Strhodes				if (!borderchar(ch))
331135446Strhodes					return (ISC_FALSE);
332135446Strhodes			} else {
333135446Strhodes				if (!middlechar(ch))
334135446Strhodes					return (ISC_FALSE);
335135446Strhodes			}
336135446Strhodes			first = ISC_FALSE;
337135446Strhodes		}
338135446Strhodes	}
339135446Strhodes	return (ISC_TRUE);
340135446Strhodes}
341135446Strhodes
342135446Strhodesisc_boolean_t
343135446Strhodesdns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard) {
344135446Strhodes	unsigned char *ndata, ch;
345135446Strhodes	unsigned int n;
346135446Strhodes	isc_boolean_t first;
347135446Strhodes
348135446Strhodes	REQUIRE(VALID_NAME(name));
349135446Strhodes	REQUIRE(name->labels > 0);
350135446Strhodes	REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
351193149Sdougb
352193149Sdougb	/*
353135446Strhodes	 * Root label.
354135446Strhodes	 */
355135446Strhodes	if (name->length == 1)
356135446Strhodes		return (ISC_TRUE);
357135446Strhodes
358135446Strhodes	/*
359135446Strhodes	 * Skip wildcard if this is a ownername.
360135446Strhodes	 */
361135446Strhodes	ndata = name->ndata;
362135446Strhodes	if (wildcard && ndata[0] == 1 && ndata[1] == '*')
363135446Strhodes		ndata += 2;
364135446Strhodes
365135446Strhodes	/*
366135446Strhodes	 * RFC292/RFC1123 hostname.
367135446Strhodes	 */
368135446Strhodes	while (ndata < (name->ndata + name->length)) {
369135446Strhodes		n = *ndata++;
370135446Strhodes		INSIST(n <= 63);
371135446Strhodes		first = ISC_TRUE;
372135446Strhodes		while (n--) {
373135446Strhodes			ch = *ndata++;
374135446Strhodes			if (first || n == 0) {
375135446Strhodes				if (!borderchar(ch))
376135446Strhodes					return (ISC_FALSE);
377135446Strhodes			} else {
378135446Strhodes				if (!middlechar(ch))
379135446Strhodes					return (ISC_FALSE);
380135446Strhodes			}
381135446Strhodes			first = ISC_FALSE;
382135446Strhodes		}
383135446Strhodes	}
384135446Strhodes	return (ISC_TRUE);
385135446Strhodes}
386135446Strhodes
387135446Strhodesisc_boolean_t
388135446Strhodesdns_name_iswildcard(const dns_name_t *name) {
389135446Strhodes	unsigned char *ndata;
390135446Strhodes
391135446Strhodes	/*
392135446Strhodes	 * Is 'name' a wildcard name?
393135446Strhodes	 */
394135446Strhodes
395135446Strhodes	REQUIRE(VALID_NAME(name));
396135446Strhodes	REQUIRE(name->labels > 0);
397135446Strhodes
398135446Strhodes	if (name->length >= 2) {
399135446Strhodes		ndata = name->ndata;
400135446Strhodes		if (ndata[0] == 1 && ndata[1] == '*')
401135446Strhodes			return (ISC_TRUE);
402135446Strhodes	}
403135446Strhodes
404135446Strhodes	return (ISC_FALSE);
405135446Strhodes}
406135446Strhodes
407170222Sdougbisc_boolean_t
408170222Sdougbdns_name_internalwildcard(const dns_name_t *name) {
409170222Sdougb	unsigned char *ndata;
410170222Sdougb	unsigned int count;
411170222Sdougb	unsigned int label;
412170222Sdougb
413170222Sdougb	/*
414170222Sdougb	 * Does 'name' contain a internal wildcard?
415170222Sdougb	 */
416170222Sdougb
417170222Sdougb	REQUIRE(VALID_NAME(name));
418170222Sdougb	REQUIRE(name->labels > 0);
419170222Sdougb
420170222Sdougb	/*
421170222Sdougb	 * Skip first label.
422170222Sdougb	 */
423170222Sdougb	ndata = name->ndata;
424170222Sdougb	count = *ndata++;
425170222Sdougb	INSIST(count <= 63);
426170222Sdougb	ndata += count;
427170222Sdougb	label = 1;
428170222Sdougb	/*
429170222Sdougb	 * Check all but the last of the remaining labels.
430170222Sdougb	 */
431170222Sdougb	while (label + 1 < name->labels) {
432170222Sdougb		count = *ndata++;
433170222Sdougb		INSIST(count <= 63);
434170222Sdougb		if (count == 1 && *ndata == '*')
435170222Sdougb			return (ISC_TRUE);
436170222Sdougb		ndata += count;
437170222Sdougb		label++;
438170222Sdougb	}
439170222Sdougb	return (ISC_FALSE);
440170222Sdougb}
441170222Sdougb
442135446Strhodesstatic inline unsigned int
443135446Strhodesname_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
444135446Strhodes	unsigned int length;
445135446Strhodes	const unsigned char *s;
446135446Strhodes	unsigned int h = 0;
447135446Strhodes	unsigned char c;
448135446Strhodes
449135446Strhodes	length = name->length;
450135446Strhodes	if (length > 16)
451135446Strhodes		length = 16;
452135446Strhodes
453135446Strhodes	/*
454135446Strhodes	 * This hash function is similar to the one Ousterhout
455135446Strhodes	 * uses in Tcl.
456135446Strhodes	 */
457135446Strhodes	s = name->ndata;
458135446Strhodes	if (case_sensitive) {
459135446Strhodes		while (length > 0) {
460135446Strhodes			h += ( h << 3 ) + *s;
461135446Strhodes			s++;
462135446Strhodes			length--;
463135446Strhodes		}
464135446Strhodes	} else {
465135446Strhodes		while (length > 0) {
466135446Strhodes			c = maptolower[*s];
467135446Strhodes			h += ( h << 3 ) + c;
468135446Strhodes			s++;
469135446Strhodes			length--;
470135446Strhodes		}
471135446Strhodes	}
472135446Strhodes
473135446Strhodes	return (h);
474135446Strhodes}
475135446Strhodes
476135446Strhodesunsigned int
477135446Strhodesdns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
478135446Strhodes	/*
479135446Strhodes	 * Provide a hash value for 'name'.
480135446Strhodes	 */
481135446Strhodes	REQUIRE(VALID_NAME(name));
482135446Strhodes
483135446Strhodes	if (name->labels == 0)
484135446Strhodes		return (0);
485135446Strhodes
486135446Strhodes	return (name_hash(name, case_sensitive));
487135446Strhodes}
488135446Strhodes
489135446Strhodesunsigned int
490135446Strhodesdns_name_fullhash(dns_name_t *name, isc_boolean_t case_sensitive) {
491135446Strhodes	/*
492135446Strhodes	 * Provide a hash value for 'name'.
493135446Strhodes	 */
494135446Strhodes	REQUIRE(VALID_NAME(name));
495135446Strhodes
496135446Strhodes	if (name->labels == 0)
497135446Strhodes		return (0);
498135446Strhodes
499135446Strhodes	return (isc_hash_calc((const unsigned char *)name->ndata,
500135446Strhodes			      name->length, case_sensitive));
501135446Strhodes}
502135446Strhodes
503135446Strhodesunsigned int
504135446Strhodesdns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
505135446Strhodes	/*
506135446Strhodes	 * This function was deprecated due to the breakage of the name space
507135446Strhodes	 * convention.  We only keep this internally to provide binary backward
508135446Strhodes	 * compatibility.
509135446Strhodes	 */
510135446Strhodes	REQUIRE(VALID_NAME(name));
511135446Strhodes
512135446Strhodes	return (dns_name_fullhash(name, case_sensitive));
513135446Strhodes}
514135446Strhodes
515135446Strhodesunsigned int
516135446Strhodesdns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive) {
517135446Strhodes	unsigned char *offsets;
518135446Strhodes	dns_offsets_t odata;
519135446Strhodes	dns_name_t tname;
520135446Strhodes	unsigned int h = 0;
521135446Strhodes	unsigned int i;
522135446Strhodes
523135446Strhodes	/*
524135446Strhodes	 * Provide a hash value for 'name'.
525135446Strhodes	 */
526135446Strhodes	REQUIRE(VALID_NAME(name));
527135446Strhodes
528135446Strhodes	if (name->labels == 0)
529135446Strhodes		return (0);
530135446Strhodes	else if (name->labels == 1)
531135446Strhodes		return (name_hash(name, case_sensitive));
532135446Strhodes
533135446Strhodes	SETUP_OFFSETS(name, offsets, odata);
534135446Strhodes	DNS_NAME_INIT(&tname, NULL);
535135446Strhodes	tname.labels = 1;
536135446Strhodes	h = 0;
537135446Strhodes	for (i = 0; i < name->labels; i++) {
538135446Strhodes		tname.ndata = name->ndata + offsets[i];
539135446Strhodes		if (i == name->labels - 1)
540135446Strhodes			tname.length = name->length - offsets[i];
541135446Strhodes		else
542135446Strhodes			tname.length = offsets[i + 1] - offsets[i];
543135446Strhodes		h += name_hash(&tname, case_sensitive);
544135446Strhodes	}
545135446Strhodes
546135446Strhodes	return (h);
547135446Strhodes}
548135446Strhodes
549135446Strhodesdns_namereln_t
550135446Strhodesdns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
551135446Strhodes		     int *orderp, unsigned int *nlabelsp)
552135446Strhodes{
553135446Strhodes	unsigned int l1, l2, l, count1, count2, count, nlabels;
554135446Strhodes	int cdiff, ldiff, chdiff;
555135446Strhodes	unsigned char *label1, *label2;
556135446Strhodes	unsigned char *offsets1, *offsets2;
557135446Strhodes	dns_offsets_t odata1, odata2;
558135446Strhodes	dns_namereln_t namereln = dns_namereln_none;
559135446Strhodes
560135446Strhodes	/*
561135446Strhodes	 * Determine the relative ordering under the DNSSEC order relation of
562135446Strhodes	 * 'name1' and 'name2', and also determine the hierarchical
563135446Strhodes	 * relationship of the names.
564135446Strhodes	 *
565135446Strhodes	 * Note: It makes no sense for one of the names to be relative and the
566135446Strhodes	 * other absolute.  If both names are relative, then to be meaningfully
567135446Strhodes	 * compared the caller must ensure that they are both relative to the
568135446Strhodes	 * same domain.
569135446Strhodes	 */
570135446Strhodes
571135446Strhodes	REQUIRE(VALID_NAME(name1));
572135446Strhodes	REQUIRE(VALID_NAME(name2));
573135446Strhodes	REQUIRE(orderp != NULL);
574135446Strhodes	REQUIRE(nlabelsp != NULL);
575135446Strhodes	/*
576135446Strhodes	 * Either name1 is absolute and name2 is absolute, or neither is.
577135446Strhodes	 */
578135446Strhodes	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
579135446Strhodes		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
580135446Strhodes
581262706Serwin	if (name1 == name2) {
582262706Serwin		*orderp = 0;
583262706Serwin		return (dns_namereln_equal);
584262706Serwin	}
585262706Serwin
586135446Strhodes	SETUP_OFFSETS(name1, offsets1, odata1);
587135446Strhodes	SETUP_OFFSETS(name2, offsets2, odata2);
588135446Strhodes
589135446Strhodes	nlabels = 0;
590135446Strhodes	l1 = name1->labels;
591135446Strhodes	l2 = name2->labels;
592254402Serwin	if (l2 > l1) {
593135446Strhodes		l = l1;
594254402Serwin		ldiff = 0 - (l2 - l1);
595254402Serwin	} else {
596135446Strhodes		l = l2;
597254402Serwin		ldiff = l1 - l2;
598254402Serwin	}
599135446Strhodes
600135446Strhodes	while (l > 0) {
601135446Strhodes		l--;
602135446Strhodes		l1--;
603135446Strhodes		l2--;
604135446Strhodes		label1 = &name1->ndata[offsets1[l1]];
605135446Strhodes		label2 = &name2->ndata[offsets2[l2]];
606135446Strhodes		count1 = *label1++;
607135446Strhodes		count2 = *label2++;
608135446Strhodes
609135446Strhodes		/*
610135446Strhodes		 * We dropped bitstring labels, and we don't support any
611135446Strhodes		 * other extended label types.
612135446Strhodes		 */
613135446Strhodes		INSIST(count1 <= 63 && count2 <= 63);
614135446Strhodes
615135446Strhodes		cdiff = (int)count1 - (int)count2;
616135446Strhodes		if (cdiff < 0)
617135446Strhodes			count = count1;
618135446Strhodes		else
619135446Strhodes			count = count2;
620135446Strhodes
621135446Strhodes		while (count > 0) {
622135446Strhodes			chdiff = (int)maptolower[*label1] -
623135446Strhodes			    (int)maptolower[*label2];
624135446Strhodes			if (chdiff != 0) {
625135446Strhodes				*orderp = chdiff;
626135446Strhodes				goto done;
627135446Strhodes			}
628135446Strhodes			count--;
629135446Strhodes			label1++;
630135446Strhodes			label2++;
631135446Strhodes		}
632135446Strhodes		if (cdiff != 0) {
633135446Strhodes			*orderp = cdiff;
634135446Strhodes			goto done;
635135446Strhodes		}
636135446Strhodes		nlabels++;
637135446Strhodes	}
638135446Strhodes
639135446Strhodes	*orderp = ldiff;
640135446Strhodes	if (ldiff < 0)
641135446Strhodes		namereln = dns_namereln_contains;
642135446Strhodes	else if (ldiff > 0)
643135446Strhodes		namereln = dns_namereln_subdomain;
644135446Strhodes	else
645135446Strhodes		namereln = dns_namereln_equal;
646135446Strhodes
647135446Strhodes done:
648135446Strhodes	*nlabelsp = nlabels;
649135446Strhodes
650135446Strhodes	if (nlabels > 0 && namereln == dns_namereln_none)
651135446Strhodes		namereln = dns_namereln_commonancestor;
652135446Strhodes
653135446Strhodes	return (namereln);
654135446Strhodes}
655135446Strhodes
656135446Strhodesint
657135446Strhodesdns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
658135446Strhodes	int order;
659135446Strhodes	unsigned int nlabels;
660135446Strhodes
661135446Strhodes	/*
662135446Strhodes	 * Determine the relative ordering under the DNSSEC order relation of
663135446Strhodes	 * 'name1' and 'name2'.
664135446Strhodes	 *
665135446Strhodes	 * Note: It makes no sense for one of the names to be relative and the
666135446Strhodes	 * other absolute.  If both names are relative, then to be meaningfully
667135446Strhodes	 * compared the caller must ensure that they are both relative to the
668135446Strhodes	 * same domain.
669135446Strhodes	 */
670135446Strhodes
671135446Strhodes	(void)dns_name_fullcompare(name1, name2, &order, &nlabels);
672135446Strhodes
673135446Strhodes	return (order);
674135446Strhodes}
675135446Strhodes
676135446Strhodesisc_boolean_t
677135446Strhodesdns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
678135446Strhodes	unsigned int l, count;
679135446Strhodes	unsigned char c;
680135446Strhodes	unsigned char *label1, *label2;
681135446Strhodes
682135446Strhodes	/*
683135446Strhodes	 * Are 'name1' and 'name2' equal?
684135446Strhodes	 *
685135446Strhodes	 * Note: It makes no sense for one of the names to be relative and the
686135446Strhodes	 * other absolute.  If both names are relative, then to be meaningfully
687135446Strhodes	 * compared the caller must ensure that they are both relative to the
688135446Strhodes	 * same domain.
689135446Strhodes	 */
690135446Strhodes
691135446Strhodes	REQUIRE(VALID_NAME(name1));
692135446Strhodes	REQUIRE(VALID_NAME(name2));
693135446Strhodes	/*
694135446Strhodes	 * Either name1 is absolute and name2 is absolute, or neither is.
695135446Strhodes	 */
696135446Strhodes	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
697135446Strhodes		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
698135446Strhodes
699262706Serwin	if (name1 == name2)
700262706Serwin		return (ISC_TRUE);
701262706Serwin
702135446Strhodes	if (name1->length != name2->length)
703135446Strhodes		return (ISC_FALSE);
704135446Strhodes
705135446Strhodes	l = name1->labels;
706135446Strhodes
707135446Strhodes	if (l != name2->labels)
708135446Strhodes		return (ISC_FALSE);
709135446Strhodes
710135446Strhodes	label1 = name1->ndata;
711135446Strhodes	label2 = name2->ndata;
712135446Strhodes	while (l > 0) {
713135446Strhodes		l--;
714135446Strhodes		count = *label1++;
715135446Strhodes		if (count != *label2++)
716135446Strhodes			return (ISC_FALSE);
717135446Strhodes
718135446Strhodes		INSIST(count <= 63); /* no bitstring support */
719135446Strhodes
720135446Strhodes		while (count > 0) {
721135446Strhodes			count--;
722135446Strhodes			c = maptolower[*label1++];
723135446Strhodes			if (c != maptolower[*label2++])
724135446Strhodes				return (ISC_FALSE);
725135446Strhodes		}
726135446Strhodes	}
727135446Strhodes
728135446Strhodes	return (ISC_TRUE);
729135446Strhodes}
730135446Strhodes
731170222Sdougbisc_boolean_t
732170222Sdougbdns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
733170222Sdougb
734170222Sdougb	/*
735170222Sdougb	 * Are 'name1' and 'name2' equal?
736170222Sdougb	 *
737170222Sdougb	 * Note: It makes no sense for one of the names to be relative and the
738170222Sdougb	 * other absolute.  If both names are relative, then to be meaningfully
739170222Sdougb	 * compared the caller must ensure that they are both relative to the
740170222Sdougb	 * same domain.
741170222Sdougb	 */
742170222Sdougb
743170222Sdougb	REQUIRE(VALID_NAME(name1));
744170222Sdougb	REQUIRE(VALID_NAME(name2));
745170222Sdougb	/*
746170222Sdougb	 * Either name1 is absolute and name2 is absolute, or neither is.
747170222Sdougb	 */
748170222Sdougb	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
749170222Sdougb		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
750170222Sdougb
751170222Sdougb	if (name1->length != name2->length)
752170222Sdougb		return (ISC_FALSE);
753170222Sdougb
754170222Sdougb	if (memcmp(name1->ndata, name2->ndata, name1->length) != 0)
755170222Sdougb		return (ISC_FALSE);
756170222Sdougb
757170222Sdougb	return (ISC_TRUE);
758170222Sdougb}
759170222Sdougb
760135446Strhodesint
761135446Strhodesdns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) {
762135446Strhodes	unsigned int l1, l2, l, count1, count2, count;
763135446Strhodes	unsigned char c1, c2;
764135446Strhodes	unsigned char *label1, *label2;
765135446Strhodes
766135446Strhodes	/*
767135446Strhodes	 * Compare two absolute names as rdata.
768135446Strhodes	 */
769135446Strhodes
770135446Strhodes	REQUIRE(VALID_NAME(name1));
771135446Strhodes	REQUIRE(name1->labels > 0);
772135446Strhodes	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
773135446Strhodes	REQUIRE(VALID_NAME(name2));
774135446Strhodes	REQUIRE(name2->labels > 0);
775135446Strhodes	REQUIRE((name2->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
776135446Strhodes
777135446Strhodes	l1 = name1->labels;
778135446Strhodes	l2 = name2->labels;
779135446Strhodes
780135446Strhodes	l = (l1 < l2) ? l1 : l2;
781135446Strhodes
782135446Strhodes	label1 = name1->ndata;
783135446Strhodes	label2 = name2->ndata;
784135446Strhodes	while (l > 0) {
785135446Strhodes		l--;
786135446Strhodes		count1 = *label1++;
787135446Strhodes		count2 = *label2++;
788135446Strhodes
789135446Strhodes		/* no bitstring support */
790135446Strhodes		INSIST(count1 <= 63 && count2 <= 63);
791135446Strhodes
792135446Strhodes		if (count1 != count2)
793135446Strhodes			return ((count1 < count2) ? -1 : 1);
794135446Strhodes		count = count1;
795135446Strhodes		while (count > 0) {
796135446Strhodes			count--;
797135446Strhodes			c1 = maptolower[*label1++];
798135446Strhodes			c2 = maptolower[*label2++];
799135446Strhodes			if (c1 < c2)
800135446Strhodes				return (-1);
801135446Strhodes			else if (c1 > c2)
802135446Strhodes				return (1);
803135446Strhodes		}
804135446Strhodes	}
805135446Strhodes
806135446Strhodes	/*
807135446Strhodes	 * If one name had more labels than the other, their common
808135446Strhodes	 * prefix must have been different because the shorter name
809135446Strhodes	 * ended with the root label and the longer one can't have
810135446Strhodes	 * a root label in the middle of it.  Therefore, if we get
811135446Strhodes	 * to this point, the lengths must be equal.
812135446Strhodes	 */
813135446Strhodes	INSIST(l1 == l2);
814135446Strhodes
815135446Strhodes	return (0);
816135446Strhodes}
817135446Strhodes
818135446Strhodesisc_boolean_t
819135446Strhodesdns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
820135446Strhodes	int order;
821135446Strhodes	unsigned int nlabels;
822135446Strhodes	dns_namereln_t namereln;
823135446Strhodes
824135446Strhodes	/*
825135446Strhodes	 * Is 'name1' a subdomain of 'name2'?
826135446Strhodes	 *
827135446Strhodes	 * Note: It makes no sense for one of the names to be relative and the
828135446Strhodes	 * other absolute.  If both names are relative, then to be meaningfully
829135446Strhodes	 * compared the caller must ensure that they are both relative to the
830135446Strhodes	 * same domain.
831135446Strhodes	 */
832135446Strhodes
833135446Strhodes	namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
834135446Strhodes	if (namereln == dns_namereln_subdomain ||
835135446Strhodes	    namereln == dns_namereln_equal)
836135446Strhodes		return (ISC_TRUE);
837135446Strhodes
838135446Strhodes	return (ISC_FALSE);
839135446Strhodes}
840135446Strhodes
841135446Strhodesisc_boolean_t
842135446Strhodesdns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) {
843135446Strhodes	int order;
844135446Strhodes	unsigned int nlabels, labels;
845135446Strhodes	dns_name_t tname;
846135446Strhodes
847135446Strhodes	REQUIRE(VALID_NAME(name));
848135446Strhodes	REQUIRE(name->labels > 0);
849135446Strhodes	REQUIRE(VALID_NAME(wname));
850135446Strhodes	labels = wname->labels;
851135446Strhodes	REQUIRE(labels > 0);
852135446Strhodes	REQUIRE(dns_name_iswildcard(wname));
853135446Strhodes
854254402Serwin#if defined(__clang__)  && \
855254402Serwin       ( __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2))
856254402Serwin	memset(&tname, 0, sizeof(tname));
857254402Serwin#endif
858135446Strhodes	DNS_NAME_INIT(&tname, NULL);
859135446Strhodes	dns_name_getlabelsequence(wname, 1, labels - 1, &tname);
860135446Strhodes	if (dns_name_fullcompare(name, &tname, &order, &nlabels) ==
861135446Strhodes	    dns_namereln_subdomain)
862135446Strhodes		return (ISC_TRUE);
863135446Strhodes	return (ISC_FALSE);
864135446Strhodes}
865135446Strhodes
866135446Strhodesunsigned int
867135446Strhodesdns_name_countlabels(const dns_name_t *name) {
868135446Strhodes	/*
869135446Strhodes	 * How many labels does 'name' have?
870135446Strhodes	 */
871135446Strhodes
872135446Strhodes	REQUIRE(VALID_NAME(name));
873135446Strhodes
874135446Strhodes	ENSURE(name->labels <= 128);
875135446Strhodes
876135446Strhodes	return (name->labels);
877135446Strhodes}
878135446Strhodes
879135446Strhodesvoid
880135446Strhodesdns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
881135446Strhodes	unsigned char *offsets;
882135446Strhodes	dns_offsets_t odata;
883135446Strhodes
884135446Strhodes	/*
885135446Strhodes	 * Make 'label' refer to the 'n'th least significant label of 'name'.
886135446Strhodes	 */
887135446Strhodes
888135446Strhodes	REQUIRE(VALID_NAME(name));
889135446Strhodes	REQUIRE(name->labels > 0);
890135446Strhodes	REQUIRE(n < name->labels);
891135446Strhodes	REQUIRE(label != NULL);
892135446Strhodes
893135446Strhodes	SETUP_OFFSETS(name, offsets, odata);
894135446Strhodes
895135446Strhodes	label->base = &name->ndata[offsets[n]];
896135446Strhodes	if (n == name->labels - 1)
897135446Strhodes		label->length = name->length - offsets[n];
898135446Strhodes	else
899135446Strhodes		label->length = offsets[n + 1] - offsets[n];
900135446Strhodes}
901135446Strhodes
902135446Strhodesvoid
903135446Strhodesdns_name_getlabelsequence(const dns_name_t *source,
904135446Strhodes			  unsigned int first, unsigned int n,
905135446Strhodes			  dns_name_t *target)
906135446Strhodes{
907135446Strhodes	unsigned char *offsets;
908135446Strhodes	dns_offsets_t odata;
909135446Strhodes	unsigned int firstoffset, endoffset;
910135446Strhodes
911135446Strhodes	/*
912135446Strhodes	 * Make 'target' refer to the 'n' labels including and following
913135446Strhodes	 * 'first' in 'source'.
914135446Strhodes	 */
915135446Strhodes
916135446Strhodes	REQUIRE(VALID_NAME(source));
917135446Strhodes	REQUIRE(VALID_NAME(target));
918135446Strhodes	REQUIRE(first <= source->labels);
919218384Sdougb	REQUIRE(n <= source->labels - first); /* note first+n could overflow */
920135446Strhodes	REQUIRE(BINDABLE(target));
921135446Strhodes
922135446Strhodes	SETUP_OFFSETS(source, offsets, odata);
923135446Strhodes
924135446Strhodes	if (first == source->labels)
925135446Strhodes		firstoffset = source->length;
926135446Strhodes	else
927135446Strhodes		firstoffset = offsets[first];
928135446Strhodes
929135446Strhodes	if (first + n == source->labels)
930135446Strhodes		endoffset = source->length;
931135446Strhodes	else
932135446Strhodes		endoffset = offsets[first + n];
933135446Strhodes
934135446Strhodes	target->ndata = &source->ndata[firstoffset];
935135446Strhodes	target->length = endoffset - firstoffset;
936193149Sdougb
937135446Strhodes	if (first + n == source->labels && n > 0 &&
938135446Strhodes	    (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
939135446Strhodes		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
940135446Strhodes	else
941135446Strhodes		target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
942135446Strhodes
943135446Strhodes	target->labels = n;
944135446Strhodes
945135446Strhodes	/*
946135446Strhodes	 * If source and target are the same, and we're making target
947135446Strhodes	 * a prefix of source, the offsets table is correct already
948135446Strhodes	 * so we don't need to call set_offsets().
949135446Strhodes	 */
950135446Strhodes	if (target->offsets != NULL &&
951135446Strhodes	    (target != source || first != 0))
952135446Strhodes		set_offsets(target, target->offsets, NULL);
953135446Strhodes}
954135446Strhodes
955135446Strhodesvoid
956165071Sdougbdns_name_clone(const dns_name_t *source, dns_name_t *target) {
957135446Strhodes
958135446Strhodes	/*
959135446Strhodes	 * Make 'target' refer to the same name as 'source'.
960135446Strhodes	 */
961135446Strhodes
962135446Strhodes	REQUIRE(VALID_NAME(source));
963135446Strhodes	REQUIRE(VALID_NAME(target));
964135446Strhodes	REQUIRE(BINDABLE(target));
965135446Strhodes
966135446Strhodes	target->ndata = source->ndata;
967135446Strhodes	target->length = source->length;
968135446Strhodes	target->labels = source->labels;
969135446Strhodes	target->attributes = source->attributes &
970135446Strhodes		(unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC |
971135446Strhodes				DNS_NAMEATTR_DYNOFFSETS);
972135446Strhodes	if (target->offsets != NULL && source->labels > 0) {
973135446Strhodes		if (source->offsets != NULL)
974262706Serwin			memmove(target->offsets, source->offsets,
975262706Serwin				source->labels);
976135446Strhodes		else
977135446Strhodes			set_offsets(target, target->offsets, NULL);
978135446Strhodes	}
979135446Strhodes}
980135446Strhodes
981135446Strhodesvoid
982135446Strhodesdns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
983135446Strhodes	unsigned char *offsets;
984135446Strhodes	dns_offsets_t odata;
985135446Strhodes	unsigned int len;
986135446Strhodes	isc_region_t r2;
987135446Strhodes
988135446Strhodes	/*
989135446Strhodes	 * Make 'name' refer to region 'r'.
990135446Strhodes	 */
991135446Strhodes
992135446Strhodes	REQUIRE(VALID_NAME(name));
993135446Strhodes	REQUIRE(r != NULL);
994135446Strhodes	REQUIRE(BINDABLE(name));
995135446Strhodes
996135446Strhodes	INIT_OFFSETS(name, offsets, odata);
997135446Strhodes
998135446Strhodes	if (name->buffer != NULL) {
999135446Strhodes		isc_buffer_clear(name->buffer);
1000135446Strhodes		isc_buffer_availableregion(name->buffer, &r2);
1001135446Strhodes		len = (r->length < r2.length) ? r->length : r2.length;
1002135446Strhodes		if (len > DNS_NAME_MAXWIRE)
1003135446Strhodes			len = DNS_NAME_MAXWIRE;
1004262706Serwin		memmove(r2.base, r->base, len);
1005135446Strhodes		name->ndata = r2.base;
1006135446Strhodes		name->length = len;
1007135446Strhodes	} else {
1008135446Strhodes		name->ndata = r->base;
1009193149Sdougb		name->length = (r->length <= DNS_NAME_MAXWIRE) ?
1010135446Strhodes			r->length : DNS_NAME_MAXWIRE;
1011135446Strhodes	}
1012135446Strhodes
1013135446Strhodes	if (r->length > 0)
1014135446Strhodes		set_offsets(name, offsets, name);
1015135446Strhodes	else {
1016135446Strhodes		name->labels = 0;
1017135446Strhodes		name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1018135446Strhodes	}
1019135446Strhodes
1020135446Strhodes	if (name->buffer != NULL)
1021135446Strhodes		isc_buffer_add(name->buffer, name->length);
1022135446Strhodes}
1023135446Strhodes
1024135446Strhodesvoid
1025135446Strhodesdns_name_toregion(dns_name_t *name, isc_region_t *r) {
1026135446Strhodes	/*
1027135446Strhodes	 * Make 'r' refer to 'name'.
1028135446Strhodes	 */
1029135446Strhodes
1030135446Strhodes	REQUIRE(VALID_NAME(name));
1031135446Strhodes	REQUIRE(r != NULL);
1032135446Strhodes
1033135446Strhodes	DNS_NAME_TOREGION(name, r);
1034135446Strhodes}
1035135446Strhodes
1036135446Strhodesisc_result_t
1037135446Strhodesdns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
1038224092Sdougb		  const dns_name_t *origin, unsigned int options,
1039135446Strhodes		  isc_buffer_t *target)
1040135446Strhodes{
1041225361Sdougb	unsigned char *ndata, *label = NULL;
1042135446Strhodes	char *tdata;
1043135446Strhodes	char c;
1044153816Sdougb	ft_state state;
1045225361Sdougb	unsigned int value = 0, count = 0;
1046225361Sdougb	unsigned int n1 = 0, n2 = 0;
1047225361Sdougb	unsigned int tlen, nrem, nused, digits = 0, labels, tused;
1048135446Strhodes	isc_boolean_t done;
1049135446Strhodes	unsigned char *offsets;
1050135446Strhodes	dns_offsets_t odata;
1051135446Strhodes	isc_boolean_t downcase;
1052135446Strhodes
1053135446Strhodes	/*
1054135446Strhodes	 * Convert the textual representation of a DNS name at source
1055135446Strhodes	 * into uncompressed wire form stored in target.
1056135446Strhodes	 *
1057135446Strhodes	 * Notes:
1058135446Strhodes	 *	Relative domain names will have 'origin' appended to them
1059135446Strhodes	 *	unless 'origin' is NULL, in which case relative domain names
1060135446Strhodes	 *	will remain relative.
1061135446Strhodes	 */
1062135446Strhodes
1063135446Strhodes	REQUIRE(VALID_NAME(name));
1064135446Strhodes	REQUIRE(ISC_BUFFER_VALID(source));
1065135446Strhodes	REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1066135446Strhodes		(target == NULL && ISC_BUFFER_VALID(name->buffer)));
1067193149Sdougb
1068135446Strhodes	downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
1069135446Strhodes
1070135446Strhodes	if (target == NULL && name->buffer != NULL) {
1071135446Strhodes		target = name->buffer;
1072135446Strhodes		isc_buffer_clear(target);
1073135446Strhodes	}
1074135446Strhodes
1075135446Strhodes	REQUIRE(BINDABLE(name));
1076135446Strhodes
1077135446Strhodes	INIT_OFFSETS(name, offsets, odata);
1078135446Strhodes	offsets[0] = 0;
1079135446Strhodes
1080135446Strhodes	/*
1081135446Strhodes	 * Make 'name' empty in case of failure.
1082135446Strhodes	 */
1083135446Strhodes	MAKE_EMPTY(name);
1084135446Strhodes
1085135446Strhodes	/*
1086135446Strhodes	 * Set up the state machine.
1087135446Strhodes	 */
1088135446Strhodes	tdata = (char *)source->base + source->current;
1089135446Strhodes	tlen = isc_buffer_remaininglength(source);
1090135446Strhodes	tused = 0;
1091135446Strhodes	ndata = isc_buffer_used(target);
1092135446Strhodes	nrem = isc_buffer_availablelength(target);
1093135446Strhodes	if (nrem > 255)
1094135446Strhodes		nrem = 255;
1095135446Strhodes	nused = 0;
1096135446Strhodes	labels = 0;
1097135446Strhodes	done = ISC_FALSE;
1098135446Strhodes	state = ft_init;
1099135446Strhodes
1100135446Strhodes	while (nrem > 0 && tlen > 0 && !done) {
1101135446Strhodes		c = *tdata++;
1102135446Strhodes		tlen--;
1103135446Strhodes		tused++;
1104135446Strhodes
1105135446Strhodes		switch (state) {
1106135446Strhodes		case ft_init:
1107135446Strhodes			/*
1108135446Strhodes			 * Is this the root name?
1109135446Strhodes			 */
1110135446Strhodes			if (c == '.') {
1111135446Strhodes				if (tlen != 0)
1112135446Strhodes					return (DNS_R_EMPTYLABEL);
1113135446Strhodes				labels++;
1114135446Strhodes				*ndata++ = 0;
1115135446Strhodes				nrem--;
1116135446Strhodes				nused++;
1117135446Strhodes				done = ISC_TRUE;
1118135446Strhodes				break;
1119135446Strhodes			}
1120135446Strhodes			if (c == '@' && tlen == 0) {
1121135446Strhodes				state = ft_at;
1122135446Strhodes				break;
1123135446Strhodes			}
1124135446Strhodes
1125135446Strhodes			/* FALLTHROUGH */
1126135446Strhodes		case ft_start:
1127135446Strhodes			label = ndata;
1128135446Strhodes			ndata++;
1129135446Strhodes			nrem--;
1130135446Strhodes			nused++;
1131135446Strhodes			count = 0;
1132135446Strhodes			if (c == '\\') {
1133135446Strhodes				state = ft_initialescape;
1134135446Strhodes				break;
1135135446Strhodes			}
1136135446Strhodes			state = ft_ordinary;
1137135446Strhodes			if (nrem == 0)
1138135446Strhodes				return (ISC_R_NOSPACE);
1139135446Strhodes			/* FALLTHROUGH */
1140135446Strhodes		case ft_ordinary:
1141135446Strhodes			if (c == '.') {
1142135446Strhodes				if (count == 0)
1143135446Strhodes					return (DNS_R_EMPTYLABEL);
1144135446Strhodes				*label = count;
1145135446Strhodes				labels++;
1146135446Strhodes				INSIST(labels <= 127);
1147135446Strhodes				offsets[labels] = nused;
1148135446Strhodes				if (tlen == 0) {
1149135446Strhodes					labels++;
1150135446Strhodes					*ndata++ = 0;
1151135446Strhodes					nrem--;
1152135446Strhodes					nused++;
1153135446Strhodes					done = ISC_TRUE;
1154135446Strhodes				}
1155135446Strhodes				state = ft_start;
1156135446Strhodes			} else if (c == '\\') {
1157135446Strhodes				state = ft_escape;
1158135446Strhodes			} else {
1159135446Strhodes				if (count >= 63)
1160135446Strhodes					return (DNS_R_LABELTOOLONG);
1161135446Strhodes				count++;
1162135446Strhodes				CONVERTTOASCII(c);
1163135446Strhodes				if (downcase)
1164135446Strhodes					c = maptolower[(int)c];
1165135446Strhodes				*ndata++ = c;
1166135446Strhodes				nrem--;
1167135446Strhodes				nused++;
1168135446Strhodes			}
1169135446Strhodes			break;
1170135446Strhodes		case ft_initialescape:
1171135446Strhodes			if (c == '[') {
1172135446Strhodes				/*
1173135446Strhodes				 * This looks like a bitstring label, which
1174135446Strhodes				 * was deprecated.  Intentionally drop it.
1175135446Strhodes				 */
1176135446Strhodes				return (DNS_R_BADLABELTYPE);
1177135446Strhodes			}
1178135446Strhodes			state = ft_escape;
1179225361Sdougb			POST(state);
1180135446Strhodes			/* FALLTHROUGH */
1181135446Strhodes		case ft_escape:
1182135446Strhodes			if (!isdigit(c & 0xff)) {
1183135446Strhodes				if (count >= 63)
1184135446Strhodes					return (DNS_R_LABELTOOLONG);
1185135446Strhodes				count++;
1186135446Strhodes				CONVERTTOASCII(c);
1187135446Strhodes				if (downcase)
1188135446Strhodes					c = maptolower[(int)c];
1189135446Strhodes				*ndata++ = c;
1190135446Strhodes				nrem--;
1191135446Strhodes				nused++;
1192135446Strhodes				state = ft_ordinary;
1193135446Strhodes				break;
1194135446Strhodes			}
1195135446Strhodes			digits = 0;
1196135446Strhodes			value = 0;
1197135446Strhodes			state = ft_escdecimal;
1198135446Strhodes			/* FALLTHROUGH */
1199135446Strhodes		case ft_escdecimal:
1200135446Strhodes			if (!isdigit(c & 0xff))
1201135446Strhodes				return (DNS_R_BADESCAPE);
1202135446Strhodes			value *= 10;
1203135446Strhodes			value += digitvalue[(int)c];
1204135446Strhodes			digits++;
1205135446Strhodes			if (digits == 3) {
1206135446Strhodes				if (value > 255)
1207135446Strhodes					return (DNS_R_BADESCAPE);
1208135446Strhodes				if (count >= 63)
1209135446Strhodes					return (DNS_R_LABELTOOLONG);
1210135446Strhodes				count++;
1211135446Strhodes				if (downcase)
1212135446Strhodes					value = maptolower[value];
1213135446Strhodes				*ndata++ = value;
1214135446Strhodes				nrem--;
1215135446Strhodes				nused++;
1216135446Strhodes				state = ft_ordinary;
1217135446Strhodes			}
1218135446Strhodes			break;
1219135446Strhodes		default:
1220135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1221135446Strhodes				    "Unexpected state %d", state);
1222135446Strhodes			/* Does not return. */
1223135446Strhodes		}
1224135446Strhodes	}
1225135446Strhodes
1226135446Strhodes	if (!done) {
1227135446Strhodes		if (nrem == 0)
1228135446Strhodes			return (ISC_R_NOSPACE);
1229135446Strhodes		INSIST(tlen == 0);
1230135446Strhodes		if (state != ft_ordinary && state != ft_at)
1231135446Strhodes			return (ISC_R_UNEXPECTEDEND);
1232135446Strhodes		if (state == ft_ordinary) {
1233135446Strhodes			INSIST(count != 0);
1234135446Strhodes			*label = count;
1235135446Strhodes			labels++;
1236135446Strhodes			INSIST(labels <= 127);
1237135446Strhodes			offsets[labels] = nused;
1238135446Strhodes		}
1239135446Strhodes		if (origin != NULL) {
1240135446Strhodes			if (nrem < origin->length)
1241135446Strhodes				return (ISC_R_NOSPACE);
1242135446Strhodes			label = origin->ndata;
1243135446Strhodes			n1 = origin->length;
1244135446Strhodes			nrem -= n1;
1245225361Sdougb			POST(nrem);
1246135446Strhodes			while (n1 > 0) {
1247135446Strhodes				n2 = *label++;
1248135446Strhodes				INSIST(n2 <= 63); /* no bitstring support */
1249135446Strhodes				*ndata++ = n2;
1250135446Strhodes				n1 -= n2 + 1;
1251135446Strhodes				nused += n2 + 1;
1252135446Strhodes				while (n2 > 0) {
1253135446Strhodes					c = *label++;
1254135446Strhodes					if (downcase)
1255135446Strhodes						c = maptolower[(int)c];
1256135446Strhodes					*ndata++ = c;
1257135446Strhodes					n2--;
1258135446Strhodes				}
1259135446Strhodes				labels++;
1260135446Strhodes				if (n1 > 0) {
1261135446Strhodes					INSIST(labels <= 127);
1262135446Strhodes					offsets[labels] = nused;
1263135446Strhodes				}
1264135446Strhodes			}
1265135446Strhodes			if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1266135446Strhodes				name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1267135446Strhodes		}
1268135446Strhodes	} else
1269135446Strhodes		name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1270135446Strhodes
1271135446Strhodes	name->ndata = (unsigned char *)target->base + target->used;
1272135446Strhodes	name->labels = labels;
1273135446Strhodes	name->length = nused;
1274135446Strhodes
1275135446Strhodes	isc_buffer_forward(source, tused);
1276135446Strhodes	isc_buffer_add(target, name->length);
1277135446Strhodes
1278135446Strhodes	return (ISC_R_SUCCESS);
1279135446Strhodes}
1280135446Strhodes
1281170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
1282170222Sdougbstatic void
1283170222Sdougbfree_specific(void *arg) {
1284170222Sdougb	dns_name_totextfilter_t *mem = arg;
1285170222Sdougb	isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
1286170222Sdougb	/* Stop use being called again. */
1287170222Sdougb	(void)isc_thread_key_setspecific(totext_filter_proc_key, NULL);
1288170222Sdougb}
1289170222Sdougb
1290170222Sdougbstatic void
1291170222Sdougbthread_key_mutex_init(void) {
1292170222Sdougb	RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS);
1293170222Sdougb}
1294170222Sdougb
1295170222Sdougbstatic isc_result_t
1296170222Sdougbtotext_filter_proc_key_init(void) {
1297170222Sdougb	isc_result_t result;
1298170222Sdougb
1299170222Sdougb	/*
1300170222Sdougb	 * We need the call to isc_once_do() to support profiled mutex
1301170222Sdougb	 * otherwise thread_key_mutex could be initialized at compile time.
1302170222Sdougb	 */
1303170222Sdougb	result = isc_once_do(&once, thread_key_mutex_init);
1304170222Sdougb	if (result != ISC_R_SUCCESS)
1305170222Sdougb		return (result);
1306170222Sdougb
1307193149Sdougb	if (!thread_key_initialized) {
1308170222Sdougb		LOCK(&thread_key_mutex);
1309170222Sdougb		if (thread_key_mctx == NULL)
1310170222Sdougb			result = isc_mem_create2(0, 0, &thread_key_mctx, 0);
1311170222Sdougb		if (result != ISC_R_SUCCESS)
1312170222Sdougb			goto unlock;
1313193149Sdougb		isc_mem_setname(thread_key_mctx, "threadkey", NULL);
1314170222Sdougb		isc_mem_setdestroycheck(thread_key_mctx, ISC_FALSE);
1315193149Sdougb
1316170222Sdougb		if (!thread_key_initialized &&
1317170222Sdougb		     isc_thread_key_create(&totext_filter_proc_key,
1318193149Sdougb					   free_specific) != 0) {
1319170222Sdougb			result = ISC_R_FAILURE;
1320170222Sdougb			isc_mem_detach(&thread_key_mctx);
1321170222Sdougb		} else
1322170222Sdougb			thread_key_initialized = 1;
1323170222Sdougb unlock:
1324170222Sdougb		UNLOCK(&thread_key_mutex);
1325193149Sdougb	}
1326170222Sdougb	return (result);
1327170222Sdougb}
1328170222Sdougb#endif
1329170222Sdougb
1330135446Strhodesisc_result_t
1331135446Strhodesdns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot,
1332135446Strhodes		isc_buffer_t *target)
1333135446Strhodes{
1334218384Sdougb	unsigned int options = DNS_NAME_MASTERFILE;
1335218384Sdougb
1336218384Sdougb	if (omit_final_dot)
1337218384Sdougb		options |= DNS_NAME_OMITFINALDOT;
1338218384Sdougb	return (dns_name_totext2(name, options, target));
1339218384Sdougb}
1340218384Sdougb
1341218384Sdougbisc_result_t
1342218384Sdougbdns_name_toprincipal(dns_name_t *name, isc_buffer_t *target) {
1343218384Sdougb	return (dns_name_totext2(name, DNS_NAME_OMITFINALDOT, target));
1344218384Sdougb}
1345218384Sdougb
1346218384Sdougbisc_result_t
1347218384Sdougbdns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target)
1348218384Sdougb{
1349135446Strhodes	unsigned char *ndata;
1350135446Strhodes	char *tdata;
1351135446Strhodes	unsigned int nlen, tlen;
1352135446Strhodes	unsigned char c;
1353135446Strhodes	unsigned int trem, count;
1354135446Strhodes	unsigned int labels;
1355135446Strhodes	isc_boolean_t saw_root = ISC_FALSE;
1356170222Sdougb	unsigned int oused = target->used;
1357170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
1358170222Sdougb	dns_name_totextfilter_t *mem;
1359170222Sdougb	dns_name_totextfilter_t totext_filter_proc = NULL;
1360170222Sdougb	isc_result_t result;
1361170222Sdougb#endif
1362218384Sdougb	isc_boolean_t omit_final_dot =
1363218384Sdougb		ISC_TF(options & DNS_NAME_OMITFINALDOT);
1364135446Strhodes
1365135446Strhodes	/*
1366135446Strhodes	 * This function assumes the name is in proper uncompressed
1367135446Strhodes	 * wire format.
1368135446Strhodes	 */
1369135446Strhodes	REQUIRE(VALID_NAME(name));
1370135446Strhodes	REQUIRE(ISC_BUFFER_VALID(target));
1371135446Strhodes
1372170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
1373170222Sdougb	result = totext_filter_proc_key_init();
1374170222Sdougb	if (result != ISC_R_SUCCESS)
1375170222Sdougb		return (result);
1376170222Sdougb#endif
1377135446Strhodes	ndata = name->ndata;
1378135446Strhodes	nlen = name->length;
1379135446Strhodes	labels = name->labels;
1380135446Strhodes	tdata = isc_buffer_used(target);
1381135446Strhodes	tlen = isc_buffer_availablelength(target);
1382135446Strhodes
1383135446Strhodes	trem = tlen;
1384135446Strhodes
1385135446Strhodes	if (labels == 0 && nlen == 0) {
1386135446Strhodes		/*
1387135446Strhodes		 * Special handling for an empty name.
1388135446Strhodes		 */
1389135446Strhodes		if (trem == 0)
1390135446Strhodes			return (ISC_R_NOSPACE);
1391135446Strhodes
1392135446Strhodes		/*
1393135446Strhodes		 * The names of these booleans are misleading in this case.
1394135446Strhodes		 * This empty name is not necessarily from the root node of
1395135446Strhodes		 * the DNS root zone, nor is a final dot going to be included.
1396135446Strhodes		 * They need to be set this way, though, to keep the "@"
1397135446Strhodes		 * from being trounced.
1398135446Strhodes		 */
1399135446Strhodes		saw_root = ISC_TRUE;
1400135446Strhodes		omit_final_dot = ISC_FALSE;
1401135446Strhodes		*tdata++ = '@';
1402135446Strhodes		trem--;
1403135446Strhodes
1404135446Strhodes		/*
1405135446Strhodes		 * Skip the while() loop.
1406135446Strhodes		 */
1407135446Strhodes		nlen = 0;
1408135446Strhodes	} else if (nlen == 1 && labels == 1 && *ndata == '\0') {
1409135446Strhodes		/*
1410135446Strhodes		 * Special handling for the root label.
1411135446Strhodes		 */
1412135446Strhodes		if (trem == 0)
1413135446Strhodes			return (ISC_R_NOSPACE);
1414135446Strhodes
1415135446Strhodes		saw_root = ISC_TRUE;
1416135446Strhodes		omit_final_dot = ISC_FALSE;
1417135446Strhodes		*tdata++ = '.';
1418135446Strhodes		trem--;
1419135446Strhodes
1420135446Strhodes		/*
1421135446Strhodes		 * Skip the while() loop.
1422135446Strhodes		 */
1423135446Strhodes		nlen = 0;
1424135446Strhodes	}
1425135446Strhodes
1426135446Strhodes	while (labels > 0 && nlen > 0 && trem > 0) {
1427135446Strhodes		labels--;
1428135446Strhodes		count = *ndata++;
1429135446Strhodes		nlen--;
1430135446Strhodes		if (count == 0) {
1431135446Strhodes			saw_root = ISC_TRUE;
1432135446Strhodes			break;
1433135446Strhodes		}
1434135446Strhodes		if (count < 64) {
1435135446Strhodes			INSIST(nlen >= count);
1436135446Strhodes			while (count > 0) {
1437135446Strhodes				c = *ndata;
1438135446Strhodes				switch (c) {
1439218384Sdougb				/* Special modifiers in zone files. */
1440218384Sdougb				case 0x40: /* '@' */
1441218384Sdougb				case 0x24: /* '$' */
1442218384Sdougb					if ((options & DNS_NAME_MASTERFILE) == 0)
1443218384Sdougb						goto no_escape;
1444254402Serwin					/* FALLTHROUGH */
1445135446Strhodes				case 0x22: /* '"' */
1446135446Strhodes				case 0x28: /* '(' */
1447135446Strhodes				case 0x29: /* ')' */
1448135446Strhodes				case 0x2E: /* '.' */
1449135446Strhodes				case 0x3B: /* ';' */
1450135446Strhodes				case 0x5C: /* '\\' */
1451135446Strhodes					if (trem < 2)
1452135446Strhodes						return (ISC_R_NOSPACE);
1453135446Strhodes					*tdata++ = '\\';
1454135446Strhodes					CONVERTFROMASCII(c);
1455135446Strhodes					*tdata++ = c;
1456135446Strhodes					ndata++;
1457135446Strhodes					trem -= 2;
1458135446Strhodes					nlen--;
1459135446Strhodes					break;
1460218384Sdougb				no_escape:
1461135446Strhodes				default:
1462135446Strhodes					if (c > 0x20 && c < 0x7f) {
1463135446Strhodes						if (trem == 0)
1464135446Strhodes							return (ISC_R_NOSPACE);
1465135446Strhodes						CONVERTFROMASCII(c);
1466135446Strhodes						*tdata++ = c;
1467135446Strhodes						ndata++;
1468135446Strhodes						trem--;
1469135446Strhodes						nlen--;
1470135446Strhodes					} else {
1471135446Strhodes						if (trem < 4)
1472135446Strhodes							return (ISC_R_NOSPACE);
1473153816Sdougb						*tdata++ = 0x5c;
1474153816Sdougb						*tdata++ = 0x30 +
1475153816Sdougb							   ((c / 100) % 10);
1476153816Sdougb						*tdata++ = 0x30 +
1477153816Sdougb							   ((c / 10) % 10);
1478153816Sdougb						*tdata++ = 0x30 + (c % 10);
1479135446Strhodes						trem -= 4;
1480135446Strhodes						ndata++;
1481135446Strhodes						nlen--;
1482135446Strhodes					}
1483135446Strhodes				}
1484135446Strhodes				count--;
1485135446Strhodes			}
1486135446Strhodes		} else {
1487135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1488135446Strhodes				    "Unexpected label type %02x", count);
1489135446Strhodes			/* NOTREACHED */
1490135446Strhodes		}
1491135446Strhodes
1492135446Strhodes		/*
1493135446Strhodes		 * The following assumes names are absolute.  If not, we
1494135446Strhodes		 * fix things up later.  Note that this means that in some
1495135446Strhodes		 * cases one more byte of text buffer is required than is
1496135446Strhodes		 * needed in the final output.
1497135446Strhodes		 */
1498135446Strhodes		if (trem == 0)
1499135446Strhodes			return (ISC_R_NOSPACE);
1500135446Strhodes		*tdata++ = '.';
1501135446Strhodes		trem--;
1502135446Strhodes	}
1503135446Strhodes
1504135446Strhodes	if (nlen != 0 && trem == 0)
1505135446Strhodes		return (ISC_R_NOSPACE);
1506135446Strhodes
1507135446Strhodes	if (!saw_root || omit_final_dot)
1508135446Strhodes		trem++;
1509135446Strhodes
1510135446Strhodes	isc_buffer_add(target, tlen - trem);
1511135446Strhodes
1512170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
1513170222Sdougb	mem = isc_thread_key_getspecific(totext_filter_proc_key);
1514170222Sdougb	if (mem != NULL)
1515170222Sdougb		totext_filter_proc = *mem;
1516170222Sdougb#endif
1517170222Sdougb	if (totext_filter_proc != NULL)
1518170222Sdougb		return ((*totext_filter_proc)(target, oused, saw_root));
1519170222Sdougb
1520135446Strhodes	return (ISC_R_SUCCESS);
1521135446Strhodes}
1522135446Strhodes
1523135446Strhodesisc_result_t
1524135446Strhodesdns_name_tofilenametext(dns_name_t *name, isc_boolean_t omit_final_dot,
1525135446Strhodes			isc_buffer_t *target)
1526135446Strhodes{
1527135446Strhodes	unsigned char *ndata;
1528135446Strhodes	char *tdata;
1529135446Strhodes	unsigned int nlen, tlen;
1530135446Strhodes	unsigned char c;
1531135446Strhodes	unsigned int trem, count;
1532135446Strhodes	unsigned int labels;
1533135446Strhodes
1534135446Strhodes	/*
1535135446Strhodes	 * This function assumes the name is in proper uncompressed
1536135446Strhodes	 * wire format.
1537135446Strhodes	 */
1538135446Strhodes	REQUIRE(VALID_NAME(name));
1539135446Strhodes	REQUIRE((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
1540135446Strhodes	REQUIRE(ISC_BUFFER_VALID(target));
1541135446Strhodes
1542135446Strhodes	ndata = name->ndata;
1543135446Strhodes	nlen = name->length;
1544135446Strhodes	labels = name->labels;
1545135446Strhodes	tdata = isc_buffer_used(target);
1546135446Strhodes	tlen = isc_buffer_availablelength(target);
1547135446Strhodes
1548135446Strhodes	trem = tlen;
1549135446Strhodes
1550135446Strhodes	if (nlen == 1 && labels == 1 && *ndata == '\0') {
1551135446Strhodes		/*
1552135446Strhodes		 * Special handling for the root label.
1553135446Strhodes		 */
1554135446Strhodes		if (trem == 0)
1555135446Strhodes			return (ISC_R_NOSPACE);
1556135446Strhodes
1557135446Strhodes		omit_final_dot = ISC_FALSE;
1558135446Strhodes		*tdata++ = '.';
1559135446Strhodes		trem--;
1560135446Strhodes
1561135446Strhodes		/*
1562135446Strhodes		 * Skip the while() loop.
1563135446Strhodes		 */
1564135446Strhodes		nlen = 0;
1565135446Strhodes	}
1566135446Strhodes
1567135446Strhodes	while (labels > 0 && nlen > 0 && trem > 0) {
1568135446Strhodes		labels--;
1569135446Strhodes		count = *ndata++;
1570135446Strhodes		nlen--;
1571135446Strhodes		if (count == 0)
1572135446Strhodes			break;
1573135446Strhodes		if (count < 64) {
1574135446Strhodes			INSIST(nlen >= count);
1575135446Strhodes			while (count > 0) {
1576135446Strhodes				c = *ndata;
1577135446Strhodes				if ((c >= 0x30 && c <= 0x39) || /* digit */
1578135446Strhodes				    (c >= 0x41 && c <= 0x5A) ||	/* uppercase */
1579135446Strhodes				    (c >= 0x61 && c <= 0x7A) || /* lowercase */
1580135446Strhodes				    c == 0x2D ||		/* hyphen */
1581135446Strhodes				    c == 0x5F)			/* underscore */
1582135446Strhodes				{
1583135446Strhodes					if (trem == 0)
1584135446Strhodes						return (ISC_R_NOSPACE);
1585135446Strhodes					/* downcase */
1586135446Strhodes					if (c >= 0x41 && c <= 0x5A)
1587135446Strhodes						c += 0x20;
1588135446Strhodes					CONVERTFROMASCII(c);
1589135446Strhodes					*tdata++ = c;
1590135446Strhodes					ndata++;
1591135446Strhodes					trem--;
1592135446Strhodes					nlen--;
1593135446Strhodes				} else {
1594135446Strhodes					if (trem < 3)
1595135446Strhodes						return (ISC_R_NOSPACE);
1596135446Strhodes					sprintf(tdata, "%%%02X", c);
1597135446Strhodes					tdata += 3;
1598135446Strhodes					trem -= 3;
1599135446Strhodes					ndata++;
1600135446Strhodes					nlen--;
1601135446Strhodes				}
1602135446Strhodes				count--;
1603135446Strhodes			}
1604135446Strhodes		} else {
1605135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1606135446Strhodes				    "Unexpected label type %02x", count);
1607135446Strhodes			/* NOTREACHED */
1608135446Strhodes		}
1609135446Strhodes
1610135446Strhodes		/*
1611135446Strhodes		 * The following assumes names are absolute.  If not, we
1612135446Strhodes		 * fix things up later.  Note that this means that in some
1613135446Strhodes		 * cases one more byte of text buffer is required than is
1614135446Strhodes		 * needed in the final output.
1615135446Strhodes		 */
1616135446Strhodes		if (trem == 0)
1617135446Strhodes			return (ISC_R_NOSPACE);
1618135446Strhodes		*tdata++ = '.';
1619135446Strhodes		trem--;
1620135446Strhodes	}
1621135446Strhodes
1622135446Strhodes	if (nlen != 0 && trem == 0)
1623135446Strhodes		return (ISC_R_NOSPACE);
1624135446Strhodes
1625135446Strhodes	if (omit_final_dot)
1626135446Strhodes		trem++;
1627135446Strhodes
1628135446Strhodes	isc_buffer_add(target, tlen - trem);
1629135446Strhodes
1630135446Strhodes	return (ISC_R_SUCCESS);
1631135446Strhodes}
1632135446Strhodes
1633135446Strhodesisc_result_t
1634135446Strhodesdns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) {
1635135446Strhodes	unsigned char *sndata, *ndata;
1636135446Strhodes	unsigned int nlen, count, labels;
1637135446Strhodes	isc_buffer_t buffer;
1638135446Strhodes
1639135446Strhodes	/*
1640135446Strhodes	 * Downcase 'source'.
1641135446Strhodes	 */
1642135446Strhodes
1643135446Strhodes	REQUIRE(VALID_NAME(source));
1644135446Strhodes	REQUIRE(VALID_NAME(name));
1645135446Strhodes	if (source == name) {
1646135446Strhodes		REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
1647135446Strhodes		isc_buffer_init(&buffer, source->ndata, source->length);
1648135446Strhodes		target = &buffer;
1649135446Strhodes		ndata = source->ndata;
1650135446Strhodes	} else {
1651135446Strhodes		REQUIRE(BINDABLE(name));
1652135446Strhodes		REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1653135446Strhodes			(target == NULL && ISC_BUFFER_VALID(name->buffer)));
1654135446Strhodes		if (target == NULL) {
1655135446Strhodes			target = name->buffer;
1656135446Strhodes			isc_buffer_clear(name->buffer);
1657135446Strhodes		}
1658135446Strhodes		ndata = (unsigned char *)target->base + target->used;
1659135446Strhodes		name->ndata = ndata;
1660135446Strhodes	}
1661135446Strhodes
1662135446Strhodes	sndata = source->ndata;
1663135446Strhodes	nlen = source->length;
1664135446Strhodes	labels = source->labels;
1665135446Strhodes
1666135446Strhodes	if (nlen > (target->length - target->used)) {
1667135446Strhodes		MAKE_EMPTY(name);
1668135446Strhodes		return (ISC_R_NOSPACE);
1669135446Strhodes	}
1670135446Strhodes
1671135446Strhodes	while (labels > 0 && nlen > 0) {
1672135446Strhodes		labels--;
1673135446Strhodes		count = *sndata++;
1674135446Strhodes		*ndata++ = count;
1675135446Strhodes		nlen--;
1676135446Strhodes		if (count < 64) {
1677135446Strhodes			INSIST(nlen >= count);
1678135446Strhodes			while (count > 0) {
1679135446Strhodes				*ndata++ = maptolower[(*sndata++)];
1680135446Strhodes				nlen--;
1681135446Strhodes				count--;
1682135446Strhodes			}
1683135446Strhodes		} else {
1684135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1685135446Strhodes				    "Unexpected label type %02x", count);
1686135446Strhodes			/* Does not return. */
1687135446Strhodes		}
1688135446Strhodes	}
1689135446Strhodes
1690135446Strhodes	if (source != name) {
1691135446Strhodes		name->labels = source->labels;
1692135446Strhodes		name->length = source->length;
1693135446Strhodes		if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1694135446Strhodes			name->attributes = DNS_NAMEATTR_ABSOLUTE;
1695135446Strhodes		else
1696135446Strhodes			name->attributes = 0;
1697135446Strhodes		if (name->labels > 0 && name->offsets != NULL)
1698135446Strhodes			set_offsets(name, name->offsets, NULL);
1699135446Strhodes	}
1700135446Strhodes
1701135446Strhodes	isc_buffer_add(target, name->length);
1702135446Strhodes
1703135446Strhodes	return (ISC_R_SUCCESS);
1704135446Strhodes}
1705135446Strhodes
1706135446Strhodesstatic void
1707135446Strhodesset_offsets(const dns_name_t *name, unsigned char *offsets,
1708135446Strhodes	    dns_name_t *set_name)
1709135446Strhodes{
1710135446Strhodes	unsigned int offset, count, length, nlabels;
1711135446Strhodes	unsigned char *ndata;
1712135446Strhodes	isc_boolean_t absolute;
1713135446Strhodes
1714135446Strhodes	ndata = name->ndata;
1715135446Strhodes	length = name->length;
1716135446Strhodes	offset = 0;
1717135446Strhodes	nlabels = 0;
1718135446Strhodes	absolute = ISC_FALSE;
1719135446Strhodes	while (offset != length) {
1720135446Strhodes		INSIST(nlabels < 128);
1721135446Strhodes		offsets[nlabels++] = offset;
1722135446Strhodes		count = *ndata++;
1723135446Strhodes		offset++;
1724135446Strhodes		INSIST(count <= 63);
1725135446Strhodes		offset += count;
1726135446Strhodes		ndata += count;
1727135446Strhodes		INSIST(offset <= length);
1728135446Strhodes		if (count == 0) {
1729135446Strhodes			absolute = ISC_TRUE;
1730135446Strhodes			break;
1731135446Strhodes		}
1732135446Strhodes	}
1733135446Strhodes	if (set_name != NULL) {
1734135446Strhodes		INSIST(set_name == name);
1735135446Strhodes
1736135446Strhodes		set_name->labels = nlabels;
1737135446Strhodes		set_name->length = offset;
1738135446Strhodes		if (absolute)
1739135446Strhodes			set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1740135446Strhodes		else
1741135446Strhodes			set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1742135446Strhodes	}
1743135446Strhodes	INSIST(nlabels == name->labels);
1744135446Strhodes	INSIST(offset == name->length);
1745135446Strhodes}
1746135446Strhodes
1747135446Strhodesisc_result_t
1748135446Strhodesdns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
1749135446Strhodes		  dns_decompress_t *dctx, unsigned int options,
1750135446Strhodes		  isc_buffer_t *target)
1751135446Strhodes{
1752135446Strhodes	unsigned char *cdata, *ndata;
1753135446Strhodes	unsigned int cused; /* Bytes of compressed name data used */
1754170222Sdougb	unsigned int nused, labels, n, nmax;
1755135446Strhodes	unsigned int current, new_current, biggest_pointer;
1756135446Strhodes	isc_boolean_t done;
1757135446Strhodes	fw_state state = fw_start;
1758135446Strhodes	unsigned int c;
1759135446Strhodes	unsigned char *offsets;
1760135446Strhodes	dns_offsets_t odata;
1761135446Strhodes	isc_boolean_t downcase;
1762170222Sdougb	isc_boolean_t seen_pointer;
1763135446Strhodes
1764135446Strhodes	/*
1765135446Strhodes	 * Copy the possibly-compressed name at source into target,
1766170222Sdougb	 * decompressing it.  Loop prevention is performed by checking
1767170222Sdougb	 * the new pointer against biggest_pointer.
1768135446Strhodes	 */
1769135446Strhodes
1770135446Strhodes	REQUIRE(VALID_NAME(name));
1771135446Strhodes	REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1772135446Strhodes		(target == NULL && ISC_BUFFER_VALID(name->buffer)));
1773135446Strhodes
1774135446Strhodes	downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
1775135446Strhodes
1776135446Strhodes	if (target == NULL && name->buffer != NULL) {
1777135446Strhodes		target = name->buffer;
1778135446Strhodes		isc_buffer_clear(target);
1779135446Strhodes	}
1780135446Strhodes
1781135446Strhodes	REQUIRE(dctx != NULL);
1782135446Strhodes	REQUIRE(BINDABLE(name));
1783135446Strhodes
1784135446Strhodes	INIT_OFFSETS(name, offsets, odata);
1785135446Strhodes
1786135446Strhodes	/*
1787135446Strhodes	 * Make 'name' empty in case of failure.
1788135446Strhodes	 */
1789135446Strhodes	MAKE_EMPTY(name);
1790135446Strhodes
1791135446Strhodes	/*
1792135446Strhodes	 * Initialize things to make the compiler happy; they're not required.
1793135446Strhodes	 */
1794135446Strhodes	n = 0;
1795135446Strhodes	new_current = 0;
1796135446Strhodes
1797135446Strhodes	/*
1798135446Strhodes	 * Set up.
1799135446Strhodes	 */
1800135446Strhodes	labels = 0;
1801135446Strhodes	done = ISC_FALSE;
1802135446Strhodes
1803135446Strhodes	ndata = isc_buffer_used(target);
1804135446Strhodes	nused = 0;
1805170222Sdougb	seen_pointer = ISC_FALSE;
1806135446Strhodes
1807135446Strhodes	/*
1808135446Strhodes	 * Find the maximum number of uncompressed target name
1809135446Strhodes	 * bytes we are willing to generate.  This is the smaller
1810135446Strhodes	 * of the available target buffer length and the
1811135446Strhodes	 * maximum legal domain name length (255).
1812135446Strhodes	 */
1813135446Strhodes	nmax = isc_buffer_availablelength(target);
1814135446Strhodes	if (nmax > DNS_NAME_MAXWIRE)
1815135446Strhodes		nmax = DNS_NAME_MAXWIRE;
1816135446Strhodes
1817135446Strhodes	cdata = isc_buffer_current(source);
1818135446Strhodes	cused = 0;
1819135446Strhodes
1820135446Strhodes	current = source->current;
1821135446Strhodes	biggest_pointer = current;
1822135446Strhodes
1823135446Strhodes	/*
1824135446Strhodes	 * Note:  The following code is not optimized for speed, but
1825135446Strhodes	 * rather for correctness.  Speed will be addressed in the future.
1826135446Strhodes	 */
1827135446Strhodes
1828135446Strhodes	while (current < source->active && !done) {
1829135446Strhodes		c = *cdata++;
1830135446Strhodes		current++;
1831170222Sdougb		if (!seen_pointer)
1832135446Strhodes			cused++;
1833135446Strhodes
1834135446Strhodes		switch (state) {
1835135446Strhodes		case fw_start:
1836135446Strhodes			if (c < 64) {
1837135446Strhodes				offsets[labels] = nused;
1838135446Strhodes				labels++;
1839135446Strhodes				if (nused + c + 1 > nmax)
1840135446Strhodes					goto full;
1841135446Strhodes				nused += c + 1;
1842135446Strhodes				*ndata++ = c;
1843135446Strhodes				if (c == 0)
1844135446Strhodes					done = ISC_TRUE;
1845135446Strhodes				n = c;
1846135446Strhodes				state = fw_ordinary;
1847135446Strhodes			} else if (c >= 128 && c < 192) {
1848135446Strhodes				/*
1849135446Strhodes				 * 14 bit local compression pointer.
1850135446Strhodes				 * Local compression is no longer an
1851135446Strhodes				 * IETF draft.
1852135446Strhodes				 */
1853135446Strhodes				return (DNS_R_BADLABELTYPE);
1854135446Strhodes			} else if (c >= 192) {
1855135446Strhodes				/*
1856135446Strhodes				 * Ordinary 14-bit pointer.
1857135446Strhodes				 */
1858135446Strhodes				if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
1859135446Strhodes				    0)
1860135446Strhodes					return (DNS_R_DISALLOWED);
1861135446Strhodes				new_current = c & 0x3F;
1862135446Strhodes				n = 1;
1863135446Strhodes				state = fw_newcurrent;
1864135446Strhodes			} else
1865135446Strhodes				return (DNS_R_BADLABELTYPE);
1866135446Strhodes			break;
1867135446Strhodes		case fw_ordinary:
1868135446Strhodes			if (downcase)
1869135446Strhodes				c = maptolower[c];
1870135446Strhodes			/* FALLTHROUGH */
1871135446Strhodes		case fw_copy:
1872135446Strhodes			*ndata++ = c;
1873135446Strhodes			n--;
1874135446Strhodes			if (n == 0)
1875135446Strhodes				state = fw_start;
1876135446Strhodes			break;
1877135446Strhodes		case fw_newcurrent:
1878135446Strhodes			new_current *= 256;
1879135446Strhodes			new_current += c;
1880135446Strhodes			n--;
1881135446Strhodes			if (n != 0)
1882135446Strhodes				break;
1883135446Strhodes			if (new_current >= biggest_pointer)
1884135446Strhodes				return (DNS_R_BADPOINTER);
1885135446Strhodes			biggest_pointer = new_current;
1886135446Strhodes			current = new_current;
1887170222Sdougb			cdata = (unsigned char *)source->base + current;
1888170222Sdougb			seen_pointer = ISC_TRUE;
1889135446Strhodes			state = fw_start;
1890135446Strhodes			break;
1891135446Strhodes		default:
1892135446Strhodes			FATAL_ERROR(__FILE__, __LINE__,
1893135446Strhodes				    "Unknown state %d", state);
1894135446Strhodes			/* Does not return. */
1895135446Strhodes		}
1896135446Strhodes	}
1897135446Strhodes
1898135446Strhodes	if (!done)
1899135446Strhodes		return (ISC_R_UNEXPECTEDEND);
1900135446Strhodes
1901135446Strhodes	name->ndata = (unsigned char *)target->base + target->used;
1902135446Strhodes	name->labels = labels;
1903135446Strhodes	name->length = nused;
1904135446Strhodes	name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1905135446Strhodes
1906135446Strhodes	isc_buffer_forward(source, cused);
1907135446Strhodes	isc_buffer_add(target, name->length);
1908135446Strhodes
1909135446Strhodes	return (ISC_R_SUCCESS);
1910135446Strhodes
1911135446Strhodes full:
1912135446Strhodes	if (nmax == DNS_NAME_MAXWIRE)
1913135446Strhodes		/*
1914135446Strhodes		 * The name did not fit even though we had a buffer
1915135446Strhodes		 * big enough to fit a maximum-length name.
1916135446Strhodes		 */
1917135446Strhodes		return (DNS_R_NAMETOOLONG);
1918135446Strhodes	else
1919135446Strhodes		/*
1920135446Strhodes		 * The name might fit if only the caller could give us a
1921135446Strhodes		 * big enough buffer.
1922135446Strhodes		 */
1923135446Strhodes		return (ISC_R_NOSPACE);
1924135446Strhodes}
1925135446Strhodes
1926135446Strhodesisc_result_t
1927165071Sdougbdns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
1928165071Sdougb		isc_buffer_t *target)
1929165071Sdougb{
1930135446Strhodes	unsigned int methods;
1931135446Strhodes	isc_uint16_t offset;
1932135446Strhodes	dns_name_t gp;	/* Global compression prefix */
1933135446Strhodes	isc_boolean_t gf;	/* Global compression target found */
1934135446Strhodes	isc_uint16_t go;	/* Global compression offset */
1935135446Strhodes	dns_offsets_t clo;
1936135446Strhodes	dns_name_t clname;
1937135446Strhodes
1938135446Strhodes	/*
1939135446Strhodes	 * Convert 'name' into wire format, compressing it as specified by the
1940135446Strhodes	 * compression context 'cctx', and storing the result in 'target'.
1941135446Strhodes	 */
1942135446Strhodes
1943135446Strhodes	REQUIRE(VALID_NAME(name));
1944135446Strhodes	REQUIRE(cctx != NULL);
1945135446Strhodes	REQUIRE(ISC_BUFFER_VALID(target));
1946135446Strhodes
1947135446Strhodes	/*
1948135446Strhodes	 * If 'name' doesn't have an offsets table, make a clone which
1949135446Strhodes	 * has one.
1950135446Strhodes	 */
1951135446Strhodes	if (name->offsets == NULL) {
1952254402Serwin#if defined(__clang__)  && \
1953254402Serwin       ( __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2))
1954254402Serwin		memset(&clname, 0, sizeof(clname));
1955254402Serwin#endif
1956135446Strhodes		DNS_NAME_INIT(&clname, clo);
1957135446Strhodes		dns_name_clone(name, &clname);
1958135446Strhodes		name = &clname;
1959135446Strhodes	}
1960135446Strhodes	DNS_NAME_INIT(&gp, NULL);
1961135446Strhodes
1962135446Strhodes	offset = target->used;	/*XXX*/
1963135446Strhodes
1964135446Strhodes	methods = dns_compress_getmethods(cctx);
1965135446Strhodes
1966193149Sdougb	if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
1967193149Sdougb	    (methods & DNS_COMPRESS_GLOBAL14) != 0)
1968135446Strhodes		gf = dns_compress_findglobal(cctx, name, &gp, &go);
1969135446Strhodes	else
1970135446Strhodes		gf = ISC_FALSE;
1971135446Strhodes
1972135446Strhodes	/*
1973135446Strhodes	 * If the offset is too high for 14 bit global compression, we're
1974135446Strhodes	 * out of luck.
1975135446Strhodes	 */
1976135446Strhodes	if (gf && go >= 0x4000)
1977135446Strhodes		gf = ISC_FALSE;
1978135446Strhodes
1979135446Strhodes	/*
1980135446Strhodes	 * Will the compression pointer reduce the message size?
1981135446Strhodes	 */
1982135446Strhodes	if (gf && (gp.length + 2) >= name->length)
1983135446Strhodes		gf = ISC_FALSE;
1984135446Strhodes
1985135446Strhodes	if (gf) {
1986135446Strhodes		if (target->length - target->used < gp.length)
1987135446Strhodes			return (ISC_R_NOSPACE);
1988262706Serwin		(void)memmove((unsigned char *)target->base + target->used,
1989262706Serwin			      gp.ndata, (size_t)gp.length);
1990135446Strhodes		isc_buffer_add(target, gp.length);
1991135446Strhodes		go |= 0xc000;
1992135446Strhodes		if (target->length - target->used < 2)
1993135446Strhodes			return (ISC_R_NOSPACE);
1994135446Strhodes		isc_buffer_putuint16(target, go);
1995135446Strhodes		if (gp.length != 0)
1996135446Strhodes			dns_compress_add(cctx, name, &gp, offset);
1997135446Strhodes	} else {
1998135446Strhodes		if (target->length - target->used < name->length)
1999135446Strhodes			return (ISC_R_NOSPACE);
2000262706Serwin		(void)memmove((unsigned char *)target->base + target->used,
2001262706Serwin			      name->ndata, (size_t)name->length);
2002135446Strhodes		isc_buffer_add(target, name->length);
2003135446Strhodes		dns_compress_add(cctx, name, name, offset);
2004135446Strhodes	}
2005135446Strhodes	return (ISC_R_SUCCESS);
2006135446Strhodes}
2007135446Strhodes
2008135446Strhodesisc_result_t
2009135446Strhodesdns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name,
2010135446Strhodes		     isc_buffer_t *target)
2011135446Strhodes{
2012135446Strhodes	unsigned char *ndata, *offsets;
2013135446Strhodes	unsigned int nrem, labels, prefix_length, length;
2014135446Strhodes	isc_boolean_t copy_prefix = ISC_TRUE;
2015135446Strhodes	isc_boolean_t copy_suffix = ISC_TRUE;
2016135446Strhodes	isc_boolean_t absolute = ISC_FALSE;
2017135446Strhodes	dns_name_t tmp_name;
2018135446Strhodes	dns_offsets_t odata;
2019135446Strhodes
2020135446Strhodes	/*
2021135446Strhodes	 * Concatenate 'prefix' and 'suffix'.
2022135446Strhodes	 */
2023135446Strhodes
2024135446Strhodes	REQUIRE(prefix == NULL || VALID_NAME(prefix));
2025135446Strhodes	REQUIRE(suffix == NULL || VALID_NAME(suffix));
2026135446Strhodes	REQUIRE(name == NULL || VALID_NAME(name));
2027135446Strhodes	REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
2028135446Strhodes		(target == NULL && name != NULL && ISC_BUFFER_VALID(name->buffer)));
2029135446Strhodes	if (prefix == NULL || prefix->labels == 0)
2030135446Strhodes		copy_prefix = ISC_FALSE;
2031135446Strhodes	if (suffix == NULL || suffix->labels == 0)
2032135446Strhodes		copy_suffix = ISC_FALSE;
2033135446Strhodes	if (copy_prefix &&
2034135446Strhodes	    (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2035135446Strhodes		absolute = ISC_TRUE;
2036135446Strhodes		REQUIRE(!copy_suffix);
2037135446Strhodes	}
2038135446Strhodes	if (name == NULL) {
2039135446Strhodes		DNS_NAME_INIT(&tmp_name, odata);
2040135446Strhodes		name = &tmp_name;
2041135446Strhodes	}
2042135446Strhodes	if (target == NULL) {
2043135446Strhodes		INSIST(name->buffer != NULL);
2044135446Strhodes		target = name->buffer;
2045135446Strhodes		isc_buffer_clear(name->buffer);
2046135446Strhodes	}
2047135446Strhodes
2048135446Strhodes	REQUIRE(BINDABLE(name));
2049135446Strhodes
2050135446Strhodes	/*
2051135446Strhodes	 * Set up.
2052135446Strhodes	 */
2053135446Strhodes	nrem = target->length - target->used;
2054135446Strhodes	ndata = (unsigned char *)target->base + target->used;
2055135446Strhodes	if (nrem > DNS_NAME_MAXWIRE)
2056135446Strhodes		nrem = DNS_NAME_MAXWIRE;
2057135446Strhodes	length = 0;
2058135446Strhodes	prefix_length = 0;
2059135446Strhodes	labels = 0;
2060135446Strhodes	if (copy_prefix) {
2061135446Strhodes		prefix_length = prefix->length;
2062135446Strhodes		length += prefix_length;
2063135446Strhodes		labels += prefix->labels;
2064135446Strhodes	}
2065135446Strhodes	if (copy_suffix) {
2066135446Strhodes		length += suffix->length;
2067135446Strhodes		labels += suffix->labels;
2068135446Strhodes	}
2069135446Strhodes	if (length > DNS_NAME_MAXWIRE) {
2070135446Strhodes		MAKE_EMPTY(name);
2071135446Strhodes		return (DNS_R_NAMETOOLONG);
2072135446Strhodes	}
2073135446Strhodes	if (length > nrem) {
2074135446Strhodes		MAKE_EMPTY(name);
2075135446Strhodes		return (ISC_R_NOSPACE);
2076135446Strhodes	}
2077135446Strhodes
2078135446Strhodes	if (copy_suffix) {
2079135446Strhodes		if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2080135446Strhodes			absolute = ISC_TRUE;
2081262706Serwin		memmove(ndata + prefix_length, suffix->ndata, suffix->length);
2082135446Strhodes	}
2083135446Strhodes
2084135446Strhodes	/*
2085135446Strhodes	 * If 'prefix' and 'name' are the same object, and the object has
2086135446Strhodes	 * a dedicated buffer, and we're using it, then we don't have to
2087135446Strhodes	 * copy anything.
2088135446Strhodes	 */
2089135446Strhodes	if (copy_prefix && (prefix != name || prefix->buffer != target))
2090262706Serwin		memmove(ndata, prefix->ndata, prefix_length);
2091135446Strhodes
2092135446Strhodes	name->ndata = ndata;
2093135446Strhodes	name->labels = labels;
2094135446Strhodes	name->length = length;
2095135446Strhodes	if (absolute)
2096135446Strhodes		name->attributes = DNS_NAMEATTR_ABSOLUTE;
2097135446Strhodes	else
2098135446Strhodes		name->attributes = 0;
2099135446Strhodes
2100135446Strhodes	if (name->labels > 0 && name->offsets != NULL) {
2101135446Strhodes		INIT_OFFSETS(name, offsets, odata);
2102135446Strhodes		set_offsets(name, offsets, NULL);
2103135446Strhodes	}
2104135446Strhodes
2105135446Strhodes	isc_buffer_add(target, name->length);
2106135446Strhodes
2107135446Strhodes	return (ISC_R_SUCCESS);
2108135446Strhodes}
2109135446Strhodes
2110135446Strhodesvoid
2111135446Strhodesdns_name_split(dns_name_t *name, unsigned int suffixlabels,
2112135446Strhodes	       dns_name_t *prefix, dns_name_t *suffix)
2113135446Strhodes
2114135446Strhodes{
2115135446Strhodes	unsigned int splitlabel;
2116135446Strhodes
2117135446Strhodes	REQUIRE(VALID_NAME(name));
2118135446Strhodes	REQUIRE(suffixlabels > 0);
2119135446Strhodes	REQUIRE(suffixlabels < name->labels);
2120135446Strhodes	REQUIRE(prefix != NULL || suffix != NULL);
2121135446Strhodes	REQUIRE(prefix == NULL ||
2122135446Strhodes		(VALID_NAME(prefix) &&
2123135446Strhodes		 prefix->buffer != NULL &&
2124135446Strhodes		 BINDABLE(prefix)));
2125135446Strhodes	REQUIRE(suffix == NULL ||
2126135446Strhodes		(VALID_NAME(suffix) &&
2127135446Strhodes		 suffix->buffer != NULL &&
2128135446Strhodes		 BINDABLE(suffix)));
2129135446Strhodes
2130135446Strhodes	splitlabel = name->labels - suffixlabels;
2131135446Strhodes
2132135446Strhodes	if (prefix != NULL)
2133135446Strhodes		dns_name_getlabelsequence(name, 0, splitlabel, prefix);
2134135446Strhodes
2135135446Strhodes	if (suffix != NULL)
2136135446Strhodes		dns_name_getlabelsequence(name, splitlabel,
2137135446Strhodes					  suffixlabels, suffix);
2138135446Strhodes
2139135446Strhodes	return;
2140135446Strhodes}
2141135446Strhodes
2142135446Strhodesisc_result_t
2143165071Sdougbdns_name_dup(const dns_name_t *source, isc_mem_t *mctx,
2144165071Sdougb	     dns_name_t *target)
2145165071Sdougb{
2146135446Strhodes	/*
2147135446Strhodes	 * Make 'target' a dynamically allocated copy of 'source'.
2148135446Strhodes	 */
2149135446Strhodes
2150135446Strhodes	REQUIRE(VALID_NAME(source));
2151135446Strhodes	REQUIRE(source->length > 0);
2152135446Strhodes	REQUIRE(VALID_NAME(target));
2153135446Strhodes	REQUIRE(BINDABLE(target));
2154135446Strhodes
2155135446Strhodes	/*
2156135446Strhodes	 * Make 'target' empty in case of failure.
2157135446Strhodes	 */
2158135446Strhodes	MAKE_EMPTY(target);
2159135446Strhodes
2160135446Strhodes	target->ndata = isc_mem_get(mctx, source->length);
2161135446Strhodes	if (target->ndata == NULL)
2162135446Strhodes		return (ISC_R_NOMEMORY);
2163135446Strhodes
2164262706Serwin	memmove(target->ndata, source->ndata, source->length);
2165135446Strhodes
2166135446Strhodes	target->length = source->length;
2167135446Strhodes	target->labels = source->labels;
2168135446Strhodes	target->attributes = DNS_NAMEATTR_DYNAMIC;
2169135446Strhodes	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2170135446Strhodes		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
2171135446Strhodes	if (target->offsets != NULL) {
2172135446Strhodes		if (source->offsets != NULL)
2173262706Serwin			memmove(target->offsets, source->offsets,
2174262706Serwin				source->labels);
2175135446Strhodes		else
2176135446Strhodes			set_offsets(target, target->offsets, NULL);
2177135446Strhodes	}
2178135446Strhodes
2179135446Strhodes	return (ISC_R_SUCCESS);
2180135446Strhodes}
2181135446Strhodes
2182135446Strhodesisc_result_t
2183135446Strhodesdns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx,
2184135446Strhodes			dns_name_t *target)
2185135446Strhodes{
2186135446Strhodes	/*
2187135446Strhodes	 * Make 'target' a read-only dynamically allocated copy of 'source'.
2188135446Strhodes	 * 'target' will also have a dynamically allocated offsets table.
2189135446Strhodes	 */
2190135446Strhodes
2191135446Strhodes	REQUIRE(VALID_NAME(source));
2192135446Strhodes	REQUIRE(source->length > 0);
2193135446Strhodes	REQUIRE(VALID_NAME(target));
2194135446Strhodes	REQUIRE(BINDABLE(target));
2195135446Strhodes	REQUIRE(target->offsets == NULL);
2196135446Strhodes
2197135446Strhodes	/*
2198135446Strhodes	 * Make 'target' empty in case of failure.
2199135446Strhodes	 */
2200135446Strhodes	MAKE_EMPTY(target);
2201135446Strhodes
2202135446Strhodes	target->ndata = isc_mem_get(mctx, source->length + source->labels);
2203135446Strhodes	if (target->ndata == NULL)
2204135446Strhodes		return (ISC_R_NOMEMORY);
2205135446Strhodes
2206262706Serwin	memmove(target->ndata, source->ndata, source->length);
2207135446Strhodes
2208135446Strhodes	target->length = source->length;
2209135446Strhodes	target->labels = source->labels;
2210135446Strhodes	target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
2211135446Strhodes		DNS_NAMEATTR_READONLY;
2212135446Strhodes	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2213135446Strhodes		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
2214135446Strhodes	target->offsets = target->ndata + source->length;
2215135446Strhodes	if (source->offsets != NULL)
2216262706Serwin		memmove(target->offsets, source->offsets, source->labels);
2217135446Strhodes	else
2218135446Strhodes		set_offsets(target, target->offsets, NULL);
2219135446Strhodes
2220135446Strhodes	return (ISC_R_SUCCESS);
2221135446Strhodes}
2222135446Strhodes
2223135446Strhodesvoid
2224135446Strhodesdns_name_free(dns_name_t *name, isc_mem_t *mctx) {
2225135446Strhodes	size_t size;
2226135446Strhodes
2227135446Strhodes	/*
2228135446Strhodes	 * Free 'name'.
2229135446Strhodes	 */
2230135446Strhodes
2231135446Strhodes	REQUIRE(VALID_NAME(name));
2232135446Strhodes	REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
2233135446Strhodes
2234135446Strhodes	size = name->length;
2235135446Strhodes	if ((name->attributes & DNS_NAMEATTR_DYNOFFSETS) != 0)
2236135446Strhodes		size += name->labels;
2237135446Strhodes	isc_mem_put(mctx, name->ndata, size);
2238135446Strhodes	dns_name_invalidate(name);
2239135446Strhodes}
2240135446Strhodes
2241135446Strhodesisc_result_t
2242135446Strhodesdns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg) {
2243135446Strhodes	dns_name_t downname;
2244135446Strhodes	unsigned char data[256];
2245135446Strhodes	isc_buffer_t buffer;
2246135446Strhodes	isc_result_t result;
2247135446Strhodes	isc_region_t r;
2248135446Strhodes
2249135446Strhodes	/*
2250135446Strhodes	 * Send 'name' in DNSSEC canonical form to 'digest'.
2251135446Strhodes	 */
2252135446Strhodes
2253135446Strhodes	REQUIRE(VALID_NAME(name));
2254135446Strhodes	REQUIRE(digest != NULL);
2255135446Strhodes
2256254402Serwin#if defined(__clang__)  && \
2257254402Serwin       ( __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2))
2258254402Serwin	memset(&downname, 0, sizeof(downname));
2259254402Serwin#endif
2260135446Strhodes	DNS_NAME_INIT(&downname, NULL);
2261254402Serwin
2262135446Strhodes	isc_buffer_init(&buffer, data, sizeof(data));
2263135446Strhodes
2264135446Strhodes	result = dns_name_downcase(name, &downname, &buffer);
2265135446Strhodes	if (result != ISC_R_SUCCESS)
2266135446Strhodes		return (result);
2267135446Strhodes
2268135446Strhodes	isc_buffer_usedregion(&buffer, &r);
2269135446Strhodes
2270135446Strhodes	return ((digest)(arg, &r));
2271135446Strhodes}
2272135446Strhodes
2273135446Strhodesisc_boolean_t
2274135446Strhodesdns_name_dynamic(dns_name_t *name) {
2275135446Strhodes	REQUIRE(VALID_NAME(name));
2276135446Strhodes
2277135446Strhodes	/*
2278135446Strhodes	 * Returns whether there is dynamic memory associated with this name.
2279135446Strhodes	 */
2280135446Strhodes
2281135446Strhodes	return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ?
2282135446Strhodes		ISC_TRUE : ISC_FALSE);
2283135446Strhodes}
2284135446Strhodes
2285135446Strhodesisc_result_t
2286135446Strhodesdns_name_print(dns_name_t *name, FILE *stream) {
2287135446Strhodes	isc_result_t result;
2288135446Strhodes	isc_buffer_t b;
2289135446Strhodes	isc_region_t r;
2290135446Strhodes	char t[1024];
2291135446Strhodes
2292135446Strhodes	/*
2293135446Strhodes	 * Print 'name' on 'stream'.
2294135446Strhodes	 */
2295135446Strhodes
2296135446Strhodes	REQUIRE(VALID_NAME(name));
2297135446Strhodes
2298135446Strhodes	isc_buffer_init(&b, t, sizeof(t));
2299135446Strhodes	result = dns_name_totext(name, ISC_FALSE, &b);
2300135446Strhodes	if (result != ISC_R_SUCCESS)
2301135446Strhodes		return (result);
2302135446Strhodes	isc_buffer_usedregion(&b, &r);
2303135446Strhodes	fprintf(stream, "%.*s", (int)r.length, (char *)r.base);
2304135446Strhodes
2305135446Strhodes	return (ISC_R_SUCCESS);
2306135446Strhodes}
2307135446Strhodes
2308170222Sdougbisc_result_t
2309170222Sdougbdns_name_settotextfilter(dns_name_totextfilter_t proc) {
2310170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
2311170222Sdougb	isc_result_t result;
2312170222Sdougb	dns_name_totextfilter_t *mem;
2313170222Sdougb	int res;
2314170222Sdougb
2315170222Sdougb	result = totext_filter_proc_key_init();
2316170222Sdougb	if (result != ISC_R_SUCCESS)
2317170222Sdougb		return (result);
2318170222Sdougb
2319170222Sdougb	/*
2320170222Sdougb	 * If we already have been here set / clear as appropriate.
2321170222Sdougb	 * Otherwise allocate memory.
2322170222Sdougb	 */
2323170222Sdougb	mem = isc_thread_key_getspecific(totext_filter_proc_key);
2324170222Sdougb	if (mem != NULL && proc != NULL) {
2325170222Sdougb		*mem = proc;
2326170222Sdougb		return (ISC_R_SUCCESS);
2327170222Sdougb	}
2328170222Sdougb	if (proc == NULL) {
2329170222Sdougb		isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
2330170222Sdougb		res = isc_thread_key_setspecific(totext_filter_proc_key, NULL);
2331170222Sdougb		if (res != 0)
2332170222Sdougb			result = ISC_R_UNEXPECTED;
2333170222Sdougb		return (result);
2334170222Sdougb	}
2335193149Sdougb
2336170222Sdougb	mem = isc_mem_get(thread_key_mctx, sizeof(*mem));
2337170222Sdougb	if (mem == NULL)
2338170222Sdougb		return (ISC_R_NOMEMORY);
2339170222Sdougb	*mem = proc;
2340170222Sdougb	if (isc_thread_key_setspecific(totext_filter_proc_key, mem) != 0) {
2341170222Sdougb		isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
2342170222Sdougb		result = ISC_R_UNEXPECTED;
2343170222Sdougb	}
2344170222Sdougb	return (result);
2345170222Sdougb#else
2346170222Sdougb	totext_filter_proc = proc;
2347170222Sdougb	return (ISC_R_SUCCESS);
2348170222Sdougb#endif
2349170222Sdougb}
2350170222Sdougb
2351135446Strhodesvoid
2352135446Strhodesdns_name_format(dns_name_t *name, char *cp, unsigned int size) {
2353135446Strhodes	isc_result_t result;
2354135446Strhodes	isc_buffer_t buf;
2355135446Strhodes
2356135446Strhodes	REQUIRE(size > 0);
2357135446Strhodes
2358135446Strhodes	/*
2359135446Strhodes	 * Leave room for null termination after buffer.
2360135446Strhodes	 */
2361135446Strhodes	isc_buffer_init(&buf, cp, size - 1);
2362135446Strhodes	result = dns_name_totext(name, ISC_TRUE, &buf);
2363135446Strhodes	if (result == ISC_R_SUCCESS) {
2364135446Strhodes		/*
2365135446Strhodes		 * Null terminate.
2366135446Strhodes		 */
2367135446Strhodes		isc_region_t r;
2368135446Strhodes		isc_buffer_usedregion(&buf, &r);
2369135446Strhodes		((char *) r.base)[r.length] = '\0';
2370135446Strhodes
2371135446Strhodes	} else
2372135446Strhodes		snprintf(cp, size, "<unknown>");
2373135446Strhodes}
2374135446Strhodes
2375224092Sdougb/*
2376224092Sdougb * dns_name_tostring() -- similar to dns_name_format() but allocates its own
2377224092Sdougb * memory.
2378224092Sdougb */
2379135446Strhodesisc_result_t
2380224092Sdougbdns_name_tostring(dns_name_t *name, char **target, isc_mem_t *mctx) {
2381224092Sdougb	isc_result_t result;
2382224092Sdougb	isc_buffer_t buf;
2383224092Sdougb	isc_region_t reg;
2384224092Sdougb	char *p, txt[DNS_NAME_FORMATSIZE];
2385224092Sdougb
2386224092Sdougb	REQUIRE(VALID_NAME(name));
2387224092Sdougb	REQUIRE(target != NULL && *target == NULL);
2388224092Sdougb
2389224092Sdougb	isc_buffer_init(&buf, txt, sizeof(txt));
2390224092Sdougb	result = dns_name_totext(name, ISC_FALSE, &buf);
2391224092Sdougb	if (result != ISC_R_SUCCESS)
2392224092Sdougb		return (result);
2393224092Sdougb
2394224092Sdougb	isc_buffer_usedregion(&buf, &reg);
2395224092Sdougb	p = isc_mem_allocate(mctx, reg.length + 1);
2396262706Serwin	memmove(p, (char *) reg.base, (int) reg.length);
2397224092Sdougb	p[reg.length] = '\0';
2398224092Sdougb
2399224092Sdougb	*target = p;
2400224092Sdougb	return (ISC_R_SUCCESS);
2401224092Sdougb}
2402224092Sdougb
2403224092Sdougb/*
2404224092Sdougb * dns_name_fromstring() -- convert directly from a string to a name,
2405224092Sdougb * allocating memory as needed
2406224092Sdougb */
2407224092Sdougbisc_result_t
2408224092Sdougbdns_name_fromstring(dns_name_t *target, const char *src, unsigned int options,
2409224092Sdougb		    isc_mem_t *mctx)
2410224092Sdougb{
2411224092Sdougb	return (dns_name_fromstring2(target, src, dns_rootname, options, mctx));
2412224092Sdougb}
2413224092Sdougb
2414224092Sdougbisc_result_t
2415224092Sdougbdns_name_fromstring2(dns_name_t *target, const char *src,
2416224092Sdougb		     const dns_name_t *origin, unsigned int options,
2417224092Sdougb		     isc_mem_t *mctx)
2418224092Sdougb{
2419224092Sdougb	isc_result_t result;
2420224092Sdougb	isc_buffer_t buf;
2421224092Sdougb	dns_fixedname_t fn;
2422224092Sdougb	dns_name_t *name;
2423224092Sdougb
2424224092Sdougb	REQUIRE(src != NULL);
2425224092Sdougb
2426254402Serwin	isc_buffer_constinit(&buf, src, strlen(src));
2427224092Sdougb	isc_buffer_add(&buf, strlen(src));
2428224092Sdougb	if (BINDABLE(target) && target->buffer != NULL)
2429224092Sdougb		name = target;
2430224092Sdougb	else {
2431224092Sdougb		dns_fixedname_init(&fn);
2432224092Sdougb		name = dns_fixedname_name(&fn);
2433224092Sdougb	}
2434224092Sdougb
2435224092Sdougb	result = dns_name_fromtext(name, &buf, origin, options, NULL);
2436224092Sdougb	if (result != ISC_R_SUCCESS)
2437224092Sdougb		return (result);
2438224092Sdougb
2439224092Sdougb	if (name != target)
2440224092Sdougb		result = dns_name_dupwithoffsets(name, mctx, target);
2441224092Sdougb	return (result);
2442224092Sdougb}
2443224092Sdougb
2444224092Sdougbisc_result_t
2445135446Strhodesdns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
2446135446Strhodes	unsigned char *ndata;
2447135446Strhodes
2448135446Strhodes	/*
2449135446Strhodes	 * Make dest a copy of source.
2450135446Strhodes	 */
2451135446Strhodes
2452135446Strhodes	REQUIRE(VALID_NAME(source));
2453135446Strhodes	REQUIRE(VALID_NAME(dest));
2454135446Strhodes	REQUIRE(target != NULL || dest->buffer != NULL);
2455135446Strhodes
2456135446Strhodes	if (target == NULL) {
2457135446Strhodes		target = dest->buffer;
2458135446Strhodes		isc_buffer_clear(dest->buffer);
2459135446Strhodes	}
2460135446Strhodes
2461135446Strhodes	REQUIRE(BINDABLE(dest));
2462135446Strhodes
2463135446Strhodes	/*
2464135446Strhodes	 * Set up.
2465135446Strhodes	 */
2466135446Strhodes	if (target->length - target->used < source->length)
2467135446Strhodes		return (ISC_R_NOSPACE);
2468135446Strhodes
2469135446Strhodes	ndata = (unsigned char *)target->base + target->used;
2470135446Strhodes	dest->ndata = target->base;
2471135446Strhodes
2472262706Serwin	memmove(ndata, source->ndata, source->length);
2473135446Strhodes
2474135446Strhodes	dest->ndata = ndata;
2475135446Strhodes	dest->labels = source->labels;
2476135446Strhodes	dest->length = source->length;
2477135446Strhodes	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2478135446Strhodes		dest->attributes = DNS_NAMEATTR_ABSOLUTE;
2479135446Strhodes	else
2480135446Strhodes		dest->attributes = 0;
2481135446Strhodes
2482135446Strhodes	if (dest->labels > 0 && dest->offsets != NULL) {
2483135446Strhodes		if (source->offsets != NULL)
2484262706Serwin			memmove(dest->offsets, source->offsets, source->labels);
2485135446Strhodes		else
2486135446Strhodes			set_offsets(dest, dest->offsets, NULL);
2487135446Strhodes	}
2488135446Strhodes
2489135446Strhodes	isc_buffer_add(target, dest->length);
2490135446Strhodes
2491135446Strhodes	return (ISC_R_SUCCESS);
2492135446Strhodes}
2493135446Strhodes
2494170222Sdougbvoid
2495170222Sdougbdns_name_destroy(void) {
2496170222Sdougb#ifdef ISC_PLATFORM_USETHREADS
2497170222Sdougb	RUNTIME_CHECK(isc_once_do(&once, thread_key_mutex_init)
2498170222Sdougb				  == ISC_R_SUCCESS);
2499170222Sdougb
2500170222Sdougb	LOCK(&thread_key_mutex);
2501170222Sdougb	if (thread_key_initialized) {
2502170222Sdougb		isc_mem_detach(&thread_key_mctx);
2503170222Sdougb		isc_thread_key_delete(totext_filter_proc_key);
2504170222Sdougb		thread_key_initialized = 0;
2505170222Sdougb	}
2506170222Sdougb	UNLOCK(&thread_key_mutex);
2507170222Sdougb
2508170222Sdougb#endif
2509170222Sdougb}
2510